I'm finding better results working on various projects for my 2D engine, citing necessity is the mother of invention (or re-invention) - rather than lay out specific functions and try to test them.. anyway my question is:

I'm working on a simple 'cannon-ball physics' type game, and I can never keep this straight:

Do my angles need to be expressed in degrees or radians?

An observation from an FPU tutorial from Raymond Filiatreault's site.. It makes sense but I didn't know you could do:
add esp,4 instead of pop to keep from trashing it the current register.. that is too kewlll...
then if I sub esp,4 do I mov esp,value?

Thnx.
Posted on 2003-11-08 13:18:31 by drarem
Angles should be in radians. You know you could just have tried both and see which worked.
Posted on 2003-11-08 14:46:31 by Eóin
ty - well I am already working with one unknown and I try to keep those to a minimum.

rewrite the first unknown 10 times ten different ways only to find out I had the second unknown wrong, at that would have been an easy fix...
Posted on 2003-11-08 14:55:57 by drarem
?The angle must be expressed in radians
is clearly specified in the first paragraph of the description for each of the fsin, fcos, fsincos and ftptan instructions in the quoted tutorial.

You can keep track of your angles in degrees (which I personally do most of the time) but you then have to convert them to radians before using them with the above trig instructions. The conversion is also explained in the tutorial.

As for the add esp,4, POPing the stack effectively adds 4 to the ESP register after retrieving the value at into a register or a memory variable. If that value is useless, modifying directly the ESP avoids the trashing of a commodity.

The sub esp,4 would only reserve space on the stack without modifying the content of that space. You would often see a similar instruction generated by an assembler for LOCAL variables in a procedure.

Raymond
Posted on 2003-11-08 22:34:59 by Raymond
alright, I've tried several times to get it right, I am close but still no cigar...


in pseudocode, this is what I need:

.for ex = 0 to 120
vx=vo*cos(a*pi/180)
vy=vo*sin(a*pi/180)
vy=vy + (-0.0000981*ex*ex) ;ex is the current time increment, for gravity's sake

x=x+vx
y=y-vy
plot x,y

next ex



definitions:



.data
blax REAL4 0.0
blay REAL4 0.0 ;coords x/y for flight of ball

PIdiv180 REAL4 0.0174533
angl REAL4 15.0 ;angle of descent
cspd REAL4 1.2
gravity REAL4 -0.0000981
VX REAL4 0.0 ;horizontal velocity = CSPD * cos(angl)
VY REAL4 0.0 ;vertical velocity = CSPD * sin(angl)
ex REAL4 0.0



... and code:


finit
fild angl
fimul PIdiv180
fcos
fmul cspd
fistp VX

fild angl
fimul PIdiv180
fsin
fmul cspd
fistp VY

fild ex
fimul ex
fmul gravity
fistp vy

;gravity seems to be working ok, the angle don't fly.. 15 shoots it at 45
; and 45 shoots it straight up in the air


mov eax,vy
add VY,eax

add ex,1

mov eax,VX
add eax,1
add blax,eax

mov eax,VY
sub blay,eax

invoke PlotPixel, blax, blay

Posted on 2003-11-09 16:06:30 by drarem


finit
[COLOR=red]fild angl[/COLOR]
[COLOR=red]fimul PIdiv180[/COLOR]
fcos
fmul cspd
[COLOR=red]fistp VX[/COLOR]

[COLOR=red]fild angl[/COLOR]
[COLOR=red]fimul PIdiv180[/COLOR]
fsin
fmul cspd
[COLOR=red]fistp VY[/COLOR]

[COLOR=red]fild ex
fimul ex[/COLOR]
fmul gravity
[COLOR=red]fistp vy[/COLOR]

;gravity seems to be working ok, the angle don't fly.. 15 shoots it at 45
; and 45 shoots it straight up in the air


mov eax,vy
add VY,eax

add ex,1

mov eax,VX
add eax,1
add blax,eax

mov eax,VY
sub blay,eax

invoke PlotPixel, blax, blay


There is a bunch of stuff going wrong here. All your memory is defined as IEEE floating point however your intructing your FPU to treat the memory as registered memory (integers). This can not be good!...

I would try this for your PSEUDO code (i didnt test this):



.data
PI_by_180 REAL4 0.0174533
Gravity REAL4 -0.0000981

.data?
Angle REAL4 ?
Vo REAL4 ?
Vx REAL4 ?
Vy REAL4 ?


PlotFunct PROC uses ebx esi edi integer_Vo:DWORD, integer_degrees:DWORD, integer_X:DWORD, interger_Y:DWORD
LOCAL ex :DWORD
LOCAL int_X :DWORD
LOCAL int_Y :DWORD
LOCAL TempAngle :REAL4

; Set initial values
finit

; Init Pixel positions
;_____________________
mov eax, integer_X
mov int_X, eax

mov eax, integer_Y
mov int_Y, eax

; Vo = (REAL4) interger_Vo
;_________________________
lea edx, Vo
fild integer_Vo
fstp REAL4 PTR [edx]

; Angle = (REAL4) integer_Angle
;______________________________
lea edx, Angle
fild integer_degrees
fld st(0)
fstp REAL4 PTR [edx]

; TempAngle = Degrees * (Pi/180)
; Note: Angle already on stack at ST(0)
;______________________________________
lea edx, PI_by_180
lea ecx, TempAngle
fld REAL4 PTR [edx]
fmul
fstp REAL4 PTR [ecx]

; Stack is now empty, begin loop
;_______________________________

xor ebx, ebx
.while ebx <= 120

; Loop Begins Here

;vx=vo*cos(a*pi/180)
;vy=vo*sin(a*pi/180)
;___________________

lea esi, Vx
lea edi, Vy
lea edx, Vo
lea ecx, TempAngle

fld REAL4 PTR [ecx] ; St0 = TempAngle
fld st(0) ; st1 = st0
fcos
fld REAL4 PTR [edx] ; St0 = Vo & St1 = Cos(@) & st2 = TempAngle
fmul
fstp REAL4 PTR [esi] ; St0 = TempAngle

fsin
fld REAL4 PTR [edx] ; St0 = Vo & St1 = Sin(@)
fmul ; St0 = Vo*sin(@)

; vy=vy + (-0.0000981*ex*ex)
;___________________________
lea edx, ex
mov [edx], ebx
fild DWORD PTR [edx]
fld st(0)
fmul ; St0 = Ex*Ex & St1 = Vy

lea edx, Gravity
fld REAL4 PTR [edx]
fmul ; Sto = -Gravity*(Ex^2) & St1 = Vy

fadd ; St0 = Vy + (-Gravity*(Ex^2))
fstp REAL4 PTR [edi] ; Stack is emtpy

; x=x+vx
;_______

lea edx, ex
fld REAL4 PTR [esi] ; st0 = vx
fistp DWORD PTR [edx] ; ex = (integer)Vx
mov eax, [edx]
add int_X, eax

; y=y-vy
;_______
fld REAL4 PTR [edi] ; st0 = Vy
fispt DWORD PTR [edx] ; ex = (integer)Vy
mov eax, [edx]
sub int_y, eax

; Plot the new pixels
;____________________
invoke PlotMyPixels, int_X, int_Y


; Loop ends here

inc ebx
.endw

ret
PlotFunct ENDP


Its not opimized or anything, but hopefully it should help you see thru it... I kept it simple deliberately. The first half is initialization stuff (guess work on my behalf), and the loop is your Pseudo code translated...
Hope it helps..
:NaN:
Posted on 2003-11-09 20:42:39 by NaN
I noticed that only Vy is changing due to gravity and Ex. So i pulled the reduntant stuff out of the inner loop as it can be pre-calculated and stored for speed in the loop. Vx is calculated once and converted to integer from in "x_const". As well Vx and Vy is calculated only once initially, but in the loop Vy is modified from each itteration. Lastly the intergers X & Y are updated and the plot call is made.

Here is a more lean & mean version of your above Pseudo code, Hope you like:


.data
PI_by_180 REAL4 0.0174533
Gravity REAL4 -0.0000981

.data?
Vo REAL4 ?
Vx REAL4 ?
Vy REAL4 ?


PlotFunct PROC uses ebx esi edi integer_Vo:DWORD, integer_degrees:DWORD, integer_X:DWORD, interger_Y:DWORD
LOCAL ex :DWORD
LOCAL x_const :DWORD

; Set initial values
finit

; Vo = (REAL4) interger_Vo
;_________________________
lea edx, Vo
fild integer_Vo
fstp REAL4 PTR [edx]

; TempAngle = Degrees * (Pi/180)
; Note: Angle already on stack at ST(0)
;______________________________________
lea edx, PI_by_180
fild integer_degrees
fld REAL4 PTR [edx]
fmul ; St0 = TempAngle

;vx=vo*cos(a*pi/180)
;vy=vo*sin(a*pi/180)
;___________________

lea edi, Vy
lea edx, Vo
lea ecx, x_const

fld st(0) ; st1 = st0 = TempAgnle
fcos
fld REAL4 PTR [edx] ; St0 = Vo & St1 = Cos(@) & st2 = TempAngle
fmul ' St0 = Vx
fistp DWORD PTR [ecx] ; St0 = TempAngle

fsin
fld REAL4 PTR [edx] ; St0 = Vo & St1 = Sin(@)
fmul ; St0 = Vo*sin(@)
fstp REAL4 PTR [edi] ; St0 = emtpy


; Stack is now empty, begin loop (ESI & EBX must be preserved)
;_______________________________

xor ebx, ebx
.while ebx <= 120

; Loop Begins Here

lea edx, ex
lea ecx, Gravity

; vy=vy + (-0.0000981*ex*ex)
;___________________________
fld REAL4 PTR [edi] ; st0 = Vy
mov [edx], ebx ; Ex = ebx
fild DWORD PTR [edx]
fld st(0)
fmul ; St0 = Ex*Ex & St1 = Vy
fld REAL4 PTR [ecx]
fmul ; Sto = -Gravity*(Ex^2) & St1 = Vy
fadd ; St0 = Vy + (-Gravity*(Ex^2))
fst REAL4 PTR [edi] ; St0 = Vy + (-Gravity*(Ex^2))

; y=y-vy
;_______
fispt DWORD PTR [edx] ; ex = (integer)Vy
mov eax, [edx]
sub integer_y, eax

; x=x+vx
;_______
mov eax, x_const
add integer_X, eax

; Plot the new pixels
;____________________
invoke PlotMyPixels integer_X, integer_Y


; Loop ends here

inc ebx
.endw

ret
PlotFunct ENDP
Posted on 2003-11-09 21:14:12 by NaN
1st:
I don't know if your source is case sensitive, but I don't see any variable labeled "vy" in the .data section.

2nd:
In addition to NaN's remarks about directing the FPU to load the wrong data types, your balistics seem to be totally wrong.

You need to compute the horizontal and vertical velocities of the projectile based on the initial angle, but those remain constant throughout the trajectory; only the negative velocity due to gravity will change.

Technically, you should be plotting the distances travelled; but, by plotting at every unit of time, you can accumulate the calculated velocities as if they were distances.

This would be my version (not tested) assuming your PlotPixel function used integers as parameters.
.data

ex dd 0
coordx dd 0 ;the integers used for plotting
coordy dd 0 ; id
angle0 dw 15 ;assuming only integer values to be used
w180 dw 180 ;WORDS can also be used with the FPU
cspd REAL4 1.2
gravity REAL4 -0.0000981
VX REAL4 0.0 ;horizontal distance per unit time
VY REAL4 0.0 ;vertical distance per unit time
distX REAL4 0.0 ;total horizontal distance travelled
distY REAL4 0.0 ;total vertical distance travelled

.code
finit
fldpi
fidiv w180
fimul angle0 ;start angle now in radians
fsincos ;st=cos, st1=sin
fmul cspd ;st=cspd*cos, st1=sin
fstp VX ;st=sin
fmul cspd ;st=cspd*sin
fstp VY

invoke PlotPixel, coordx,coordy ;plot starting point

loop_here:

inc ex
fild ex
fmul st,st ;st=ex*ex
fmul gravity ;st=ex*ex*gravity
fadd VY ;st=ex*ex*gravity+VY
fadd distY ;st=ex*ex*gravity+VY+distY
fst distY ;keep as REAL4
fistp coordy ;store as rounded integer

fld distX ;st=distX
fadd VX ;st=distX+VX
fst distX ;keep as REAL4
fistp coordx ;store as rounded integer

invoke PlotPixel, coordx,coordy
cmp ex,120
jbe loop_here

Raymond
Posted on 2003-11-09 22:02:51 by Raymond
Sorry for error. My head must have gone a little balistic late at night.

The a*(t^2) calculates the cumulative distance travelled due to an accelaration a over a period of time t (technically it should read 0.5a*t^2).
It must not be accumulated in each iteration. The computation of the "coordy" in my previous post should thus be altered as follows:
fld   VY        ;st=VY

fadd distY ;st=VY+distY
fst distY ;cumulative distance due to velocity
inc ex
fild ex ;st=ex, st1=VY+distY
fmul st,st ;st=ex*ex, st1=VY+distY
fmul gravity ;st=ex*ex*gravity, st1=VY+distY
fadd ;st=ex*ex*gravity+VY+distY
fistp coordy ;store as rounded integer
Raymond
Posted on 2003-11-10 08:15:53 by Raymond
thank you Nan and Raymond, for your help.. I think I will try Nan's way first, it seems like I will learn more from it.. as for your way Raymond, I tried plugging it in and the ball goes down and then back up. I think it has to do with:

vy=vy+(gravity*t*t)
Y=Y-vy ;<=== this needs to be separate, (VY+distY) - (gravity*t^2) working on parenthesis before subtraction
X=X+vx

why can't I do fmul ST (or fmul ex) - it wont multiply the value by its stored value?

when does the value stored in the ST(n) shift.. when you specify the P , or can it do it on an add? Is there a general rule of thumb to know when that happens? I think that is the most confusing for me.

I take it I can't use FADD to add integers or FIADD for floating point??

I've come to realize also, fild works with integers and fld with floating point numbers (as it says in your docs) - I take it dwords, real4's, etc.. can be signed or unsigned and I don't have to worry bout that as I do with the decimals.
Posted on 2003-11-10 09:47:00 by drarem

thank you Nan and Raymond, for your help.. I think I will try Nan's way first, it seems like I will learn more from it.. as for your way Raymond, I tried plugging it in and the ball goes down and then back up. I think it has to do with:

vy=vy+(gravity*t*t)
Y=Y-vy ;<=== this needs to be separate, (VY+distY) - (gravity*t^2) working on parenthesis before subtraction
X=X+vx

why can't I do fmul ST (or fmul ex) - it wont multiply the value by its stored value?

when does the value stored in the ST(n) shift.. when you specify the P , or can it do it on an add? Is there a general rule of thumb to know when that happens? I think that is the most confusing for me.

I take it I can't use FADD to add integers or FIADD for floating point??

I've come to realize also, fild works with integers and fld with floating point numbers (as it says in your docs) - I take it dwords, real4's, etc.. can be signed or unsigned and I don't have to worry bout that as I do with the decimals.


(1) FMUL if i remember correctlly will only work on ST(0) and ST(1), or ST(0) and Memory.

(2) Yes, the stack drops when "popped", just like the normal ESP stack, except the FPU stack has only 8 positions. When FLD is like Push, and FSTP is like POP. However, FST is only a memory write, the stack is unaffected.

(3) The "I" commands are only for bringing data into or out of the FPU stack. Then stack is *ALWAYS* a 10 byte IEEE floating point. So your REAL4's or REAL8's, or DWORDS are all converted to a "REAL10 or TWORD" on the stack. This is why you specificy the data size to the command. So no, the FIADD is not needed even if 4.0 is on the stack. FADD will surfice, since its already converted to floating point.

(4) As for signed dwords, im not too sure. I would check the doc's.

Regards,
:NaN:
Posted on 2003-11-10 11:48:45 by NaN
My suggestion would be that you reread Chap.1 and Chap.2 of the tutorial a few times. It may take some time for all that info to sink in.

Then make sure you read the description of each instruction you intend to use. Some of the instructions may shift register numbers back or forth.

For example, you would read that the fsincos instruction replaces the angle in st(0) with its "sin" value and then pushes all the registers to load the "cos" value into the new top register. But only if the angle is within the acceptable range. If it is "out-of-range", the angle value would then stay unaltered in the top register and no register is "pushed"!!!

Raymond
Posted on 2003-11-10 14:20:50 by Raymond