Here's some of my code (full lib too big) which uses fire-creation code from someone else (see efxFireFlame()). Basically it is using a mem buffer which is the bitmap for an opengl texture, drawn using code such as the proc shown first. I use it to create a fire effect on a large monitor *inside* a large 3D scene. This method should be much quicker. The code is complete in function, ie, your own codes needs to provide the opengl context and a textured poly.
PS: The FireEffect "module" uses code in one of my other "modules" but it should be fairly easy to figure out and replace with your own code. Poss only at one point, eg, "memResize(fire\firetex, fire\s)" in efxTextureInit() because I use instrumented memory allocation (for bug hunting).
(actually efxTextureSet() below may do the above. I haven't looked at this code in a while)
Code: Select all
;-STRUCTURES
;-S firetexT
Structure firetexT
w.l: h.l ; Texture Width, Height
t.l ; Type of dynamic texture to create
s.l ; Size of texture data (bytes)
firetex.l ; Main texture buffer
fba1.l ; Fire Buffer Address 1
fba2.l ; Fire Buffer Address 2
cx.l: cy.l ; Fire buffer width, height
pal.rgbaBT[256] ; Palette
EndStructure
;-GLOBALS
Global fire.firetexT
;-PG
Procedure efxTextureInit(w.l, h.l)
Shared fire.firetexT
If w<=64 : fire\w=64
ElseIf w<=128: fire\w=128
Else : fire\w=256
EndIf
If h<=64 : fire\h=64
ElseIf h<=128: fire\h=128
Else : fire\h=256
EndIf
; Allocate memory for texture data buffer
fire\s = fire\w * fire\h * 4 ; Texture format is RGBA (4 bytes)
fire\firetex = memResize(fire\firetex, fire\s)
; To set alpha bit's (colour bits will be overwrote anyway)
RtlFillMemory_(fire\firetex, fire\s, $FF)
EndProcedure
Procedure efxTextureSet(filter.l)
; Set current texture with specified filter.
Shared fire.firetexT
Select filter
Case 0; MIPMAPPING:
glTexParameterf_(#GL_TEXTURE_2D, #GL_Texture_Mag_Filter, #GL_LINEAR);
glTexParameteri_(#GL_TEXTURE_2D, #GL_Texture_Min_Filter, #GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps_(#GL_TEXTURE_2D, 3, fire\w, fire\h, #GL_RGB, #GL_UNSIGNED_BYTE, fire\firetex)
Case 1; NEAREST:
glTexParameterf_(#GL_TEXTURE_2D, #GL_Texture_Mag_Filter, #GL_NEAREST)
glTexParameterf_(#GL_TEXTURE_2D, #GL_Texture_Min_Filter, #GL_NEAREST)
Case 2; LINEAR:
glTexParameterf_(#GL_TEXTURE_2D, #GL_Texture_Mag_Filter, #GL_LINEAR)
glTexParameterf_(#GL_TEXTURE_2D, #GL_Texture_Min_Filter, #GL_LINEAR)
EndSelect
glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGBA, fire\w, fire\h, 0, #GL_RGBA, #GL_UNSIGNED_BYTE, fire\firetex)
EndProcedure
Procedure efxShadePalette(sbeg.l, send.l, r1.l, g1.l, b1.l, r2.l, g2.l, b2.l)
Protected interval.f, dr.f, dg.f, db.f, k.f
Protected i.l, r.l, g.l, b.l
If sbeg >= send: ProcedureReturn: EndIf
interval.f = send - sbeg + 0.0
dr.f = (r2-r1+0.0)/interval
dg.f = (g2-g1+0.0)/interval
db.f = (b2-b1+0.0)/interval
For i = sbeg To send
k.f = i-sbeg+0.0
r=r1+dr*k: g=g1+dg*k: b=b1+db*k
fire\pal[i]\r=r: fire\pal[i]\g=g: fire\pal[i]\b=b
fire\pal[i]\a = (r+g+b)/3
Next
EndProcedure
;**********************************************************
;* FIRE TEXTURE *
;**********************************************************
Procedure efxFireInitPalette()
; Prepare custom palette.
efxShadePalette( 0, 64, 0, 0, 0, 255, 51, 36);
efxShadePalette( 64, 96, 255, 51, 36, 255, 189, 51);
efxShadePalette( 96, 128, 255, 189, 51, 255, 237, 51);
efxShadePalette(128, 196, 255, 237, 51, 100, 100, 189);
efxShadePalette(196, 255, 100, 100, 189, 255, 231, 51);
EndProcedure
Procedure efxFireInit(w.l, h.l)
Shared fire.firetexT
Protected bufsize.l
efxTextureInit(w, h)
fire\cx = fire\w ;
fire\cy = fire\h+3; we stay 3 lines to put random points.
bufsize = fire\cx * fire\cy
; allocate memory for fire buffers.
fire\fba1 = memResize(fire\fba1, bufsize)
fire\fba2 = memResize(fire\fba2, bufsize)
efxFireInitPalette()
ProcedureReturn
; For testing: Display palette (assumes 128x128)
Protected pba0.l, cpa0.l, cpn.l, cpa1.l, px.l
pba0 = fire\firetex
cpa0 = @fire\pal[0]
For cpn = 0 To 255 Step 2
cpa1 = cpa0 + 4*cpn
;cpa2 = cpa0 + 4*(cpn+128)
For px = 0 To 127
CopyMemory(cpa1, pba0 + cpn*128*2 + px*4, 4)
;CopyMemory(cpa2, pba0 + cpn*128*4 + (px+64)*4, 4)
Next
Next
EndProcedure
Procedure efxFireFuel(f.l)
; To keep the fire burning...
Shared fire.firetexT
Protected mp.l, np.l, p0.l, p1.l, i.l, o.l
Protected c.b
;MinPoints = ft_w >> 2
;MaxPoints = MinPoints + Random(ft_w-1) ; max number random spots.
mp = 3*fire\w ; Max number of points (= extra 3 lines)
np = mp >> f ; Number of points (binary scaled by f)
p0 = np >> 1 ; Always at least half number of points
p1 = p0 + Random(p0-1) ; So p0..2*p0 random points.
For i = 1 To p1
o = Random(mp) ; Somewhere in extra three lines
c.b = Random(255) ; Random colour (from palette)
;c.b = Random(223)+32 ; Random colour (from palette)
PokeB(fire\fba1 + o, c)
Next
EndProcedure
Procedure efxFireSparks(n.l)
; For random sparks...
Shared fire.firetexT
Protected hh.l, i.l, x.l, y.l
Protected c.b
hh = fire\h >> 2: ; Qtr height
For i = 1 To n
x = Random(fire\w-1)
y = hh + Random(hh-1); Put somewhere in second qtr
c.b = 128+Random(127)
PokeB(fire\fba1 + y * fire\w + x, c)
Next
EndProcedure
Procedure efxFireFlame()
; the following lines to burn the fire,
; method from Alex Champandard's tutorial "The art of demomaking"
; URL: http://www.flipcode.com/demomaking/
; "09/20/99 - Issue 05 - Filters"
Shared fire.firetexT
Protected h.l, w.l, y.l, o.l, x.l, c.l
h = fire\cy-3
w = fire\cx-1
For y=0 To h-1
o = y*fire\cx + 2*fire\cx
;o = y*fire\cx + fire\cx
PokeB(fire\fba2 + o, 0)
For x = 1 To w-1
o+1
c = 0
;c = PeekB(fire\fba1 + o)
; Line 0
c = c + 255 & PeekB(fire\fba1 + o - 1)
c = c + 255 & PeekB(fire\fba1 + o + 1)
; Line -1
c = c + 255 & PeekB(fire\fba1 + o - fire\cx - 1)
c = c + 255 & PeekB(fire\fba1 + o - fire\cx)
c = c + 255 & PeekB(fire\fba1 + o - fire\cx + 1)
; Line -2
c = c + 255 & PeekB(fire\fba1 + o - 2*fire\cx - 1)
c = c + 255 & PeekB(fire\fba1 + o - 2*fire\cx)
c = c + 255 & PeekB(fire\fba1 + o - 2*fire\cx + 1)
;c = c/5
c = c >> 3
;ci = 255 & c
;c = (c & 255) >> 3;
If c: c-1: EndIf
PokeB(fire\fba2 + o, c)
Next
o+1
PokeB(fire\fba2 + o, 0)
Next
EndProcedure
Procedure.l efxFireRender(vaw.l, vah.l) ; Returns data address
; Render a fire texture.
Shared fire.firetexT
Protected pc.l, sa.l, da.l, fba.l, i.l, c.l, t.l
pc = fire\w * fire\h
efxFireFuel(2)
;efxFireSparks(5)
efxFireFlame() ; Cost ~ 9 FPS
; Cost ~ 0 FPS
sa = @fire\pal[0]
da = fire\firetex
;dst = ft_s - 4
;fba = ft_fba2
fba = fire\fba2 + fire\w*3
For i = 0 To pc-1
c = PeekB(fba+i) & $FF
CopyMemory(@fire\pal[c], da, 4)
;CopyMemory(sa+c, da, 4)
da+4
Next
t=fire\fba1: fire\fba1=fire\fba2: fire\fba2=t ;Swap buffer pointers
; Assuming texture dims for now...
PokeL(vaw, fire\w): PokeL(vah, fire\h)
ProcedureReturn fire\firetex
EndProcedure