I’ve been playing around with shaders trying to get used to using them, and I ended up with this version of the Game of Life. It runs at the pixel level and goes about 10 FPS on my iPad Air. New cells are green and existing cells are white. I use green and white because it’s easier on my eyes. You can use different images as the starting image, but I use the green value for the calculations. If you want to set your own starting points, see the comments at bottom. Tap the screen to start or pause the display.
EDIT: Changed code in the draw function, img1,img2=img2,img1. It now runs at about 30 FPS instead of 10.
displayMode(FULLSCREEN)
function setup()
gen=0
img1=readImage("Cargo Bot:Startup Screen")
img2=image(WIDTH,HEIGHT)
m=mesh()
m:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
m.texture=img1
end
function draw()
setContext(img2)
m:draw()
setContext()
m:draw()
img1,img2=img2,img1
m.texture=img1
collectgarbage()
text("Generations "..gen,WIDTH/2,HEIGHT-30)
text("FPS "..(1/DeltaTime)//1,WIDTH/2,HEIGHT-50)
if m.shader~=nil then
gen=gen+1
end
end
function touched(t)
if t.state==BEGAN then
if m.shader==nil then
m.shader=shader(GOL.vertex,GOL.fragment)
m.shader.x=1/WIDTH
m.shader.y=1/HEIGHT
else
m.shader=nil
end
end
end
GOL=
{ vertex=
[[ uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec2 texCoord;
varying highp vec2 vTexCoord;
void main()
{ vTexCoord=texCoord;
gl_Position=modelViewProjection * position;
}
]],
fragment=
[[ uniform lowp sampler2D texture;
uniform highp float x;
uniform highp float y;
highp float x1;
highp float y1;
varying highp vec2 vTexCoord;
lowp float limit=.5; // alter limit if you want (0 to 1)
lowp int count;
void get(lowp sampler2D tex,highp vec2 pos)
{ count=0;
for (x1=-1.;x1<2.;x1++)
{ for (y1=-1.;y1<2.;y1++)
{ if (texture2D(tex,(pos+vec2(x1*x,y1*y))).g>limit)
{ if (x1!=0. || y1!=0. )
count+=1;
}
}
}
}
void main()
{ lowp vec4 col=texture2D(texture,vTexCoord);
get(texture,vTexCoord);
if (count<2 || count>3) // too few or too many neighbors
col=vec4(0,0,0,1); // current cell dies or stays dead (black)
if (count==3) // if right amount of neighbors
{ if (col.g<limit) // if cell is dead
col=vec4(0,1,0,1); // new cell is born (green)
else
col=vec4(1,1,1,1); // current cell continues (white)
}
gl_FragColor=col;
}
]]
}
If you want to set your own starting points, replace img1=readImage(…) with something like this. This creates a blinker.
img1=image(WIDTH,HEIGHT)
setContext(img1)
background(0)
img1:set(300,300,0,255,0,255) // use the green color
img1:set(300,301,0,255,0,255)
img1:set(300,302,0,255,0,255)
setContext()