Copy Link
Add to Bookmark
Report

How to create plasma effects

This is the first demo programming tutorial in the X3M Demo Programming Series, and covers how to create plasma effects. Not that static plasma, but realtime plasma effects that makes you sea sick!

DrWatson's profile picture
Published in 
atari
 · 26 Nov 2023

 ÛÛÛÛ       ÛÛÛÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß 
ßÛÛÛÜ ÜÛÛÛß -= Demo Programming Series =-
ßÛÛÛÜ ÜÛÛÛß by Sten Roger Sandvik
ßÛÛÛÛÛß
ÜÛÛÛßÛÛÛÜ I - HOW TO CREATE PLASMA EFFECTS
ÜÛÛÛß ßÛÛÛÜ
ÛÛÛÛ ÛÛÛÛ (c) 1994 by X3M Productions
ÛÛÛÛ ÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ

Hey all out there, and welcome to part one of the X3M demo programming series. In this and all of the following demo programming series, I'll take it for granted that you know how to program the VGA controller, and some knowledge about X-mode.

This time we'll discuss a psychedelic effect that is used in many demos. Yepp! You got it... Plasmas! Oki, no sense in wasting time here talking about bullshit... let's go to work!

 The Workings of Plasmas

In this text I will only cover the real type of plasma. No sills here, only state-of-the-art realtime plasma calculations!

When you look at the method realtime plasmas is created, you'll see that it's merely an intersection of a number of cosinus waves. In this example we'll use 4 cosinus waves, which makes a very cool effect. The color of a particular point is calculated using this formula:

color = costbl[cos_1]+costbl[cos_2]+costbl[cos_3]+costbl[cos_4]

The trick is getting the four indexes of that cosinus table to create something that looks neat. We use two of the indexes for vertical movement, and the remaining two for horizontal movement.

This means that by changing these value we can move along the plasma. To draw an individual screen, we pass the values of the four to another four so that we do not disturb the original values. For every pixel on the x-axis, we add values to the first two indexes, then displaying the next pixel. For every row down, we add values to the second two indexes.

By altering the original four values, we can get all sorts of neat movement and cycling of the plasma. The reason we use a cosinus function is as follows:

  • Nice curvature.
  • Adding two or more together it's possible to get circular pictures.

 Fading

When you look at the sample demo, you'll see that when it fades in and out the colors all reach their destination at the same time. This is very clever, if I may say so ? Well, in other words, they do not all increment by one until they hit the right color. If you should do it this way the fading looks extremely unprofessional.

 How to do a step-crossfade

Each red, green and blue values can be between 0 and 63. Have the palette we want to get to in TOPAL and the temporary palette in TEMPPAL. For each step, from 0 to 63 do the following:

TEMPPAL[loop].red   = TOPAL[loop].red   * step / 64; 
TEMPPAL[loop].green = TOPAL[loop].green * step / 64;
TEMPPAL[loop].blue = TOPAL[loop].blue * step / 64;

That means if we are halfway through the crossfade (step=32) and the red value is meant to get to 16, then naturally the color would be value would be 8, which is half the way. This means all colors will fade in/out with the same ratios.

 Palette rotating

The palette rotating is very simple, so here is a brief description on how to do it.

  • Move color 0 into a temporary variable.
  • Move color 1 into color 0
  • Move color 2 into color 1
  • .
  • .
  • Move color 255 into color 254
  • Move temporary color into color 255

 About the sample demo

The plasma sample demo code is written in pascal, and is (I think) self explanitory. I have also done an assembly version that you can look at, but the pascal code illustrates the plasma principle very clearly.

Well if you have any questions about anything (Uhh... well about programming), just leave me a note. Be seein' YA!

E-mail -> srs@alkymi.unit.no


 ZIP file contents:

  • PLASMA.TXT - The file you are looking at NOW!
  • PLASMA.PAS - Pascal version of the sample code
  • PLASMA.EXE - Executable version of the pascal version (Huh ?)
  • COSTBL.INC - Cosinus table file for the assembler version
  • PLASMEFF.ASM - Assembler version of the sample code (FAST!)
  • PLASMEFF.EXE - Executable version of the assembler version!

How to create plasma effects
Pin it

PLASMA.PAS

{ 
ÛÛÛÛ ÛÛÛÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
ßÛÛÛÜ ÜÛÛÛß Project: Plasma Effect [PASCAL]
ßÛÛÛÜ ÜÛÛÛß File : PLASMA.PAS
ßÛÛÛÛÛß Version: 1.00 Created: 261194 Modified: 261194
ÜÛÛÛßÛÛÛÜ
ÜÛÛÛß ßÛÛÛÜ Nice plasma effect by X3M Productions.
ÛÛÛÛ ÛÛÛÛ If you have any questions, e-mail: srs@alkymi.unit.no
ÛÛÛÛ ÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ
}

{$X+}
Uses
Crt;

Type
RGBType = Record
R,G,B : Byte;
End;
PalType = Array[0..255] of RGBType;

Var
TempPal, ToPal : PalType; { Temp and current palette }
CosTbl : Array [0..255] of byte; { Cosinus table }
Pos1, Pos2,
Pos3, Pos4 : Byte; { Current positions }


{ This gives sets a color it's red, green and blue value }
Procedure SetCol(Col,R,G,B : Byte); Assembler;
Asm
mov dx,3c8h
mov al,[col]
out dx,al
inc dx
mov al,[r]
out dx,al
mov al,[g]
out dx,al
mov al,[b]
out dx,al
End;

{ Sets the entire palette. Very fast! }
Procedure SetPal(Var Palette : PalType); Assembler;
Asm
push ds
lds si, Palette
mov dx, 3c8h
mov al, 0
out dx, al
inc dx
mov cx, 768
rep outsb
pop ds
End;

{ Converts degrees to radians }
Function Rad(theta : Real) : Real;
Begin
rad := theta * pi / 180
End;

{ Initialize colors }
Procedure InitColors;
Var
i : Byte;
Begin
For i:=0 to 63 do
Begin
TempPal[i].R := 63;
TempPal[i].G := i;
TempPal[i].B := 63-i;
TempPal[i+64].R := 63-i;
TempPal[i+64].G := 63;
TempPal[i+64].B := i;
TempPal[i+128].R := 0;
TempPal[i+128].G := 63-i;
TempPal[i+128].B := 63;
TempPal[i+192].R := i;
TempPal[i+192].G := 0;
TempPal[i+192].B := 63;
End;
End;

{ Initializes plasma colors and look-up table }
Procedure InitPlasma;
Var
i : Byte;
Begin
Asm
mov ax,0013h
int 10h { Enter mode 13 }
cli
mov dx,3c4h
mov ax,604h { Enter unchained mode }
out dx,ax
mov ax,0F02h { All planes }
out dx,ax
mov dx,3D4h
mov ax,14h { Disable dword mode}
out dx,ax
mov ax,0E317h { Enable byte mode.}
out dx,ax
mov al,9
out dx,al
inc dx
in al,dx
and al,0E0h { Duplicate each scan 8 times.}
add al,7
out dx,al
End;

FillChar(ToPal,SizeOf(ToPal),0); { Clear pallette ToPal }
SetPal(ToPal);

{ Set up cosinus look-up table }
For i:=0 to 255 do
CosTbl[i] := Round(Cos(Rad(i/360*255*2))*31)+32;

InitColors;
End;

{ Draws the plasma on screen }
Procedure DrawPlasma;
Var
i,j,color,
tpos1,tpos2,
tpos3,tpos4 : Byte;
where : Word;
Begin
tpos3:=pos3;
tpos4:=pos4;
where:=0;

Asm
mov ax,0a000h
mov es,ax
End;

{ 50 rows down }
For i:=1 to 50 do
Begin
tpos1:=pos1;
tpos2:=pos2;

{ 80 columns across }
For j:=1 to 80 do
Begin
{ color in the intersection of numerous cos waves }
color := CosTbl[tpos1]+CosTbl[tpos2]+CosTbl[tpos3]+
CosTbl[tpos4]+CosTbl[i]+CosTbl[j];

Asm
mov di,where
mov al,color
mov es:[di],al
End;

where:=where+1; { Inc the place to put the pixel }
tpos1:=tpos1+4;
tpos2:=tpos2+3; { Try out different combination for
different effects }
End;
tpos3:=tpos3+4;
tpos4:=tpos4+5; { Try it out here to }
End;
End;

{ Moves the plasma left/right/up/down }
Procedure MovePlasma;
Begin
pos1:=pos1-4;
pos3:=pos3+4;
pos1:=pos1+random(1);
pos2:=pos2-random(2);
pos3:=pos3+random(1);
pos4:=pos4-random(2);
End;

{ Waits for a vertical retrace }
Procedure WaitRetrace; Assembler;
Label
l1, l2;
Asm
mov dx,3DAh
l1:
in al,dx
test al,8
jnz l1
l2:
in al,dx
test al,8
jz l2
End;

{ Fades up the palette ToPal by incrementing by 1 and sets the onscreen
palette. }
Procedure FadeUpOne(stage:Integer);
Var
i : Byte;
Tmp : RGBType;
Begin
Move(TempPal,Tmp,3);
Move(TempPal[1],TempPal[0],765);
Move(Tmp,TempPal[255],3);

For i:=0 to 255 do
Begin
ToPal[i].R := Integer(TempPal[i].R * stage div 64);
ToPal[i].G := Integer(TempPal[i].G * stage div 64);
ToPal[i].B := Integer(TempPal[i].B * stage div 64);
End;

SetPal(ToPal);
End;

{ Rotates the palette }
Procedure ShiftPallette;
Var
Tmp : RGBType;
Begin
Move(ToPal[0],Tmp,3);
Move(ToPal[1],ToPal[0],765);
Move(Tmp,ToPal[255],3);
SetPal(ToPal);
End;

{ Main plasma routine }
Procedure DoPlasma;
Var
i : Byte;
Begin
{ Fades up the plasma }
For i:=1 to 64 do
Begin
FadeUpOne(i);
DrawPlasma;
MovePlasma;
End;

{ Do the plasma thing }
Repeat
ShiftPallette;
DrawPlasma;
MovePlasma;
{WaitRetrace;} { Use this if you have flicker! }
Until Keypressed;

{ Fades down the plasma }
Move(ToPal,TempPal,768);
For i:=1 to 64 do
Begin
FadeUpOne(64-i);
DrawPlasma;
MovePlasma;
End;

While keypressed do readkey;

{ Back to text mode }
Asm
mov ax,0003h
int 10h
End;
End;

Begin
InitPlasma;
DoPlasma;
End.

COSTBL.INC

;  Costable, angles 0-255, Modulo 32+32 ------------ 

DB 64, 64, 64, 64, 64, 64, 64, 64, 63, 63, 63, 63
DB 63, 62, 62, 62, 62, 61, 61, 61, 60, 60, 59, 59
DB 59, 58, 58, 57, 57, 56, 56, 55, 55, 54, 53, 53
DB 52, 52, 51, 50, 50, 49, 48, 48, 47, 46, 46, 45
DB 44, 44, 43, 42, 41, 41, 40, 39, 38, 37, 37, 36
DB 35, 34, 34, 33, 32, 31, 30, 30, 29, 28, 27, 27
DB 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 18
DB 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 11, 10
DB 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 5, 4
DB 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1
DB 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2
DB 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7
DB 7, 8, 8, 9, 9, 10, 11, 11, 12, 12, 13, 14
DB 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22
DB 23, 23, 24, 25, 26, 27, 27, 28, 29, 30, 30, 31
DB 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 41
DB 41, 42, 43, 44, 44, 45, 46, 46, 47, 48, 48, 49
DB 50, 50, 51, 52, 52, 53, 53, 54, 55, 55, 56, 56
DB 57, 57, 58, 58, 59, 59, 59, 60, 60, 61, 61, 61
DB 62, 62, 62, 62, 63, 63, 63, 63, 63, 64, 64, 64
DB 64, 64, 64, 64

PLASMEFF.ASM

; ÛÛÛÛ       ÛÛÛÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß 
; ßÛÛÛÜ ÜÛÛÛß Project: Plasma Effect [ASM]
; ßÛÛÛÜ ÜÛÛÛß File : PLASMEFF.ASM
; ßÛÛÛÛÛß Version: 1.00 Created: 261194 Modified: 261194
; ÜÛÛÛßÛÛÛÜ
; ÜÛÛÛß ßÛÛÛÜ Nice and fast plasma effect by X3M Productions.
; ÛÛÛÛ ÛÛÛÛ If you have any questions, e-mail: srs@alkymi.unit.no
; ÛÛÛÛ ÛÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ


.MODEL SMALL
.STACK 400

DOSSEG
LOCALS

PAL_DIVIDER = 2


.DATA


CosTable LABEL BYTE
INCLUDE COSTBL.INC


Palette LABEL BYTE
i = 0
REPT 128 SHR PAL_DIVIDER
DB 63, i, 63-i
i = i + (1 SHL (PAL_DIVIDER-1))
ENDM
i = 0
REPT 128 SHR PAL_DIVIDER
DB 63-i, 63, i
i = i + (1 SHL (PAL_DIVIDER-1))
ENDM
i = 0
REPT 128 SHR PAL_DIVIDER
DB 0, 63-i, 63
i = i + (1 SHL (PAL_DIVIDER-1))
ENDM
i = 0
REPT 128 SHR PAL_DIVIDER
DB i, 0, 63
i = i + (1 SHL (PAL_DIVIDER-1))
ENDM


VTime1 DB 2
VTime2 DB 1
VTime3 DB 3
VTime4 DB 4


UDATASEG

PlasmaPal DB (256 SHR (PAL_DIVIDER-1))*3 DUP (?)

Time1 DB ?
Time2 DB ?
Time3 DB ?
Time4 DB ?


.CODE
.STARTUP

CLD
MOV AX,13h
INT 10h
CLI
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
MOV DX,3c8h
MOV AL,256-(256 SHR (PAL_DIVIDER-1))
OUT DX,AL
INC DX
MOV CX,(256 SHR (PAL_DIVIDER-1))*3
MOV SI,OFFSET Palette

@@pl1:
LODSB
OUT DX,AL
LOOP @@pl1
MOV AX,0A000h
MOV ES,AX
MOV SI,OFFSET CosTable

MainLoop:
MOV DX,3DAh

@@vs1:
IN AL,DX
TEST AL,8
JZ @@vs1

@@vs2:
IN AL,DX
TEST AL,8
JNZ @@vs2
XOR DI,DI
MOV AH,50
MOV CL,Time3
MOV CH,Time4

@@lv:
PUSH AX
MOV AH,80
MOV DL,Time1
MOV DH,Time2

@@lh:
MOV BX,BP
MOV AL,BL
; ADD AL,AH ; Could make for more perturbations.
XOR BH,BH
MOV BL,DL
ADD AL,[SI+BX]
MOV BL,DH
ADD AL,[SI+BX]
MOV BL,CL
ADD AL,[SI+BX]
MOV BL,CH
ADD AL,[SI+BX]

IFDIF %PAL_DIVIDER,<1>
OR AL, (0FFh SHL (9-PAL_DIVIDER)) AND 0FFh
ENDIF

STOSB
ADD DL,1
ADD DH,3
DEC AH
JNZ @@lh
ADD CL,2
ADD CH,1
POP AX
DEC AH
JNZ @@lv

DEC BP
MOV BX,BP
XOR BL,BH
XOR BL,-1[DI]
XOR BL,CL
XOR BL,DL
ADD BL,CH
ADD BL,DH

XOR BH,BH
MOV DI,OFFSET VTime1
TEST BL,8
JNZ @@dec
AND BL,3
CMP BYTE PTR [DI+BX],3
JG @@sum
INC BYTE PTR [DI+BX]
JMP @@sum

@@dec:
AND BL,3
CMP BYTE PTR [DI+BX],-3
JL @@sum
DEC BYTE PTR [DI+BX]

@@sum:
MOV DL,VTime1
MOV DH,VTime2
MOV CL,VTime3
MOV CH,VTime4
ADD Time1,DL
SUB Time2,DH
ADD Time3,CL
SUB Time4,CH
MOV AH,1
INT 16h
JNZ Bye
JMP MainLoop

Bye:
XOR AH,AH
INT 16h
MOV AX,3
INT 10h
XOR BH,BH
MOV DX,1700h
MOV AH,2
INT 10h
MOV AX,4C00h
INT 21h

END

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT