<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.winamp.com/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://wiki.winamp.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cope</id>
		<title>Winamp Developer Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.winamp.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cope"/>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Special:Contributions/Cope"/>
		<updated>2026-05-16T00:37:24Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.22.3</generator>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-19T01:00:01Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Functions for Complex Math */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;br /&gt;
== Complex Number to Complex Power ==&lt;br /&gt;
Ok, here's where things get a little hairy. Suppose you have an equation like '''F(Z) = Z^(2-Z) + C ''', now we're raising a complex number to a complex power. So lets step through it, like most math it's not so hard once you've done it a few times. I'm going to describe the procedure from beginning to end, to give you an idea of how to approach a problem like this.&lt;br /&gt;
&lt;br /&gt;
Before we start we define the regular fractal code:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
&lt;br /&gt;
First step is to compute the easiest bit, 2-Z. Since adding/subtracting a scalar works the same for a complex number as it does for a normal number, the operation is simply:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
We're going to skip all the theory behind how this next equation works, it's complicated and I don't fully understand it myself. But if you want an in depth look try [[http://home.att.net/~srschmitt/script_complex_power.html this page]]. The equation for finding a complex exponent of a complex number looks like this:&lt;br /&gt;
    x = a + bi&lt;br /&gt;
    y = c + di&lt;br /&gt;
    r = sqrt(x.x*x.x + x.y*x.y);&lt;br /&gt;
    θ = atan2(x.y, x.x);&lt;br /&gt;
    x&amp;lt;sup&amp;gt;y&amp;lt;/sup&amp;gt; = ( r&amp;lt;sup&amp;gt;c&amp;lt;/sup&amp;gt; * e&amp;lt;sup&amp;gt;(-d*θ)&amp;lt;/sup&amp;gt; ) * (cos(c*θ + d*log(r) + isin(c*θ + d*log(r))&lt;br /&gt;
First thing to note is that we only need to find modulus and theta for the base, not the exponent. Second thing, the + in front of the isin is ''not'' an addition, it's the signal that this is a complex number. The other +'s ''are'' additions. So lets see this equation in shader code for computing Z&amp;lt;sup&amp;gt;zp&amp;lt;/sup&amp;gt; + c:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    float mp = pow(moduz, zp.x)*exp(-zp.y*thetaz);&lt;br /&gt;
    uv1 = mp*float2(cos(zp.y*log(moduz) + zp.x*thetaz), sin(zp.y*log(moduz) + zp.x*thetaz))+c;    &lt;br /&gt;
So first thing we do is find the bit at the front of the equation, which evaluates to a float1 (a scalar). exp(x) is the built in function for the funny ''e'' and is the same as e&amp;lt;sup&amp;gt;x&amp;lt;/sup&amp;gt;. Then we simply plug the right values into the rest of the equation and multiply the whole float2 by mp, which is the first bit of the equation. Notice we're not using any values from uv1 directly, just the modulus and theta we calculated from it. If we get right down to it, this is actually a combination of the polar and Cartesian forms. The base (uv1) is in polar form while the exponent (zp) is in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
And that's that. The key with the more complicated fractal equations is to break them down into smaller pieces, so for example for the equation '''F(Z) = (Z^2 + C^2)^2Z ''' the process would go something like this:&lt;br /&gt;
* Calculate Z^2 (Cartesian form square), store it in a new float2&lt;br /&gt;
* Calculate C^2 (Cartesian form square), store it in C&lt;br /&gt;
* Calculate 2Z (just 2*Z), store it in a new float2&lt;br /&gt;
* Calculate Z^2+C^2 (just simple addition), store it in Z&lt;br /&gt;
* Calculate Z^2Z (complex power of a complex number), store it in Z&lt;br /&gt;
The most important thing here is that we're storing the results of the first and third calculations in a temporary variable. We can't store them to Z because we need Z unaltered for later equations.&lt;br /&gt;
== Functions for Complex Math ==&lt;br /&gt;
Stahlregen found a nice use for custom funtions that can make the shader code for complex math a lot easier to read. We're going to set up 4 custom functions that you can paste into any shader and use in the shader body. The functions will be cmul, cdiv, cpow and cexp. They'll do the same thing as their regular counterparts, except they'll work with complex numbers. Here's the code to define these functions, '''remember to put this before the shader_body statement''':&lt;br /&gt;
  float2 cmul(float2 mul1, float2 mul2) {&lt;br /&gt;
    float2 mul = float2(mul1.x*mul2.x - mul1.y*mul2.y, mul1.y*mul2.x + mul1.x*mul2.y);&lt;br /&gt;
    return mul;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cdiv(float2 div1, float2 div2) {&lt;br /&gt;
    float2 div = float2( (div1.x*div2.x + div1.y*div2.y)/(div2.x*div2.x + div2.y*div2.y),&lt;br /&gt;
    (div1.y*div2.x + div1.x*div2.y)/(div2.x*div2.x + div2.y*div2.y) );&lt;br /&gt;
    return div;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cpow(float2 base, float ex) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float2 pow = float2(pow(moduz, ex)*cos(thetaz*ex), pow(moduz, ex)*sin(thetaz*ex));&lt;br /&gt;
    return pow;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cexp(float2 base, float2 ex) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float mp = pow(moduz, ex.x)*exp(-ex.y*thetaz);&lt;br /&gt;
    float2 sol = mp*float2(cos(ex.y*log(moduz) + ex.x*thetaz), sin(ex.y*log(moduz) + ex.x*thetaz));&lt;br /&gt;
    return sol;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Notice all the moduz and thetaz calculations are done in these functions, which means we don't need to worry about writing them by hand anymore. All we need to do is pass the two complex variables involved to the function and it'll take care of the rest. Now the full shader_body code for the equation above, '''F(Z) = Z^(2-Z) + C ''', would look like this:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    &lt;br /&gt;
    uv1 = cexp(uv1, zp)+c; &lt;br /&gt;
Nice! As a bonus, custom functions don't count toward your instruction limit if you don't use them, so there's no &lt;br /&gt;
performance difference between using a custom function or writing the calculation out by hand each time.&lt;br /&gt;
&lt;br /&gt;
'''Important Note:''' cexp() is NOT the same as the function exp(). exp() raises the funny ''e'' to a power, cexp raises one complex number to another. So if you come across an equation that uses e^Z cexp() will not work for it. More on e^Z later.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-19T00:59:47Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Functions for Complex Math */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;br /&gt;
== Complex Number to Complex Power ==&lt;br /&gt;
Ok, here's where things get a little hairy. Suppose you have an equation like '''F(Z) = Z^(2-Z) + C ''', now we're raising a complex number to a complex power. So lets step through it, like most math it's not so hard once you've done it a few times. I'm going to describe the procedure from beginning to end, to give you an idea of how to approach a problem like this.&lt;br /&gt;
&lt;br /&gt;
Before we start we define the regular fractal code:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
&lt;br /&gt;
First step is to compute the easiest bit, 2-Z. Since adding/subtracting a scalar works the same for a complex number as it does for a normal number, the operation is simply:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
We're going to skip all the theory behind how this next equation works, it's complicated and I don't fully understand it myself. But if you want an in depth look try [[http://home.att.net/~srschmitt/script_complex_power.html this page]]. The equation for finding a complex exponent of a complex number looks like this:&lt;br /&gt;
    x = a + bi&lt;br /&gt;
    y = c + di&lt;br /&gt;
    r = sqrt(x.x*x.x + x.y*x.y);&lt;br /&gt;
    θ = atan2(x.y, x.x);&lt;br /&gt;
    x&amp;lt;sup&amp;gt;y&amp;lt;/sup&amp;gt; = ( r&amp;lt;sup&amp;gt;c&amp;lt;/sup&amp;gt; * e&amp;lt;sup&amp;gt;(-d*θ)&amp;lt;/sup&amp;gt; ) * (cos(c*θ + d*log(r) + isin(c*θ + d*log(r))&lt;br /&gt;
First thing to note is that we only need to find modulus and theta for the base, not the exponent. Second thing, the + in front of the isin is ''not'' an addition, it's the signal that this is a complex number. The other +'s ''are'' additions. So lets see this equation in shader code for computing Z&amp;lt;sup&amp;gt;zp&amp;lt;/sup&amp;gt; + c:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    float mp = pow(moduz, zp.x)*exp(-zp.y*thetaz);&lt;br /&gt;
    uv1 = mp*float2(cos(zp.y*log(moduz) + zp.x*thetaz), sin(zp.y*log(moduz) + zp.x*thetaz))+c;    &lt;br /&gt;
So first thing we do is find the bit at the front of the equation, which evaluates to a float1 (a scalar). exp(x) is the built in function for the funny ''e'' and is the same as e&amp;lt;sup&amp;gt;x&amp;lt;/sup&amp;gt;. Then we simply plug the right values into the rest of the equation and multiply the whole float2 by mp, which is the first bit of the equation. Notice we're not using any values from uv1 directly, just the modulus and theta we calculated from it. If we get right down to it, this is actually a combination of the polar and Cartesian forms. The base (uv1) is in polar form while the exponent (zp) is in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
And that's that. The key with the more complicated fractal equations is to break them down into smaller pieces, so for example for the equation '''F(Z) = (Z^2 + C^2)^2Z ''' the process would go something like this:&lt;br /&gt;
* Calculate Z^2 (Cartesian form square), store it in a new float2&lt;br /&gt;
* Calculate C^2 (Cartesian form square), store it in C&lt;br /&gt;
* Calculate 2Z (just 2*Z), store it in a new float2&lt;br /&gt;
* Calculate Z^2+C^2 (just simple addition), store it in Z&lt;br /&gt;
* Calculate Z^2Z (complex power of a complex number), store it in Z&lt;br /&gt;
The most important thing here is that we're storing the results of the first and third calculations in a temporary variable. We can't store them to Z because we need Z unaltered for later equations.&lt;br /&gt;
== Functions for Complex Math ==&lt;br /&gt;
Stahlregen found a nice use for custom funtions that can make the shader code for complex math a lot easier to read. We're going to set up 4 custom functions that you can paste into any shader and use in the shader body. The functions will be cmul, cdiv, cpow and cexp. They'll do the same thing as their regular counterparts, except they'll work with complex numbers. Here's the code to define these functions, '''remember to put this before the shader_body statement''':&lt;br /&gt;
  float2 cmul(float2 mul1, float2 mul2) {&lt;br /&gt;
    float2 mul = float2(mul1.x*mul2.x - mul1.y*mul2.y, mul1.y*mul2.x + mul1.x*mul2.y);&lt;br /&gt;
    return mul;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cdiv(float2 div1, float2 div2) {&lt;br /&gt;
    float2 div = float2( (div1.x*div2.x + div1.y*div2.y)/(div2.x*div2.x + div2.y*div2.y),&lt;br /&gt;
    (div1.y*div2.x + div1.x*div2.y)/(div2.x*div2.x + div2.y*div2.y) );&lt;br /&gt;
    return div;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cpow(float2 base, float ex) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float2 pow = float2(pow(moduz, ex)*cos(thetaz*ex), pow(moduz, ex)*sin(thetaz*ex));&lt;br /&gt;
    return pow;&lt;br /&gt;
  }&lt;br /&gt;
 float2 cexp(float2 base, float2 ex) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float mp = pow(moduz, ex.x)*exp(-ex.y*thetaz);&lt;br /&gt;
    float2 sol = mp*float2(cos(ex.y*log(moduz) + ex.x*thetaz), sin(ex.y*log(moduz) + ex.x*thetaz));&lt;br /&gt;
    return sol;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Notice all the moduz and thetaz calculations are done in these functions, which means we don't need to worry about writing them by hand anymore. All we need to do is pass the two complex variables involved to the function and it'll take care of the rest. Now the full shader_body code for the equation above, '''F(Z) = Z^(2-Z) + C ''', would look like this:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    &lt;br /&gt;
    uv1 = cexp(uv1, zp)+c; &lt;br /&gt;
Nice! As a bonus, custom functions don't count toward your instruction limit if you don't use them, so there's no &lt;br /&gt;
performance difference between using a custom function or writing the calculation out by hand each time.&lt;br /&gt;
&lt;br /&gt;
'''Important Note:''' cexp() is NOT the same as the function exp(). exp() raises the funny ''e'' to a power, cexp raises one complex number to another. So if you come across an equation that uses e^Z cexp() will not work for it. More on e^Z later.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-19T00:54:40Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Functions for Complex Math */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;br /&gt;
== Complex Number to Complex Power ==&lt;br /&gt;
Ok, here's where things get a little hairy. Suppose you have an equation like '''F(Z) = Z^(2-Z) + C ''', now we're raising a complex number to a complex power. So lets step through it, like most math it's not so hard once you've done it a few times. I'm going to describe the procedure from beginning to end, to give you an idea of how to approach a problem like this.&lt;br /&gt;
&lt;br /&gt;
Before we start we define the regular fractal code:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
&lt;br /&gt;
First step is to compute the easiest bit, 2-Z. Since adding/subtracting a scalar works the same for a complex number as it does for a normal number, the operation is simply:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
We're going to skip all the theory behind how this next equation works, it's complicated and I don't fully understand it myself. But if you want an in depth look try [[http://home.att.net/~srschmitt/script_complex_power.html this page]]. The equation for finding a complex exponent of a complex number looks like this:&lt;br /&gt;
    x = a + bi&lt;br /&gt;
    y = c + di&lt;br /&gt;
    r = sqrt(x.x*x.x + x.y*x.y);&lt;br /&gt;
    θ = atan2(x.y, x.x);&lt;br /&gt;
    x&amp;lt;sup&amp;gt;y&amp;lt;/sup&amp;gt; = ( r&amp;lt;sup&amp;gt;c&amp;lt;/sup&amp;gt; * e&amp;lt;sup&amp;gt;(-d*θ)&amp;lt;/sup&amp;gt; ) * (cos(c*θ + d*log(r) + isin(c*θ + d*log(r))&lt;br /&gt;
First thing to note is that we only need to find modulus and theta for the base, not the exponent. Second thing, the + in front of the isin is ''not'' an addition, it's the signal that this is a complex number. The other +'s ''are'' additions. So lets see this equation in shader code for computing Z&amp;lt;sup&amp;gt;zp&amp;lt;/sup&amp;gt; + c:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    float mp = pow(moduz, zp.x)*exp(-zp.y*thetaz);&lt;br /&gt;
    uv1 = mp*float2(cos(zp.y*log(moduz) + zp.x*thetaz), sin(zp.y*log(moduz) + zp.x*thetaz))+c;    &lt;br /&gt;
So first thing we do is find the bit at the front of the equation, which evaluates to a float1 (a scalar). exp(x) is the built in function for the funny ''e'' and is the same as e&amp;lt;sup&amp;gt;x&amp;lt;/sup&amp;gt;. Then we simply plug the right values into the rest of the equation and multiply the whole float2 by mp, which is the first bit of the equation. Notice we're not using any values from uv1 directly, just the modulus and theta we calculated from it. If we get right down to it, this is actually a combination of the polar and Cartesian forms. The base (uv1) is in polar form while the exponent (zp) is in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
And that's that. The key with the more complicated fractal equations is to break them down into smaller pieces, so for example for the equation '''F(Z) = (Z^2 + C^2)^2Z ''' the process would go something like this:&lt;br /&gt;
* Calculate Z^2 (Cartesian form square), store it in a new float2&lt;br /&gt;
* Calculate C^2 (Cartesian form square), store it in C&lt;br /&gt;
* Calculate 2Z (just 2*Z), store it in a new float2&lt;br /&gt;
* Calculate Z^2+C^2 (just simple addition), store it in Z&lt;br /&gt;
* Calculate Z^2Z (complex power of a complex number), store it in Z&lt;br /&gt;
The most important thing here is that we're storing the results of the first and third calculations in a temporary variable. We can't store them to Z because we need Z unaltered for later equations.&lt;br /&gt;
== Functions for Complex Math ==&lt;br /&gt;
Stahlregen found a nice use for custom funtions that can make the shader code for complex math a lot easier to read. We're going to set up 4 custom functions that you can paste into any shader and use in the shader body. The functions will be cmul, cdiv, cpow and cexp. They'll do the same thing as their regular counterparts, except they'll work with complex numbers. Here's the code to define these functions, '''remember to put this before the shader_body statement''':&lt;br /&gt;
  float2 cmul(float2 mul1, float2 mul2) {&lt;br /&gt;
    float2 mul = float2(mul1.x*mul2.x - mul1.y*mul2.y, mul1.y*mul2.x + mul1.x*mul2.y);&lt;br /&gt;
    return mul;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cdiv(float2 div1, float2 div2) {&lt;br /&gt;
    float2 div = float2( (div1.x*div2.x + div1.y*div2.y)/(div2.x*div2.x + div2.y*div2.y),&lt;br /&gt;
    (div1.y*div2.x + div1.x*div2.y)/(div2.x*div2.x + div2.y*div2.y) );&lt;br /&gt;
    return div;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cpow(float2 base, float exp) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float2 pow = float2(pow(moduz, exp)*cos(thetaz*exp), pow(moduz, exp)*sin(thetaz*exp));&lt;br /&gt;
    return pow;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cexp(float2 base, float2 exp) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float mp = pow(moduz, exp.x)*exp(-exp.y*thetaz);&lt;br /&gt;
    float2 exp = mp*float2(cos(exp.y*log(moduz) + exp.x*thetaz), sin(exp.y*log(moduz) + exp.x*thetaz));&lt;br /&gt;
    return exp;&lt;br /&gt;
  }&lt;br /&gt;
Notice all the moduz and thetaz calculations are done in these functions, which means we don't need to worry about writing them by hand anymore. All we need to do is pass the two complex variables involved to the function and it'll take care of the rest. Now the full shader_body code for the equation above, '''F(Z) = Z^(2-Z) + C ''', would look like this:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    &lt;br /&gt;
    uv1 = cexp(uv1, zp)+c; &lt;br /&gt;
Nice! As a bonus, custom functions don't count toward your instruction limit if you don't use them, so there's no &lt;br /&gt;
performance difference between using a custom function or writing the calculation out by hand each time.&lt;br /&gt;
&lt;br /&gt;
'''Important Note:''' cexp() is NOT the same as the function exp(). exp() raises the funny ''e'' to a power, cexp raises one complex number to another. So if you come across an equation that uses e^Z cexp() will not work for it. More on e^Z later.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-19T00:45:12Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;br /&gt;
== Complex Number to Complex Power ==&lt;br /&gt;
Ok, here's where things get a little hairy. Suppose you have an equation like '''F(Z) = Z^(2-Z) + C ''', now we're raising a complex number to a complex power. So lets step through it, like most math it's not so hard once you've done it a few times. I'm going to describe the procedure from beginning to end, to give you an idea of how to approach a problem like this.&lt;br /&gt;
&lt;br /&gt;
Before we start we define the regular fractal code:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
&lt;br /&gt;
First step is to compute the easiest bit, 2-Z. Since adding/subtracting a scalar works the same for a complex number as it does for a normal number, the operation is simply:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
We're going to skip all the theory behind how this next equation works, it's complicated and I don't fully understand it myself. But if you want an in depth look try [[http://home.att.net/~srschmitt/script_complex_power.html this page]]. The equation for finding a complex exponent of a complex number looks like this:&lt;br /&gt;
    x = a + bi&lt;br /&gt;
    y = c + di&lt;br /&gt;
    r = sqrt(x.x*x.x + x.y*x.y);&lt;br /&gt;
    θ = atan2(x.y, x.x);&lt;br /&gt;
    x&amp;lt;sup&amp;gt;y&amp;lt;/sup&amp;gt; = ( r&amp;lt;sup&amp;gt;c&amp;lt;/sup&amp;gt; * e&amp;lt;sup&amp;gt;(-d*θ)&amp;lt;/sup&amp;gt; ) * (cos(c*θ + d*log(r) + isin(c*θ + d*log(r))&lt;br /&gt;
First thing to note is that we only need to find modulus and theta for the base, not the exponent. Second thing, the + in front of the isin is ''not'' an addition, it's the signal that this is a complex number. The other +'s ''are'' additions. So lets see this equation in shader code for computing Z&amp;lt;sup&amp;gt;zp&amp;lt;/sup&amp;gt; + c:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    float mp = pow(moduz, zp.x)*exp(-zp.y*thetaz);&lt;br /&gt;
    uv1 = mp*float2(cos(zp.y*log(moduz) + zp.x*thetaz), sin(zp.y*log(moduz) + zp.x*thetaz))+c;    &lt;br /&gt;
So first thing we do is find the bit at the front of the equation, which evaluates to a float1 (a scalar). exp(x) is the built in function for the funny ''e'' and is the same as e&amp;lt;sup&amp;gt;x&amp;lt;/sup&amp;gt;. Then we simply plug the right values into the rest of the equation and multiply the whole float2 by mp, which is the first bit of the equation. Notice we're not using any values from uv1 directly, just the modulus and theta we calculated from it. If we get right down to it, this is actually a combination of the polar and Cartesian forms. The base (uv1) is in polar form while the exponent (zp) is in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
And that's that. The key with the more complicated fractal equations is to break them down into smaller pieces, so for example for the equation '''F(Z) = (Z^2 + C^2)^2Z ''' the process would go something like this:&lt;br /&gt;
* Calculate Z^2 (Cartesian form square), store it in a new float2&lt;br /&gt;
* Calculate C^2 (Cartesian form square), store it in C&lt;br /&gt;
* Calculate 2Z (just 2*Z), store it in a new float2&lt;br /&gt;
* Calculate Z^2+C^2 (just simple addition), store it in Z&lt;br /&gt;
* Calculate Z^2Z (complex power of a complex number), store it in Z&lt;br /&gt;
The most important thing here is that we're storing the results of the first and third calculations in a temporary variable. We can't store them to Z because we need Z unaltered for later equations.&lt;br /&gt;
== Functions for Complex Math ==&lt;br /&gt;
Stahlregen found a nice use for custom funtions that can make the shader code for complex math a lot easier to read. We're going to set up 4 custom functions that you can paste into any shader and use in the shader body. The functions will be cmul, cdiv, cpow and cexp. They'll do the same thing as their regular counterparts, except they'll work with complex numbers. Here's the code to define these functions, '''remember to put this before the shader_body statement''':&lt;br /&gt;
  float2 cmul(float2 mul1, float2 mul2) {&lt;br /&gt;
    float2 mul = float2(mul1.x*mul2.x - mul1.y*mul2.y, mul1.y*mul2.x + mul1.x*mul2.y);&lt;br /&gt;
    return mul;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cdiv(float2 div1, float2 div2) {&lt;br /&gt;
    float2 div = float2( (div1.x*div2.x + div1.y*div2.y)/(div2.x*div2.x + div2.y*div2.y),&lt;br /&gt;
    (div1.y*div2.x + div1.x*div2.y)/(div2.x*div2.x + div2.y*div2.y) );&lt;br /&gt;
    return div;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cpow(float2 base, float exp) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float2 pow = float2(pow(moduz, exp)*cos(thetaz*exp), pow(moduz, exp)*sin(thetaz*exp));&lt;br /&gt;
    return pow;&lt;br /&gt;
  }&lt;br /&gt;
  float2 cexp(float2 base, float2 exp) {&lt;br /&gt;
    float moduz = sqrt(base.x*base.x + base.y*base.y);&lt;br /&gt;
    float thetaz = atan2(base.y, base.x);&lt;br /&gt;
    float mp = pow(moduz, exp.x)*exp(-exp.y*thetaz);&lt;br /&gt;
    float2 exp = mp*float2(cos(exp.y*log(moduz) + exp.x*thetaz), sin(exp.y*log(moduz) + exp.x*thetaz));&lt;br /&gt;
    return exp;&lt;br /&gt;
  }&lt;br /&gt;
Notice all the moduz and thetaz calculations are done in these functions, which means we don't need to worry about writing them by hand anymore. All we need to do is pass the two complex variables involved to the function and it'll take care of the rest. Now the full shader_body code for the equation above, '''F(Z) = Z^(2-Z) + C ''', would look like this:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    &lt;br /&gt;
    uv1 = cexp(uv1, zp)+c; &lt;br /&gt;
Nice! As a bonus, custom functions don't count toward your instruction limit if you don't use them, so there's no &lt;br /&gt;
performance difference between using a custom function or writing the calculation out by hand each time.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-16T20:36:19Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Complex Number to Complex Power */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;br /&gt;
== Complex Number to Complex Power ==&lt;br /&gt;
Ok, here's where things get a little hairy. Suppose you have an equation like '''F(Z) = Z^(2-Z) + C ''', now we're raising a complex number to a complex power. So lets step through it, like most math it's not so hard once you've done it a few times. I'm going to describe the procedure from beginning to end, to give you an idea of how to approach a problem like this.&lt;br /&gt;
&lt;br /&gt;
Before we start we define the regular fractal code:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
&lt;br /&gt;
First step is to compute the easiest bit, 2-Z. Since adding/subtracting a scalar works the same for a complex number as it does for a normal number, the operation is simply:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
We're going to skip all the theory behind how this next equation works, it's complicated and I don't fully understand it myself. But if you want an in depth look try [[http://home.att.net/~srschmitt/script_complex_power.html this page]]. The equation for finding a complex exponent of a complex number looks like this:&lt;br /&gt;
    x = a + bi&lt;br /&gt;
    y = c + di&lt;br /&gt;
    r = sqrt(x.x*x.x + x.y*x.y);&lt;br /&gt;
    θ = atan2(x.y, x.x);&lt;br /&gt;
    x&amp;lt;sup&amp;gt;y&amp;lt;/sup&amp;gt; = ( r&amp;lt;sup&amp;gt;c&amp;lt;/sup&amp;gt; * e&amp;lt;sup&amp;gt;(-d*θ)&amp;lt;/sup&amp;gt; ) * (cos(c*θ + d*log(r) + isin(c*θ + d*log(r))&lt;br /&gt;
First thing to note is that we only need to find modulus and theta for the base, not the exponent. Second thing, the + in front of the isin is ''not'' an addition, it's the signal that this is a complex number. The other +'s ''are'' additions. So lets see this equation in shader code for computing Z&amp;lt;sup&amp;gt;zp&amp;lt;/sup&amp;gt; + c:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    float mp = pow(moduz, zp.x)*exp(-zp.y*thetaz);&lt;br /&gt;
    uv1 = mp*float2(cos(zp.y*log(moduz) + zp.x*thetaz), sin(zp.y*log(moduz) + zp.x*thetaz))+c;    &lt;br /&gt;
So first thing we do is find the bit at the front of the equation, which evaluates to a float1 (a scalar). exp(x) is the built in function for the funny ''e'' and is the same as e&amp;lt;sup&amp;gt;x&amp;lt;/sup&amp;gt;. Then we simply plug the right values into the rest of the equation and multiply the whole float2 by mp, which is the first bit of the equation. Notice we're not using any values from uv1 directly, just the modulus and theta we calculated from it. If we get right down to it, this is actually a combination of the polar and Cartesian forms. The base (uv1) is in polar form while the exponent (zp) is in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
And that's that. The key with the more complicated fractal equations is to break them down into smaller pieces, so for example for the equation '''F(Z) = (Z^2 + C^2)^2Z ''' the process would go something like this:&lt;br /&gt;
* Calculate Z^2 (Cartesian form square), store it in a new float2&lt;br /&gt;
* Calculate C^2 (Cartesian form square), store it in C&lt;br /&gt;
* Calculate 2Z (just 2*Z), store it in a new float2&lt;br /&gt;
* Calculate Z^2+C^2 (just simple addition), store it in Z&lt;br /&gt;
* Calculate Z^2Z (complex power of a complex number), store it in Z&lt;br /&gt;
The most important thing here is that we're storing the results of the first and third calculations in a temporary variable. We can't store them to Z because we need Z unaltered for later equations.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-16T20:34:58Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;br /&gt;
== Complex Number to Complex Power ==&lt;br /&gt;
Ok, here's where things get a little hairy. Suppose you have an equation like '''F(Z) = Z^(2-Z) + C ''', now we're raising a complex number to a complex power. So lets step through it, like most math it's not so hard once you've done it a few times. I'm going to describe the procedure from beginning to end, to give you an idea of how to approach a problem like this.&lt;br /&gt;
&lt;br /&gt;
Before we start we define the regular fractal code:&lt;br /&gt;
    float2 zoom = 1.5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
&lt;br /&gt;
First step is to compute the easiest bit, 2-Z. Since adding/subtracting a scalar works the same for a complex number as it does for a normal number, the operation is simply:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
We're going to skip all the theory behind how this next equation works, it's complicated and I don't fully understand it myself. But if you want an in depth look try [[http://home.att.net/~srschmitt/script_complex_power.html this page]]. The equation for finding a complex exponent of a complex number looks like this:&lt;br /&gt;
    x = a + bi&lt;br /&gt;
    y = c + di&lt;br /&gt;
    r = sqrt(x.x*x.x + x.y*x.y);&lt;br /&gt;
    θ = atan2(x.y, x.x);&lt;br /&gt;
    x&amp;lt;sup&amp;gt;y&amp;lt;/sup&amp;gt; = ( r&amp;lt;sup&amp;gt;c&amp;lt;/sup&amp;gt; * e&amp;lt;sup&amp;gt;(-d*θ)&amp;lt;/sup&amp;gt; ) * (cos(c*θ + d*log(r) + isin(c*θ + d*log(r))&lt;br /&gt;
First thing to note is that we only need to find modulus and theta for the base, not the exponent. Second thing, the + in front of the isin is ''not'' an addition, it's the signal that this is a complex number. The other +'s ''are'' additions. So lets see this equation in shader code for computing Z&amp;lt;sup&amp;gt;zp&amp;lt;/sup&amp;gt; + c:&lt;br /&gt;
    float2 zp = 2-uv1;&lt;br /&gt;
    float mp = pow(moduz, zp.x)*exp(-zp.y*thetaz);&lt;br /&gt;
    uv1 = mp*float2(cos(zp.y*log(moduz) + zp.x*thetaz), sin(zp.y*log(moduz) + zp.x*thetaz))+c;    &lt;br /&gt;
So first thing we do is find the bit at the front of the equation, which evaluates to a float1 (a scalar). exp(x) is the built in function for the funny ''e'' and is the same as e&amp;lt;sup&amp;gt;x&amp;lt;/sup&amp;gt;. Then we simply plug the right values into the rest of the equation and multiply the whole float2 by mp, which is the first bit of the equation. Notice we're not using any values from uv1 directly, just the modulus and theta we calculated from it. If we get right down to it, this is actually a combination of the polar and Cartesian forms. The base (uv1) is in polar form while the exponent (zp) is in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
And that's that. The key with the more complicated fractal equations is to break them down into smaller pieces, so for example for the equation '''F(Z) = (Z^2 + C^2)^2Z ''' the process would go something like this:&lt;br /&gt;
* Calculate Z^2 (polar form sin/cos), store it in a new float2&lt;br /&gt;
* Calculate C^2 (polar form sin/cos), store it in C&lt;br /&gt;
* Calculate 2Z (just 2*Z), store it in a new float2&lt;br /&gt;
* Calculate Z^2+C^2 (just simple addition), store it in Z&lt;br /&gt;
* Calculate Z^2Z (complex power of a complex number), store it in Z&lt;br /&gt;
The most important thing here is that we're storing the results of the first and third calculations in a temporary variable. We can't store them to Z because we need Z unaltered for later equations.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-14T14:48:17Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Polar Form */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
We can use polar form to multiply two complex numbers together too, as long as both are in polar form. To multiply them, we multiply the modulus of both numbers together and add the arguments (angles). So to multiply uv1*c we'd first have to calculate the modulus and theta values for c, which we'll call mod_c and theta_c, then we do this:&lt;br /&gt;
   uv1 = float2(modulus*mod_c*cos(theta + theta_c), modulus*mod_c*sin(theta + theta_c));&lt;br /&gt;
Note this method uses a LOT more instruction slots than the Cartesian form of multiplication, and it's really a waste. I've only included it here to show that any of the Cartesian operations can be done in polar form too. Normally we'd only use polar form to do exponents, because there's no simple way to do those in Cartesian form.&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-14T14:36:42Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Polar Form */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as (uv-0.5). That is,&lt;br /&gt;
   float2(uv.x-0.5, uv.y-0.5) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-14T14:30:17Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Introduction to Complex Numbers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number (actually complex numbers can have any number of dimensions, but we'll stick with 2 for now). It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y).&lt;br /&gt;
&lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as float2(uv.x, uv.y). That is,&lt;br /&gt;
   float2(uv.x, uv.y) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-14T00:42:18Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Polar Form */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number. It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y). &lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as float2(uv.x, uv.y). That is,&lt;br /&gt;
   float2(uv.x, uv.y) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code. '''Important Note:''' Any time you change the uv1 values you need to recalculate modulus and theta before you can use it again in another polar form equation. &lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-14T00:29:41Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number. It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y). &lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as float2(uv.x, uv.y). That is,&lt;br /&gt;
   float2(uv.x, uv.y) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code.&lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;br /&gt;
&lt;br /&gt;
Flexi also created a nice set of tutorial presets with some examples of fractals, rotations and other uses of complex numbers. Here's the link to the .zip file: [http://forums.winamp.com/attachment.php?s=&amp;amp;postid=2397425 Flexi's Complex Numbers Tutorial]&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-14T00:27:28Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number. It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y). &lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z. This is part of the reason why we set the origin to the center of the screen earlier with (uv-0.5). &lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
'''Important Note:''' This equation is ''exactly the same'' as float2(uv.x, uv.y). That is,&lt;br /&gt;
   float2(uv.x, uv.y) ==  float2(modulus * cos(theta), modulus * sin(theta))&lt;br /&gt;
as long as we've done the math for the modulus and theta right. This is very important, because it means once Milkdrop has evaluated this equation we can use uv1 in any of the Cartesian operational rules for complex numbers. In fact you can mix the two forms all you want, as long as they're done in different steps, and as long as you compute modulus and theta in the beginning of the shader code.&lt;br /&gt;
&lt;br /&gt;
So why bother with polar form? Well with this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;br /&gt;
Which gives the ''exact same values'' as&lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
&lt;br /&gt;
As a final example lets do the equation '''z' = (z^0.5)*c + c'''. Here's the full warp shader code for this equation:&lt;br /&gt;
&lt;br /&gt;
    float2 zoom = 5;&lt;br /&gt;
    float2 c = float2(q4, q5);&lt;br /&gt;
    float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
    float moduz = sqrt(uv1.x*uv1.x + uv1.y*uv1.y);&lt;br /&gt;
    float thetaz = atan2(uv1.y, uv1.x);&lt;br /&gt;
    &lt;br /&gt;
    uv1 = float2((pow(moduz, 0.5)*cos(thetaz*0.5)), (pow(moduz, 0.5)*sin(thetaz*0.5)));&lt;br /&gt;
    uv1 = float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y);&lt;br /&gt;
    uv1 += c;&lt;br /&gt;
This equation doesn't give us a fractal, it's just an example of mixing the two forms together. For (hundreds) more fractal equations take a [http://www.lifesmith.com/formulas.html look here]&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Complex_Numbers</id>
		<title>Complex Numbers</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Complex_Numbers"/>
				<updated>2009-01-13T20:54:17Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: New page: Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Originally I'd planned to just write a short guide to generating a fractal using complex numbers, but complex numbers are a huge field with many applications in computer graphics. For now I'll keep everything in this article, but at some point it'll probably be split into different articles. &lt;br /&gt;
&lt;br /&gt;
== Introduction to Complex Numbers ==&lt;br /&gt;
The best way to describe a complex number is to say that it's a 2 dimensional number. It has two components, a real value and an 'imaginary' value. It's not really important to know the differences between the two components, except to know that all our standard operations (like addition, multiplication...) might work a little differently when we're working with 2 dimensional numbers. &lt;br /&gt;
&lt;br /&gt;
A complex number can be represented in two ways, the first way is called the Cartesian form and looks like '''a + bi''', where a is the real part and b is the imaginary part (the i isn't really a variable, it's just there to say b is the imaginary component). This is very handy for us working with a 2D display like Milkdrop, because it means we can think of a point on the display, P=(x,y), as a complex number, x is the real part and y is the imaginary part. In this form point P becomes a two dimensional number, and we can use it in an equation as if it were a single number (as long as we remember that the operations work differently), like this:&lt;br /&gt;
   F(P) = P^2 + c&lt;br /&gt;
which is the equation for the Julia fractal. c is a second complex number, which for us is just another float2 with arbitrary values. We'll often assign some oscillating values to c in the form of q variables that we define in the per-frame code, with equations similar to 0.5*sin(time), because this will cause the fractal to change over time. We'll come back to the Julia fractal a bit later.&lt;br /&gt;
&lt;br /&gt;
So the important thing to remember is that for us a complex number is nothing more than a float2, with one variable of any equation we use being the current uv coordinates (uv.x,uv.y). &lt;br /&gt;
== Operations with Complex Numbers ==&lt;br /&gt;
I'll give an example of each operation and how it might look in Milkdrop. The main thing to note with all these rules is that the form a + bi doesn't mean a ''plus'' bi, the + in there is just there to signify that this is a two dimensional number. So when we map this to a float2 we simply ignore the + sign, a becomes x and b becomes y. &lt;br /&gt;
&lt;br /&gt;
For these examples we're going to use these two variables:&lt;br /&gt;
   float2 uv1 = float2(uv.x, uv.y);&lt;br /&gt;
   float2 c = float2(q1, q2);&lt;br /&gt;
Note uv1 is just our normal uv coordinates with a different name, and c is just two arbitrary values that we're importing from the per-frame code. All of the following operations will create a third float2 that would normally get assigned to a variable.&lt;br /&gt;
&lt;br /&gt;
'''Addition: (a + bi) + (c + di) = (a + c) + (b + d)i'''  &lt;br /&gt;
   uv1 + c =&amp;gt; float2(uv1.x + c.x, uv1.y + c.y)&lt;br /&gt;
'''Subtraction: (a + bi) - (c + di) = (a - c) + (b - d)i'''  &lt;br /&gt;
   uv1 - c =&amp;gt; float2(uv1.x - c.x, uv1.y - c.y)&lt;br /&gt;
So addition and subtraction is pretty straight forward, it works just like adding two float2's together because that's all we're doing!&lt;br /&gt;
&lt;br /&gt;
'''Multiplication: (a + bi) * (c + di) = (ac - bd) + (bc + ad)i'''  &lt;br /&gt;
   uv1 * c =&amp;gt; float2(uv1.x*c.x - uv1.y*c.y, uv1.y*c.x + uv1.x*c.y)&lt;br /&gt;
We'll see this one pop up quite a bit, because rotations on complex numbers are all done with multiplication. &lt;br /&gt;
&lt;br /&gt;
'''Division: (a + bi) / (c + di) = ( ac + bd / c^2 + d^2 ) + ( bc - ad / c^2 + d^2 )i'''&lt;br /&gt;
   uv1 / c =&amp;gt; float2( (uv1.x*c.x + uv1.y*c.y)/(c.x*c.x + c.y*c.y), (uv1.y*c.x + uv1.x*c.y)/(c.x*c.x + c.y*c.y) )&lt;br /&gt;
Division is a little messy, but on the upside we won't use it very often.&lt;br /&gt;
&lt;br /&gt;
Exponents are tricky with complex numbers in Cartesian form. To avoid a complete shit storm of math we're limited to integer components, and realistically we're limited to the exponents 2 or 3. We achieve this simply by treating it as a multiplication that gets repeated for each exponent, uv1^3 = uv1*uv1*uv1. Each time we multiply we need to use the multiplication rule from above and feed the answer into another iteration of the multiplication rule. This quickly gets out of control, and there's no easy way to calculate something like uv1^1.5. For that we'll need to express complex numbers in polar form, but before we get to that lets take a look at how the Julia fractal can be computed in Milkdrop.&lt;br /&gt;
== The Julia Fractal ==&lt;br /&gt;
The equation for the Julia fractal is '''z' = z^2 + c''', where z is our uv coordinates and c is some arbitrary numbers that control how the resulting fractal looks. Using the operator rules from above, it's pretty easy to work this out:&lt;br /&gt;
   float1 zoom = 1.6;&lt;br /&gt;
   float2 uv1 = (uv-0.5)*zoom;&lt;br /&gt;
   float2 c = float2(0.2, 0.45);&lt;br /&gt;
   &lt;br /&gt;
   uv1 = float2(uv1.x*uv1.x - uv1.y*uv1.y, 2*uv1.x*uv1.y)+c;&lt;br /&gt;
   ret = tex2D(sampler_fc_main, uv1) + 0.01;&lt;br /&gt;
First off, there's a few things we need to say about our 3 variables,&lt;br /&gt;
* '''zoom:''' It's hard to describe what this controls, but basically it decides how 'open' or 'closed' our fractal will look. Smaller values will zoom in and tend to 'open' the fractal up, while larger values will zoom out and tend to 'close' the fractal in on itself. It can be very picky and you'll probably need to experiment with each new fractal equation to find a value that works. 1.6 happens to work well for the Julia fractal.&lt;br /&gt;
* '''uv1:''' (uv-0.5) is basically making the origin (point (0,0)) at the center of the screen as opposed to the top left corner. After this the screen can be thought of as a standard graph with x and y axis, both of which run from -0.5..0.5, just like the standard graphs from trigonometry class. Multiplying this by zoom adjusts the size of the graph in the x and y dimensions, since here zoom is 1.6 our graph now runs from -0.8..0.8. This isn't really an important concept, it's just important to know that you always have to adjust uv in this way for a fractal to work.&lt;br /&gt;
* '''c:''' c is another picky parameter, and the range of 'acceptable' values will be different for every fractal equation. &lt;br /&gt;
&lt;br /&gt;
So what we're doing in the calculation is simple, just multiplying uv1 by itself to get z^2. The y parameter of the new float2 doesn't look like the multiplication rule above, but that's just because we've simplified it from (uv1.x*uv1.y + uv1.y*uv1.x) to (2*uv1.x*uv1.y). We can do that so long as we're multiplying a complex number by itself. Then at the end we just add c, as per the Julia equation.&lt;br /&gt;
&lt;br /&gt;
All the ret line is doing is sampling sampler_main and adding 0.01. This is just the standard way of displaying the fractal if we want to use sampler_main as the source, since it makes each iteration of the fractal equation a little brighter than the last, which gives the fractal its layered look.&lt;br /&gt;
&lt;br /&gt;
You can plug that simple bit of code into the warp shader and you'll get the Julia fractal. Like any fractal, we could loop the equation to be done more than once per pixel, which would give us a very different (often more complex looking) version of the same fractal. It's possible though that multiple iterations will throw off the c and zoom variables so that you'll need to tweak them to get the fractal to display nicely again.&lt;br /&gt;
== Polar Form ==&lt;br /&gt;
There are literally hundreds of fractal equations out there and not all of them are as easy to write as the Julia equation. For instance, say we wanted to try '''z' = z^1.5 + c''', how do we translate an exponent of 1.5 into our system of multiplying complex numbers by themselves? We can't, at least I don't know how. What we need is a different way of expressing complex numbers, and luckily one exists. It's called Polar Form, and while it looks complicated in the beginning it's actually quite a bit easier to work with. But there's a trade off, working with complex numbers in polar form usually means a ''lot'' more instruction slots, because we'll be working with sin/cos/atan functions. The 64 instruction slots in PS 2.0 just won't be enough, so polar form is pretty much limited to PS 2.X or above and will still take a toll on older video cards.&lt;br /&gt;
&lt;br /&gt;
Since this is meant as an introduction to complex numbers we're not going to bother figuring out ''why'' polar form works, just how. The basic idea is simple, we turn '''z = (a + bi)''' into '''z = r(cos(θ) + sin(θ)i)'''. In this form, '''r''' is called the ''modulus'' (or ''absolute'') form of z, which is calculated with the equation:&lt;br /&gt;
'''|z| = sqrt(x^2 + y^2)'''&lt;br /&gt;
Since for us '''z''' is just the uv coordinates, in shader code the equation looks like this:&lt;br /&gt;
   float1 modulus = sqrt(uv.x*uv.x + uv.y*uv.y);&lt;br /&gt;
You'll notice this is just the Pythagorean theorem of a right triangle. Our x and y values are the two right sides of the triangle, and the absolute form of z is just the hypotenuse of this triangle, which is the distance from the origin (the center of the screen) to the point z.&lt;br /&gt;
The '''θ''' (theta) is called the argument (or angle) of z. To find it we need to think of our complex number '''z''' as being on a graph:&lt;br /&gt;
&lt;br /&gt;
[[Image:graph.gif|A complex number &amp;quot;A&amp;quot; on a graph.]]&lt;br /&gt;
Trig 101 tells us that to find the angle θ we need to take the arc tangent of y/x, and the shader has a built in function for this which looks like:&lt;br /&gt;
   float1 theta = atan2(uv.y, uv.x);&lt;br /&gt;
Now we have all the variables we need to put our complex number into polar form:&lt;br /&gt;
   float2 uv1 = float2(modulus * cos(theta), modulus * sin(theta));&lt;br /&gt;
With this we can use something called De Moivre's Theorem to raise z to any power we want without using the multiplication rule. De Moivre's equation is almost the same as the normal polar form equation:&lt;br /&gt;
&lt;br /&gt;
[[Image:dem5.gif]]&lt;br /&gt;
To see it in action, lets do the equation we were having trouble with earlier, '''z' = z^1.5 + c''':&lt;br /&gt;
   uv1 = float2(pow(modulus, 1.5)*cos(theta*1.5), pow(modulus, 1.5)*sin(theta*1.5))+c;&lt;br /&gt;
And the Julia set equation would look like this:&lt;br /&gt;
   uv1 = float2(pow(modulus, 2)*cos(theta*2), pow(modulus, 2)*sin(theta*2))+c;&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Dem5.gif</id>
		<title>File:Dem5.gif</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Dem5.gif"/>
				<updated>2009-01-13T20:49:58Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: complex numbers&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;complex numbers&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Graph.gif</id>
		<title>File:Graph.gif</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Graph.gif"/>
				<updated>2009-01-13T20:39:22Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: complex numbers guide graph&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;complex numbers guide graph&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-10T12:44:03Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Important note about ATI cards */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, or 0 for any value smaller than 0, so (1.5,-0.4) becomes (1,0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,-0.4) becomes (0.5,0.6). Note when the values are greater than 1 wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. If the values are negative numbers then it's not the same, because for example -0.1 will be turned into 0.9, not 0.1. In practical terms, wrap mode will tile a texture when the uv coordinates go out of bounds.&lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively. Any x or y coordinate smaller than 0 (negative) will return the color value at the left edge or top edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
&lt;br /&gt;
One important note is that Milkdrop uses 8 bit values for the color channels, which is a fancy way of saying that there are 256 possible shades in each channel, giving a maximum precision of 0.004.&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;br /&gt;
== Important note about ATI cards ==&lt;br /&gt;
Due to some obscure bug in either Milkdrop's source or ATI's drivers, PS 3.0 in Milkdrop will not work on any ATI card. As a temporary fix to this problem PS 2.X support has been added to Milkdrop. There aren't many differences between the two version as far as we're concerned, so try to keep your presets limited to PS 2.0 or PS 2.X, which should give you more than enough [http://dev.winamp.com/wiki/Advanced_Pixel_Shader_Concepts#Instruction_Slots  instruction slots] to play with.&lt;br /&gt;
&lt;br /&gt;
A second bug affects the Xx00 and 9x00 line of Radeon cards, that has to do with the _fw_ and _pw_ sampling modes for textures (made worse by the fact that _fw_ is the default sampling mode). To have this display properly encase the uv coordinates in frac() like this;&lt;br /&gt;
   tex2D(sampler_main, frac(uv));&lt;br /&gt;
This bug seems to be fixed on the Radeon HD line of cards (both the 3xxx's and the 4xxx's).&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Fireeffect.jpg</id>
		<title>File:Fireeffect.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Fireeffect.jpg"/>
				<updated>2009-01-10T01:36:23Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: The finished fire effect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The finished fire effect&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Fire_dis4.jpg</id>
		<title>File:Fire dis4.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Fire_dis4.jpg"/>
				<updated>2009-01-10T00:22:09Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: Fire effect tutorial, displacement texture&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Fire effect tutorial, displacement texture&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Fire_base.jpg</id>
		<title>File:Fire base.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Fire_base.jpg"/>
				<updated>2009-01-10T00:21:39Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: Fire effect tutorial, base texture&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Fire effect tutorial, base texture&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-09T21:18:35Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Important note about ATI cards */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, or 0 for any value smaller than 0, so (1.5,-0.4) becomes (1,0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,-0.4) becomes (0.5,0.6). Note when the values are greater than 1 wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. If the values are negative numbers then it's not the same, because for example -0.1 will be turned into 0.9, not 0.1. In practical terms, wrap mode will tile a texture when the uv coordinates go out of bounds.&lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively. Any x or y coordinate smaller than 0 (negative) will return the color value at the left edge or top edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
&lt;br /&gt;
One important note is that Milkdrop uses 8 bit values for the color channels, which is a fancy way of saying that there are 256 possible shades in each channel, giving a maximum precision of 0.004.&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;br /&gt;
== Important note about ATI cards ==&lt;br /&gt;
Due to some obscure bug in either Milkdrop's source or ATI's drivers, PS 3.0 in Milkdrop will not work on any ATI card. As a temporary fix to this problem PS 2.X support has been added to Milkdrop. There aren't many differences between the two version as far as we're concerned, so try to keep your presets limited to PS 2.0 or PS 2.X, which should give you more than enough [http://dev.winamp.com/wiki/Advanced_Pixel_Shader_Concepts#Instruction_Slots  instruction slots] to play with.&lt;br /&gt;
&lt;br /&gt;
A second bug affects some older ATI cards, that has to do with the _fw_ and _pw_ sampling modes for textures (made worse by the fact that _fw_ is the default sampling mode). To have this display properly encase the uv coordinates in frac() like this;&lt;br /&gt;
   tex2D(sampler_main, frac(uv));&lt;br /&gt;
This bug seems to be fixed on newer ATI cards like the Radeon HD series.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-09T21:18:10Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, or 0 for any value smaller than 0, so (1.5,-0.4) becomes (1,0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,-0.4) becomes (0.5,0.6). Note when the values are greater than 1 wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. If the values are negative numbers then it's not the same, because for example -0.1 will be turned into 0.9, not 0.1. In practical terms, wrap mode will tile a texture when the uv coordinates go out of bounds.&lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively. Any x or y coordinate smaller than 0 (negative) will return the color value at the left edge or top edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
&lt;br /&gt;
One important note is that Milkdrop uses 8 bit values for the color channels, which is a fancy way of saying that there are 256 possible shades in each channel, giving a maximum precision of 0.004.&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;br /&gt;
== Important note about ATI cards ==&lt;br /&gt;
Due to some obscure bug in either Milkdrop's source or ATI's drivers, PS 3.0 in Milkdrop will not work on any ATI card. As a temporary fix to this problem PS 2.X support has been added to Milkdrop. There aren't many differences between the two version as far as we're concerned, so try to keep your presets limited to PS 2.0 or PS 2.X, which should give you more than enough [http://dev.winamp.com/wiki/Advanced_Pixel_Shader_Concepts#Instruction_Slots | instruction slots] to play with.&lt;br /&gt;
&lt;br /&gt;
A second bug affects some older ATI cards, that has to do with the _fw_ and _pw_ sampling modes for textures (made worse by the fact that _fw_ is the default sampling mode). To have this display properly encase the uv coordinates in frac() like this;&lt;br /&gt;
   tex2D(sampler_main, frac(uv));&lt;br /&gt;
This bug seems to be fixed on newer ATI cards like the Radeon HD series.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_shader_guide</id>
		<title>Pixel shader guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_shader_guide"/>
				<updated>2009-01-09T19:27:00Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Table of Contents'''&lt;br /&gt;
&lt;br /&gt;
== Pixel Shader Theory ==&lt;br /&gt;
* [[Pixel Shader Basics]] - textures, uv coordinates, color values&lt;br /&gt;
* [[Advanced Pixel Shader Concepts]] - instructions, compiling, shader versions, flow control, intrinsic functions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Shader Effects ==&lt;br /&gt;
* [[Painterly Effect]]&lt;br /&gt;
* [[Error Diffusion Dither]]&lt;br /&gt;
* [[Complex Numbers | Complex Numbers (fractals)]]&lt;br /&gt;
* [[Texture fire | Texture Based Fire Effect]]&lt;br /&gt;
&lt;br /&gt;
== Preset Dissection ==&lt;br /&gt;
This section focuses on dissecting the shader code in a handful of presets to give a line-by-line description of what it does.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_shader_guide</id>
		<title>Pixel shader guide</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_shader_guide"/>
				<updated>2009-01-09T14:49:31Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: New page: '''Table of Contents'''  == Pixel Shader Theory == * Pixel Shader Basics - textures, uv coordinates, color values * Advanced Pixel Shader Concepts - instructions, compiling, shader...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Table of Contents'''&lt;br /&gt;
&lt;br /&gt;
== Pixel Shader Theory ==&lt;br /&gt;
* [[Pixel Shader Basics]] - textures, uv coordinates, color values&lt;br /&gt;
* [[Advanced Pixel Shader Concepts]] - instructions, compiling, shader versions, flow control&lt;br /&gt;
* [[Intrinsic Functions]] - list of functions available, some of which aren't in the preset authoring guide&lt;br /&gt;
&lt;br /&gt;
== Shader Effects ==&lt;br /&gt;
* [[Painterly Effect]]&lt;br /&gt;
* [[Error Diffusion Dither]]&lt;br /&gt;
* [[Complex Numbers | Complex Numbers (fractals)]]&lt;br /&gt;
* [[Texture fire | Texture Based Fire Effect]]&lt;br /&gt;
&lt;br /&gt;
== Preset Dissection ==&lt;br /&gt;
This section focuses on dissecting the shader code in a handful of presets to give a line-by-line description of what it does.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T22:24:18Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Color Values */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, or 0 for any value smaller than 0, so (1.5,-0.4) becomes (1,0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,-0.4) becomes (0.5,0.6). Note when the values are greater than 1 wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. If the values are negative numbers then it's not the same, because for example -0.1 will be turned into 0.9, not 0.1. In practical terms, wrap mode will tile a texture when the uv coordinates go out of bounds.&lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively. Any x or y coordinate smaller than 0 (negative) will return the color value at the left edge or top edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
&lt;br /&gt;
One important note is that Milkdrop uses 8 bit values for the color channels, which is a fancy way of saying that there are 256 possible shades in each channel, giving a maximum precision of 0.004.&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T22:18:52Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Texture Wrap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, or 0 for any value smaller than 0, so (1.5,-0.4) becomes (1,0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,-0.4) becomes (0.5,0.6). Note when the values are greater than 1 wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. If the values are negative numbers then it's not the same, because for example -0.1 will be turned into 0.9, not 0.1. In practical terms, wrap mode will tile a texture when the uv coordinates go out of bounds.&lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively. Any x or y coordinate smaller than 0 (negative) will return the color value at the left edge or top edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T22:17:36Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Texture Wrap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, or 0 for any value smaller than 0, so (1.5,-0.4) becomes (1,0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,-0.4) becomes (0.5,0.6). Note when the values are greater than 1 wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. If the values are negative numbers then it's not the same, because for example -0.1 will be turned into 0.9, not 0.1. In practical terms, wrap mode will tile a texture when the uv coordinates go out of bounds.&lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T22:09:54Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: /* Texture Wrap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, so (1.5,1.5) becomes (1.0,1.0), and 0 for any coordinate smaller than 0. Wrap mode (fw and pw) will simply roll the coordinates back to 0 (or 1) when the values are over 1.0 (or under 0) and then add the remainder. (1.5,1.5) becomes (0.5,0.5). Note wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. &lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T21:35:27Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
It's important to understand that the two pixel shaders in Milkdrop, the warp shader and the composite shader, do very different things. We'll go over exactly how they're different later in the article, for now just keep in mind that they do not do the same thing.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this. Consider the Zoom effect in the Motion menu. To replicate this with pixel shaders we add the following instruction to the '''warp shader''':&lt;br /&gt;
   uv = 0.5 + (uv-0.5)*0.95;&lt;br /&gt;
This causes the scene to zoom ''in'' and does exactly the same thing as setting Zoom Amount to 1.05 in the Motion menu.&lt;br /&gt;
&lt;br /&gt;
=== Texture Wrap ===&lt;br /&gt;
Remember that uv coordinates are always values between 0..1, so what happens if we multiply (0.75,0.75) by 2 to get the coordinate (1.5,1.5)? The answer depends on which sampling mode you've chosen to use on your texture; wrap or clamp. Clamp mode (fc and pc) will use 1.0 for any coordinate value larger than 1, so (1.5,1.5) becomes (1.0,1.0). Wrap mode (fw and pw) will simply roll the coordinates back to 0 when the values are over 1.0 and then add the remainder. (1.5,1.5) becomes (0.5,0.5). Note wrap mode always returns just the fractional component, so writing this:&lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fc'''_main, frac(uv)); &lt;br /&gt;
will return exactly the same result as &lt;br /&gt;
   uv = (1.5,1.5);&lt;br /&gt;
   tex2D(sampler_'''fw'''_main, uv);&lt;br /&gt;
because by encasing uv inside frac() we ensure the coordinate values will never be &amp;gt;= 1.0. &lt;br /&gt;
&lt;br /&gt;
In clamp mode any x or y coordinate value larger than 1.0 will cause tex2D() to return the color value at the right edge or bottom edge of the screen respectively.&lt;br /&gt;
&lt;br /&gt;
== Color Values ==&lt;br /&gt;
All of the work done inside a pixel shader is done to find a single set of values; the rgb color values of the current pixel. This is what you assign to ''ret'' at the end of your shader code, and this is what Milkdrop draws onto the screen for that pixel. All the fancy mathematics we see in shader code is done to manipulate color values in one form or another, because that's all a pixel shader can do.&lt;br /&gt;
&lt;br /&gt;
=== RGB basics ===&lt;br /&gt;
In Milkdrop shaders color values are always stored as a float3 that represents the amount of red, green and blue color at a particular point. In the body of your shader code these values can be any number at all, but the final values that are assigned to ret at the end of your shader must be between 0..1 or they will be clamped to either 0 or 1. A negative value will be 0, a value greater than 1 will be 1. Here are a few other notes about color values, working with ''ret'':&lt;br /&gt;
* '''1-ret''' returns the inverse of the color, assuming it is clamped to the 0..1 range&lt;br /&gt;
* '''saturate(ret)''' clamps the color to the 0..1 range&lt;br /&gt;
* '''ret.zyx''' causes the red and blue channels to trade places&lt;br /&gt;
* '''ret.x''' gives a float1 with the value of the red channel&lt;br /&gt;
* '''lum(ret)''' basically returns the greyscale version of the color&lt;br /&gt;
=== Color in Comp shader vs Warp shader ===&lt;br /&gt;
Just as with uv transformations, color manipulation works differently in the warp shader than it does in the composite shader. Adding the following instruction,&lt;br /&gt;
   ret += 0.01;&lt;br /&gt;
to the warp shader will quickly white out the entire scene, while adding the same line to the composite shader will make hardly any difference. Again, this is because the effects in the warp shader are compounded with each successive frame, it will keep adding 0.01 to the pixel's color with each new frame until all 3 channels reach 1.0 and get clamped there. This is why any color correction (like giving the entire scene a green tint) should be done in the composite shader.&lt;br /&gt;
=== Basic color examples ===&lt;br /&gt;
To give give the entire preset a green tint we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= float3(0.5, 1.0, 0.5);&lt;br /&gt;
Which would cut the red and blue color values in half, allowing more of the green to show through. &lt;br /&gt;
&lt;br /&gt;
To make the entire scene brighter we could add this instruction to the composite shader:&lt;br /&gt;
   ret *= 3;&lt;br /&gt;
Which simply multiplies each channel by 3, making them brighter. Keep in mind final output will still be clamped to 1.0, you can't get any brighter than pure white!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For a more advanced use of color, why don't we combine it with uv translation? Consider the following instructions in the '''warp shader''':&lt;br /&gt;
   float3 temp = tex2D(sampler_main, uv);&lt;br /&gt;
   float2 myuv = float2( uv.x + 0.05*temp.x, uv.y);&lt;br /&gt;
   ret = tex2D(sampler_main, myuv);&lt;br /&gt;
Here we first sample the colors of the current pixel from sampler_main and assign them to temp. In the next line we create a new coordinate value that multiplies 0.05 by the value of temp's red channel and adds it to uv.x, while keeping uv.y the same. Where temp's red channel is 1.0 we're adding 0.05 to uv.x, where the red channel is 0.5 we're only adding 0.025 to x, and where the red channel is 0 we're keeping uv.x the same. The effect of this is a translation based on how much red is in the current pixel. A lot of neat effects can be done with this, including the [[painterly]] effect.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T19:45:45Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action in the '''Composite Shader''':&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale205.png | 0.25 + uv*0.5&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
Notice in the third image we've moved the sampling area to the center of the texture. It's easy to see why this works, all we've done is add 0.25 to the coordinates so that the box now extends from (0.25,0.25) to (0.75,0.75). &lt;br /&gt;
&lt;br /&gt;
==== Comp shader vs Warp shader ====&lt;br /&gt;
It's important to note that the effects of these transformations are very different in the two Milkdrop shaders. Remember, the composite shader treats sampler_main as a static texture and returns a modified ''copy'' of it that Milkdrop displays. Think of it as a camera, when we apply a translation to the uv coordinates we are moving the camera. When we scale the coordinates we are zooming the camera in or out. At the end the camera takes a picture of what it sees and returns that picture.&lt;br /&gt;
&lt;br /&gt;
In the warp shader, on the other hand, we're really ''changing the scene'' when we transform the uv coordinates. And this transformation gets compounded in each successive frame. A lot of cool effects like fractals and error diffusion dither take advantage of this.&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Mdscale205.png</id>
		<title>File:Mdscale205.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Mdscale205.png"/>
				<updated>2009-01-08T18:53:38Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: Milkdrop scale example 205&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Milkdrop scale example 205&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T18:53:20Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action:&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
Image:Mdscale1.png | uv*1&lt;br /&gt;
Image:Mdscale05.png | uv*0.5&lt;br /&gt;
Image:Mdscale2.png | uv*2&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Mdscale05.png</id>
		<title>File:Mdscale05.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Mdscale05.png"/>
				<updated>2009-01-08T18:49:01Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: Milkdrop scale example 3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Milkdrop scale example 3&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Mdscale2.png</id>
		<title>File:Mdscale2.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Mdscale2.png"/>
				<updated>2009-01-08T18:48:41Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: Milkdrop scale example 2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Milkdrop scale example 2&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/File:Mdscale1.png</id>
		<title>File:Mdscale1.png</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/File:Mdscale1.png"/>
				<updated>2009-01-08T18:48:19Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: Milkdrop scale example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Milkdrop scale example&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	<entry>
		<id>http://wiki.winamp.com/wiki/Pixel_Shader_Basics</id>
		<title>Pixel Shader Basics</title>
		<link rel="alternate" type="text/html" href="http://wiki.winamp.com/wiki/Pixel_Shader_Basics"/>
				<updated>2009-01-08T18:47:32Z</updated>
		
		<summary type="html">&lt;p&gt;Cope: New page: == Introduction == This article assumes you've read through the wonderful  Preset Authoring Guide and will attempt to build on the information there. By the ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This article assumes you've read through the wonderful [[MilkDrop_Preset_Authoring | Preset Authoring Guide]] and will attempt to build on the information there. By the end you should have a solid understanding of how pixel shaders work in Milkdrop.&lt;br /&gt;
== Overview of Pixel Shaders ==&lt;br /&gt;
Simply put, a pixel shader is a tool that applies a set of instructions to every pixel in a display window. In almost every modern video game pixel shaders are used to create realistic lighting and shading effects in 3D scenes. A pixel Shader takes in information about models, textures, light sources and materials, applies a set of instructions to this data and returns a single float4 value, which holds the current pixel's red, blue, green and alpha channel values. &lt;br /&gt;
&lt;br /&gt;
Pixel shaders in Milkdrop are a bit simpler, because we're limited to working in 2 dimensions without things like models or light sources. In addition, the final return value of our pixel shaders is a float3, leaving out the alpha channel. But the principle is still the same; when we write the code for a pixel shader we are giving it a set of instructions to perform on every pixel in the display window, which it uses to find the final color value for that pixel, which is assigned to ''ret''.&lt;br /&gt;
&lt;br /&gt;
== Textures ==&lt;br /&gt;
In the Milkdrop pixel shaders a texture is simply a sampling source. They can be sampled using the tex2D() function, or the tex3D function if you're sampling from a 3D noise volume. There are 3 types of textures we can access in Milkdrop; sampler_main, [[MilkDrop_Preset_Authoring#NOISE_TEXTURES | noise textures]] and [[MilkDrop_Preset_Authoring#READING_TEXTURES_FROM_DISK | custom textures]]. The latter two are covered very well in the preset authoring guide, so we'll just take a moment to say a few things about sampler_main.&lt;br /&gt;
=== sampler_main ===&lt;br /&gt;
We can think of this texture as a screenshot of the display window. This snapshot is taken by Milkdrop just before it executes the Warp Shader, and is passed to the Warp Shader as sampler_main. Using sampler_main we can get the color value of the current pixel either by calling tex2D(sampler_main, uv), or by calling GetPixel(uv). &lt;br /&gt;
&lt;br /&gt;
There is one important difference between the Warp Shader and the Composite Shader when it comes to sampler_main; Milkdrop takes a ''new'' snapshot of the scene after the Warp Shader has finished executing, and passes this new snapshot to the Composite Shader. What this means is that the Warp Shader actively ''alters'' the scene, while the Composite Shader only returns a ''copy'' of the scene to display. In other words, anything the Composite Shader does, does not affect the rest of Milkdrop because it only alters a copy of the scene, instead of the scene itself. The Warp Shader alters the scene itself, and anything it does ''will'' affect the rest of Milkdrop.&lt;br /&gt;
&lt;br /&gt;
== UV Coordinates ==&lt;br /&gt;
A pixel shader needs some way of knowing which pixel it's currently working on, and which pixel you want to sample in a texture. In Milkdrop these concepts are represented by ''uv'', which is a float2 with x and y values between 0..1. The top left corner of the scene has the coordinates (0.0,0.0), while the bottom right corner is (1.0,1.0). How Milkdrop generates these values between 0..1 is not so important, what's important is that it stores the dimensions of the display window ''and'' the size of a single pixel in the float4 variable '''texsize.xyzw'''. Lets suppose we have a display window of size 600x400, in this case texsize will hold the following values:&lt;br /&gt;
* texsize.x = 600&lt;br /&gt;
* texsize.y = 400&lt;br /&gt;
* texsize.z = 1/600 = 0.0017&lt;br /&gt;
* texsize.w = 1/400 = 0.0025&lt;br /&gt;
A pixel shader always moves from left to right, starting in the upper left corner with pixel (0,0). Next it will increment to (move to) the next pixel, and because the size of a single pixel along the x axis for our supposed window is 0.0017 the current uv value is changed from (0,0) to (0.0017,0). For our window, the pixel shader does this 600 times, each time adding 0.0017 to the uv.x value and keeping uv.y the same. After 600 increments it's reached the right side of the screen, (1,0), so it moves back to the left side and starts with the next line of pixels, the uv value is now (0,0.0025). This process gets repeated for the entire display window, in our hypothetical case a total of 240,000 times. &lt;br /&gt;
&lt;br /&gt;
This also means the shader code you write will be executed 240,000 times for that frame, for a window size of 1680x1050 that number increases to 1.7 million times, per frame! At 60 fps this means your graphics card is executing your instructions 106 million times per second, per shader! Something to think about the next time one of the more intense presets brings your machine to its knees.&lt;br /&gt;
&lt;br /&gt;
Getting back to our example, remember that sampler_main contains a copy of the scene in the form of a texture. We know enough now to read the following instruction:&lt;br /&gt;
   ret = tex2D(sampler_main, uv);&lt;br /&gt;
as &amp;quot;Set ret to the rgb values from the sampler_main texture at the coordinates of the current pixel&amp;quot;. &lt;br /&gt;
=== Modifying the uv coordinates ===&lt;br /&gt;
Some very interesting effects can be achieved by modifying the uv coordinates before you sample a texture. The theory behind this is very straight forward because there are really only two things we can do, translate and scale. &lt;br /&gt;
&lt;br /&gt;
==== Translation ====&lt;br /&gt;
Lets say we want to create a movement effect similar to dx (aka Translation (X) in the Motion menu) that moves the entire scene one pixel to the left each frame. In mathematical terms this is called a Translation, and you achieve it by modifying the uv values like so:&lt;br /&gt;
   ret = tex2D(sampler_main, float2(uv.x + texsize.z, uv.y));&lt;br /&gt;
which reads as &amp;quot;Set ret to the rgb values from the sampler_main texture at one pixel to the right of the current pixel&amp;quot;. When we do this for every pixel we've in effect moved the entire scene one pixel to the left. Conversely, subtracting texsize.z from uv.x would move the scene one pixel to the right. To move the scene 2 pixels to the left we just multiply texsize.z by 2. &lt;br /&gt;
&lt;br /&gt;
==== Scaling ====&lt;br /&gt;
In the same way that translation is achieved by addition and subtraction, scaling is achieved by multiplying and dividing. An important note though, by dividing we really mean to multiply by a decimal fraction, uv*0.5 instead of uv/2 for example. This is because a computer can perform multiplication much faster than division, so we multiply whenever we can. &lt;br /&gt;
&lt;br /&gt;
When we scale uv what we're really doing is increasing or decreasing the sampling area. For example, the instruction uv*0.5 will cut the available sampling area in half, and the sampling box now goes from (0,0) to (0.5,0.5). Notice this also means that the pixel ratio between the display window and the sampling area is no longer 1:1, one pixel from the sampling area gets scaled up to be ''4 pixels'' in the display window. The effect of this is that the sampling area is blown up to fit the display window, and you lose some resolution in the process. The entire process is less confusing if we see it in action:&lt;br /&gt;
&amp;lt;gallery caption= widths=&amp;quot;250px&amp;quot; heights=&amp;quot;196px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;/div&gt;</summary>
		<author><name>Cope</name></author>	</entry>

	</feed>