From 88d31483a2e542f7831cd648bc60a87dcbc5699a Mon Sep 17 00:00:00 2001 From: adroitwhiz Date: Sun, 22 Mar 2020 21:58:52 -0400 Subject: [PATCH] Enhance mysterious atmosphere --- src/RenderWebGL.js | 80 +++++++++++++++++++++++++++++++++++++++-- src/ShaderManager.js | 4 ++- src/shaders/sprite.frag | 28 +++++++++++++++ src/shaders/sprite.vert | 2 ++ 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js index b3f6a0a..0401110 100644 --- a/src/RenderWebGL.js +++ b/src/RenderWebGL.js @@ -139,6 +139,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; @@ -242,6 +249,7 @@ class RenderWebGL extends EventEmitter { resize (pixelsWide, pixelsTall) { const {canvas} = this._gl; const pixelRatio = window.devicePixelRatio || 1; + const newWidth = pixelsWide * pixelRatio; const newHeight = pixelsTall * pixelRatio; @@ -250,10 +258,16 @@ class RenderWebGL extends EventEmitter { if (canvas.width !== newWidth || canvas.height !== newHeight) { canvas.width = newWidth; canvas.height = newHeight; + + if (this._mystery.modeActive && this._mystery.bufferInfo) { + twgl.resizeFramebufferInfo(this._gl, this._mystery.bufferInfo, [ + {format: this._gl.RGBA} + ], pixelsWide * pixelRatio, pixelsTall * pixelRatio); + } + // Resizing the canvas causes it to be cleared, so redraw it. this.draw(); } - } /** @@ -653,7 +667,43 @@ class RenderWebGL extends EventEmitter { gl.clearColor(...this._backgroundColor4f); 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)); @@ -2083,6 +2133,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 4082235..18dff3a 100644 --- a/src/ShaderManager.js +++ b/src/ShaderManager.js @@ -181,7 +181,9 @@ ShaderManager.DRAW_MODE = { /** * Draw the background in a certain color. Must sometimes be used instead of gl.clear. */ - background: 'background' + background: 'background', + + mystery: 'mystery' }; module.exports = ShaderManager; diff --git a/src/shaders/sprite.frag b/src/shaders/sprite.frag index da28688..6d5c5d2 100644 --- a/src/shaders/sprite.frag +++ b/src/shaders/sprite.frag @@ -43,6 +43,10 @@ uniform float u_lineLength; uniform vec4 u_backgroundColor; #endif // DRAW_MODE_background +#ifdef DRAW_MODE_mystery +uniform vec2 u_mousePosition; +#endif + uniform sampler2D u_skin; #ifndef DRAW_MODE_background @@ -118,6 +122,15 @@ void main() #if !(defined(DRAW_MODE_line) || defined(DRAW_MODE_background)) 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 @@ -161,6 +174,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 24437c3..c5c6406 100644 --- a/src/shaders/sprite.vert +++ b/src/shaders/sprite.vert @@ -68,6 +68,8 @@ void main() { gl_Position = vec4(position, 0, 1); #elif defined(DRAW_MODE_background) gl_Position = vec4(a_position * 2.0, 0, 1); + #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); v_texCoord = a_texCoord;