Jump to content

Cellular Automaton


Recommended Posts

Ignore this post. I got the code to work (see later in thread). Feel free to critique, of course.

I've never written a plugin before, so I thought I'd start with something simple... a cellular automaton... <_< I figured it might be useful for making textures or something.

After writing this code, I finally got no errors to come up. I'm not really familiar with C# that much, so it took me like 15 minutes to figure out that Math.pow should be Math.Pow (I'm mostly use to java and actionscript). Anywho, when I run this code in codelab nothing happens, and I can't really seem to figure out why. Any help appreciated! :)

Also, I know it's not optimized AT ALL (lol), I was just trying to get it to actually work first.

Behold... my first of many crappy attempts at a plugin:

(Code outdated - updated (and working) version in later reply)

#region UICode
int Amount1=30;	//[0,255]Rule Number
#endregion

void Render(Surface dst, Surface src, Rectangle rect)
{
   ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
   ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;

   bool[] table = new bool[8];
   for(int i = 0; i < 7; i++)
   {
       table[i] = false;
   }
   //rule [0-255]
   int rule = Amount1;
   for(int place = 7; place >= 0; place--)
   {
       if(rule >= Math.Pow(2, place))
       {
           rule -= (int)Math.Pow(2, place);
           table[7-place] = true;
       }
   }	

   ColorBgra CurrentPixel;

   //Randomize first row
   Random random = new Random();
   for (int x = rect.Left; x < rect.Right; x++)
   {
	CurrentPixel = src[x,rect.Top];
	if (random.Next(2) == 1)
	{
	    CurrentPixel.R = (byte)PrimaryColor.R;
           	    CurrentPixel.G = (byte)PrimaryColor.G;
           	    CurrentPixel.B = (byte)PrimaryColor.B;
           	    CurrentPixel.A = (byte)PrimaryColor.A;
	}
	else
	{
	    CurrentPixel.R = (byte)SecondaryColor.R;
         	    CurrentPixel.G = (byte)SecondaryColor.G;
          	    CurrentPixel.B = (byte)SecondaryColor.B;
          	    CurrentPixel.A = (byte)SecondaryColor.A;
	}
	dst[x,rect.Top] = CurrentPixel;
}

   for (int y = rect.Top+1; y < rect.Bottom; y++)
   {
       for (int x = rect.Left; x < rect.Right; x++)
       {
		CurrentPixel = src[x,y];
		bool left = false, middle = false, right = false;
		if(x != 0 && dst[x-1,y-1] == PrimaryColor)
		{
			left = true;
		}
		if(dst[x,y-1] == PrimaryColor)
		{
			middle = true;
		}
		if(x != rect.Right && dst[x+1,y-1] == PrimaryColor)
		{
			right = true;
		}



		if(left) //B--
		{
			if(middle) //BB-
			{
				if(right) //BBB
				{
					if(table[0])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
				else //BBW
				{
					if(table[1])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
			}
			else //BW-
			{
				if(right) //BWB
				{
					if(table[2])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
				else //BWW
				{
					if(table[3])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
			}
		}
		else //W--
		{
			if(middle) //WB-
			{
				if(right) //WBB
				{
					if(table[4])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
				else //WBW
				{
					if(table[5])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
			}
			else //WW-
			{
				if(right) //WWB
				{
					if(table[6])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
				else //WWW
				{
					if(table[7])
					{
						CurrentPixel.R = (byte)PrimaryColor.R;
						CurrentPixel.G = (byte)PrimaryColor.G;
						CurrentPixel.B = (byte)PrimaryColor.B;
						CurrentPixel.A = (byte)PrimaryColor.A;
					}
					else
					{
						CurrentPixel.R = (byte)SecondaryColor.R;
						CurrentPixel.G = (byte)SecondaryColor.G;
						CurrentPixel.B = (byte)SecondaryColor.B;
						CurrentPixel.A = (byte)SecondaryColor.A;
					}
				}
			}
		}
		dst[x,y] = CurrentPixel;
       }
   }
}

Edited by Hellfire010
HellRiverSig3_stretch.png
Link to comment
Share on other sites

Ignore this post. I got the code to work (see later in thread). Feel free to critique, of course.

lol :roll: it is rather... err... iffy >_>

http://en.wikipedia.org/wiki/Cellular_automaton

or, more specifically,

http://en.wikipedia.org/wiki/Elementary_cellular_automaton

Basing this off of a Java program I wrote for a class last year.

http://privatepaste.com/3718890fbf

An example of "rule 30"

rule30r.gif

Mostly, rule multiples of 15 produce interesting fractals. I have a lot of weird and interesting ideas to do with this once I get it working.

It was like 1:00 am and it's my first attempt, I'm trying to figure out how these pluginamajiggies work x_x

...Oh, and is a bool or an array of bools in C# automatically set to false when created? Wasn't sure on that.

But... this is my updated code. Something isn't working right. I think it's something to do with the ROI thing. So yeah, help appreciated. Oh, commented it a bit for you Rick, in case you're interested in this awful mess. :P

Some pictures (random turned off)

This is what it's suppose to look like, and on occasion, it will render this way. In fact, every time it runs at these settings it should look exactly like this.

http://i172.photobucket.com/albums/w6/AndrewM16921/Random/right.jpg

But, I often get results like these:

http://i172.photobucket.com/albums/w6/AndrewM16921/Random/fail1.jpg

http://i172.photobucket.com/albums/w6/AndrewM16921/Random/fail2.jpg

http://i172.photobucket.com/albums/w6/AndrewM16921/Random/fail3.jpg

http://i172.photobucket.com/albums/w6/AndrewM16921/Random/fail4.jpg

(Code outdated - updated (and working) version in later reply)

#region UICode
int Amount1 = 30;	//[0,255]Rule Number
bool Amount2 = true; // [0,1] Wrap
bool Amount3 = false; // [0,1] Randomize
#endregion

private static bool[] table = new bool[8];
private static bool[] prevRow, currentRow;

private static int mostRecentRowCalculated = -1;
private static void calcRow(int row, int width, bool rand, bool wrap)
{
if(mostRecentRowCalculated == -1)
{
	//Randomize a first row
	if(rand)
	{
		currentRow = new bool[width];
		Random random = new Random();
		for(int x = 0; x < width; x++)
		{
			if(random.Next(6) == 1)
			{
				currentRow[x] = true;
			}
			else
			{
				currentRow[x] = false;
			}
		}
	}
	//Creates first row with just a center pixel
	else
	{
		currentRow = new bool[width];
		currentRow[width/2] = true;
	}
	mostRecentRowCalculated++;
}

while(mostRecentRowCalculated < row)
{
	prevRow = currentRow;
	currentRow = new bool[width];
	for(int x = 0; x < width; x++)
	{
		//Again, idk if this is necessary in C#
		bool left = false, middle = false, right = false;

		//Determines the "neighborhood" from previous row
		if( (x != 0 && prevRow[x-1]) || (wrap && x == 0 && prevRow[width-1]) )
		{
			left = true;
		}
		if(prevRow[x])
		{
			middle = true;
		}
		if( (x != width-1 && prevRow[x+1]) || (wrap && x == width-1 && prevRow[0]) )
		{
			right = true;
		}

		//Use rule to determine the current pixel from the neighborhood
		//In comments: 'B' represents true, 'W' represents false ... (black/white)
		currentRow[x] = false;
		if(left) //B--
		{
			if(middle) //BB-
			{
				if(right) //BBB
				{
					if(table[0])
					{
						currentRow[x] = true;
					}
				}
				else //BBW
				{
					if(table[1])
					{
						currentRow[x] = true;
					}
				}
			}
			else //BW-
			{
				if(right) //BWB
				{
					if(table[2])
					{
						currentRow[x] = true;
					}
				}
				else //BWW
				{
					if(table[3])
					{
						currentRow[x] = true;
					}
				}
			}
		}
		else //W--
		{
			if(middle) //WB-
			{
				if(right) //WBB
				{
					if(table[4])
					{
						currentRow[x] = true;
					}
				}
				else //WBW
				{
					if(table[5])
					{
						currentRow[x] = true;
					}
				}
			}
			else //WW-
			{
				if(right) //WWB
				{
					if(table[6])
					{
						currentRow[x] = true;
					}
				}
				else //WWW
				{
					if(table[7])
					{
						currentRow[x] = true;
					}
				}
			}
		}
	}
	mostRecentRowCalculated++;
}
}

//RENDER
void Render(Surface dst, Surface src, Rectangle rect)
{
ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;

//Idk if this is necessary in C#. I know it's not in Java, but just in case I put it in for now...
for(int i = 0; i < 7; i++)
{
	table[i] = false;
}
//Determine rule table by converting Amount1 [0-255] to an array of bools (binary representation)
int rule = Amount1;
for(int place = 7; place >= 0; place--)
{
	if(rule >= Math.Pow(2, place))
	{
		rule -= (int)Math.Pow(2, place);
		table[7-place] = true;
	}
}

ColorBgra CurrentPixel;
for (int y = rect.Top; y < rect.Bottom; y++)
{
	calcRow(y, src.Width, Amount3, Amount2);
	for (int x = rect.Left; x < rect.Right; x++)
	{
		CurrentPixel = new ColorBgra();
		//Set new pixel
		if(currentRow[x])
		{
			CurrentPixel.R = (byte)PrimaryColor.R;
			CurrentPixel.G = (byte)PrimaryColor.G;
			CurrentPixel.B = (byte)PrimaryColor.B;
			CurrentPixel.A = (byte)PrimaryColor.A;
		}
		else
		{
			CurrentPixel.R = (byte)SecondaryColor.R;
			CurrentPixel.G = (byte)SecondaryColor.G;
			CurrentPixel.B = (byte)SecondaryColor.B;
			CurrentPixel.A = (byte)SecondaryColor.A;
		}
		dst[x,y] = CurrentPixel;
	}
}
}

Edited by Hellfire010
HellRiverSig3_stretch.png
Link to comment
Share on other sites

So... after much fiddling, I finally got it to work right.

Not exactly optimized, but it works for now (cept changing settings in the UI doesn't update it right... trying to figure out why).

#region UICode
int Amount1 = 30;	//[0,255] Rule Number
bool Amount2 = true; // [0,1] Wrap
bool Amount3 = false; // [0,1] Randomize
#endregion

private static bool[] ruleTable = new bool[8];
private static bool[,] table;
private static void generateTable(int width, int height, bool rand, bool wrap)
{
table = new bool[width,height];
//Randomize a first row
if(rand)
{
	Random random = new Random();
	for(int x = 0; x < width; x++)
	{
		if(random.Next(6) == 1)
		{
			table[x,0] = true;
		}
		else
		{
			table[x,0] = false;
		}
	}
}
//Creates first row with just a center pixel
else
{
	table[width/2,0] = true;
}

for(int y = 1; y < height; y++)
{
	for(int x = 0; x < width; x++)
	{
		bool left = false, middle = false, right = false;

		//Determines the "neighborhood" from previous row
		if( (x != 0 && table[x-1,y-1]) || (wrap && x == 0 && table[width-1,y-1]) )
		{
			left = true;
		}
		if(table[x,y-1])
		{
			middle = true;
		}
		if( (x != width-1 && table[x+1,y-1]) || (wrap && x == width-1 && table[0,y-1]) )
		{
			right = true;
		}

		//Use rule to determine the current pixel from the neighborhood
		//In comments: 'B' represents true, 'W' represents false ... (black/white)
		table[x,y] = false;
		if(left) //B--
		{
			if(middle) //BB-
			{
				if(right) //BBB
				{
					if(ruleTable[0])
					{
						table[x,y] = true;
					}
				}
				else //BBW
				{
					if(ruleTable[1])
					{
						table[x,y] = true;
					}
				}
			}
			else //BW-
			{
				if(right) //BWB
				{
					if(ruleTable[2])
					{
						table[x,y] = true;
					}
				}
				else //BWW
				{
					if(ruleTable[3])
					{
						table[x,y] = true;
					}
				}
			}
		}
		else //W--
		{
			if(middle) //WB-
			{
				if(right) //WBB
				{
					if(ruleTable[4])
					{
						table[x,y] = true;
					}
				}
				else //WBW
				{
					if(ruleTable[5])
					{
						table[x,y] = true;
					}
				}
			}
			else //WW-
			{
				if(right) //WWB
				{
					if(ruleTable[6])
					{
						table[x,y] = true;
					}
				}
				else //WWW
				{
					if(ruleTable[7])
					{
						table[x,y] = true;
					}
				}
			}
		}
	}
}
}

//RENDER
void Render(Surface dst, Surface src, Rectangle rect)
{
ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
ColorBgra SecondaryColor = (ColorBgra)EnvironmentParameters.SecondaryColor;

//Determine rule ruleTable by converting Amount1 [0-255] to an array of bools (binary representation)
int rule = Amount1;
for(int place = 7; place >= 0; place--)
{
	if(rule >= Math.Pow(2, place))
	{
		rule -= (int)Math.Pow(2, place);
		ruleTable[7-place] = true;
	}
}
if(table == null)
{
	generateTable(src.Width, src.Height, Amount3, Amount2);
}
ColorBgra CurrentPixel;
for (int y = rect.Top; y < rect.Bottom; y++)
{
	for (int x = rect.Left; x < rect.Right; x++)
	{
		CurrentPixel = new ColorBgra();
		//Set new pixel
		if(table[x,y])
		{
			CurrentPixel.R = (byte)PrimaryColor.R;
			CurrentPixel.G = (byte)PrimaryColor.G;
			CurrentPixel.B = (byte)PrimaryColor.B;
			CurrentPixel.A = (byte)PrimaryColor.A;
		}
		else
		{
			CurrentPixel.R = (byte)SecondaryColor.R;
			CurrentPixel.G = (byte)SecondaryColor.G;
			CurrentPixel.B = (byte)SecondaryColor.B;
			CurrentPixel.A = (byte)SecondaryColor.A;
		}
		dst[x,y] = CurrentPixel;
	}
}
}

Edited by Hellfire010
HellRiverSig3_stretch.png
Link to comment
Share on other sites

The problem is here:

	if(table == null)
{
	generateTable(src.Width, src.Height, Amount3, Amount2);
}

if you define table this way:

private static bool[,] table;

(which you do) it will only be null the first time the effect is run. "Static" makes it retain its values even after it is done. So, when the UI slider changes, the table will never be rebuilt.

You see, this is the sort of thing that needs to be called from the OnSetRenderInfo function which can not be modified in CodeLab. If you want this to work properly, you'll need to change it into a full project plugin. Read the "Limitations of CodeLab" section near the bottom of this page: http://boltbait.com/pdn/CodeLab/help/tutorial3.asp and specifically click the link on that page to look at the Render Flames plugin source code.

Link to comment
Share on other sites

//Idk if this is necessary in C#. I know it's not in Java, but just in case I put it in for now...
for(int i = 0; i < 7; i++)
{
	table[i] = false;
}

It is not necessary, as bool is a value type, not a reference type. It is, by default, false.

By the way, if it were necessary, you'd have experienced problems, since your indexing is wrong in this loop. You should be using i < 8 as your conditional, or you'll only index up to 6. Better yet, use i < table.Length.

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

And thanks Pyrochild, but I already changed that in my most reason version. And yeah, when I saw the 7 I literally facepalmed quietly to myself. =P

Hmmmm.... I could have sworn I saw that in the last code post and quoted from that. Weird; must be losing my mind.

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

Still appreciated though!

VS isn't free... sadface

Hmm... would it be possible to tell WHEN the Render function is on the last row. Like, if rect.Bottom is equal to the bottom of the selection? Then, from there, set table back to null? *goes to try*

Edited by Hellfire010
HellRiverSig3_stretch.png
Link to comment
Share on other sites

Express = free download! Get the latest version. It's all you'll ever need (unless you're actually a professional).

There's a VS template here

Link to comment
Share on other sites

The easiest way to turn a CodeLab script into a full project is to build it into a DLL using CodeLab. On that screen, click the check box that says "view source". On the source screen, select all and copy that to a .cs file.

Already did that ^_^

Just realized my school's free software section has VS 5 and 8, but I'm downloading 10 from DreamSpark now. Works for me. :o

There's a VS template here

Thanks for that. I'll look into it when I have time... Unfortunately, I have a Calc II exam tomorrow so I need to get studying a bit. All in due time, though.

But hey, no more copy/pasta from notepad++ :D

Edit:

Just sayin, after Java being my language of choice for quite a while, I read up on C# a bit today, and I think C# is starting to be my new choice... we shall see. O_o

Edited by Hellfire010
HellRiverSig3_stretch.png
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...