In any case, after you've gotten the compiler set up, here are instructions for adding in a new iteration function.
First, we need to decide what function to add. In this case, let's do a simple composite function, z -> (z*z+c)*(z*z+c)+d. This is simple f(f(z)) where f(z)=z^2+c, only with the c parameter different each time.
Let's name the function. We'll call it "(z^2+c)^2+d".
Next, we add that into the iterations listbox. Open up "Config Dialogue.h" and click on the listbox under the Iteration Function heading in the form designer. It should now be selected. Click on the little arrow that just appeared on top of the listbox. Select edit items. This should bring up a window with a field full of functions. Type in "(z^2+c)^2+d" (without quotes) on its own line and hit ok.
Now it will display our new function when we compile and run the settings for the screensaver, but we still have to link it together in the program so that it can translate the string from the listbox into a #define for the shader.
Next thing to do is open "ModeList.h". This is the header where we define names and values for functions. The format is like this:
#define <Function Handle Name> <Value>
where <Function Handle Name> is a valid variable name in C++ (i.e. no spaces or symbols) and <Value> is some integer that's unique to the given handle.
Since the name of the handle can't have symbols in it, we can't just use the same plaintext name we have in the listbox. Instead, I've been using a sort of shorthand that uses only letters to "spell out" the function (The name can be whatever you want, though I recommend you use some sort of shorthand to help keep the names straight!). In this case, I would pick the name "iterateLZpow2pCRpow2pD". Let's break this down so you can see how I'm naming it.
iterate refers to the fact that we're defining an iteration function. Next we have "L" which is a Left parenthesis '('. Next is Z which stands for 'z'. Then pow, which is short for Power, and represents the exponentiation operator '^'. Then we have the number 2, which represents 2 (note that numeric charecters are valid INSIDE the name, but NOT BEGINNING the name, hence x2 is fine but 2x is not.). Next we have 'p' which stands for Plus, or '+'. Then C which is 'c'. Then R for ')', pow for '^'. 2, and pD for '+d'. Hopefully you get the general idea. Anyway, the line we're going to add to the bottom of the file is:
#define iterateLZpow2pCRpow2pD 48
followed by a blank line since the compiler likes to complain if the last line of the file isn't a carriage return. We choose the number 48 since the previous line had 47.
Now we have to link these together in the code proper. Open "Config Dialogue.cpp"
Scroll down until you reach the System::String^ encodeFunctionIndex(int functionIndex) line. Here is where we put the function for converting from handle to string name. Add the 2 lines:
case iterateLZpow2pCRpow2pD:
return ("(z^2+c)^2+d");
on a new line inserted right before the comment //coloration functions. All the functions use the same function to convert their names, so I have them broken into sections by type. Thus we have the //iteration functions block, the //coloration functions block and the //palette functions block.
Now, scroll down some more until you get to int decodeFunctionName(System::String^ str). At the end of the //iteration functions block, just like before, add in the lines:
if (str == "(z^2+c)^2+d")
return iterateLZpow2pCRpow2pD;
This converts the string into the handle.
Next, open up ModeSelecter.cpp.
You'll see it's broken up into sections just like the other functions were. Add the lines:
else if (modeName == iterateLZpow2pCRpow2pD)
{
defineSlot[0].Name = "iterateLZpow2pCRpow2pD";
defineSlot[0].Definition = "";
viewCenterR = 0.0;
viewCenterI = 0.0;
viewRadius = 1.5;
}
at the end of the Iteration functions block. This provides the string name for the HLSL define, as well as parameters for the window size and variable ranges to use. Since we only entered parameters for the window and the function name, our c and d parameters will simply assume default ranges.
Now we finally get to the shader code itself. Open Iterate.fx.
Scroll down to right before the first #ifdef bailout***** line. The iteration code is broken into two sections - one section has the defines for the actual code for each iteration, and the second section has bailout functions. Since our function has typical bailout behavior, we can just use bailoutDefault. Thus let's add the skeleton for the function as follows:
#ifdef iterateLZpow2pCRpow2pD
#define bailoutDefault
#define ITERATE_FUNCTION\
#endif
Notice the backslash after ITERATE_FUNCTION. This is how you tell the preprocesser that the define goes on to the next line. Thus, we can write our iteration function over several lines instead of cramming it all into a single line.
The last thing to do is to add in the actual code. Note: The code must define the variables x, y, and r, where x is the real component of the next value of z, y is the imaginary, and r is the radius squared, or x*x+y*y. The current values of parameters are stored in cr, ci, dr, di, ect. where cr is the real part of c, ci is the imaginary part, dr is the real part of d, and so forth. Let's write the code now.
#ifdef iterateLZpow2pCRpow2pD
#define bailoutDefault
#define ITERATE_FUNCTION\
float2 z = float2(x,y);\
float2 c = float2(cr,ci);\
float2 d = float2(dr,di);\
z = cSqr(cSqr(z)+c)+d;\
x = z.x;\
y = z.y;\
r = x*x+y*y;
#endif
First, notice the float2. float2 is one of the base types provided by HLSL. It is basically a vector of two floats, where the operators +-*/ are defined component wise, that is, a*b = float2(a.x*b.x,a.y*b.y). Hence, we can use + and - straight as is, since they work the same as complex numbers would, but for anything else, we have to write our own functions... or use the functions provided in library.fx! The names of the functions in the library are things like cSin(z) or cTan(z) or cAcoth(z), where the c in the beginning designates the functions as working on complex numbers (and, more importantly, differentiates them from built in functions like Sin and Cos). The most important ones are cMul(z1,z2) and cDiv(z1,z2) where cMul returns z1*z2, and cDiv returns z1/z2. All functions in the library operate on inputs of type float2. In our case, we're only using cSqr(z) which returns z*z.
Finally, rebuild the project, and your new function should be good to go!