resl({ manifest: { texture: { type: 'image', src: sat8x8pnguri, parser: (data) => regl.texture({ data: data, mag: 'nearest', min: 'nearest', flipY: true }) }, digitsTexture: { type: 'image', src: numerify.digits.uri, parser: (data) => regl.texture({ data: data, mag: 'nearest', min: 'nearest', flipY: true }) } }, onDone: ({texture, digitsTexture}) => { // make a bunch of fbos for ping-ponging intermediate computations, and the output buffer etc. let fbos = [null, null, null, null].map(function () { return regl.framebuffer({ color: regl.texture({ width: texture.width, height: texture.height, stencil: false, format: 'rgba', type: 'float', depth: false, wrap: 'clamp', mag: 'nearest', min: 'nearest' }), stencil: false, depth: false, depthStencil: false, wrap: 'clamp', mag: 'nearest', min: 'nearest' }); }); // use one FBO for the output. let outFbo = fbos.pop(); // and another for the input, for later use. let inFbo = fbos.pop(); computeSat({texture: texture, fbos: fbos, outFbo: outFbo, regl, components: 'rgb', type: 'vec3'}); let upscaledCellWidth = 32; let upscaledCellHeight = 32; let upscaledWidth = texture.width * Math.max(upscaledCellWidth, upscaledCellHeight); let upscaledHeight = texture.height * Math.max(upscaledCellWidth, upscaledCellHeight); // a command to take an input texture and "numerify" it and place it in a destination FBO. const drawNumbersToFbo = regl({ frag: numerify.makeFrag({ multiplier: 256.0, sourceSize: `vec2(${texture.width}, ${texture.height})`, destinationCellSize: `vec2(${upscaledCellWidth - 1}, ${upscaledCellHeight - 1})`, destinationSize: `vec2(${upscaledWidth}, ${upscaledHeight})`, component: 'r'}), vert: numerify.makeVert(), attributes: { a_position: quad.verts, a_uv: quad.uvs }, elements: quad.indices, uniforms: { digits_texture: digitsTexture, source_texture: regl.prop('texture'), u_clip_y: 1 }, framebuffer: regl.prop('fbo') }); // allocate two FBOS to store the numerified textures. let numbersFBOs = [null, null].map(function () { return regl.framebuffer({ color: regl.texture({ width: upscaledWidth, height: upscaledHeight, stencil: false, format: 'rgba', type: 'uint8', depth: false, wrap: 'clamp', mag: 'nearest', min: 'nearest' }) }); }); // one FBO to store the input texture as a numerified texture. let inNumbersFBO = numbersFBOs[0]; // and a second FBO to store the SAT result texture as a numerified texture. let outNumbersFBO = numbersFBOs[1]; // copy the input texture to the `inFbo`. drawTextureToFbo({texture, fbo: inFbo}); // "numerify" the input texture. drawNumbersToFbo({texture: inFbo.color[0], fbo: inNumbersFBO}); // "numerify" the SAT result texture. drawNumbersToFbo({texture: outFbo.color[0], fbo: outNumbersFBO}); // draw the stuff to img tags, and put everything into the DOM for display. let $srcDiv = $('<div class="source-images"></div>').css('text-align', 'center').appendTo('body'); $('<h3>').appendTo($srcDiv).css('text-align', 'center').text('Source image (upscaled)'); let $resultDiv = $('<div class="result-images"></div>').css('text-align', 'center').appendTo('body'); $('<h3>').appendTo($resultDiv).css('text-align', 'center').text('Result image (upscaled)'); function figureTemplate ({src, captionHtml = '', alt = ''}) { return ` <figure> <img src="${src}" alt="${alt}"> <figcaption>${captionHtml}</figcaption> </figure> `; } let $srcImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: inFbo, width: upscaledWidth, height: upscaledHeight, regl}), alt: 'Source image (Rescaled)', captionHtml: '<strong>Source image (Rescaled)</strong>'})); let $srcNumbersImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: inNumbersFBO, width: upscaledWidth, height: upscaledHeight, regl}), alt: 'Source image numerified red', captionHtml: '<strong>Source image, numerified red</strong>'})); let $satImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: outFbo, width: upscaledWidth, height: upscaledHeight, regl}), alt: 'Result SAT image (Rescaled)', captionHtml: '<strong>Result SAT image (Rescaled)</strong>'})); let $satNumbersImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: outNumbersFBO, width: upscaledWidth, height: upscaledHeight, regl}), alt: 'Result SAT image numerified red', captionHtml: '<strong>Result SAT image, numerified red</strong>'})); $($srcImg).css('display', 'inline-block').appendTo($srcDiv); $($srcNumbersImg).css('display', 'inline-block').appendTo($srcDiv); $($satImg).css('display', 'inline-block').appendTo($resultDiv); $($satNumbersImg).css('display', 'inline-block').appendTo($resultDiv); } });
resl({ manifest: { texture: { type: 'image', // src: 'docs/numerify-4x4-exemplar.png', src: 'data:image/png;base64,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', parser: (data) => regl.texture({ data: data, mag: 'nearest', min: 'nearest', flipY: true }) }, digitsTexture: { type: 'image', src: numerify.digits.uri, parser: (data) => regl.texture({ data: data, mag: 'nearest', min: 'nearest', flipY: true }) } }, onDone: ({texture, digitsTexture}) => { // console.log(texture.width); // console.log(digitsTexture.width); let fbo = makeFBORgbUint8({width: texture.width * 16, height: texture.height * 16}); let frag = numerify.makeFrag({ multiplier: 256, sourceSize: `vec2(${texture.width}, ${texture.height})`, destinationSize: `vec2(${texture.width * 16}, ${texture.height * 16})`, destinationCellSize: 'vec2(16, 16)'}); let vert = numerify.makeVert(); console.log('vert:', vert); console.log('frag:', frag); const numerifyToFBO = regl({ frag: frag, vert: vert, attributes: { a_position: quad.verts, a_uv: quad.uvs }, elements: quad.indices, uniforms: { source_texture: regl.prop('sourceTexture'), digits_texture: regl.prop('digitsTexture'), u_clip_y: regl.prop('clip_y') }, framebuffer: regl.prop('fbo') }); numerifyToFBO({ sourceTexture: texture, digitsTexture: digitsTexture, fbo: fbo, clip_y: 1}); drawToScreen({texture: fbo.color[0], clip_y: 1}); } });
var regl = require('regl')() var camera = require('regl-camera')(regl, { distance: 2, center: [0,0.5,0] }) var resl = require('resl') resl({ manifest: { bliss: { type: 'image', src: 'bliss.jpg' } }, onDone: ready }) function ready (assets) { var draw = { feedback: require('regl-feedback')(regl, ` vec3 sample (vec2 uv, sampler2D tex) { vec2 tpos = ((2.0*uv-1.0)+1.0)*0.5; vec2 p = vec2( cos(tpos.x*${2*Math.PI}*16.0) + cos(tpos.x*${2*Math.PI}*4.0) + cos(tpos.x*${2*Math.PI}*8.0) + sin(tpos.x*${2*Math.PI}*64.0), sin(tpos.y*${2*Math.PI}*16.0) + sin(tpos.y*${2*Math.PI}*4.0) + sin(tpos.y*${2*Math.PI}*8.0) + cos(tpos.y*${2*Math.PI}*64.0) ) * 0.004; return 0.999*texture2D(tex,tpos+p).rgb; } `),
resl({ manifest: { texture: { type: 'image', src: './assets/Storm Cell Over the Southern Appalachian Mountains-dsc_2303_0-256x256.png', parser: (data) => regl.texture({ data: data, mag: 'nearest', min: 'nearest', flipY: true }) } }, onDone: ({texture, digitsTexture}) => { // make a bunch of fbos for ping-ponging intermediate computations, and the output buffer etc. let fbos = [null, null, null, null].map(function () { return regl.framebuffer({ color: regl.texture({ width: texture.width, height: texture.height, stencil: false, format: 'rgba', type: 'float', depth: false, wrap: 'clamp', mag: 'nearest', min: 'nearest' }), stencil: false, depth: false, depthStencil: false, wrap: 'clamp', mag: 'nearest', min: 'nearest' }); }); // use one FBO for the output. let outFbo = fbos.pop(); // and another for the input, for later use. let inFbo = fbos.pop(); let radius = 1; gaussian.blur.gaussian.compute({regl, texture, radius, fbos, outFbo: outFbo, components: 'rgb', type: 'vec3'}); let upscaledCellWidth = 16; let upscaledCellHeight = 16; let upscaledWidth = texture.width * Math.max(upscaledCellWidth, upscaledCellHeight); let upscaledHeight = texture.height * Math.max(upscaledCellWidth, upscaledCellHeight); // copy the input texture to the `inFbo`. drawTextureToFbo({texture, fbo: inFbo}); // draw the stuff to img tags, and put everything into the DOM for display. let $srcDiv = $('<div class="source-images"></div>').css('text-align', 'center').appendTo('body'); $('<h3>').appendTo($srcDiv).css('text-align', 'center').text('Source image'); let $resultDiv = $('<div class="result-images"></div>').css('text-align', 'center').appendTo('body'); $('<h3>').appendTo($resultDiv).css('text-align', 'center').text('Result image'); function figureTemplate ({src, captionHtml = '', alt = ''}) { return ` <figure> <img src="${src}" alt="${alt}"> <figcaption>${captionHtml}</figcaption> </figure> `; } upscaledWidth = texture.width; upscaledHeight = texture.height; let $srcImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: inFbo, width: upscaledWidth, height: upscaledHeight, regl}), alt: 'Source image', captionHtml: '<strong>Source image</strong>'})); // let $srcNumbersImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: inNumbersFBO, width: upscaledWidth, height: upscaledHeight, regl}), // alt: 'Source image numerified red', // captionHtml: '<strong>Source image, numerified red</strong>'})); let $resultImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: outFbo, width: upscaledWidth, height: upscaledHeight, regl}), alt: 'Result blurred image', captionHtml: `<strong>Result blurred image (kernel radius of ${radius})</strong>`})); // let $resultNumbersImg = $.parseHTML(figureTemplate({src: dataURIFromFBO({fbo: outNumbersFBO, width: upscaledWidth, height: upscaledHeight, regl}), // alt: 'Result blurred image numerified red', // captionHtml: '<strong>Result blurred image, numerified red</strong>'})); $($srcImg).css('display', 'inline-block').appendTo($srcDiv); // $($srcNumbersImg).css('display', 'inline-block').appendTo($srcDiv); $($resultImg).css('display', 'inline-block').appendTo($resultDiv); // $($resultNumbersImg).css('display', 'inline-block').appendTo($resultDiv); } });
resl({ manifest: { texture: { type: 'image', src: 'https://raw.githubusercontent.com/realazthat/glsl-gaussian/master/assets/Storm%20Cell%20Over%20the%20Southern%20Appalachian%20Mountains-dsc_2303_0-256x256.png', parser: (data) => regl.texture({ data: data, mag: 'nearest', min: 'mipmap', flipY: true, mipmap: 'nice' }) } }, onDone: ({texture}) => { let L = Math.ceil(Math.max(Math.log2(texture.width), Math.log2(texture.height))); function makeUint8Fbo ({width, height}) { return regl.framebuffer({ color: regl.texture({ width: width, height: height, stencil: false, format: 'rgba', type: 'uint8', depth: false, wrap: 'clamp', mag: 'nearest', min: 'nearest' }), width: width, height: height, depth: false, stencil: false, depthStencil: false, depthTexture: false, colorType: 'uint8', colorFormat: 'rgba' }); } let scaledFbos = range(L + 1).map(function (level) { // level 1 should have a mipmap size of 2^(L-1) // level 2 should have a mipmap size of 2^(L-2) let mipmapSize = 1 << (L - level); return makeUint8Fbo({width: mipmapSize, height: mipmapSize}); }); for (let levelZeroOnly of [false, true]) { for (let level = 1; level < L + 1; ++level) { // level 1 should have a mipmap size of 2^(L-1) // level 2 should have a mipmap size of 2^(L-2) let mipmapSize = 1 << (L - level); let scaledFbo = scaledFbos[level]; extractMiplevel({texture, regl, outFbo: scaledFbo, level: levelZeroOnly ? 0 : level}); } let viewport = { x: levelZeroOnly ? 0 : 1 << L, y: 0, width: 1 << L, height: 1 << L }; for (let level = 1; level < L + 1; ++level) { let lastMipmapSize = 1 << (L - (level - 1)); let mipmapSize = 1 << (L - level); viewport.y += lastMipmapSize; viewport.width = mipmapSize; viewport.height = mipmapSize; draw({ texture: scaledFbos[level].color[0], viewport: viewport }); } } } });