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;