BBC BASIC
« Quest for fire library (group effort ) »
Welcome Guest. Please Login or Register. Mar 31st, 2018, 11:12pm
ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018. We apologize Conforums does not have any export functions to migrate data. Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.
Thank you Conforums members.
Cross-platform BBC BASIC (Windows, Linux x86, Mac OS-X, Android, iOS, Raspberry Pi)
Quest for fire library (group effort )
« Thread started on: Dec 21st, 2017, 5:35pm »
I offer a challenge to everyone to create some fire animations.. Sprite animations are ok and so are code/graphics based.. ( I am not sure about sprites on BBCSDL, but there is the commands for saving graphics areas and displaying them with OSCLI.
If you want to add your creation to a image library let me know.
I offer a challenge to everyone to create some fire animations.
Here's my offering, in 100% BBC BASIC code for BBCSDL (32-bit and 64-bit) or BB4W. In BBCSDL it uses the built-in spatial filtering provided by OpenGL whereas in BB4W I've used GDI+ to do it. A proper 'blurring' filter would give better results, but be considerably more work (especially in a cross-platform context). The code is listed below.
Richard.
Code:
REM Simple BBC BASIC fire simulation for BBCSDL or BB4W REM by Richard Russell, 27th December 2017 IF INKEY$(-256) = "W" THEN INSTALL @lib$ + "GDIPLIB" PROC_gdipinit SYS "GetModuleHandle", "GDIPLUS.DLL" TO gdip% SYS "GetProcAddress", gdip%, "GdipCreateBitmapFromGdiDib" TO `GdipCreateBitmapFromGdiDib` SYS "GetProcAddress", gdip%, "GdipDrawImageRectI" TO `GdipDrawImageRectI` SYS "GetProcAddress", gdip%, "GdipDisposeImage" TO `GdipDisposeImage` ENDIF MODE 8 : OFF ON CLOSE OSCLI "refresh on" : PROCcleanup : QUIT ON ERROR OSCLI "refresh on" : PROCcleanup : CLS : PRINT REPORT$ : END Width% = 16 : REM Must be multiple of 4 Height% = 32 nParticles% = Width% * Height% * 2 REM Create bitmap: DIM BMP{bfType{l&,h&}, bfSize%, bfReserved%, bfOffBits%, \ \ biSize%, biWidth%, biHeight%, biPlanes{l&,h&}, biBitCount{l&,h&}, \ \ biCompression%, biSizeImage%, biXPelsPerMeter%, biYPelsPerMeter%, \ \ biClrUsed%, biClrImportant%, palette%(255), p&(Height%-1,Width%-1)} REM Initialise bitmap: BMP.bfType.l& = ASC"B" BMP.bfType.h& = ASC"M" BMP.bfSize% = DIM(BMP{}) BMP.bfOffBits% = ^BMP.p&(0,0) - BMP{} BMP.biSize% = 40 BMP.biWidth% = Width% BMP.biHeight% = Height% BMP.biPlanes.l& = 1 BMP.biBitCount.l& = 8 REM Set palette: FOR index% = 0 TO 255 r% = index% << 2 : IF r% < 0 r% = 0 ELSE IF r% > &FF r% = &FF g% = (index% - 96) << 2 : IF g% < 0 g% = 0 ELSE IF g% > &FF g% = &FF b% = (index% - 192) << 2 : IF b% < 0 b% = 0 ELSE IF b% > &FF b% = &FF BMP.palette%(index%) = &FF000000 OR (r% << 16) OR (g% << 8) OR b% NEXT REM Create and initialise particles: DIM p{(nParticles%-1) x,y,d,s,c&} FOR I% = 0 TO nParticles%-1 p{(I%)}.x = Width%/2 p{(I%)}.c& = RND(255) NEXT REM Animate fire: *REFRESH OFF REPEAT BMP.p&() = STRING$(Width%*Height%-1, CHR$0) FOR I% = 0 TO nParticles%-1 PROCupdate(p{(I%)}) NEXT IF INKEY$(-256) = "W" THEN PROCrender(BMP{},192,0,256,512) WAIT 1 ELSE OSCLI "mdisplay " + STR$~BMP{} + " 384,0,512,1024" ENDIF *REFRESH UNTIL FALSE END DEF PROCupdate(p{}) LOCAL a, I% p.x += p.s * SIN(p.d) p.y += p.s * COS(p.d) p.d += (RND(1) - 0.5) / 20 p.c& -= 1 IF p.c& = FALSE OR p.y >= Height% OR p.x < 0 OR p.x >= Width% THEN I% = RND(Width%-2) p.x = I% p.y = 0 p.d = 0 p.s = (RND(1) + 1) * Height% / 128 a = (Width% - I%*2)/Width% p.c& = (1 - ABSa) * 64 + 1 ENDIF I% = ^BMP.p&(p.y,p.x) ?I% = FNclip(?I% + p.c&) ENDPROC DEF FNclip(P%) = P% OR (P% > &FF) DEF PROCrender(bmp{}, X%, Y%, W%, H%) LOCAL B% SYS `GdipCreateBitmapFromGdiDib`, bmp{}+14, bmp{}+bmp.bfOffBits%, ^B% SYS `GdipDrawImageRectI`, FN_gdipg, B%, X%, Y%, W%, H% SYS `GdipDisposeImage`, B% SYS "InvalidateRect", @hwnd%, 0, 0 ENDPROC DEF PROCcleanup IF INKEY$(-256) = "W" PROC_gdipexit ENDPROC
Re: Quest for fire library (group effort )
« Reply #3 on: Dec 28th, 2017, 12:23am »
That's very nice. David Williams contributed quite a few samples also..
I think perhaps a resizable fire for dungeons would be an asset..
As I recall, fire has been a huge part of pretty well any game that involves adventure or role play or multiplayer role play. Fire could make a dungeon made with lines have depth and feeling.
Logged
I like reinventing the wheel, but for now I will work on tools for D3D
I think perhaps a resizable fire for dungeons would be an asset..
I'm not too sure how it could be any more 'resizable' than it is now, given that the last two parameters of the *mdisplay or PROCrender calls are the width and height! Can you explain?
Re: Quest for fire library (group effort )
« Reply #6 on: Jan 2nd, 2018, 1:50pm »
I had a play with this. I make no claims that it is any better than previous offerings...
Seems to run OK in BB4W and in BBC_SDL, though rather slower in the latter - you might want to change the WAIT to 5, or even 1.
I have thought about converting it to use D3D (or equivalent): then you could blend colours for the triangles, and make them semi-transparent, so you could see the firewood through them. I'm not sure what will happen if I try to rewrite the vertex buffers dynamically - it may cause a spectacular crash... Does anyone know?
Best wishes,
D Code:
MODE 21 *REFRESH OFF GCOL 3 FOR duration%=0 TO 100 CLS PROCDrawLog(180,420,-30,100,320) PROCDrawLog(200,370,0,80,340) PROCDrawLog(240,330,30,90,320) PROCDrawFlame(430,420,210,500) PROCDrawFlame(300,400,210,400) PROCDrawFlame(500,400,210,400) PROCDrawFlame(400,300,210,300) PROCDrawLog(780,420,-30,30,120) PROCDrawLog(800,370,0,25,140) PROCDrawLog(840,330,30,30,120) PROCDrawFlame(830,420,50,70) PROCDrawFlame(800,400,50,70) PROCDrawFlame(900,400,50,70) PROCDrawFlame(850,350,50,85) *REFRESH WAIT 10 NEXT duration% *REFRESH ON END : DEFPROCDrawLog(px%,py%,a%,w%,l%) COLOUR 3,50,30,0 MOVE px%,py% MOVE px%+w%*COSRAD(a%+90),py%+w%*SINRAD(a%+90) PLOT 117,px%+l%*COSRAD(a%)+w%*COSRAD(a%+90),py%+l%*SINRAD(a%)+w%*SINRAD(a%+90) ENDPROC : DEFPROCDrawFlame(px%,py%,w%,h%) LOCAL x%,hw%,dw%,dh%,f%() DIM f%(26,2) hw%=w%/2 dw%=hw%*0.8 dh%=h%/25 FOR x%=0 TO 25 f%(x%,1)=px%+RND(x%) f%(x%,0)=f%(x%,1)-hw%+ABS(dw%-dw%*SQR(x%)/2.5)+RND(x%)*hw%/100 f%(x%,2)=f%(x%,1)+hw%-ABS(dw%-dw%*SQR(x%)/2.5)-RND(x%)*hw%/100 NEXT x% f%(26,1)=px%+RND(x%) f%(26,0)=f%(26,1) f%(26,2)=f%(26,1) GCOL 3 FOR x%=0 TO 25 COLOUR 3,200+x%,150-2*x%,26-x% MOVE f%(x%,1),x%*dh%+py% MOVE f%(x%+1,1),(x%+1)*dh%+py% PLOT 85,f%(x%,0),x%*dh%+py% PLOT 85,f%(x%+1,0),(x%+1)*dh% +py% MOVE f%(x%,1),x%*dh%+py% MOVE f%(x%+1,1),(x%+1)*dh%+py% PLOT 85,f%(x%,2),x%*dh%+py% PLOT 85,f%(x%+1,2),(x%+1)*dh%+py% COLOUR 3,220+x%,220-2*x%,70-x% MOVE f%(x%,1),x%*dh%+py% MOVE f%(x%+1,1),(x%+1)*dh%+py% PLOT 85,(f%(x%,0)+f%(x%,1))/2,x%*dh%+py% PLOT 85,(f%(x%+1,0)+f%(x%+1,1))/2,(x%+1)*dh% +py% MOVE f%(x%,1),x%*dh%+py% MOVE f%(x%+1,1),(x%+1)*dh%+py% PLOT 85,(f%(x%,2)+f%(x%,1))/2,x%*dh%+py% PLOT 85,(f%(x%+1,2)+f%(x%+1,1))/2,(x%+1)*dh% +py% NEXT x% ENDPROC
I had a play with this. I make no claims that it is any better than previous offerings...
I'd call it a 'flame' rather than a 'fire' I think.
Quote:
Seems to run OK in BB4W and in BBC_SDL, though rather slower in the latter
Interesting: it runs slightly faster in BBCSDL than in BB4W on this laptop (about 10% CPU for BBCSDL and 11% for BB4W). That makes me suspect that the OpenGL acceleration on your PC isn't all that hot, which is a shame because it's going to hit BBCSDL graphics performance across the board.
Re: Quest for fire library (group effort )
« Reply #9 on: Jan 3rd, 2018, 3:18pm »
Hi Richard,
Assuming it might be rash, but in this case it is true...
When I say it "runs slower", I didn't look at the CPU usage, or frame rate or anything, just a subjective impression that the "flickering" was more laboured.
Your comment about OpenGL acceleration is probably pertinent: it's an oldish corporate PC, and I doubt if pushing the latest OpenGL drivers is high on their list of priorities...
I didn't look at the CPU usage, or frame rate or anything, just a subjective impression that the "flickering" was more laboured.
You have to be careful what you are comparing because your program uses *REFRESH, which works differently in BB4W and BBCSDL. In BB4W *REFRESH is an asynchronous command which simply sets a flag to tell Windows to update the display when it next 'gets around to it' (Windows doesn't synchronise its update with the display refresh unless you do it yourself using e.g. Direct Draw).
In BBCSDL, on the other hand, *REFRESH is a synchronous command which waits until the next display refresh (vertical sync) before returning. So, typically, it's necessary in BB4W to include a WAIT statement to prevent a program gobbling up 100% CPU, whereas in BBCSDL it waits in *REFRESH (whether it waits efficiently, with low CPU usage, or busy-waits with high CPU usage is a function of the platform and its drivers, and is out of your control).
So my cross-platform programs tend to have a code snippet such as this:
Re: Quest for fire library (group effort )
« Reply #12 on: Jan 11th, 2018, 08:48am »
Hi Folks,
Well, I did have a go at doing it in D3D. It's proved harder than I hoped to get nice transparency effects - I can't seem to get it to show the logs through the flames, for example, and I don't think I understand emissivity properly! Anyway, I think the Gouraud shading makes the flames look quite nice, and they DO overlap each other...
Here's the code for the "flames" bit. It requires an FVF file for the logs: I'll post code for that separately in a moment.
At the moment this is written specifically for BB4W, and Windows, since it uses a number of D3D SYS calls. I don't know how to do the equivalent in SDL, but I'd be interested to see a conversion! I presume a lot of the stuff with FVF buffers should be fairly straightforward to convert.
Best wishes,
D Code:
HIMEM=LOMEM+1E8 MODE 21 nbufs%=4 REM Here I'm actually reserving arrays 1 BIGGER than nbufs% (i.e. 0 - nbufs%), which gives me one for background scene - here, the logs DIM l%(nbufs%), b%(nbufs%), n%(nbufs%), f%(nbufs%), s%(nbufs%), m%(nbufs%), t%(nbufs%), y(nbufs%), p(nbufs%), r(nbufs%), X(nbufs%), Y(nbufs%), Z(nbufs%), e(2), a(2) INSTALL @lib$+"D3DLIBA" ON CLOSE PROCcleanup(nbufs%):QUIT ON ERROR PROCcleanup(nbufs%):PRINT REPORT$:END d% = FN_initd3d(@hwnd%, 1, 1) IF d% = 0 ERROR 100, "Can't initialise Direct3D" REM David's attempt to set alpha blending SYS !(!d%+200),d%,27,1:REM SetRenderState(Alphablendenable) SYS !(!d%+200),d%,19,5:REM SetRenderState( set source blend to D3DBLEND_SRCALPHA) SYS !(!d%+200),d%,20,6:REM SetRenderState(set destination blend to D3DBLEND_INVSRCALPHA) SYS !(!d%+200),d%,148,1:REM SetRenderState(set emissive materialcoloursource to "diffuse vertex colour") DIM l%(0) 103 l%(0)!0 = 3 : REM directional light, taken from manual (parameters adjusted) l%(0)!4 = FN_f4(1) : REM red component l%(0)!8 = FN_f4(1) : REM green component l%(0)!12 = FN_f4(1) : REM blue component l%(0)!64 = FN_f4(0.5) : REM. X component of direction l%(0)!68 = FN_f4(-0.50) : REM. Y component of direction l%(0)!72 = FN_f4(0.2) : REM. Z component of direction nv%=26*12 :REM number of layers * 4 triangles (2 on each side between this layer and the next) REM Set up vertex buffers for each flame FOR x%=0 TO nbufs%-1 n%(x%)=nv% f%(x%)=&52 s%(x%)=28 X(x%)=(x%-0.8)/2 Y(x%)=(x% MOD 2)*0.5 b%(x%)=FN_setupVbuf(d%,n%(x%),f%(x%),s%(x%)) IF b%(x%)=0 THEN PROCcleanup(nbufs%):PRINT x%,"Disaster!":END NEXT x% REM Set up vertex buffer by loading the background "scene" - here it's just 3 logs! b%(nbufs%)=FN_load3d(d%,"logs.fvf",n%(nbufs%),f%(nbufs%),s%(nbufs%)) IF b%(nbufs%)=0 THEN PROCcleanup(nbufs%):PRINT "Logs failed to load!":END X(nbufs%)=-0.5 Z(nbufs%)=0.8 p() = 0 :REM No pan/roll/yaw - could be omitted! r() = 0 y()=0 e() = 0,0,-10 :REM Eye/camera position a() = 0, 1, 0 :REM Point you are looking at (centre of screen) FOR duration%=0 TO 100 FOR x%=0 TO nbufs%-1 PROCWriteVBufData(b%(x%),n%(x%),s%(x%),1,2) :REM Re-write the actual vertex data to make flames flicker NEXT x% PROC_render(d%, &FF101010, 1, l%(), nbufs%+1, m%(), t%(), b%(), n%(), f%(), s%(), y(), p(), r(), X(), Y(), Z(), e(), a(), PI/4, 5/4, 1, 1000,0) WAIT 10 NEXT duration% PROCcleanup(nbufs%) END : DEF FN_setupVbuf(D%,N%,V%,L%) :REM Adapted from D3DLib (as some of the other D3D stuff!) LOCAL B%,R% SYS!(!D%+92),D%,N%*L%,0,V%,0,^B% TO R%:REM CreateVertexBuffer IF R% THEN=0 =B% : DEFPROCWriteVBufData(B%,N%,L%,w,h) LOCAL P%,vb% LOCAL x%,n%,n2%,c1%,c2%,dc%,hn,hw,dw,f() n%=5 :REM you can change this to change the shape/detail of the flame - there will be n%^2 layers. REM If you make n% more than 5, you may need to increase the memory reserved at the beginning, or it will crash! n2%=n%^2 hn=n%/2 DIM f(n2%+1,2) hw=w/2 dw=hw*0.8 FOR x%=0 TO n2% f(x%,1)=RND(x%)/(4*n2%) f(x%,0)=f(x%,1)-hw+ABS(dw-dw*SQR(x%)/hn)+RND(x%)*hw/(8*n2%) f(x%,2)=f(x%,1)+hw-ABS(dw-dw*SQR(x%)/hn)-RND(x%)*hw/(8*n2%) NEXT x% f(n2%+1,1)=RND(n2%)/(2*n2%) f(n2%+1,0)=f(n2%+1,1) f(n2%+1,2)=f(n2%+1,1) SYS!(!B%+44),B%,0,N%*L%,^P%,0:REM pVB::Lock vb%=P% :REM vb% is a pointer to where we have got to in the buffer dc%=(1<<16)-(2<<8)-1 :REM calculate difference in colour for one level higher FOR x%=0 TO n2% REM Calculate colours for edge and centre of the flame at this level c1%=((160+x%)<<16)+((130-2*x%)<8)+26-x% +(&80<<24) c2%=((190+x%)<<16)+((158-x%)<<8)+55-x% +(&80<<24) REM write data for the trapezium between this level and the next REM 4 triangles, two from the left edge to the centre, and two from the right edge to the centre PROCDoPoint(f(x%,0),x%*h/(n2%+1),0,c1%,vb%) PROCDoPoint(f(x%+1,1),(x%+1)*h/(n2%+1),0,c2%-dc%,vb%) PROCDoPoint(f(x%,1),x%*h/(n2%+1),0,c2%,vb%) PROCDoPoint(f(x%,0),x%*h/(n2%+1),0,c1%,vb%) PROCDoPoint(f(x%+1,0),(x%+1)*h/(n2%+1),0,c1%-dc%,vb%) PROCDoPoint(f(x%+1,1),(x%+1)*h/(n2%+1),0,c2%,vb%) PROCDoPoint(f(x%,2),x%*h/(n2%+1),0,c1%,vb%) PROCDoPoint(f(x%,1),x%*h/(n2%+1),0,c2%,vb%) PROCDoPoint(f(x%+1,1),(x%+1)*h/(n2%+1),0,c2%-dc%,vb%) PROCDoPoint(f(x%,2),x%*h/(n2%+1),0,c1%,vb%) PROCDoPoint(f(x%+1,1),(x%+1)*h/(n2%+1),0,c2%-dc%,vb%) PROCDoPoint(f(x%+1,2),(x%+1)*h/(n2%+1),0,c1%-dc%,vb%) NEXT x% SYS!(!B%+48),B%:REM pVB::Unlock ENDPROC : DEFPROCDoPoint(x,y,z,c%, RETURN vb%) REM Here are the coordinates of the point !vb%=FN_f4(x) vb%!4=FN_f4(y) vb%!8=FN_f4(z) REM Now need normals! Assume all points are flat in the plane,so normal faces towards Z vb%!12=FN_f4(0.0) vb%!16=FN_f4(0.0) vb%!20=FN_f4(1.0) REM Now the colour vb%!24=c% vb%+=28 :REM Update pointer. I do it here so it's easy to change if you change the vertex size ENDPROC : DEF PROCcleanup(nbufs%) : REM From example, slightly amended to allow for multiple buffers LOCAL x% FOR x%=0 TO nbufs% t%(nbufs%) += 0:IF t%(nbufs%) PROC_release(t%(nbufs%)) b%(nbufs%) += 0:IF b%(nbufs%) PROC_release(b%(nbufs%)) b%(nbufs%) += 0:IF b%(nbufs%) PROC_release(b%(nbufs%)) NEXT x% d% += 0 :IF d% PROC_release(d%) ENDPROC
Re: Quest for fire library (group effort )
« Reply #13 on: Jan 11th, 2018, 09:04am »
Here's the code for the logs: you'll need my Make3DLib, which I actually keep in my D3D folder: amend the INSTALL address accordingly.
Make3DLib is available in the files area on the groups.io site: if you give me a couple of minutes I'll update the version there to make sure it is the current one.
SDL is 2D only (I assume you're relying on the third dimension, otherwise you wouldn't be using D3DLIB - unless you want it solely for transparency in which case GDIPlus might be easier).
For 3D stuff in BBCSDL you need to use OpenGL (which is generally more straightforward than Direct3D because of the 'flat' interface); there's no shortage of documentation online. For enabling alphablending you can look at 'bbcowl.bbc' which relies on it I think.
Mind you I'm not sure that you will find a direct OpenGL equivalent of 'set emissive materialcoloursource to "diffuse vertex colour"' (without coding a shader) - and Google doesn't help.