/*
* Copyright 2021 Markus Heimerl, OTH Regensburg
* Licensed under CC BY-NC 4.0
*
* ANY USE OF THIS SOFTWARE MUST COMPLY WITH THE
* CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL 4.0 INTERNATIONAL LICENSE
* AGREEMENTS
*/
cellularautomatonMulti();
function cellularautomatonMulti(){
const vertexshadersource = `
attribute vec2 a_vertexdata;
void main(){
gl_Position = vec4(a_vertexdata.xy, 0.0, 1.0);
}
`;
const drawfragmentshadersource = `
precision lowp float;
uniform sampler2D texture;
uniform vec2 dimensions;
void main(){
gl_FragColor = texture2D(texture, gl_FragCoord.xy/dimensions);
}
`;
const logicfragmentshadersource = `
precision lowp float;
uniform sampler2D texture;
uniform vec2 dimensions;
int getValue(int x, int y){
return (texture2D(texture, (gl_FragCoord.xy + vec2(x,y))/dimensions).g) > 0.0 ? 1 : 0;
}
void main(){
int neighb = 0;
for(int i = ` + $("#cellRuleInputMultiRadius").val() + `*-1; i < ` + $("#cellRuleInputMultiRadius").val() + `+1; i++){
for(int j = ` + $("#cellRuleInputMultiRadius").val() + `*-1; j < ` + $("#cellRuleInputMultiRadius").val() + `+1; j++){
if(!(i == 0 && j == 0)){
neighb += getValue(i, j);
}
}
}
int current = getValue(0,0);
if(` + parseRulestring($("#cellRuleInputMulti").val())[0] + `){gl_FragColor = vec4(0.7, 0.9, 0.1, 1.0);}
else if(` + parseRulestring($("#cellRuleInputMulti").val())[1] + `){gl_FragColor = vec4(current, current, current, 1.0);}
else{gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);}
}
`;
var running = true;
var scaleofonepixel = 1;
$("#cellularautomatoncanvasmultineighbor")[0].width = Math.pow(2, Math.floor(getBaseLog(2, $(window).width() * 0.88)));
var gl = $("#cellularautomatoncanvasmultineighbor")[0].getContext("webgl");
// local copy of library https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
const r3webgl = {...parentr3webgl};
r3webgl.gl = gl;
var programs = {
drawprogram: r3webgl.createShaderProgram(vertexshadersource, drawfragmentshadersource),
logicprogram: r3webgl.createShaderProgram(vertexshadersource, logicfragmentshadersource)
};
var drawuniformlocations = r3webgl.getUniformLocations(programs.drawprogram, ["dimensions"]);
var logicuniformlocations = r3webgl.getUniformLocations(programs.logicprogram, ["dimensions"]);
var textures = {
front: createTexture(true),
back: createTexture(false)
}
window.addEventListener("orientationchange", function() {
toggleRunning();
setTimeout(function(){
var newwidth = Math.pow(2, Math.floor(getBaseLog(2, $(window).width() * 0.88)));
$("#cellularautomatoncanvasmultineighbor")[0].width = newwidth;
textures.front = createTexture(true);
textures.back = createTexture(false);
toggleRunning();
}, 200);
});
function createTexture(noise){
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
var data = [];
if(noise){
for(var i = 0; i < gl.canvas.width*gl.canvas.height; i++){var col = Math.round(Math.random()*Math.random()*0.8)*255; data.push(col, col, col);}
}else{
for(var i = 0; i < gl.canvas.width*gl.canvas.height; i++){data.push(0, 0, 0);}
}
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.canvas.width/scaleofonepixel, gl.canvas.height/scaleofonepixel, 0, gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array(data));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
return tex;
}
$("#cellToggleButtonApply").click(function(){
const logicfragmentshadersource = `
precision lowp float;
uniform sampler2D texture;
uniform vec2 dimensions;
int getValue(int x, int y){
return (texture2D(texture, (gl_FragCoord.xy + vec2(x,y))/dimensions).g) > 0.0 ? 1 : 0;
}
void main(){
int neighb = 0;
for(int i = ` + $("#cellRuleInputMultiRadius").val() + `*-1; i < ` + $("#cellRuleInputMultiRadius").val() + `+1; i++){
for(int j = ` + $("#cellRuleInputMultiRadius").val() + `*-1; j < ` + $("#cellRuleInputMultiRadius").val() + `+1; j++){
if(!(i == 0 && j == 0)){
neighb += getValue(i, j);
}
}
}
int current = getValue(0,0);
if(` + parseRulestring($("#cellRuleInputMulti").val())[0] + `){gl_FragColor = vec4(0.7, 0.9, 0.1, 1.0);}
else if(` + parseRulestring($("#cellRuleInputMulti").val())[1] + `){gl_FragColor = vec4(current, current, current, 1.0);}
else{gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);}
}
`;
console.log(logicfragmentshadersource);
programs.logicprogram = r3webgl.createShaderProgram(vertexshadersource, logicfragmentshadersource);
drawuniformlocations = r3webgl.getUniformLocations(programs.drawprogram, ["dimensions"]);
logicuniformlocations = r3webgl.getUniformLocations(programs.logicprogram, ["dimensions"]);
});
$("#cellToggleButtonMulti").click(toggleRunning);
function toggleRunning(){
if(running){
running = false;
$("#cellToggleButtonMulti").html("Start");
}else{
running = true;
$("#cellToggleButtonMulti").html("Stop");
}
}
$("#cellRandButtonMulti").click(function(){
textures.front = createTexture(true);
});
start();
setTimeout(toggleRunning, 200);
function start(){
const quadvert = [1, 1, -1, 1, 1, -1, -1, -1,];
var quadbuffer = r3webgl.createBuffer(gl.ARRAY_BUFFER, quadvert);
r3webgl.connectBufferToAttribute(gl.ARRAY_BUFFER, quadbuffer, 0, 2, true);
var fb = gl.createFramebuffer();
mainloop();
function mainloop(){
if(running){
draw();
play();
}
//requestAnimationFrame(mainloop);
setTimeout(mainloop, 40);
}
function draw(){
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, textures.front);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(programs.drawprogram);
gl.uniform2f(drawuniformlocations.dimensions, gl.canvas.width, gl.canvas.height);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function play(){
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.viewport(0, 0, gl.canvas.width/scaleofonepixel, gl.canvas.height/scaleofonepixel);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.back, 0);
gl.useProgram(programs.logicprogram);
gl.uniform2f(logicuniformlocations.dimensions, gl.canvas.width/scaleofonepixel, gl.canvas.height/scaleofonepixel);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
var swap = textures.back;
textures.back = textures.front;
textures.front = swap;
}
}
}