let properFrameCount = 0;
const MONOTONE_PATTERN = 0;
const TRIANGLE_PATTERN = 4;
const SEIGAIHA_PATTERN = 5;
const ASANOHA_PATTERN = 7;
const MONOTONE_GRADATION = 0;
const testFunc = {'alert':function(){console.log("hello!")}};
PARTICLE_COLOR:{r:32,g:64,b:255},
MAIN_COLOR:{r:0,g:0,b:0},
BASE_COLOR:{r:60,g:60,b:60},
BGPATTERN:MONOTONE_PATTERN,
GRADATION:MONOTONE_GRADATION,
var gui = new dat.GUI({ width: 280 });
gui.addColor(config, 'PARTICLE_COLOR').name('particleColor');
gui.add(config, 'AUTO_COLOR').name('autoColor');
gui.add(config, 'MIRROR_X').name('mirrorX');
gui.add(config, 'MIRROR_Y').name('mirrorY');
gui.add(config, 'INVERT').name('invert');
let bgFolder = gui.addFolder('bg');
bgFolder.addColor(config, 'MAIN_COLOR').name('mainColor');
bgFolder.addColor(config, 'SUB_COLOR').name('subColor');
bgFolder.addColor(config, 'BASE_COLOR').name('baseColor');
bgFolder.add(config, 'BGPATTERN', {'MONOTONE':MONOTONE_PATTERN, 'NOISE':NOISE_PATTERN, 'CHECK':CHECK_PATTERN, 'CLOUD':CLOUD_PATTERN, 'TRIANGLE':TRIANGLE_PATTERN, 'SEIGAIHA':SEIGAIHA_PATTERN, 'KOJI':KOJI_PATTERN, 'ASANOHA':ASANOHA_PATTERN}).name('pattern');
bgFolder.add(config, 'GRADATION', {'MONOTONE':MONOTONE_GRADATION, 'GRADATION_X':X_GRADATION, 'GRADATION_Y':Y_GRADATION}).name('gradation');
bgFolder.add(config, 'TRANSPARENT').name('transparent');
let sizeFolder = gui.addFolder('size');
sizeFolder.add(config, 'SIZETYPE', {'AUTO':AUTO_SIZE, 'MANUAL':MANUAL_SIZE}).name('sizeType');
sizeFolder.add(config, 'WIDTH', 256, 1280, 1).name('width');
sizeFolder.add(config, 'HEIGHT', 256, 768, 1).name('height');
let bloomFolder = gui.addFolder('bloom');
bloomFolder.add(config, 'BLOOM').name('bloom');
bloomFolder.add(config, 'BLOOM_DITHER').name('dither');
bloomFolder.add(config, 'BLOOM_ITERATIONS', 1, 8, 1).name('iterations');
bloomFolder.add(config, 'BLOOM_INTENSITY', 0, 5, 0.1).name('intensity');
bloomFolder.add(config, 'BLOOM_THRESHOLD', 0, 1, 0.1).name('threshold');
bloomFolder.add(config, 'BLOOM_SOFT_KNEE', 0, 1, 0.1).name('soft_knee');
bloomFolder.addColor(config, 'BLOOM_COLOR').name('bloom_color');
gui.add({fun:saveFlagOn}, 'fun').name('save');
gui.add({fun:dataInput}, 'fun').name('reset');
gui.add(config, 'HIDE').name('hide').onChange(showReset);
if(!config.HIDE){ dataInput(); }
"vec2 prepareForTexture(vec2 p){" +
" if(uTextureId == 6.0){" +
" p *= mat2(0.5,-sqrt(3.0)*0.5,0.5,sqrt(3.0)*0.5);" +
" }else if(uTextureId == 7.0){" +
" p.y = fract(p.y*2.0/sqrt(3.0));" +
"float getAmount(vec2 tex){" +
" float offsetX = mod(uTextureId, 4.0) * 0.25;" +
" float offsetY = floor(uTextureId / 4.0) * 0.25;" +
" float delta = 1.0/uTextureSize;" +
" tex.x = clamp(tex.x, delta, 1.0-delta);" +
" tex.y = clamp(tex.y, delta, 1.0-delta);" +
" vec2 _tex = vec2(offsetX, offsetY) + tex*0.25;" +
" float amt = texture2D(uTextureTable, _tex).r;" +
"precision mediump float;" +
"attribute vec2 aPosition;" +
" gl_Position = vec4(aPosition, 0.0, 1.0);" +
"precision mediump float;" +
"uniform float uTexSize;" +
" vec2 p = gl_FragCoord.xy / uTexSize;" +
" vec2 pos = (p - 0.5) * 2.0;" +
" gl_FragColor = vec4(pos, 0.0, 0.0);" +
"precision mediump float;" +
"attribute vec2 aPosition;" +
" gl_Position = vec4(aPosition, 0.0, 1.0);" +
"precision mediump float;" +
"uniform sampler2D uTex;" +
"uniform float uTexSize;" +
"uniform bool uMouseFlag;" +
"uniform float uAccell;" +
"const float SPEED = 0.05;" +
" vec2 p = gl_FragCoord.xy / uTexSize;" +
" vec4 t = texture2D(uTex, p);" +
" vec2 velocity = t.zw;" +
" vec2 v = normalize(uMouse - pos) * 0.2;" +
" vec2 w = normalize(velocity + v);" +
" vec4 destColor = vec4(pos + w * SPEED * uAccell, w);" +
" if(!uMouseFlag){ destColor.zw = velocity; }" +
" gl_FragColor = destColor;" +
"precision mediump float;" +
"attribute float aIndex;" +
"uniform sampler2D uTex;" +
"uniform vec2 uResolution;" +
"uniform float uTexSize;" +
"uniform float uPointScale;" +
" float indX = mod(aIndex, uTexSize);" +
" float indY = floor(aIndex / uTexSize);" +
" float x = (indX + 0.5) / uTexSize;" +
" float y = (indY + 0.5) / uTexSize;" +
" vec4 t = texture2D(uTex, vec2(x, y));" +
" p *= vec2(min(uResolution.x, uResolution.y)) / uResolution;" +
" gl_Position = vec4(p, 0.0, 1.0);" +
" gl_PointSize = 0.1 + uPointScale;" +
"precision mediump float;" +
" gl_FragColor = vec4(uColor, 1.0);" +
"precision mediump float;" +
"attribute vec2 aPosition;" +
" vUv = aPosition * 0.5 + 0.5;" +
" vUv.y = 1.0 - vUv.y;" +
" gl_Position = vec4(aPosition, 0.0, 1.0);" +
"precision mediump float;" +
"precision mediump sampler2D;" +
"varying highp vec2 vUv;" +
"uniform sampler2D uTex;" +
" gl_FragColor = texture2D(uTex, vUv);" +
"precision mediump float;" +
"precision mediump sampler2D;" +
"varying highp vec2 vUv;" +
"uniform sampler2D uTex;" +
"uniform vec2 uMirror;" +
" vec2 p1 = vec2(1.0-p.x, p.y);" +
" vec2 p2 = vec2(p.x, 1.0-p.y);" +
" vec2 p3 = vec2(1.0-p.x, 1.0-p.y);" +
" vec4 result = texture2D(uTex, p);" +
" if(uMirror.x > 0.0){ result += texture2D(uTex, p1); }" +
" if(uMirror.y > 0.0){ result += texture2D(uTex, p2); }" +
" if(uMirror.x > 0.0 && uMirror.y > 0.0){ result += texture2D(uTex, p3); }" +
" gl_FragColor = result;" +
"precision mediump float;" +
"attribute vec2 aPosition;" +
" gl_Position = vec4(aPosition, 0.0, 1.0);" +
"precision mediump float;" +
"uniform vec2 uResolution;" +
"uniform vec3 uMainColor;" +
"uniform vec3 uSubColor;" +
"uniform vec3 uBaseColor;" +
"uniform float uTextureId;" +
"uniform float uTextureSize;" +
"uniform sampler2D uTextureTable;" +
"uniform int uGradationId;" +
"float check(vec2 st){" +
" vec2 f = vec2(floor(st.x / 25.0), floor(st.y / 25.0));" +
" return mod(f.x + f.y, 2.0);" +
" vec2 st = gl_FragCoord.xy;" +
" vec2 tex = st / uTextureSize;" +
" tex.y = 1.0 - tex.y;" +
" vec2 q = st / uResolution;" +
" tex = prepareForTexture(tex);" +
" float amt = getAmount(tex);" +
" if(uGradationId == 0){ col = uMainColor; }" +
" else if(uGradationId == 1){ col = uMainColor * q.x + uSubColor * (1.0 - q.x); }" +
" else if(uGradationId == 2){ col = uMainColor * q.y + uSubColor * (1.0 - q.y); }" +
" col = (1.0 - amt) * col + amt * uBaseColor;" +
" gl_FragColor = vec4(col, 1.0);" +
"precision highp float;" +
"attribute vec2 aPosition;" +
"uniform vec2 uTexelSize;" +
" vUv = aPosition * 0.5 + 0.5;" +
" vL = vUv - vec2(uTexelSize.x, 0.0);" +
" vR = vUv + vec2(uTexelSize.x, 0.0);" +
" vT = vUv + vec2(0.0, uTexelSize.y);" +
" vB = vUv - vec2(0.0, uTexelSize.y);" +
" gl_Position = vec4(aPosition, 0.0, 1.0);" +
const simpleVertexShader =
"precision highp float;" +
"attribute vec2 aPosition;" +
" vUv = aPosition * 0.5 + 0.5;" +
" gl_Position = vec4(aPosition, 0.0, 1.0);" +
const displayShaderSource =
"precision highp float;" +
"precision highp sampler2D;" +
"uniform sampler2D uTexture;" +
"uniform sampler2D uDithering;" +
"uniform vec2 uDitherScale;" +
"uniform sampler2D uBloom;" +
"uniform bool uBloomFlag;" +
"uniform bool uDitheringFlag;" +
"uniform bool uInvertFlag;" +
"vec3 linearToGamma (vec3 color) {" +
" color = max(color, vec3(0));" +
" return max(1.055 * pow(color, vec3(0.416666667)) - 0.055, vec3(0));" +
" vec4 tex = texture2D(uTexture, vUv);" +
" bloom = texture2D(uBloom, vUv).rgb;" +
" float noise = texture2D(uDithering, vUv * uDitherScale).r;" +
" noise = noise * 2.0 - 1.0;" +
" bloom += noise / 255.0;" +
" bloom = linearToGamma(bloom);" +
" if(uInvertFlag){ c=1.0-c; }" +
" gl_FragColor = vec4(c, tex.a);" +
const bloomPrefilterShader =
"precision mediump float;" +
"precision mediump sampler2D;" +
"uniform sampler2D uTexture;" +
"uniform float uThreshold;" +
" vec3 c = texture2D(uTexture, vUv).rgb;" +
" float br = max(c.r, max(c.g, c.b));" +
" float rq = clamp(br - uCurve.x, 0.0, uCurve.y);" +
" rq = uCurve.z * rq * rq;" +
" c *= max(rq, br - uThreshold) / max(br, 0.0001);" +
" gl_FragColor = vec4(c, 0.0);" +
"precision mediump float;" +
"precision mediump sampler2D;" +
"uniform sampler2D uTexture;" +
" vec4 sum = vec4(0.0);" +
" sum += texture2D(uTexture, vL);" +
" sum += texture2D(uTexture, vR);" +
" sum += texture2D(uTexture, vT);" +
" sum += texture2D(uTexture, vB);" +
"precision mediump float;" +
"precision mediump sampler2D;" +
"uniform sampler2D uTexture;" +
"uniform float uIntensity;" +
"uniform vec3 uBloomColor;" +
" vec4 sum = vec4(0.0);" +
" sum += texture2D(uTexture, vL);" +
" sum += texture2D(uTexture, vR);" +
" sum += texture2D(uTexture, vT);" +
" sum += texture2D(uTexture, vB);" +
" gl_FragColor = sum * uIntensity * vec4(uBloomColor, 1.0);" +
let ditheringImg, ditheringTexture;
textureTableSource = loadImage("https://inaridarkfox4231.github.io/assets/texture/textureTable.png");
ditheringImg = loadImage("https://inaridarkfox4231.github.io/assets/texture/dither.png");
createCanvas(windowWidth, windowHeight, WEBGL);
setAttributes('version', 1);
currentWidth = windowWidth;
currentHeight = windowHeight;
_node = new RenderNode();
const positions = [-1, -1, -1, 1, 1, -1, 1, 1];
sh = createShader(patternVert, patternFrag);
_node.regist('pattern', sh, 'board')
.registAttribute('aPosition', positions, 2);
sh = createShader(dataVert, dataFrag);
_node.regist('input', sh, 'board')
.registAttribute('aPosition', positions, 2);
sh = createShader(moveVert, moveFrag);
_node.regist('move', sh, 'board')
.registAttribute('aPosition', positions, 2)
.registUniformLocation('uTex');
for(let i = 0; i < TEX_SIZE * TEX_SIZE; i++){ indices.push(i); }
sh = createShader(pointVert, pointFrag);
_node.regist('point', sh, 'display')
.registAttribute('aIndex', indices, 1)
.registUniformLocation('uTex');
sh = createShader(copyVert, mirrorFrag);
_node.regist('mirror', sh, 'board')
.registAttribute('aPosition', positions, 2)
.registUniformLocation('uTex');
sh = createShader(simpleVertexShader, bloomPrefilterShader);
_node.regist('bloomPrefilter', sh, 'simple')
.registAttribute('aPosition', positions, 2)
.registUniformLocation('uTexture');
sh = createShader(baseVertexShader, bloomBlurShader);
_node.regist('bloomBlur', sh, 'board')
.registAttribute('aPosition', positions, 2)
.registUniformLocation('uTexture');
sh = createShader(baseVertexShader, bloomFinalShader);
_node.regist('bloomFinal', sh, 'board')
.registAttribute('aPosition', positions, 2)
.registUniformLocation('uTexture');
sh = createShader(baseVertexShader, displayShaderSource);
_node.regist('display', sh, 'board')
.registAttribute('aPosition', positions, 2)
.registUniformLocation('uTexture')
.registUniformLocation('uBloom')
.registUniformLocation('uDithering');
_node.registDoubleFBO('data', 11, TEX_SIZE, TEX_SIZE, gl.FLOAT, gl.NEAREST);
_node.registFBO('particle', 13, width, height, gl.FLOAT, gl.NEAREST);
textureTable = new p5.Texture(_gl, textureTableSource);
ditheringTexture = new p5.Texture(_gl, ditheringImg);
gl.bindTexture(gl.TEXTURE_2D, ditheringTexture.glTex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
function initFramebuffers(){
const halfFloat = ext.textureHalfFloat.HALF_FLOAT_OES;
const linearFilterParam = (ext.textureHalfFloatLinear ? gl.LINEAR : gl.NEAREST);
_node.registDoubleFBO("dye", 0, width, height, halfFloat, linearFilterParam);
function initBloomFramebuffers(){
let res = getResolution(config.BLOOM_RESOLUTION);
const halfFloat = ext.textureHalfFloat.HALF_FLOAT_OES;
const linearFilterParam = (ext.textureHalfFloatLinear ? gl.LINEAR : gl.NEAREST);
_node.registFBO('bloom_0', 2, res.frameWidth, res.frameHeight, halfFloat, linearFilterParam);
for(let i = 1; i <= config.BLOOM_ITERATIONS; i++){
let fw = (res.frameWidth >> i);
let fh = (res.frameHeight >> i);
_node.registFBO('bloom_' + i, 2 + i, fw, fh, halfFloat, linearFilterParam);
const _size = min(width, height);
const mouse_x = (mouseX / width - 0.5) * 2.0 * width / _size;
const mouse_y = (mouseY / height - 0.5) *2.0 * height / _size;
const mouse_flag = mouseIsPressed;
moveRendering(mouse_x, mouse_y, mouse_flag);
_node.setViewport(0, 0, width, height);
if(!saveFlag){ drawCheckerBoard(); }
let {r, g, b} = getProperColor(config.PARTICLE_COLOR);
const col = _HSV((properFrameCount%720)/720, 0.8, 1);
r = col.r; g = col.g; b = col.b;
r /= 255; g /= 255; b /= 255;
_node.bindFBO('particle')
gl.blendFunc(gl.ONE_MINUS_DST_COLOR, gl.ONE);
_node.use('point', 'display')
.setUniform("uTexSize", TEX_SIZE)
.setUniform("uColor", [r, g, b])
.setUniform("uPointScale", accell)
.setUniform("uResolution", [width, height])
_node.use('mirror', 'board')
.setFBO('uTex', 'particle')
.setUniform("uMirror", [config.MIRROR_X, config.MIRROR_Y])
.drawArrays(gl.TRIANGLE_STRIP)
if(mouse_flag){ accell = 1.0; }else{ accell *= 0.95; }
if(config.SIZETYPE == MANUAL_SIZE){
currentWidth = config.WIDTH;
currentHeight = config.HEIGHT;
currentWidth = windowWidth;
currentHeight = windowHeight;
if(currentWidth == width && currentHeight == height){ return; }
resizeCanvas(currentWidth, currentHeight);
_node.registFBO('particle', 2, currentWidth, currentHeight, gl.FLOAT, gl.NEAREST);
const halfFloat = ext.textureHalfFloat.HALF_FLOAT_OES;
const linearFilterParam = (ext.textureHalfFloatLinear ? gl.LINEAR : gl.NEAREST);
_node.registDoubleFBO("dye", 0, width, height, halfFloat, linearFilterParam);
.setViewport(0, 0, TEX_SIZE, TEX_SIZE)
.setUniform('uTexSize', TEX_SIZE)
.drawArrays(gl.TRIANGLE_STRIP)
function moveRendering(mx, my, mFlag){
.setViewport(0, 0, TEX_SIZE, TEX_SIZE)
.setUniform("uTexSize", TEX_SIZE)
.setUniform("uAccell", accell)
.setUniform("uMouseFlag", mFlag)
.setUniform("uMouse", [mx, my])
.drawArrays(gl.TRIANGLE_STRIP)
function drawBackground(){
const mainColor = getProperColor(config.MAIN_COLOR);
const subColor = getProperColor(config.SUB_COLOR);
const baseColor = getProperColor(config.BASE_COLOR);
_node.use('pattern', 'board')
.setUniform('uResolution', [width, height])
.setTexture('uTextureTable', textureTable.glTex, 0)
.setUniform('uTextureId', config.BGPATTERN)
.setUniform('uTextureSize', 256)
.setUniform('uMainColor', [mainColor.r/255, mainColor.g/255, mainColor.b/255])
.setUniform('uSubColor', [subColor.r/255, subColor.g/255, subColor.b/255])
.setUniform('uBaseColor', [baseColor.r/255, baseColor.g/255, baseColor.b/255])
.setUniform('uGradationId', config.GRADATION)
.drawArrays(gl.TRIANGLE_STRIP)
function drawCheckerBoard(){
_node.use('pattern', 'board')
.setUniform('uResolution', [width, height])
.setTexture('uTextureTable', textureTable.glTex, 0)
.setUniform('uTextureId', 2)
.setUniform('uTextureSize', 256)
.setUniform('uMainColor', [0.8, 0.8, 0.8])
.setUniform('uSubColor', [0,0,0])
.setUniform('uBaseColor', [0.9, 0.9, 0.9])
.setUniform('uGradationId', 0)
.drawArrays(gl.TRIANGLE_STRIP)
let res = getResolution(256);
let knee = config.BLOOM_THRESHOLD * config.BLOOM_SOFT_KNEE + 0.0001;
let curve0 = config.BLOOM_THRESHOLD - knee;
let curve2 = 0.25 / knee;
_node.bindFBO('bloom_0');
_node.use('bloomPrefilter', 'simple')
.setFBO('uTexture', 'dye')
.setUniform('uCurve', [curve0, curve1, curve2])
.setUniform('uThreshold', config.BLOOM_THRESHOLD)
.drawArrays(gl.TRIANGLE_STRIP)
_node.use('bloomBlur', 'board')
for(let i = 1; i <= config.BLOOM_ITERATIONS; i++){
const w = (res.frameWidth >> (i-1));
const h = (res.frameHeight >> (i-1));
_node.bindFBO('bloom_' + i);
_node.setUniform('uTexelSize', [1/w, 1/h])
.setFBO('uTexture', 'bloom_' + (i-1))
.drawArrays(gl.TRIANGLE_STRIP);
gl.blendFunc(gl.ONE, gl.ONE);
for(let i = config.BLOOM_ITERATIONS; i >= 2; i--){
const w = (res.frameWidth >> i);
const h = (res.frameHeight >> i);
_node.bindFBO('bloom_' + (i-1));
_node.setUniform('uTexelSize', [1/w, 1/h])
.setFBO('uTexture', 'bloom_' + i)
.drawArrays(gl.TRIANGLE_STRIP);
const w1 = (res.frameWidth >> 1);
const h1 = (res.frameHeight >> 1);
const col = getProperColor(config.BLOOM_COLOR);
_node.bindFBO('bloom_0');
_node.use('bloomFinal', 'board')
.setFBO('uTexture', 'bloom_1')
.setUniform('uTexelSize', [1/w1, 1/h1])
.setUniform('uIntensity', config.BLOOM_INTENSITY)
.setUniform('uBloomColor', [col.r/255, col.g/255, col.b/255])
.drawArrays(gl.TRIANGLE_STRIP)
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
_node.use('display', 'board')
.setFBO('uTexture', 'dye')
.setUniform('uBloomFlag', config.BLOOM)
.setFBO('uBloom', 'bloom_0')
.setUniform('uDitheringFlag', config.BLOOM_DITHER)
.setTexture('uDithering', ditheringTexture.glTex, 14)
.setUniform('uDitherScale', [width/ditheringImg.width, height/ditheringImg.height])
.setUniform('uInvertFlag', config.INVERT)
.drawArrays(gl.TRIANGLE_STRIP)
function confirmExtensions(){
ext.textureFloat = gl.getExtension('OES_texture_float');
ext.textureHalfFloat = gl.getExtension('OES_texture_half_float');
ext.textureHalfFloatLinear = gl.getExtension('OES_texture_half_float_linear');
ext.elementIndexUint = gl.getExtension('OES_element_index_uint');
if(ext.textureFloat == null || ext.textureHalfFloat == null){
alert('float texture not supported');
if(ext.elementIndexUint == null){
alert('Your web browser does not support the WebGL Extension OES_element_index_uint.');
function create_fbo(name, texId, w, h, textureFormat, filterParam){
textureFormat = gl.UNSIGNED_BYTE;
filterParam = gl.NEAREST;
let framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
let depthRenderBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRenderBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthRenderBuffer);
let fTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0 + texId);
gl.bindTexture(gl.TEXTURE_2D, fTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, textureFormat, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterParam);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterParam);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fTexture, 0);
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return {f:framebuffer, d:depthRenderBuffer, t:fTexture, id:texId, name:name, frameWidth:w, frameHeight:h, texelSizeX:1/w, texelSizeY:1/h};
function create_double_fbo(name, texId, w, h, textureFormat, filterParam){
let fbo1 = create_fbo(name, texId, w, h, textureFormat, filterParam);
let fbo2 = create_fbo(name, texId + 1, w, h, textureFormat, filterParam);
doubleFbo.swap = function(){
doubleFbo.frameWidth = w;
doubleFbo.frameHeight = h;
doubleFbo.texelSizeX = 1/w;
doubleFbo.texelSizeY = 1/h;
function create_vbo(data){
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
function create_ibo(data, type){
var ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new (type)(data), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
function set_attribute(attributes){
for(let name of Object.keys(attributes)){
const attr = attributes[name];
gl.bindBuffer(gl.ARRAY_BUFFER, attr.vbo);
gl.enableVertexAttribArray(attr.location);
gl.vertexAttribPointer(attr.location, attr.stride, gl.FLOAT, false, 0, 0);
function getResolution(resolution){
let aspectRatio = width / height;
if(aspectRatio < 1){ aspectRatio = 1.0 / aspectRatio; }
let _min = Math.round(resolution);
let _max = Math.round(resolution * aspectRatio);
return {frameWidth: _max, frameHeight: _min};
return {frameWidth: _min, frameHeight: _max};
if(arguments.length === 1){
let _r = constrain(abs(((6 * h) % 6) - 3) - 1, 0, 1);
let _g = constrain(abs(((6 * h + 4) % 6) - 3) - 1, 0, 1);
let _b = constrain(abs(((6 * h + 2) % 6) - 3) - 1, 0, 1);
_r = _r * _r * (3 - 2 * _r);
_g = _g * _g * (3 - 2 * _g);
_b = _b * _b * (3 - 2 * _b);
result.r = v * (1 - s + s * _r);
result.g = v * (1 - s + s * _g);
result.b = v * (1 - s + s * _b);
function getProperColor(col){
if(typeof(col) == "object"){
return {r:col.r, g:col.g, b:col.b};
}else if(typeof(col) == "string"){
return {r:red(col), g:green(col), b:blue(col)};
return {r:255, g:255, b:255};
constructor(name, _shader){
this.program = _shader._glProgram;
this.uniformLocations = {};
registTopology(topologyName){
if(this.topologies[topologyName] !== undefined){ return; }
this.topologies[topologyName] = new Topology(topologyName);
getTopology(topologyName){
return this.topologies[topologyName];
registUniformLocation(uniformName){
if(this.uniformLocations[uniformName] !== undefined){ return; }
this.uniformLocations[uniformName] = gl.getUniformLocation(this.program, uniformName);
setTexture(uniformName, _texture, locationID){
gl.activeTexture(gl.TEXTURE0 + locationID);
gl.bindTexture(gl.TEXTURE_2D, _texture);
gl.uniform1i(this.uniformLocations[uniformName], locationID);
this.framebufferObjects = {};
this.currentRenderSystem = undefined;
this.currentShader = undefined;
this.currentTopology = undefined;
this.useTextureFlag = false;
this.uMV = new p5.Matrix();
registRenderSystem(renderSystemName, _shader){
if(this.renderSystems[renderSystemName] !== undefined){ return this; }
this.renderSystems[renderSystemName] = new RenderSystem(renderSystemName, _shader);
this.useRenderSystem(renderSystemName);
useRenderSystem(renderSystemName){
this.currentRenderSystem = this.renderSystems[renderSystemName];
this.currentShader = this.currentRenderSystem.getShader();
this.currentShader.useProgram();
registTopology(topologyName){
this.currentRenderSystem.registTopology(topologyName);
this.useTopology(topologyName);
useTopology(topologyName){
this.currentTopology = this.currentRenderSystem.getTopology(topologyName);
regist(renderSystemName, _shader, topologyName){
this.registRenderSystem(renderSystemName, _shader);
this.registTopology(topologyName);
use(renderSystemName, topologyName){
this.useRenderSystem(renderSystemName);
this.useTopology(topologyName);
if(typeof(target) == 'string'){
return this.framebufferObjects[target] !== undefined;
return this.framebufferObjects[target.name] !== undefined;
registFBO(target, texId, w, h, textureFormat, filterParam){
if(typeof(target) == 'string'){
let fbo = create_fbo(target, texId, w, h, textureFormat, filterParam);
this.framebufferObjects[target] = fbo;
this.framebufferObjects[target.name] = target;
registDoubleFBO(targetName, texId, w, h, textureFormat, filterParam){
let fbo = create_double_fbo(targetName, texId, w, h, textureFormat, filterParam);
this.framebufferObjects[targetName] = fbo;
resizeFBO(targetName, texId, w, h, textureFormat, filterParam){
let fbo = this.framebufferObjects[targetName];
this.framebufferObjects[targetName] = resize_fbo(fbo, texId, w, h, textureFormat, filterParam);
resizeDoubleFBO(targetName, texId, w, h, textureFormat, filterParam){
let fbo = this.framebufferObjects[targetName];
this.framebufferObjects[targetName] = resize_double_fbo(fbo, texId, w, h, textureFormat, filterParam);
if(typeof(target) == 'string'){
let fbo = this.framebufferObjects[target];
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.write.f);
gl.viewport(0, 0, fbo.frameWidth, fbo.frameHeight);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.f);
gl.viewport(0, 0, fbo.frameWidth, fbo.frameHeight);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, width, height);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.f);
gl.viewport(0, 0, target.frameWidth, target.frameHeight);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
setFBO(uniformName, FBOName){
if(FBOName === undefined || (typeof FBOName !== 'string')){
alert("Inappropriate name setting.");
let fbo = this.framebufferObjects[FBOName];
alert("The corresponding framebuffer does not exist.");
this.setTexture(uniformName, fbo.read.t, fbo.read.id);
this.setTexture(uniformName, fbo.t, fbo.id);
if(FBOName == null){ return this; }
let fbo = this.framebufferObjects[FBOName];
if(fbo.read && fbo.write){ fbo.swap(); }
registAttribute(attributeName, data, stride){
this.currentTopology.registAttribute(this.currentRenderSystem.getProgram(), attributeName, data, stride);
registAttributes(attrData){
for(let attrName of Object.keys(attrData)){
const attr = attrData[attrName];
this.registAttribute(attrName, attr.data, attr.stride);
this.currentTopology.setAttribute();
if(data.length > 65535){ type = Uint32Array; }
this.currentTopology.registIndexBuffer(data, type);
this.currentTopology.bindIndexBuffer();
registUniformLocation(uniformName){
this.currentRenderSystem.registUniformLocation(uniformName);
setTexture(uniformName, _texture, locationID){
this.currentRenderSystem.setTexture(uniformName, _texture, locationID);
this.useTextureFlag = true;
setUniform(uniformName, data){
this.currentShader.setUniform(uniformName, data);
this.currentTopology.clear();
gl.bindTexture(gl.TEXTURE_2D, null);
this.useTextureFlag = false;
const sh = this.currentShader;
sh.setUniform('uProjectionMatrix', _gl.uPMatrix.mat4);
sh.setUniform('uModelViewMatrix', this.uMV.mat4);
sh.setUniform('uViewMatrix', _gl._curCamera.cameraMatrix.mat4);
_gl.uNMatrix.inverseTranspose(this.uMV);
sh.setUniform('uNormalMatrix', _gl.uNMatrix.mat3);
for(let i = 0; i < 16; i++){
this.uMV.mat4[i] = _gl.uMVMatrix.mat4[i];
this.setMatrixStandard();
const name = Object.keys(command)[0];
const value = command[name];
if(value.length === 1){ value.push(value[0], value[0]); }
this.uMV.translate(value);
this.uMV.rotateX(value); break;
this.uMV.rotateY(value); break;
this.uMV.rotateZ(value); break;
this.uMV.rotate(...value); break;
if(value.length === 1){ value.push(value[0], value[0]); }
this.uMV.scale(...value); break;
const sh = this.currentShader;
sh.setUniform('uUseColorFlag', 0);
setMonoColor(col, a = 1){
const sh = this.currentShader;
sh.setUniform('uUseColorFlag', 1);
sh.setUniform('uMonoColor', [col.r, col.g, col.b, a]);
const sh = this.currentShader;
sh.setUniform("uUseColorFlag", 2);
setDirectionalLight(col, x, y, z){
const sh = this.currentShader;
sh.setUniform('uUseDirectionalLight', true);
sh.setUniform('uDirectionalDiffuseColor', [col.r, col.g, col.b]);
sh.setUniform('uLightingDirection', [x, y, z]);
const sh = this.currentShader;
sh.setUniform('uAmbientColor', [col.r, col.g, col.b]);
setPointLight(col, x, y, z, att0 = 1, att1 = 0, att2 = 0){
const sh = this.currentShader;
sh.setUniform('uUsePointLight', true);
sh.setUniform('uPointLightDiffuseColor', [col.r, col.g, col.b]);
sh.setUniform('uPointLightLocation', [x, y, z]);
sh.setUniform('uAttenuation', [att0, att1, att2]);
drawArrays(mode, first, count){
if(arguments.length == 1){
count = this.currentTopology.getAttrSize();
gl.drawArrays(mode, first, count);
drawElements(mode, count){
const _type = this.currentTopology.getIBOType();
const type = (_type === Uint16Array ? gl.UNSIGNED_SHORT : gl.UNSIGNED_INT);
if(count === undefined){ count = this.currentTopology.getIBOSize(); }
gl.drawElements(mode, count, type, 0);
this.iboType = undefined;
registAttribute(program, attributeName, data, stride){
attr.vbo = create_vbo(data);
attr.location = gl.getAttribLocation(program, attributeName);
this.attrSize = Math.floor(data.length / stride);
this.attributes[attributeName] = attr;
set_attribute(this.attributes);
registIndexBuffer(data, type){
this.ibo = create_ibo(data, type);
this.iboSize = data.length;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ibo);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
if(this.ibo !== undefined){ gl.bindBuffer(gl.ELEMENT_BUFFER, null); }
if(keyCode == 32){ saveFlagOn(); }
if(keyCode == 82){ dataInput(); }
const elapsedSeconds = hour()*3600 + minute()*60 + second();
const title = "gpu_particle_" + elapsedSeconds;