diff --git a/package.json b/package.json
index 2d4d54773..2b6d7335a 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,8 @@
"dependencies": {
"htmlparser2": "3.9.0",
"memoizee": "0.3.10",
- "promise": "7.1.1"
+ "promise": "7.1.1",
+ "scratch-render-webgl": "git+https://github.com/LLK/scratch-render-webgl.git"
},
"devDependencies": {
"eslint": "2.7.0",
diff --git a/playground/index.html b/playground/index.html
index 82535807b..e11d72c82 100644
--- a/playground/index.html
+++ b/playground/index.html
@@ -13,9 +13,14 @@
+ Renderer
VM Threads
VM Block Representation
+
+ Render
+
+
Thread explorer
@@ -240,6 +245,54 @@
+
+
+
+
+ 10
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+ 90
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
@@ -249,6 +302,8 @@
+
+
diff --git a/playground/playground.css b/playground/playground.css
index 451a7cad5..a15e1d81c 100644
--- a/playground/playground.css
+++ b/playground/playground.css
@@ -32,6 +32,6 @@ a {
font-size: 10pt;
}
-#tab-blockexplorer {
+#tab-blockexplorer, #tab-threadexplorer {
display: none;
}
diff --git a/playground/playground.js b/playground/playground.js
index be683ceb7..220549c9f 100644
--- a/playground/playground.js
+++ b/playground/playground.js
@@ -3,6 +3,10 @@ window.onload = function() {
var vm = new window.VirtualMachine();
window.vm = vm;
+ var canvas = document.getElementById('scratch-stage');
+ window.renderer = new window.RenderWebGLLocal(canvas);
+ window.renderer.connectWorker(window.vm.vmWorker);
+
var toolbox = document.getElementById('toolbox');
var workspace = window.Blockly.inject('blocks', {
toolbox: toolbox,
@@ -85,16 +89,25 @@ window.onload = function() {
var tabBlockExplorer = document.getElementById('tab-blockexplorer');
var tabThreadExplorer = document.getElementById('tab-threadexplorer');
+ var tabRenderExplorer = document.getElementById('tab-renderexplorer');
// Handlers to show different explorers.
document.getElementById('threadexplorer-link').addEventListener('click',
function () {
tabBlockExplorer.style.display = 'none';
+ tabRenderExplorer.style.display = 'none';
tabThreadExplorer.style.display = 'block';
});
document.getElementById('blockexplorer-link').addEventListener('click',
function () {
tabBlockExplorer.style.display = 'block';
+ tabRenderExplorer.style.display = 'none';
+ tabThreadExplorer.style.display = 'none';
+ });
+ document.getElementById('renderexplorer-link').addEventListener('click',
+ function () {
+ tabBlockExplorer.style.display = 'none';
+ tabRenderExplorer.style.display = 'block';
tabThreadExplorer.style.display = 'none';
});
};
diff --git a/src/blocks/scratch3_motion.js b/src/blocks/scratch3_motion.js
new file mode 100644
index 000000000..4fcc3b056
--- /dev/null
+++ b/src/blocks/scratch3_motion.js
@@ -0,0 +1,31 @@
+function Scratch3MotionBlocks(runtime) {
+ /**
+ * The runtime instantiating this block package.
+ * @type {Runtime}
+ */
+ this.runtime = runtime;
+}
+
+/**
+ * Retrieve the block primitives implemented by this package.
+ * @return {Object.
} Mapping of opcode to Function.
+ */
+Scratch3MotionBlocks.prototype.getPrimitives = function() {
+ return {
+ 'motion_gotoxy': this.goToXY,
+ 'motion_turnright': this.turnRight
+ };
+};
+
+Scratch3MotionBlocks.prototype.goToXY = function (args, util) {
+ util.target.setXY(args.X, args.Y);
+};
+
+Scratch3MotionBlocks.prototype.turnRight = function (args, util) {
+ if (args.DEGREES !== args.DEGREES) {
+ throw "Bad degrees" + args.DEGREES;
+ }
+ util.target.setDirection(args.DEGREES + util.target.direction);
+};
+
+module.exports = Scratch3MotionBlocks;
diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 75077061c..86cb50350 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -31,7 +31,12 @@ Scratch3OperatorsBlocks.prototype.getPrimitives = function() {
};
Scratch3OperatorsBlocks.prototype.number = function (args) {
- return Number(args.NUM);
+ var num = Number(args.NUM);
+ if (num !== num) {
+ // NaN
+ return 0;
+ }
+ return num;
};
Scratch3OperatorsBlocks.prototype.text = function (args) {
diff --git a/src/engine/execute.js b/src/engine/execute.js
index 001178d56..aa413a76b 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -70,7 +70,8 @@ var execute = function (sequencer, thread) {
stackFrame: currentStackFrame.executionContext,
startSubstack: function (substackNum) {
sequencer.stepToSubstack(thread, substackNum);
- }
+ },
+ target: target
});
// Deal with any reported value.
diff --git a/src/engine/runtime.js b/src/engine/runtime.js
index a0db919ae..c51800cdb 100644
--- a/src/engine/runtime.js
+++ b/src/engine/runtime.js
@@ -6,6 +6,7 @@ var util = require('util');
var defaultBlockPackages = {
'scratch3_control': require('../blocks/scratch3_control'),
'scratch3_event': require('../blocks/scratch3_event'),
+ 'scratch3_motion': require('../blocks/scratch3_motion'),
'scratch3_operators': require('../blocks/scratch3_operators')
};
@@ -257,6 +258,9 @@ Runtime.prototype._setInterval = function(fcn, interval) {
Runtime.prototype.start = function () {
this._setInterval(function() {
this._step();
+ if (self.renderer) {
+ self.renderer.draw();
+ }
}.bind(this), Runtime.THREAD_STEP_INTERVAL);
};
diff --git a/src/index.js b/src/index.js
index 08109c0a9..fff9c52db 100644
--- a/src/index.js
+++ b/src/index.js
@@ -24,6 +24,7 @@ function VirtualMachine () {
// @todo support multiple targets/sprites.
// This is just a demo/example.
var exampleSprite = new Sprite();
+ exampleSprite.createClone();
var exampleTargets = [exampleSprite.clones[0]];
instance.exampleSprite = exampleSprite;
instance.runtime = new Runtime(exampleTargets);
@@ -96,6 +97,10 @@ VirtualMachine.prototype.getPlaygroundData = function () {
* from a worker environment.
*/
if (ENV_WORKER) {
+ self.importScripts(
+ './node_modules/scratch-render-webgl/build/render-webgl-worker.js'
+ );
+ self.renderer = new self.RenderWebGLWorker();
self.vmInstance = new VirtualMachine();
self.onmessage = function (e) {
var messageData = e.data;
@@ -123,7 +128,11 @@ if (ENV_WORKER) {
});
break;
default:
- throw 'Unknown method' + messageData.method;
+ if (e.data.id == 'RendererConnected') {
+ //initRenderWorker();
+ }
+ self.renderer.onmessage(e);
+ break;
}
};
// Bind runtime's emitted events to postmessages.
diff --git a/src/sprites/clone.js b/src/sprites/clone.js
index afbd56f1c..f4f99abbe 100644
--- a/src/sprites/clone.js
+++ b/src/sprites/clone.js
@@ -3,9 +3,19 @@ var Target = require('../engine/target');
function Clone(spriteBlocks) {
Target.call(this, spriteBlocks);
+ this.drawableID = null;
+ this.initDrawable();
}
util.inherits(Clone, Target);
+Clone.prototype.initDrawable = function () {
+ var createPromise = self.renderer.createDrawable();
+ var instance = this;
+ createPromise.then(function (id) {
+ instance.drawableID = id;
+ });
+};
+
// Clone-level properties
Clone.prototype.x = 0;
@@ -13,4 +23,19 @@ Clone.prototype.y = 0;
Clone.prototype.direction = 90;
+Clone.prototype.setXY = function (x, y) {
+ this.x = x;
+ this.y = y;
+ self.renderer.updateDrawableProperties(this.drawableID, {
+ position: [this.x, this.y]
+ });
+};
+
+Clone.prototype.setDirection = function (direction) {
+ this.direction = direction;
+ self.renderer.updateDrawableProperties(this.drawableID, {
+ direction: this.direction
+ });
+};
+
module.exports = Clone;
diff --git a/src/sprites/sprite.js b/src/sprites/sprite.js
index 1608b0571..1ec25b3ba 100644
--- a/src/sprites/sprite.js
+++ b/src/sprites/sprite.js
@@ -9,9 +9,12 @@ function Sprite (blocks) {
}
this.blocks = blocks;
this.clones = [];
-
- // Initial single clone with the shared blocks.
- this.clones.push(new Clone(this.blocks));
}
+Sprite.prototype.createClone = function () {
+ var newClone = new Clone(this.blocks);
+ this.clones.push(newClone);
+ return newClone;
+};
+
module.exports = Sprite;