Afternoon, .

That surely is the most weirdest message pump I've seen in a while:tongue: :grin: :alright: .

This improves it a little:


;=====<< CAPP_PROCESS_MESSAGES >>===\
CApp_ProcessMessages proc
LOCAL msg :MSG
mov ecx,CApp_OnlyInstance

; // loop until s_bWait is false
; .repeat
.if [ecx].CApp.bWait != TRUE
; // if g_bWait is false do not wait in the loop, so check the
; // existance of messages and processes them if available
.if $invoke (PeekMessage, addr msg, PM_NOREMOVE, 0, 0, 0 )
.if !$invoke (GetMessage, addr msg, NULL, 0, 0 )
return FALSE
.else
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
.endif
.endif

.else
; // if g_bWait is true use GetMessage to return control to the operating system
.if !$invoke (GetMessage,addr msg, NULL, 0, 0 )
return FALSE
.else
invoke TranslateMessage, addr msg
invoke DispatchMessage,addr msg
.endif

.endif
mov ecx,CApp_OnlyInstance
; .until [ecx].CApp.bWait == FALSE
; // all messages are processed and no quit message was recieved so return true
return TRUE
CApp_ProcessMessages ENDP
;=======/


However...
If you're going to be dispatching any waiting messages in the queue anyway, then you might as well do this:


;=====<< CAPP_PROCESS_MESSAGES >>===\
CApp_ProcessMessages proc
LOCAL msg :MSG

invoke PeekMessage, ADDR msg, NULL, 0, 0, PM_REMOVE
.IF eax != 0
.IF msg.message == WM_QUIT
return FALSE
.ELSE
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
.ENDIF

.ENDIF

; // all messages are processed and no quit message was recieved so return true
return TRUE
CApp_ProcessMessages ENDP
;=======/

Which seems to work just the same.

Cheers,
Scronty
Posted on 2003-12-12 06:29:53 by Scronty
Cheers, I merely translated the original from c++, I assumed they knew something I didn't ... lol , again, what you get for not having faith in urself.
Posted on 2003-12-12 06:33:43 by Homer
Afternoon, EvilHomer2k.

Adjusted the CApp_Run proc so that elapsed time is never zero:


CApp_Run proc uses ecx
icall CApp_OnlyInstance, CApp, ProcessMessages
.while eax!=FALSE
@@:
mov g_dCurTime , $invoke (timeGetTime)
fild g_dCurTime
fild g_dLastTime
fcompp
GetFPUFlags
je @B ; if no time has elapsed, then just loop back (do nothing)
fild g_dCurTime
fisub g_dLastTime
fmul fp0pt001 ; /1000
fstp g_fElapsedTime ; (float)((g_dCurTime - g_dLastTime) * 0.001);
m2m g_dLastTime , g_dCurTime
icall CApp_OnlyInstance, CApp, Render
icall CApp_OnlyInstance, CApp, ProcessMessages
.endw
ret
CApp_Run endp


Also:
inside demo_render.inc file:
render proc:
Changed the "fElapsedTime = " text so that it'll display the FPS (updated once per second so that there's no flicker):


.data
fpFPStime FLOAT 0.0f
dwFPSinc dd 0
dwFPS dd 0
.code

add dwFPSinc, 1
fld g_fElapsedTime ; update the elapsed-time over a second
fadd fpFPStime
fst fpFPStime
fld1
fcompp ; see whether it's reached one second
GetFPUFlags
ja @F ; still under a second, so don't update text

fld fpFPStime ; subtract one (1) second from the counter
fldz
fstp fpFPStime

m2m dwFPS, dwFPSinc
mov dwFPSinc, 0

@@:
invoke wsprintf,addr ErrBuf,CTEXT("fElapsedTime = %d"),dwFPS
invoke DrawTextLine ,pFont, addr MyVerticalPosition,addr ErrBuf, -1


NOTE:
I changed the speeling of g_fElpasedTime to g_fElapsedTime ;) .
Plus added the GetFPUFlags macro to the MACROS.inc file:


GetFPUFlags MACRO
fnstsw ax
sahf
ENDM


Cheers,
Scronty
Posted on 2003-12-12 21:36:13 by Scronty
I've implemented the changes posted above.
Well that certainly looks nicer, and seems to behave better (messagepump).
I certainly appreciate your input :)
For some reason now, the ParticleSystem_Update procedure is no longer emitting any new particles, and the #particles active remains at zero :(
Considering that activities in Update are based on the ElapsedTime (passed to it in the call made from CApp_Render), there would appear to be an inconsistancy which wasnt there before these changes were implemented...
I guess now it's time to go back to the Update proc and try to figure out why it's not behaving itself.. maybe I should skip Update when fElapsed is zero.

Also, seems that macro is included in one of the other inc files since I did not need to add it as a macro, and for that matter, I generally use the __FJ?? macros in Caleb's "FKT" include when it comes to floating compares, same thing really.

Thanks once more for taking the time to help with some aspects of this code, it seems very few of us are interested in this field of programming, at least in terms of asm, which is a shame. (Scronty was added to the credits as a contributing author)
Posted on 2003-12-13 00:26:04 by Homer
Latest update for anyone who is interested.
Posted on 2003-12-13 00:47:38 by Homer
Thanks to Roticv for bringing this small "feature" to my attention.
In the CApp_CApp Constructor:

invoke ShowWindow,.CApp.hWnd,SW_SHOW
mov ecx,me ;<---- under NT systems, api sometimes alter ecx, sometimes not - be safe :)
invoke UpdateWindow,.CApp.hWnd
mov eax,CApp_OnlyInstance
ret

I now refresh value of ecx after call to ShowWindow, in case NT messes up ecx during that call, which only happens SOMETIMES and not ALWAYS, heh.
It caused a nasty GPF which was rare but now is fixed.
Posted on 2003-12-13 01:23:37 by Homer
I've been drinking beer all weekend and haven't had a chance to get to the bottom of the mystery of the missing particles, but I tell you this: when I removed the param fElapsedTime from the procedure ParticleSystem_Update and used the global g_fElapsedTime instead, the particles reappear - magic? The localized fElapsedTime param is the freaking global anyway, passed from the main Render proc, so this is bizarre and indicates stack issues, yet no crash is occuring...
Posted on 2003-12-14 05:17:38 by Homer
Today I implemented the "nice" method of calculating the random vector used for the direction and speed of particles...so here's another update :)
Posted on 2003-12-15 07:09:28 by Homer
Just added visual confirmation of the current particlesystem's fVelocityVar value, which is multiplied by the random vector (direction) of individual particles to give them the same velocity but different directions.
I'll wait until tomorrow to repost, kinda tired.
Posted on 2003-12-15 07:33:37 by Homer
Let's make a closer examination of the code used to update the position of particles over time, because something is horribly wrong :(

Here is the current update of my source for this procedure, whittled down to only show the relevant code section...
Please assume that the vectors for Gravity and Wind are zero, because that's the case for the default ParticleSystem.
This means we can effectively skip down to the code following the comment " Finally, update position with respect to velocity".
Now bear in mind that all particles have an initial Position value equal to that of their owner ParticleSystem (the Emitter), likewise for Velocity.
In the case of the default ParticleSystem, Velocity = 10.0f
So what could be wrong with this code?



;========================================================
;Last Updated December 16, 2003, by Homer
;I've placed two parts of this three-part procedure in separate includes, so that
;the Reader (you) can concentrate on the most important code - updating Particles Positions over Time.
;========================================================
ParticleSystem_Update proc
local me:DWORD
local pParticle:ptr Particle
local ppParticle:ptr LPPARTICLE
local pPlane:ptr Plane
local ppPlane:ptr LPPLANE
local vOldPosition,Vn,Vp,Vt,temp:D3DXVECTOR3
local Kr:FLOAT
local countie:DWORD

.if g_fElapsedTime==0 ;if no time has passed (which seems improbable but it happens..)
ret ;simply get the hell out of here because everything is timebased
.endif ;and no time means no difference, so why waste our cycles?

mov me,ecx
fld g_fElapsedTime
fadd .ParticleSystem.m_fCurrentTime
fstp .ParticleSystem.m_fCurrentTime ; // Update our particle system timer...
mov eax,.ParticleSystem.m_pActiveList
mov ppParticle , eax; // Start at the head of the active list

.while ppParticle != NULL
mov ecx,me
m2m pParticle , dword ptr ppParticle ; // Set a pointer to the head
; // Calculate new position
mov esi,pParticle
fld .ParticleSystem.m_fCurrentTime
fsub .Particle.m_fInitTime
fstp .ParticleSystem.fTimePassed

mov eax,.ParticleSystem.fTimePassed
.if eax >= .ParticleSystem.m_fLifeCycle
; // Time is up, put the particle back on the free list...
mov esi,pParticle
m2m ppParticle , .Particle.m_pNext
m2m .Particle.m_pNext , .ParticleSystem.m_pFreeList
m2m .ParticleSystem.m_pFreeList , pParticle
dec .ParticleSystem.m_dwActiveCount
.else
; // Update particle position and velocity
mov esi,pParticle

; // Update velocity with respect to Gravity (Constant Accelaration)
; pParticle->m_vCurVel += m_vGravity * fElpasedTime;

fld g_fElapsedTime
fmul .ParticleSystem.vGravity.x
fadd .Particle.m_vCurVel.x
fstp .Particle.m_vCurVel.x
fld g_fElapsedTime
fmul .ParticleSystem.vGravity.y
fadd .Particle.m_vCurVel.y
fstp .Particle.m_vCurVel.y
fld g_fElapsedTime
fmul .ParticleSystem.vGravity.z
fadd .Particle.m_vCurVel.z
fstp .Particle.m_vCurVel.z

; // Update velocity with respect to Wind (Accelaration based on difference of vectors)
.if .ParticleSystem.bAirResistence == TRUE
fld .ParticleSystem.vWind.x
fsub .Particle.m_vCurVel.x
fmul g_fElapsedTime
fadd .Particle.m_vCurVel.x
fstp .Particle.m_vCurVel.x
fld .ParticleSystem.vWind.y
fsub .Particle.m_vCurVel.y
fmul g_fElapsedTime
fadd .Particle.m_vCurVel.y
fstp .Particle.m_vCurVel.y
fld .ParticleSystem.vWind.z
fsub .Particle.m_vCurVel.z
fmul g_fElapsedTime
fadd .Particle.m_vCurVel.z
fstp .Particle.m_vCurVel.z
.endif

; // Finally, update position with respect to velocity
__LoadFloat3 .Particle.m_vCurPos
__StoreFloat3 vOldPosition
fld .Particle.m_vCurVel.x
fmul g_fElapsedTime
fadd .Particle.m_vCurPos.x
fstp .Particle.m_vCurPos.x
fld .Particle.m_vCurVel.y
fmul g_fElapsedTime
fadd .Particle.m_vCurPos.y
fstp .Particle.m_vCurPos.y
fld .Particle.m_vCurVel.z
fmul g_fElapsedTime
fadd .Particle.m_vCurPos.z
fstp .Particle.m_vCurPos.z

;========================================================
include Planes_Collisions_Snippet.inc ; 'inner loop' to check each particle against all 'Planes'
;========================================================

.endif
mov esi,pParticle
m2m ppParticle ,.Particle.m_pNext
.endw
@@:
;========================================================
include Emit_Particles_Snippet.inc ; not part of any Loop, this is always executed (unconditional)
@@:
;========================================================
return S_OK
ParticleSystem_Update endp
Posted on 2003-12-15 21:56:09 by Homer
Afternoon, EvilHomer2k.

Ummmm....
Excuse moi, n00b...

but why isn't ESI being restored?:grin:

Cheers,
Scronty
Posted on 2003-12-16 05:39:58 by Scronty
Huh? Excuse moi ignorance, but where is it NOT being restored? Did I post something incomplete? I edited this just before I posted ...
Man , now I have to stare at it again thru beer goggles, I hate that :(
I bet ur right too, and I'll kick myself if and when I spot it lol, maybe I should wait until I sober up .. :tongue: damn its hot here !! :grin:
As for the n00b thing, I'll let that slide since I am relatively new to x86, having avoided it for the past two decades...


Nope, beer goggles don't note any issue with esi not being restored in that code, unless u mean like at the end of the proc, which is not necessary.
All the same, I have respect for ur eagle eye and ur experience in this gear and I'll look again with my superb 20/20 hindsight and check in the morning, thanks for ur input, always appreciated.
Posted on 2003-12-16 06:08:29 by Homer
Janis Joplin was absolutely correct - it IS all the same day, man.

Here's an update with 100% working camera controls
(use mouse with leftbutton to rotate, cursor arrows to move around)

ParticleUpdate is 99% working, will crash when you try to close down.
Key "1" to change active system.
No guarantees are made about anything but the default particlesystem.

Have a nice day :)
Posted on 2003-12-17 23:43:34 by Homer
Afternoon, EvilHomer2k.

In your last code posting on the previous page of this thread (ParticleSystem_Update proc):

Scroll down until you get to:
; // Calculate new position


Immediately after that comment, you've got:
mov esi,pParticle


Now correct me if I'm wrong.... but you never push esi...pop esi within that proc anywhere. Nor have you got:
ParticleSystem_Update proc uses esi

... which would allow you to get away with pushing/popping esi.

All of us n00bs forget to restore esi/edi/ebx every now-and-then:grin: .

Cheers,
Scronty
Posted on 2003-12-18 03:56:49 by Scronty
True that Scronty, but I wasn't concerned about preserving the esi register. I tend to use it as a general purpose register and since NO API CALLS are made from within this procedure, there's little reason to want to preserve it. I know that's not "the right way to do things", but I see little reason in this case.
Anyway, I managed to sort out the issues in the Update procedure, and here's a new post which is rock solid compared to the last one :tongue:

The LinkedList Management works as follows:
We have an ActiveList, and we have a FreeList.
The FreeList is used to hold particles which have expired but are yet to be recycled.
Recycling of course happens in the EmitParticles section of code in the same proc.
When a particle expires, it gets removed from the ActiveList and chucked on the FreeList. In order to achieve this, we first determine if the expired particle is the current Head of the ActiveList (first node). If it is, we simply make the Next one the new Head. If not, we patch around it, from the Previous to the Next. Either way, we then attach the FreeList to the expired particle, and make it the new Head of the FreeList.
Just out of curiosity, why are you so pedantic about ESI?
Also, how can I get the cpu time down, now I'm using your simplified MessagePump, the cpu usage has shot to hell.
The Camera View code works nicely, I modified it to limit motion in Y for the purposes of this demo.
Posted on 2003-12-18 06:03:44 by Homer
... and here's another one with (finally!) the Textures of particles working. Also, Wind is working ("air resistance")
YAYYYYYY :alright:
Only issue to fix now is the color, which is easy, but I'm tired now so too bad :tongue: oh yeah and also Planar collisions...

Have a nice day :)
Posted on 2003-12-18 07:28:03 by Homer
Afternoon, EvilHomer2k.

I guess if you never have esi loaded with something *before* calling ParticleSystem_Update, then not preserving esi is fine.
It's just that...
*if* esi is loaded with something before the call to ParticleSystem_Update, then esi would end up changed.

I guess it's just the matter of:
If the procs are only ever called from within the particle system, you can use/abuse registers however you like. Anyone using the particle system would never call ParticleSystem_Update themselves, right?

After looking through all your files, it seems you're correct. esi doesn't need preserving in that proc;) .

As for the message pump:
I'll look into seeeing if that can be fixed.

It may have something to do with adding to CApp_WndProc:


.elseif msg == WM_SIZE
.IF (w == SIZE_MAXHIDE) || (w == SIZE_MINIMIZED)
mov ecx,CApp_OnlyInstance
mov [ecx].CApp.bWait , TRUE
.ELSE
mov ecx,CApp_OnlyInstance
mov [ecx].CApp.bWait , FALSE
.ENDIF

and also getting the rendering to *not* run while bWait is TRUE.

With regards to the Camera code:
I've built a library (dll currently, but going to be changed to a static lib) which has the equivalent of an OOP "SSMovement" thingy.

At this current stage, you create a SSMovement object like so:
Inside .data section:


gPlayerObject LPSSMovementStruc 0 ; pointer to out player object
gCameraObject LPSSMovementStruc 0 ; pointer to out camera object

Inside any initialization proc:


; create our camera object
invoke SSMovement_NewObject
mov gCameraObject, eax

; create our player object
invoke SSMovement_NewObject
mov gPlayerObject, eax

Inside any cleanup proc:


; destroy our player object
invoke SSMovement_DeleteObject, gPlayerObject

; destroy our camera object
invoke SSMovement_DeleteObject, gCameraObject

I've been playing around with the Meshes example (#6), and have replaced the spacebuggy and view matrice update like so:


.DATA
dwOldTime dd 0
dwNewTime dd 0
fp0pt001 FLOAT 0.001f
fpRotationVelocity FLOAT 3.1415926535897932384626433832795f ; two rotations per second
.CODE

invoke timeGetTime
mov dwNewTime, eax

fild dwNewTime
fild dwOldTime
fsub
fmul fp0pt001 ; change elapsed time to seconds
fstp gfpTimeElapsed

mov eax, dwNewTime
mov dwOldTime, eax

fld fpRotationVelocity
mov edx, gPlayerObject
fstp [edx].SSMovementStruc.Yaw

invoke SSMovement_UpdateObject, gPlayerObject, gfpTimeElapsed

mov edx, gPlayerObject
mcall [g_pd3dDevice],IDirect3DDevice8_SetTransform, 256, ADDR [edx].SSMovementStruc.matUpdated

.DATA
eye_vector D3DXVECTOR3 <0.0f, 30.0f,-50.0f>
lookat_vector D3DXVECTOR3 <0.0f, 0.0f, 0.0f>
up_vector D3DXVECTOR3 <0.0f, 1.0f, 0.0f>
rotateradians D3DXVECTOR3 <0.00001f, 0.0f, 0.0f>
initialrun dd 0
fp0pt0 FLOAT 0.0f
.CODE

invoke SSMovement_PositionObject, gCameraObject, eye_vector.x, eye_vector.y, eye_vector.z
.if initialrun == 0
mov initialrun, 1
invoke SSMovement_RotateObject, gCameraObject, rotateradians.x, rotateradians.y, rotateradians.z
.else
invoke SSMovement_RotateObject, gCameraObject, fp0pt0, fp0pt0, fp0pt0
.endif
invoke SSMovement_UpdateObjectAsCamera, gCameraObject, gfpTimeElapsed

mov edx, gCameraObject
mcall [g_pd3dDevice],IDirect3DDevice8_SetTransform, D3DTS_VIEW, ADDR [edx].SSMovementStruc.matUpdated

Note that for every normal object, I use SSMovement_UpdateObject. For any camera, I use SSMovement_UpdateObjectAsCamera.
Apart from those two procs, all othe rprocs are used for all moving objects.

I still have to fill in the rest of the basic movment/rotate procs (will only take a few minutes really).
After that, I'll be able to add more complicated procs for movement.
i.e.
Something similar to D3DXMatrixLookAtLH, where you can point an object/camera at anything/anywhere.
Movement buffering, where any movement/rotation automagically slows down to a halt.
Target locking (similar to the D3DXMatrixLookAtLH above, except the object will always stay locked on target.
Path following, where the object will follow a curved path (after been supplied a list of waypoints).
etc, etc.

Should be fun.

I'll be keeping it as a lib/dll for now until it's robust enough to change to a static lib. Doing it this way means that people won't have to worry about any assembling/linking problems (i.e. people not having their inc/lib files set up the same as myself need nolonger worry about not being able to use this stuff).

Cheers,
Scronty
Posted on 2003-12-18 07:52:17 by Scronty
Scronty - Sounds like phun to me :)

Arrrgh, having a problem with planar collision physics.
Anyone good at physics here?

Assume that for a given Particle, we save the current position and velocity of that particle just before it gets updated. Now we have the Old Position & Velocity, as well as the Current Position & Velocity. We then test the Current values against one or more Planes and determine whether the Particle is on the "back" side of any of those Planes. Let's just talk about Bouncing for now. Assuming that we correctly determine we have passed a Plane, we then use the following formula (and code) to reset the current velocity, and we revert to the old position...
Physics people, please check my formula is correct.

mov esi,pPlane
.if .Plane.m_nCollisionResult == CR_BOUNCE
; //-----------------------------------------------------------------
; //
; // The new velocity vector of a particle that is bouncing off
; // a plane is computed as follows:
; //
; // Vn = (N.V) * N
; // Vt = V - Vn
; // Vp = Vt - Kr * Vn
; //
; // Where:
; //
; // . = Dot product operation
; // N = The normal of the plane from which we bounced
; // V = Velocity vector prior to bounce
; // Vn = Normal force
; // Kr = The coefficient of restitution ( Ex. 1 = Full Bounce, 0 = Particle Sticks )
; // Vp = New velocity vector after bounce
; //
; //-----------------------------------------------------------------
; *** NOTE Kr = .Plane.m_fBounceFactor

mov esi,pPlane
;// FIRST WE CALCULATE Vn (=Normal Force) according to given formula
invoke D3DXVec3Dot, addr .Plane.m_vNormal, addr vOldVelocity
mov ftemp,eax ;store Dot Product result
mov esi,pPlane ;just in case api messes our registers
mov ecx,pParticle
fld .Plane.m_vNormal.x
fmul ftemp
fstp Vn.x
fld .Plane.m_vNormal.y
fmul ftemp
fstp Vn.y
fld .Plane.m_vNormal.z
fmul ftemp
fstp Vn.z

;// NEXT WE CALCULATE Vt (=V-Vn)
__LoadFloat3 vOldVelocity
__SubFloat3 Vn
__StoreFloat3 Vt

;// FINALLY WE CALCULATE Vp (=Vt - Kr * Vn)
fld Vt.x
fld .Plane.m_fBounceFactor
fmul Vn.x
fsub
fstp .Particle.m_vCurVel.x
fld Vt.y
fld .Plane.m_fBounceFactor
fmul Vn.y
fsub
fstp .Particle.m_vCurVel.y
fld Vt.z
fld .Plane.m_fBounceFactor
fmul Vn.z
fsub
fstp .Particle.m_vCurVel.z

;// AND PUT THE PARTICLE BACK ON THE 'SAFE' SIDE OF THE PLANE
__LoadFloat3 vOldPosition
__StoreFloat3 .Particle.m_vCurPos

Right now, the Particles continue on their merry way right through the plane, and for all purposes their Velocity (which incorporates Direction) is unaltered.
For example, if we enable Gravity and define a Floor Plane with a Normal pointing into Y+, the particles rain right through the floor and into eternity, until they time out.
Any ideas?
Posted on 2003-12-18 22:30:38 by Homer
Afternoon, EvilHomer2k.



;=====<< CAPP_PROCESS_MESSAGES >>===\
CApp_ProcessMessages proc
LOCAL msg :MSG
LOCAL bGotMsg:DWORD

INVOKE PeekMessage, ADDR msg, NULL, 0, 0, PM_NOREMOVE

; Enter the message loop
.WHILE msg.message != WM_QUIT

mov ecx,CApp_OnlyInstance
.if [ecx].CApp.bWait != TRUE
INVOKE PeekMessage, ADDR msg, NULL, 0, 0, PM_REMOVE
mov bGotMsg, eax
.ELSE
INVOKE GetMessage, ADDR msg, NULL, 0, 0
mov bGotMsg, eax
.ENDIF

.IF bGotMsg

INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg

.ELSE


; Render a frame during idle time (no messages are waiting)
mov ecx,CApp_OnlyInstance
.if [ecx].CApp.bWait != TRUE

invoke timeGetTime
mov g_dCurTime, eax

fild g_dCurTime
fild g_dLastTime
fsub
fmul fp0pt001 ; change elapsed time to seconds
fstp g_fElapsedTime

mov eax, g_dCurTime
mov g_dLastTime, eax

icall CApp_OnlyInstance, CApp, Render


.ENDIF

.ENDIF
.ENDW


; // all messages are processed and no quit message was recieved so return true
return TRUE
CApp_ProcessMessages ENDP
;=======/



CApp_Run proc uses ecx
icall CApp_OnlyInstance, CApp, ProcessMessages

ret
CApp_Run endp

Inside the "render proc pd3dDevice:DWORD" for CApp:


add dwFPSinc, 1
fld g_fElapsedTime ; update the elapsed-time over a second
fadd fpFPStime
fst fpFPStime
fld1
fcompp ; see whether it's reached one second
GetFPUFlags
ja @F ; still under a second, so don't update text

fldz
fstp fpFPStime

m2m dwFPS, dwFPSinc
mov dwFPSinc, 0
@@:

invoke wsprintf,addr ErrBuf,CTEXT("FrameRate = %d fps"),dwFPS
invoke DrawTextLine ,pFont, addr MyVerticalPosition,addr ErrBuf, -1


Cheers,
Scronty
Posted on 2003-12-18 22:51:29 by Scronty
Hell yeah !!
cpu time down to practically zero...w00t !!
If I keep slapping my forehead like this, I'll end up with a permanent welt :tongue:

As for the physics issue (reflection), I can't find any good examples which use the coplanar point method :( I'll keep looking, and hopefully in the meantime a physics student can point out that my formula is wrong. I'm assuming it's the formula because my implementation in code looks ok. I have verified that my ClassifyPoint procedure is correctly determining on which side of a plane (defined by a normal and coplanar point) a given point is sitting. Irritating. In a "real app" I would be using DX's intersection tests anyway, but I still wanna know what's wrong here, since we still have to perform the reflection ourselves. I don't wanna use a reflection matrix for this because it seems redundant - how often will multiple particles strike the same plane in a real game? I assume here that the world isn't nice and flat, and that the planes are all over the place, thinking in outdoor engine terms, not Quake1 terms.
Posted on 2003-12-18 23:19:57 by Homer