What follows is a draft - it is not debugged, and is missing vital code.
I'm posting this here for suggestions before I finish it up.
Please voice your opinions :)


;Title  - ParticleSystem Object for ObjAsm32
;Author - Evil Homer
;Dated  - 17 July, 2005
;
;A ParticleSystem can be thought of as a Particle Emitter.
;You can attach them to anything, they squirt stuff.
;This ParticleSystem object implementation contains
;some interesting features, particularly its runtime
;capabilities such as overriding the Render method at runtime,
;and the ability to attach and detach Emitters at runtime.
;This opens the possibility for ParticleSystems to be
;attached to Particles owned by another ParticleSystem,
;such that Particles may emit SubParticles during their lifetime.
;Many other interesting possibilities exist.
;
;=================================================
;Data Members (All TIMES are in Floating Seconds)
;=================================================
;
;TimeOfLastEmission (REAL4)
;Time at which the previous Particle Emission occurred
;
;TimeBetweenEmissions (REAL4)
;Period of Time to elapse between Particle Emissions
;
;ParticlesPerEmission (DWORD)
;Maximum Particles to emit during a Particle Emission
;
;LifeTimePerParticle (REAL4)
;Period of Time for which a Particle is "alive"
;
;MaxParticles (REAL4)
;Capacity of the ParticleSystem
;
;pPositionAttach (Pointer to Vec3)
;Pointer to a Vec3 Position to serve as the 3D Origin
;for newly-emitted Particles, ie the Emitter Position.
;As an example use for this field, the Vec3 could
;be a point on any moving object in the world..
;
;Position (Vec3)
;Position of the Particle Emitter when NOT Attached by Position.
;Remembers the Detachment Position.
;
;Force (Vec3)
;Defines the ambient Force to apply to active Particles over Time
;Includes Gravity, and can be used to introduce "wind" effects etc.
;
;Particles
;Pointer to Heap-Allocated memory containing the Particle Array
;
;=================================================
; METHODS
;=================================================
;
;Done
;As usual, this is the Destructor Method, called by the Destroy macro.
;
;Init (MaxParticles,ParticlesPerEmission,TimeBetweenEmissions,
;   LifeTimePerParticle,AppTime)
;This is the Constructor Method, which you must call yourself.
;
;AttachPosition (pPosition=ptr Vec3)
;This method attaches the ParticleSystem to an arbitrary external Vec3
;such that the Emitter is now "glued" in worldspace to this (possibly moving)
;3D Position value.
;
;DetachPosition
;This method detaches the ParticleSystem from its attached Position
;and sets the detachment position as the ParticleSystem (emitter) Position
;such that the Emitter is now "glued" in worldspace at the point of detachment
;
;RenderParticle (pParticle)
;This method , which can be dynamically overidden in derived objects,
;renders a single Particle to the screen.
;The default Method supplied is designed for rendering a textured
;rectangle with alphablending, presumably under Othographic projection.
;
;Reset
;This method sets up Particle Colors and Revives all Particles
;
;ReviveParticle (pParticle)
;This method breathes new life into a "dead" Particle
;
;Update
;This method updates Particle Positions and Velocities over Time
;
Object ParticleSystem,ParticleSystemID,Primer
RedefineMethod  Done
RedefineMethod Init,dword,dword,REAL4,REAL4,REAL4 ;#Particles,ParticlesPerEmission,TimeBetweenEmissions,LifeTimePerParticle,AppTime
StaticMethod AttachPosition,Pointer ;pVec3
StaticMethod DetachPosition
DynamicMethod RenderParticle,Pointer ;pParticle
StaticMethod Reset,REAL4 ;AppTime
StaticMethod ReviveParticle,Pointer ;pParticle
StaticMethod Update,REAL4,REAL4 ;AppTime,ElapsedTime

DefineVariable TimeOfLastEmission,REAL4,0
DefineVariable TimeBetweenEmissions,REAL4,0
DefineVariable ParticlesPerEmission,dword,0
DefineVariable LifeTimePerParticle,REAL4,0
DefineVariable MaxParticles,dword,0
DefineVariable  pPositionAttach,dword,0
DefineVariable  Position,Vec3,{}
DefineVariable Force, Vec3,{}
DefineVariable Particles,dword,0
ObjectEnd

Particle struct
active  dd ?  ; Active (Yes/No)
life REAL4 ? ; Particle Life
fade REAL4 ? ; Fade Speed
r REAL4 ? ; Red Value
g REAL4 ? ; Green Value
b REAL4 ? ; Blue Value
Position Vec3 <>
Velocity Vec3 <>
Particle ends

;Macro to load a "random signed float" onto the fpu
;The random value X is in the Range of -Y> X <+Y
;where Y is a Positive REAL4 Range Limiting Value
;which can be a Named Variable or an immediate float
;Example1 : FLDRndSignedFloat 26.0f
;Example2 : FldRndSignedFloat r4_26_0_f
FLDRndSignedFloat macro t
local we, wa, OYeah1, OYeah2, OYeah
we = 0
wa InStr <t>, <.>
invoke TFRandom
fsub r4_half
if wa ne 0
;We found a DOT so assume its an immediate Float , ie 1.0f
we InStr <t>, <->
if we ne 0
OYeah1 SubStr <t>, we+1, wa-2
OYeah1 CatStr <m>, OYeah1
else
    OYeah1 SubStr <t>, 1, wa - 1
    endif
OYeah2 SubStr <t>, wa + 1   
    OYeah  CatStr <r4_>,OYeah1,<_>,OYeah2
    OYeah1 CatStr <_>,OYeah

%ifndef OYeah1
OYeah1 = 1
%ECHO OYeah REAL4 t
.data
OYeah REAL4 t
.code
endif
fmul OYeah
else
;We found no DOT so assume its the name of a REAL4 variable
fmul t
endif
endm

.data
colors glColor3 {1.0f,0.5f,0.5f},
{1.0f,0.75f,0.5f},
{1.0f,1.0f,0.5f},
{0.75f,1.0f,0.5f},
{0.5f,1.0f,0.5f},
{0.5f,1.0f,0.75f},
{0.5f,1.0f,1.0f},
{0.5f,0.75f,1.0f},
{0.5f,0.5f,1.0f},
{0.75f,0.5f,1.0f},
{1.0f,0.5f,1.0f},
{1.0f,0.5f,0.75f}

Method ParticleSystem.Done,uses esi
SetObject esi
MemFree .Particles
MethodEnd

Method ParticleSystem.Init,uses esi,MaxParticles,ParticlesPerEmission,TimeBetweenEmissions,LifeTimePerParticle,fTime
SetObject esi
m2m .MaxParticles,MaxParticles
m2m .ParticlesPerEmission,ParticlesPerEmission
m2m .TimeBetweenEmissions,TimeBetweenEmissions
m2m .LifeTimePerParticle,LifeTimePerParticle
mov eax,sizeof Particle
mul MaxParticles
mov .Particles,$MemAlloc(eax)
OCall DetachPosition
OCall Reset,fTime
MethodEnd

Method ParticleSystem.AttachPosition,uses esi,pPosition
SetObject esi
m2m .pPositionAttach,pPosition
MethodEnd

Method ParticleSystem.DetachPosition,uses esi
SetObject esi
.if .pPositionAttach!=NULL
mov eax,.pPositionAttach
fld .Vec3.X
fstp .Position.X
fld .Vec3.Y
fstp .Position.Y
fld .Vec3.Z
fstp .Position.Z
mov .pPositionAttach,NULL
.endif
MethodEnd

Method ParticleSystem.Update,uses esi ecx,fAbsoluteTime,fElapsedTime
local ParticlesEmittedThisEmission
local EmissionRequired
local EmissionPerformed

mov ParticlesEmittedThisEmission,0
mov EmissionPerformed,FALSE
SetObject esi

;Calculate whether it's time to perform
;a Particle Emission yet
;(Sets EmissionRequired=TRUE or FALSE)
mov EmissionRequired,FALSE
fld fAbsoluteTime
fsub .TimeOfLastEmission
fcomp .TimeBetweenEmissions
GetFPUFlags
ja @F
mov EmissionRequired,TRUE
@@:

;For each Particle...
mov ebx,.Particles
xor ecx,ecx
.while ecx<.MaxParticles
push ecx
mov eax,sizeof Particle
mul ecx
add ebx,eax
;Is this Particle "dead" ??
.if .Particle.active==FALSE
;And it's time to Emit Particles ??
.if EmissionRequired==TRUE
;And we've not Emitted enough Particles ??
mov eax,ParticlesEmittedThisEmission
.if eax<.ParticlesPerEmission
;Then give this Particle NEW LIFE !!! IT LIVES :D
mov EmissionPerformed,TRUE
inc ParticlesEmittedThisEmission
OCall ReviveParticle,ebx
.endif
.endif
.else
;Update Particle Life Timer
fld .Particle.life
fsub fElapsedTime
fcomp r4_0_0f
GetFPUFlags
ja @F
mov .Particle.active,FALSE
jmp doLoop
@@: ;Update Particle Position
fld .Particle.Velocity.X
fadd .Particle.Position.X
fstp .Particle.Position.X
fld .Particle.Velocity.Y
fadd .Particle.Position.Y
fstp .Particle.Position.Y
fld .Particle.Velocity.Z
fadd .Particle.Position.Z
fstp .Particle.Position.Z
;Update Particle Velocity
;NewVelocity = (Force * dTime) + OldVelocity
fld fElapsedTime
fmul .Force.X
fadd .Particle.Velocity.X
fstp .Particle.Velocity.X
fld fElapsedTime
fmul .Force.Y
fadd .Particle.Velocity.Y
fstp .Particle.Velocity.Y
fld fElapsedTime
fmul .Force.Z
fadd .Particle.Velocity.Z
fstp .Particle.Velocity.Z
;Render Particle
OCall RenderParticle,ebx
.endif
.if EmissionPerformed==TRUE
fld fAbsoluteTime
fstp .TimeOfLastEmission
.endif
doLoop:
pop ecx
inc ecx
.endw
MethodEnd

Method ParticleSystem.Reset,uses esi ecx,fAbsoluteTime
local pParticle
SetObject esi
mov ebx,.Particles
fld fAbsoluteTime
fstp .TimeOfLastEmission
xor ecx,ecx
.while ecx<.MaxParticles
mov eax,sizeof Particle
mul ecx
add ebx,eax

;Set up Particle Color
mov eax,ecx
div 12
mov eax,sizeof glColor
mul edx
m2m .Particle.r, colors
add eax,sizeof glColor
m2m .Particle.g, colors
add eax,sizeof glColor
m2m .Particle.b, colors

OCall ReviveParticle,ebx

inc ecx
.endw
MethodEnd

Method ParticleSystem.ReviveParticle,uses esi ebx ecx,pParticle
SetObject esi
mov ebx,pParticle
mov .Particle.active,TRUE ; Make All The Particles Active
fld .LifeTimePerParticle
fstp .Particle.life
invoke TIRandom,1,100
fadd r4_0_003f
fstp .Particle.fade  ;(rand%100)/1000.0f+0.003f; // Random Fade Speed

FLDRndSignedFloat 26.0f
fstp .Particle.Velocity.X
FLDRndSignedFloat 26.0f
fstp .Particle.Velocity.Y
FLDRndSignedFloat 26.0f
fstp .Particle.Velocity.Z

.if .pPositionAttach==NULL
fld  .Position.X
fstp  .Particle.Position.X
fld  .Position.Y
fstp  .Particle.Position.Y
fld  .Position.Z
fstp  .Particle.Position.Z
.else
mov eax,pPositionAttach
fld .Vec3.X
fstp .Particle.Position.X
fld .Vec3.Y
fstp .Particle.Position.Y
fld .Vec3.Z
fstp .Particle.Position.Z
.endif
fld r4_0_0
fst  .Force.X
fstp .Force.Z
fld  r4_gravity ;-0.86
fstp .Force.Y
MethodEnd


Method ParticleSystem.RenderParticle,uses esi,pParticle
local x1,y1,fz
local x2,y2
mov esi,pParticle
fld .Particle.Position.X
fadd r4_half
fstp x1
fld .Particle.Position.X
fsub r4_half
fstp x2

fld .Particle.Position.Y
fadd r4_half
fstp y1
fld .Particle.Position.Y
fsub r4_half
fstp y2

fld .Particle.Position.Z
fstp fz
_glColor4f .Particle.r,.Particle.g,.Particle.b,.Particle.life
; Build Quad From A Triangle Strip
invoke glBegin,GL_TRIANGLE_STRIP
_glTexCoord2d 1.0f,1.0f
_glVertex3f x1,y1,fz); // Top Right
_glTexCoord2d 0.0f,1.0f
_glVertex3f x2,y1,fz; // Top Left
_glTexCoord2d 1.0f,0.0f
_glVertex3f x1,y2,fz; // Bottom Right
_glTexCoord2d 0.0f,0.0f
_glVertex3f x2,y2,fz; // Bottom Left
invoke glEnd
MethodEnd



Posted on 2005-07-17 06:30:51 by Homer

All I asked for was your opinion, that's a crap response.
I implemented the ParticleSystem.
This isn't showing much off, but regardless:

http://homer.rantx.com/UDPClient.exe

Cmon guys, gimme some feedback :(
If you have DebugCenter installed, you will see Debug information :)
Posted on 2005-07-18 03:56:54 by Homer
i think the particles are too fast - i can hardly see them.
when i hold LMB on a menuitem, the debug center keeps shooting the text about selected option ( "play alone" etc).? when i leave the window, while holding LMB, release it, then it still keeps shooting the text (probably thinks that i hold it.



/edit
Added CPU's clock frequency
Posted on 2005-07-18 07:20:59 by ti_mo_n
On my machine it works nice... (P3 500)

Biterider
Posted on 2005-07-18 08:33:25 by Biterider
Thanks for the replies.

I can understand the bug regarding moving off the window with the button down, I'll sort it out, it's because I enable a flag on mousedown, and disable it on mouseup.

I've improved the code somewhat and tweaked some of the settings for the particlesystem.
Particle Emitter is now attached to a point manipulated with trig.
Particle initial random velocity was screwed with.
Particles never go toward you, and they have less thrust so you can see gravity working.
I'm thinking about making an overridable "Particle Behaviour" method ..

modified exe was uploaded to same url as last given.
Have a nice day :)
Posted on 2005-07-18 10:39:49 by Homer
the emitrer is going in circles and shoots the particles so fast, that I can see -at most- 10 of them. I think that it would look nicer if there were more of them. ...and they should move slower! :)
Posted on 2005-07-18 11:14:51 by ti_mo_n
That's interesting - it indicates that there's a problem with my "elapsed time" function and/or the way the particle physics works.. If you resize the window smaller, they seem to speed up, which is wrong.. I'll try to remedy it tomorrow.. just implemented some more of the Menu, which was commented out.. checked that menu page switches work, and fixed the mousebutton bug.

Have a nice day :)
Posted on 2005-07-18 11:30:49 by Homer
Mousebutton bug is still present... :|
Posted on 2005-07-18 12:32:20 by ti_mo_n
Homer, when are you registering mouseclicks? mouse-down or mouse-up?
Posted on 2005-07-18 13:19:32 by f0dder
on buttondown use "set capture" and on buttonup use "release capture". this way you'll get 'buttonup' even if the button gets released outside the window.
Posted on 2005-07-18 14:38:12 by ti_mo_n
re mousebug:
I'm detecting mousedown, mouseup no longer handled at all.
I simply hadn't had a chance to upload an updated exe yet, sorry.. there's a new update available now :)
This time I've enabled one of the SubMenus and change the "current menu" on mouseclick.
The menu still needs the items to be switched around since my 2D artist decided to change things around without letting me know .. that's why you see incorrect debug feedback on menu item selections.

Have a nice day :)
Posted on 2005-07-18 22:55:50 by Homer