Conway's Game of Life (again)

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()

I haven’t understood, but searched: What does the X//1 do?

@TokOut it does the same thing as math.floor(x/1) so for example, 10//3 will give you 3

@dave1707 - I get close to 60 FPS on my Air 2