Merge pull request #159 from paulkaplan/color-picking

Add color extraction method to renderer
This commit is contained in:
Paul Kaplan
2017-09-06 13:54:08 -04:00
committed by GitHub
2 changed files with 73 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ const twgl = require('twgl.js');
const BitmapSkin = require('./BitmapSkin');
const Drawable = require('./Drawable');
const Rectangle = require('./Rectangle');
const PenSkin = require('./PenSkin');
const RenderConstants = require('./RenderConstants');
const ShaderManager = require('./ShaderManager');
@@ -711,6 +712,73 @@ class RenderWebGL extends EventEmitter {
};
}
/**
* @typedef ColorExtraction
* @property {Uint8Array} data Raw pixel data for the drawable
* @property {int} width Drawable bounding box width
* @property {int} height Drawable bounding box height
* @property {object} color Color object with RGBA properties at picked location
*/
/**
* Return drawable pixel data and color at a given position
* @param {int} x The client x coordinate of the picking location.
* @param {int} y The client y coordinate of the picking location.
* @param {int} radius The client radius to extract pixels with.
* @return {?ColorExtraction} Data about the picked color
*/
extractColor (x, y, radius) {
const scratchX = Math.round(this._nativeSize[0] * ((x / this._gl.canvas.clientWidth) - 0.5));
const scratchY = Math.round(-this._nativeSize[1] * ((y / this._gl.canvas.clientHeight) - 0.5));
const gl = this._gl;
twgl.bindFramebufferInfo(gl, this._queryBufferInfo);
const bounds = new Rectangle();
bounds.initFromBounds(scratchX - radius, scratchX + radius, scratchY - radius, scratchY + radius);
const pickX = scratchX - bounds.left;
const pickY = bounds.top - scratchY;
gl.viewport(0, 0, bounds.width, bounds.height);
const projection = twgl.m4.ortho(bounds.left, bounds.right, bounds.top, bounds.bottom, -1, 1);
gl.clearColor.apply(gl, this._backgroundColor);
gl.clear(gl.COLOR_BUFFER_BIT);
this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, projection);
const data = new Uint8Array(Math.floor(bounds.width * bounds.height * 4));
gl.readPixels(0, 0, bounds.width, bounds.height, gl.RGBA, gl.UNSIGNED_BYTE, data);
const color = {
r: data[Math.floor(4 * (pickY * bounds.width + pickX))],
g: data[Math.floor(4 * (pickY * bounds.width + pickX)) + 1],
b: data[Math.floor(4 * (pickY * bounds.width + pickX)) + 2],
a: data[Math.floor(4 * (pickY * bounds.width + pickX)) + 3]
};
if (this._debugCanvas) {
this._debugCanvas.width = bounds.width;
this._debugCanvas.height = bounds.height;
const ctx = this._debugCanvas.getContext('2d');
const imageData = ctx.createImageData(bounds.width, bounds.height);
imageData.data.set(data);
ctx.putImageData(imageData, 0, 0);
ctx.strokeStyle = 'black';
ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})`;
ctx.rect(pickX - 4, pickY - 4, 8, 8);
ctx.fill();
ctx.stroke();
}
return {
data: data,
width: bounds.width,
height: bounds.height,
color: color
};
}
/**
* Get the candidate bounding box for a touching query.
* @param {int} drawableID ID for drawable of query.

View File

@@ -126,6 +126,11 @@
};
}
canvas.onmousemove = function(event) {
var mousePos = getMousePos(event, canvas);
renderer.extractColor(mousePos.x, mousePos.y, 30);
};
canvas.onclick = function(event) {
var mousePos = getMousePos(event, canvas);
var pickID = renderer.pick(mousePos.x, mousePos.y);