Plasma Effect

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
Ophelius
Posts: 428
Joined: Feb 26, 2006 1:57

Plasma Effect

Post by Ophelius »

Here's an attempt at some plasma. I just started learning about how to do this today, so it's unoriginal and unoptimized. You'll need the Allegro 4.0 dll if you haven't got it:
http://www.dlldll.com/downdll/7417.html

Code: Select all

#include "Allegro.bi"

DECLARE SUB Shift_Pal ()


DIM SHARED AS INTEGER SCR_W = 500, SCR_H = 200
DIM SHARED AS RGB Pal(0 to 255), Temp_Col
DIM SHARED Buffer AS BITMAP PTR

Allegro_Init ()

Install_Keyboard

IF SET_GFX_MODE(0, SCR_W, SCR_H, 0, 0) <> 0 then end

Buffer = Create_Bitmap(SCR_W, SCR_H)

dim as integer i, x, y, Style

'Generate Palette

'set entire pal to black
for i = 0 to 255
    Pal(i).R = 0
    Pal(i).G = 0
    Pal(i).B = 0
next i

for i = 0 to 63
    Pal(i).R = 0
    Pal(i).G = i
    Pal(i).B = i
next i

for i = 0 to 63
    Pal(64+i).R = 0
    Pal(64+i).G = 63-i
    Pal(64+i).B = 63-i
next i

Set_Palette @Pal(0)

Style = 1

do
    
    Clear_Bitmap Buffer
       
    for y = 0 to SCR_H - 1
        for x = 0 to SCR_W - 1
            
            Select Case Style
            Case 1
                i = int( (32 + (32 * SIN( y / 16 ) ) ) +_
                         (32 + (32 * SIN( x / 16 ) ) ) +_
                         (32 + (32 * SIN( (SQR(x*x + y*y)) / 16 ) ) ) ) \ 3
            Case 2
                i = int( (32 + (32 * SIN( y * SQR(X)/ 128 ) ) ) +_
                         (32 + (32 * SIN( x * SQR(Y)/ 128 ) ) ) +_
                         (32 + (32 * SIN( (SQR(x*x + y*y)) /32 ) ) ) ) \ 3
            END SELECT
            
            PutPixel Buffer, x, y, i
            
        next x
    next y

    Shift_Pal

    Set_Palette @Pal(0)
        
    Blit Buffer, Screen, 0, 0, 0, 0, Buffer->W, Buffer->H
    
loop until KEY(KEY_ESC)


END



SUB Shift_Pal ()
    
    dim i as integer
    
    Temp_Col.R = Pal(127).R
    Temp_Col.G = Pal(127).G
    Temp_Col.B = Pal(127).B
    for i = 127 to 1 step -1
        Pal(i).R = Pal(i-1).R
        Pal(i).G = Pal(i-1).G
        Pal(i).B = Pal(i-1).B
    NEXT i
    Pal(0).R = Temp_Col.R
    Pal(0).G = Temp_Col.G
    Pal(0).B = Temp_Col.B
    
END SUB

If you have ideas how to make this look better, or more optimized, let me know. ;)

Ophelius
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Post by relsoft »

Palette switching is good. But the coolest looking plasmas are ones made in real-time.

http://qbcm.hybd.net/issues/4-1/#plasmas
Ophelius
Posts: 428
Joined: Feb 26, 2006 1:57

Post by Ophelius »

Thanks Rel, that helped a lot. I updated my code to use both palette shifting and plasma movement. The effect is really cool:

Code: Select all

#include "Allegro.bi"

DECLARE SUB Shift_Pal ()


DIM SHARED AS INTEGER SCR_W = 500, SCR_H = 200
DIM SHARED AS RGB Pal(0 to 255), Temp_Col
DIM SHARED Buffer AS BITMAP PTR

Allegro_Init ()

Install_Keyboard

IF SET_GFX_MODE(0, SCR_W, SCR_H, 0, 0) <> 0 then end

Buffer = Create_Bitmap(SCR_W, SCR_H)

dim as integer i, x, y, Style

'Generate Palette

for i = 0 to 255
    Pal(i).R = 0
    Pal(i).G = 0
    Pal(i).B = 0
next i

for i = 0 to 63
    Pal(i).R = 0
    Pal(i).G = i
    Pal(i).B = i
next i

for i = 0 to 63
    Pal(64+i).R = 0
    Pal(64+i).G = 63-i
    Pal(64+i).B = 63-i
next i

Set_Palette @Pal(0)


dim c as integer
do
    
    Clear_Bitmap Buffer
       
    for y = 0 to SCR_H - 1
        for x = 0 to SCR_W - 1
            
            i = ((32+(SIN((x)/32) * 32)) + (32+(COS((x+y+C)/16) * 32))+(32+(COS((SQR(y*y+x*x))/8) * 32))) / 3
            
            PutPixel Buffer, x, y, i
            
        next x
    next y

    C = (C+2) MOD 100

    Shift_Pal

    Set_Palette @Pal(0)

    Blit Buffer, Screen, 0, 0, 0, 0, Buffer->W, Buffer->H
    
loop until KEY(KEY_ESC)


END



SUB Shift_Pal ()
    
    dim i as integer
    
    Temp_Col.R = Pal(127).R
    Temp_Col.G = Pal(127).G
    Temp_Col.B = Pal(127).B
    for i = 127 to 1 step -1
        Pal(i).R = Pal(i-1).R
        Pal(i).G = Pal(i-1).G
        Pal(i).B = Pal(i-1).B
    NEXT i
    Pal(0).R = Temp_Col.R
    Pal(0).G = Temp_Col.G
    Pal(0).B = Temp_Col.B
    
END SUB
It's a lot of fun trying new equations to see what comes up. Has anyone ever written a manual explaining a lot of the popular graphic tricks, stuff you would find in demos?(roto-zooming, palette tricks, etc). I would like to know more about these techniques.
Merick
Posts: 1038
Joined: May 28, 2007 1:52

Post by Merick »

Take a look at DBF, it's a demoscene forum with a section dedicated to FB: http://www.dbfinteractive.com/
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Post by relsoft »

Ophelius wrote:Thanks Rel, that helped a lot. I updated my code to use both palette shifting and plasma movement. The effect is really cool:



It's a lot of fun trying new equations to see what comes up. Has anyone ever written a manual explaining a lot of the popular graphic tricks, stuff you would find in demos?(roto-zooming, palette tricks, etc). I would like to know more about these techniques.
Here:
http://rel.betterwebber.com/index.php?a ... =Tutorials

Try to read "How to make Blobs(metaballs)" and "lensflares".
Ophelius
Posts: 428
Joined: Feb 26, 2006 1:57

Post by Ophelius »

I've studied the metaballs code and it's easier than it looks. You had a more complicated Plasma+metaball example too. I was stunned by the plasma in the background. How do you go about finding good equations for a plasma. Yours looks really complex. Do you just stumble on one by trying different numbers/forms, or is it based on some Physics(it looks like fluid dynamics)? I still have so much to learn. :(
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Post by relsoft »

Ophelius wrote:I've studied the metaballs code and it's easier than it looks. You had a more complicated Plasma+metaball example too. I was stunned by the plasma in the background. How do you go about finding good equations for a plasma. Yours looks really complex. Do you just stumble on one by trying different numbers/forms, or is it based on some Physics(it looks like fluid dynamics)? I still have so much to learn. :(
I just try to change equations until it looks good while being sure that the offsets and params are not over the scale that I gave the sin luts. It's easy to visualize trig funks since they are periodic in nature.

Here's an example I made for my daughter's Nintendo DS yesterday. Sorry its C++ but I could make it in FB later if you want.

Code: Select all

/*
NDS Translucent Plasma
Relminator

http://rel.betterwebber.com

*/

#include <nds.h>
#include <stdio.h>
#include <math.h>


// some sine LUTs
u8 lsin1[2048];
u8 lsin2[2048];
u8 lsin3[2048];

// RGB palette
u16 pal[256];    

int main(void)
{
	
	// constant sine divisor
	const u8 K1 = 32;
    const u8 K2 = 12;
    const u8 K3 = 28;
	
	// maximum values our dynamic plasmas can move
	u16 KSIN1 = u8(K1 *(360/57.3f));
    u16 KSIN2 = u8(K2 *(360/57.3f));
    u16 KSIN3 = u8(K3 *(360/57.3f));
	
	
    		
	// precalculate our luts
	for (int i = 0; i< ((2048) - 1); i++)
	{
        lsin1[i] = sin(i/(float)K1) * 32+32;
        lsin2[i] = sin(i/(float)K2) * 16+16;
        lsin3[i] = sin(i/(float)K3) * 20+20;
    }    

	// generate our 256 color palette
	for (int i=0; i<256; i++)
	{
	    u8 r = (u8)(abs(int(16 - 15 * sin(i * M_PI / 16.0f))));
		u8 g = (u8)(abs(int(16 - 15 * sin(i * M_PI / 12.0f))));
		u8 b = (u8)(abs(int(16 - 15 * sin(i * M_PI / 18.0f))));
		pal[i] = RGB15(r,g,b);
	}

	irqInit();
	irqEnable(IRQ_VBLANK);
	
	
	//initialize the DS Dos-like functionality
	consoleDemoInit();
	
	iprintf("\x1b[1;1HTranslucent Plasma!");
	iprintf("\x1b[2;1HFramebuffer madness!");
	iprintf("\x1b[3;1HRelsoft");
	iprintf("\x1b[4;1Hhttp://rel.betterwebber.com");
	iprintf("\x1b[6;1HAnya Therese B. Lope");
 
	//set frame buffer mode 0
	videoSetMode(MODE_FB0);
 
	//enable VRAM A for writting by the cpu and use 
	//as a framebuffer by video hardware
	vramSetBankA(VRAM_A_LCD);
 
	u8 rot;						// translucent factor
	u16 counter =0;				// frame counter
	u16 a = 0, b = 0, ct = 0;	// movement deltas
	u16 c;						// palette color index
	
	while(1)
	{

		// dynamically move our plasmas 
		a= (a + 1) % (KSIN1 + 1);
		b = (b + 1) % (KSIN2 + 1);
		ct = (ct + 1) % (KSIN3 + 1);
		
		// offset 2nd plasma by a factor of 64 * 2 or (-64 to 64)
		rot = 64 * (((counter & 1) == 1) | 1);
		
		// inc frame
		counter++;
	    
		//write to vram directly
		short unsigned int *vram_offset = VRAM_A;
		
		for (int ya = 0; ya<SCREEN_HEIGHT; ya++)
		{
			for (int xa = 0; xa <SCREEN_WIDTH-1; xa++)
			{
				rot = -rot;		// draw plasmas every other pixel
				// calculate colors
				c = (lsin1[xa + a + rot] + lsin2[ya + b + rot] +lsin3[1024+xa + ya - ct]);
				c = (lsin1[xa + a + rot+c] + lsin2[ya + b + rot+c] +lsin3[1024+xa + ya - ct+c]);
				// write to vram
				*vram_offset++ = pal[c];
			}
			vram_offset++;		// magic
		}		
		swiWaitForVBlank();
	}
 
	return 0;
}
 
Ophelius
Posts: 428
Joined: Feb 26, 2006 1:57

Post by Ophelius »

Thanks for that. I converted it to FB for you. Looks real cool. Though I don't know the DS's screen res and what the U8 and U16 meant, I had to improvise, so I think there might be issues with that. The palette was pretty dark, so you'll notice I multiplied it by 8 to get it brighter. I'm sure it's just some mistake in my conversion and wasn't your intention.

I was surprised I got it to work right away because I don't code in C, but it's very similar. I just guessed that % meant Mod and | meant Or, etc:

Code: Select all

DIM AS INTEGER SCR_W = 320, SCR_H=200

DIM LSIN1(2048) AS DOUBLE
DIM LSIN2(2048) AS DOUBLE
DIM LSIN3(2048) AS DOUBLE

'constant sine divisor
Const K1 = 32
Const K2 = 12
Const K3 = 28

const PI = 3.141593

        
'maximum values our dynamic plasmas can move
DIM AS INTEGER KSIN1 = K1 *(360/57.3)
DIM AS INTEGER KSIN2 = K2 *(360/57.3)
DIM AS INTEGER KSIN3 = K3 *(360/57.3)

                    
'precalculate our luts
dim as integer i
For i = 0 to 2047

    lsin1(i) = Sin(i/K1) * 32 + 32
    lsin2(i) = Sin(i/K2) * 16 + 16
    lsin3(i) = Sin(i/K3) * 20 + 20
    
next i


SCREENRES SCR_W, SCR_H, 8 


'generate our 256 Color Palette
DIM AS INTEGER r,g,b
For i = 0 to 255

    r = 8*(Abs(Int(16 - 15 * Sin(i * PI / 16.0))))
    g = 8*(Abs(Int(16 - 15 * Sin(i * PI / 12.0))))
    b = 8*(Abs(Int(16 - 15 * Sin(i * PI / 18.0))))
    
    palette i, r, g, b
    
Next i

DIM AS INTEGER rot                              ' translucent factor
DIM AS INTEGER counter =0                       ' frame counter
DIM AS INTEGER d_a = 0, d_b = 0, d_ct = 0       ' movement deltas
DIM AS INTEGER c                                ' Palette Color index
DIM AS INTEGER xa, ya

While INKEY = ""


        'dynamically move our plasmas 
        d_a= (d_a + 1) MOD (KSIN1 + 1)
        d_b = (d_b + 1) MOD (KSIN2 + 1)
        d_ct = (d_ct + 1) MOD (KSIN3 + 1)
        
        'offset 2nd plasma by a factor of 64 * 2 Or (-64 To 64)
        rot = 64 * (((counter AND 1) = 1) OR 1)
        
        
        For ya = 0 TO SCR_H - 1
        
                For xa = 0 to SCR_W-1
                
                        rot = -rot        'Draw plasmas every other pixel
                        
                        'calculate colors
                        c = (lsin1(xa + d_a + rot) + lsin2(ya + d_b + rot) + lsin3(1024+xa + ya - d_ct))
                        c = (lsin1(xa + d_a + rot+c) + lsin2(ya + d_b + rot+c) + lsin3(1024+xa + ya - d_ct+c))
                        
                        'SCREENLOCK  'don't know if this is necessary
                        PSET (xa, ya), c
                        'SCREENUNLOCK 'this either

                Next xa
                
        Next ya
        
        'inc frame
        Counter+=1
        
WEND
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Post by relsoft »

Nice!! I forgot to tell you that the DS has 16 bit of colors and its RGB15 ranges of only 0-31 per channel as opposed to FB's 32 bit mode where channels range from 0-255.

Anyways, here's a 32 bit version I coded last night.

Code: Select all

''Plazma!!!
''relminator
''http://rel.betterwebber.com

const as integer SCR_WID = 256
const as integer SCR_HEI = 192
const as integer BPP = 32


const as single PI = atn(1) * 4


const as integer K1 = 22
const as integer K2 = 32
const as integer K3 = 58


dim shared as integer ksin1,ksin2,ksin3
    
dim shared as uinteger ptr lsin1 
dim shared as uinteger ptr lsin2
dim shared as uinteger ptr lsin3

lsin1 = new uinteger[2048]
lsin2 = new uinteger[2048]
lsin3 = new uinteger[2048]    
    
for i as integer = 0 to 2048 - 1
    lsin1[i] = sin((i-1024)/K1) * 120+120 
    lsin2[i] = sin((i-1024)/K2) * 64+64
    lsin3[i] = sin((i-1024)/K3) * 164+164
next i
 

KSIN1 = int(K1 *(360/57.3))
KSIN2 = int(K2 *(360/57.3))
KSIN3 = int(K3 *(360/57.3))





dim as uinteger ptr pal = new uinteger[256]

for i as integer = 0 to 255
    dim as ubyte r = cbyte(abs(INT(128 - 127 * SIN(i * PI / 32))))
    dim as ubyte g = cbyte(abs(INT(128 - 127 * SIN(i * PI / 64))))
    dim as ubyte b = cbyte(abs(INT(128 - 127 * SIN(i * PI / 128))))
    pal[i]=rgb(r,g,b)
next i





dim as integer a = 0, b = 0, ct = 0    
dim as integer rot, counter =0

screenres SCR_WID,SCR_HEI,BPP,2

screenset 1, 0
do
    a = (a + 1) mod (KSIN1 + 1)
    b = (b + 1) mod (KSIN2 + 1)
    ct = (ct + 1) mod (KSIN3 + 1)
    
    rot = 64 * (((counter AND 1) = 1) OR 1)
	counter += 1
	
    screenlock
    Line (0, 0)-(SCR_WID, SCR_HEI), 0, BF
    
    for y as integer = 0 to 191
    	for x as integer = 0 to 254   		        
    		rot = -rot    		
            dim as integer c = Lsin1[x+a] + Lsin2[y+b] + Lsin3[x+y-ct+1024] 
            c = Lsin1[x+a+rot+c] + Lsin2[y+b+rot+c] + Lsin3[x+y-ct+1024]       
            c = c and 255
    		pset (x,y), pal[c]
    	next x
    next y
    screenunlock
    sleep 1,1
    
    ScreenCopy
Loop While Inkey = ""


delete[] lsin1
delete[] lsin2
delete[] lsin3
delete[] pal


end

joseywales72
Posts: 206
Joined: Aug 27, 2005 2:02
Location: Istanbul, Turkey

Post by joseywales72 »

Hi,
Great effects... There is something strange though. Ophelius' translation compiles and works fine on my Linux (Arch 32, 2.6.33, Xorg 1.7.5) but Relsofts last one does not compile and gives this error.

Code: Select all

/usr/lib/libsupc++.a(eh_personality.o): In function `__gxx_personality_v0':
(.text.__gxx_personality_v0+0xba): undefined reference to `_Unwind_GetIPInfo'
Any ideas?
Thanks.
Anil
Ophelius
Posts: 428
Joined: Feb 26, 2006 1:57

Post by Ophelius »

Could be because he's allocating memory for his Luts and Palette with the NEW function. I don't understand why he did that when a simple DIM would work fine. Is it speed increase Rel? So maybe that doesn't work in Linux.
relsoft
Posts: 1767
Joined: May 27, 2005 10:34
Location: Philippines
Contact:

Post by relsoft »

Ophelius wrote:Could be because he's allocating memory for his Luts and Palette with the NEW function. I don't understand why he did that when a simple DIM would work fine. Is it speed increase Rel? So maybe that doesn't work in Linux.
As for the Linux bug, I have no idea. It's been 5 years since I last touched a Linux Distro.

Yeah, I usually use new and delete for speed. Dynamic Arrays in FB or anywhere has a few overheads on access.

BTW, to make it faster, ditch the pset and write directly to the buffer using screenptr+offset.
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Post by anonymous1337 »

@joseywales: You need GCC to compile FB programs with certain features from now on.
Post Reply