[bb] "Twirly" special FX demo by big10p [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:42

Previous topic - Next topic

BlitzBot

Title : "Twirly" special FX demo
Author : big10p
Posted : 1+ years ago

Description : This was a special FX entity system I was working on about a year ago before I gave up on it after realizing that overlaying lots of blended layers on top of each other wasn't such a great idea (speed wise).

Anyway, I guess 'Twirlies' could still be used for certain things, like making a pretty screensaver, or something. They're pretty much infinately configurable as each can have it's own user defined CLUT which can be cycled etc.


Code :
Code (blitzbasic) Select
;
; Twirly Special FX demo by big10p (A.K.A. Chris Chadwick) 2003
;


Graphics3D 800,600,32
SetBuffer BackBuffer()

WireFrame 0
AntiAlias 0

SeedRnd MilliSecs()

Type twirly_layerT
Field ent ; Layer star mesh entity.
Field rot# ; Amount to rotate layer each update.
Field clut_i% ; Index of layer's CLUT colour.
End Type

Type twirlyT
Field tx#,ty# ; Demo-specific 2D twirly movement amounts.

Field piv ; Control pivot - all layers are attached to this.
Field hidden% ; Bool flag to indicate if Twirly is hidden.
Field layer_bank ; Bank holding Handle() IDs of all layers.
Field num_layers% ; Total number of Twirly layers.
Field clut% ; clut_banks() index of Twirly's CLUT.
Field max_clut_i% ; Bank index of last colour (RGB set) in CLUT.
Field clut_cycle% ; CLUT cycle control. - left, 0 no cycle, + right.
Field cycle_count% ; Count down to next CLUT cycle.
End Type

; Create 2 starfield planes.
Global tex1 = CreateTexture(128,128,4)
make_tex(tex1)
plane1 = CreatePlane()
RotateEntity plane1,-90,0,0
PositionEntity plane1,0,0,10
EntityTexture plane1,tex1
Global tex2 = CreateTexture(128,128,4)
make_tex(tex2)
plane2 = CreatePlane()
RotateEntity plane2,-90,0,0
PositionEntity plane2,0,0,11
EntityTexture plane2,tex2

Global frame_count%
Global fps%
Global slowest_fps%
Global fps_timeout%
Global frame_time%
Global slowest_frame%
Global frame_start%
fps_timer = CreateTimer(60)
slowmo% = False
wiref% = False

Global cam = CreateCamera()
PositionEntity cam,0,0,-20
CameraZoom cam,1.4

light = CreateLight()

Const END_OF_CLUT% = -1
Const END_OF_CLUT_LIST% = -2
Const MAX_CLUTS% = 100
Global num_cluts% = 0

Dim clut_banks(MAX_CLUTS-1)
open_twirly()
copy_clut_grad(1,5)

; Create some twirlies.
For n = 1 To 3
tw1.twirlyT = create_preset_twirly(n)
PositionEntity tw1piv,Rnd(-5,5),Rnd(-5,5),-10
Next

vp1# = 1 : vp2# = 1


; --- Main loop ---

While Not KeyHit(1)

frame_start = MilliSecs()

If KeyHit(28) Then slowmo = Not slowmo
If KeyHit(14) Then wiref = Not wiref : WireFrame wiref

For this.twirlyT = Each twirlyT
CameraProject cam,EntityX(thispiv),EntityY(thispiv),EntityZ(thispiv)
If ProjectedX() > 800 Or ProjectedX() < 0 Then this x=-this x
If ProjectedY() > 600 Or ProjectedY() < 0 Then this y=-this y
TranslateEntity thispiv,this x,this y,0
Next

vp1 = vp1 - 0.003
vp2 = vp2 - 0.001
PositionTexture tex1,1,vp1
PositionTexture tex2,1,vp2

update_twirly()
RenderWorld
;show_info()
;show_clut(10,80)

frame_time = MilliSecs() - frame_start

WaitTimer(fps_timer)
Flip(1)

If slowmo Then Delay 200
Wend

close_twirly()
ClearWorld

End


; The Twirly CLUTS, defined in RGB sets.
.twirly_clut_data

Data 255,0,0
Data 0,255,0
Data 0,0,255
Data END_OF_CLUT

Data 255,255,0
Data 0,255,0
Data 0,255,255
Data 0,0,255
Data 255,0,255
Data 255,0,0
Data END_OF_CLUT

Data END_OF_CLUT_LIST


;
; Draws random coloured starfield onto text.
;
Function make_tex(tex)

SetBuffer TextureBuffer(tex)

For y = 0 To 127
For x = 0 To 127
WritePixel x,y,$00000000
Next
Next
Color 255,255,255

For n = 1 To 200
r = Rand(0,255) Shl 16
g = Rand(0,255) Shl 8
b = Rand(0,255)
WritePixel Rand(0,127),Rand(0,127),$ff000000 Or (r Or g Or b)
Next
ScaleTexture tex,30,30
SetBuffer BackBuffer()

End Function


;
; Prepares the Twirly system ready for use.
;
Function open_twirly()

Local r%,g%,b%
Local clut_size%[MAX_CLUTS-1]
Local cs% = 0

; Count CLUT entries and size.
Restore twirly_clut_data
Repeat
Read r
If r = END_OF_CLUT
clut_size[num_cluts] = cs
num_cluts = num_cluts + 1
cs = 0

Read r : If r = END_OF_CLUT_LIST Then Exit
EndIf
Read g
Read b

cs = cs + 1
Forever

; Create CLUT banks.
Restore twirly_clut_data
For i = 0 To num_cluts-1
clut_banks(i) = CreateBank((clut_size[i]*3)*4)

For n = 0 To BankSize(clut_banks(i))-1 Step 12
Read r,g,b
PokeInt clut_banks(i),n,r
PokeInt clut_banks(i),n+4,g
PokeInt clut_banks(i),n+8,b
Next

Read dummy ; Skip END_OF_CLUT terminator.
Next

End Function


;
; Closes down the Twirly system, freeing all resources.
;
Function close_twirly()

; Kill all Twirlies.
For this.twirlyT = Each twirlyT
free_twirly(this)
Next

; Free the CLUT banks.
For i = 0 To num_cluts-1
FreeBank clut_banks(i)
Next

End Function


;
; Frees all resources used by a given twirly.
;
; Params:
; twirly - The twirly to be freed.
;
Function free_twirly(twirly.twirlyT)

; Free all Twirly layer resources.
For n = 0 To BankSize(twirlylayer_bank)-1 Step 4
layer.twirly_layerT = Object.twirly_layerT(PeekInt(twirlylayer_bank,n))
FreeEntity layerent
Delete layer
Next

; Free actual Twirly resources.
FreeEntity twirlypiv
FreeBank layer_bank
Delete twirly

End Function


;
; Creates a single layer twirly. See create_star_mesh() for params.
;
Function create_twirly.twirlyT(radius#,points%,indent#,ratio%=True)

twirly.twirlyT = New twirlyT
twirlypiv = CreatePivot()
RotateEntity twirlypiv,0,180,0 ; So we can point twirly at camera.
twirly
um_layers = 1
twirlyhidden = False

twirly x = Rnd(.01,.03) : If Rand(0,1) Then twirly x = -twirly x
twirly y = Rnd(.01,.03) : If Rand(0,1) Then twirly y = -twirly y

layer.twirly_layerT = New twirly_layerT
twirlylayer_bank = CreateBank(4)
PokeInt twirlylayer_bank,0,Handle(layer)

; Create initial twirly layer.
layerent = create_star_mesh(radius,points,indent,ratio)
EntityParent layerent,twirlypiv
PositionEntity layerent,0,0,0,0
EntityFX layerent,1+4+8

Return twirly

End Function


;
; Adds a layer to the specified, existing twirly.
; See create_star_mesh() for other params.
;
Function add_twirly_layer(twirly.twirlyT,radius#,points%,indent#,ratio%=True)

layer.twirly_layerT = New twirly_layerT
bs = BankSize(twirlylayer_bank)
ResizeBank twirlylayer_bank,bs+4
PokeInt twirlylayer_bank,bs,Handle(layer)

; Create twirly layer.
layerent = create_star_mesh(radius,points,indent,ratio)
PositionEntity layerent,0,0,Float(twirly
um_layers)*0.001
EntityParent layerent,twirlypiv,1

twirly
um_layers = twirly
um_layers + 1
EntityFX layerent,1+4+8

End Function


;
; Sequentially 'paints' all layers of a twirly with the given CLUT.
;
; Params:
; twirly - Twirly to be coloured with the specified CLUT.
; clut   - Number of CLUT to colour twirly with.
; cycle  - Specifies how to cycle the CLUT every time the twirly is updated:
;          0 (default) to not cycle the CLUT.
;          -1 to cycle the CLUT to the left.
;          1 to cycle the CLUT to the right.
; dir    - Direction to colour the twirly layers with:
;          0 (default) to colour layers from first-to-last.
;          1 to colour layers from last-to-first.
;
Function set_twirly_clut(twirly.twirlyT,clut%,cycle%=0,dir%=0)

clut_i% = 0
clut_size% = BankSize(clut_banks(clut))
cb = clut_banks(clut)

If dir = 0
For n = 0 To twirly
um_layers-1
id = PeekInt(twirlylayer_bank,n*4)
layer.twirly_layerT = Object.twirly_layerT(id)
layerclut_i = clut_i
EntityColor layerent,PeekInt(cb,clut_i),PeekInt(cb,clut_i+4),PeekInt(cb,clut_i+8)
clut_i = clut_i + 12
If clut_i = clut_size Then clut_i = 0
Next
Else
For n = twirly
um_layers-1 To 0 Step -1
id = PeekInt(twirlylayer_bank,n*4)
layer.twirly_layerT = Object.twirly_layerT(id)
layerclut_i = clut_i
EntityColor layerent,PeekInt(cb,clut_i),PeekInt(cb,clut_i+4),PeekInt(cb,clut_i+8)
clut_i = clut_i + 12
If clut_i = clut_size Then clut_i = 0
Next
EndIf

twirlyclut = clut
twirlyclut_cycle = cycle
twirlycycle_count = Abs(cycle)
twirlymax_clut_i = clut_size-12

End Function


;
; Sets all layers of a twirly to use a given blend mode.
;
Function set_twirly_blend(twirly.twirlyT,mode%)

For n = 0 To BankSize(twirlylayer_bank)-1 Step 4
layer.twirly_layerT = Object.twirly_layerT(PeekInt(twirlylayer_bank,n))
EntityBlend layerent,mode
Next

End Function


;
; Sets all layers of a twirly to use a given alpha level.
;
Function set_twirly_alpha(twirly.twirlyT,alpha#)

For n = 0 To BankSize(twirlylayer_bank)-1 Step 4
layer.twirly_layerT = Object.twirly_layerT(PeekInt(twirlylayer_bank,n))
EntityAlpha layerent,alpha
Next

End Function


;
; Creates a copy of an existing CLUT with gradients between each colour.
;
; Params:
; clut   - Number of CLUT to be copied.
; grads  - Number of gradients to insert between each colour.
; grad_r - Each colour from the copied CLUT is faded to this colour.
; grad_g   If not specified (default), colours fade to the next colour
; grad_b   from the CLUT being copied.
;
; Returns:
; Index of new clut in clut_banks() array.
;
Function copy_clut_grad(clut%,grads%,grad_r#=-1,grad_g#=-1,grad_b#=-1)

old_clut = clut_banks(clut)
old_size = BankSize(clut_banks(clut))

new_clut = CreateBank(old_size*(grads+1))
clut_banks(num_cluts) = new_clut
num_cluts = num_cluts + 1

poke_i = 0

If grad_r=-1 Or grads=0
; Create gradients between adjacent colours from the copied CLUT.

grad_div = grads + 1

For i = 0 To old_size-1 Step 12
r1# = Float(PeekInt(old_clut,i))
g1# = Float(PeekInt(old_clut,i+4))
b1# = Float(PeekInt(old_clut,i+8))

; Get colour to fade to.
If i = old_size-12
; Wraparound to first colour.
r2# = Float(PeekInt(old_clut,0))
g2# = Float(PeekInt(old_clut,4))
b2# = Float(PeekInt(old_clut,8))
Else
; Use next colour in CLUT.
r2# = Float(PeekInt(old_clut,i+12))
g2# = Float(PeekInt(old_clut,i+12+4))
b2# = Float(PeekInt(old_clut,i+12+8))
EndIf

r_step# = (r2-r1)/grad_div
g_step# = (g2-g1)/grad_div
b_step# = (b2-b1)/grad_div

; Add original colour and gradients to new CLUT.
For n = 0 To grads
PokeInt new_clut,poke_i,  Int(r1 + (n*r_step))
PokeInt new_clut,poke_i+4,Int(g1 + (n*g_step))
PokeInt new_clut,poke_i+8,Int(b1 + (n*b_step))
poke_i = poke_i + 12
Next
Next
Else
; Create gradients from copied CLUT colour to grad_r,grad_g,grad_b.

For i = 0 To old_size-1 Step 12
r1# = Float(PeekInt(old_clut,i))
g1# = Float(PeekInt(old_clut,i+4))
b1# = Float(PeekInt(old_clut,i+8))

r_step# = (grad_r-r1)/grads
g_step# = (grad_g-g1)/grads
b_step# = (grad_b-b1)/grads

; Add original colour and gradients to new CLUT.
For n = 0 To grads
PokeInt new_clut,poke_i,  Int(r1 + (n*r_step))
PokeInt new_clut,poke_i+4,Int(g1 + (n*g_step))
PokeInt new_clut,poke_i+8,Int(b1 + (n*b_step))
poke_i = poke_i + 12
Next
Next
EndIf

Return num_cluts - 1

End Function


;
; Updates ALL non-hidden Twirlies.
;
Function update_twirly()

For this.twirlyT = Each twirlyT
If Not thishidden
PointEntity thispiv,cam
cb = clut_banks(thisclut)

; Twirly's CLUT cycle frequency management.
do_cycle = False
If thisclut_cycle
thiscycle_count = thiscycle_count - 1
If thiscycle_count = 0
thiscycle_count = Abs(thisclut_cycle)
do_cycle = True
EndIf
EndIf

If do_cycle
; Update each layer attached to this twirly, cycling the CLUT.
For n = 0 To BankSize(thislayer_bank)-1 Step 4
layer.twirly_layerT = Object.twirly_layerT(PeekInt(thislayer_bank,n))
TurnEntity layerent,0,0,layerot

If thisclut_cycle < 0
; Cycle CLUT to the left.
clut_i = layerclut_i + 12
If clut_i > thismax_clut_i Then clut_i = 0
Else
; Cycle CLUT to the right.
clut_i = layerclut_i - 12
If clut_i < 0 Then clut_i = thismax_clut_i
EndIf

layerclut_i = clut_i
EntityColor layerent,PeekInt(cb,clut_i),PeekInt(cb,clut_i+4),PeekInt(cb,clut_i+8)
Next
Else
; Update each layer attached to this twirly.
For n = 0 To BankSize(thislayer_bank)-1 Step 4
layer.twirly_layerT = Object.twirly_layerT(PeekInt(thislayer_bank,n))
TurnEntity layerent,0,0,layerot
Next
EndIf

End If
Next

End Function


;
; Creates a planar, star-shaped mesh.
;
; Params:
; radius - Radius of star in world units.
; points - Number of points the star should have.
; indent - Sets the 'depth' of the indent between the points of the star.
; ratio  - True (default) to indicate that indent is a ratio of the radius
;          e.g. 1=no indent (circle), .5=indent midway between point and centre.
;          False to indicate that indent is an absolute size.
;
; Returns:
; The newly created star mesh.
;
Function create_star_mesh(radius#=1.0,points%=5,indent#=0.5,ratio%=True)

If ratio Then indent = radius * indent ; Convert indent to ratio of radius.

mesh = CreateMesh()
surf = CreateSurface(mesh)

verts% = points * 2
vang# = 0
vang_step# = 360.0/Float(verts)

; Add verts for all star points & indents.
For n = 0 To verts-1

If (n And 1) Then size# = indent Else size# = radius

AddVertex(surf,Cos(vang)*size,Sin(vang)*size,0)
VertexNormal surf,n,0,0,-1

vang = vang + vang_step
Next

; Add centre vert.
AddVertex(surf,0,0,0)
VertexNormal surf,verts,0,0,-1

; Make triangles.
For n = 0 To verts-2
AddTriangle surf,n,verts,n+1
Next
AddTriangle surf,verts-1,verts,0

Return mesh

End Function


;
; Creates a twirly_type preset twirly.
;
Function create_preset_twirly.twirlyT(twirly_type%)

Select twirly_type
Case 1
dir#=.01
For n = 1 To 30
If n=1
tw.twirlyT = create_twirly(n*.01,10,.2)
Else
add_twirly_layer(tw,n*.1,10,.1)
EndIf
set_layer_rotate(tw,n-1,dir*n)
Next
set_twirly_clut(tw,2,2,1)
set_twirly_blend(tw,3)
set_twirly_alpha(tw,.2)
Return tw
Case 2
dir#=.01
For n = 1 To 30
If n=1
tw.twirlyT = create_twirly(n*.01,5,.2)
Else
add_twirly_layer(tw,n*.1,10,.3)
EndIf
set_layer_rotate(tw,n-1,dir*n)
dir = -dir
Next
set_twirly_clut(tw,2,2,1)
set_twirly_blend(tw,3)
set_twirly_alpha(tw,.2)
Return tw
Case 3
dir#=.01
For n = 1 To 30
If n=1
tw.twirlyT = create_twirly(n*.01,5,.2)
Else
add_twirly_layer(tw,n*.1,5,.3)
EndIf
set_layer_rotate(tw,n-1,dir*n)
Next
set_twirly_clut(tw,2,2,1)
set_twirly_blend(tw,3)
set_twirly_alpha(tw,.2)
Return tw
End Select

End Function


;
; Hides a Twirly from view. Ignores if Twirly is already hidden.
;
; Params:
; twirly - The Twirly to hide from view.
;
Function hide_twirly(twirly.twirlyT)

If twirlyhidden = False
HideEntity twirlypiv
twirlyhidden = True
End If

End Function


;
; Makes a hidden Twirly visible. Ignores if Twirly is already visible.
;
; Params:
; twirly - The hidden Twirly to make visible.
;
Function show_twirly(twirly.twirlyT)

If twirlyhidden = True
ShowEntity twirlypiv
twirlyhidden = False
End If

End Function


;
; Sets a given twirly layer to an absolute rotation.
;
Function rotate_twirly_layer(twirly.twirlyT,layer%,rot#)

star.twirly_layerT = Object.twirly_layerT(PeekInt(twirlylayer_bank,layer*4))
RotateEntity starent,0,0,rot,1

End Function


;
; Sets how much a given twirly layer should rotate by every update.
;
Function set_layer_rotate(twirly.twirlyT,layer%,rot#)

star.twirly_layerT = Object.twirly_layerT(PeekInt(twirlylayer_bank,layer*4))
starot = rot

End Function


;
; Debug function to visually display CLUT(s).
;
; Params:
; cx   - Screen X coord to display CLUT at.
; cy   - Screen Y coord to display CLUT at.
; clut - Number of CLUT to display.
;        If not specified (default) then all CLUTS are displayed.
;
Function show_clut(cx%=0,cy%=0,clut%=-1)

Local cxs = cx
Local cw = 10
Local ch = 10
Local gap = 0

If clut = -1
first_clut = 0
last_clut = num_cluts - 1
Else
first_clut = clut
last_clut = clut
EndIf

For n = first_clut To last_clut
clut = clut_banks(n)

For j = 0 To BankSize(clut)-1 Step 12
r = PeekInt(clut,j)
g = PeekInt(clut,j+4)
b = PeekInt(clut,j+8)
Color r,g,b
Rect cx,cy,cw,ch,1
cx = cx + cw + gap
If (cx+cw-1)>=GraphicsWidth() Then cx=cxs:cy=cy+ch+gap
Next

cx = cxs
cy = cy + ch + 4
Next

Color 255,255,255

End Function


;
; Display debug info.
;
Function show_info()

If fps_timeout
frame_count = frame_count + 1

If MilliSecs() > fps_timeout Then
fps_timeout = MilliSecs() + 1000
fps = frame_count
frame_count = 0

If fps < slowest_fps Or slowest_fps = 0 Then slowest_fps = fps
EndIf

If frame_time > slowest_frame Then slowest_frame = frame_time

Color 0,255,0
Text 10,10," Triangles: " + TrisRendered()
Color 255,255,0
Text 10,25," Millisecs: " + frame_time
Text 10,40,"   Slowest: " + slowest_frame
Color 0,255,255
Text 10,55,"       FPS: " + fps
Text 10,70,"     Worst: " + slowest_fps
Color 255,255,255
Else
; First call initialization.
fps_timeout = MilliSecs() + 1000
EndIf

End Function


Comments :


Clyde(Posted 1+ years ago)

 Wicked stuff there mate!


Rook Zimbabwe(Posted 1+ years ago)

 This has to be the coolest thing!


big10p(Posted 1+ years ago)

 Crikey, this is an old one. Glad you like it, though. :)


Yo! Wazzup?(Posted 1+ years ago)

 Oooohhhhh... pretty lights...