kopia lustrzana https://github.com/backface/turtlestitch
migrated sprite rendering
rodzic
6c5acd1111
commit
cb3ac6c033
|
|
@ -34,8 +34,8 @@
|
|||
var world;
|
||||
window.onload = function () {
|
||||
world = new WorldMorph(document.getElementById('world'));
|
||||
world.isDevMode = true; // +++
|
||||
// new IDE_Morph().openIn(world);
|
||||
world.isDevMode = false;
|
||||
new IDE_Morph().openIn(world);
|
||||
loop();
|
||||
};
|
||||
function loop() {
|
||||
|
|
|
|||
173
src/objects.js
173
src/objects.js
|
|
@ -84,7 +84,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, BooleanSlotMorph,
|
|||
localize, TableMorph, TableFrameMorph, normalizeCanvas, VectorPaintEditorMorph,
|
||||
HandleMorph, AlignmentMorph, Process, XML_Element, WorldMap, copyCanvas*/
|
||||
|
||||
modules.objects = '2020-January-28';
|
||||
modules.objects = '2020-February-21';
|
||||
|
||||
var SpriteMorph;
|
||||
var StageMorph;
|
||||
|
|
@ -1654,7 +1654,7 @@ SpriteMorph.prototype.init = function (globals) {
|
|||
this.paletteCache = {}; // not to be serialized (!)
|
||||
this.rotationOffset = new Point(); // not to be serialized (!)
|
||||
this.idx = 0; // not to be serialized (!) - used for de-serialization
|
||||
this.wasWarped = false; // not to be serialized, used for fast-tracking
|
||||
this.wasWarped = false; // not to be serialized, used for fast-tracking // +++ is this needed anymore?
|
||||
|
||||
this.graphicsValues = {
|
||||
'color': 0,
|
||||
|
|
@ -1676,6 +1676,8 @@ SpriteMorph.prototype.init = function (globals) {
|
|||
this.cachedPropagation = false; // not to be persisted
|
||||
this.inheritedAttributes = []; // 'x position', 'direction', 'size' etc...
|
||||
|
||||
// video- and rendering state
|
||||
this.imageExtent = new Point(0, 0);
|
||||
this.imageData = {}; // version: date, pixels: Uint32Array
|
||||
this.motionAmount = 0;
|
||||
this.motionDirection = 0;
|
||||
|
|
@ -1683,13 +1685,13 @@ SpriteMorph.prototype.init = function (globals) {
|
|||
|
||||
SpriteMorph.uber.init.call(this);
|
||||
|
||||
this.isCachingImage = true;
|
||||
this.cachedHSV = this.color.hsv();
|
||||
this.isDraggable = true;
|
||||
this.isDown = false;
|
||||
this.heading = 90;
|
||||
this.changed();
|
||||
this.drawNew();
|
||||
this.changed();
|
||||
this.fixLayout();
|
||||
this.rerender();
|
||||
};
|
||||
|
||||
// SpriteMorph duplicating (fullCopy)
|
||||
|
|
@ -1807,13 +1809,25 @@ SpriteMorph.prototype.setName = function (string) {
|
|||
|
||||
// SpriteMorph rendering
|
||||
|
||||
SpriteMorph.prototype.drawNew = function () {
|
||||
SpriteMorph.prototype.getImage = function () {
|
||||
// overrides inherited method to allow for an image exceeding my bounds
|
||||
// to accommodate rotation and to disable retina resolution to
|
||||
// optimize graphics performance
|
||||
if (this.shouldRerender || !this.cachedImage) {
|
||||
this.cachedImage = newCanvas(this.imageExtent, true, this.cachedImage);
|
||||
this.render(this.cachedImage.getContext('2d'));
|
||||
this.shouldRerender = false;
|
||||
}
|
||||
return this.cachedImage;
|
||||
};
|
||||
|
||||
SpriteMorph.prototype.fixLayout = function () {
|
||||
// determine my extent and the extent designated for my cached image
|
||||
var myself = this,
|
||||
currentCenter,
|
||||
facing, // actual costume heading based on my rotation style
|
||||
isFlipped,
|
||||
isLoadingCostume,
|
||||
cst,
|
||||
pic, // (flipped copy of) actual costume based on my rotation style
|
||||
imageSide,
|
||||
stageScale,
|
||||
|
|
@ -1822,14 +1836,8 @@ SpriteMorph.prototype.drawNew = function () {
|
|||
origin,
|
||||
shift,
|
||||
corner,
|
||||
costumeExtent,
|
||||
ctx,
|
||||
handle;
|
||||
costumeExtent;
|
||||
|
||||
if (this.isWarped) {
|
||||
this.wantsRedraw = true;
|
||||
return;
|
||||
}
|
||||
currentCenter = this.center();
|
||||
isLoadingCostume = this.costume &&
|
||||
typeof this.costume.loaded === 'function';
|
||||
|
|
@ -1844,32 +1852,34 @@ SpriteMorph.prototype.drawNew = function () {
|
|||
}
|
||||
}
|
||||
if (this.costume && !isLoadingCostume) {
|
||||
pic = isFlipped ? this.costume.flipped() : this.costume;
|
||||
pic = isFlipped ? this.costume.flipped() : this.costume;
|
||||
|
||||
// determine the rotated costume's bounding box
|
||||
corners = pic.bounds().corners().map(function (point) {
|
||||
return point.rotateBy(
|
||||
radians(facing - 90),
|
||||
myself.costume.center()
|
||||
);
|
||||
});
|
||||
origin = corners[0];
|
||||
corner = corners[0];
|
||||
corners.forEach(function (point) {
|
||||
origin = origin.min(point);
|
||||
corner = corner.max(point);
|
||||
});
|
||||
costumeExtent = origin.corner(corner)
|
||||
.extent().multiplyBy(this.scale * stageScale);
|
||||
// determine the rotated costume's bounding box
|
||||
corners = pic.bounds().corners().map(function (point) {
|
||||
return point.rotateBy(
|
||||
radians(facing - 90),
|
||||
myself.costume.center()
|
||||
);
|
||||
});
|
||||
origin = corners[0];
|
||||
corner = corners[0];
|
||||
corners.forEach(function (point) {
|
||||
origin = origin.min(point);
|
||||
corner = corner.max(point);
|
||||
});
|
||||
costumeExtent = origin.corner(corner)
|
||||
.extent().multiplyBy(this.scale * stageScale);
|
||||
|
||||
// determine the new relative origin of the rotated shape
|
||||
shift = new Point(0, 0).rotateBy(
|
||||
radians(-(facing - 90)),
|
||||
pic.center()
|
||||
).subtract(origin);
|
||||
// determine the new relative origin of the rotated shape
|
||||
shift = new Point(0, 0).rotateBy(
|
||||
radians(-(facing - 90)),
|
||||
pic.center()
|
||||
).subtract(origin);
|
||||
|
||||
// determine an adequately dimensioned image extent, so the
|
||||
// shape on the canvas ran be rotated without having to create
|
||||
// a new canvas each time
|
||||
|
||||
// create a new, adequately dimensioned canvas
|
||||
// and draw the costume on it
|
||||
if (this.rotationStyle === 1) { // rotate freely in all directions
|
||||
// create a canvas that is big enough, so the sprite's current
|
||||
// costume can be fully rotated inside, so we can recycle
|
||||
|
|
@ -1886,30 +1896,16 @@ SpriteMorph.prototype.drawNew = function () {
|
|||
imageSide = Math.sqrt(
|
||||
Math.pow(pic.width(), 2) + Math.pow(pic.height(), 2)
|
||||
) * this.scale * stageScale;
|
||||
this.image = newCanvas(
|
||||
new Point(imageSide, imageSide),
|
||||
true,
|
||||
this.image
|
||||
);
|
||||
this.imageExtent = Point(imageSide, imageSide);
|
||||
} else { // don't actually rotate
|
||||
this.image = newCanvas(costumeExtent, true, this.image);
|
||||
this.imageExtent = costumeExtent;
|
||||
}
|
||||
this.silentSetExtent(costumeExtent);
|
||||
ctx = this.image.getContext('2d');
|
||||
ctx.save();
|
||||
ctx.scale(this.scale * stageScale, this.scale * stageScale);
|
||||
ctx.translate(shift.x, shift.y);
|
||||
ctx.rotate(radians(facing - 90));
|
||||
ctx.drawImage(pic.contents, 0, 0);
|
||||
ctx.restore();
|
||||
this.bounds.setExtent(costumeExtent);
|
||||
|
||||
// apply graphics effects to image
|
||||
this.image = this.applyGraphicsEffects(this.image);
|
||||
|
||||
// adjust my position to the rotation
|
||||
// adjust my position to the rotation // +++ why do we need this?
|
||||
this.setCenter(currentCenter, true); // just me
|
||||
|
||||
// determine my rotation offset
|
||||
// determine my rotation offset // +++ why do we need this?
|
||||
this.rotationOffset = shift
|
||||
.translateBy(pic.rotationCenter)
|
||||
.rotateBy(radians(-(facing - 90)), shift)
|
||||
|
|
@ -1923,11 +1919,61 @@ SpriteMorph.prototype.drawNew = function () {
|
|||
),
|
||||
1000
|
||||
);
|
||||
this.silentSetExtent(new Point(newX, newX));
|
||||
this.bounds.setWidth(newX);
|
||||
this.bounds.setHeight(newX);
|
||||
this.setCenter(currentCenter, true); // just me
|
||||
SpriteMorph.uber.drawNew.call(this, facing, this.image); // recycle
|
||||
this.rotationOffset = this.extent().divideBy(2);
|
||||
this.image = this.applyGraphicsEffects(this.image);
|
||||
}
|
||||
this.version = Date.now();
|
||||
};
|
||||
|
||||
SpriteMorph.prototype.render = function (ctx) {
|
||||
var myself = this,
|
||||
facing, // actual costume heading based on my rotation style
|
||||
isFlipped,
|
||||
isLoadingCostume,
|
||||
cst,
|
||||
pic, // (flipped copy of) actual costume based on my rotation style
|
||||
stageScale,
|
||||
origin,
|
||||
shift,
|
||||
handle;
|
||||
|
||||
isLoadingCostume = this.costume &&
|
||||
typeof this.costume.loaded === 'function';
|
||||
stageScale = this.parent instanceof StageMorph ?
|
||||
this.parent.scale : 1;
|
||||
facing = this.rotationStyle ? this.heading : 90;
|
||||
if (this.rotationStyle === 2) {
|
||||
facing = 90;
|
||||
if ((this.heading > 180 && (this.heading < 360))
|
||||
|| (this.heading < 0 && (this.heading > -180))) {
|
||||
isFlipped = true;
|
||||
}
|
||||
}
|
||||
if (this.costume && !isLoadingCostume) {
|
||||
pic = isFlipped ? this.costume.flipped() : this.costume;
|
||||
|
||||
// determine the relative origin of the rotated shape
|
||||
origin = pic.bounds().origin.rotateBy(
|
||||
radians(facing - 90),
|
||||
this.costume.center()
|
||||
);
|
||||
shift = new Point(0, 0).rotateBy(
|
||||
radians(-(facing - 90)),
|
||||
pic.center()
|
||||
).subtract(origin);
|
||||
|
||||
ctx.save();
|
||||
ctx.scale(this.scale * stageScale, this.scale * stageScale);
|
||||
ctx.translate(shift.x, shift.y);
|
||||
ctx.rotate(radians(facing - 90));
|
||||
ctx.drawImage(pic.contents, 0, 0);
|
||||
ctx.restore();
|
||||
|
||||
} else {
|
||||
SpriteMorph.uber.render.call(this, ctx);
|
||||
|
||||
if (isLoadingCostume) { // retry until costume is done loading
|
||||
cst = this.costume;
|
||||
handle = setInterval(
|
||||
|
|
@ -1940,10 +1986,11 @@ SpriteMorph.prototype.drawNew = function () {
|
|||
return myself.wearCostume(null, true);
|
||||
}
|
||||
}
|
||||
this.version = Date.now(); // for observer optimization
|
||||
// apply graphics effects to image
|
||||
// +++ this.cachedImage = this.applyGraphicsEffects(this.cachedImage); // +++ graphic effects disabled while working on rendering
|
||||
};
|
||||
|
||||
SpriteMorph.prototype.endWarp = function () {
|
||||
SpriteMorph.prototype.endWarp = function () { // +++ is this needed anymore?
|
||||
this.isWarped = false;
|
||||
if (this.wantsRedraw) {
|
||||
var x = this.xPosition(),
|
||||
|
|
@ -1975,7 +2022,7 @@ SpriteMorph.prototype.getImageData = function () {
|
|||
imageData;
|
||||
canvasContext = canvas.getContext("2d");
|
||||
canvasContext.drawImage(
|
||||
this.image,
|
||||
this.getImage(),
|
||||
0, 0, Math.floor(ext.x),
|
||||
Math.floor(ext.y),
|
||||
0, 0, newExtent.x, newExtent.y
|
||||
|
|
@ -1998,7 +2045,7 @@ SpriteMorph.prototype.projectionSnap = function() {
|
|||
var stage = this.parentThatIsA(StageMorph),
|
||||
center = this.center().subtract(stage.position())
|
||||
.divideBy(stage.scale),
|
||||
cst = this.costume || this.image,
|
||||
cst = this.costume || this.getImage(),
|
||||
w, h, rot,
|
||||
offset,
|
||||
snap,
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue