Add renderer demo using scratch-render-webgl

This commit is contained in:
Tim Mickel 2016-06-29 20:56:55 -04:00
parent 809528abdc
commit 19da0b0032
11 changed files with 155 additions and 8 deletions

View file

@ -16,7 +16,8 @@
"dependencies": { "dependencies": {
"htmlparser2": "3.9.0", "htmlparser2": "3.9.0",
"memoizee": "0.3.10", "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": { "devDependencies": {
"eslint": "2.7.0", "eslint": "2.7.0",

View file

@ -13,9 +13,14 @@
<button id="greenflag">Green flag</button> <button id="greenflag">Green flag</button>
<button id="stopall">Stop</button> <button id="stopall">Stop</button>
<p> <p>
<a id="renderexplorer-link" href="#">Renderer</a><br />
<a id="threadexplorer-link" href="#">VM Threads</a><br /> <a id="threadexplorer-link" href="#">VM Threads</a><br />
<a id="blockexplorer-link" href="#">VM Block Representation</a> <a id="blockexplorer-link" href="#">VM Block Representation</a>
</p> </p>
<div id="tab-renderexplorer">
Render<br />
<canvas id="scratch-stage" style="width: 480px; height: 360px;"></canvas>
</div>
<div id="tab-threadexplorer"> <div id="tab-threadexplorer">
Thread explorer Thread explorer
<pre id="threadexplorer"></pre> <pre id="threadexplorer"></pre>
@ -240,6 +245,54 @@
</value> </value>
</block> </block>
</category> </category>
<category name="Motion">
<block type="motion_movesteps">
<value name="STEPS">
<shadow type="math_number">
<field name="NUM">10</field>
</shadow>
</value>
</block>
<block type="motion_turnright">
<value name="DEGREES">
<shadow type="math_number">
<field name="NUM">15</field>
</shadow>
</value>
</block>
<block type="motion_turnleft">
<value name="DEGREES">
<shadow type="math_number">
<field name="NUM">15</field>
</shadow>
</value>
</block>
<block type="motion_pointindirection">
<value name="DIRECTION">
<shadow type="math_number">
<field name="NUM">90</field>
</shadow>
</value>
</block>
<block type="motion_pointtowards">
<value name="TOWARDS">
<shadow type="motion_pointtowards_menu">
</shadow>
</value>
</block>
<block type="motion_gotoxy">
<value name="X">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
<value name="Y">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
</block>
</category>
</xml> </xml>
<!-- Syntax highlighter --> <!-- Syntax highlighter -->
@ -249,6 +302,8 @@
<script src="../node_modules/scratch-blocks/blockly_compressed_vertical.js"></script> <script src="../node_modules/scratch-blocks/blockly_compressed_vertical.js"></script>
<script src="../node_modules/scratch-blocks/blocks_compressed.js"></script> <script src="../node_modules/scratch-blocks/blocks_compressed.js"></script>
<script src="../node_modules/scratch-blocks/blocks_compressed_vertical.js"></script> <script src="../node_modules/scratch-blocks/blocks_compressed_vertical.js"></script>
<!-- Renderer -->
<script src="../node_modules/scratch-render-webgl/build/render-webgl.js"></script>
<!-- VM Worker --> <!-- VM Worker -->
<script src="../vm.worker.js"></script> <script src="../vm.worker.js"></script>
<!-- Playground --> <!-- Playground -->

View file

@ -32,6 +32,6 @@ a {
font-size: 10pt; font-size: 10pt;
} }
#tab-blockexplorer { #tab-blockexplorer, #tab-threadexplorer {
display: none; display: none;
} }

View file

@ -3,6 +3,10 @@ window.onload = function() {
var vm = new window.VirtualMachine(); var vm = new window.VirtualMachine();
window.vm = vm; 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 toolbox = document.getElementById('toolbox');
var workspace = window.Blockly.inject('blocks', { var workspace = window.Blockly.inject('blocks', {
toolbox: toolbox, toolbox: toolbox,
@ -85,16 +89,25 @@ window.onload = function() {
var tabBlockExplorer = document.getElementById('tab-blockexplorer'); var tabBlockExplorer = document.getElementById('tab-blockexplorer');
var tabThreadExplorer = document.getElementById('tab-threadexplorer'); var tabThreadExplorer = document.getElementById('tab-threadexplorer');
var tabRenderExplorer = document.getElementById('tab-renderexplorer');
// Handlers to show different explorers. // Handlers to show different explorers.
document.getElementById('threadexplorer-link').addEventListener('click', document.getElementById('threadexplorer-link').addEventListener('click',
function () { function () {
tabBlockExplorer.style.display = 'none'; tabBlockExplorer.style.display = 'none';
tabRenderExplorer.style.display = 'none';
tabThreadExplorer.style.display = 'block'; tabThreadExplorer.style.display = 'block';
}); });
document.getElementById('blockexplorer-link').addEventListener('click', document.getElementById('blockexplorer-link').addEventListener('click',
function () { function () {
tabBlockExplorer.style.display = 'block'; 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'; tabThreadExplorer.style.display = 'none';
}); });
}; };

View file

@ -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.<string, Function>} 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;

View file

@ -31,7 +31,12 @@ Scratch3OperatorsBlocks.prototype.getPrimitives = function() {
}; };
Scratch3OperatorsBlocks.prototype.number = function (args) { 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) { Scratch3OperatorsBlocks.prototype.text = function (args) {

View file

@ -70,7 +70,8 @@ var execute = function (sequencer, thread) {
stackFrame: currentStackFrame.executionContext, stackFrame: currentStackFrame.executionContext,
startSubstack: function (substackNum) { startSubstack: function (substackNum) {
sequencer.stepToSubstack(thread, substackNum); sequencer.stepToSubstack(thread, substackNum);
} },
target: target
}); });
// Deal with any reported value. // Deal with any reported value.

View file

@ -6,6 +6,7 @@ var util = require('util');
var defaultBlockPackages = { var defaultBlockPackages = {
'scratch3_control': require('../blocks/scratch3_control'), 'scratch3_control': require('../blocks/scratch3_control'),
'scratch3_event': require('../blocks/scratch3_event'), 'scratch3_event': require('../blocks/scratch3_event'),
'scratch3_motion': require('../blocks/scratch3_motion'),
'scratch3_operators': require('../blocks/scratch3_operators') 'scratch3_operators': require('../blocks/scratch3_operators')
}; };
@ -257,6 +258,9 @@ Runtime.prototype._setInterval = function(fcn, interval) {
Runtime.prototype.start = function () { Runtime.prototype.start = function () {
this._setInterval(function() { this._setInterval(function() {
this._step(); this._step();
if (self.renderer) {
self.renderer.draw();
}
}.bind(this), Runtime.THREAD_STEP_INTERVAL); }.bind(this), Runtime.THREAD_STEP_INTERVAL);
}; };

View file

@ -24,6 +24,7 @@ function VirtualMachine () {
// @todo support multiple targets/sprites. // @todo support multiple targets/sprites.
// This is just a demo/example. // This is just a demo/example.
var exampleSprite = new Sprite(); var exampleSprite = new Sprite();
exampleSprite.createClone();
var exampleTargets = [exampleSprite.clones[0]]; var exampleTargets = [exampleSprite.clones[0]];
instance.exampleSprite = exampleSprite; instance.exampleSprite = exampleSprite;
instance.runtime = new Runtime(exampleTargets); instance.runtime = new Runtime(exampleTargets);
@ -96,6 +97,10 @@ VirtualMachine.prototype.getPlaygroundData = function () {
* from a worker environment. * from a worker environment.
*/ */
if (ENV_WORKER) { 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.vmInstance = new VirtualMachine();
self.onmessage = function (e) { self.onmessage = function (e) {
var messageData = e.data; var messageData = e.data;
@ -123,7 +128,11 @@ if (ENV_WORKER) {
}); });
break; break;
default: default:
throw 'Unknown method' + messageData.method; if (e.data.id == 'RendererConnected') {
//initRenderWorker();
}
self.renderer.onmessage(e);
break;
} }
}; };
// Bind runtime's emitted events to postmessages. // Bind runtime's emitted events to postmessages.

View file

@ -3,9 +3,19 @@ var Target = require('../engine/target');
function Clone(spriteBlocks) { function Clone(spriteBlocks) {
Target.call(this, spriteBlocks); Target.call(this, spriteBlocks);
this.drawableID = null;
this.initDrawable();
} }
util.inherits(Clone, Target); 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-level properties
Clone.prototype.x = 0; Clone.prototype.x = 0;
@ -13,4 +23,19 @@ Clone.prototype.y = 0;
Clone.prototype.direction = 90; 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; module.exports = Clone;

View file

@ -9,9 +9,12 @@ function Sprite (blocks) {
} }
this.blocks = blocks; this.blocks = blocks;
this.clones = []; 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; module.exports = Sprite;