From 53b92e70f0de50762cf21b79bd08857b7de46789 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sun, 10 Jul 2022 11:31:37 -0400 Subject: [PATCH] Add support for float textures + an example --- .prettierrc | 9 ++++++ examples/feedback/index.html | 12 +++++++ examples/feedback/sketch.js | 61 ++++++++++++++++++++++++++++++++++++ examples/feedback/style.css | 7 +++++ p5.Framebuffer.js | 58 +++++++++++++++++++++++++--------- package.json | 5 +-- yarn.lock | 5 +++ 7 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 .prettierrc create mode 100644 examples/feedback/index.html create mode 100644 examples/feedback/sketch.js create mode 100644 examples/feedback/style.css diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..71289f3 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "useTabs": false, + "tabWidth": 2, + "semi": false, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 80, + "arrowParens": "always" +} diff --git a/examples/feedback/index.html b/examples/feedback/index.html new file mode 100644 index 0000000..5ad27e5 --- /dev/null +++ b/examples/feedback/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/examples/feedback/sketch.js b/examples/feedback/sketch.js new file mode 100644 index 0000000..10a8ef2 --- /dev/null +++ b/examples/feedback/sketch.js @@ -0,0 +1,61 @@ +let fboPrev, fboNext +let canvas + +function setup() { + canvas = createCanvas(400, 400, WEBGL) + // There's a bug in Firefox where you can only make floating point textures + // if they're RGBA, and it breaks if it's just RGB + setAttributes({ alpha: true }) + + // Try changing `float` to `unsigned_byte` to see it leave a trail + options = { colorFormat: 'float' } + fboPrev = createFramebuffer(options) + fboNext = createFramebuffer(options) + imageMode(CENTER) + rectMode(CENTER) + noStroke() +} + +function draw() { + // Swap prev and next so that we can use the previous frame as a texture + // when drawing the current frame + [fboPrev, fboNext] = [fboNext, fboPrev] + + // Draw to the Framebuffer + fboNext.draw(() => { + clear() + + background(255) + + // Disable depth testing so that the image of the previous + // frame doesn't cut off the sube + _renderer.GL.disable(_renderer.GL.DEPTH_TEST) + push() + scale(1.003) + texture(fboPrev.color) + plane(width, -height) + pop() + + push() + // Fade to white slowly. This will leave a permanent trail if you don't + // use floating point textures. + fill(255, 1) + rect(0, 0, width, height) + pop() + _renderer.GL.enable(_renderer.GL.DEPTH_TEST) + + push() + normalMaterial() + translate(100*sin(frameCount * 0.014), 100*sin(frameCount * 0.02), 0) + rotateX(frameCount * 0.01) + rotateY(frameCount * 0.01) + box(50) + pop() + }) + + clear() + push() + texture(fboNext.color) + plane(width, -height) + pop() +} diff --git a/examples/feedback/style.css b/examples/feedback/style.css new file mode 100644 index 0000000..9386f1c --- /dev/null +++ b/examples/feedback/style.css @@ -0,0 +1,7 @@ +html, body { + margin: 0; + padding: 0; +} +canvas { + display: block; +} diff --git a/p5.Framebuffer.js b/p5.Framebuffer.js index f2c4072..23705d0 100644 --- a/p5.Framebuffer.js +++ b/p5.Framebuffer.js @@ -1,5 +1,5 @@ -const _createFramebuffer = function() { - const fb = new Framebuffer(this) +const _createFramebuffer = function (options) { + const fb = new Framebuffer(this, options) // Extend the old resize handler to also update the size of the framebuffer const oldResize = this._renderer.resize @@ -14,7 +14,7 @@ p5.prototype.createFramebuffer = _createFramebuffer p5.Graphics.prototype.createFramebuffer = _createFramebuffer const parentGetTexture = p5.RendererGL.prototype.getTexture -p5.RendererGL.prototype.getTexture = function(imgOrTexture) { +p5.RendererGL.prototype.getTexture = function (imgOrTexture) { if (imgOrTexture instanceof p5.Texture) { return imgOrTexture } else { @@ -31,12 +31,7 @@ p5.RendererGL.prototype.getTexture = function(imgOrTexture) { // that looks like a p5 texture but that never tries to update // data in order to use framebuffer textures inside p5. class RawTextureWrapper extends p5.Texture { - constructor( - renderer, - obj, - w, - h, - ) { + constructor(renderer, obj, w, h) { super(renderer, obj) this.width = w this.height = h @@ -64,15 +59,33 @@ class RawTextureWrapper extends p5.Texture { } class Framebuffer { - constructor(canvas) { + constructor(canvas, options = {}) { this._renderer = canvas._renderer - const gl = this._renderer.GL - const ext = gl.getExtension('WEBGL_depth_texture') - if (!ext) { + if (!gl.getExtension('WEBGL_depth_texture')) { throw new Error('Unable to create depth textures in this environment') } + this.colorFormat = this.glColorFormat(options.colorFormat) + this.depthFormat = this.glDepthFormat(options.depthFormat) + if ( + (options.colorFormat === 'float' || options.depthFormat === 'float') && + (!gl.getExtension('OES_texture_float') || + !gl.getExtension('OES_texture_float_linear') || + !gl.getExtension('WEBGL_color_buffer_float')) + ) { + // Reset to default + if (options.colorFormat === 'float') { + this.colorFormat = this.glColorFormat() + } + if (options.depthFormat === 'float') { + this.depthFormat = this.glDepthFormat() + } + console.warn( + 'Warning: Unable to create floating point textures in this environment. Falling back to integers', + ) + } + const framebuffer = gl.createFramebuffer() if (!framebuffer) { throw new Error('Unable to create a framebuffer') @@ -81,6 +94,21 @@ class Framebuffer { this.recreateTextures() } + glColorFormat(format) { + const gl = this._renderer.GL + if (format === 'float') { + return gl.FLOAT + } + return gl.UNSIGNED_BYTE + } + glDepthFormat(format) { + const gl = this._renderer.GL + if (format === 'float') { + return gl.FLOAT + } + return gl.UNSIGNED_SHORT + } + handleResize() { const oldColor = this.colorTexture const oldDepth = this.depthTexture @@ -117,7 +145,7 @@ class Framebuffer { height * density, 0, hasAlpha ? gl.RGBA : gl.RGB, - gl.UNSIGNED_BYTE, + this.colorFormat, null, ) @@ -140,7 +168,7 @@ class Framebuffer { height * density, 0, gl.DEPTH_COMPONENT, - gl.UNSIGNED_SHORT, + this.depthFormat, null, ) diff --git a/package.json b/package.json index 968240e..f913fc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@davepagurek/p5.framebuffer", - "version": "0.0.2", + "version": "0.0.3", "main": "p5.Framebuffer.js", "author": "Dave Pagurek ", "license": "MIT", @@ -14,7 +14,8 @@ "homepage": "https://github.com/davepagurek/p5.Framebuffer", "dependencies": {}, "devDependencies": { - "minify": "^9.0.0" + "minify": "^9.0.0", + "prettier": "^2.7.1" }, "scripts": { "build:core": "minify p5.Framebuffer.js > p5.Framebuffer.core.min.js", diff --git a/yarn.lock b/yarn.lock index bb5f74e..37fefd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -206,6 +206,11 @@ path-exists@^5.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== +prettier@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + readjson@^2.2.0, readjson@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/readjson/-/readjson-2.2.2.tgz#ed940ebdd72b88b383e02db7117402f980158959"