------------------------------------------------------------------------------
---------------------------************************---------------------------
---------------------------**CODE YOUR OWN PLASMA**---------------------------
---------------------------************************---------------------------
-----------------------------BY SPANSH / DYNAMIX------------------------------
Disclaimer
----------

I'm sorry I have to do this but here goes.  I accept no responsibility for any
damage done to your computer by either my programs or by your following my
instructions.   Any problems caused by this tutorial are entirely your
problem.  Do not come to me saying 'Your program deleted windows' or any other
line.  You use this tutorial at your own risk.  All programs have been tested
on my computer and other peoples computers and have worked okay without
problems.




Any examples in this tutorial are going to be in pascal.  I'm sorry if you
don't like this but I don't code in C yet, and Assembler is out of the
question for understanding the code.


In this tutorial I am going to show you how to code your own plasma.  Now you
may be saying to yourself at this point "Plasma what the heck is he going on
about".  Well read on if you do.  A plasma is a waving multicoloured pattern
on the screen.  It can be created in a number of ways

1. Sin/Cos plasma which is like moving circles on a screen.
2. Fractal plasma which is a static fractal picture with a *palette rotation*.
3. Any other picture with a *palette rotaion*.

** By palette rotation I mean changing the colours in the picture
ie replace all of the pixels coloured black with a blue colour.
A palette is a table of colours like so.

-----------------------------
|Colour | Red | Green | Blue|
|----------------------------
|  1    |  2  |   5   |  4  |
|  2    |  3  |   4   |  4  |
|  3    |  4  |   3   |  4  |
|  4    |  5  |   2   |  4  |
-----------------------------

This ia a small palette of 4 colours to rotate that palette you would move all
the colours down one and move the last colour to the top.
Then repeat that operation and your are rotating the palette.


Okay, the plasma I am going to explain here is the sin/cos plasma.
This is done by using a *sine wave*.


**A sine wave is calculated using the mathematical function sine.  The sine
function is mainly used in trigonometry with triangles.  


The Sine Wave
-------------

   y
  1| /-\         /-\
   |/   \       /   \
  0|-----|-----|-----|-----|->x
   |      \   /       \   /
 -1|       \-/         \-/
   |

   |     |     |     |     |
   0    180   360   540   720 (Okay so my ASCII art stinks)

In Maths Terms
--------------
 Y = Sin(X)

This is the graph that you would get if you plotted the number that you put
into your sine function as the x value and the sine of that number as the y
value.

We don't need to worry about all that maths bit.  All that we need to know is
that it makes a nice pretty wavy shape.  Now that wavy shape goes from -1 to
1 and back.  That will happen all the time (unless we got a problem).  Now in
order to get a sine wave that is a little less repetetive we need to add
together a few sine waves. (Here's where it gets a bit more complicated).  To
get a different sine wave you can instead of getting the sine  of the x value
we can multiply that number by 2 and the sine wave will be more squashed up.
Like so

The Sine Wave (Version 2)
-------------

   y
  1| /-\         /-\
   |/   \       /   \
  0|-----|-----|-----|-----|->x
   |      \   /       \   /
 -1|       \-/         \-/
   |

   |     |     |     |     |
   0    360   720   1080  1440

In Maths Terms
--------------
 Y = Sin(X*2)

Now That is the same graph but the x line is more squashed up.  It looks
a lot more understandable (I hope) in the example program (Sines.exe/pas).


You can also make a more spaced out sine wave by using Y = Sin(X/2) if
you follow the reasoning. I am going to stop using ASCII art and hope that
you will be able to figure out the maths yourself now.  If you can't then I
would get a piece of paper and plot the graphs for yourself to see.
Or alternatively look at the example program.

Now we can add these sine waves together. Say we take three sine waves.

Sin(X), Sin(X*2), Sin(X/2)

We Can add them together and make them into a graph by using.

Y = Sin(X) + Sin(X*2) + Sin(X/2)

Now we can multiply each of those sine waves by a number.

Y = 20 * Sin(X) + 50 * Sin(X*2) + 30 * Sin(X/2)

Now we can make this into a dynamic graph.  Okay okay I will explain a
Dynamic graph to you.  A dynamic graph is a graph of three variables.
like - 
Y = X + A
If We start with A as 0 then we plot
Y = X
Then we add 1 to a and plot
Y = X + 1.

So a dynamic graph is like a bit like a film.  Now to make the sine graph
into a nice dynamic graph then we do the following.
We first make a new variable such as A.
The we take our old equation

Y = 20 * Sin(X) + 50 * Sin(X*2) + 30 * Sin(X/2)

And much in the same way as we could make the sine wave more spaced out or
squashed up by changing X (by multiplying it or by sharing it by a number).
We can do the same to a by using
(A * 2), (A / 2), (A)

Then we take add these to our equation like so.

Y = 20 * Sin( (X)+(A * 2) ) + 50 * Sin( (X*2)+(A / 2) ) + 30 * Sin( (X/2) + A)

Wow our equation is getting rather big isn't it ?  This equation is exactly
how the last part of the example program is done.  First you plot the equation
with a equal to 0. Then you add a tiny amount to A and plot the equation again.
Now that is pretty in itself.

Now comes another hard part actually creating the plasma
--------------------------------------------------------

Say we have a square 100 by 100 pixels, okay.  Then we make two of our moving
sine waves.  Now instead of plotting the (X,Y) graph we take the coordinates
for each of our pixels in the square. say we have the first coordinate (0,0).

Now in the first sine wave equation we place the X-Coordinate of our square.
Then in our second sine wave equation we place the Y-Coordinate of our square.
The We add the two answers we get from our equations together, and we colour
the pixel at those the coordinates that we placed into our equations ((0,0)
in this example) with the value we obtained by adding the two answers together
.  And then when we have gone through the square and coloured every pixel.  We
ann a tiny amout to our dynamic variable (A is the one we were using) and start
again.  This will produce our plasma.  Okay so this sounds extremely hard.
Its not really.  Take a look at the sample program (Plasma.pas/exe)

Now comes another good bit Speeding the plasma up
-------------------------------------------------

Okay so yiou might not have been very impressed by that plasma program but
imagine it running at 30 frames per second in full screen and a nice palette.
Good eh.  Well Heres the good bit speeding the plasma up.


Well first of all calculating sines is a very slow way of doing things.  Now
maybe you know or maybe you don't but your basic sine wave repeats itself
after every 360 degrees.  So we could create an *array* of the values of each
sine.

**If you don't know what an array is then here is a quick description.  If a
variable is like a little hole that you can store data in like this.
     _
    |_|
 Variable A

Then an array would be like this
     _ _ _ _ _ _ _ _ _ _
    |_|_|_|_|_|_|_|_|_|_|
            Array A
An array is like a stack of variables.

Now if the array was called 'A' then we could access the second variable in
that array by (In Pascal anyway) using the identifier like this.

A[10] would give us the 10th variable in the array A.  The identifier can be
any ordinal type.
An ordinal type is a type that has no decimal places so in this case any of
the following would be valid ordinal types.

A to Z, Any number from 0 to Infinity (there are limits but never mind that).

You could not have any of the following

PI, 3.5746389 as these are both reals.


Anyway back to our sine array.  So I f we created an array called SinArray.
In pascal we would declare this in our var field like this :-

Var
    SinArray            : Array [0..360] Of Real;
    {The name of our array is SinArray, it is of type real and it has 360
    variables in it}

Now we have to create that array.  By create it I mean place the values of
sine into it.  This is very simple.  We just do this by using a for loop
(In Pascal)

For Counter := 0 to 360 Do
    Begin
        Angle := Rad(Coutner);
        SinArray[Counter] := Sin(Angle);
    End;
{Another advantage of this is that we can stop using those stupid radians
Yaaaaaay}

Okay but now we have a small problem that the angle we create might be over
360.  Wee cannot access that array after the 360th variable so what do we do?
But we know that the sine function repeats itself every 360 degrees so we just
divide by 360 and find the remainder.  In pascal we would use the mod
function.So to Access our array we would do the following.

XAnswer := 20 * SinArray[((X * 2  ) + (ToAdd      )) Mod 360]+
           30 * SinArray[((X      ) + (ToAdd * 2  )) Mod 360]+
           50 * SinArray[((X Div 2) + (ToAdd Div 2)) Mod 360] ;

{Since the identifier for the array has to be of ordinal type and we are now
using degrees we can made ToAdd an Integer and add 1 to it each frame.}
I have changed the /'s into divs because a / will give us a real value but the
div function will give us an ordinal value.}

Okay now we have our array.  For an example of this look at the example
program (PlasArra.Pas/exe)

Hey we now have a nice plasma.  It is quite fast but what it is only
100x100 squares.  Okay now we are going to have to make a bit of a leap in
knowlegde here.

Fixed Point Arithmetic
----------------------

Now here comes a hard part.

In this plasma all these truncs and rounds that we use are very slow.  We need
a faster way of doing this and fixed point is a way of using integers to
simulate real numbers.  I can hear you saying now what the hell is he going on
about.  A real number is a real number and an Integer is an integer they can't
be both can they ??   Well you're right of course they can't.  But I we did
our trunc before the array then we would lose a lot off accuracy in fact we
would only get about 4 colours.  Well yes but watch this hopefully nice
example.

We have our real number 3.12548 ok.
Now if we wanted to put that into fixed point we could
(I know I'm using 10's here but it is to make understanding much easier)
multiply it by 100000.
3.12548 * 100000 = 312548.

Well so what I hear you say.  Well if you notice that that has no decimal
point in it but it still contains all of the original numbers in exactly the
same order.  And it turns out that we can treat this exactly in the same way
as the original number (adding, subtracting, multiplying, dividing anyway)
so long as we divide our final number by 10000.  Now all we are doing is a mix
of those four functions.  So if we made our array fixed point then we could
lose all of those truncs in the plasma code. Yaaaay.  Now it also turns out
that you don't have to only multiply by powers of 10 we could multiply by any
number so long as we share by that number at the end.  Now we all know that
the computer works in binary right.  Well binary works in powers of 2 so we
can make the computer work very fast by using the following numbers.

2 ^ 1  = 2
2 ^ 2  = 4
2 ^ 3  = 8
2 ^ 4  = 16
2 ^ 5  = 32
2 ^ 6  = 64
2 ^ 7  = 128
2 ^ 8  = 256
2 ^ 9  = 512
2 ^ 10 = 1024

Now we can do a very fast multiply by a power of 2 by using the shifting.
In pascal we use SHR and SHL.  We could multiply by 4 by using

OurNumber Shl 2 = Answer.  so we SH(L or R) by the power to multiply by
2 to that power.  To divide by that you simply SHR instead of SHL.

So Instead of multiplying by 10000 we are going to use 1024 as this is a
power of 2.  To convert our final number back t owhat we want we simply use
SHR 10.  Ok. If not then try to look at the code in the example program
(PlasFix.pas/exe)

There is a downside in fixed point in that we do lose a bit of accuracy but
since we are going to need an integer anyway there won't be too much of a
difference.

Okay I still have a few tricks up my sleeve.

Now When we are using a putpixel we are having to calculate the position of
each pixel every time we place one.  Now we know exactly where we are going to
be putting each pixel it will be right after the last one.  Then when we get
to the end oa line it will start from the beginning again.  So instead of
using a putpixel we could just keep a counter variable that keeps track of
where we are in the plasma.  Look at the program to see what I mean.
(PlasFast.exe/pas)  This program includes these last two pointers.

Okay you know I said the computer works fastest with powers of two.  Well
The mod function is also a bit slow.  nd if we were getting the remainder of
a power of two then we could just use the And function.

We would use it like so

Number Mod 512 = Answer;
Number And 511 = SameAnswer;

So we and by 1 less than the power.  Don't ask me why I do know but this tut
is getting too long as it is.

Now I bet you are saying to me that this is of no use to us as 360 is not a
power of 2.  Ok I'll give you that.  but what if we could forget using degrees
and make our own measurement that went about 360 degrees in 512 units.  It's
actally not that hard.  All we have to do Is divide our Angle (In Radians) by
360 and multiply by 512.  We only have to do this once (when we calculate the
array)Take a look at the example program (Plasfast.pas/exe) if you don't
understand.

There is one more optimisation which I have found out and I don't think anyone
else has used it.  If I am wrong then correct me.  The way I do my Plasma's
is almost fully realtime ie  I add up the sine waves in the loop.  This
makes it much much more versatile, but this does mean that the calculation for
the x part of the loop is performed 64000 times a frame.  Now if you look at
it then you will notice that it is going to be the same values calculated for
every frame for each y value.  So if we create an array that is the size of
our screen width and before you start the main loop :

 For Y := 0 to 199 Do

Then you do a loop like this

For X := 0 to 319 Do
    XValues[X] := {Your sin Calculations}
Position := 0;
For Y :=  0 to 199 Do
    Begin
        YAnswer := {Your sin calculations}
        For X := 0 to 319 Do
            Begin
                XAnswer := XValues[X];
                Colour := (Xanswer + YAnswer) Shr 10;
                Mem[VGA:Position] := Colour;
                Inc(Position);
            End;
    End;
        
This loop will be much much faster that before.  



Well I think thats it from me.  Here are a few greets and I have also included
my plasma (in exe form plasmess.exe) It is coded in Pascal and Inline
assembler and is only 3kish.

Spansh Greets
=============                                            ____________________
Tig2      - Thanx for all your help                     |If you want some    |
            (Get his PMode tut now)                     |tutorials from me   |
Jungle    - Without you there would be no tut.          |then mail me, if I  |
Statix    - Thanx for putting up with me at Wired,      |get a few requests  |
            when is the next demo/intro out ?           |from people of what |
Optix     - Again Thanx for putting up with me at Wired,|they want then I    |
            When is Molejo out ?                        |will do a tutorial  |
AquaFresh - Thanx for getting me to Wired :)            |for what the most   |
Auruora   - You know who you are.                       |requested stuff is  |
Denthor   - For getting me into VGA coding.             |Ask for anything    |
RyanT     - For not adding me to X's user list :)       |Textured Tunnels,   |
Fatar     - For all your help                           |Shadebobs, Wormholes|
D_Talbane - Cool mov file man B-)                       |, Starfields (I got |
#coders   - you guys know who you are :)                |a cool one), Binary,|
                                                        |Optimising, Whatever|
                                                        |____________________|

MiKMaN Greetz
=============
<Put your greetz here mik>

/---------------------------+---------------------------\
|Dynamix Are :-             | Mail                      |
+---------------------------+---------------------------+
|Spansh  = Coder.           |Gareth.Harper@onyxnet.co.uk|
|MiKMaN  = GFX + 3d Objects.|PMGroom@Compuserve.com     |
+---------------------------+---------------------------+
|Mik I need some 3d objects now, anytime will do. :)    |
\---------------------------+---------------------------/

Oh yeah we need a musician if u wanna be in the group send us an example
of your music and we'll get back to ya.


