dev in the making

game development, maya and code by brainzizi

GameOfLife – Source code

leave a comment »

O hai! Last time I’ve posted I promised you some code so here it is.

GameOfLifeGPU is a simple project to implement Conway’s Game Of Life algorithm on a GPU. I’m using a 400×300 grid with edge wrapping, loading premade patterns from 400×300 content files and a simple mechanism for switching between those premade patterns. I’m also using a QuadDrawer class which you can find somewhere on Ziggyware.

GameOfLife.cs:


using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.IO;

namespace GameOfLifeGPU
{
 /// <summary>
 /// This is the main type for your game
 /// </summary>
 public class GameOfLife : Microsoft.Xna.Framework.Game
 {
 GraphicsDeviceManager graphics;
 SpriteBatch spriteBatch;
 private QuadRenderer quadDrawer;

 private int width = 400;
 private int height = 300;
 private RenderTarget2D gridRT;
 private Texture2D texture;

 private Effect clearEffect;
 private Effect updateEffect;

 private string currentTexture = "gliders";

 private KeyboardState keyState;
 private KeyboardState oldKeyState;

 public GameOfLife()
 {
 graphics = new GraphicsDeviceManager(this);
 Content.RootDirectory = "Content";

 quadDrawer = new QuadRenderer(this);
 Components.Add(quadDrawer);
 }

 /// <summary>
 /// Allows the game to perform any initialization it needs to before starting to run.
 /// This is where it can query for any required services and load any non-graphic
 /// related content.  Calling base.Initialize will enumerate through any components
 /// and initialize them as well.
 /// </summary>
 protected override void Initialize()
 {
 graphics.PreferredBackBufferWidth = 1024;
 graphics.PreferredBackBufferHeight = 786;
 graphics.PreferMultiSampling = false;
 graphics.ApplyChanges();

 IsFixedTimeStep = true;
 IsMouseVisible = true;
 TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 10);

 base.Initialize();
 }

 /// <summary>
 /// LoadContent will be called once per game and is the place to load
 /// all of your content.
 /// </summary>
 protected override void LoadContent()
 {
 // Create a new SpriteBatch, which can be used to draw textures.
 spriteBatch = new SpriteBatch(GraphicsDevice);

 clearEffect = Content.Load<Effect>("Effects\\clear");
 updateEffect = Content.Load<Effect>("Effects\\update");
 gridRT = new RenderTarget2D(GraphicsDevice, width, height, 1, SurfaceFormat.Color);

 texture = Content.Load<Texture2D>("glider");
 }

 /// <summary>
 /// UnloadContent will be called once per game and is the place to unload
 /// all content.
 /// </summary>
 protected override void UnloadContent()
 {
 }

 /// <summary>
 /// Allows the game to run logic such as updating the world,
 /// checking for collisions, gathering input, and playing audio.
 /// </summary>
 /// <param name="gameTime">Provides a snapshot of timing values.</param>
 protected override void Update(GameTime gameTime)
 {
 oldKeyState = keyState;
 keyState = Keyboard.GetState();
 if (keyState.IsKeyDown(Keys.Space) && !oldKeyState.IsKeyDown(Keys.Space))
 {
 string[] textures = Directory.GetFiles(Content.RootDirectory);
 for (int j = 0; j < textures.Length; j++)
 {
 textures[j] = Path.GetFileNameWithoutExtension(textures[j]);
 }

 int i = Array.IndexOf(textures, currentTexture);
 texture = Content.Load<Texture2D>(textures[(i + 1)%textures.Length]);
 currentTexture = textures[(i + 1)%textures.Length];
 Window.Title = "GameOfLife - " + currentTexture;
 }

 base.Update(gameTime);
 }

 /// <summary>
 /// This is called when the game should draw itself.
 /// </summary>
 /// <param name="gameTime">Provides a snapshot of timing values.</param>
 protected override void Draw(GameTime gameTime)
 {
 GraphicsDevice.SetRenderTarget(0, gridRT);
 updateEffect.Begin();
 updateEffect.Parameters["Texture"].SetValue(texture);
 updateEffect.Parameters["GridSize"].SetValue(new Vector2(width, height));
 updateEffect.CurrentTechnique.Passes[0].Begin();
 quadDrawer.RenderFullscreen();
 updateEffect.CurrentTechnique.Passes[0].End();
 updateEffect.End();

 GraphicsDevice.SetRenderTarget(0, null);
 texture = gridRT.GetTexture();
 GraphicsDevice.Clear(Color.Black);
 spriteBatch.Begin();
 spriteBatch.Draw(texture,
 new Rectangle(0, 0, GraphicsDevice.PresentationParameters.BackBufferWidth, GraphicsDevice.PresentationParameters.BackBufferHeight),
 Color.White);
 spriteBatch.End();

 base.Draw(gameTime);
 }

 }
}

Just simple pattern switching code in the Update region and the draw mechanism in the Draw region.

Content\Effects\clear.fx:


struct VertexShaderInput
{
 float4 Position : POSITION0;
};

struct VertexShaderOutput
{
 float4 Position : POSITION0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
 VertexShaderOutput output;
 output.Position = input.Position;

 return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
 return float4(0, 0, 0, 1);
}

technique Technique1
{
 pass Pass1
 {
 VertexShader = compile vs_1_1 VertexShaderFunction();
 PixelShader = compile ps_1_1 PixelShaderFunction();
 }
}

Content\Effects\update.fx:


texture Texture;
sampler2D TextureSampler = sampler_state
{
 Texture = <Texture>;
 ADDRESSU = WRAP;
 ADDRESSV = WRAP;
 MAGFILTER = POINT;
 MINFILTER = POINT;
 MIPFILTER = POINT;
};

float2 GridSize;

struct VertexShaderInput
{
 float4 Position : POSITION0;
 float2 Texcoord : TEXCOORD0;
};

struct VertexShaderOutput
{
 float4 Position : POSITION0;
 float2 Texcoord : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
 VertexShaderOutput output;

 output.Position = input.Position;
 output.Texcoord = input.Texcoord;

 return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
 float4 cell = float4(0, 0, 0, 1);
 float4 alive = float4(1, 1, 1, 1);
 float4 dead = float4(0, 0, 0, 1);

 float2 pixel = 1.0f / GridSize;

 float n = 0.0f;

 // count neighbours
 n += tex2D(TextureSampler, float2(input.Texcoord.x - pixel.x, input.Texcoord.y - pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x - pixel.x, input.Texcoord.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x - pixel.x, input.Texcoord.y + pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x, input.Texcoord.y - pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x, input.Texcoord.y + pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x + pixel.x, input.Texcoord.y - pixel.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x + pixel.x, input.Texcoord.y)).r;
 n += tex2D(TextureSampler, float2(input.Texcoord.x + pixel.x, input.Texcoord.y + pixel.y)).r;

 if (tex2D(TextureSampler, input.Texcoord).r == 1.0f)
 {
 if (n == 2.0f || n == 3.0f)
 cell = alive;
 else
 cell = dead;
 }
 else
 {
 if (n == 3.0f)
 cell = alive;
 else
 cell = dead;
 }

 return cell;
}

technique Technique1
{
 pass Pass1
 {
 // TODO: set renderstates here.

 VertexShader = compile vs_2_0 VertexShaderFunction();
 PixelShader = compile ps_2_0 PixelShaderFunction();
 }
}

The algorithm kicks in the update.fx. Space cycles the premade patterns and you can make your own patterns by inserting your own 400×300 images. Check out the premade patterns. Wrapping edges were so easy to do. Easy like writing ADDRESSU = WRAP;  ADDRESSV = WRAP;. In the CPU version they are a bit more complicated. So here you go. Simple and easy. Here’s the complete project in a zip file (73kb), which you can download from MU or RS:

http://www.megaupload.com/?d=PMV3OPJF

http://rapidshare.com/files/290162624/GameOfLifeGPU.zip

EDIT: I’ve corrected a typo in the LoadContent method. The starting texture name shouldn’t be “gliders”, but “glider”. Please correct this in your downloaded project file also.

Written by brainzizizi

10.08.2009 at 07:14

Posted in XNA, general programming

Tagged with , ,

Offside – Semester started

leave a comment »

As soon as the semester starts I got a mental blockade as far as programming goes. Last I did in like 30 minutes was Conway’s game of life on the CPU and the GPU. It’s easier to do on the GPU if you know what you’re doing. I’ll post the source as soon as I have some time.

Written by brainzizizi

09.20.2009 at 09:01

Offside – WordPress deleting my pics?

leave a comment »

In the last post I uploaded a pic of a door, and WP deleted it. Just throws a file not found. This wouldn’t be weird if it didn’t happened the last time a posted a pic and then included it as a 1×1 gallery in the post. Awful.

Written by brainzizizi

09.14.2009 at 21:54

Posted in private

Tagged with ,