Stencil buffers are for life (not just xmas!)

BlitzMax Forums/BlitzMax OpenGL Programming/Stencil buffers are for life (not just xmas!)

was quite impressed with this (technique) so ported it (mainly to see if stencil buffers actually were working!!)

Rem
/*
 * Conway's Game of Life in OpenGL
 * Simon Green (simes@...) 3/00
 *
 * This uses roughly the same algorithm described in the OpenGL
 * red book (p.590 in 3rd edition) to compute Life in the frame buffer:
 *
 * - Reads frame buffer contents to texture using CopyTexImage.
 * - Renders textured quad 8 times offset one pixel in each direction,
 *   using alpha test and stencil buffer increment to count neighbours.
 * - Uses stencil test to determine deaths and births for next generation
 *
 * This is not very efficient (10 passes), but leaves results in texture map.
 * Requires stencil buffer, destination alpha.
 *
 */

'bodged to work on max by Chris C
EndRem



Global winw:Int = 512, winh:Int = 512
Global lifew:Int = 512, lifeh:Int = 512
Global gen:Int = 0

Global animating:Int = 0
Global wraparound:Int = 1

Global alivecol:Float[] = [ 0.0, 1.0, 0.0, 1.0 ]
Global deadcol:Float[]=[ 0.0, 0.0, 0.0, 0.0 ]



SetGraphicsDriver GLGraphicsDriver()

Graphics(winw,winh,0,0,GRAPHICS_STENCILBUFFER|GRAPHICS_ALPHABUFFER)

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);

glReadBuffer(GL_FRONT);
glDrawBuffer(GL_FRONT);

glClearColor(0.0, 0.0, 0.0, 0.0);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, Float(winw), 0.0, Float(winh), -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);

glViewport(0.0, 0.0, Float(winw), Float(winh));

randdots()

While Not KeyHit(KEY_ESCAPE)
	If AppTerminate() Then End
	If KeyDown(KEY_R) Then
		'FlushKeys()
		randdots()
	EndIf
	generation()
	glFinish()
Wend

Function randdots()
	glColor4fv(alivecol)
	glBegin(GL_POINTS)
	For Local n:Int=1 To 10000
	glvertex2f Rand(0,winw),Rand(0,winh)
	Next
	glend()
	glfinish()
EndFunction

Function drawQuad(x:Int, y:Int)

	glBegin(GL_QUADS)

	If wraparound Then
'		// this is clever - use texture coordinate wrapping For edge wraparound
		Local tx:Float, ty:Float
		tx = Float(x) / Float(lifew)
		ty = Float(y) / Float(lifeh)
		glTexCoord2f(tx, ty)
		glVertex2i(0, 0)
		glTexCoord2f(tx + 1.0, ty)
		glVertex2i(lifew, 0)
		glTexCoord2f(tx + 1.0, ty + 1.0)
		glVertex2i(lifew, lifeh)
		glTexCoord2f(tx, ty + 1.0)
		glVertex2i(0, lifeh);

	Else 
		glTexCoord2f(0.0, 0.0); glVertex2i(x, y);
		glTexCoord2f(1.0, 0.0); glVertex2i(x + lifew, y);
		glTexCoord2f(1.0, 1.0); glVertex2i(x + lifew, y + lifeh);
		glTexCoord2f(0.0, 1.0);	glVertex2i(x, y + lifeh);
	EndIf

	glEnd()
EndFunction

Function generation()

	glClear(GL_STENCIL_BUFFER_BIT);

'	/* read frame buffer To texture memory */
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 0, 0, lifew, lifeh, 0);

	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glEnable(GL_TEXTURE_2D);

'	/* draw image 8 times offset with stencil To count neighbours */
	glAlphaFunc(GL_GREATER, 0.0);	'/* only write pixels with alpha > 0.0 */
	glEnable(GL_ALPHA_TEST);
	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); '	/* no need To write To color buffer */

	glStencilFunc(GL_ALWAYS, 0, $ff);
	glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);'	/* fail, zfail, zpass */
	glEnable(GL_STENCIL_TEST);

	drawQuad(-1, -1);
	drawQuad( 0, -1);
	drawQuad( 1, -1);
	drawQuad(-1,  0);
	drawQuad( 1,  0);
	drawQuad(-1,  1);
	drawQuad( 0,  1);
	drawQuad( 1,  1);

	glDisable(GL_STENCIL_TEST);
	glDisable(GL_ALPHA_TEST);
	glDisable(GL_TEXTURE_2D);

	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); '	/* enable writes To color buffer */

'	// draw births (neighbours == 3)
	glStencilFunc(GL_EQUAL, 3, $ff);	'	/* write And decr, only If stencil == 3 */
	glStencilOp(GL_KEEP, GL_DECR, GL_DECR);	'/* fail, zfail, zpass */
	glEnable(GL_STENCIL_TEST);

	glColor4fv(alivecol);
	drawQuad(0, 0);	

'	// clear everything but survivors (neighbours == 2 Or 3) */
	glStencilFunc(GL_NOTEQUAL, 2, $ff);	'/* write only If stencil != 2 */
	glColor4fv(deadcol);
	drawQuad(0, 0);	

	glDisable(GL_STENCIL_TEST);

'	checkErrors("generation");
	gen:+1;
EndFunction


Thank you, just found this, i'm quite impressed as well.