; ------------------------------------------------------
; Bump Mapping
; Copyright (c) 2005-2016, Franck Charlet
; All rights reserved.
; ------------------------------------------------------
; buildblock RELEASE
;       CAPT %5\Release.bat
; buildblockend
; buildblock DEBUG
;       CAPT %5\Debug.bat
; buildblockend

; ------------------------------------------------------
; Constants
SCREEN_WIDTH            equ     800
SCREEN_HEIGHT           equ     600
SCREEN_BPP              equ     32

; ------------------------------------------------------
; Includes
                        include ..\Common_Src\FrameWork.asm
                        include ..\Common_Src\Picture.asm
                        include ..\Common_Src\Textures.asm
                        include ..\Common_Src\Camera.asm
                        include ..\Common_Src\Simple_Object.asm

; ------------------------------------------------------
; Constants
GEN_1ST_PASS            equ     0
GEN_2ND_PASS            equ     1
GEN_ALL_PASSES          equ     2

; ------------------------------------------------------
; Fucntions
Send_Cube_Vertex        proto   :LPFACE_DAT, :LPVERTEX, :LPVERTEX_DAT, :dword
Display_Cube            proto   :dword

; ------------------------------------------------------
; Variables
RotX                    real4   0.0
RotXSpeed               real4   40.0
RotY                    real4   0.0
RotYSpeed               real4   30.0
RotZ                    real4   0.0
RotZSpeed               real4   20.0

Texture1                PICTURE <>
Texture1_Id             dd      0
Texture_CubeMap_Id      dd      0
Texture_Dot3_Id         dd      0

Object                  dd      0

Gen_2_Passes            dd      FALSE

Bump_Light_Pos          VERTEX  <-1.0, 0.7, 2.0>
Object_Light_Pos        VERTEX  <>

Fog_Color               real4   0.0, 0.0, 0.0, 0.0

; For the gfxcard without 3 textures units
Light_Diffuse           real4   1.0, 1.0, 1.0, 1.0
Light_Ambient           real4   0.5, 0.5, 0.5, 1.0

; ------------------------------------------------------
; Name: Initialize()
; Desc: Perform the various initializations
Initialize              proc

                        invoke  glClearDepth, CDBL(1.0)
                        invoke  glHint, GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST
                        invoke  glClearColor, 0, 0, 0, CFLT(1.0)
                        invoke  glEnable, GL_NORMALIZE
                        invoke  glEnable, GL_CULL_FACE
                        invoke  glDepthFunc, GL_LEQUAL

                        invoke  Init_Textures_Context
                        .if     _HWMultiTex == FALSE
                                invoke  Set_Error_Msg, CSTR("Multi-texturing not supported on this hardware")
                                mov     eax, FALSE
                                ret
                        .endif
                        
                        ; If the gfxcard doesn't have 3 textures
                        ; we draw it in 2 passes instead
                        invoke  Get_Nbr_Textures_Units
                        .if     eax < 3
                                mov     Gen_2_Passes, TRUE
                        .endif

                        .if     _HWCubeMap == FALSE
                                invoke  Set_Error_Msg, CSTR("Cubemap textures aren't supported on this hardware")
                                mov     eax, FALSE
                                ret
                        .endif

                        invoke  Load_PICTURE, CSTR("..\..\Media\floor.jpg"), addr Texture1, -1
                        .if     eax == FALSE
                                invoke  Set_Error_Msg, CSTR("Can't load main texture file")
                                mov     eax, FALSE
                                ret
                        .endif
                        
                        invoke  Create_2D_Texture, Texture1.Datas, Texture1._Width, TRUE, GL_RGBA, GL_RGBA
                        mov     Texture1_Id, eax
                        .if     eax == FALSE
                                invoke  Set_Error_Msg, CSTR("Can't create main texture")
                                mov     eax, FALSE
                                ret
                        .endif

                        invoke  Create_Norm_CubeMap, Texture1._Width
                        mov     Texture_CubeMap_Id, eax
                        .if     eax == FALSE
                                invoke  Set_Error_Msg, CSTR("Can't create cubemap texture")
                                mov     eax, FALSE
                                ret
                        .endif

                        ; Create the DOT3 texture
                        invoke  Create_NormalMap, Texture1.Datas, Texture1._Width, CFLT(1.0)
                        mov     ebx, eax
                        .if     eax == FALSE
Err_Dot3:                       invoke  Set_Error_Msg, CSTR("Can't create dot3 texture")
                                mov     eax, FALSE
                                ret
                        .endif
                        invoke  Create_2D_Texture, ebx, Texture1._Width, TRUE, GL_RGBA, GL_RGBA
                        mov     Texture_Dot3_Id, eax
                        .if     eax == FALSE
                                jmp     Err_Dot3
                        .endif
                        FREEMEM ebx

                        invoke  Load_OBJECT, CSTR("..\..\Media\cube.txt")
                        .if     eax == NULL
                                invoke  Set_Error_Msg, CSTR("Can't load object")
                                mov     eax, FALSE
                                ret
                        .endif
                        mov     Object, eax

                        mov     eax, TRUE
                        ret
Initialize              endp

; ------------------------------------------------------
; Name: Deinitialize()
; Desc: Free allocated resources
Deinitialize            proc

                        invoke  Unload_OBJECT, Object
                        invoke  Destroy_Texture, Texture_Dot3_Id
                        invoke  Destroy_Texture, Texture_CubeMap_Id
                        invoke  Destroy_Texture, Texture1_Id
                        invoke  Unload_PICTURE, addr Texture1
                        ret
Deinitialize            endp

; ------------------------------------------------------
; Name: Update()
; Desc: Update the scene
Update                  proc    FrameRate:real4

                        ; Update scene here

                        fld     RotXSpeed
                        fmul    FrameRate
                        fadd    RotX
                        fstp    RotX

                        fld     RotYSpeed
                        fmul    FrameRate
                        fadd    RotY
                        fstp    RotY

                        fld     RotZSpeed
                        fmul    FrameRate
                        fadd    RotZ
                        fstp    RotZ

                        invoke  DInput_Get_Key, DIK_ESCAPE
                        test    eax, eax
                        jz      Esc_Pressed
                        invoke  Terminate_Application
Esc_Pressed:            ret
Update                  endp

; ------------------------------------------------------
; Name: Draw()
; Desc: Draw the scene
Draw                    proc
                        local   Matrix_Quat:QUAT
                        local   Light_Quat:QUAT
                        local   Quat:QUAT
                        local   Light_Quat2:QUAT
                        local   View_Matrix:MATRIX
                        local   Inv_RotX:real4
                        
                        invoke  glClear, GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT

                        invoke  glEnable, GL_DEPTH_TEST

                        ; Draw scene here
                        invoke  glFogf, GL_FOG_MODE, GL_EXP2
                        invoke  glFogfv, GL_FOG_COLOR, addr Fog_Color
                        invoke  glFogf, GL_FOG_DENSITY, CFLT(0.1)
                        invoke  glEnable, GL_FOG

                        invoke  glPushMatrix
                                invoke  glRotatef, RotX, CFLT(0.0), CFLT(1.0), CFLT(0.0)
        
                                invoke  Quat_RotateXYZ, addr Quat, RotX, RotY, RotZ
                                ; Convert the quaternion into a matrix
                                invoke  QuatToMat, addr Quat, addr View_Matrix
                                invoke  Matrix_Translate, addr View_Matrix, CFLT(0.0), CFLT(0.0), CFLT(-4.0)
                                ; Send it to opengl once it is rotated and positionned
                                invoke  glLoadMatrixf, addr View_Matrix

                                ; Make sure the light source stays at the same place
                                ; By inverting all rotations
                                invoke  QuatInverse, addr Quat
                                invoke  QuatToMat, addr Quat, addr View_Matrix
                                
                                ; Create the position of the light source
                                fld     View_Matrix.m[0 * 4]
                                fmul    Bump_Light_Pos.x
                                fld     View_Matrix.m[4 * 4]
                                fmul    Bump_Light_Pos.y
                                faddp   st(1), st(0)
                                fld     View_Matrix.m[8 * 4]
                                fmul    Bump_Light_Pos.z
                                faddp   st(1), st(0)
                                fstp    Object_Light_Pos.x

                                fld     View_Matrix.m[1 * 4]
                                fmul    Bump_Light_Pos.x
                                fld     View_Matrix.m[5 * 4]
                                fmul    Bump_Light_Pos.y
                                faddp   st(1), st(0)
                                fld     View_Matrix.m[9 * 4]
                                fmul    Bump_Light_Pos.z
                                faddp   st(1), st(0)
                                fstp    Object_Light_Pos.y

                                fld     View_Matrix.m[2 * 4]
                                fmul    Bump_Light_Pos.x
                                fld     View_Matrix.m[6 * 4]
                                fmul    Bump_Light_Pos.y
                                faddp   st(1), st(0)
                                fld     View_Matrix.m[10 * 4]
                                fmul    Bump_Light_Pos.z
                                faddp   st(1), st(0)
                                fstp    Object_Light_Pos.z

                                invoke  glColor3f, CFLT(1.0), CFLT(1.0), CFLT(1.0)

                                ; The normalization cube map
                                invoke  glActiveTextureARB, GL_TEXTURE0_ARB
                                invoke  glEnable, GL_TEXTURE_2D
                                invoke  glEnable, GL_TEXTURE_CUBE_MAP_ARB
                                invoke  glBindTexture, GL_TEXTURE_CUBE_MAP_ARB, Texture_CubeMap_Id
                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                invoke  glTexEnvi, GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE

                                ; The normals map
                                invoke  glActiveTextureARB, GL_TEXTURE1_ARB
                                invoke  glEnable, GL_TEXTURE_2D
                                invoke  glBindTexture, GL_TEXTURE_2D, Texture_Dot3_Id
                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                invoke  glTexEnvi, GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB
                                invoke  glTexEnvi, GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB
                                invoke  glTexEnvi, GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB
                                invoke  glTexEnvi, GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE
                                
                                .if     Gen_2_Passes == FALSE
                                        ; 3 textures mode
                                        invoke  glActiveTextureARB, GL_TEXTURE2_ARB
                                        invoke  glEnable, GL_TEXTURE_2D
                                        invoke  glBindTexture, GL_TEXTURE_2D, Texture1_Id
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                        invoke  glTexEnvi, GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE
                                        invoke  Display_Cube, GEN_ALL_PASSES

                                        invoke  glActiveTextureARB, GL_TEXTURE2_ARB
                                        invoke  glDisable, GL_TEXTURE_2D
                                .else
                                        ; 2 textures mode (first pass)
                                        invoke  Display_Cube, GEN_1ST_PASS
                                .endif
                                
                                invoke  glActiveTextureARB, GL_TEXTURE1_ARB
                                invoke  glDisable, GL_TEXTURE_2D
                                invoke  glActiveTextureARB, GL_TEXTURE0_ARB
                                invoke  glDisable, GL_TEXTURE_CUBE_MAP_ARB
                                invoke  glDisable, GL_TEXTURE_2D
                                
                                .if     Gen_2_Passes == TRUE
                                        ; 2 textures mode (second pass)
                                        ; We draw it normally with a stock light source
                                        invoke  glEnable, GL_BLEND
                                        invoke  glBlendFunc, GL_DST_COLOR, GL_SRC_COLOR
                                        invoke  glLightfv, GL_LIGHT0, GL_DIFFUSE, addr Light_Diffuse
                                        invoke  glLightfv, GL_LIGHT0, GL_AMBIENT, addr Light_Ambient
                                        invoke  glLightfv, GL_LIGHT0, GL_POSITION, addr Object_Light_Pos
                                        invoke  glEnable, GL_LIGHT0
                                        invoke  glEnable, GL_LIGHTING

                                        invoke  glEnable, GL_TEXTURE_2D
                                        invoke  glBindTexture, GL_TEXTURE_2D, Texture1_Id
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                        invoke  glTexEnvi, GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE
                                        invoke  Display_Cube, GEN_2ND_PASS
                                        
                                        invoke  glDisable, GL_TEXTURE_2D
                                        invoke  glDisable, GL_LIGHTING
                                        invoke  glDisable, GL_BLEND
                                .endif

                                ; Show the lightsource position
                                ;invoke glEnable, GL_POINT_SMOOTH
                                ;invoke glBegin, GL_POINTS
                                ;       invoke  glVertex3f, Object_Light_Pos.x, Object_Light_Pos.y, Object_Light_Pos.z
                                ;invoke glEnd
                                ;invoke glDisable, GL_POINT_SMOOTH

                        invoke  glPopMatrix
                        ret
Draw                    endp

; ------------------------------------------------------
; Name: Display_Cube
; Desc: Display the cube
Display_Cube            proc    Gen_Simple_Tex:dword
                        
                        mov     esi, Object
                        lodsd
                        mov     ecx, eax
                        xor     ebx, ebx
                        .while  ebx < ecx
                                push    ebx
                                push    ecx
                                lodsd
                                push    eax
                                .if     eax == 3
                                        invoke  glBegin, GL_TRIANGLES
                                .elseif eax == 4
                                        invoke  glBegin, GL_QUADS
                                .elseif
                                        invoke  glBegin, GL_POLYGON
                                .endif
                                invoke  glNormal3f, [esi], [esi + 4], [esi + 8]
                                lea     edi, [esi]
                                add     esi, sizeof FACE_DAT
                                pop     ecx
                                xor     ebx, ebx
                                .while  ebx < ecx
                                        push    ecx
                                        invoke  Send_Cube_Vertex, edi, addr Object_Light_Pos, esi, Gen_Simple_Tex
                                        add     esi, 20
                                        pop     ecx
                                        inc     ebx
                                .endw                           
                                invoke  glEnd
                                pop     ecx
                                pop     ebx
                                inc     ebx
                        .endw
                        ret
Display_Cube            endp

; ------------------------------------------------------
; Name: Send_Cube_Vertex
; Desc: Send a vertex & the according texture coordinates
Send_Cube_Vertex        proc    uses ebx esi Face:LPFACE_DAT, Light_Pos:LPVERTEX, Vx_Dat:LPVERTEX_DAT, Gen_Simple_Tex:dword
                        local   Light_Vertex:VERTEX
                        local   Tangent_Vertex:VERTEX

                        mov     ebx, Vx_Dat
                        invoke  Vec_Sub, addr Light_Vertex, Light_Pos, ebx

                        mov     esi, Face
                        invoke  Vec_DotProduct, addr [esi + FACE_DAT.Tangents], addr Light_Vertex
                        fstp    Tangent_Vertex.x
                        invoke  Vec_DotProduct, addr [esi + FACE_DAT.BiNormals], addr Light_Vertex
                        fchs
                        fstp    Tangent_Vertex.y
                        invoke  Vec_DotProduct, addr [esi + FACE_DAT.Normals], addr Light_Vertex
                        fstp    Tangent_Vertex.z
                        .if     Gen_Simple_Tex == GEN_1ST_PASS
                                invoke  glMultiTexCoord3fARB, GL_TEXTURE0_ARB, Tangent_Vertex.x, Tangent_Vertex.y, Tangent_Vertex.z
                                invoke  glMultiTexCoord2fARB, GL_TEXTURE1_ARB, [ebx + VERTEX_DAT.TxU], [ebx + VERTEX_DAT.TxV]
                        .elseif Gen_Simple_Tex == GEN_2ND_PASS
                                invoke  glTexCoord2f, [ebx + VERTEX_DAT.TxU], [ebx + VERTEX_DAT.TxV]
                        .else
                                invoke  glMultiTexCoord3fARB, GL_TEXTURE0_ARB, Tangent_Vertex.x, Tangent_Vertex.y, Tangent_Vertex.z
                                invoke  glMultiTexCoord2fARB, GL_TEXTURE1_ARB, [ebx + VERTEX_DAT.TxU], [ebx + VERTEX_DAT.TxV]
                                invoke  glMultiTexCoord2fARB, GL_TEXTURE2_ARB, [ebx + VERTEX_DAT.TxU], [ebx + VERTEX_DAT.TxV]
                        .endif
                        invoke  glVertex3f, [ebx + VERTEX_DAT.Coords.x], [ebx + VERTEX_DAT.Coords.y], [ebx + VERTEX_DAT.Coords.z]
                        ret
Send_Cube_Vertex        endp

end start
