Compare commits
36 Commits
greenkeepe
...
greenkeepe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61e7c279b7 | ||
|
|
4a55d63ada | ||
|
|
c9c780aa69 | ||
|
|
590c2ca084 | ||
|
|
757d7e3c96 | ||
|
|
e365a909dc | ||
|
|
bffe80086e | ||
|
|
008dc5b15b | ||
|
|
9177705e04 | ||
|
|
b304ea8fdf | ||
|
|
f9428ee096 | ||
|
|
9526612d79 | ||
|
|
fb767b7553 | ||
|
|
e864018d87 | ||
|
|
e0b420a183 | ||
|
|
a24b853af6 | ||
|
|
73896b6f32 | ||
|
|
80630a64da | ||
|
|
e31934f6a9 | ||
|
|
8f007c0986 | ||
|
|
3c79a5562e | ||
|
|
d59d45b6c8 | ||
|
|
19ee8e8eaa | ||
|
|
fe01fea9d0 | ||
|
|
5fb9346036 | ||
|
|
3d373571f8 | ||
|
|
152cf028cc | ||
|
|
147b79d319 | ||
|
|
f2a7085492 | ||
|
|
996a1d6cf7 | ||
|
|
61bf4c84c3 | ||
|
|
7628c1e7f9 | ||
|
|
9f7bd971c9 | ||
|
|
44d2fdeba8 | ||
|
|
e022222365 | ||
|
|
be5ab2e689 |
@@ -42,7 +42,7 @@
|
||||
"travis-after-all": "^1.4.4",
|
||||
"uglifyjs-webpack-plugin": "^1.2.5",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-cli": "3.3.1",
|
||||
"webpack-dev-server": "^3.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -53,7 +53,7 @@
|
||||
"minilog": "3.1.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"scratch-storage": "^1.0.0",
|
||||
"scratch-svg-renderer": "0.2.0-prerelease.20190125192231",
|
||||
"scratch-svg-renderer": "0.2.0-prerelease.20190419183947",
|
||||
"twgl.js": "4.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,20 +79,31 @@ class BitmapSkin extends Skin {
|
||||
setBitmap (bitmapData, costumeResolution, rotationCenter) {
|
||||
const gl = this._renderer.gl;
|
||||
|
||||
// Preferably bitmapData is ImageData. ImageData speeds up updating
|
||||
// Silhouette and is better handled by more browsers in regards to
|
||||
// memory.
|
||||
let textureData = bitmapData;
|
||||
if (bitmapData instanceof HTMLCanvasElement) {
|
||||
// Given a HTMLCanvasElement get the image data to pass to webgl and
|
||||
// Silhouette.
|
||||
const context = bitmapData.getContext('2d');
|
||||
textureData = context.getImageData(0, 0, bitmapData.width, bitmapData.height);
|
||||
}
|
||||
|
||||
if (this._texture) {
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmapData);
|
||||
this._silhouette.update(bitmapData);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureData);
|
||||
this._silhouette.update(textureData);
|
||||
} else {
|
||||
// TODO: mipmaps?
|
||||
const textureOptions = {
|
||||
auto: true,
|
||||
wrap: gl.CLAMP_TO_EDGE,
|
||||
src: bitmapData
|
||||
src: textureData
|
||||
};
|
||||
|
||||
this._texture = twgl.createTexture(gl, textureOptions);
|
||||
this._silhouette.update(bitmapData);
|
||||
this._silhouette.update(textureData);
|
||||
}
|
||||
|
||||
// Do these last in case any of the above throws an exception
|
||||
|
||||
@@ -36,8 +36,10 @@ const getLocalPosition = (drawable, vec) => {
|
||||
// localPosition matches that transformation.
|
||||
localPosition[0] = 0.5 - (((v0 * m[0]) + (v1 * m[4]) + m[12]) / d);
|
||||
localPosition[1] = (((v0 * m[1]) + (v1 * m[5]) + m[13]) / d) + 0.5;
|
||||
// Apply texture effect transform.
|
||||
EffectTransform.transformPoint(drawable, localPosition, localPosition);
|
||||
// Apply texture effect transform if the localPosition is within the drawable's space.
|
||||
if ((localPosition[0] >= 0 && localPosition[0] < 1) && (localPosition[1] >= 0 && localPosition[1] < 1)) {
|
||||
EffectTransform.transformPoint(drawable, localPosition, localPosition);
|
||||
}
|
||||
return localPosition;
|
||||
};
|
||||
|
||||
|
||||
@@ -154,6 +154,13 @@ class PenSkin extends Skin {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if alpha is premultiplied, false otherwise
|
||||
*/
|
||||
get hasPremultipliedAlpha () {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Array<number>} the "native" size, in texels, of this skin. [width, height]
|
||||
*/
|
||||
@@ -181,8 +188,9 @@ class PenSkin extends Skin {
|
||||
clear () {
|
||||
const gl = this._renderer.gl;
|
||||
twgl.bindFramebufferInfo(gl, this._framebuffer);
|
||||
|
||||
gl.clearColor(1, 1, 1, 0);
|
||||
|
||||
/* Reset framebuffer to transparent black */
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
const ctx = this._canvas.getContext('2d');
|
||||
@@ -598,7 +606,7 @@ class PenSkin extends Skin {
|
||||
this._silhouetteBuffer = twgl.createFramebufferInfo(gl, [{format: gl.RGBA}], width, height);
|
||||
}
|
||||
|
||||
gl.clearColor(1, 1, 1, 0);
|
||||
gl.clearColor(0, 0, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
this._silhouetteDirty = true;
|
||||
|
||||
@@ -1620,7 +1620,14 @@ class RenderWebGL extends EventEmitter {
|
||||
}
|
||||
|
||||
twgl.setUniforms(currentShader, uniforms);
|
||||
|
||||
|
||||
/* adjust blend function for this skin */
|
||||
if (drawable.skin.hasPremultipliedAlpha){
|
||||
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
} else {
|
||||
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
twgl.drawBufferInfo(gl, this._bufferInfo, gl.TRIANGLES);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,14 @@ class SVGSkin extends Skin {
|
||||
this._textureScale = newScale;
|
||||
this._svgRenderer._draw(this._textureScale, () => {
|
||||
if (this._textureScale === newScale) {
|
||||
const canvas = this._svgRenderer.canvas;
|
||||
const context = canvas.getContext('2d');
|
||||
const textureData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const gl = this._renderer.gl;
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);
|
||||
this._silhouette.update(this._svgRenderer.canvas);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureData);
|
||||
this._silhouette.update(textureData);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -99,20 +103,28 @@ class SVGSkin extends Skin {
|
||||
this._svgRenderer.fromString(svgData, 1, () => {
|
||||
const gl = this._renderer.gl;
|
||||
this._textureScale = this._maxTextureScale = 1;
|
||||
|
||||
// Pull out the ImageData from the canvas. ImageData speeds up
|
||||
// updating Silhouette and is better handled by more browsers in
|
||||
// regards to memory.
|
||||
const canvas = this._svgRenderer.canvas;
|
||||
const context = canvas.getContext('2d');
|
||||
const textureData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||
|
||||
if (this._texture) {
|
||||
gl.bindTexture(gl.TEXTURE_2D, this._texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._svgRenderer.canvas);
|
||||
this._silhouette.update(this._svgRenderer.canvas);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureData);
|
||||
this._silhouette.update(textureData);
|
||||
} else {
|
||||
// TODO: mipmaps?
|
||||
const textureOptions = {
|
||||
auto: true,
|
||||
wrap: gl.CLAMP_TO_EDGE,
|
||||
src: this._svgRenderer.canvas
|
||||
src: textureData
|
||||
};
|
||||
|
||||
this._texture = twgl.createTexture(gl, textureOptions);
|
||||
this._silhouette.update(this._svgRenderer.canvas);
|
||||
this._silhouette.update(textureData);
|
||||
}
|
||||
|
||||
const maxDimension = Math.max(this._svgRenderer.canvas.width, this._svgRenderer.canvas.height);
|
||||
|
||||
@@ -19,12 +19,12 @@ let __SilhouetteUpdateCanvas;
|
||||
* @param {number} y - y
|
||||
* @return {number} Alpha value for x/y position
|
||||
*/
|
||||
const getPoint = ({_width: width, _height: height, _data: data}, x, y) => {
|
||||
const getPoint = ({_width: width, _height: height, _colorData: data}, x, y) => {
|
||||
// 0 if outside bouds, otherwise read from data.
|
||||
if (x >= width || y >= height || x < 0 || y < 0) {
|
||||
return 0;
|
||||
}
|
||||
return data[(y * width) + x];
|
||||
return data[(((y * width) + x) * 4) + 3];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,6 @@ class Silhouette {
|
||||
* The data representing a skin's silhouette shape.
|
||||
* @type {Uint8ClampedArray}
|
||||
*/
|
||||
this._data = null;
|
||||
this._colorData = null;
|
||||
|
||||
this.colorAtNearest = this.colorAtLinear = (_, dst) => dst.fill(0);
|
||||
@@ -88,28 +87,33 @@ class Silhouette {
|
||||
* rendering can be queried from.
|
||||
*/
|
||||
update (bitmapData) {
|
||||
const canvas = Silhouette._updateCanvas();
|
||||
const width = this._width = canvas.width = bitmapData.width;
|
||||
const height = this._height = canvas.height = bitmapData.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
let imageData;
|
||||
if (bitmapData instanceof ImageData) {
|
||||
// If handed ImageData directly, use it directly.
|
||||
imageData = bitmapData;
|
||||
this._width = bitmapData.width;
|
||||
this._height = bitmapData.height;
|
||||
} else {
|
||||
// Draw about anything else to our update canvas and poll image data
|
||||
// from that.
|
||||
const canvas = Silhouette._updateCanvas();
|
||||
const width = this._width = canvas.width = bitmapData.width;
|
||||
const height = this._height = canvas.height = bitmapData.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
if (!(width && height)) {
|
||||
return;
|
||||
if (!(width && height)) {
|
||||
return;
|
||||
}
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.drawImage(bitmapData, 0, 0, width, height);
|
||||
imageData = ctx.getImageData(0, 0, width, height);
|
||||
}
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.drawImage(bitmapData, 0, 0, width, height);
|
||||
const imageData = ctx.getImageData(0, 0, width, height);
|
||||
|
||||
this._data = new Uint8ClampedArray(imageData.data.length / 4);
|
||||
this._colorData = imageData.data;
|
||||
// delete our custom overriden "uninitalized" color functions
|
||||
// let the prototype work for itself
|
||||
delete this.colorAtNearest;
|
||||
delete this.colorAtLinear;
|
||||
|
||||
for (let i = 0; i < imageData.data.length; i += 4) {
|
||||
this._data[i / 4] = imageData.data[i + 3];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,7 +170,7 @@ class Silhouette {
|
||||
* @return {boolean} If the nearest pixel has an alpha value.
|
||||
*/
|
||||
isTouchingNearest (vec) {
|
||||
if (!this._data) return;
|
||||
if (!this._colorData) return;
|
||||
return getPoint(
|
||||
this,
|
||||
Math.floor(vec[0] * (this._width - 1)),
|
||||
@@ -181,7 +185,7 @@ class Silhouette {
|
||||
* @return {boolean} Any of the pixels have some alpha.
|
||||
*/
|
||||
isTouchingLinear (vec) {
|
||||
if (!this._data) return;
|
||||
if (!this._colorData) return;
|
||||
const x = Math.floor(vec[0] * (this._width - 1));
|
||||
const y = Math.floor(vec[1] * (this._height - 1));
|
||||
return getPoint(this, x, y) > 0 ||
|
||||
|
||||
@@ -76,6 +76,13 @@ class Skin extends EventEmitter {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if alpha is premultiplied, false otherwise
|
||||
*/
|
||||
get hasPremultipliedAlpha () {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {int} the unique ID for this Skin.
|
||||
*/
|
||||
|
||||
@@ -194,12 +194,6 @@ void main()
|
||||
discard;
|
||||
}
|
||||
#endif // DRAW_MODE_colorMask
|
||||
|
||||
// WebGL defaults to premultiplied alpha
|
||||
#ifndef DRAW_MODE_stamp
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
#endif // DRAW_MODE_stamp
|
||||
|
||||
#endif // DRAW_MODE_silhouette
|
||||
|
||||
#else // DRAW_MODE_lineSample
|
||||
|
||||
Reference in New Issue
Block a user