Merge pull request #159 from paulkaplan/color-picking
Add color extraction method to renderer
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user