Hey trendsetters,

just had a lovely few days away from the keys, hope it did me some good...
I've shelved the oopskinmesh example (again) although I know what's got to be done to sort it out...
Since I just got back and was feeling a little bored, I've begun implementing an oop-based extensible ParticleSystem Demo , theres the C source I am translating...
I'm using Ultrano's Class Support, our CApp baseclass, etc.
Everyone finished their Christmas wishlist ?? :)
Posted on 2003-11-26 23:16:13 by Homer
Here's a taste of what's to come - note this aint by any means complete.
.. thanks be to Ultrano for his OOP support module.
Posted on 2003-11-29 00:20:21 by Homer
thanks for the effort. I'm checking out the code.
Posted on 2003-12-01 10:47:07 by Porkster
That source I was basing that on is relatively unsuitable for a D3D example, because it is quite dated and uses a combination of DirectDraw7 and Direct3D8.
I've since found a better example written for DX9, available C source zip here (also contains exe), I am rewriting that one for DX8.1, and it's almost complete.
Why have I done this?
Because the earlier one had some dubious mechanism whereby inheriting classes could manipulate the vtable of the inherited class (their owner), which was not straight forward "overloading" of class methods, and had some other weirdness, and did not contain any optimization of rendering.
This second example is easier to understand, slightly more powerful, and just as flexible as the old one, albeit not as oop-friendly in terms of extensions.
It is however a much better example in modern terms, and uses PointSprites to accomplish its rending of alphablended rectangles which means that vertexbuffers hold just one vertex per sprite rather than four.
I've almost completed the translation to MASM for dx8.1, I'll post it soon.
Posted on 2003-12-02 21:52:17 by Homer
I think PointSprites aren't supported on anything less than GF3. Looks very nice anyway ;]
Posted on 2003-12-04 09:45:33 by panoramix
Thats true, PointSprites are not handled by some cards, and as such, this demo should really check the capabilities of the local hardware, and resort to using textured quads for rending sprites when the hardware isn't capable of PointSprites... speaking of which, I'm stuck at the moment with a minor bug in creation of vertex buffers for holding pointsprites...
I'm getting a return value of "1" from my call to create the vertexbuffer, and checking msdn docs for this call, the value "1" is not even enumerated as a possible return value !! What The?
Note the following function is Class based, using Ultrano's macros, and assumes that ecx=pThis on entry. Anyone got a clue? I really don't wanna use software vertex processing, this is the whole point !

ParticleSystem_RestoreDeviceObjects proc uses ecx pd3dDevice:LPDIRECT3DDEVICE8

local me:DWORD
local ErrBuf[256]:BYTE
local pVB:DWORD
; // Create a vertex buffer for the particle system. The size of this buffer
; // does not relate to the number of particles that exist. Rather, the
; // buffer is used as a communication channel with the device. we fill in
; // a chunck, and tell the device to draw. While the device is drawing, we
; // fill in the next chunck using NOOVERWRITE. We continue doing this until
; // we run out of vertex buffer space, and are forced to DISCARD the buffer
; // and start over at the beginning.
mov me,ecx
DebugValue addr ErrBuf,CTEXT("(m_dwDiscard = %lu)",13,10),.ParticleSystem.m_dwDiscard
mov ecx,me
mov ebx,.ParticleSystem.m_dwDiscard
imul ebx, sizeof PointVertex
PARTICLE_USAGE equ (D3DUSAGE_DYNAMIC or D3DUSAGE_WRITEONLY or D3DUSAGE_POINTS)
FVF_POINTVERTEX equ D3DFVF_XYZ or D3DFVF_DIFFUSE
mcall pd3dDevice,IDirect3DDevice8_CreateVertexBuffer, ebx,PARTICLE_USAGE, FVF_POINTVERTEX, 0, addr pVB
push eax
.if eax!=D3D_OK
Debug CTEXT("Failed to (re?)-Create VertexBuffer... ")
pop eax
.if eax==D3DERR_INVALIDCALL
Debug CTEXT("Reason = 'INVALIDCALL'",13,10)
.elseif eax==D3DERR_OUTOFVIDEOMEMORY
Debug CTEXT("Reason = 'OUTOFVIDEOMEMORY'",13,10)
.elseif eax==E_OUTOFMEMORY
Debug CTEXT("Reason = 'OUTOFMEMORY'",13,10)
.else
DebugValue addr ErrBuf, CTEXT(", Error=0x%lX",13,10),eax
return E_FAIL
.endif
.else
pop eax
mov ecx,me
DebugValue addr ErrBuf, CTEXT("(re?)-Created VertexBuffer @ 0x%lX",13,10),pVB
return S_OK
.endif
ParticleSystem_RestoreDeviceObjects endp
Posted on 2003-12-06 04:42:07 by Homer
I just tried changing that line to:
mcall pd3dDevice,IDirect3DDevice8_CreateVertexBuffer, ebx,PARTICLE_USAGE, FVF_POINTVERTEX, D3DPOOL_DEFAULT, addr pVB


I still get a return value of 1, and no result in my pVB..
Posted on 2003-12-06 04:58:26 by Homer
Heya :)
Here is the complete translation of the DX9 ParticleSystem Demo, rewritten for MASM and DX8.1
It is 99% complete and apparently bugfree (I have not, for example, implemented any of the keyboard or mouse controls) but alas is refusing to render anything to the screen !! I know there's not much wrong, and would love to know what I missed :) If you can spot the render issue, I'll be more than grateful. Again, this demo is not my own work per se, I claim no legal ownership in any respect. Do whatever you like with it :) Finally, I have deliberately left out the two files UUID.LIB and LIBCI.LIB due to size restrictions more than any respect for m$'s EULA :tongue:
Posted on 2003-12-06 20:25:00 by Homer
I've cleaned up that source a little, but I've made no real changes to it.
I've commented out the call to update the view matrix for now.
I've implemented the escape and F-Key switches.
Can anyone help me get the single textured quad "FloorPlane" to render?
I've done this stuff before, I can't see what the problem is :(
Posted on 2003-12-07 06:31:58 by Homer
Thanks to Scronty for taking time to have a peek at my rubbish and awaiting a definite answer to the dilemma of (at the least) why I can't see the Floor.
Posted on 2003-12-07 23:55:48 by Homer
Well, I have disabled the function "updateViewMatrix" and replaced it with a fixed view matrix for now, and lo and behold, the floor appears :)
Obviously there is a problem with my translation of that function, but I'm not really concerned so much with the Camera at the moment as I am with the fact that not a single Particle is being rendered... hmmz... I'm going to look into this now.
I'd appreciate some help with this - do my Render states look ok? There's two places where the problem could lie, either the RenderStates are bad, or the Particles are not being correctly updated in terms of their position over time...
Posted on 2003-12-08 23:36:29 by Homer
Hmmz, well, here is the latest version, I found a couple more issues and fixed them up, one of the main ones being that since I use WM_CHAR for keyboard input I cannot detect F-Keys like F1... please note I am currently using key "1" for changing the current ParticleSystem.

Now, I have two questions on things which are bothering me.
The first is that I am only getting screen updates when a WM happens, I implemented a visual means of checking the "Elapsed Time" which proves this is true. There's a big problem with my MessagePump !! My first question therefore is - what is wrong with my MessagePump? It's meant to fall through and return if no messages are in the queue, and thus only render when nothing is happening, this is not what we are seeing, is it?

My second question is probably related - the app currently operates in Windowed Mode, but if I switch to another window, I cannot switch back - the application window simply stops getting any input and does not get focus back. This means you can't even hit escape to quit anymore. Why?
Posted on 2003-12-09 00:16:31 by Homer
I've fixed the MessagePump issue - now I'm going to try to figure out where my truant particles are hiding...

The issue in the messagepump was the line:
.if $invoke (PeekMessage, addr msg, PM_NOREMOVE, 0, 0, 0 )

I had altered it to follow the C source, which is actually wrong.
That's what you get for not having faith in yourself.
Posted on 2003-12-09 22:08:15 by Homer
Progress Report : I've found that the Particle issues stem from the ParticleSystem_Update procedure - in fact, no particles were even being created.
Now particles are being created, but subsequent calls to Update crash the application, so I'll have to look more closely at the first part of that procedure (the second part is where they are created). Therefore I have disabled the call to ParticleSystem_Render until my phantom particles are being created and updating over time and behaving themselves :)
On a side note, when I claimed to have fixed the problems with my MessagePump, I should have said I fixed the issue of the Window losing and not regaining focus. There's still a problem in terms of the Render function only being called when a WM is processed, which is irritating me.
Bugs:2 , Homer:1
Posted on 2003-12-10 02:06:32 by Homer
Actually, there's no issue with the MessagePump - for some reason, with no changes from me, it's now showing the true ElapsedTime when all I have done is correct the issues in the second half of the particle Update procedure... weird.
Ok now, particles are being created over time correctly, and I can confirm this with a visual examination of the #particles in current system being viewed (realtime).
Still there is an issue in the first part of same procedure.
Specifically, when attempting to update the linkedlist of Particles owned by a given system, we enter an infinite loop, never finding a null pNext at the end.
Considering the method used for creating links between particles, I find this odd.
Bear in mind that the system's pActiveList is initialized to zero when it is created (see the contructor for the class, ParticleSystem_ParticleSystem for proof)...

; //Attach Old Head to new Particle
m2m .Particle.m_pNext , .ParticleSystem.m_pActiveList
; // Make it the new head...
m2m .ParticleSystem.m_pActiveList , pParticle

What is happening here is that when we make a new particle, it automatically becomes the head of the list, and the old head is attached under it.
Considering the initial head is zero, the last pNext should be zero !!

Therefore, it seems strange to never find it, right?
Anyone have any feedback on this issue?
Posted on 2003-12-10 22:10:26 by Homer
(just to prove the issue is in the Particles update loop, I commented out the inner loop checking the particle against all Planes...)
Posted on 2003-12-10 22:21:44 by Homer
heh - fixed the infinite loop issue, only one more to go in this section of code, the "inner loop" where we "check if the current particle has passed any of our Planes", contains a bug, theres no default plane lol, I think I'll be posting a 100% version of this demo before this day is out :)
Posted on 2003-12-10 23:06:26 by Homer
One last issue: there is a problem inthe particle rendering proc, when I try to lock the VB, even though it returns D3D_OK, the pointer it returns is bad.
I'll try to solve this as soon as possible, I for one am keen to see some particles on my screen :)
Posted on 2003-12-11 01:08:10 by Homer
Well, now I render a frame which shows a particle, but subsequently the application hangs. It's still apparently a Render issue, because if I disable ONLY the ParticleSystem_Render proc, everything is peachy.

Here's the current code for that procedure:
Can anyone see a problem in it? It returns the first time...

ParticleSystem_Render proc uses ecx pd3dDevice:LPDIRECT3DDEVICE8
local me:DWORD
local pParticle:DWORD
local pVertices:ptr PointVertex
local vPos:D3DXVECTOR3
local vVel:D3DXVECTOR3
local m_pVB:DWORD
local ErrBuf[256]:BYTE

;//-----------------------------------------------------------------------------
;// Name: Render()
;// Desc: Renders the particle system using pointsprites loaded in a vertex
;// buffer.
;//
;// Note: D3DLOCK_DISCARD:
;//
;// The application overwrites, with a write-only operation, the entire
;// index buffer. This enables Direct3D to return a pointer to a new
;// memory area so that the dynamic memory access (DMA) and rendering
;// from the old area do not stall.
;//
;// D3DLOCK_NOOVERWRITE:
;//
;// Indicates that no vertices that were referred to in drawing calls
;// since the start of the frame or the last lock without this flag will
;// be modified during the lock. This can enable optimizations when the
;// application is appending data only to the vertex buffer.
;//-----------------------------------------------------------------------------
mov me,ecx ; As always, preserve pThis
m2m m_pVB,.ParticleSystem.m_pVB



; //
; // Set the render states for using point sprites..
; //

mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSPRITEENABLE, TRUE ; // Turn on point sprites
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSCALEENABLE, TRUE ; // Allow sprites to be scaled with distance
mov ecx,me
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSIZE, .ParticleSystem.m_fSize ; // Float value that specifies the size to use for point size computation in cases where point size is not specified for each vertex.
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSIZE_MIN, fp1 ; // Float value that specifies the minimum size of point primitives. Point primitives are clamped to this size during rendering.
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSCALE_A, 0 ; // Default 1.0
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSCALE_B, 0 ; // Default 0.0
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSCALE_C, fp1 ; // Default 0.0
mov ecx,me
m2m pParticle , .ParticleSystem.m_pActiveList;
mov .ParticleSystem.dwNumParticlesToRender , 0

; // Lock the vertex buffer. We fill the vertex buffer in small
; // chunks, using D3DLOCK_NOOVERWRITE. When we are done filling
; // each chunk, we call DrawPrim, and lock the next chunk. When
; // we run out of space in the vertex buffer, we start over at
; // the beginning, using D3DLOCK_DISCARD.

; // Move the offset forward so we can fill the next chunk of the vertex buffer
mov eax,.ParticleSystem.m_dwFlush
add .ParticleSystem.m_dwVBOffset ,eax

; // If we're about to overflow the buffer, reset the offset counter back to 0
mov eax, .ParticleSystem.m_dwVBOffset
.if eax >= .ParticleSystem.m_dwDiscard
mov .ParticleSystem.m_dwVBOffset , 0
.endif

mov ebx,.ParticleSystem.m_dwVBOffset ;calc offset to lock
imul ebx,sizeof PointVertex
mov ecx,.ParticleSystem.m_dwFlush ;calc size to lock
imul ecx,sizeof PointVertex

.if ebx!=0
mcall m_pVB,IDirect3DVertexBuffer8_Lock, ebx, ecx, addr pVertices, D3DLOCK_NOOVERWRITE
.else
mcall m_pVB,IDirect3DVertexBuffer8_Lock, ebx, ecx, addr pVertices, D3DLOCK_DISCARD
.endif
.if eax==D3DERR_INVALIDCALL
Debug CTEXT("Failed to Render ParticleSystem due to failed Lock.",13,10,"Reason=INVALIDCALL",13,10)
ret
.endif

; int 3
; // Render each particle
.while pParticle


mov esi,pParticle
__LoadFloat3 .Particle.m_vCurPos
__StoreFloat3 vPos
__LoadFloat3 .Particle.m_vCurVel
__StoreFloat3 vVel

mov esi,pVertices
__LoadFloat3 vPos
__StoreFloat3 .PointVertex.posit
__LoadFloat4 .ParticleSystem.m_clrColor
__StoreFloat4 .PointVertex.color
add pVertices,sizeof PointVertex

mov ecx,me
inc .ParticleSystem.dwNumParticlesToRender
mov eax,.ParticleSystem.m_dwFlush
.if( .ParticleSystem.dwNumParticlesToRender == eax )
; // Done filling this chunk of the vertex buffer. Lets unlock and
; // draw this portion so we can begin filling the next chunk.
mcall m_pVB, IDirect3DVertexBuffer8_Unlock
mcall pd3dDevice, IDirect3DDevice8_SetStreamSource, 0, m_pVB, sizeof PointVertex
mcall pd3dDevice,IDirect3DDevice8_SetVertexShader, FVF_POINTVERTEX
mov ecx,me
mcall pd3dDevice,IDirect3DDevice8_DrawPrimitive, D3DPT_POINTLIST, .ParticleSystem.m_dwVBOffset, .ParticleSystem.dwNumParticlesToRender
.if eax!=D3D_OK
ret
.endif

; // Lock the next chunk of the vertex buffer. If we are at the
; // end of the vertex buffer, DISCARD the vertex buffer and start
; // at the beginning. Otherwise, specify NOOVERWRITE, so we can
; // continue filling the VB while the previous chunk is drawing.
mov ecx,me
mov eax,.ParticleSystem.m_dwFlush
add .ParticleSystem.m_dwVBOffset ,eax

; // If we're about to overflow the buffer, reset the offset counter back to 0
mov eax,.ParticleSystem.m_dwDiscard
.if .ParticleSystem.m_dwVBOffset >= eax
mov .ParticleSystem.m_dwVBOffset , 0
.endif

mov ebx,.ParticleSystem.m_dwVBOffset
imul ebx,sizeof PointVertex
mov ecx,.ParticleSystem.m_dwFlush
imul ecx,sizeof PointVertex
.if ebx!=0
mcall m_pVB,IDirect3DVertexBuffer8_Lock,ebx, ecx, addr pVertices, D3DLOCK_NOOVERWRITE
.else
mcall m_pVB,IDirect3DVertexBuffer8_Lock,ebx, ecx, addr pVertices, D3DLOCK_DISCARD
.endif
.if eax!=D3D_OK
ret
.endif
mov ecx,me
mov .ParticleSystem.dwNumParticlesToRender , 0
.endif
mov esi,pParticle
m2m pParticle , .Particle.m_pNext
.endw

; // Unlock the vertex buffer
mcall m_pVB,IDirect3DVertexBuffer8_Unlock

; // Render any remaining particles
mov ecx,me
.if .ParticleSystem.dwNumParticlesToRender
mcall pd3dDevice,IDirect3DDevice8_SetStreamSource, 0, m_pVB, sizeof PointVertex
mcall pd3dDevice,IDirect3DDevice8_SetVertexShader, FVF_POINTVERTEX
mov ecx,me
mcall pd3dDevice,IDirect3DDevice8_DrawPrimitive, D3DPT_POINTLIST, .ParticleSystem.m_dwVBOffset, .ParticleSystem.dwNumParticlesToRender
.if eax!=D3D_OK
ret
.endif
.endif

; //
; // Reset render states...
; //

mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSPRITEENABLE, FALSE
mcall pd3dDevice,IDirect3DDevice8_SetRenderState, D3DRS_POINTSCALEENABLE, FALSE
mcall pd3dDevice,IDirect3DDevice8_SetVertexShader,NULL

ret
ParticleSystem_Render endp
Posted on 2003-12-11 04:35:13 by Homer
Here is the current version, which is working, albeit not as it should be.
You will see what I mean.


After I posted THIS release, small changes were made..
I've cleanup up some of the lower ParticleSystem procs where I have replaced the RtlMoveMemory calls with Caleb's fpu macros, much more appropriate. I've implemented the ParticleSystem_Init function which was missing, not that it made any difference...
Posted on 2003-12-11 21:55:16 by Homer