ifndef                  _SIMPLE_OBJECT_ASM
_SIMPLE_OBJECT_ASM      equ     1

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

; ------------------------------------------------------
; Cosntants
ifndef                  SEEK_SET
SEEK_SET                equ     0
endif
ifndef                  SEEK_CUR
SEEK_CUR                equ     1
endif
ifndef                  SEEK_END
SEEK_END                equ     2
endif

; ------------------------------------------------------
; Structures
VERTEX_DAT              struct
Coords                  VERTEX  <?>
TxU                     real4   ?
TxV                     real4   ?
VERTEX_DAT              ends
LPVERTEX_DAT            typedef ptr VERTEX_DAT

FACE_DAT                struct
Normals                 VERTEX  <?>
Tangents                VERTEX  <?>
BiNormals               VERTEX  <?>
FACE_DAT                ends
LPFACE_DAT              typedef ptr FACE_DAT

; ------------------------------------------------------
; Functions
_Create_TB              proto   :LPVERTEX_DAT, :LPVERTEX_DAT, :LPVERTEX_DAT, :LPVERTEX, :LPVERTEX

; ------------------------------------------------------
; Variables
_Ident_Tangents         VERTEX  <1.0, 0.0, 0.0>
_Ident_BiNormals        VERTEX  <0.0, 1.0, 0.0>
_dwDatas                dd      0
_fpDatas                VERTEX_DAT <>
_fpDatas_Norm           VERTEX_DAT <>
                        VERTEX_DAT <>
                        VERTEX_DAT <>
_dwFormat               db      "%d",0
_fpFormat               db      "%f",0
_VecFormat              db      "%f %f %f",0
_VecDatFormat           db      "%f %f %f %f %f",0

; ------------------------------------------------------
; Name: Load_OBJECT
; Desc: Load a simple object
Load_OBJECT             proc    OBJECT_FileName:dword
                        local   Object_File:dword
                        local   Object_Datas:dword
                        local   FSize:dword

                        ; Load object into memory
                        push    CSTR("r")
                        push    OBJECT_FileName
                        call    fopen
                        mov     Object_File, eax
                        add     esp, (2 * 4)
                        .if     eax != NULL
                                mov     Object_File, eax
                                xor     edi, edi
                                push    offset _dwDatas
                                push    offset _dwFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (3 * 4)
                                add     edi, 4
                                mov     ecx, _dwDatas
                                .if     _dwDatas < 1
                                        ; Mangled file format
                                        jmp     Err_File_Format
                                .endif
Count_Faces:                    push    ecx
                                push    offset _dwDatas
                                push    offset _dwFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (3 * 4)
                                ; We need at least 1 face of 3 vertices
                                .if     _dwDatas < 3
                                        ; Mangled file format
                                        jmp     Err_File_Format
                                .endif
                                push    _dwDatas
                                add     edi, 4
                                add     edi, sizeof FACE_DAT            ; Complete with tangents & binormals
                                push    offset _fpDatas.Coords.z
                                push    offset _fpDatas.Coords.y
                                push    offset _fpDatas.Coords.x
                                push    offset _VecFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (5 * 4)
                                pop     ecx
                                mov     eax, ecx
                                imul    eax, sizeof VERTEX_DAT
                                add     edi, eax
Check_Datas:                    push    ecx
                                push    offset _fpDatas.TxV
                                push    offset _fpDatas.TxU
                                push    offset _fpDatas.Coords.z
                                push    offset _fpDatas.Coords.y
                                push    offset _fpDatas.Coords.x
                                push    offset _VecDatFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (7 * 4)
                                pop     ecx
                                loop    Check_Datas
                                pop     ecx
                                dec     ecx
                                jnz     Count_Faces
                                push    edi
                                mov     Object_Datas, ALLOCMEM(edi)
                                .if     Object_Datas == FALSE
Err_File_Format:                        push    Object_File
                                        call    fclose
                                        add     esp, 4
                                        xor     eax, eax
                                        ret
                                .endif
                                pop     ecx
                                ; Go back to beginning of file
                                push    SEEK_SET
                                push    0
                                push    Object_File
                                call    fseek
                                add     esp, (3 * 4)
                                mov     esi, Object_File
                                mov     edi, Object_Datas
                                push    offset _dwDatas
                                push    offset _dwFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (3 * 4)
                                mov     eax, _dwDatas
                                mov     ecx, eax
                                stosd
Store_Faces:                    push    ecx
                                push    offset _dwDatas
                                push    offset _dwFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (3 * 4)
                                mov     eax, _dwDatas
                                push    eax
                                stosd
                                push    offset _fpDatas.Coords.z
                                push    offset _fpDatas.Coords.y
                                push    offset _fpDatas.Coords.x
                                push    offset _VecFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (5 * 4)
                                ; Copy the normals
                                lea     esi, offset _fpDatas
                                mov     ecx, sizeof VERTEX
                                rep     movsb
                                push    edi
                                ; Read the 3 first VERTEX_DAT
                                mov     ecx, 3
                                lea     edi, _fpDatas_Norm
Load_Norm_Vecs:                 push    ecx
                                push    offset _fpDatas.TxV
                                push    offset _fpDatas.TxU
                                push    offset _fpDatas.Coords.z
                                push    offset _fpDatas.Coords.y
                                push    offset _fpDatas.Coords.x
                                push    offset _VecDatFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (7 * 4)
                                lea     esi, offset _fpDatas
                                mov     ecx, sizeof VERTEX_DAT
                                rep     movsb
                                pop     ecx
                                dec     ecx
                                jnz     Load_Norm_Vecs
                                pop     edi
                                lea     esi, _fpDatas_Norm
                                invoke  _Create_TB, addr [esi], addr [esi + sizeof VERTEX_DAT], addr [esi + (sizeof VERTEX_DAT * 2)], addr [edi], addr [edi + sizeof VERTEX]
                                add     edi, sizeof FACE_DAT - sizeof VERTEX
                                lea     esi, offset _fpDatas_Norm
                                mov     ecx, sizeof VERTEX_DAT * 3
                                rep     movsb
                                pop     ecx
                                ; Complete with the rest
                                sub     ecx, 3
                                jz      No_More_Vertices
Store_Datas:                    push    ecx
                                push    offset _fpDatas.TxV
                                push    offset _fpDatas.TxU
                                push    offset _fpDatas.Coords.z
                                push    offset _fpDatas.Coords.y
                                push    offset _fpDatas.Coords.x
                                push    offset _VecDatFormat
                                push    Object_File
                                call    fscanf
                                add     esp, (7 * 4)
                                lea     esi, offset _fpDatas
                                mov     ecx, sizeof VERTEX_DAT
                                rep     movsb
                                pop     ecx
                                loop    Store_Datas
No_More_Vertices:               pop     ecx
                                dec     ecx
                                jnz     Store_Faces
                                push    Object_File
                                call    fclose
                                add     esp, 4
                                mov     eax, Object_Datas
                        .endif
                        ret
Load_OBJECT             endp

; ------------------------------------------------------
; Name: Unload_BMP
; Desc: Free an allocated object memory
Unload_OBJECT           proc    Object_Datas:dword
                        mov     eax, Object_Datas
                        test    eax, eax
                        jz      @F
                        FREEMEM eax
@@:                     ret
Unload_OBJECT           endp

; ------------------------------------------------------
; Name: _Create_TB
; Desc: Calc the tangents & binormals (converted from a routine i found on the web)
_Create_TB              proc    uses ebx esi edi Vec1:LPVERTEX_DAT, Vec2:LPVERTEX_DAT, Vec3:LPVERTEX_DAT, Tangents:LPVERTEX, BiNormals:LPVERTEX
                        local   vDirVec_v2_to_v1:VERTEX
                        local   vDirVec_v3_to_v1:VERTEX
                        local   vDirVec_v2u_to_v1u:real4
                        local   vDirVec_v2v_to_v1v:real4
                        local   vDirVec_v3u_to_v1u:real4
                        local   vDirVec_v3v_to_v1v:real4
                        local   Denom:real4
                        local   Temp_Tangent:VERTEX
                        local   Temp_BiNormal:VERTEX
                        local   Temp_Normal:VERTEX
                        local   Scale_Vec:real4
                        local   Scale_Norm:real4
                        local   Tmp_Cross:VERTEX
                        
                        mov     ebx, Vec1
                        mov     esi, Vec2
                        mov     edi, Vec3
                        invoke  Vec_Sub, addr vDirVec_v2_to_v1, addr [esi + VERTEX_DAT.Coords], addr [ebx + VERTEX_DAT.Coords]
                        invoke  Vec_Sub, addr vDirVec_v3_to_v1, addr [edi + VERTEX_DAT.Coords], addr [ebx + VERTEX_DAT.Coords]
                        fld     [esi + VERTEX_DAT.TxU]
                        fsub    [ebx + VERTEX_DAT.TxU]
                        fstp    vDirVec_v2u_to_v1u
                        fld     [esi + VERTEX_DAT.TxV]
                        fsub    [ebx + VERTEX_DAT.TxV]
                        fstp    vDirVec_v2v_to_v1v
                        fld     [edi + VERTEX_DAT.TxU]
                        fsub    [ebx + VERTEX_DAT.TxU]
                        fstp    vDirVec_v3u_to_v1u
                        fld     [edi + VERTEX_DAT.TxV]
                        fsub    [ebx + VERTEX_DAT.TxV]
                        fstp    vDirVec_v3v_to_v1v
                        fld     vDirVec_v2u_to_v1u
                        fmul    vDirVec_v3v_to_v1v                      
                        fld     vDirVec_v3u_to_v1u
                        fmul    vDirVec_v2v_to_v1v
                        fsubp   st(1), st(0)
                        fstp    Denom
                        FCMP    Denom, CFLT(0.0001)
                        jae     Set_Identity
                        FCMP    Denom, CFLT(-0.0001)
                        jbe     Set_Identity
                        invoke  Vec_Copy, Tangents, addr _Ident_Tangents
                        invoke  Vec_Copy, BiNormals, addr _Ident_BiNormals
                        ret
Set_Identity:           fld1
                        fdiv    Denom
                        fstp    Scale_Vec
                        fld     vDirVec_v3v_to_v1v
                        fmul    vDirVec_v2_to_v1.x
                        fld     vDirVec_v2v_to_v1v
                        fmul    vDirVec_v3_to_v1.x
                        fsubp   st(1), st(0)
                        fmul    Scale_Vec
                        fstp    Temp_Tangent.x          
                        fld     vDirVec_v3v_to_v1v
                        fmul    vDirVec_v2_to_v1.y
                        fld     vDirVec_v2v_to_v1v
                        fmul    vDirVec_v3_to_v1.y
                        fsubp   st(1), st(0)
                        fmul    Scale_Vec
                        fstp    Temp_Tangent.y
                        fld     vDirVec_v3v_to_v1v
                        fmul    vDirVec_v2_to_v1.z
                        fld     vDirVec_v2v_to_v1v
                        fmul    vDirVec_v3_to_v1.z
                        fsubp   st(1), st(0)
                        fmul    Scale_Vec
                        fstp    Temp_Tangent.z
                        fld     vDirVec_v3u_to_v1u
                        fchs
                        fmul    vDirVec_v2_to_v1.x
                        fld     vDirVec_v2u_to_v1u
                        fmul    vDirVec_v3_to_v1.x
                        faddp   st(1), st(0)
                        fmul    Scale_Vec
                        fstp    Temp_BiNormal.x
                        fld     vDirVec_v3u_to_v1u
                        fchs
                        fmul    vDirVec_v2_to_v1.y
                        fld     vDirVec_v2u_to_v1u
                        fmul    vDirVec_v3_to_v1.y
                        faddp   st(1), st(0)
                        fmul    Scale_Vec
                        fstp    Temp_BiNormal.y
                        fld     vDirVec_v3u_to_v1u
                        fchs
                        fmul    vDirVec_v2_to_v1.z
                        fld     vDirVec_v2u_to_v1u
                        fmul    vDirVec_v3_to_v1.z
                        faddp   st(1), st(0)
                        fmul    Scale_Vec
                        fstp    Temp_BiNormal.z
                        invoke  Vec_CrossProduct, addr Temp_Normal, addr Temp_Tangent, addr Temp_BiNormal
                        fld1
                        fld     Temp_Tangent.x
                        fmul    Temp_BiNormal.y
                        fmul    Temp_Normal.z
                        fld     Temp_Tangent.z
                        fmul    Temp_BiNormal.y
                        fmul    Temp_Normal.x
                        fsubp   st(1), st(0)
                        fld     Temp_BiNormal.x
                        fmul    Temp_Normal.y
                        fmul    Temp_Tangent.z
                        fld     Temp_BiNormal.z
                        fmul    Temp_Normal.y
                        fmul    Temp_Tangent.x
                        fsubp   st(1), st(0)
                        fld     Temp_Normal.x
                        fmul    Temp_Tangent.y
                        fmul    Temp_BiNormal.z
                        fld     Temp_Normal.z
                        fmul    Temp_Tangent.y
                        fmul    Temp_BiNormal.x
                        fsubp   st(1), st(0)
                        faddp   st(1), st(0)
                        faddp   st(1), st(0)
                        fdivp   st(1), st(0)
                        fstp    Scale_Norm
                        mov     esi, Tangents
                        mov     edi, BiNormals
                        invoke  Vec_CrossProduct, addr Tmp_Cross, addr Temp_BiNormal, addr Temp_Normal
                        fld     Tmp_Cross.x
                        fmul    Scale_Norm
                        fstp    [esi + VERTEX.x]
                        invoke  Vec_CrossProduct, addr Tmp_Cross, addr Temp_Normal, addr Temp_Tangent
                        fld     Tmp_Cross.x
                        fmul    Scale_Norm
                        fchs
                        fstp    [esi + VERTEX.y]
                        invoke  Vec_CrossProduct, addr Tmp_Cross, addr Temp_Tangent, addr Temp_BiNormal
                        fld     Tmp_Cross.x
                        fmul    Scale_Norm
                        fstp    [esi + VERTEX.z]
                        invoke  Vec_Normalize, esi, esi
                        invoke  Vec_CrossProduct, addr Tmp_Cross, addr Temp_BiNormal, addr Temp_Normal
                        fld     Tmp_Cross.y
                        fmul    Scale_Norm
                        fchs
                        fstp    [edi + VERTEX.x]        
                        invoke  Vec_CrossProduct, addr Tmp_Cross, addr Temp_Normal, addr Temp_Tangent
                        fld     Tmp_Cross.y
                        fmul    Scale_Norm
                        fstp    [edi + VERTEX.y]
                        invoke  Vec_CrossProduct, addr Tmp_Cross, addr Temp_Tangent, addr Temp_BiNormal
                        fld     Tmp_Cross.y
                        fmul    Scale_Norm
                        fchs
                        fstp    [edi + VERTEX.z]
                        invoke  Vec_Normalize, edi, edi
                        invoke  Vec_Scale, edi, CFLT(-1.0)
                        ret
_Create_TB              endp

endif
