Reaction-Diffusion
Note to Internet Explorer users
About the code
Definition
 
				
Coding
		float table[2][SCREEN_HEIGHT][SCREEN_WIDTH];
				
		float nextTable[2][SCREEN_HEIGHT][SCREEN_WIDTH];
				
		float DA = 1.0f;
		float DB = 0.5f;
		float f = 0.055f;
		float k = 0.062f;
				
		float Laplacian(int tab, int x, int y)
		{
				
			static const float coef[3][3] =
			{
				{0.05f, 0.2f,  0.05f},
				{0.2f,  -1.0f, 0.2f},
				{0.05f, 0.2f,  0.05f}
			};
				
			float sum = 0;
			for (int dy = -1; dy <= 1; dy++)
				for (int dx = -1; dx <= 1; dx++)
				{
				
					int posX = (x + dx + SCREEN_WIDTH) % SCREEN_WIDTH;
					int posY = (y + dy + SCREEN_HEIGHT) % SCREEN_HEIGHT;
				
					float c = coef[dy + 1][dx + 1];
					sum += c * table[tab][posY][posX];
				}
				
			return sum;
		}
				
		void update()
		{
				
			for (int y = 0; y < SCREEN_HEIGHT; ++y)
				for (int x = 0; x < SCREEN_WIDTH; ++x)
				{
				
					float A = table[0][y][x];
					float B = table[1][y][x];
				
					nextTable[0][y][x] = A + DA * Laplacian(0, x, y) - A * B * B + f * (1.0f - A);
					nextTable[1][y][x] = B + DB * Laplacian(1, x, y) + A * B * B - (k + f) * B;
				}
				
			memcpy(table, nextTable, SCREEN_WIDTH * SCREEN_HEIGHT * 2 * sizeof(float));
		}
				
		// initialize the table
		for (int y = 0; y < SCREEN_HEIGHT; ++y)
			for (int x = 0; x < SCREEN_WIDTH; ++x)
			{
				table[0][y][x] = 1.0f;
				table[1][y][x] = 0.0f;
			}
				
		for (int y = 0; y < 10; ++y)
			for (int x = 0; x < 10; ++x)
			{
				int posX = SCREEN_WIDTH  / 2 + x - 5;
				int posY = SCREEN_HEIGHT / 2 + y - 5;
				table[1][posY][posX] = 1.0f;
			}
				
		while (sys.isQuitRequested() == false)
		{
			// draw the current table
			for (int y = 0; y < SCREEN_HEIGHT; ++y)
				for (int x = 0; x < SCREEN_WIDTH; ++x)
				{
					Color col(table[0][y][x] * 255,
					          0,
					          table[1][y][x] * 255);
					gfx.setPixel(x, y, col);
				}
				
			gfx.render();
			sys.processEvents();
				
			// update the table
			update();
		}
		Download source code
		Download executable for Windows
				
 
				
Timing
		float tim = 0;
		int cnt = 0;
				
		sys.StartPerfCounter();
				
		cnt++;
		if (cnt < 2000)
			tim += sys.StopPerfCounter();
		else if (cnt == 2000)
			printf("%f\n", tim);
		Download source code
		Download executable for Windows
				
Using doubles
		#include <stdio.h>
		#include <stdlib.h>
		#include "main.h"
		#include "Graphics.h"
		#include "System.h"
		#include <string.h>
		#include <stdlib.h>
		#define SCREEN_WIDTH    400
		#define SCREEN_HEIGHT   400
		double table[2][SCREEN_HEIGHT][SCREEN_WIDTH];
		double nextTable[2][SCREEN_HEIGHT][SCREEN_WIDTH];
		double DA = 1.0;
		double DB = 0.5;
		double f = 0.055;
		double k = 0.062;
		double Laplacian(int tab, int x, int y)
		{
			static const double coef[3][3] =
			{
				{0.05, 0.2,  0.05},
				{0.2,  -1.0, 0.2},
				{0.05, 0.2,  0.05}
			};
			double sum = 0;
			for (int dy = -1; dy <= 1; dy++)
				for (int dx = -1; dx <= 1; dx++)
				{
					int posX = (x + dx + SCREEN_WIDTH) % SCREEN_WIDTH;
					int posY = (y + dy + SCREEN_HEIGHT) % SCREEN_HEIGHT;
					double c = coef[dy + 1][dx + 1];
					sum += c * table[tab][posY][posX];
				}
			return sum;
		}
		float tim = 0;
		int cnt = 0;
		void update()
		{
			sys.StartPerfCounter();
			for (int y = 0; y < SCREEN_HEIGHT; ++y)
				for (int x = 0; x < SCREEN_WIDTH; ++x)
				{
					double A = table[0][y][x];
					double B = table[1][y][x];
					nextTable[0][y][x] = A + DA * Laplacian(0, x, y) - A * B * B + f * (1.0 - A);
					nextTable[1][y][x] = B + DB * Laplacian(1, x, y) + A * B * B - (k + f) * B;
				}
			memcpy(table, nextTable, SCREEN_WIDTH * SCREEN_HEIGHT * 2 * sizeof(double));
			cnt++;
			if (cnt < 2000)
				tim += sys.StopPerfCounter();
			else if (cnt == 2000)
				printf("%f\n", tim);
		}
		int main(int argc, char* argv[])
		{
			// init the window
			gfx.init("Reaction/Diffusion 2", SCREEN_WIDTH, SCREEN_HEIGHT);
			gfx.init2D();
			gfx.clearScreen(Color(0, 0, 0, SDL_ALPHA_OPAQUE));
			// initialize the table
			for (int y = 0; y < SCREEN_HEIGHT; ++y)
				for (int x = 0; x < SCREEN_WIDTH; ++x)
				{
					table[0][y][x] = 1.0;
					table[1][y][x] = 0.0;
				}
			for (int y = 0; y < 10; ++y)
				for (int x = 0; x < 10; ++x)
				{
					int posX = SCREEN_WIDTH  / 2 + x - 5;
					int posY = SCREEN_HEIGHT / 2 + y - 5;
					table[1][posY][posX] = 1.0;
				}
			while (sys.isQuitRequested() == false)
			{
				// draw the current table
				for (int y = 0; y < SCREEN_HEIGHT; ++y)
					for (int x = 0; x < SCREEN_WIDTH; ++x)
					{
						Color col(table[0][y][x] * 255,
						          0,
						          table[1][y][x] * 255);
						gfx.setPixel(x, y, col);
					}
				gfx.render();
				sys.processEvents();
				// update the table
				update();
			}
			gfx.quit();
			return EXIT_SUCCESS;
		}
		Download source code
		Download executable for Windows
				
Rewriting the laplacian
		double Laplacian(int tab, int x, int y)
		{
			int xp[3];
			int yp[3];
			for (int i = -1; i <= 1; i++)
			{
			   xp[i + 1] = (x + i +  SCREEN_WIDTH) % SCREEN_WIDTH;
			   yp[i + 1] = (y + i + SCREEN_HEIGHT) % SCREEN_HEIGHT;
			}
				
			double sum1 = table[tab][yp[0]][xp[0]] +
			              table[tab][yp[0]][xp[2]] +
			              table[tab][yp[2]][xp[0]] +
			              table[tab][yp[2]][xp[2]];
			double sum2 = table[tab][yp[0]][xp[1]] +
			              table[tab][yp[1]][xp[0]] +
			              table[tab][yp[1]][xp[2]] +
			              table[tab][yp[2]][xp[1]];
			return 0.05 * sum1 + 0.2 * sum2 - table[tab][yp[1]][xp[1]];
		}
		Download source code
		Download executable for Windows
				
Avoiding wrapping
		double table[2][SCREEN_HEIGHT+2][SCREEN_WIDTH+2];
		double nextTable[2][SCREEN_HEIGHT+2][SCREEN_WIDTH+2];
				
		for (int i = -1; i <= 1; i++)
		{
			xp[i + 1] = x + i;
			yp[i + 1] = y + i;
		}
				
		for (int y = 1; y < SCREEN_HEIGHT+1; ++y)
			for (int x = 1; x < SCREEN_WIDTH+1; ++x)
			{
				double A = table[0][y][x];
				
		memcpy(table, nextTable, (SCREEN_WIDTH+2) * (SCREEN_HEIGHT+2) * 2 * sizeof(double));
				
		// initialize the table
		for (int y = 0; y < SCREEN_HEIGHT+2; ++y)
			for (int x = 0; x < SCREEN_WIDTH+2; ++x)
			{
				table[0][y][x] = 1.0;
				table[1][y][x] = 0.0;
				nextTable[0][y][x] = 1.0;
				nextTable[1][y][x] = 0.0;
			}
				
		// draw the current table
		for (int y = 0; y < SCREEN_HEIGHT; ++y)
			for (int x = 0; x < SCREEN_WIDTH; ++x)
			{
				int r = table[0][y+1][x+1] * 255;
				int b = table[1][y+1][x+1] * 255;
				gfx.setPixel(x, y, Color(r, 0, b));
			}
		Download source code
		Download executable for Windows
				 
				
Rewriting the laplacian (2)
		double prod1Table[2][SCREEN_HEIGHT+2][SCREEN_WIDTH+2];
		double prod2Table[2][SCREEN_HEIGHT+2][SCREEN_WIDTH+2];
				
		void product()
		{
			for (int t = 0; t < 2; t++)
			{
				for (int y = 0; y < SCREEN_HEIGHT+2; ++y)
					for (int x = 1; x < SCREEN_WIDTH+1; ++x)
						prod1Table[t][y][x] = table[t][y][x - 1] + 4.0f * table[t][y][x] + table[t][y][x + 1];
				for (int y = 1; y < SCREEN_HEIGHT+1; ++y)
					for (int x = 1; x < SCREEN_WIDTH+1; ++x)
						prod2Table[t][y][x] = prod1Table[t][y - 1][x] + 4.0f * prod1Table[t][y][x] + prod1Table[t][y + 1][x];
			}
		}
				
		double Laplacian(int tab, int x, int y)
		{
			return 0.05 * prod2Table[tab][y][x] - 1.8 * table[tab][y][x];
		}
				
		void update()
		{
			sys.StartPerfCounter();
			product();
		Download source code
		Download executable for Windows
				
Rewriting the main formulas
		nextTable[0][y][x] = A + DA * Laplacian(0, x, y) - A * B * B + f * (1.0 - A);
		nextTable[1][y][x] = B + DB * Laplacian(1, x, y) + A * B * B - (k + f) * B;
				
		nextTable[0][y][x] = A + DA * (0.05 * prod2Table[0][y][x] - 1.8 * table[0][y][x]) - A*B*B + f*(1.0 - A);
		nextTable[1][y][x] = B + DB * (0.05 * prod2Table[1][y][x] - 1.8 * table[1][y][x]) + A*B*B - (k + f)*B;
				
		nextTable[0][y][x] = A + DA * (0.05 * prod2Table[0][y][x] - 1.8*A) - A*B*B + f*(1.0 - A);
		nextTable[1][y][x] = B + DB * (0.05 * prod2Table[1][y][x] - 1.8*B) + A*B*B - (k + f)*B;
				
		nextTable[0][y][x] = A + DA * 0.05 * prod2Table[0][y][x] - 1.8*DA*A - A*B*B + f - f*A;
		nextTable[1][y][x] = B + DB * 0.05 * prod2Table[1][y][x] - 1.8*DB*B + A*B*B - k*B - f*B;
				
		nextTable[0][y][x] = 0.05 * DA * prod2Table[0][y][x] - A*B*B + A - f*A - 1.8*DA*A + f;
		nextTable[1][y][x] = 0.05 * DB * prod2Table[1][y][x] + A*B*B + B - f*B - 1.8*DB*B - k*B;
				
		nextTable[0][y][x] = 0.05 * DA * prod2Table[0][y][x] - A*B*B + (1.0 - f - 1.8*DA) * A + f;
		nextTable[1][y][x] = 0.05 * DB * prod2Table[1][y][x] + A*B*B + (1.0 - f - 1.8*DB - k) * B;
				
		double ca = 1.0 - f - 1.8 * DA;
		double cb = 1.0 - f - 1.8 * DB - k;
		nextTable[0][y][x] = 0.05 * DA * prod2Table[0][y][x] - A*B*B + ca * A + f;
		nextTable[1][y][x] = 0.05 * DB * prod2Table[1][y][x] + A*B*B + cb * B;
				
		void update()
		{
			sys.StartPerfCounter();
			double ca = 1.0 - f - 1.8 * DA;
			double cb = 1.0 - f - 1.8 * DB - k;
			product();
			for (int y = 1; y < SCREEN_HEIGHT+1; ++y)
				for (int x = 1; x < SCREEN_WIDTH+1; ++x)
				{
					double A = table[0][y][x];
					double B = table[1][y][x];
					nextTable[0][y][x] = 0.05 * DA * prod2Table[0][y][x] - A * B * B + ca * A + f;
					nextTable[1][y][x] = 0.05 * DB * prod2Table[1][y][x] + A * B * B + cb * B;
				}
				
			[...]
		}
		Download source code
		Download executable for Windows
				
Avoiding the memcpy()
		double table[2][2][SCREEN_HEIGHT+2][SCREEN_WIDTH+2];
				
		int curT = 0;
				
		prod1Table[t][y][x] = table[curT][t][y][x - 1] + 4.0f * table[curT][t][y][x] + table[curT][t][y][x + 1];
				
		void update()
		{
			[...]
			for (int y = 1; y < SCREEN_HEIGHT+1; ++y)
				for (int x = 1; x < SCREEN_WIDTH+1; ++x)
				{
					double A = table[curT][0][y][x];
					double B = table[curT][1][y][x];
					table[1-curT][0][y][x] = 0.05 * DA * prod2Table[0][y][x] - A * B * B + ca * A + f;
					table[1-curT][1][y][x] = 0.05 * DB * prod2Table[1][y][x] + A * B * B + cb * B;
				}
				
		curT = 1 - curT;
		Download source code
		Download executable for Windows
				
Putting back the wrapping
		void update()
		{
			double ca = 1.0 - f - 1.8 * DA;
			double cb = 1.0 - f - 1.8 * DB - k;
			for (int t = 0; t < 2; ++t)
			{
				for (int x = 0; x < SCREEN_WIDTH + 2; ++x)
				{
					table[curT][t][SCREEN_HEIGHT - 1][x] = table[curT][t][1][x];
					table[curT][t][0][x] = table[curT][t][SCREEN_HEIGHT - 2][x];
				}
				for (int y = 0; y < SCREEN_HEIGHT + 2; ++y)
				{
					table[curT][t][y][SCREEN_WIDTH - 1] = table[curT][t][y][1];
					table[curT][t][y][0] = table[curT][t][y][SCREEN_WIDTH - 2];
				}
				table[curT][t][0][0] = table[curT][t][SCREEN_HEIGHT - 2][SCREEN_WIDTH - 2];
				table[curT][t][0][SCREEN_WIDTH - 1] = table[curT][t][SCREEN_HEIGHT - 2][1];
				table[curT][t][SCREEN_HEIGHT - 1][0] = table[curT][t][1][SCREEN_WIDTH - 2];
				table[curT][t][SCREEN_HEIGHT - 1][SCREEN_WIDTH - 1] = table[curT][t][1][1];
			}
		Download source code
		Download executable for Windows
				
Bonus: cool effect
		int r = table[0][0][y+1][x+1] * 255;
		int b = table[0][1][y+1][x+1] * 255;
		int g = (table[0][0][y+1][x+1] - table[1][0][y+1][x+1]) * 650000;
		g = ABS(g);
		if (g > 255)
			g = 255;
		gfx.setPixel(x, y, Color(r, g, b));
		Download source code
		Download executable for Windows
				
