cloning speedup

significantly speed up sprite cloning through partial shallow-copying
of scripts and costumes instead of deep-duplication
dev
Jens Mönig 2016-05-04 16:37:46 +02:00
rodzic d7479f90e4
commit 71333021d4
7 zmienionych plików z 91 dodań i 45 usunięć

Wyświetl plik

@ -145,11 +145,11 @@ radians, useBlurredShadows, SpeechBubbleMorph, modules, StageMorph,
fontHeight, TableFrameMorph, SpriteMorph, Context, ListWatcherMorph,
CellMorph, DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph,
Costume, IDE_Morph, BlockDialogMorph, BlockEditorMorph, localize, isNil,
isSnapObject*/
isSnapObject, copy*/
// Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2016-May-02';
modules.blocks = '2016-May-04';
var SyntaxElementMorph;
var BlockMorph;
@ -3251,7 +3251,14 @@ BlockMorph.prototype.setCategory = function (aString) {
// BlockMorph copying
BlockMorph.prototype.fullCopy = function () {
BlockMorph.prototype.fullCopy = function (forClone) {
if (forClone) {
if (this.hasBlockVars()) {
forClone = false;
} else {
return copy(this);
}
}
var ans = BlockMorph.uber.fullCopy.call(this);
ans.removeHighlight();
ans.isDraggable = true;
@ -3261,22 +3268,15 @@ BlockMorph.prototype.fullCopy = function () {
ans.allChildren().filter(function (block) {
if (block instanceof SyntaxElementMorph) {
block.cachedInputs = null;
// if (block instanceof InputSlotMorph) {
// block.contents().clearSelection();
// } else
if (block.definition) {
block.initializeVariables();
}
// } else if (block instanceof CursorMorph) {
// block.destroy();
}
return !isNil(block.comment);
}).forEach(function (block) {
var cmnt = block.comment.fullCopy();
block.comment = cmnt;
cmnt.block = block;
//block.comment = null;
});
ans.cachedInputs = null;
return ans;
@ -3286,6 +3286,12 @@ BlockMorph.prototype.reactToTemplateCopy = function () {
this.forceNormalColoring();
};
BlockMorph.prototype.hasBlockVars = function () {
return this.anyChild(function (any) {
return any.definition && any.definition.variableNames.length;
});
};
// BlockMorph events
BlockMorph.prototype.mouseClickLeft = function () {
@ -5177,7 +5183,7 @@ ScriptsMorph.prototype.init = function (owner) {
// ScriptsMorph deep copying:
ScriptsMorph.prototype.fullCopy = function () {
ScriptsMorph.prototype.fullCopy = function (forClone) {
var cpy = new ScriptsMorph(),
pos = this.position(),
child;
@ -5186,17 +5192,21 @@ ScriptsMorph.prototype.fullCopy = function () {
}
this.children.forEach(function (morph) {
if (!morph.block) { // omit anchored comments
child = morph.fullCopy();
child.setPosition(morph.position().subtract(pos));
child = morph.fullCopy(forClone);
cpy.add(child);
if (child instanceof BlockMorph) {
child.allComments().forEach(function (comment) {
comment.align(child);
});
if (!forClone) {
child.setPosition(morph.position().subtract(pos));
if (child instanceof BlockMorph) {
child.allComments().forEach(function (comment) {
comment.align(child);
});
}
}
}
});
cpy.adjustBounds();
if (!forClone) {
cpy.adjustBounds();
}
return cpy;
};

4
gui.js
Wyświetl plik

@ -70,7 +70,7 @@ isSnapObject*/
// Global stuff ////////////////////////////////////////////////////////
modules.gui = '2016-May-02';
modules.gui = '2016-May-04';
// Declarations
@ -2835,7 +2835,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world();
aboutTxt = 'Snap! 4.0.7\nBuild Your Own Blocks\n\n'
aboutTxt = 'Snap! 4.0.7.1\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2016 Jens M\u00F6nig and '
+ 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'

Wyświetl plik

@ -2908,10 +2908,15 @@ http://snap.berkeley.edu/run#cloud:Username=jens&ProjectName=PathFollower
http://snap.berkeley.edu/run#present:Username=jens&ProjectName=cartwheel
http://snap.berkeley.edu/run#cloud:Username=jens&ProjectName=rotation
* new Indonesian translation. Yay!! Thank you, Alexander Liu!!
* Translation updates: Slovenian, Portuguese, Chinese
* minor bug fixes
== v4.0.7 ==== - first class sprites
160504
------
* Morphic, Objects, Blocks, Threads, GUI: Partially shallow-copy clones for speed
* new Estonian translation! Yay!! Thanks, Hasso Tepper!
== v4.0.7.1 ==== - cloning speed-up

Wyświetl plik

@ -42,7 +42,7 @@
/*global modules, contains*/
modules.locale = '2016-May-02';
modules.locale = '2016-May-04';
// Global stuff

Wyświetl plik

@ -337,7 +337,7 @@
(c) an application
-------------------
Of course, most of the time you don't want to just plain use the
standard Morhic World "as is" out of the box, but write your own
standard Morphic World "as is" out of the box, but write your own
application (something like Scratch!) in it. For such an
application you'll create your own morph prototypes, perhaps
assemble your own "window frame" and bring it all to life in a
@ -1054,10 +1054,9 @@
// Global settings /////////////////////////////////////////////////////
/*global window, HTMLCanvasElement, getMinimumFontHeight, FileReader, Audio,
FileList, getBlurredShadowSupport*/
/*global window, HTMLCanvasElement, FileReader, Audio, FileList*/
var morphicVersion = '2016-February-24';
var morphicVersion = '2016-May-04';
var modules = {}; // keep track of additional loaded modules
var useBlurredShadows = getBlurredShadowSupport(); // check for Chrome-bug
@ -1938,7 +1937,7 @@ Rectangle.prototype.round = function () {
Rectangle.prototype.spread = function () {
// round me by applying floor() to my origin and ceil() to my corner
// expand by 1 to be on the safe side, this eliminates rounding
// artefacts caused by Safari's auto-scaling on retina displays
// artifacts caused by Safari's auto-scaling on retina displays
return this.origin.floor().corner(this.corner.ceil()).expandBy(1);
};
@ -2090,6 +2089,20 @@ Node.prototype.forAllChildren = function (aFunction) {
aFunction.call(null, this);
};
Node.prototype.anyChild = function (aPredicate) {
// includes myself
var i;
if (aPredicate.call(null, this)) {
return true;
}
for (i = 0; i < this.children.length; i += 1) {
if (this.children[i].anyChild(aPredicate)) {
return true;
}
}
return false;
};
Node.prototype.allLeafs = function () {
var result = [];
this.allChildren().forEach(function (element) {

Wyświetl plik

@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph*/
modules.objects = '2016-May-02';
modules.objects = '2016-May-04';
var SpriteMorph;
var StageMorph;
@ -1364,7 +1364,7 @@ SpriteMorph.prototype.init = function (globals) {
// SpriteMorph duplicating (fullCopy)
SpriteMorph.prototype.fullCopy = function () {
SpriteMorph.prototype.fullCopy = function (forClone) {
var c = SpriteMorph.uber.fullCopy.call(this),
myself = this,
arr = [],
@ -1374,20 +1374,22 @@ SpriteMorph.prototype.fullCopy = function () {
c.color = this.color.copy();
c.blocksCache = {};
c.paletteCache = {};
c.scripts = this.scripts.fullCopy();
c.scripts = this.scripts.fullCopy(forClone);
c.scripts.owner = c;
c.variables = this.variables.copy();
c.variables.owner = c;
c.customBlocks = [];
this.customBlocks.forEach(function (def) {
cb = def.copyAndBindTo(c);
c.customBlocks.push(cb);
c.allBlockInstances(def).forEach(function (block) {
block.definition = cb;
if (!forClone) {
this.customBlocks.forEach(function (def) {
cb = def.copyAndBindTo(c);
c.customBlocks.push(cb);
c.allBlockInstances(def).forEach(function (block) {
block.definition = cb;
});
});
});
}
this.costumes.asArray().forEach(function (costume) {
var cst = costume.copy();
var cst = forClone ? costume : costume.copy();
arr.push(cst);
if (costume === myself.costume) {
c.costume = cst;
@ -1404,12 +1406,11 @@ SpriteMorph.prototype.fullCopy = function () {
c.anchor = null;
c.parts = [];
this.parts.forEach(function (part) {
var dp = part.fullCopy();
var dp = part.fullCopy(forClone);
dp.nestingScale = part.nestingScale;
dp.rotatesWithAnchor = part.rotatesWithAnchor;
c.attachPart(dp);
});
return c;
};
@ -2834,12 +2835,30 @@ SpriteMorph.prototype.remove = function () {
}
};
// SpriteMorph cloning (experimental)
// SpriteMorph cloning
/*
clones are temporary, partially shallow copies of sprites that don't
appear as icons in the corral. Clones get deleted when the red stop button
is pressed. Shallow-copying clones' scripts and costumes makes spawning
very fast, so they can be used for particle system simulations.
This speed-up, however, comes at the cost of some detrimental side
effects: Changes to a costume or a script of the original sprite are
in some cases shared with all of its clones, however such shared changes
are hard to predict for users and not actively propagated, so they don't
offer any reliable feature, and will not be supported as such.
Changes to the original sprite's scripts affect all of its clones, unless
the script contains any custom block whose definition contains one or more
block variables (in which case the script does get deep-copied).
The original sprite's scripting area, costumes wardrobe or sounds jukebox
are also not shared. therefore adding or deleting a script, sound or
costume in the original sprite has no effect on any of its clones.
*/
SpriteMorph.prototype.createClone = function () {
var stage = this.parentThatIsA(StageMorph);
if (stage && stage.cloneCount <= 1000) {
this.fullCopy().clonify(stage);
if (stage && stage.cloneCount <= 2000) {
this.fullCopy(true).clonify(stage);
}
};
@ -6636,7 +6655,6 @@ Costume.prototype.copy = function () {
var canvas = newCanvas(this.extent()),
cpy,
ctx;
ctx = canvas.getContext('2d');
ctx.drawImage(this.contents, 0, 0);
cpy = new Costume(canvas, this.name ? copy(this.name) : null);

Wyświetl plik

@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
TableFrameMorph, isSnapObject*/
modules.threads = '2016-May-02';
modules.threads = '2016-May-04';
var ThreadManager;
var Process;
@ -354,7 +354,7 @@ ThreadManager.prototype.doWhen = function (block, stopIt) {
if (invoke(
pred,
null,
null,
block.receiver(), // needed for shallow copied clones - was null
50,
'the predicate takes\ntoo long for a\ncustom hat block',
true // suppress errors => handle them right here instead