Implement color-touching-color
The `isTouchingColor` function now takes an optional mask parameter. If provided, only the parts of the Drawable which match the mask color will be used for the test. For example: ``` isTouchingColor(4, red, blue); ``` This means "are there any parts of Drawable #4 which are blue and are touching a red pixel on some other Drawable?"
This commit is contained in:
parent
6b0f3379bf
commit
9f59b42901
@ -119,8 +119,20 @@ Drawable.EFFECTS = Object.keys(Drawable._effectConverter);
|
||||
* @enum {string}
|
||||
*/
|
||||
Drawable.DRAW_MODE = {
|
||||
/**
|
||||
* Draw normally.
|
||||
*/
|
||||
default: 'default',
|
||||
pick: 'pick'
|
||||
|
||||
/**
|
||||
* Draw the Drawable's silhouette using a particular color.
|
||||
*/
|
||||
silhouette: 'silhouette',
|
||||
|
||||
/**
|
||||
* Draw only the parts of the drawable which match a particular color.
|
||||
*/
|
||||
colorMask: 'colorMask'
|
||||
};
|
||||
|
||||
/**
|
||||
@ -238,7 +250,7 @@ Drawable.prototype._useSkin = function(
|
||||
/**
|
||||
* Fetch the shader for this Drawable's set of active effects.
|
||||
* Build the shader if necessary.
|
||||
* @param {Drawable.DRAW_MODE} drawMode Draw normally or for picking, etc.
|
||||
* @param {Drawable.DRAW_MODE} drawMode Draw normally, silhouette, etc.
|
||||
* @returns {module:twgl.ProgramInfo?} The shader's program info.
|
||||
*/
|
||||
Drawable.prototype.getShader = function (drawMode) {
|
||||
@ -255,7 +267,7 @@ Drawable.prototype.getShader = function (drawMode) {
|
||||
|
||||
/**
|
||||
* Build the shader for this Drawable's set of active effects.
|
||||
* @param {Drawable.DRAW_MODE} drawMode Draw normally or for picking, etc.
|
||||
* @param {Drawable.DRAW_MODE} drawMode Draw normally, silhouette, etc.
|
||||
* @returns {module:twgl.ProgramInfo?} The new shader's program info.
|
||||
* @private
|
||||
*/
|
||||
|
@ -128,13 +128,14 @@ RenderWebGL.prototype.draw = function () {
|
||||
/**
|
||||
* Draw all Drawables, with the possible exception of
|
||||
* @param {int[]} drawables The Drawable IDs to draw, possibly this._drawables.
|
||||
* @param {Drawable.DRAW_MODE} drawMode Draw normally or for picking, etc.
|
||||
* @param {Drawable.DRAW_MODE} drawMode Draw normally, silhouette, etc.
|
||||
* @param {module:twgl/m4.Mat4} projection The projection matrix to use.
|
||||
* @param {Drawable~idFilterFunc} [filter] An optional filter function.
|
||||
* @param {Object.<string,*>} [extraUniforms] Extra uniforms for the shaders.
|
||||
* @private
|
||||
*/
|
||||
RenderWebGL.prototype._drawThese = function(
|
||||
drawables, drawMode, projection, filter) {
|
||||
drawables, drawMode, projection, filter, extraUniforms) {
|
||||
|
||||
var gl = this._gl;
|
||||
var currentShader = null;
|
||||
@ -156,14 +157,20 @@ RenderWebGL.prototype._drawThese = function(
|
||||
twgl.setBuffersAndAttributes(gl, currentShader, this._bufferInfo);
|
||||
twgl.setUniforms(currentShader, {u_projectionMatrix: projection});
|
||||
twgl.setUniforms(currentShader, {u_fudge: window.fudge || 0});
|
||||
|
||||
// TODO: should these be set after the Drawable's uniforms?
|
||||
// That would allow Drawable-scope uniforms to be overridden...
|
||||
if (extraUniforms) {
|
||||
twgl.setUniforms(currentShader, extraUniforms);
|
||||
}
|
||||
}
|
||||
|
||||
twgl.setUniforms(currentShader, drawable.getUniforms());
|
||||
|
||||
// TODO: consider moving u_pickColor into Drawable's getUniforms()...
|
||||
if (drawMode == Drawable.DRAW_MODE.pick) {
|
||||
// TODO: move u_silhouetteColor into Drawable's getUniforms()
|
||||
if (drawMode == Drawable.DRAW_MODE.silhouette) {
|
||||
twgl.setUniforms(currentShader,
|
||||
{u_pickColor: Drawable.color4fFromID(drawableID)});
|
||||
{u_silhouetteColor: Drawable.color4fFromID(drawableID)});
|
||||
}
|
||||
|
||||
twgl.drawBufferInfo(gl, gl.TRIANGLES, this._bufferInfo);
|
||||
@ -329,7 +336,7 @@ RenderWebGL.prototype.pick = function (
|
||||
var projection = twgl.m4.ortho(
|
||||
pickLeft, pickRight, pickTop, pickBottom, -1, 1);
|
||||
|
||||
this._drawThese(candidateIDs, Drawable.DRAW_MODE.pick, projection);
|
||||
this._drawThese(candidateIDs, Drawable.DRAW_MODE.silhouette, projection);
|
||||
|
||||
var pixels = new Buffer(touchWidth * touchHeight * 4);
|
||||
gl.readPixels(
|
||||
@ -371,7 +378,15 @@ RenderWebGL.prototype.pick = function (
|
||||
return hit | 0;
|
||||
};
|
||||
|
||||
RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub) {
|
||||
/**
|
||||
* Check if a particular Drawable is touching a particular color.
|
||||
* @param {int} drawableID The ID of the Drawable to check.
|
||||
* @param {int[]} color3ub Test if the Drawable is touching this color.
|
||||
* @param {float[]} [mask3f] Optionally mask the check to this part of Drawable.
|
||||
* @returns {boolean} True iff the Drawable is touching the color.
|
||||
*/
|
||||
RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub, mask3f) {
|
||||
|
||||
var gl = this._gl;
|
||||
|
||||
twgl.bindFramebufferInfo(gl, this._queryBufferInfo);
|
||||
@ -385,13 +400,26 @@ RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub) {
|
||||
gl.clearColor.apply(gl, this._backgroundColor);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
||||
|
||||
var extraUniforms;
|
||||
if (mask3f) {
|
||||
extraUniforms = {
|
||||
u_colorMask: mask3f,
|
||||
u_colorMaskTolerance: 1 / 255
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
gl.enable(gl.STENCIL_TEST);
|
||||
gl.stencilFunc(gl.ALWAYS, 1, 1);
|
||||
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
|
||||
gl.colorMask(false, false, false, false);
|
||||
this._drawThese(
|
||||
[drawableID], Drawable.DRAW_MODE.pick, this._projection);
|
||||
[drawableID],
|
||||
mask3f ?
|
||||
Drawable.DRAW_MODE.colorMask : Drawable.DRAW_MODE.silhouette,
|
||||
this._projection,
|
||||
undefined,
|
||||
extraUniforms);
|
||||
|
||||
gl.stencilFunc(gl.EQUAL, 1, 1);
|
||||
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
|
||||
@ -432,6 +460,7 @@ RenderWebGL.prototype.isTouchingColor = function(drawableID, color3ub) {
|
||||
|
||||
for (var pixelBase = 0; pixelBase < pixels.length; pixelBase += 4) {
|
||||
// TODO: tolerance?
|
||||
// TODO: use u_colorMask to make this test something like "pixel != 0"
|
||||
if ((pixels[pixelBase] == color3ub[0]) &&
|
||||
(pixels[pixelBase + 1] == color3ub[1]) &&
|
||||
(pixels[pixelBase + 2] == color3ub[2])) {
|
||||
|
@ -2,16 +2,21 @@ precision mediump float;
|
||||
|
||||
uniform float u_fudge;
|
||||
|
||||
#ifdef DRAW_MODE_pick
|
||||
uniform vec4 u_pickColor;
|
||||
#else // DRAW_MODE_pick
|
||||
#ifdef DRAW_MODE_silhouette
|
||||
uniform vec4 u_silhouetteColor;
|
||||
#else // DRAW_MODE_silhouette
|
||||
# ifdef ENABLE_color
|
||||
uniform float u_color;
|
||||
# endif // ENABLE_color
|
||||
# ifdef ENABLE_brightness
|
||||
uniform float u_brightness;
|
||||
# endif // ENABLE_brightness
|
||||
#endif // DRAW_MODE_pick
|
||||
#endif // DRAW_MODE_silhouette
|
||||
|
||||
#ifdef DRAW_MODE_colorMask
|
||||
uniform vec3 u_colorMask;
|
||||
uniform float u_colorMaskTolerance;
|
||||
#endif // DRAW_MODE_colorMask
|
||||
|
||||
#ifdef ENABLE_fisheye
|
||||
uniform float u_fisheye;
|
||||
@ -34,7 +39,7 @@ uniform sampler2D u_skin;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
#if !defined(DRAW_MODE_pick) && (defined(ENABLE_color) || defined(ENABLE_brightness))
|
||||
#if !defined(DRAW_MODE_silhouette) && (defined(ENABLE_color) || defined(ENABLE_brightness))
|
||||
// Branchless color conversions based on code from:
|
||||
// http://www.chilliant.com/rgb2hsv.html by Ian Taylor
|
||||
// Based in part on work by Sam Hocevar and Emil Persson
|
||||
@ -72,7 +77,7 @@ vec3 convertHSL2RGB(vec3 hsl)
|
||||
float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
|
||||
return (rgb - 0.5) * c + hsl.z;
|
||||
}
|
||||
#endif // !defined(DRAW_MODE_pick) && (defined(ENABLE_color) || defined(ENABLE_brightness))
|
||||
#endif // !defined(DRAW_MODE_silhouette) && (defined(ENABLE_color) || defined(ENABLE_brightness))
|
||||
|
||||
const vec2 kCenter = vec2(0.5, 0.5);
|
||||
|
||||
@ -140,10 +145,10 @@ void main()
|
||||
discard;
|
||||
}
|
||||
|
||||
#ifdef DRAW_MODE_pick
|
||||
// switch to u_pickColor only AFTER the alpha test
|
||||
gl_FragColor = u_pickColor;
|
||||
#else // DRAW_MODE_pick
|
||||
#ifdef DRAW_MODE_silhouette
|
||||
// switch to u_silhouetteColor only AFTER the alpha test
|
||||
gl_FragColor = u_silhouetteColor;
|
||||
#else // DRAW_MODE_silhouette
|
||||
|
||||
#if defined(ENABLE_color) || defined(ENABLE_brightness)
|
||||
{
|
||||
@ -171,8 +176,17 @@ void main()
|
||||
}
|
||||
#endif // defined(ENABLE_color) || defined(ENABLE_brightness)
|
||||
|
||||
#ifdef DRAW_MODE_colorMask
|
||||
vec3 maskDistance = abs(gl_FragColor.rgb - u_colorMask);
|
||||
vec3 colorMaskTolerance = vec3(u_colorMaskTolerance, u_colorMaskTolerance, u_colorMaskTolerance);
|
||||
if (any(greaterThan(maskDistance, colorMaskTolerance)))
|
||||
{
|
||||
discard;
|
||||
}
|
||||
#endif // DRAW_MODE_colorMask
|
||||
|
||||
// WebGL defaults to premultiplied alpha
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
|
||||
#endif // DRAW_MODE_pick
|
||||
#endif // DRAW_MODE_silhouette
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user