ifndef                  _VERTICES_ASM
_VERTICES_ASM           equ     1

; ------------------------------------------------------
; Structures
VERTEX                  struct
x                       real4   ?
y                       real4   ?
z                       real4   ?
VERTEX                  ends
LPVERTEX                typedef ptr VERTEX

; ------------------------------------------------------
; Name: Vec_Load
; Desc: Load values into a vertex
Vec_Load                proc    DestVec:LPVERTEX, X:real4, Y:real4, Z:real4
                        mov     eax, DestVec
                        fld     dword ptr [X]
                        fstp    dword ptr [eax + VERTEX.x]
                        fld     dword ptr [Y]
                        fstp    dword ptr [eax + VERTEX.y]
                        fld     dword ptr [Z]
                        fstp    dword ptr [eax + VERTEX.z]
                        ret
Vec_Load                endp

; ------------------------------------------------------
; Name: Vec_Sub
; Desc: Substraction of two vertices
Vec_Sub                 proc    uses ebx DestVec:LPVERTEX, A:LPVERTEX, B:LPVERTEX 
                        mov     eax, DestVec
                        mov     ebx, A
                        mov     ecx, B
                        fld     dword ptr [ebx + VERTEX.x]
                        fsub    dword ptr [ecx + VERTEX.x]
                        fstp    dword ptr [eax + VERTEX.x]

                        fld     dword ptr [ebx + VERTEX.y]
                        fsub    dword ptr [ecx + VERTEX.y]
                        fstp    dword ptr [eax + VERTEX.y]

                        fld     dword ptr [ebx + VERTEX.z]
                        fsub    dword ptr [ecx + VERTEX.z]
                        fstp    dword ptr [eax + VERTEX.z]
                        ret
Vec_Sub                 endp

; ------------------------------------------------------
; Name: Vec_Add
; Desc: Addition of two vertices
Vec_Add                 proc    uses ebx DestVec:LPVERTEX, A:LPVERTEX, B:LPVERTEX 
                        mov     eax, DestVec
                        mov     ebx, A
                        mov     ecx, B

                        fld     [ebx + VERTEX.x]
                        fadd    [ecx + VERTEX.x]
                        fstp    [eax + VERTEX.x]

                        fld     [ebx + VERTEX.y]
                        fadd    [ecx + VERTEX.y]
                        fstp    [eax + VERTEX.y]

                        fld     [ebx + VERTEX.z]
                        fadd    [ecx + VERTEX.z]
                        fstp    [eax + VERTEX.z]
                        ret
Vec_Add                 endp

; ------------------------------------------------------
; Name: Vec_Mul
; Desc: Multiplication of two vertices
Vec_Mul                 proc    uses ebx DestVec:LPVERTEX, A:LPVERTEX, B:LPVERTEX 
                        mov     eax, DestVec
                        mov     ebx, A
                        mov     ecx, B

                        fld     [ebx + VERTEX.x]
                        fmul    [ecx + VERTEX.x]
                        fstp    [eax + VERTEX.x]

                        fld     [ebx + VERTEX.y]
                        fmul    [ecx + VERTEX.y]
                        fstp    [eax + VERTEX.y]

                        fld     [ebx + VERTEX.z]
                        fmul    [ecx + VERTEX.z]
                        fstp    [eax + VERTEX.z]
                        ret
Vec_Mul                 endp

; ------------------------------------------------------
; Name: Vec_Copy
; Desc: Copy a vertex into another
Vec_Copy                proc    uses ebx ecx DestVec:LPVERTEX, A:LPVERTEX
                        mov     ecx, DestVec
                        mov     ebx, A
                        mov     [ecx + VERTEX.x], CMEM([ebx + VERTEX.x])
                        mov     [ecx + VERTEX.y], CMEM([ebx + VERTEX.y])
                        mov     [ecx + VERTEX.z], CMEM([ebx + VERTEX.z])
                        ret
Vec_Copy                endp

; ------------------------------------------------------
; Name: Vec_Scale
; Desc: Scale a vertex
Vec_Scale               proc    DestVec:LPVERTEX, Val:real4
                        mov     eax, DestVec

                        fld     [eax + VERTEX.x]
                        fmul    Val
                        fstp    [eax + VERTEX.x]

                        fld     [eax + VERTEX.y]
                        fmul    Val
                        fstp    [eax + VERTEX.y]

                        fld     [eax + VERTEX.z]
                        fmul    Val
                        fstp    [eax + VERTEX.z]
                        ret
Vec_Scale               endp

; ------------------------------------------------------
; Name: Vec_Div
; Desc: Divide a vertex
Vec_Div                 proc    DestVec:LPVERTEX, Val:real4
                        mov     eax, DestVec

                        fld     [eax + VERTEX.x]
                        fdiv    Val
                        fstp    [eax + VERTEX.x]

                        fld     [eax + VERTEX.y]
                        fdiv    Val
                        fstp    [eax + VERTEX.y]

                        fld     [eax + VERTEX.z]
                        fdiv    Val
                        fstp    [eax + VERTEX.z]
                        ret
Vec_Div                 endp

; ------------------------------------------------------
; Name: Vec_DotProduct
; Desc: Return the dot product of two vertices
Vec_DotProduct          proc    A:LPVERTEX, B:LPVERTEX
                        mov     eax, A
                        mov     ecx, B

                        fld     [eax + VERTEX.x]
                        fmul    [ecx + VERTEX.x]
                        
                        fld     [eax + VERTEX.y]
                        fmul    [ecx + VERTEX.y]
                        faddp   st(1), st(0)

                        fld     [eax + VERTEX.z]
                        fmul    [ecx + VERTEX.z]
                        faddp   st(1), st(0)            
                        ret
Vec_DotProduct          endp

; ------------------------------------------------------
; Name: Vec_Magnitude()
; Desc: Return the length of a vertex
Vec_Magnitude           proc    A:LPVERTEX
                        invoke  Vec_DotProduct, A, A
                        fsqrt
                        ret
Vec_Magnitude           endp

; ------------------------------------------------------
; Name: Vec_Normalize
; Desc: Normalize a vertex
Vec_Normalize           proc    uses ebx edi DestVec:LPVERTEX, A:LPVERTEX
                        local   Product:real4
    
                        mov     ebx, A
                        mov     edi, DestVec
                        invoke  Vec_DotProduct, A, A
                        fsqrt
                        fstp    Product
                        FCMP    Product, CFLT(0.0)
                        jne     Empty_Product
                        mov     [edi + VERTEX.x], 0
                        mov     [edi + VERTEX.y], 0
                        mov     [edi + VERTEX.z], 0
                        ret
Empty_Product:
                        fld     [ebx + VERTEX.x]
                        fdiv    Product
                        fstp    [edi + VERTEX.x]

                        fld     [ebx + VERTEX.y]
                        fdiv    Product
                        fstp    [edi + VERTEX.y]

                        fld     [ebx + VERTEX.z]
                        fdiv    Product
                        fstp    [edi + VERTEX.z]
                        ret
Vec_Normalize           endp

; ------------------------------------------------------
; Name: Vec_Scale01
; Desc: Scale a vertex
Vec_Scale01             proc    DestVec:LPVERTEX
                        
                        invoke  Vec_Normalize, DestVec, DestVec
                        
                        mov     eax, DestVec
                        fld     [eax + VERTEX.x]
                        fmul    CFLT(0.5)
                        fadd    CFLT(0.5)
                        fstp    [eax + VERTEX.x]

                        fld     [eax + VERTEX.y]
                        fmul    CFLT(0.5)
                        fadd    CFLT(0.5)
                        fstp    [eax + VERTEX.y]

                        fld     [eax + VERTEX.z]
                        fmul    CFLT(0.5)
                        fadd    CFLT(0.5)
                        fstp    [eax + VERTEX.z]
                        ret
Vec_Scale01             endp

; ------------------------------------------------------
; Name: Rotate_X
; Desc: Rotate a vertex around X axis
Rotate_X                proc    DestVec:LPVERTEX, Degrees:real4
                        local   Radians_Sin:real4
                        local   Radians_Cos:real4

                        mov     eax, DestVec

                        fld     Degrees
                        fmul    CFLT(0.0174532)
                        fld     st(0)
                        fcos
                        fstp    Radians_Cos 
                        fsin
                        fstp    Radians_Sin

                        fld     [eax + VERTEX.z]
                        fmul    Radians_Cos
                        fld     [eax + VERTEX.x]
                        fld     st(0)
                        fmul    Radians_Cos
                        fld     [eax + VERTEX.z]
                        fmul    Radians_Sin
                        faddp   st(1), st(0)
                        fstp    [eax + VERTEX.x]
                        fmul    Radians_Sin
                        fsubp   st(1), st(0)
                        fstp    [eax + VERTEX.z]
                        ret
Rotate_X                endp

; ------------------------------------------------------
; Name: Rotate_Y
; Desc: Rotate a vertex around Y axis
Rotate_Y                proc    DestVec:LPVERTEX, Degrees:real4
                        local   Radians_Sin:real4
                        local   Radians_Cos:real4

                        mov     eax, DestVec

                        fld     Degrees
                        fmul    CFLT(0.0174532)
                        fld     st(0)
                        fcos
                        fstp    Radians_Cos 
                        fsin
                        fstp    Radians_Sin

                        fld     [eax + VERTEX.z]
                        fmul    Radians_Cos
                        fld     [eax + VERTEX.y]
                        fld     st(0)
                        fmul    Radians_Cos
                        fld     [eax + VERTEX.z]
                        fmul    Radians_Sin
                        faddp   st(1), st(0)
                        fstp    [eax + VERTEX.y]
                        fmul    Radians_Sin
                        fsubp   st(1), st(0)
                        fstp    [eax + VERTEX.z]
                        ret
Rotate_Y                endp

; ------------------------------------------------------
; Name: Rotate_Z
; Desc: Rotate a vertex around Z axis
Rotate_Z                proc    DestVec:LPVERTEX, Degrees:real4
                        local   Radians_Sin:real4
                        local   Radians_Cos:real4

                        mov     eax, DestVec

                        fld     Degrees
                        fmul    CFLT(0.0174532)
                        fld     st(0)
                        fcos
                        fstp    Radians_Cos 
                        fsin
                        fstp    Radians_Sin

                        fld     [eax + VERTEX.x]
                        fmul    Radians_Cos
                        fld     [eax + VERTEX.y]
                        fld     st(0)
                        fmul    Radians_Cos
                        fld     [eax + VERTEX.x]
                        fmul    Radians_Sin
                        faddp   st(1), st(0)
                        fstp    [eax + VERTEX.y]
                        fmul    Radians_Sin
                        fsubp   st(1), st(0)
                        fstp    [eax + VERTEX.x]
                        ret
Rotate_Z                endp

; ------------------------------------------------------
; Name: Vec_CrossProduct
; Desc: Calc the cross product of two vertices
Vec_CrossProduct        proc    uses ebx esi DestVec:LPVERTEX, A:LPVERTEX, B:LPVERTEX
                        mov     eax, DestVec
                        mov     ebx, A
                        mov     esi, B
                        fld     [ebx + VERTEX.y]
                        fmul    [esi + VERTEX.z]
                        fld     [ebx + VERTEX.z]
                        fmul    [esi + VERTEX.y]
                        fsubp   st(1), st(0)
                        fstp    [eax + VERTEX.x]

                        fld     [ebx + VERTEX.z]
                        fmul    [esi + VERTEX.x]
                        fld     [ebx + VERTEX.x]
                        fmul    [esi + VERTEX.z]
                        fsubp   st(1), st(0)
                        fstp    [eax + VERTEX.y]

                        fld     [ebx + VERTEX.x]
                        fmul    [esi + VERTEX.y]
                        fld     [ebx + VERTEX.y]
                        fmul    [esi + VERTEX.x]
                        fsubp   st(1), st(0)
                        fstp    [eax + VERTEX.z]
                        ret
Vec_CrossProduct        endp

; ------------------------------------------------------
; Name: Vec_Normal
; Desc: Calc the normal of 3 vertices
Vec_Normal              proc    DestVec:LPVERTEX, A:LPVERTEX, B:LPVERTEX , _C:LPVERTEX
                        local   d1:VERTEX 
                        local   d2:VERTEX 

                        invoke  Vec_Sub, addr d1, B, A
                        invoke  Vec_Sub, addr d2, _C, A
                        invoke  Vec_CrossProduct, DestVec, addr d1, addr d2
                        ret
Vec_Normal              endp

; ------------------------------------------------------
; Name: Vec_RadToDeg
; Desc: Convert radians angles into degrees ones
Vec_RadToDeg            proc    Radians:real4
                        fld     Radians
                        fmul    CFLT(180.0)     
                        fldpi
                        fdivp   st(1), st(0)            
                        ret
Vec_RadToDeg            endp

; ------------------------------------------------------
; Name: Vec_DegToRad
; Desc: Convert degrees angles into radians ones
Vec_DegToRad            proc    Degrees:real4
                        fld     Degrees
                        fmul    CFLT(0.0174532)
                        ret
Vec_DegToRad            endp

; ------------------------------------------------------
; Name: Vec_Unit
; Desc: Return a vertex of length 1 in the given direction
Vec_Unit                proc    DestVec:LPVERTEX, A:LPVERTEX
                        local   Magn:real4

                        invoke  Vec_Magnitude, A
                        fstp    Magn
                        invoke  Vec_Copy, DestVec, A
                        invoke  Vec_Div, DestVec, Magn
                        ret
Vec_Unit                endp

endif