How to program a plasma demo
Learn how to do your own plasmas using Tweaked mode and mode 13H. Full sources in Watcom C/C++ 10+ included in this archive!
/----------------\
/-\--------/-/--ANuBiS DeMo TUtORS--/-/--------/-\
\----------------/
#Issue 1 : Plasmas
------------------
Writted by RaPhiuS / ANubIS aka Raphael Henrotte
---> henrraph@skynet.be <---
Source code provided in Watcom C/C++ 10+
/-\--------/-/--/----------------\--/-/--------/-\
Disclaimer
I cannot be responsible of any damage these codes could do. The only thing I can say you is that these codes are working perfectly on my computer. If you use them, use at your own risk !
Introduction
Hi it's RaphiuS over there teaching how to do demo effects !! Please do not pay attention to my English, I know it is bad...not my native language so please be indulgent. Sorry for the disclaimer but I want to be sure that nobody will say me that my codes destroyed their computer. Anyway, today we will discuss of plasmas, not static plasmas but realtime plasmas to open this series of Anubis tutors. I know, this effect was used a bit in many demos, like the demos I've made when I was in the Gyzmor Belgium demo group. But, it is always a nice effect and it's pretty easy to do. It's just a cosine function for the maths ;) I'll explain you the theory. I added sources for C language. Let's go !!
Theory
Today we'll discuss on realtime plasmas, not static who are simply palette rotation but plasmas using a cosine function to draw nice curves on screen. Realtime plasmas are a bit more tricky than static but they are better ! Elsewhere, they are not hard to do.
First, we will need routines to get into Tweaked mode. (I'm not going to explain you this mode but if you want more infos just look at a tutor about it). Why this mode ? coz having a screen of 80x50 is better than 320x200 ! Why ? Imagine you have a 320x200 screen : on this screen you have 320*200=64000 pixels. When doing plasmas you update each pixels at each frame. So, here the advantage of the Tweaked mode is that you have only 4000 pixels on screen (80*50=4000). Instead of updating 64000 pixels you update 4000 pixels. It's much faster ! (I added sources for Tweaked and 320*200 mode so you can see what you prefer, but remember that Tweaked is much faster than 320*200).
When we have these routines working we need to calculate cosine. What as hell does we need a cosine ? Simple, cosine do nice curves on screen that make plasmas more real (heh, realtime plasmas ;)). Personally I use this formula to set up my cosine table : 30*(cos(i*pi/64). My cosine table is usually 256 long so define it like this :
int cosinus[256];
Now, what you need to do is to set up your cosine table. It is much faster to precalculate your cosine table instead of using the damn cos each time who use a lot of tic's ! Do a loop (256 here) and calculate the cosine table with the formula I gave you above. This will give you something like this :
For loop = 0 to 256 do
cosinus[loop] = 30*(cos(loop*pi/64)
Now you got your cosine table ! The thing you need to do now is to set up a good palette but I'm not going to show you how. Hehe, you probably know so I'll not spend bytes on this subject in this tut :) If you don't know, then look at the sources attached with this tut and the things will be more clear ;)
Now that we have our cosine and our palette, what will we do with this cosine ? We want to draw nice curves no ? Yes so, to create our realtime plasma we just add 4 cosine and draw the result ! It is 2 cosine for vertical movement and 2 cosine for horizontal movement. What you do is this : you define p1, p2, p3 ,p4 as bytes and t1, t2, t3 and t4 as bytes too. It is important to define them as bytes, coz the result will be shown using the color parameters, it mean's that the value can NEVER go over 256 (It depends of the mode you are using of course). Why ? Coz the graphic mode used here have only 256 colors and more than that will probably crash the PC ! I hear you cry : Why 8 points, it is only 2 for vertical movement and 2 for horizontal movement ? Hummm, you need to save you original cosine values and it's why you define t1, t2, t3, t4. Now, it's time to make the main function.
So, for the main function it's easy. I said you that you need to save your original values and it is 2 values for vertical movement and 2 values for horizontal movement, right ? Ok, so let's take P1 and P2 for vertical movement and P3 and P4 for horizontal movement. It's logical that P1 and P2 will be saved before the Y loop coz there are vertical movement and vice versa for P3 and P4 but the only change you need to do is the loop and adapt it to X, coz horizontal movement of course ;) So, what you do is this : You save P1 in T1 and so on with P2,... It will be something like this:
P1=T1
P2=T2
...
But, I talked you about loop no ? Easy, after you saved the vertical movement values just do a loop of the length of your Y axis and do the same thing just after saving values for horizontal movement but adapt it to the X axis. It will look something like this :
P1=T1
P2=T2
For loop = 0 to Y-length do
P3=T3
P4=T4
For loop = 0 to X-length do
Now the cosine enter in action ! For every Putpixel function you pass a color right ? Normally the variable is called Col so instead of setting a simple value, make Col be equal to the addition of the four cosine. And you add each T1,... to each cosine. So it will be like this :
I'm sure that now you understand why the variable CAN'T be a Integer ;) When you've done this just show the result on the screen like a dumb Putpixel( X,Y,Col) ! Now you just change your T1,T2,T3 and T4 values. You must change T3 and T4 first coz you are in the X loop. Choose value you want :) When it's done close your X loop, change values for T1 and T2 and then close your Y loop. Then, change P1,P2,P3 and P4 values. Then close the main function and your plasma is working :))
Final Words
I hope this tutor will help you and that my English didn't afraid you to understand something. If you haven't understand something coz something is not logical or my English is too bad just Email me and I'll give you the infos you want : henrraph@skynet.be. I'm conscient that it is many tutors on the net and around the world but I wanted to share my vision of plasmas with you coders! It will be more tutors in the future, and don't forget to get them ! See ya next time !
Where to get Anubis Demo Tutors ?
Http://users.skynet.be/henrraph/
Http://www.geocities.com/SiliconValley/Heights/3094
Http://www.chez.com/raphius
Http://www.hornet.org in the incoming directory (search AnututX.Zip).
ANuBiS DeMo GrOuP
WWW : Http://users.skynet.be/henrraph/
Email : henrraph@skynet.be
Greetz : All Anubis members, Vulture/OUTLAW TRIAD, Jare/Vangelisteam's, Ryant, MR Boom, Voltaire/OTM, Phred/OTM, D3lsl, Lord Crc, Psyq, Kiwidog/Terraformer&Hornet, Denthor/Asphyxia, Piko, and all the guys I know and especially all the buddies on #coders ! ;)
-Writted by RapHIuS / ANubIS
28/8/97 at 8PM
PLASMAC.C
// Plasma Effect using Tweaked mode
// Code : RaPhIuS / ANUbis
// henrraph@skynet.be
// (!) 1997 WWW : Http://users.skynet.be/henrraph/
// Coded in Watcom C/C++ 10.6 (Use MAKEFILE.BAT to compile)
#include <stdio.h>
#include <math.h>
#define PI 3.141592654
int cosinus[256];
unsigned char p1,p2,p3,p4,t1,t2,t3,t4;
int x,y,col,v;
int pal[768];
unsigned char *videomem = 0xa0000;
//------------------------------------
// Video Routines
//------------------------------------
void setvga(void);
#pragma aux setvga=\
"mov ax,13h"\
"int 10h"\
modify[eax];
void settxt(void);
#pragma aux settxt=\
"mov ax,03h"\
"int 10h"\
modify[eax];
// Set unchained tweaked vga mode
void Tweak(void);
#pragma aux Tweak=\
"mov dx,3c4h"\
"mov ax,604h"\
"out dx,ax"\
"mov ax,0f02h"\
"out dx,ax"\
"mov dx,3d4h"\
"mov ax,14h"\
"out dx,ax"\
"mov ax,0e317h"\
"out dx,ax"\
"mov al,9"\
"out dx,al"\
"inc dx"\
"in al,dx"\
"and al,0e0h"\
"add al,7"\
"out dx,al"\
modify[dx ax];
void waitretrace(void);
#pragma aux waitretrace=\
"mov dx,3dah"\
"wvr1:"\
"in al,dx"\
"test al,8"\
"jnz wvr1"\
"wvr2:"\
"in al,dx"\
"test al,8"\
"jz wvr2"\
modify [dx al];
void setpal(int which[768])
{
int i;
outp(0x3c8,8);
for (i=0;i<768;i+=3)
{
outp(0x3c9,which[i]);
outp(0x3c9,which[i+1]);
outp(0x3c9,which[i+2]);
}
}
//---------------------------------
// Plasmas Stuff
//---------------------------------
void Do_Plasma(void)
{
v=0;
waitretrace();
t1=p1;
t2=p2;
for (y=0;y<50;y++)
{
t3=p3;
t4=p4;
for (x=0;x<80;x++)
{
col=cosinus[t1]+cosinus[t2]+cosinus[t3]+cosinus[t4];
videomem[v]=col;
v++;
t3+=1;
t4+=3;
}
t1+=2;
t2+=1;
}
p1+=1;
p2-=2;
p3+=3;
p4-=4;
}
void Prep_Pal(void)
{
int i;
for (x=0,y=0;x<63*3;x+=3,y++) pal[x]=y;
for (x=63*3,y=63;x<127*3;x+=3,y--) pal[x]=y;
for (x=127*3,y=0;x<191*3;x+=3,y++) pal[x+1]=y;
for (x=191*3,y=191;x<255*3;x+=3,y--) pal[x+1]=y;
}
void Pre_Calc(void)
{
int i;
for (i=0;i<256;i++)
cosinus[i]=30*(cos(i*PI/64));
}
//------------------------------------
// Main Stuff
//------------------------------------
void main()
{
setvga();
Tweak();
Pre_Calc();
Prep_Pal();
setpal(pal);
do {
Do_Plasma();
} while (!kbhit());
settxt();
}
PLASMAC2.C
// Plasma Effect using 320*200*256
// Code : RaPhIuS / ANUbis
// henrraph@skynet.be
// (!) 1997 WWW : Http://users.skynet.be/henrraph/
// Coded in Watcom C/C++ 10.6 (Use MAKEFILE.BAT to compile)
#include <stdio.h>
#include <math.h>
#define PI 3.141592654
int cosinus[256];
unsigned char p1,p2,p3,p4,t1,t2,t3,t4;
int x,y,col;
int pal[768];
//------------------------------------
// Video Routines
//------------------------------------
void setvga(void);
#pragma aux setvga=\
"mov ax,13h"\
"int 10h"\
modify[eax];
void settxt(void);
#pragma aux settxt=\
"mov ax,03h"\
"int 10h"\
modify[eax];
void putpixel(long x,long y,long col);
#pragma aux putpixel=\
"mov edi,0a0000h"\
"mov ecx,eax"\
"shl eax,8"\
"shl ecx,6"\
"add eax,ecx"\
"add eax,ebx"\
"mov byte ptr [edi+eax],dl"\
modify [edi ecx]\
parm [ebx] [eax] [edx];
void waitretrace(void);
#pragma aux waitretrace=\
"mov dx,3dah"\
"wvr1:"\
"in al,dx"\
"test al,8"\
"jnz wvr1"\
"wvr2:"\
"in al,dx"\
"test al,8"\
"jz wvr2"\
modify [dx al];
void setpal(int which[768])
{
int i;
outp(0x3c8,8);
for (i=0;i<768;i+=3)
{
outp(0x3c9,which[i]);
outp(0x3c9,which[i+1]);
outp(0x3c9,which[i+2]);
}
}
//---------------------------------
// Plasmas Stuff
//---------------------------------
void Do_Plasma(void)
{
waitretrace();
t1=p1;
t2=p2;
for (y=0;y<200;y++)
{
t3=p3;
t4=p4;
for (x=0;x<320;x++)
{
col=cosinus[t1]+cosinus[t2]+cosinus[t3]+cosinus[t4];
putpixel(x,y,col);
t3+=1;
t4+=3;
}
t1+=2;
t2+=1;
}
p1+=1;
p2-=2;
p3+=3;
p4-=4;
}
void Prep_Pal(void)
{
int i;
for (x=0,y=0;x<63*3;x+=3,y++) pal[x]=y;
for (x=63*3,y=63;x<127*3;x+=3,y--) pal[x]=y;
for (x=127*3,y=0;x<191*3;x+=3,y++) pal[x+1]=y;
for (x=191*3,y=191;x<255*3;x+=3,y--) pal[x+1]=y;
}
void Pre_Calc(void)
{
int i;
for (i=0;i<256;i++)
cosinus[i]=30*(cos(i*PI/64));
}
//------------------------------------
// Main Stuff
//------------------------------------
void main()
{
setvga();
Pre_Calc();
Prep_Pal();
setpal(pal);
do {
Do_Plasma();
} while (!kbhit());
settxt();
}