Here's a handy utility class I've been working with lately.
Combined with hcall, it becomes even more useful.



;VECTOR Class
;OOP Support for 3D Vectors (ATC 3.2+)
;Written by Evil Homer on March 6, 2005
;
;Notes on use:
;Just watch out for "destructive" methods which modify the data of the object
;apon which they are called, for example, "CrossProduct".
;They are intended to be called apon "target objects", which both carry
;data as input and receive the result.


VECTOR_Magnitude = VECTOR_GetLength

class VECTOR, ,C++ compatible
void Reset ;Sets Vector to 0,0,0
void Copy:pOtherVector ;Copies "this"="other"
void Set:fx,fy,fz ;Sets Vector to x,y,z
void GetLength ;Calculates 3D length of vector, result on fpu
void SetLength:fLength ;Scales Vector to given Length
void Add:pOtherVector ;"this"="this" + "other
void Subtract:pOtherVector ;"this"="this" - "other"
void Magnitude
void Multiply:pOtherVector ;"this"="this" * "other"
void MultiplyFPU ;Multiplies "this" vector xyz * fpu value
void DivideFPU ;Divides "this" vector xyz / fpu value
void IsZero ;Returns TRUE or FALSE
void Normalize ;Destructively forces "this" vector length to 1 (unit length)
void CrossProduct:pOtherVector ;Destructively forces "this" vector = "this" cross "other"
void DotProduct:pOtherVector ;Calculates "this" dot "other" , result on fpu
void Wedge:pOtherVector, pResultVector ;Calculates vector between vectors
float x
float y
float z
endclass

VECTOR_VECTOR proc
ret
VECTOR_VECTOR endp

VECTOR_$VECTOR proc
ret
VECTOR_$VECTOR endp

VECTOR_IsZero proc
.if [ecx].VECTOR.x==0 \
&& [ecx].VECTOR.y==0 \
&& [ecx].VECTOR.z==0
return TRUE
.endif
return FALSE
VECTOR_IsZero endp

VECTOR_Reset proc
fld r4_0_0
fst [ecx].VECTOR.x
fst [ecx].VECTOR.y
fstp [ecx].VECTOR.z
ret
VECTOR_Reset endp

VECTOR_Copy proc uses ebx pOtherVector
mov ebx, pOtherVector
fld [ebx].VECTOR.x
fstp [ecx].VECTOR.x
fld [ebx].VECTOR.y
fstp [ecx].VECTOR.y
fld [ebx].VECTOR.z
fstp [ecx].VECTOR.z
ret
VECTOR_Copy endp

;Since the parameters are actually DWORD sized
;(disregarding the fact that they contain floating point values)
;we can use stack operation (push/pop) to move the data
;from the input parameters into the object data fields..
VECTOR_Set proc fx:REAL4,fy:REAL4,fz:REAL4
m2m [ecx].VECTOR.x, fx
m2m [ecx].VECTOR.y, fy
m2m [ecx].VECTOR.z, fz
ret
VECTOR_Set endp

;WARNING !! WARNING !!
;DANGER, WILL ROBINSON !!
;The result of this procedure is left on the FPU !!
VECTOR_DotProduct proc uses ebx pInputVect:ptr VECTOR
mov ebx, pInputVect
fld [ecx].VECTOR.x
fmul [ecx].VECTOR.x
fld [ecx].VECTOR.y
fmul [ecx].VECTOR.y
fld [ecx].VECTOR.z
fmul [ecx].VECTOR.z
fadd
fadd
ret
VECTOR_DotProduct endp

;This procedure calculates the crossproduct vector
;from "this" vector and some "other" vector.
;The result is stored in "this" vector.
VECTOR_CrossProduct proc uses ebx pInputVect
local vtemp:VECTOR
fld [ecx].VECTOR.x ;<-- Copy "this" vector's xyz values
fld [ecx].VECTOR.y ;<-- into a temporary vector
fld [ecx].VECTOR.z
fstp vtemp.z
fstp vtemp.y
fstp vtemp.x

mov ebx,pInputVect

fld [ebx].VECTOR.y ;<-- x = vect.y * temp.z - vect.z * temp.y;
fmul vtemp.z
fld [ebx].VECTOR.z
fmul vtemp.y
fsub
fstp [ecx].VECTOR.x

fld [ebx].VECTOR.z ;<-- y = vect.z * temp.x - vect.x * temp.z;
fmul vtemp.x
fld [ebx].VECTOR.x
fmul vtemp.z
fsub
fstp [ecx].VECTOR.y

fld [ebx].VECTOR.x ;<-- z = vect.x * temp.y - vect.y * temp.x;
fmul vtemp.y
fld [ebx].VECTOR.y
fmul vtemp.x
fsub
fstp [ecx].VECTOR.z
ret
VECTOR_CrossProduct endp

VECTOR_GetLength proc
fld [ecx].VECTOR.x
fmul [ecx].VECTOR.x
fld [ecx].VECTOR.y
fmul [ecx].VECTOR.y
fld [ecx].VECTOR.z
fmul [ecx].VECTOR.z
fadd
fadd
fsqrt
ret
VECTOR_GetLength endp

VECTOR_Subtract proc uses ebx pOtherVector
mov ebx, pOtherVector
fld [ecx].VECTOR.x
fsub [ebx].VECTOR.x
fstp [ecx].VECTOR.x
fld [ecx].VECTOR.y
fsub [ebx].VECTOR.y
fstp [ecx].VECTOR.y
fld [ecx].VECTOR.z
fsub [ebx].VECTOR.z
fstp [ecx].VECTOR.z
ret
VECTOR_Subtract endp

VECTOR_Add proc uses ebx pOtherVector
mov ebx, pOtherVector
fld [ecx].VECTOR.x
fadd [ebx].VECTOR.x
fstp [ecx].VECTOR.x
fld [ecx].VECTOR.y
fadd [ebx].VECTOR.y
fstp [ecx].VECTOR.y
fld [ecx].VECTOR.z
fadd [ebx].VECTOR.z
fstp [ecx].VECTOR.z
ret
VECTOR_Add endp

VECTOR_Multiply proc uses ebx pOtherVector
mov ebx, pOtherVector
fld [ecx].VECTOR.x
fmul [ebx].VECTOR.x
fstp [ecx].VECTOR.x
fld [ecx].VECTOR.y
fmul [ebx].VECTOR.y
fstp [ecx].VECTOR.y
fld [ecx].VECTOR.z
fmul [ebx].VECTOR.z
fstp [ecx].VECTOR.z
ret
VECTOR_Multiply endp

VECTOR_MultiplyFPU proc
local ftemp:REAL8
fstp ftemp
fld [ecx].VECTOR.x
fmul ftemp
fstp [ecx].VECTOR.x
fld [ecx].VECTOR.y
fmul ftemp
fstp [ecx].VECTOR.y
fld [ecx].VECTOR.z
fmul ftemp
fstp [ecx].VECTOR.z
ret
VECTOR_MultiplyFPU endp

VECTOR_DivideFPU proc
local ftemp:REAL8
fstp ftemp
fld [ecx].VECTOR.x
fdiv ftemp
fstp [ecx].VECTOR.x
fld [ecx].VECTOR.y
fdiv ftemp
fstp [ecx].VECTOR.y
fld [ecx].VECTOR.z
fdiv ftemp
fstp [ecx].VECTOR.z
ret
VECTOR_DivideFPU endp

VECTOR_SetLength proc fl:REAL4
local flen:REAL8
; GLfloat len = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
icall ecx, VECTOR, GetLength
fstp flen

;v.x *= l/len;
;v.y *= l/len;
;v.z *= l/len;
fld fl
fdiv flen
fmul [ecx].VECTOR.x
fstp [ecx].VECTOR.x
fld fl
fdiv flen
fmul [ecx].VECTOR.y
fstp [ecx].VECTOR.y
fld fl
fdiv flen
fmul [ecx].VECTOR.z
fstp [ecx].VECTOR.z
ret
VECTOR_SetLength endp

VECTOR_Wedge proc uses eax ebx pOtherVector, pResultVector
mov ebx,pOtherVector
mov eax,pResultVector

fld [ecx].VECTOR.y ; result.x = (v1.y * v2.z) - (v2.y * v1.z);
fmul [ebx].VECTOR.z
fld [ebx].VECTOR.y
fmul [ecx].VECTOR.z
fsub
fstp [eax].VECTOR.x

fld [ecx].VECTOR.z ; result.y = (v1.z * v2.x) - (v2.z * v1.x);
fmul [ebx].VECTOR.x
fld [ebx].VECTOR.z
fmul [ecx].VECTOR.x
fsub
fstp [eax].VECTOR.y

fld [ecx].VECTOR.x ; result.z = (v1.x * v2.y) - (v2.x * v1.y);
fmul [ebx].VECTOR.y
fld [ebx].VECTOR.x
fmul [ecx].VECTOR.y
fsub
fstp [eax].VECTOR.z

ret
VECTOR_Wedge endp

VECTOR_Normalize proc
icall ecx, VECTOR, Magnitude ; Get the magnitude of our normal

; Now that we have the magnitude, we can divide our normal by that magnitude.
; That will make our normal a total length of 1. This makes it easier to work with too.
icall ecx, VECTOR, DivideFPU
ret
VECTOR_Normalize endp




Posted on 2005-03-07 02:46:11 by Homer
Awesome class man,
Posted on 2005-04-26 02:09:04 by Rain Dog
But shouldn't the class be "non-virtual" ?
class VECTOR, ,non-virtual
Posted on 2005-04-28 23:22:45 by Ultrano
Yes it should, but I wrote it for ATC version 32.
If I'm not mistaken, non-virtual support appears in version 34.
By the way, did you include my hcall macro? This is the class which inspired me to write it, as its handy to declare temp vec3's as locals.


Posted on 2005-04-30 05:27:04 by Homer
I didn't include it - I had an idea on how to enhance the hcall and pcall macros - but I didn't find time to upgrade them :| . I'll include your hcall in ATC and reupload it at www.ultrano.com/ilix    now.
Posted on 2005-04-30 06:07:22 by Ultrano