Merge branch 'LLK/master'

This commit is contained in:
Scimonster 2013-11-03 18:01:50 +02:00
commit ba40cd3396
24 changed files with 764 additions and 698 deletions

View file

@ -1,9 +1,16 @@
Scratch HTML5 Player
# Scratch HTML5 Player
This project aims to create a Scratch Player in HTML5. Scratch is currently implemented with Actionscript 3 and requires the Flash Player version 10.2. Since Flash does not run on iOS (iPads, iPods, etc) and newer Android devices, we would like to have an HTML5 version to display (but not edit) projects on mobile devices. Scratch projects played in the HTML5 player should look and behave as closely as possible to the way they look and behave when played by the Flash player. We will not be accepting pull requests for new features that don't already exist in the Flash based Scratch project player.
There are a few github issues created that represent some of the missing features. At this point, the HTML5 player is about 40% complete and can run some simple projects. Running the HTML5 player on your own website, or locally, you will need to have PHP so that the proxy.php file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
There are a few github issues created that represent some of the missing features. At this point, the HTML5 player is about 40% complete and can run some simple projects.
Unimplementable Features on iOS: Image effects for whirl, fisheye, mosaic, and pixelate. Sound and video input for loudness, video motion, and touching colors from the video.
More documentation will be added as time permits. Thanks for contributing, and Scratch On!
## Installation
Running the HTML5 player on your own website, or locally, you will need to have
PHP so that the `proxy.php` file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
See the file `TESTING.md` for more details.

45
TESTING.md Normal file
View file

@ -0,0 +1,45 @@
Running the HTML5 player on your own website, or locally, you will need to have
PHP so that the `proxy.php` file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
# Ubuntu
If you're using Ubuntu, you can follow the following steps to set up the proxy correctly. You'll need to type the following commands in Terminal.
Install PHP and Apache for running the proxy file:
$ sudo apt-get install apache2 php5
Fork this repository on Github, and then clone it into your home folder somewhere (replacing `<username>` with your Github username):
$ git clone https://github.com/<username>/scratch-html5
We'd like to add a new localhost domain, so that we can access the player from our web browser. Something like `scratch.localhost`. Run this command to edit the `/etc/hosts` file:
$ sudo nano /etc/hosts
Add the following line:
127.0.0.1 scratch.localhost
Use <key>Ctrl-O</key>, <key>Return</key>, <key>Ctrl-X</key> to quit.
Now we want to add a new Apache configuration for the new domain. Run the following:
$ cd /etc/apache2/sites-available/
$ sudo nano scratch
And type in the following, replacing `user` with your username, and making sure the `DocumentRoot` matches where you cloned the repository earlier:
<VirtualHost *:80>
ServerName scratch.localhost
DocumentRoot /home/user/scratch-html5
</VirtualHost>
Finally, run the following commands to enable the site:
$ sudo a2ensite scratch
$ sudo service apache2 reload
Now when you go to <http://scratch.localhost/>, the project should play. If you get a "Forbidden" error message, you may need to check the permissions of the folders that the player code is in.
Now you can go fix bugs in the HTML5 player!

View file

@ -55,14 +55,16 @@ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
};
// Pass in the cloud token for the project
if(window.getCloudToken)
if (window.getCloudToken) {
flashvars.cloud_token = encodeURIComponent(getCloudToken());
}
var params = {
allowscriptaccess: 'always',
allowfullscreen: 'false',
wmode: 'direct',
menu: 'false'};
menu: 'false'
};
var flashPlayer = null;
//var swf_url = "http://cdn.scratch.mit.edu/scratchr2/static/Scratch.swf";
@ -71,7 +73,7 @@ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
"http://cdn.scratch.mit.edu/scratchr2/static/expressInstall.swf",
flashvars, params, null, function(e) {
$('#flashScratch').css('visibility', 'visible');
if(e.success) flashPlayer = e.ref;
if (e.success) flashPlayer = e.ref;
});
$('#trigger_green_flag, #greenSlide').click(function() {
@ -104,7 +106,6 @@ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
</a>
</div>
</div>
<div id="info">Loading...</div>
<button id="trigger_green_flag">Green flag</button>

View file

@ -33,20 +33,18 @@ var IO = function() {
this.asset_suffix = '/get/';
this.soundbank_base = 'soundbank/';
this.spriteLayerCount = 0;
}
};
IO.prototype.loadProject = function(project_id) {
var runningIO = this;
$.getJSON(this.project_base + project_id + this.project_suffix,
function(data) {
$.getJSON(this.project_base + project_id + this.project_suffix, function(data) {
runningIO.data = data;
runningIO.makeObjects();
runningIO.loadThreads();
runningIO.loadNotesDrums();
runtime.loadStart(); // Try to run the project.
}
);
}
});
};
IO.prototype.soundRequest = function(sound, sprite) {
var request = new XMLHttpRequest();
@ -63,9 +61,9 @@ IO.prototype.soundRequest = function(sound, sprite) {
data[i] = samples[i];
}
sprite.soundsLoaded++;
}
};
request.send();
}
};
IO.prototype.loadNotesDrums = function() {
var self = this;
@ -81,10 +79,10 @@ IO.prototype.loadNotesDrums = function() {
var soundBuffer = waveData.readBytes(2 * info.sampleCount);
Instr.samples[name] = soundBuffer;
Instr.wavsLoaded++;
}
};
request.send();
});
}
};
IO.prototype.makeObjects = function() {
// Create the stage
@ -92,7 +90,6 @@ IO.prototype.makeObjects = function() {
runtime.stage.attach(runtime.scene);
runtime.stage.attachPenLayer(runtime.scene);
runtime.stage.loadSounds();
// Create the sprites and watchers
$.each(this.data.children.concat(this.data.lists), function i(index, obj) {
var newSprite;
@ -111,7 +108,7 @@ IO.prototype.makeObjects = function() {
if (!obj.cmd && !obj.listName)
newSprite.loadSounds();
});
}
};
IO.prototype.loadThreads = function() {
var target = runtime.stage;
@ -129,7 +126,7 @@ IO.prototype.loadThreads = function() {
});
}
});
}
};
// Returns the number sprite we are rendering
// used for initial layering assignment
@ -137,4 +134,4 @@ IO.prototype.getCount = function() {
var rv = this.spriteLayerCount;
this.spriteLayerCount++;
return rv;
}
};

View file

@ -30,7 +30,7 @@ var Block = function(opAndArgs, optionalSubstack) {
this.nextBlock = null;
this.tmp = -1;
interp.fixArgs(this);
}
};
var Thread = function(block, target) {
this.nextBlock = block; // next block to run; null when thread is finished
@ -40,7 +40,7 @@ var Thread = function(block, target) {
this.tmp = null; // used for thread operations like Timer
this.tmpObj = []; // used for Sprite operations like glide
this.firstTime = true;
}
};
var Interpreter = function() {
// Interpreter state
@ -54,7 +54,7 @@ var Interpreter = function() {
this.yield = false;
this.doRedraw = false;
this.opCount = 0; // used to benchmark the interpreter
}
};
// Utilities for building blocks and sequences of blocks
Interpreter.prototype.fixArgs = function(b) {
@ -66,7 +66,7 @@ Interpreter.prototype.fixArgs = function(b) {
if (arg && arg.constructor == Array) {
if ((arg.length > 0) && (arg[0].constructor == Array)) {
// if first element arg is itself an array, then arg is a substack
if(!b.substack) {
if (!b.substack) {
b.substack = this.makeBlockList(arg);
} else {
b.substack2 = this.makeBlockList(arg);
@ -80,7 +80,7 @@ Interpreter.prototype.fixArgs = function(b) {
}
}
b.args = newArgs;
}
};
Interpreter.prototype.makeBlockList = function(blockList) {
var firstBlock = null, lastBlock = null;
@ -91,7 +91,7 @@ Interpreter.prototype.makeBlockList = function(blockList) {
lastBlock = b;
}
return firstBlock;
}
};
// The Interpreter proper
Interpreter.prototype.stepThreads = function() {
@ -121,11 +121,11 @@ Interpreter.prototype.stepThreads = function() {
}
this.currentMSecs = this.timer.time();
}
}
};
Interpreter.prototype.stepActiveThread = function() {
// Run the active thread until it yields.
if(typeof(this.activeThread) == 'undefined') {
if (typeof(this.activeThread) == 'undefined') {
return;
}
var b = this.activeThread.nextBlock;
@ -149,7 +149,7 @@ Interpreter.prototype.stepActiveThread = function() {
}
}
}
}
};
Interpreter.prototype.toggleThread = function(b, targetObj) {
var newThreads = [], wasRunning = false;
@ -161,15 +161,15 @@ Interpreter.prototype.toggleThread = function(b, targetObj) {
}
}
this.threads = newThreads;
if(!wasRunning) {
if (!wasRunning) {
this.startThread(b, targetObj);
}
}
}
Interpreter.prototype.startThread = function(b, targetObj) {
this.activeThread = new Thread(b, targetObj);
this.threads.push(this.activeThread);
}
};
Interpreter.prototype.restartThread = function(b, targetObj) {
// used by broadcast; stop any thread running on b, then start a new thread on b
@ -184,7 +184,7 @@ Interpreter.prototype.restartThread = function(b, targetObj) {
if (!wasRunning) {
this.threads.push(newThread);
}
}
};
Interpreter.prototype.arg = function(block, index) {
var arg = block.args[index];
@ -193,11 +193,11 @@ Interpreter.prototype.arg = function(block, index) {
return arg.primFcn(arg); // expression
}
return arg;
}
};
Interpreter.prototype.targetSprite = function() {
return this.activeThread.target;
}
};
// Timer
Interpreter.prototype.startTimer = function(secs) {
@ -206,7 +206,7 @@ Interpreter.prototype.startTimer = function(secs) {
this.activeThread.tmp = this.currentMSecs + waitMSecs; // end time in milliseconds
this.activeThread.firstTime = false;
this.yield = true;
}
};
Interpreter.prototype.checkTimer = function() {
// check for timer expiration and clean up if expired. return true when expired
@ -219,11 +219,11 @@ Interpreter.prototype.checkTimer = function() {
this.yield = true;
return false;
}
}
};
Interpreter.prototype.redraw = function() {
this.doRedraw = true;
}
};
// Primitive operations
Interpreter.prototype.initPrims = function() {
@ -231,14 +231,14 @@ Interpreter.prototype.initPrims = function() {
this.primitiveTable['whenGreenFlag'] = this.primNoop;
this.primitiveTable['whenKeyPressed'] = this.primNoop;
this.primitiveTable['whenClicked'] = this.primNoop;
this.primitiveTable['if'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b) };
this.primitiveTable['doForever'] = function(b) { interp.startSubstack(b, true) };
this.primitiveTable['if'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b); };
this.primitiveTable['doForever'] = function(b) { interp.startSubstack(b, true); };
this.primitiveTable['doForeverIf'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b, true); else interp.yield = true; };
this.primitiveTable['doIf'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b); };
this.primitiveTable['doRepeat'] = this.primRepeat;
this.primitiveTable['doIfElse'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b); else interp.startSubstack(b, false, true); };
this.primitiveTable['doWaitUntil'] = function(b) { if (!interp.arg(b, 0)) interp.yield = true };
this.primitiveTable['doUntil'] = function(b) { if (!interp.arg(b, 0)) interp.startSubstack(b, true) };
this.primitiveTable['doWaitUntil'] = function(b) { if (!interp.arg(b, 0)) interp.yield = true; };
this.primitiveTable['doUntil'] = function(b) { if (!interp.arg(b, 0)) interp.startSubstack(b, true); };
this.primitiveTable['doReturn'] = function(b) { interp.activeThread = new Thread(null); };
this.primitiveTable['stopAll'] = function(b) { interp.activeThread = new Thread(null); interp.threads = []; }
this.primitiveTable['whenIReceive'] = this.primNoop;
@ -247,26 +247,26 @@ Interpreter.prototype.initPrims = function() {
this.primitiveTable['wait:elapsed:from:'] = this.primWait;
// added by John:
this.primitiveTable['showBubble'] = function(b) { console.log(interp.arg(b, 1)) }
this.primitiveTable['timerReset'] = function(b) {interp.timerBase = (new Date()).getTime() }
this.primitiveTable['timer'] = function(b) {return ((new Date()).getTime() - interp.timerBase) / 1000 }
this.primitiveTable['showBubble'] = function(b) { console.log(interp.arg(b, 1)); };
this.primitiveTable['timerReset'] = function(b) { interp.timerBase = Date.now(); };
this.primitiveTable['timer'] = function(b) { return (Date.now() - interp.timerBase) / 1000; };
new Primitives().addPrimsTo(this.primitiveTable);
}
};
Interpreter.prototype.timerBase = (new Date()).getTime();
Interpreter.prototype.timerBase = Date.now();
Interpreter.prototype.lookupPrim = function(op) {
var fcn = interp.primitiveTable[op];
if (fcn == null) fcn = function(b) { console.log('not implemented: ' + b.op) }
if (fcn == null) fcn = function(b) { console.log('not implemented: ' + b.op); };
return fcn;
}
};
Interpreter.prototype.primNoop = function(b) { console.log(b.op); }
Interpreter.prototype.primNoop = function(b) { console.log(b.op); };
Interpreter.prototype.primWait = function(b) {
if (interp.activeThread.firstTime) interp.startTimer(interp.arg(b, 0));
else interp.checkTimer();
}
};
Interpreter.prototype.primRepeat = function(b) {
if (b.tmp == -1) {
@ -280,14 +280,14 @@ Interpreter.prototype.primRepeat = function(b) {
b.tmp = -1;
b = null;
}
}
};
Interpreter.prototype.broadcast = function(b, waitFlag) {
var pair;
if (interp.activeThread.firstTime) {
var receivers = [];
var msg = String(interp.arg(b, 0)).toLowerCase();
var findReceivers = function (stack, target) {
var findReceivers = function(stack, target) {
if ((stack.op == "whenIReceive") && (stack.args[0].toLowerCase() == msg)) {
receivers.push([stack, target]);
}
@ -310,7 +310,7 @@ Interpreter.prototype.broadcast = function(b, waitFlag) {
} else {
interp.yield = true;
}
}
};
Interpreter.prototype.isRunning = function(b) {
for (t in interp.threads) {
@ -319,7 +319,7 @@ Interpreter.prototype.isRunning = function(b) {
}
}
return false;
}
};
Interpreter.prototype.startSubstack = function(b, isLoop, secondSubstack) {
// Start the substack of a control structure command such as if or forever.
@ -327,9 +327,9 @@ Interpreter.prototype.startSubstack = function(b, isLoop, secondSubstack) {
b.isLoop = true;
this.activeThread.stack.push(b); // remember the block that started the substack
}
if(!secondSubstack) {
if (!secondSubstack) {
this.activeThread.nextBlock = b.substack;
} else {
this.activeThread.nextBlock = b.substack2;
}
}
};

View file

@ -33,7 +33,7 @@ var Reporter = function(data) {
this.el = null; // jQuery Element for the outer box
this.valueEl = null; // jQ element containing the reporter value
this.slider = null; // slider jQ element
}
};
Reporter.prototype.attach = function(scene) {
switch (this.mode) {
@ -68,13 +68,13 @@ Reporter.prototype.attach = function(scene) {
this.valueEl.css('background-color', 'rgb(' + cR + ',' + cG + ',' + cB + ')');
this.el.css('display', this.visible ? 'inline-block' : 'none');
scene.append(this.el);
}
};
Reporter.prototype.update = function() {
this.el.css('display', this.visible ? 'inline-block' : 'none');
if (!this.visible) return;
var newValue ='';
var newValue = '';
var target = runtime.spriteNamed(this.target);
switch (this.cmd) {
case 'getVar:':
@ -104,20 +104,21 @@ Reporter.prototype.update = function() {
break;
}
this.valueEl.html(newValue);
if (this.mode == 3)
if (this.mode == 3) {
this.slider.val(parseInt(newValue));
}
}
};
Reporter.prototype.updateLayer = function() {
this.el.css('z-index', this.z);
}
};
Reporter.prototype.changeSlider = function() {
var newValue = parseInt($(this).val());
var target = runtime.spriteNamed($(this).attr('data-target'));
var variable = $(this).attr('data-var');
target.variables[variable] = newValue;
}
};
var List = function(data) {
this.contents = data.contents;
@ -171,7 +172,7 @@ List.prototype.attach = function(scene) {
this.el.height(this.height);
this.el.css('z-index', this.z);
this.el.css('display', this.visible ? 'inline-block' : 'none');
}
};
List.prototype.update = function(){
this.el.css('display', this.visible ? 'inline-block' : 'none');
@ -191,4 +192,4 @@ List.prototype.update = function(){
List.prototype.updateLayer = function() {
this.el.css('z-index', this.z);
}
};

View file

@ -35,7 +35,7 @@ var Runtime = function() {
this.audioPlaying = [];
this.notesPlaying = [];
this.projectLoaded = false;
}
};
// Initializer for the drawing and audio contexts.
Runtime.prototype.init = function() {
@ -44,7 +44,7 @@ Runtime.prototype.init = function() {
this.audioContext = new AudioContext();
this.audioGain = this.audioContext.createGainNode();
this.audioGain.connect(runtime.audioContext.destination);
}
};
// Load start waits for the stage and the sprites to be loaded, without
// hanging the browser. When the loading is finished, we begin the step
@ -69,7 +69,7 @@ Runtime.prototype.loadStart = function() {
$('#info').html("Loaded!");
setInterval(this.step, 33);
this.projectLoaded = true;
}
};
Runtime.prototype.greenFlag = function() {
if (this.projectLoaded) {
@ -78,7 +78,7 @@ Runtime.prototype.greenFlag = function() {
interp.primitiveTable.timerReset();
this.startGreenFlags();
}
}
};
Runtime.prototype.stopAll = function() {
interp.activeThread = new Thread(null);
@ -86,10 +86,11 @@ Runtime.prototype.stopAll = function() {
stopAllSounds();
// Hide reporters
for (var s = 0; s < runtime.sprites.length; s++) {
if (typeof runtime.sprites[s].hideBubble == 'function')
if (typeof runtime.sprites[s].hideBubble == 'function') {
runtime.sprites[s].hideBubble();
}
}
}
};
// Step method for execution - called every 33 milliseconds
Runtime.prototype.step = function() {
@ -97,7 +98,7 @@ Runtime.prototype.step = function() {
for (var r = 0; r < runtime.reporters.length; r++) {
runtime.reporters[r].update();
}
}
};
// Stack functions -- push and remove stacks
// to be run by the interpreter as threads.
@ -106,7 +107,7 @@ Runtime.prototype.allStacksDo = function(f) {
var stack;
for (var i = runtime.sprites.length-1; i >= 0; i--) {
var o = runtime.sprites[i];
if(typeof(o) == 'object' && o.constructor == Sprite) {
if (typeof(o) == 'object' && o.constructor == Sprite) {
$.each(o.stacks, function(index, stack) {
f(stack, o);
});
@ -115,7 +116,7 @@ Runtime.prototype.allStacksDo = function(f) {
$.each(stage.stacks, function(index, stack) {
f(stack, stage);
});
}
};
// Hat triggers
Runtime.prototype.startGreenFlags = function() {
@ -123,7 +124,7 @@ Runtime.prototype.startGreenFlags = function() {
if (stack.op == 'whenGreenFlag') interp.toggleThread(stack, target);
}
this.allStacksDo(startIfGreenFlag);
}
};
Runtime.prototype.startKeyHats = function(ch) {
var keyName = null;
@ -140,30 +141,30 @@ Runtime.prototype.startKeyHats = function(ch) {
if (ch == 32) keyName = "space";
if (keyName == null) return;
var startMatchingKeyHats = function (stack, target) {
var startMatchingKeyHats = function(stack, target) {
if ((stack.op == "whenKeyPressed") && (stack.args[0] == keyName)) {
// Only start the stack if it is not already running
if (!interp.isRunning(stack))
if (!interp.isRunning(stack)) {
interp.toggleThread(stack, target);
}
}
}
runtime.allStacksDo(startMatchingKeyHats);
}
};
Runtime.prototype.startClickedHats = function(sprite) {
function startIfClicked(stack, target) {
if(target == sprite && stack.op == "whenClicked") {
if(!interp.isRunning(stack))
if (target == sprite && stack.op == "whenClicked" && !interp.isRunning(stack)) {
interp.toggleThread(stack, target);
}
}
runtime.allStacksDo(startIfClicked);
}
};
// Returns true if a key is pressed.
Runtime.prototype.keyIsDown = function(ch) {
return this.keysDown[ch] || false;
}
};
// Sprite named -- returns one of the sprites on the stage.
Runtime.prototype.spriteNamed = function(n) {
@ -176,7 +177,22 @@ Runtime.prototype.spriteNamed = function(n) {
}
});
return selected_sprite;
}
};
Runtime.prototype.getTimeString = function(which) {
// Return local time properties.
var now = new Date();
switch (which) {
case 'hour': return now.getHours();
case 'minute': return now.getMinutes();
case 'second': return now.getSeconds();
case 'year': return now.getFullYear(); // four digit year (e.g. 2012)
case 'month': return now.getMonth() + 1; // 1-12
case 'date': return now.getDate(); // 1-31
case 'day of week': return now.getDay() + 1; // 1-7, where 1 is Sunday
}
return ''; // shouldn't happen
};
// Reassigns z-indices for layer functions
Runtime.prototype.reassignZ = function(target, move) {
@ -193,7 +209,7 @@ Runtime.prototype.reassignZ = function(target, move) {
if (move == null) {
// Move to the front
this.sprites.splice(this.sprites.length, 0, target);
} else if (oldIndex - move >= 0 && oldIndex - move < this.sprites.length+1) {
} else if (oldIndex - move >= 0 && oldIndex - move < this.sprites.length + 1) {
// Move to the new position
this.sprites.splice(oldIndex - move, 0, target);
} else {
@ -208,4 +224,4 @@ Runtime.prototype.reassignZ = function(target, move) {
sprite.updateLayer();
newZ++;
});
}
};

View file

@ -23,7 +23,7 @@
'use strict';
var runtime, interp, io, iosAudioActive = false;
$(function () {
$(function() {
runtime = new Runtime();
runtime.init();

View file

@ -22,12 +22,12 @@
'use strict';
var Sprite = function(data) {
if(!this.data) {
if (!this.data) {
this.data = data;
}
// Public variables used for Scratch-accessible data.
this.visible = (typeof(this.data.visible) == "undefined") ? true : data.visible;
this.visible = typeof(this.data.visible) == "undefined" ? true : data.visible;
this.scratchX = data.scratchX || 0;
this.scratchY = data.scratchY || 0;
@ -94,7 +94,7 @@ var Sprite = function(data) {
// Stacks to be pushed to the interpreter and run
this.stacks = [];
}
};
// Attaches a Sprite (<img>) to a Scratch scene
Sprite.prototype.attach = function(scene) {
@ -109,7 +109,7 @@ Sprite.prototype.attach = function(scene) {
sprite.costumesLoaded += 1;
sprite.updateCostume();
$(sprite.textures[c]).css('display', (sprite.currentCostumeIndex == c) ? 'inline' : 'none');
$(sprite.textures[c]).css('display', sprite.currentCostumeIndex == c ? 'inline' : 'none');
$(sprite.textures[c]).css('position', 'absolute').css('left', '0px').css('top', '0px');
$(sprite.textures[c]).bind('dragstart', function(evt) { evt.preventDefault(); })
.bind('selectstart', function(evt) { evt.preventDefault(); })
@ -139,21 +139,20 @@ Sprite.prototype.attach = function(scene) {
this.talkBubble.append(this.talkBubbleStyler);
runtime.scene.append(this.talkBubble);
}
};
// Load sounds from the server and buffer them
Sprite.prototype.loadSounds = function() {
var spr = this;
$.each(this.sounds, function (index, sound) {
$.each(this.sounds, function(index, sound) {
io.soundRequest(sound, spr);
});
}
};
// True when all the costumes have been loaded
Sprite.prototype.isLoaded = function() {
return (this.costumesLoaded == this.costumes.length
&& this.soundsLoaded == Object.keys(this.sounds).length);
}
return this.costumesLoaded == this.costumes.length && this.soundsLoaded == Object.keys(this.sounds).length;
};
// Step methods
Sprite.prototype.showCostume = function(costume) {
@ -167,33 +166,33 @@ Sprite.prototype.showCostume = function(costume) {
this.currentCostumeIndex = costume;
}
this.updateCostume();
}
};
Sprite.prototype.indexOfCostumeNamed = function(name) {
for(var i in this.costumes) {
for (var i in this.costumes) {
var c = this.costumes[i];
if(c['costumeName'] == name) {
if (c['costumeName'] == name) {
return i;
}
}
return null;
}
};
Sprite.prototype.showCostumeNamed = function(name) {
var index = this.indexOfCostumeNamed(name);
if(!index) return;
if (!index) return;
this.showCostume(index);
}
};
Sprite.prototype.updateCostume = function() {
if(!this.textures[this.currentCostumeIndex]) {
if (!this.textures[this.currentCostumeIndex]) {
this.currentCostumeIndex = 0;
}
$(this.mesh).css('display', 'none');
this.mesh = this.textures[this.currentCostumeIndex];
this.updateVisible();
this.updateTransform();
}
};
Sprite.prototype.onClick = function(evt) {
// TODO - needs work!!
@ -238,23 +237,24 @@ Sprite.prototype.onClick = function(evt) {
$(underElement).click();
$(this.mesh).show();
}
}
};
Sprite.prototype.setVisible = function(v) {
this.visible = v;
this.updateVisible();
}
};
Sprite.prototype.updateLayer = function() {
$(this.mesh).css('z-index', this.z);
if (this.talkBubble) this.talkBubble.css('z-index', this.z);
}
};
Sprite.prototype.updateVisible = function() {
$(this.mesh).css('display', (this.visible) ? 'inline' : 'none');
if (this.talkBubbleOn)
this.talkBubble.css('display', (this.visible) ? 'inline-block' : 'none');
}
$(this.mesh).css('display', this.visible ? 'inline' : 'none');
if (this.talkBubbleOn) {
this.talkBubble.css('display', this.visible ? 'inline-block' : 'none');
}
};
Sprite.prototype.updateTransform = function() {
var texture = this.textures[this.currentCostumeIndex];
@ -305,7 +305,7 @@ Sprite.prototype.updateTransform = function() {
}
this.updateLayer();
}
};
Sprite.prototype.getTalkBubbleXY = function() {
var texture = this.textures[this.currentCostumeIndex];
@ -316,7 +316,7 @@ Sprite.prototype.getTalkBubbleXY = function() {
var drawX = this.scratchX + (480 / 2) - rotationCenterX;
var drawY = -this.scratchY + (360 / 2) - rotationCenterY;
return [drawX + drawWidth, drawY - drawHeight / 2];
}
};
Sprite.prototype.showBubble = function(text, type) {
var xy = this.getTalkBubbleXY();
@ -329,30 +329,34 @@ Sprite.prototype.showBubble = function(text, type) {
this.talkBubbleStyler.removeClass('bubble-say');
this.talkBubbleStyler.removeClass('bubble-think');
if (type == 'say') this.talkBubbleStyler.addClass('bubble-say');
else if (type == 'think') this.talkBubbleStyler.addClass('bubble-think');
if (type == 'say') {
this.talkBubbleStyler.addClass('bubble-say');
} else if (type == 'think') {
this.talkBubbleStyler.addClass('bubble-think');
}
if (this.visible)
if (this.visible) {
this.talkBubble.css('display', 'inline-block');
}
this.talkBubbleBox.html(text);
}
};
Sprite.prototype.hideBubble = function() {
this.talkBubbleOn = false;
this.talkBubble.css('display', 'none');
}
};
Sprite.prototype.setXY = function(x, y) {
this.scratchX = x;
this.scratchY = y;
this.updateTransform();
}
};
Sprite.prototype.setDirection = function(d) {
var rotation;
d = d % 360
if (d < 0) d += 360;
this.direction = (d > 180) ? d - 360 : d;
this.direction = d > 180 ? d - 360 : d;
if (this.rotationStyle == 'normal') {
rotation = (this.direction - 90) % 360;
} else if (this.rotationStyle == 'leftRight') {
@ -367,22 +371,22 @@ Sprite.prototype.setDirection = function(d) {
}
this.rotation = rotation;
this.updateTransform();
}
};
Sprite.prototype.setRotationStyle = function(r) {
this.rotationStyle = r;
}
};
Sprite.prototype.getSize = function() {
return this.scale * 100;
}
};
Sprite.prototype.setSize = function(percent) {
var newScale = percent / 100.0;
newScale = Math.max(0.05, Math.min(newScale, 100));
this.scale = newScale;
this.updateTransform();
}
};
// Move functions
Sprite.prototype.keepOnStage = function() {
@ -398,7 +402,7 @@ Sprite.prototype.keepOnStage = function() {
if (myBox.top > edgeBox.bottom) y -= myBox.top - edgeBox.bottom;
this.scratchX = x - 240;
this.scratchY = 180 - y;
}
};
Sprite.prototype.getRect = function() {
var cImg = this.textures[this.currentCostumeIndex];
@ -406,7 +410,7 @@ Sprite.prototype.getRect = function() {
var y = 180 - this.scratchY - (cImg.height/2.0);
var myBox = new Rectangle(x, y, cImg.width, cImg.height);
return myBox;
}
};
// Pen functions
Sprite.prototype.setPenColor = function(c) {
@ -414,26 +418,29 @@ Sprite.prototype.setPenColor = function(c) {
this.penHue = (200 * hsv[0]) / 360 ;
this.penShade = 50 * hsv[2]; // not quite right; doesn't account for saturation
this.penColorCache = c;
}
};
Sprite.prototype.setPenHue = function(n) {
this.penHue = n % 200;
if (this.penHue < 0) this.penHue += 200;
this.updateCachedPenColor();
}
};
Sprite.prototype.setPenShade = function(n) {
this.penShade = n % 200;
if (this.penShade < 0) this.penShade += 200;
this.updateCachedPenColor();
}
};
Sprite.prototype.updateCachedPenColor = function() {
var c = Color.fromHSV((this.penHue * 180.0) / 100.0, 1, 1);
var shade = (this.penShade > 100) ? 200 - this.penShade : this.penShade; // range 0..100
var shade = this.penShade > 100 ? 200 - this.penShade : this.penShade; // range 0..100
if (shade < 50) {
this.penColorCache = Color.mixRGB(0, c, (10 + shade) / 60.0);
} else {
this.penColorCache = Color.mixRGB(c, 0xFFFFFF, (shade - 50) / 60);
}
}
};
Sprite.prototype.stamp = function(canvas, opacity) {
var drawWidth = this.textures[this.currentCostumeIndex].width * this.scale;
@ -447,12 +454,13 @@ Sprite.prototype.stamp = function(canvas, opacity) {
canvas.drawImage(this.mesh, -drawWidth/2, -drawHeight/2, drawWidth, drawHeight);
canvas.restore();
canvas.globalAlpha = 1;
}
};
Sprite.prototype.soundNamed = function(name) {
if (name in this.sounds && this.sounds[name].buffer)
if (name in this.sounds && this.sounds[name].buffer) {
return this.sounds[name];
else if (name in runtime.stage.sounds && runtime.stage.sounds[name].buffer)
} else if (name in runtime.stage.sounds && runtime.stage.sounds[name].buffer) {
return runtime.stage.sounds[name];
}
return null;
}
};

View file

@ -35,30 +35,27 @@ var Stage = function(data) {
this.lineCache = this.lineCanvas.getContext('2d');
Sprite.call(this, data);
}
};
Stage.prototype = Object.create(Sprite.prototype);
Stage.prototype.constructor = Stage;
Stage.prototype.attachPenLayer = function(scene) {
if (this.penLayerLoaded)
return;
if (this.penLayerLoaded) return;
this.penLayerLoaded = true;
$(this.lineCanvas).css('position', 'absolute');
$(this.lineCanvas).css('z-index', '-1');
scene.append(this.lineCanvas);
}
};
Stage.prototype.isLoaded = function() {
return (this.penLayerLoaded
&& this.costumesLoaded == this.costumes.length
&& this.soundsLoaded == Object.keys(this.sounds).length);
}
return this.penLayerLoaded && this.costumesLoaded == this.costumes.length && this.soundsLoaded == Object.keys(this.sounds).length;
};
// Pen functions
Stage.prototype.clearPenStrokes = function() {
this.lineCache.clearRect(0, 0, 480, 360);
}
};
Stage.prototype.stroke = function(from, to, width, color) {
this.lineCache.lineWidth = width;
@ -69,4 +66,4 @@ Stage.prototype.stroke = function(from, to, width, color) {
this.lineCache.lineTo(to[0] + 240.5, 180.5 - to[1]);
this.lineCache.strokeStyle = 'rgb(' + (color >> 16) + ',' + (color >> 8 & 255) + ',' + (color & 255) + ')';
this.lineCache.stroke();
}
};

View file

@ -15,7 +15,7 @@
'use strict';
var LooksPrims = function() {}
var LooksPrims = function() {};
LooksPrims.prototype.addPrimsTo = function(primTable) {
primTable["show"] = this.primShow;
@ -47,22 +47,22 @@ LooksPrims.prototype.addPrimsTo = function(primTable) {
primTable["say:duration:elapsed:from:"] = function(b) { showBubbleAndWait(b, 'say'); };
primTable["think:"] = function(b) { showBubble(b, 'think'); };
primTable["think:duration:elapsed:from:"] = function(b) { showBubbleAndWait(b, 'think'); };
}
};
LooksPrims.prototype.primShow = function(b) {
interp.targetSprite().setVisible(true);
interp.redraw();
}
};
LooksPrims.prototype.primHide = function(b) {
interp.targetSprite().setVisible(false);
interp.redraw();
}
};
LooksPrims.prototype.primNextCostume = function(b) {
interp.targetSprite().showCostume(interp.targetSprite().currentCostumeIndex + 1);
interp.redraw();
}
};
LooksPrims.prototype.primShowCostume = function(b) {
var s = interp.targetSprite();
@ -88,7 +88,7 @@ LooksPrims.prototype.primShowCostume = function(b) {
}
}
if (s.visible) interp.redraw();
}
};
LooksPrims.prototype.primStartScene = function(b) {
var s = runtime.stage;
@ -113,55 +113,55 @@ LooksPrims.prototype.primStartScene = function(b) {
}
}
if (s.visible) interp.redraw();
}
};
LooksPrims.prototype.primCostumeNum = function(b) {
var s = interp.targetSprite();
return (s == null) ? 1 : s.currentCostumeIndex + 1;
}
return s == null ? 1 : s.currentCostumeIndex + 1;
};
LooksPrims.prototype.primChangeSize = function(b) {
var s = interp.targetSprite();
if (s == null) return;
s.setSize(s.getSize() + interp.arg(b, 0));
if (s.visible) interp.redraw();
}
};
LooksPrims.prototype.primSetSize = function(b) {
var s = interp.targetSprite();
if (s == null) return;
s.setSize(interp.arg(b, 0));
if (s.visible) interp.redraw();
}
};
LooksPrims.prototype.primSize = function(b) {
var s = interp.targetSprite();
if (s == null) return 100;
return s.getSize();
}
};
LooksPrims.prototype.primGoFront = function(b) {
var s = interp.targetSprite();
runtime.reassignZ(s, null);
if(s.visible) interp.redraw();
}
if (s.visible) interp.redraw();
};
LooksPrims.prototype.primGoBack = function(b) {
var s = interp.targetSprite();
runtime.reassignZ(s, interp.arg(b, 0));
if(s.visible) interp.redraw();
}
if (s.visible) interp.redraw();
};
LooksPrims.prototype.primChangeEffect = function(b) {}
LooksPrims.prototype.primChangeEffect = function(b) {};
LooksPrims.prototype.primSetEffect = function(b) {}
LooksPrims.prototype.primSetEffect = function(b) {};
LooksPrims.prototype.primClearEffects = function(b) {}
LooksPrims.prototype.primClearEffects = function(b) {};
var showBubble = function(b, type) {
var s = interp.targetSprite();
if (s != null) s.showBubble(interp.arg(b, 0), type);
}
};
var showBubbleAndWait = function(b, type) {
var s = interp.targetSprite();
@ -175,4 +175,4 @@ var showBubbleAndWait = function(b, type) {
} else {
if (interp.checkTimer()) s.hideBubble();
}
}
};

View file

@ -15,7 +15,7 @@
'use strict';
var MotionAndPenPrims = function() {}
var MotionAndPenPrims = function() {};
MotionAndPenPrims.prototype.addPrimsTo = function(primTable) {
primTable['forward:'] = this.primMove;
@ -52,60 +52,59 @@ MotionAndPenPrims.prototype.addPrimsTo = function(primTable) {
primTable["stampCostume"] = this.primStamp;
primTable["stampTransparent"] = this.primStampTransparent;
}
};
MotionAndPenPrims.prototype.primMove = function(b) {
var s = interp.targetSprite();
var radians = ((Math.PI * (90 - s.direction)) / 180);
var radians = (90 - s.direction) * Math.PI / 180;
var d = interp.arg(b, 0);
moveSpriteTo(s, s.scratchX + (d * Math.cos(radians)),
s.scratchY + (d * Math.sin(radians)));
if(s.visible) interp.redraw();
}
moveSpriteTo(s, s.scratchX + d * Math.cos(radians), s.scratchY + d * Math.sin(radians));
if (s.visible) interp.redraw();
};
MotionAndPenPrims.prototype.primTurnLeft = function(b) {
var s = interp.targetSprite();
var d = s.direction - interp.arg(b, 0);
s.setDirection(d);
if(s.visible) interp.redraw();
}
if (s.visible) interp.redraw();
};
MotionAndPenPrims.prototype.primTurnRight = function(b) {
var s = interp.targetSprite();
var d = s.direction + interp.arg(b, 0);
s.setDirection(d);
if(s.visible) interp.redraw();
}
if (s.visible) interp.redraw();
};
MotionAndPenPrims.prototype.primSetDirection = function(b) {
var s = interp.targetSprite();
s.setDirection(interp.arg(b, 0));
if(s.visible) interp.redraw();
}
if (s.visible) interp.redraw();
};
MotionAndPenPrims.prototype.primPointTowards = function(b) {
var s = interp.targetSprite();
var p = mouseOrSpritePosition(interp.arg(b, 0));
if ((s == null) || (p == null)) return;
if (s == null || p == null) return;
var dx = p.x - s.scratchX;
var dy = p.y - s.scratchY;
var angle = 90 - ((Math.atan2(dy, dx) * 180) / Math.PI);
var angle = 90 - Math.atan2(dy, dx) * 180 / Math.PI;
s.setDirection(angle);
if (s.visible) interp.redraw();
}
};
MotionAndPenPrims.prototype.primGoTo = function(b) {
var s = interp.targetSprite();
if (s != null) moveSpriteTo(s, interp.arg(b, 0), interp.arg(b, 1));
}
};
MotionAndPenPrims.prototype.primGoToSpriteOrMouse = function(b) {
var s = interp.targetSprite();
var p = mouseOrSpritePosition(interp.arg(b, 0));
if ((s == null) || (p == null)) return;
if (s == null || p == null) return;
moveSpriteTo(s, p.x, p.y);
}
};
MotionAndPenPrims.prototype.primGlide = function(b) {
var s = interp.targetSprite();
@ -119,16 +118,15 @@ MotionAndPenPrims.prototype.primGlide = function(b) {
return;
}
// record state: [0]start msecs, [1]duration, [2]startX, [3]startY, [4]endX, [5]endY
interp.activeThread.tmpObj =
[interp.currentMSecs, 1000 * secs, s.scratchX, s.scratchY, destX, destY];
interp.activeThread.tmpObj = [interp.currentMSecs, 1000 * secs, s.scratchX, s.scratchY, destX, destY];
interp.startTimer(secs);
} else {
var state = interp.activeThread.tmpObj;
if (!interp.checkTimer()) {
// in progress: move to intermediate position along path
var frac = (interp.currentMSecs - state[0]) / state[1];
var newX = state[2] + (frac * (state[4] - state[2]));
var newY = state[3] + (frac * (state[5] - state[3]));
var newX = state[2] + frac * (state[4] - state[2]);
var newY = state[3] + frac * (state[5] - state[3]);
moveSpriteTo(s, newX, newY);
} else {
// finished: move to final position and clear state
@ -136,27 +134,27 @@ MotionAndPenPrims.prototype.primGlide = function(b) {
interp.activeThread.tmpObj = null;
}
}
}
};
MotionAndPenPrims.prototype.primChangeX = function(b) {
var s = interp.targetSprite();
if (s != null) moveSpriteTo(s, s.scratchX + interp.arg(b, 0), s.scratchY);
}
};
MotionAndPenPrims.prototype.primSetX = function(b) {
var s = interp.targetSprite();
if (s != null) moveSpriteTo(s, interp.arg(b, 0), s.scratchY);
}
};
MotionAndPenPrims.prototype.primChangeY = function(b) {
var s = interp.targetSprite();
if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primSetY = function(b) {
var s = interp.targetSprite();
if (s != null) moveSpriteTo(s, s.scratchX, interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primBounceOffEdge = function(b) {
var s = interp.targetSprite();
@ -164,7 +162,7 @@ MotionAndPenPrims.prototype.primBounceOffEdge = function(b) {
if (!turnAwayFromEdge(s)) return;
ensureOnStageOnBounce(s);
if (s.visible) interp.redraw();
}
};
MotionAndPenPrims.prototype.primSetRotationStyle = function(b) {
var s = interp.targetSprite();
@ -175,95 +173,94 @@ MotionAndPenPrims.prototype.primSetRotationStyle = function(b) {
else if (request == 'left-right') rotationStyle = 'leftRight';
else if (request == 'none') rotationStyle = 'none';
s.setRotationStyle(rotationStyle);
}
};
MotionAndPenPrims.prototype.primXPosition = function(b) {
var s = interp.targetSprite();
return (s != null) ? s.scratchX : 0;
}
return s != null ? s.scratchX : 0;
};
MotionAndPenPrims.prototype.primYPosition = function(b) {
var s = interp.targetSprite();
return (s != null) ? s.scratchY : 0;
}
return s != null ? s.scratchY : 0;
};
MotionAndPenPrims.prototype.primDirection = function(b) {
var s = interp.targetSprite();
return (s != null) ? s.direction : 0;
}
return s != null ? s.direction : 0;
};
MotionAndPenPrims.prototype.primClear = function(b) {
runtime.stage.clearPenStrokes();
interp.redraw();
}
};
MotionAndPenPrims.prototype.primPenDown = function(b) {
var s = interp.targetSprite();
if (s != null) s.penIsDown = true;
stroke(s, s.scratchX, s.scratchY, s.scratchX + 0.2, s.scratchY + 0.2);
interp.redraw();
}
};
MotionAndPenPrims.prototype.primPenUp = function(b) {
var s = interp.targetSprite();
if (s != null) s.penIsDown = false;
}
};
MotionAndPenPrims.prototype.primSetPenColor = function(b) {
var s = interp.targetSprite();
if (s != null) s.setPenColor(interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primSetPenHue = function(b) {
var s = interp.targetSprite();
if (s != null) s.setPenHue(interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primChangePenHue = function(b) {
var s = interp.targetSprite();
if (s != null) s.setPenHue(s.penHue + interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primSetPenShade = function(b) {
var s = interp.targetSprite();
if (s != null) s.setPenShade(interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primChangePenShade = function(b) {
var s = interp.targetSprite();
if (s != null) s.setPenShade(s.penShade + interp.arg(b, 0));
}
};
MotionAndPenPrims.prototype.primSetPenSize = function(b) {
var s = interp.targetSprite();
var w = Math.max(0, Math.min(interp.arg(b, 0), 100));
if (s != null) s.penWidth = w;
}
};
MotionAndPenPrims.prototype.primChangePenSize = function(b) {
var s = interp.targetSprite();
var w = Math.max(0, Math.min(s.penWidth + interp.arg(b, 0), 100));
if (s != null) s.penWidth = w;
}
};
MotionAndPenPrims.prototype.primStamp = function(b) {
var s = interp.targetSprite();
s.stamp(runtime.stage.lineCache, 100);
}
};
MotionAndPenPrims.prototype.primStampTransparent = function(b) {
var s = interp.targetSprite();
var transparency = Math.max(0, Math.min(interp.arg(b, 0), 100));
var alpha = 100 - transparency;
s.stamp(runtime.stage.lineCache, alpha);
}
};
// Helpers
var stroke = function(s, oldX, oldY, newX, newY) {
runtime.stage.stroke([oldX, oldY],
[newX, newY], s.penWidth, s.penColorCache);
runtime.stage.stroke([oldX, oldY], [newX, newY], s.penWidth, s.penColorCache);
interp.redraw();
}
};
var mouseOrSpritePosition = function(arg) {
if (arg == "_mouse_") {
@ -275,7 +272,7 @@ var mouseOrSpritePosition = function(arg) {
return new Point(s.scratchX, s.scratchY);
}
return null;
}
};
var moveSpriteTo = function(s, newX, newY) {
var oldX = s.scratchX;
@ -283,8 +280,8 @@ var moveSpriteTo = function(s, newX, newY) {
s.setXY(newX, newY);
s.keepOnStage();
if (s.penIsDown) stroke(s, oldX, oldY, s.scratchX, s.scratchY);
if ((s.penIsDown) || (s.visible)) interp.redraw();
}
if (s.penIsDown || s.visible) interp.redraw();
};
var turnAwayFromEdge = function(s) {
// turn away from the nearest edge if it's close enough; otherwise do nothing
@ -298,23 +295,23 @@ var turnAwayFromEdge = function(s) {
var d4 = Math.max(0, 360 - r.bottom);
// find the nearest edge
var e = 0, minDist = 100000;
if (d1 < minDist) { minDist = d1; e = 1 }
if (d2 < minDist) { minDist = d2; e = 2 }
if (d3 < minDist) { minDist = d3; e = 3 }
if (d4 < minDist) { minDist = d4; e = 4 }
if (d1 < minDist) { minDist = d1; e = 1; }
if (d2 < minDist) { minDist = d2; e = 2; }
if (d3 < minDist) { minDist = d3; e = 3; }
if (d4 < minDist) { minDist = d4; e = 4; }
if (minDist > 0) return false; // not touching to any edge
// point away from nearest edge
var radians = ((90 - s.direction) * Math.PI) / 180;
var radians = (90 - s.direction) * Math.PI / 180;
var dx = Math.cos(radians);
var dy = -Math.sin(radians);
if (e == 1) { dx = Math.max(0.2, Math.abs(dx)) }
if (e == 2) { dy = Math.max(0.2, Math.abs(dy)) }
if (e == 3) { dx = 0 - Math.max(0.2, Math.abs(dx)) }
if (e == 4) { dy = 0 - Math.max(0.2, Math.abs(dy)) }
var newDir = ((180 * Math.atan2(dy, dx)) / Math.PI) + 90;
if (e == 1) { dx = Math.max(0.2, Math.abs(dx)); }
if (e == 2) { dy = Math.max(0.2, Math.abs(dy)); }
if (e == 3) { dx = 0 - Math.max(0.2, Math.abs(dx)); }
if (e == 4) { dy = 0 - Math.max(0.2, Math.abs(dy)); }
var newDir = Math.atan2(dy, dx) * 180 / Math.PI + 90;
s.direction = newDir;
return true;
}
};
var ensureOnStageOnBounce = function(s) {
var r = s.getRect();
@ -326,4 +323,4 @@ var ensureOnStageOnBounce = function(s) {
if (r.bottom > 360) {
moveSpriteTo(s, s.scratchX, s.scratchY + (r.bottom - 360));
}
}
};

View file

@ -26,29 +26,29 @@ var Primitives = function() {}
Primitives.prototype.addPrimsTo = function(primTable) {
// Math primitives
primTable["+"] = function(b) { return interp.arg(b, 0) + interp.arg(b, 1) };
primTable["-"] = function(b) { return interp.arg(b, 0) - interp.arg(b, 1) };
primTable["*"] = function(b) { return interp.arg(b, 0) * interp.arg(b, 1) };
primTable["/"] = function(b) { return interp.arg(b, 0) / interp.arg(b, 1) };
primTable["%"] = function(b) { return interp.arg(b, 0) % interp.arg(b, 1) };
primTable["+"] = function(b) { return interp.arg(b, 0) + interp.arg(b, 1); };
primTable["-"] = function(b) { return interp.arg(b, 0) - interp.arg(b, 1); };
primTable["*"] = function(b) { return interp.arg(b, 0) * interp.arg(b, 1); };
primTable["/"] = function(b) { return interp.arg(b, 0) / interp.arg(b, 1); };
primTable["%"] = function(b) { return interp.arg(b, 0) % interp.arg(b, 1); };
primTable["randomFrom:to:"] = this.primRandom;
primTable["<"] = function(b) { return (interp.arg(b, 0) < interp.arg(b, 1)) };
primTable["="] = function(b) { return (interp.arg(b, 0) == interp.arg(b, 1)) };
primTable[">"] = function(b) { return (interp.arg(b, 0) > interp.arg(b, 1)) };
primTable["&"] = function(b) { return interp.arg(b, 0) && interp.arg(b, 1) };
primTable["|"] = function(b) { return interp.arg(b, 0) || interp.arg(b, 1) };
primTable["<"] = function(b) { return (interp.arg(b, 0) < interp.arg(b, 1)); };
primTable["="] = function(b) { return (interp.arg(b, 0) == interp.arg(b, 1)); };
primTable[">"] = function(b) { return (interp.arg(b, 0) > interp.arg(b, 1)); };
primTable["&"] = function(b) { return interp.arg(b, 0) && interp.arg(b, 1); };
primTable["|"] = function(b) { return interp.arg(b, 0) || interp.arg(b, 1); };
primTable["not"] = function(b) { return !interp.arg(b, 0) };
primTable["abs"] = function(b) { return Math.abs(interp.arg(b, 0)) };
primTable["sqrt"] = function(b) { return Math.sqrt(interp.arg(b, 0)) };
primTable["\\\\"] = this.primModulo;
primTable["rounded"] = function(b) { return Math.round(interp.arg(b, 0)) };
primTable["rounded"] = function(b) { return Math.round(interp.arg(b, 0)); };
primTable["computeFunction:of:"] = this.primMathFunction;
// String primitives
primTable["concatenate:with:"] = function(b) { return "" + interp.arg(b, 0) + interp.arg(b, 1) };
primTable["concatenate:with:"] = function(b) { return "" + interp.arg(b, 0) + interp.arg(b, 1); };
primTable["letter:of:"] = this.primLetterOf;
primTable["stringLength:"] = function(b) { return interp.arg(b, 0).length };
primTable["stringLength:"] = function(b) { return interp.arg(b, 0).length; };
new VarListPrims().addPrimsTo(primTable);
new MotionAndPenPrims().addPrimsTo(primTable);
@ -60,20 +60,20 @@ Primitives.prototype.addPrimsTo = function(primTable) {
Primitives.prototype.primRandom = function(b) {
var n1 = interp.arg(b, 0);
var n2 = interp.arg(b, 1);
var low = (n1 <= n2) ? n1 : n2;
var hi = (n1 <= n2) ? n2 : n1;
if(low == hi) return low;
var low = n1 <= n2 ? n1 : n2;
var hi = n1 <= n2 ? n2 : n1;
if (low == hi) return low;
// if both low and hi are ints, truncate the result to an int
if ((Math.floor(low) == low) && (Math.floor(hi) == hi)) {
return low + Math.floor(Math.random() * ((hi + 1) - low));
if (Math.floor(low) == low && Math.floor(hi) == hi) {
return low + Math.floor(Math.random() * (hi + 1 - low));
}
return (Math.random() * (hi - low)) + low;
return Math.random() * (hi - low) + low;
}
Primitives.prototype.primLetterOf = function(b) {
var s = interp.arg(b, 1);
var i = interp.arg(b, 0) - 1;
if ((i < 0) || (i >= s.length)) return "";
if (i < 0 || i >= s.length) return "";
return s.charAt(i);
}
@ -90,12 +90,12 @@ Primitives.prototype.primMathFunction = function(b) {
switch(op) {
case "abs": return Math.abs(n);
case "sqrt": return Math.sqrt(n);
case "sin": return Math.sin((Math.PI * n) / 180);
case "cos": return Math.cos((Math.PI * n) / 180);
case "tan": return Math.tan((Math.PI * n) / 180);
case "asin": return (Math.asin(n) * 180) / Math.PI;
case "acos": return (Math.acos(n) * 180) / Math.PI;
case "atan": return (Math.atan(n) * 180) / Math.PI;
case "sin": return Math.sin(n * Math.PI / 180);
case "cos": return Math.cos(n * Math.PI / 180);
case "tan": return Math.tan(n * Math.PI / 180);
case "asin": return Math.asin(n) * 180 / Math.PI;
case "acos": return Math.acos(n) * 180 / Math.PI;
case "atan": return Math.atan(n) * 180 / Math.PI;
case "ln": return Math.log(n);
case "log": return Math.log(n) / Math.LN10;
case "e ^": return Math.exp(n);

View file

@ -15,7 +15,7 @@
'use strict';
var SensingPrims = function() {}
var SensingPrims = function() {};
SensingPrims.prototype.addPrimsTo = function(primTable) {
primTable['touching:'] = this.primTouching;
@ -30,9 +30,9 @@ SensingPrims.prototype.addPrimsTo = function(primTable) {
primTable['getAttribute:of:'] = this.primGetAttribute;
primTable['timeAndDate'] = this.primTimeDate;
primTable['timeAndDate'] = function(b){ return runtime.getTimeString(interp.arg(b, 0)); };
primTable['timestamp'] = this.primTimestamp;
}
};
SensingPrims.prototype.primTouching = function(b) {
var s = interp.targetSprite();
@ -51,7 +51,7 @@ SensingPrims.prototype.primTouching = function(b) {
if (s2 == null || !s2.visible) return false;
return spriteHitTest(s, s2);
}
};
SensingPrims.prototype.primTouchingColor = function(b) {
var s = interp.targetSprite();
@ -60,7 +60,7 @@ SensingPrims.prototype.primTouchingColor = function(b) {
var color = interp.arg(b, 0);
return stageColorHitTest(s, color);
}
};
SensingPrims.prototype.primColorTouchingColor = function(b) {
var s = interp.targetSprite();
@ -70,7 +70,7 @@ SensingPrims.prototype.primColorTouchingColor = function(b) {
var stageColor = interp.arg(b, 1);
return stageColorByColorHitTest(s, myColor, stageColor);
}
};
var spriteHitTest = function(a, b) {
var hitCanvas = document.createElement('canvas');
@ -91,7 +91,7 @@ var spriteHitTest = function(a, b) {
}
}
return false;
}
};
var stageColorHitTest = function(target, color) {
var r, g, b;
@ -123,18 +123,18 @@ var stageColorHitTest = function(target, color) {
return true;
}
return false;
}
};
var stageColorByColorHitTest = function(target, myColor, otherColor) {
var threshold_acceptable = function(a, b, c, x, y, z) {
diff_a = Math.abs(a-x);
diff_b = Math.abs(b-y);
diff_c = Math.abs(c-z);
var diff_a = Math.abs(a-x);
var diff_b = Math.abs(b-y);
var diff_c = Math.abs(c-z);
if (diff_a + diff_b + diff_c < 100) {
return true;
}
return false;
}
};
var targetCanvas = document.createElement('canvas');
targetCanvas.width = 480;
targetCanvas.height = 360;
@ -157,22 +157,22 @@ var stageColorByColorHitTest = function(target, myColor, otherColor) {
var hitCanvas = document.createElement('canvas');
hitCanvas.width = 480;
hitCanvas.height = 360;
hitCtx = hitCanvas.getContext('2d');
var hitCtx = hitCanvas.getContext('2d');
$.each(runtime.sprites, function(i, sprite) {
if (sprite != target)
if (sprite != target) {
sprite.stamp(hitCtx, 100);
}
});
var hitData = hitCtx.getImageData(0, 0, hitCanvas.width, hitCanvas.height).data;
var pxCount = targetData.length;
for (var i = 0; i < pxCount; i += 4) {
if (threshold_acceptable(targetData[i], targetData[i+1], targetData[i+2], mr, mg, mb)
&& threshold_acceptable(hitData[i], hitData[i+1], hitData[i+2], or, og, ob)) {
if (threshold_acceptable(targetData[i], targetData[i+1], targetData[i+2], mr, mg, mb) && threshold_acceptable(hitData[i], hitData[i+1], hitData[i+2], or, og, ob)) {
return true;
}
}
return false;
}
};
SensingPrims.prototype.primKeyPressed = function(b) {
var key = interp.arg(b, 0);
@ -184,7 +184,7 @@ SensingPrims.prototype.primKeyPressed = function(b) {
if (key == "down arrow") ch = 40;
if (key == "space") ch = 32;
return (typeof(runtime.keysDown[ch]) != 'undefined');
}
};
SensingPrims.prototype.primDistanceTo = function(b) {
var s = interp.targetSprite();
@ -193,7 +193,7 @@ SensingPrims.prototype.primDistanceTo = function(b) {
var dx = p.x - s.scratchX;
var dy = p.y - s.scratchY;
return Math.sqrt((dx * dx) + (dy * dy));
}
};
SensingPrims.prototype.primGetAttribute = function(b) {
var attr = interp.arg(b, 0);
@ -207,7 +207,7 @@ SensingPrims.prototype.primGetAttribute = function(b) {
if (attr == 'size') return targetSprite.getSize();
if (attr == 'volume') return targetSprite.volume;
return 0;
}
};
SensingPrims.prototype.primTimeDate = function(b) {
var dt = interp.arg(b, 0);
@ -220,13 +220,16 @@ SensingPrims.prototype.primTimeDate = function(b) {
if (dt == 'minute') return now.getMinutes();
if (dt == 'second') return now.getSeconds();
return 0;
}
};
SensingPrims.prototype.primTimestamp = function(b) {
var now = new Date(), epoch = new Date(2000,0,1), dst = now.getTimezoneOffset() - epoch.getTimezoneOffset(), msSince = now.getTime() - epoch.getTime();
var now = new Date();
var epoch = new Date(2000, 0, 1);
var dst = now.getTimezoneOffset() - epoch.getTimezoneOffset();
var msSince = now.getTime() - epoch.getTime();
msSince += (now.getTimezoneOffset() - dst) * 60000;
return msSince / 86400000;
}
};
// Helpers
SensingPrims.prototype.mouseOrSpritePosition = function(arg) {
@ -239,4 +242,4 @@ SensingPrims.prototype.mouseOrSpritePosition = function(arg) {
return new Point(s.scratchX, s.scratchY);
}
return null;
}
};

View file

@ -15,7 +15,7 @@
'use strict';
var SoundPrims = function() {}
var SoundPrims = function() {};
SoundPrims.prototype.addPrimsTo = function(primTable) {
primTable['playSound:'] = this.primPlaySound;
@ -34,7 +34,7 @@ SoundPrims.prototype.addPrimsTo = function(primTable) {
primTable['changeTempoBy:'] = function(b) { runtime.stage.data.tempoBPM = runtime.stage.data.tempoBPM + interp.arg(b, 0); };
primTable['setTempoTo:'] = function(b) { runtime.stage.data.tempoBPM = interp.arg(b, 0); };
primTable['tempo'] = function(b) { return runtime.stage.data.tempoBPM; };
}
};
var playSound = function(snd) {
if (snd.source) {
@ -64,7 +64,7 @@ var playSound = function(snd) {
runtime.audioPlaying.push(snd);
snd.source.noteOn(0);
return snd.source;
}
};
var playDrum = function(drum, secs, client) {
var player = SoundBank.getDrumPlayer(drum, secs);
@ -83,7 +83,7 @@ var playDrum = function(drum, secs, client) {
}
window.setTimeout(source.finished, secs * 1000);
return player;
}
};
var playNote = function(instrument, midiKey, secs, client) {
var player = SoundBank.getNotePlayer(instrument, midiKey);
@ -101,7 +101,7 @@ var playNote = function(instrument, midiKey, secs, client) {
}
window.setTimeout(source.finished, secs * 1000);
return player;
}
};
var stopAllSounds = function() {
var oldPlaying = runtime.audioPlaying;
@ -121,14 +121,14 @@ var stopAllSounds = function() {
oldPlaying[s].finished();
}
}
}
};
SoundPrims.prototype.primPlaySound = function(b) {
var s = interp.targetSprite();
if (s == null) return;
var snd = s.soundNamed(interp.arg(b, 0));
if (snd != null) playSound(snd);
}
};
SoundPrims.prototype.primPlaySoundUntilDone = function(b) {
var activeThread = interp.activeThread;
@ -145,11 +145,11 @@ SoundPrims.prototype.primPlaySoundUntilDone = function(b) {
} else {
interp.yield = true;
}
}
};
var beatsToSeconds = function(beats) {
return (beats * 60) / runtime.stage.data.tempoBPM;
}
return beats * 60 / runtime.stage.data.tempoBPM;
};
SoundPrims.prototype.primPlayNote = function(b) {
var s = interp.targetSprite();
@ -162,7 +162,7 @@ SoundPrims.prototype.primPlayNote = function(b) {
} else {
interp.checkTimer();
}
}
};
SoundPrims.prototype.primPlayDrum = function(b) {
var s = interp.targetSprite();
@ -175,7 +175,7 @@ SoundPrims.prototype.primPlayDrum = function(b) {
} else {
interp.checkTimer();
}
}
};
SoundPrims.prototype.primPlayRest = function(b) {
var s = interp.targetSprite();
@ -186,28 +186,28 @@ SoundPrims.prototype.primPlayRest = function(b) {
} else {
interp.checkTimer();
}
}
};
SoundPrims.prototype.primSetInstrument = function(b) {
var s = interp.targetSprite();
if (s != null) s.instrument = interp.arg(b, 0);
}
};
SoundPrims.prototype.primStopAllSounds = function(b) {
stopAllSounds();
}
};
SoundPrims.prototype.primChangeVolume = function(b) {
var s = interp.targetSprite();
if (s != null) s.volume += interp.arg(b, 0);
}
};
SoundPrims.prototype.primSetVolume = function(b) {
var s = interp.targetSprite();
if (s != null) s.volume = interp.arg(b, 0);
}
};
SoundPrims.prototype.primVolume = function(b) {
var s = interp.targetSprite();
return (s != null) ? s.volume : 0;
}
return s != null ? s.volume : 0;
};

View file

@ -34,7 +34,7 @@ VarListPrims.prototype.addPrimsTo = function(primTable) {
primTable['lineCountOfList:'] = this.primListLength;
primTable['getLine:ofList:'] = this.primListGetLine;
primTable['list:contains:'] = this.primListContains;
}
};
// Variable primitive implementations
@ -42,21 +42,23 @@ VarListPrims.prototype.primReadVar = function(b) {
var s = interp.targetSprite();
if (s == null) return;
var targetVar = interp.arg(b, 0);
if (targetVar in s.variables)
if (targetVar in s.variables) {
return s.variables[targetVar];
else if (targetVar in runtime.stage.variables)
} else if (targetVar in runtime.stage.variables) {
return runtime.stage.variables[targetVar];
}
}
};
VarListPrims.prototype.primSetVar = function(b) {
var s = interp.targetSprite();
if (s == null) return;
var targetVar = interp.arg(b, 0);
if (targetVar in s.variables)
if (targetVar in s.variables) {
s.variables[targetVar] = interp.arg(b, 1);
else if (targetVar in runtime.stage.variables)
} else if (targetVar in runtime.stage.variables) {
runtime.stage.variables[targetVar] = interp.arg(b, 1);
}
}
};
VarListPrims.prototype.primChangeVar = function(b) {
var s = interp.targetSprite();
@ -69,7 +71,7 @@ VarListPrims.prototype.primChangeVar = function(b) {
runtime.stage.variables[targetVar] = parseFloat(runtime.stage.variables[targetVar]);
runtime.stage.variables[targetVar] += interp.arg(b, 1);
}
}
};
VarListPrims.prototype.primHideVar = function(b) {
var targetVar = interp.arg(b, 0);
@ -79,7 +81,7 @@ VarListPrims.prototype.primHideVar = function(b) {
return;
}
}
}
};
VarListPrims.prototype.primShowVar = function(b) {
var targetVar = interp.arg(b, 0);
@ -89,7 +91,7 @@ VarListPrims.prototype.primShowVar = function(b) {
return;
}
}
}
};
// List primitive implementations
@ -102,20 +104,20 @@ var findList = function(targetSprite, listName) {
return runtime.stage.lists[listName].contents;
}
return null;
}
};
VarListPrims.prototype.primReadList = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 0));
if (list) {
var allOne = list.map(function(val){return val.length}).reduce(function(old,val){return old+val},0)===list.length;
return list.join(allOne?'':' ');
var allOne = list.map(function(val) { return val.length; }).reduce(function(old,val) { return old + val; }, 0) === list.length;
return list.join(allOne ? '' : ' ');
}
}
};
VarListPrims.prototype.primListAppend = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 1));
if (list) list.push(interp.arg(b, 0));
}
};
VarListPrims.prototype.primListDeleteLine = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 1));
@ -124,7 +126,7 @@ VarListPrims.prototype.primListDeleteLine = function(b) {
if (line == 'all' || list.length == 0) list.length = 0;
else if (line == 'last') list.splice(list.length - 1, 1);
else if (parseInt(line) - 1 in list) list.splice(parseInt(line) - 1, 1);
}
};
VarListPrims.prototype.primListInsertAt = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 2));
@ -138,7 +140,7 @@ VarListPrims.prototype.primListInsertAt = function(b) {
if (position > list.length) return;
list.splice(position, 0, newItem);
}
};
VarListPrims.prototype.primListSetLine = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 1));
@ -149,16 +151,17 @@ VarListPrims.prototype.primListSetLine = function(b) {
if (position == 'last') position = list.length - 1;
else if (position == 'random') position = Math.floor(Math.random() * list.length);
else position = parseInt(position) - 1;
if (position > list.length - 1) return;
list[position] = newItem;
}
};
VarListPrims.prototype.primListLength = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 0));
if (!list) return 0;
return list.length;
}
};
VarListPrims.prototype.primListGetLine = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 1));
@ -169,7 +172,7 @@ VarListPrims.prototype.primListGetLine = function(b) {
else if (line == 'last') line = list.length;
else if (list.length < line) return 0;
return list[line - 1];
}
};
VarListPrims.prototype.primListContains = function(b) {
var list = findList(interp.targetSprite(), interp.arg(b, 0));
@ -177,4 +180,4 @@ VarListPrims.prototype.primListContains = function(b) {
var searchItem = interp.arg(b, 1);
if (parseFloat(searchItem) == searchItem) searchItem = parseFloat(searchItem);
return $.inArray(searchItem, list) > -1;
}
};

View file

@ -65,11 +65,11 @@ var NotePlayer = function(wavFileData, originalPitch, loopStart, loopEnd, env) {
if (env) {
this.attackEnd = env[0] * 44.100;
if (this.attackEnd > 0) this.attackRate = Math.pow(33000, 1 / this.attackEnd);
this.holdEnd = this.attackEnd + (env[1] * 44.100);
this.holdEnd = this.attackEnd + env[1] * 44.100;
var decayCount = env[2] * 44100;
this.decayRate = (decayCount == 0) ? 1 : Math.pow(33000, -1 / decayCount);
this.decayRate = decayCount == 0 ? 1 : Math.pow(33000, -1 / decayCount);
}
}
};
NotePlayer.prototype = Object.create(SoundDecoder.prototype);
NotePlayer.prototype.constructor = NotePlayer;
@ -79,14 +79,14 @@ NotePlayer.prototype.setNoteAndDuration = function(midiKey, secs) {
var pitch = 440 * Math.pow(2, (midiKey - 69) / 12); // midi key 69 is A (440 Hz)
this.stepSize = pitch / (2 * this.originalPitch); // adjust for original sampling rate of 22050
this.setDuration(secs);
}
};
NotePlayer.prototype.setDuration = function(secs) {
this.samplesSinceStart = 0;
this.samplesRemaining = 44100 * secs;
if (!this.isLooped) this.samplesRemaining = Math.min(this.samplesRemaining, this.endOffset / this.stepSize);
this.envelopeValue = (this.attackEnd > 0) ? 1 / 33000 : 1;
}
this.envelopeValue = this.attackEnd > 0 ? 1 / 33000 : 1;
};
NotePlayer.prototype.interpolatedSample = function() {
if (this.samplesRemaining-- <= 0) { this.noteFinished(); return 0; }
@ -99,11 +99,11 @@ NotePlayer.prototype.interpolatedSample = function() {
var frac = this.index - i;
var curr = this.rawSample(i);
var next = this.rawSample(i + 1);
var sample = (curr + (frac * (next - curr))) / 100000; // xxx 32000; attenuate...
var sample = (curr + frac * (next - curr)) / 100000; // xxx 32000; attenuate...
if (this.samplesRemaining < 1000) sample *= (this.samplesRemaining / 1000.0); // relaase phease
this.updateEnvelope();
return this.envelopeValue * sample;
}
};
NotePlayer.prototype.rawSample = function(sampleIndex) {
if (sampleIndex >= this.endOffset) {
@ -112,8 +112,8 @@ NotePlayer.prototype.rawSample = function(sampleIndex) {
}
var byteIndex = 2 * sampleIndex;
var result = (this.soundData[byteIndex + 1] << 8) + this.soundData[byteIndex];
return (result <= 32767) ? result : result - 65536;
}
return result <= 32767 ? result : result - 65536;
};
NotePlayer.prototype.updateEnvelope = function() {
// Compute envelopeValue for the current sample.
@ -125,4 +125,4 @@ NotePlayer.prototype.updateEnvelope = function() {
} else if (this.samplesSinceStart > this.holdEnd) {
if (this.decayRate < 1) this.envelopeValue *= this.decayRate;
}
}
};

View file

@ -178,24 +178,24 @@ SoundBank.getNotePlayer = function(instNum, midiKey) {
// Return a NotePlayer for the given Scratch 2.0 instrument number (1..21)
// and MIDI key (0..127). If the instrument is out of range, use 1.
var r = SoundBank.getNoteRecord(instNum - 1, midiKey);
var env = (r.length > 5) ? r[5] : null;
var env = r.length > 5 ? r[5] : null;
return new NotePlayer(Instr.samples[r[1]], SoundBank.pitchForKey(r[2]), r[3], r[4], env);
}
};
SoundBank.getNoteRecord = function(instNum, midiKey) {
// Get a note record for the given instrument number.
if ((instNum < 0) || (instNum >= SoundBank.instruments.length)) instNum = 0;
if (instNum < 0 || instNum >= SoundBank.instruments.length) instNum = 0;
var keyRanges = SoundBank.instruments[instNum];
for (var r = 0; r < keyRanges.length; r++) {
var topOfKeyRange = keyRanges[r][0];
if (midiKey <= topOfKeyRange) return keyRanges[r];
}
return keyRanges[keyRanges.length - 1]; // return the note record for the top key range.
}
};
SoundBank.pitchForKey = function(midiKey) {
return 440 * Math.pow(2, (midiKey - 69) / 12); // midi key 69 is A=440 Hz
}
};
SoundBank.getDrumPlayer = function(drumNum, secs) {
// Return a NotePlayer for the given drum number.
@ -210,6 +210,4 @@ SoundBank.getDrumPlayer = function(drumNum, secs) {
var player = new NotePlayer(Instr.samples[entry[0]], SoundBank.pitchForKey(60), loopStart, loopEnd, env);
player.setNoteAndDuration(60 + entry[1], 0);
return player;
}
};

View file

@ -61,12 +61,12 @@ var SoundDecoder = function(wavFileData) {
if (info.bitsPerSample == 16) this.getSample = this.getSample16Uncompressed;
}
}
}
};
SoundDecoder.prototype.noteFinished = function() {
// Called by subclasses to force ending condition to be true in writeSampleData()
this.bytePosition = this.endOffset;
}
};
// Used for Notes and Drums - Web Audio API ScriptProcessorNodes use this
// as a callback function to fill the buffers with sample data.
@ -78,7 +78,7 @@ SoundDecoder.prototype.writeSampleData = function(evt) {
var n = this.interpolatedSample();
output[i] = n;
}
}
};
// For pre-caching the samples of WAV sounds
// Return a full list of samples generated by the decoder.
@ -90,7 +90,7 @@ SoundDecoder.prototype.getAllSamples = function() {
smp = this.interpolatedSample();
}
return samples;
}
};
// Provide the next sample for the buffer
SoundDecoder.prototype.interpolatedSample = function() {
@ -101,11 +101,9 @@ SoundDecoder.prototype.interpolatedSample = function() {
this.fraction -= 1.0;
}
if (this.nextSample == null) { return null; }
var out = (this.fraction == 0) ?
this.thisSample :
this.thisSample + (this.fraction * (this.nextSample - this.thisSample));
return (out) / 32768.0;
}
var out = this.fraction == 0 ? this.thisSample : this.thisSample + this.fraction * (this.nextSample - this.thisSample);
return out / 32768.0;
};
// 16-bit samples, big-endian
SoundDecoder.prototype.getSample16Uncompressed = function() {
@ -119,13 +117,13 @@ SoundDecoder.prototype.getSample16Uncompressed = function() {
result = null;
}
return result;
}
};
// 8-bit samples, uncompressed
SoundDecoder.prototype.getSample8Uncompressed = function() {
if (this.bytePosition >= this.info.sampleDataSize) return null;
return (this.soundData[this.bytePosition++] - 128) << 8;
}
};
/*SoundDecoder.prototype.updateVolume = function() {
if (this.client == null) {
@ -154,8 +152,8 @@ SoundDecoder.prototype.getSampleADPCM = function() {
// Note: Handles only one channel, 4-bits/sample.
var step = 0, code = 0, delta = 0;
if (((this.bytePosition % this.adpcmBlockSize) == 0) && (this.lastByte < 0)) { // read block header
if (this.bytePosition > (this.info.sampleDataSize - 4)) return null;
if (this.bytePosition % this.adpcmBlockSize == 0 && this.lastByte < 0) { // read block header
if (this.bytePosition > this.info.sampleDataSize - 4) return null;
this.sample = (this.soundData[this.bytePosition + 1] << 8) + this.soundData[this.bytePosition];
if (this.sample > 32767) this.sample -= 65536;
this.index = this.soundData[this.bytePosition + 2];
@ -184,7 +182,7 @@ SoundDecoder.prototype.getSampleADPCM = function() {
if (this.index > 88) this.index = 88;
if (this.index < 0) this.index = 0;
// compute and output sample
this.sample += ((code & 8) ? -delta : delta);
this.sample += code & 8 ? -delta : delta;
if (this.sample > 32767) this.sample = 32767;
if (this.sample < -32768) this.sample = -32768;
return this.sample;

View file

@ -19,7 +19,6 @@
var WAVFile = function() {};
WAVFile.decode = function(waveData) {
// Decode the given WAV file data and return an Object with the format and sample data.
var result = {};
@ -75,8 +74,7 @@ WAVFile.decode = function(waveData) {
return;
}
return result;
}
};
WAVFile.extractChunk = function(desiredType, data) {
// Return the contents of the first chunk of the given type or an empty OffsetBuffer if it is not found.
@ -93,8 +91,7 @@ WAVFile.extractChunk = function(desiredType, data) {
}
}
return new OffsetBuffer(new ArrayBuffer());
}
};
WAVFile.dataChunkStartAndSize = function(data) {
// Return an array with the starting offset and size of the first chunk of the given type.
@ -110,4 +107,4 @@ WAVFile.dataChunkStartAndSize = function(data) {
}
}
return [0, 0]; // chunk not found; bad wave file
}
};

View file

@ -29,8 +29,8 @@ Color.fromHSV = function(h, s, v) {
var i = Math.floor(h / 60);
var f = (h / 60) - i;
var p = v * (1 - s);
var q = v * (1 - (s * f));
var t = v * (1 - (s * (1 - f)));
var q = v * (1 - s * f);
var t = v * (1 - s * (1 - f));
if (i == 0) { r = v; g = t; b = p; }
else if (i == 1) { r = q; g = v; b = p; }
else if (i == 2) { r = p; g = v; b = t; }
@ -41,7 +41,7 @@ Color.fromHSV = function(h, s, v) {
g = Math.floor(g * 255);
b = Math.floor(b * 255);
return (r << 16) | (g << 8) | b;
}
};
Color.rgb2hsv = function(rgb) {
var h, s, v, x, f, i;
@ -51,18 +51,18 @@ Color.rgb2hsv = function(rgb) {
x = Math.min(Math.min(r, g), b);
v = Math.max(Math.max(r, g), b);
if (x == v) return [0, 0, v]; // gray; hue arbitrarily reported as zero
f = (r == x) ? g - b : ((g == x) ? b - r : r - g);
i = (r == x) ? 3 : ((g == x) ? 5 : 1);
h = ((i - (f / (v - x))) * 60) % 360;
f = r == x ? g - b : g == x ? b - r : r - g;
i = r == x ? 3 : g == x ? 5 : 1;
h = ((i - f / (v - x)) * 60) % 360;
s = (v - x) / v;
return [h, s, v];
}
};
Color.scaleBrightness = function(rgb, scale) {
var hsv = Color.rgb2hsv(rgb);
scale = Math.max(0, Math.min(scale, 1));
return Color.fromHSV(hsv[0], hsv[1], scale * hsv[2]);
}
};
Color.mixRGB = function(rgb1, rgb2, fraction) {
// Mix rgb1 with rgb2. 0 gives all rgb1, 1 gives rbg2, .5 mixes them 50/50.
@ -78,7 +78,7 @@ Color.mixRGB = function(rgb1, rgb2, fraction) {
var g = ((fraction * g2) + ((1.0 - fraction) * g1)) & 255;
var b = ((fraction * b2) + ((1.0 - fraction) * b1)) & 255;
return (r << 16) | (g << 8) | b;
}
};
Color.random = function() {
// return a random color
@ -86,4 +86,4 @@ Color.random = function() {
var s = 0.7 + (0.3 * Math.random());
var v = 0.6 + (0.4 * Math.random());
return Color.fromHSV(h, s, v);
}
};

View file

@ -19,63 +19,63 @@
var OffsetBuffer = function(data) {
this.offset = 0;
this.ab = data;
}
};
// Read various datatypes from the ArrayBuffer, seeking the offset.
OffsetBuffer.prototype.readString = function(length) {
var str = this.ab2str(this.ab.slice(this.offset, this.offset + length));
this.offset += length;
return str;
}
};
OffsetBuffer.prototype.readInt = function() {
var num = this.ab2int(this.ab.slice(this.offset, this.offset + 4));
this.offset += 4;
return num;
}
};
OffsetBuffer.prototype.readUint = function() {
var num = this.ab2uint(this.ab.slice(this.offset, this.offset + 4));
this.offset += 4;
return num;
}
};
OffsetBuffer.prototype.readShort = function() {
var num = this.ab2short(this.ab.slice(this.offset, this.offset + 2));
this.offset += 2;
return num;
}
};
OffsetBuffer.prototype.readBytes = function(length) {
var bytes = this.ab.slice(this.offset, this.offset + length);
this.offset += length;
return bytes;
}
};
// Length of the internal buffer
OffsetBuffer.prototype.getLength = function() {
return this.ab.byteLength;
}
};
// Number of bytes remaining from the current offset
OffsetBuffer.prototype.bytesAvailable = function() {
return (this.getLength() - this.offset);
}
return this.getLength() - this.offset;
};
// ArrayBuffer -> JS type conversion methods
OffsetBuffer.prototype.ab2str = function(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
};
// These create Javascript Numbers
OffsetBuffer.prototype.ab2int = function(buf) {
return new Int32Array(buf)[0];
}
};
OffsetBuffer.prototype.ab2uint = function(buf) {
return new Uint32Array(buf)[0];
}
};
OffsetBuffer.prototype.ab2short = function(buf) {
return new Int16Array(buf)[0];
}
};

View file

@ -16,7 +16,7 @@
var Point = function(x, y) {
this.x = x;
this.y = y;
}
};
var Rectangle = function(x, y, width, height) {
this.x = x;
@ -27,10 +27,8 @@ var Rectangle = function(x, y, width, height) {
this.right = x + width;
this.top = y;
this.bottom = y + height;
}
};
Rectangle.prototype.intersects = function(other) {
return !(this.left > other.right ||
this.right < other.left ||
this.top > other.bottom ||
this.bottom < other.top);
}
return !(this.left > other.right || this.right < other.left || this.top > other.bottom || this.bottom < other.top);
};

View file

@ -21,40 +21,40 @@ var Timer = function() {
var trials = [];
var last_trial = 0;
var start_time = 0;
}
};
Timer.prototype.time = function() {
return (new Date()).getTime();
}
return Date.now();
};
Timer.prototype.start = function() {
start_time = this.time();
}
};
Timer.prototype.stop = function() {
end = this.time();
last_trial = end - start_time;
trials.push(last_trial);
}
};
Timer.prototype.count = function() {
return trials.length;
}
};
Timer.prototype.average = function() {
sum = 0;
for(i = 0; i < this.count(); i++) {
for (i = 0; i < this.count(); i++) {
sum += trials[i];
}
return sum / this.count();
}
};
Timer.prototype.print = function(element) {
text = "Trial: " + last_trial + "ms" +
"<br />\nTrials: " + this.count() + ", Avg: " + this.average() + "ms";
if(element) {
if (element) {
$(element).html(text);
} else {
console.log(text);
}
}
};