Optimising Particles - Pooling etc.

BlitzMax Forums/BlitzMax Programming/Optimising Particles - Pooling etc.

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

I'm using lists as well. 2 actually. One for the active particles and one for the pool which has a logic within to reduce the pool size over the time
Interesting idea, so this helps to remove the slow memory allocation for creating and destroying types over and over.

hmmm, this is what the link I posted above does for you automatically. in your code, you just do
list.AddLast()
it takes it from the pool and does your own clean routine *or* if there are none in the pool, it will create a new instance.
(you have to create and init and create function in your type as per the example)

but if you want the fastest and easiest to use.... your BEST bet is to embed a simple single (or double)linked list in your particle type. it's not a TList, all you do is have a global which points to the first particle. each particle points to the next one. that's it. this will be as fast as arrays. add a pool pointer and you remove the memory allocation.

now if you implement a double linked list then you can remove any particle at any time. if you just do a single list then you can only remove when you are normally processing the list (since you need to know the previous particle )which is all you need for particles.

here's impixi's example modified
 
'Particle System Test
'Particle pool list and live particle list

SuperStrict

Framework BRL.GLMax2D
'Framework BRL.D3D7Max2D

Import BRL.Random
Import BRL.PNGLoader

Global ScreenWidth:Int = 800
Global ScreenHeight:Int = 600

Graphics ScreenWidth, ScreenHeight
TParticle.Init 2000, "c:\program files\blitzmax\samples\birdie\games\tiledrop\media\part.png"

Local Renders:Int, FPS:Int
Local CurrentMS:Int, OldMS:Int
Local MemAlloced:Int = GCMemAlloced()

SetBlend ALPHABLEND

While Not KeyHit(KEY_ESCAPE)

	Cls

	TParticle.RenderLive
	
	If MouseDown(MOUSE_LEFT) Then For Local i:Int = 0 To 10; TParticle.Spawn MouseX(), MouseY();Next
	
	If KeyHit(KEY_M) Then MemAlloced = GCMemAlloced()
	
	SetColor 255, 255, 255
	SetAlpha 1.0
	SetScale 1.0, 1.0
		
	Renders :+ 1
	CurrentMS = MilliSecs()	
		
	If (CurrentMS - OldMS) >= 1000
		OldMS = CurrentMS
		FPS = Renders
		Renders = 0
	EndIf

	DrawText FPS + " FPS", 10, 10
	DrawText "Memory: " + MemAlloced + " bytes", 10, 30
	DrawText "Live particles: " + TParticle.LiveCount, 10, 70
	DrawText "M - Memory useage. LEFT CLICK - spawn new particle.", 10, GraphicsHeight() - 30
	
	Flip 0

Wend


End


Type TParticle


	Const STATUS_DEAD:Int = 0
	Const STATUS_LIVE:Int = 1

	Global ParticlePool:TParticle
	Global LiveParticles:TParticle
	Global LiveCount:Int
	
	Global ParticleImage:TImage

	
	Function Init(qty:Int, img_url:String= "")
	
		Local pixmap:TPixmap = LoadPixmap(img_url)
		If pixmap Then 
			Pixmap = ResizePixmap(pixmap, 64, 64) 				
			ParticleImage = LoadImage(pixmap)
		Else
			ParticleImage = createSprite()
		EndIf 

		For Local n:Int = 1 To qty
			Local p:TParticle = New TParticle
			p.NextParticle = ParticlePool
			ParticlePool = p
		Next
		
		LiveCount = 0
		
		pixmap = Null
		GCCollect
		
	EndFunction
	
	
	Function Spawn(x:Int, y:Int)
			
		Local p:TParticle = Null	
			
		If ParticlePool <> Null
			
			p = ParticlePool
			ParticlePool = p.NextParticle
				
			p.X = x
			p.Y = y
			p.XDir = Rnd(-0.15, 0.15)
			p.YDir = Rnd(-0.15, 0.15)
			p.R = Rand(32, 255)
			p.G = Rand(32, 255)
			p.B = Rand(32, 255)
			p.Size = Rnd(0.1, 0.5)
			p.Alpha = 1.0
						
			p.NextParticle = LiveParticles
			LiveParticles = p
					
			LiveCount :+ 1

		EndIf
			
	EndFunction
	
	
	Function RenderLive()
		
		Local lp:TParticle
		Local np:TParticle
		Local p:TParticle = LiveParticles
		While p
			np = p.NextParticle
			If p.Render() = STATUS_DEAD 
				If lp
					lp.NextParticle = p.NextParticle
				Else
					LiveParticles = p.NextParticle
				EndIf
				p.NextParticle = ParticlePool
				ParticlePool = p
				LiveCount :- 1
			Else
				lp = p
			EndIf
			p = np
		Wend
		
	EndFunction
	
	
	'-------------------------------------
	
	
	Field X:Float, Y:Float
	Field XDir:Float, YDir:Float
	Field R:Byte, G:Byte, B:Byte
	Field Size:Float
	Field Alpha:Float
	Field NextParticle:TParticle

	Method Render:Int()
	
		SetColor R, G, B
		SetAlpha Alpha
		
		X :+ XDir
		Y :+ YDir
				
		SetScale Size, Size
		DrawImage ParticleImage, X, Y
	
		Alpha :- 0.0005
	
		Local Dead:Int = False
		
		If Alpha <= 0.0 Then Dead = True
		If X < 0 Or X > ScreenWidth Then Dead = True
		If Y < 0 Or Y > ScreenHeight Then Dead = True

		If Dead Then Return STATUS_DEAD Else Return STATUS_LIVE

	EndMethod


EndType


Function CreateSprite:TImage()

	Local size:Int = 64

	Local img:TImage = CreateImage(size, size, 1, DYNAMICIMAGE|MASKEDIMAGE)
	
	SetBlend SOLIDBLEND
	SetColor 255, 255, 255
	DrawOval 0, 0, Size, Size	
	
	GrabImage(img, 0, 0)

	Return img

EndFunction