ifndef                  _CAMERA_ASM
_CAMERA_ASM             equ     1

; ------------------------------------------------------
; Includes
                        include Vertices.asm

; ------------------------------------------------------
; Variables
qHeading                QUAT    <>
qPitch                  QUAT    <>
_Camera_Position        VERTEX  <0.0, 0.0, 0.0>
_Camera_View            VERTEX  <1.0, 0.0, 0.0>
_Camera_Right           VERTEX  <0.0, 1.0, 0.0>
_Camera_Up              VERTEX  <0.0, 1.0, 0.0>

; ------------------------------------------------------
; Name: Cam_Orientation()
; Desc: Set the camera's Pitch & Heading
Cam_Orientation         proc    uses ebx Pitch:real4, Heading:real4
                        local   _q:QUAT
                        local   _m:MATRIX

                        invoke  QuatSetValue, addr qPitch, CFLT(1.0), CFLT(0.0), CFLT(0.0), Pitch
                        invoke  QuatSetValue, addr qHeading, CFLT(0.0), CFLT(1.0), CFLT(0.0), Heading
                        invoke  QuatMul, addr qPitch, addr qHeading, addr _q
                        invoke  QuatInverse, addr _q
                        invoke  QuatToMat, addr _q, addr _m
                        invoke  glLoadMatrixf, addr _m
                        ret
Cam_Orientation         endp

; ------------------------------------------------------
; Name: Quat_RotateX()
; Desc: Rotate a quaternion on X axis
Quat_RotateX            proc    Quat:LPQUAT, RotX:real4
                        invoke  QuatSetValue, Quat, CFLT(0.0), CFLT(1.0), CFLT(0.0), RotX
                        ret
Quat_RotateX            endp

; ------------------------------------------------------
; Name: Quat_RotateY()
; Desc: Rotate a quaternion on Y axis
Quat_RotateY            proc    Quat:LPQUAT, RotY:real4
                        invoke  QuatSetValue, Quat, CFLT(1.0), CFLT(0.0), CFLT(0.0), RotY
                        ret
Quat_RotateY            endp

; ------------------------------------------------------
; Name: Quat_RotateZ()
; Desc: Rotate a quaternion on Z axis
Quat_RotateZ            proc    Quat:LPQUAT, RotZ:real4
                        invoke  QuatSetValue, Quat, CFLT(0.0), CFLT(0.0), CFLT(1.0), RotZ
                        ret
Quat_RotateZ            endp

; ------------------------------------------------------
; Name: Quat_RotateXYZ()
; Desc: Rotate a quaternion on XYZ axes
Quat_RotateXYZ          proc    Quat:LPQUAT, RotX:real4, RotY:real4, RotZ:real4
                        local   _RotX:real4
                        local   _RotY:real4
                        local   _RotZ:real4

                        ; Convert them into radians
                        fld     RotX
                        fmul    CFLT(0.0174532)
                        fstp    _RotX
                        fld     RotY
                        fmul    CFLT(0.0174532)
                        fstp    _RotY
                        fld     RotZ
                        fmul    CFLT(0.0174532)
                        fstp    _RotZ
                        invoke  EulerToQuat, _RotY, _RotX, _RotZ, Quat
                        invoke  QuatInverse, Quat
                        ret
Quat_RotateXYZ          endp

; ------------------------------------------------------
; Name: Matrix_Translate()
; Desc: Set the positions in a matrix
Matrix_Translate        proc    Matrix:LPMATRIX, PosX:real4, PosY:real4, PosZ:real4
                        mov     eax, Matrix
                        fld     PosX
                        fstp    [eax + MATRIX._41]
                        fld     PosY
                        fstp    [eax + MATRIX._42]
                        fld     PosZ
                        fstp    [eax + MATRIX._43]
                        ret
Matrix_Translate        endp

; ------------------------------------------------------
; Name: Camera_Rotate()
; Desc: Rotate the camera around the axes
Camera_Rotate           proc    Degrees:LPVERTEX
                        local   Tmp_Vec:VERTEX
                        local   Radians_Sin:real4
                        local   Radians_Cos:real4
                        local   View:VERTEX
                        local   Right:VERTEX
                        local   Up:VERTEX

                        mov     eax, [Degrees]
                        invoke  Vec_DegToRad, [eax + VERTEX.y]
                        fld     st(0)
                        fsin
                        fstp    Radians_Sin
                        fcos
                        fstp    Radians_Cos

                        invoke  Vec_Copy, addr View, addr _Camera_View
                        invoke  Vec_Scale, addr View, Radians_Cos
                        invoke  Vec_Copy, addr Up, addr _Camera_Up
                        invoke  Vec_Scale, addr Up, Radians_Sin
                        invoke  Vec_Add, addr View, addr View, addr Up
                        invoke  Vec_Normalize, addr _Camera_View, addr View
                        invoke  Vec_CrossProduct, addr _Camera_Up, addr _Camera_View, addr _Camera_Right
                        invoke  Vec_Scale, addr _Camera_Up, CFLT(-1.0)

                        mov     eax, [Degrees]
                        invoke  Vec_DegToRad, [eax + VERTEX.x]
                        fld     st(0)
                        fsin
                        fstp    Radians_Sin
                        fcos
                        fstp    Radians_Cos

                        invoke  Vec_Copy, addr View, addr _Camera_View
                        invoke  Vec_Scale, addr View, Radians_Cos
                        invoke  Vec_Copy, addr Right, addr _Camera_Right
                        invoke  Vec_Scale, addr Right, Radians_Sin
                        invoke  Vec_Sub, addr View, addr View, addr Right
                        invoke  Vec_Normalize, addr _Camera_View, addr View
                        invoke  Vec_CrossProduct, addr _Camera_Right, addr _Camera_View, addr _Camera_Up

                        mov     eax, [Degrees]
                        invoke  Vec_DegToRad, [eax + VERTEX.z]
                        fld     st(0)
                        fsin
                        fstp    Radians_Sin
                        fcos
                        fstp    Radians_Cos

                        invoke  Vec_Copy, addr Right, addr _Camera_Right
                        invoke  Vec_Scale, addr Right, Radians_Cos
                        invoke  Vec_Copy, addr Up, addr _Camera_Up
                        invoke  Vec_Scale, addr Up, Radians_Sin
                        invoke  Vec_Add, addr Right, addr Right, addr Up
                        invoke  Vec_Normalize, addr _Camera_Right, addr Right
                        invoke  Vec_CrossProduct, addr _Camera_Up, addr _Camera_View, addr _Camera_Right
                        invoke  Vec_Scale, addr _Camera_Up, CFLT(-1.0)
                        ret
Camera_Rotate           endp

; ------------------------------------------------------
; Name: Camera_Move()
; Desc: Rotate a camera around Y axis
Camera_Move             proc    Position:LPVERTEX
                        local   Dist:real4
                        local   View:VERTEX
                        local   Right:VERTEX
                        local   Up:VERTEX
                        
                        mov     eax, Position
                        fld     [eax + VERTEX.z]
                        fstp    Dist
                        invoke  Vec_Copy, addr View, addr _Camera_View
                        invoke  Vec_Scale, addr View, Dist
                        invoke  Vec_Add, addr _Camera_Position, addr _Camera_Position, addr View

                        mov     eax, Position
                        fld     [eax + VERTEX.x]
                        fstp    Dist
                        invoke  Vec_Copy, addr Right, addr _Camera_Right
                        invoke  Vec_Scale, addr Right, Dist
                        invoke  Vec_Add, addr _Camera_Position, addr _Camera_Position, addr Right

                        mov     eax, Position
                        fld     [eax + VERTEX.y]
                        fstp    Dist
                        invoke  Vec_Copy, addr Up, addr _Camera_Up
                        invoke  Vec_Scale, addr Up, Dist
                        invoke  Vec_Add, addr _Camera_Position, addr _Camera_Position, addr Up
                        ret
Camera_Move             endp

; ------------------------------------------------------
; Name: Camera_LookAt()
; Desc: Send the camera position to opengl
Camera_LookAt           proc
                        local   _View_Position:VERTEX
                        
                        invoke  Vec_Add, addr _View_Position, addr _Camera_Position, addr _Camera_View
                        invoke  gluLookAt, FLT2DBL(_Camera_Position.x), \
                                           FLT2DBL(_Camera_Position.y), \
                                           FLT2DBL(_Camera_Position.z), \
                                           FLT2DBL(_View_Position.x), \
                                           FLT2DBL(_View_Position.y), \
                                           FLT2DBL(_View_Position.z), \
                                           FLT2DBL(_Camera_Up.x), \
                                           FLT2DBL(_Camera_Up.y), \
                                           FLT2DBL(_Camera_Up.z)
                        ret
Camera_LookAt           endp

endif
