diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js index 56c7c49d..09cfc2e1 100644 --- a/src/RenderWebGL.js +++ b/src/RenderWebGL.js @@ -133,6 +133,13 @@ class RenderWebGL extends EventEmitter { throw new Error('Could not get WebGL context: this browser or environment may not support WebGL.'); } + this._mystery = { + modeActive: false, + mouseMoveListener: null, + bufferInfo: null, + mouseCoords: [0, 0] + }; + /** @type {RenderWebGL.UseGpuModes} */ this._useGpuMode = RenderWebGL.UseGpuModes.Automatic; @@ -223,6 +230,12 @@ class RenderWebGL extends EventEmitter { const pixelRatio = window.devicePixelRatio || 1; this._gl.canvas.width = pixelsWide * pixelRatio; this._gl.canvas.height = pixelsTall * pixelRatio; + + if (this._mystery.modeActive && this._mystery.bufferInfo) { + twgl.resizeFramebufferInfo(this._gl, this._mystery.bufferInfo, [ + {format: this._gl.RGBA} + ], pixelsWide * pixelRatio, pixelsTall * pixelRatio); + } } /** @@ -615,7 +628,43 @@ class RenderWebGL extends EventEmitter { gl.clearColor.apply(gl, this._backgroundColor); gl.clear(gl.COLOR_BUFFER_BIT); - this._drawThese(this._drawList, ShaderManager.DRAW_MODE.default, this._projection); + let drawList = this._drawList; + if (this._mystery.modeActive) { + drawList = drawList.slice(1); + twgl.bindFramebufferInfo(gl, this._mystery.bufferInfo); + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + } + this._drawThese(drawList, ShaderManager.DRAW_MODE.default, this._projection); + + if (this._mystery.modeActive) { + // draw all layers except for the bottom layer onto the mystery buffer + twgl.bindFramebufferInfo(gl, null); + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); + this._drawThese([this._drawList[0]], ShaderManager.DRAW_MODE.default, this._projection); + + this._doExitDrawRegion(); + const newShader = this._shaderManager.getShader(ShaderManager.DRAW_MODE.mystery, 0); + this._regionId = newShader; + + // draw mystery buffer to main buffer + gl.useProgram(newShader.program); + twgl.setBuffersAndAttributes(gl, newShader, this._bufferInfo); + const uniforms = { + u_projectionMatrix: this._projection, + u_modelMatrix: twgl.m4.identity(), + u_skin: this._mystery.bufferInfo.attachments[0], + u_mousePosition: this._mystery.mouseCoords + }; + + twgl.setTextureParameters( + gl, uniforms.u_skin, {minMag: gl.LINEAR} + ); + + twgl.setUniforms(newShader, uniforms); + twgl.drawBufferInfo(gl, this._bufferInfo, gl.TRIANGLES); + } + if (this._snapshotCallbacks.length > 0) { const snapshot = gl.canvas.toDataURL(); this._snapshotCallbacks.forEach(cb => cb(snapshot)); @@ -1909,6 +1958,32 @@ class RenderWebGL extends EventEmitter { return dst; } + setMysteryMode (enableMysteryMode) { + this._mystery.modeActive = enableMysteryMode; + + if (enableMysteryMode) { + this._mystery.bufferInfo = twgl.createFramebufferInfo( + this._gl, + [{format: this._gl.RGBA}], + this._gl.drawingBufferWidth, + this._gl.drawingBufferHeight + ); + + this._mystery.mouseMoveListener = event => { + const rect = this.canvas.getBoundingClientRect(); + this._mystery.mouseCoords[0] = (event.clientX - rect.left) / rect.width; + this._mystery.mouseCoords[1] = (event.clientY - rect.top) / rect.height; + }; + + document.addEventListener('mousemove', this._mystery.mouseMoveListener); + } else { + if (this._mystery.bufferInfo) { + this._gl.deleteFramebuffer(this._mystery.bufferInfo.framebuffer); + } + document.removeEventListener('mousemove', this._mystery.mouseMoveListener); + } + } + /** * @callback RenderWebGL#snapshotCallback * @param {string} dataURI Data URI of the snapshot of the renderer diff --git a/src/ShaderManager.js b/src/ShaderManager.js index a71ef2d2..22cd236f 100644 --- a/src/ShaderManager.js +++ b/src/ShaderManager.js @@ -171,7 +171,9 @@ ShaderManager.DRAW_MODE = { /** * Sample a "texture" to draw a line with caps. */ - lineSample: 'lineSample' + lineSample: 'lineSample', + + mystery: 'mystery' }; module.exports = ShaderManager; diff --git a/src/shaders/sprite.frag b/src/shaders/sprite.frag index 13fe19de..b4b1d6ce 100644 --- a/src/shaders/sprite.frag +++ b/src/shaders/sprite.frag @@ -39,6 +39,10 @@ uniform float u_capScale; uniform float u_aliasAmount; #endif // DRAW_MODE_lineSample +#ifdef DRAW_MODE_mystery +uniform vec2 u_mousePosition; +#endif + uniform sampler2D u_skin; varying vec2 v_texCoord; @@ -112,6 +116,15 @@ void main() #ifndef DRAW_MODE_lineSample vec2 texcoord0 = v_texCoord; + #ifdef DRAW_MODE_mystery + vec2 mysteryCoord = texcoord0; + vec2 offset = vec2(u_mousePosition.x, 1.0 - u_mousePosition.y); + mysteryCoord -= offset; + const float SCALE_FACTOR = 0.85; + mysteryCoord *= vec2(SCALE_FACTOR, SCALE_FACTOR); + mysteryCoord += offset; + #endif + #ifdef ENABLE_mosaic texcoord0 = fract(u_mosaic * texcoord0); #endif // ENABLE_mosaic @@ -155,6 +168,21 @@ void main() gl_FragColor = texture2D(u_skin, texcoord0); + #ifdef DRAW_MODE_mystery + const vec4 SHADOW_COLOR = vec4(0.0, 0.0, 0.0, 0.5); + const float SHADOW_BLUR = 0.0025; + + float shadowSample1 = texture2D(u_skin, mysteryCoord + vec2(SHADOW_BLUR, SHADOW_BLUR)).a; + float shadowSample2 = texture2D(u_skin, mysteryCoord + vec2(-SHADOW_BLUR, SHADOW_BLUR)).a; + float shadowSample3 = texture2D(u_skin, mysteryCoord + vec2(SHADOW_BLUR, -SHADOW_BLUR)).a; + float shadowSample4 = texture2D(u_skin, mysteryCoord + vec2(-SHADOW_BLUR, -SHADOW_BLUR)).a; + + float shadowAlpha = (shadowSample1 + shadowSample2 + shadowSample3 + shadowSample4) * 0.25; + + vec4 shadow = SHADOW_COLOR * shadowAlpha; + gl_FragColor = gl_FragColor + (shadow * (1.0 - gl_FragColor.a)); + #endif + #if defined(ENABLE_color) || defined(ENABLE_brightness) // Divide premultiplied alpha values for proper color processing // Add epsilon to avoid dividing by 0 for fully transparent pixels diff --git a/src/shaders/sprite.vert b/src/shaders/sprite.vert index a9bbe150..8bb133cf 100644 --- a/src/shaders/sprite.vert +++ b/src/shaders/sprite.vert @@ -15,7 +15,9 @@ void main() { vec2 position = a_position; position.y = clamp(position.y * u_positionScalar, -0.5, 0.5); gl_Position = u_projectionMatrix * u_modelMatrix * vec4(position, 0, 1); - #else + #elif defined(DRAW_MODE_mystery) + gl_Position = vec4(a_position * vec2(-2.0, 2.0), 0.0, 1.0); + #else gl_Position = u_projectionMatrix * u_modelMatrix * vec4(a_position, 0, 1); #endif v_texCoord = a_texCoord;