ifndef                  _TEXTURES_ASM
_TEXTURES_ASM           equ     1

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

; ------------------------------------------------------
; Constants
SKYBOX_LEFT             equ     0
SKYBOX_RIGHT            equ     1 * 4
SKYBOX_TOP              equ     2 * 4
SKYBOX_BOTTOM           equ     3 * 4
SKYBOX_BACK             equ     4 * 4
SKYBOX_FRONT            equ     5 * 4

; ------------------------------------------------------
; Structures
ifndef                  _DDS_STRUCT_ASM
_DDS_STRUCT_ASM         equ     1

DDS                     struct
_Datas                  dword   ?
_Width                  dword   ?
_Height                 dword   ?
_Bits                   dword   ?
_Mips                   dword   ?
_Compression            dword   ?
DDS                     ends
endif

; ------------------------------------------------------
; Variables
glMultiTexCoord2fARB    PFNGLMULTITEXCOORD2FARBPROC 0
glMultiTexCoord3fARB    PFNGLMULTITEXCOORD3FARBPROC 0
glActiveTextureARB      PFNGLACTIVETEXTUREARBPROC 0
glTexImage3D            PFNGLTEXIMAGE3DPROC 0
glCompressedTexImage2DARB PFNGLCOMPRESSEDTEXIMAGE2DARBPROC 0

_HWMipMap               dd      0
_HWMultiTex             dd      0
_HWCompTex              dd      0
_HWCubeMap              dd      0
_HWThirdTexture         dd      0
_Cube_Map_Orientations  dd      GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
                        dd      GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
                        dd      GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
                        dd      GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
                        dd      GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
                        dd      GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB

; ------------------------------------------------------
; Name: Init_Textures_Context
; Desc: Check if some textures extensions are available
Init_Textures_Context   proc
                        invoke  wglGetProcAddress, CSTR("glMultiTexCoord2fARB")
                        mov     glMultiTexCoord2fARB, eax
                        invoke  wglGetProcAddress, CSTR("glMultiTexCoord3fARB")
                        mov     glMultiTexCoord3fARB, eax
                        invoke  wglGetProcAddress, CSTR("glActiveTextureARB")
                        mov     glActiveTextureARB, eax
                        invoke  wglGetProcAddress, CSTR("glCompressedTexImage2DARB")
                        mov     glCompressedTexImage2DARB, eax

                        .if     glMultiTexCoord2fARB != NULL && glActiveTextureARB != NULL && glMultiTexCoord3fARB != NULL
                                ; Multi texturing supported
                                mov     _HWMultiTex, TRUE
                        .endif
                        invoke  Check_Extension, CSTR("GL_ARB_texture_cube_map")
                        .if     eax == TRUE
                                ; Cubemap textures supported in hardware
                                mov     _HWCubeMap, TRUE
                        .endif

                        invoke  Check_Extension, CSTR("GL_SGIS_generate_mipmap")
                        .if     eax == TRUE
                                ; Mipmaps generation supported in hardware
                                mov     _HWMipMap, TRUE
                                invoke  glHint, GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST
                        .endif

                        invoke  Check_Extension, CSTR("GL_ARB_texture_compression")
                        .if     eax == TRUE
                                ; Compressed textures supported in hardware
                                mov     _HWCompTex, TRUE
                        .endif
                        ret
Init_Textures_Context   endp

; ------------------------------------------------------
; Name: Get_Nbr_Textures_Units
; Desc: Return the number of available textures units
Get_Nbr_Textures_Units  proc
                        local   Units:dword
                        
                        mov     Units, 0
                        invoke  glGetIntegerv, GL_MAX_TEXTURE_UNITS_ARB, addr Units
                        mov     eax, Units
                        ret
Get_Nbr_Textures_Units  endp

; ------------------------------------------------------
; Name: Create_2D_Texture
; Desc: Create a 2D texture
Create_2D_Texture       proc    txDatas:dword, txWidth:dword, _Gen_MipMap:dword, txSource_Resolution:dword, txDest_Resolution:dword
                        local   txId:dword

                        invoke  glGenTextures, 1, addr txId
                        .if     txId != 0
                                invoke  glBindTexture, GL_TEXTURE_2D, txId
                                invoke  glEnable, GL_TEXTURE_2D
                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT
                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT
                                .if     _Gen_MipMap == TRUE
                                        .if     _HWMipMap == TRUE
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                        .else
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                        .endif
                                .else
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST
                                .endif
                                invoke  glTexImage2D, GL_TEXTURE_2D, 0, txDest_Resolution, txWidth, txWidth, 0, txSource_Resolution, GL_UNSIGNED_BYTE, txDatas
                                .if     _Gen_MipMap == TRUE && _HWMipMap == TRUE
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE
                                .endif
                                invoke  glDisable, GL_TEXTURE_2D
                        .endif
                        mov     eax, txId
                        ret
Create_2D_Texture       endp

; ------------------------------------------------------
; Name: Create_DXT_Texture
; Desc: Create a compressed texture
Create_DXT_Texture      proc    uses ebx esi edi DDS_Struct:dword, _Filter:dword
                        local   txId:dword
                        local   _Width:dword
                        local   _MipMul:dword

                        mov     esi, [DDS_Struct]
                        invoke  glGenTextures, 1, addr txId
                        .if     txId != 0
                                invoke  glBindTexture, GL_TEXTURE_2D, txId
                                invoke  glEnable, GL_TEXTURE_2D
                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT
                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT
                                .if     _Filter == TRUE
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                .else
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST
                                .endif
                                mov     _Width, CMEM([esi + DDS._Width])
                                .if     [esi + DDS._Compression] == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
                                        mov     _MipMul, 8
                                .else
                                        mov     _MipMul, 16
                                .endif
                                xor     edi, edi
                                xor     ebx, ebx
                                .repeat
                                        mov     eax, _Width
                                        add     eax, 3
                                        shr     eax, 2
                                        imul    eax, eax
                                        imul    eax, _MipMul
                                        mov     ecx, [esi + DDS._Datas]
                                        add     ecx, edi
                                        add     edi, eax
                                        invoke  glCompressedTexImage2DARB, GL_TEXTURE_2D, ebx, [esi + DDS._Compression], _Width, _Width, 0, eax, ecx
                                        shr     _Width, 1
                                        inc     ebx
                                .until  ebx >= [esi + DDS._Mips]
                                invoke  glDisable, GL_TEXTURE_2D
                        .endif
                        mov     eax, txId
                        ret
Create_DXT_Texture      endp

; ------------------------------------------------------
; Name: Create_CubeMap_Texture
; Desc: Create a cube map texture from 6 pictures
Create_CubeMap_Texture  proc    uses ebx txDatas:dword, txWidth:dword, _Filter:dword, txSource_Resolution:dword, txDest_Resolution:dword
                        local   txId:dword

                        invoke  glGenTextures, 1, addr txId
                        .if     txId != 0
                                invoke  glBindTexture, GL_TEXTURE_CUBE_MAP_ARB, txId
                                invoke  glEnable, GL_TEXTURE_CUBE_MAP_ARB
                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE
                                .if     _Filter == TRUE
                                        .if     _HWMipMap == TRUE
                                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, GL_TRUE
                                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR
                                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                        .else
                                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                                invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                        .endif
                                .else
                                        invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST
                                        invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST
                                .endif
                                xor     ebx, ebx
                                .while  ebx < 6
                                        mov     eax, txDatas
                                        mov     eax, [eax + ebx * 4]
                                        invoke  glTexImage2D, [_Cube_Map_Orientations + ebx * 4], 0, txDest_Resolution, txWidth, txWidth, 0, txSource_Resolution, GL_UNSIGNED_BYTE, eax
                                        inc     ebx
                                .endw
                                .if     _Filter == TRUE && _HWMipMap == TRUE
                                        invoke  glTexParameteri, GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, GL_FALSE
                                .endif
                                invoke  glDisable, GL_TEXTURE_CUBE_MAP_ARB
                        .endif
                        mov     eax, txId
                        ret
Create_CubeMap_Texture  endp

; ------------------------------------------------------
; Name: Create_Skybox_Texture
; Desc: Create a skybox from 6 pictures
Create_Skybox_Texture   proc    uses ebx esi txDatas:dword, txDatas_Ids:dword, txWidth:dword, _Filter:dword, txSource_Resolution:dword, txDest_Resolution:dword
                        local   txId:dword

                        xor     ebx, ebx
                        .while  ebx < 6
                                mov     eax, txDatas
                                mov     esi, [eax + ebx * 4]

                                invoke  glGenTextures, 1, addr txId
                                .if     txId != 0
                                        invoke  glBindTexture, GL_TEXTURE_2D, txId
                                        invoke  glEnable, GL_TEXTURE_2D
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE
                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE
                                        .if _Filter == TRUE
                                                .if _HWMipMap == TRUE
                                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE
                                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR
                                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                                .else
                                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
                                                        invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
                                                .endif
                                        .else
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST
                                        .endif
                                        invoke  glTexImage2D, GL_TEXTURE_2D, 0, txDest_Resolution, txWidth, txWidth, 0, txSource_Resolution, GL_UNSIGNED_BYTE, esi
                                        .if     _Filter == TRUE && _HWMipMap == TRUE
                                                invoke  glTexParameteri, GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE
                                        .endif
                                        invoke  glDisable, GL_TEXTURE_2D
                                .else
                                        mov     eax, FALSE
                                        ret
                                .endif
                                mov     ecx, txDatas_Ids
                                mov     eax, txId
                                mov     [ecx + ebx * 4], eax
                                inc     ebx
                        .endw
                        mov     eax, TRUE
                        ret
Create_Skybox_Texture   endp

; ------------------------------------------------------
; Name: Draw_Skybox
; Desc: Display a skybox
Draw_Skybox             proc    uses ebx txDatas_Ids:dword
                        invoke  glDisable, GL_DEPTH_TEST
                        invoke  glDepthMask, GL_FALSE

                        mov     ebx, txDatas_Ids
                        invoke  glBindTexture, GL_TEXTURE_2D, [ebx + SKYBOX_FRONT]
                        invoke  glBegin, GL_QUADS
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(-1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(-1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(1.0), CFLT(-1.0)
                        invoke  glEnd

                        invoke  glBindTexture, GL_TEXTURE_2D, [ebx + SKYBOX_RIGHT]
                        invoke  glBegin, GL_QUADS
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(-1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(-1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(1.0), CFLT(-1.0)
                        invoke  glEnd

                        invoke  glBindTexture, GL_TEXTURE_2D, [ebx + SKYBOX_BACK]
                        invoke  glBegin, GL_QUADS
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(-1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(-1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(1.0), CFLT(1.0)
                        invoke  glEnd

                        invoke  glBindTexture, GL_TEXTURE_2D, [ebx + SKYBOX_LEFT]
                        invoke  glBegin, GL_QUADS
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(-1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(-1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(1.0), CFLT(1.0)
                        invoke  glEnd

                        invoke  glBindTexture, GL_TEXTURE_2D, [ebx + SKYBOX_TOP]
                        invoke  glBegin, GL_QUADS
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(1.0), CFLT(1.0)
                        invoke  glEnd

                        invoke  glBindTexture, GL_TEXTURE_2D, [ebx + SKYBOX_BOTTOM]
                        invoke  glBegin, GL_QUADS
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(-1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(0.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(-1.0), CFLT(1.0)
                                invoke  glTexCoord2f, CFLT(0.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(1.0), CFLT(-1.0), CFLT(-1.0)
                                invoke  glTexCoord2f, CFLT(1.0), CFLT(1.0)
                                invoke  glVertex3f, CFLT(-1.0), CFLT(-1.0), CFLT(-1.0)
                        invoke  glEnd

                        invoke  glDepthMask, GL_TRUE
                        invoke  glEnable, GL_DEPTH_TEST
                        ret
Draw_Skybox             endp

; ------------------------------------------------------
; Name: Destroy_Skybox
; Desc: Delete a previously created skybox
Destroy_Skybox          proc    uses ebx txDatas_Ids:dword
                        xor     ebx, ebx
                        .while  ebx < 6
                                mov     eax, txDatas_Ids
                                lea     eax, [eax + ebx * 4]
                                invoke  glDeleteTextures, 1, eax
                                inc     ebx
                        .endw
                        ret
Destroy_Skybox          endp

; ------------------------------------------------------
; Name: Destroy_Texture
; Desc: Delete a previously created texture
Destroy_Texture         proc    txId:dword
                        invoke  glDeleteTextures, 1, addr txId
                        ret
Destroy_Texture         endp

; ------------------------------------------------------
; Name: Enter_Tx_Matrix_Mode
; Desc: Select the texture matrix
Enter_Tx_Matrix_Mode    proc
                        invoke  glMatrixMode, GL_TEXTURE
                        invoke  glLoadIdentity
                        ret
Enter_Tx_Matrix_Mode    endp

; ------------------------------------------------------
; Name: Leave_Tx_Matrix_Mode
; Desc: Select the model view matrix
Leave_Tx_Matrix_Mode    proc
                        invoke  glMatrixMode, GL_MODELVIEW
                        ret
Leave_Tx_Matrix_Mode    endp

; ------------------------------------------------------
; Name: Tx_Matrix_Reset
; Desc: Reset the texture matrix
Tx_Matrix_Reset         proc
                        invoke  Enter_Tx_Matrix_Mode
                        invoke  glLoadIdentity
                        invoke  Leave_Tx_Matrix_Mode
                        ret
Tx_Matrix_Reset         endp

; ------------------------------------------------------
; _Store_Cube_Norm
_Store_Cube_Norm        proc    uses ebx Vec:LPVERTEX
                        local   Color:dword

                        invoke  Vec_Scale01, Vec

                        mov     ebx, Vec
                        fld     [ebx + VERTEX.x]
                        fmul    CFLT(255.0)
                        fistp   Color
                        mov     eax, Color
                        stosb
        
                        fld     [ebx + VERTEX.y]
                        fmul    CFLT(255.0)
                        fistp   Color
                        mov     eax, Color
                        stosb
        
                        fld     [ebx + VERTEX.z]
                        fmul    CFLT(255.0)
                        fistp   Color
                        mov     eax, Color
                        stosb

                        or      al, -1
                        stosb
                        ret
_Store_Cube_Norm        endp

; ------------------------------------------------------
; Name: Create_Norm_CubeMap
; Desc: Create a normalization cube texture
Create_Norm_CubeMap     proc    uses ebx edi _Size:dword
                        local   Texture_Cube_Id:dword
                        local   Cube_Datas[6]:dword
                        local   Size_Half:real4
                        local   Vec:VERTEX
                        
                        mov     Texture_Cube_Id, 0
                        mov     ebx, _Size
                        imul    ebx, ebx
                        shl     ebx, 2
                        mov     Cube_Datas[0 * 4], ALLOCMEM(ebx)
                        mov     Cube_Datas[1 * 4], ALLOCMEM(ebx)
                        mov     Cube_Datas[2 * 4], ALLOCMEM(ebx)
                        mov     Cube_Datas[3 * 4], ALLOCMEM(ebx)
                        mov     Cube_Datas[4 * 4], ALLOCMEM(ebx)
                        mov     Cube_Datas[5 * 4], ALLOCMEM(ebx)
                        .if     Cube_Datas[0 * 4] != NULL && Cube_Datas[1 * 4] != NULL && Cube_Datas[2 * 4] != NULL && \
                                Cube_Datas[3 * 4] != NULL && Cube_Datas[4 * 4] != NULL && Cube_Datas[5 * 4] != NULL     
                                fild    _Size
                                fmul    CFLT(0.5)
                                fstp    Size_Half
                                mov     edi, Cube_Datas[0 * 4]
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                push    ecx
                                                fld     Size_Half
                                                fstp    Vec.x

                                                fld     INT2FLT(ebx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.y

                                                fld     INT2FLT(ecx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fchs
                                                fstp    Vec.z

                                                invoke  _Store_Cube_Norm, addr Vec
                                                pop     ecx
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw
                                mov     edi, Cube_Datas[1 * 4]
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                push    ecx
                                                fld     Size_Half
                                                fchs
                                                fstp    Vec.x

                                                fld     INT2FLT(ebx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.y

                                                fld     INT2FLT(ecx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.z

                                                invoke  _Store_Cube_Norm, addr Vec
                                                pop     ecx
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw
                                mov     edi, Cube_Datas[2 * 4]
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                push    ecx
                                                fld     Size_Half
                                                fchs
                                                fstp    Vec.y

                                                fld     INT2FLT(ebx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.z

                                                fld     INT2FLT(ecx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.x

                                                invoke  _Store_Cube_Norm, addr Vec
                                                pop     ecx
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw
                                mov     edi, Cube_Datas[3 * 4]
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                push    ecx
                                                fld     Size_Half
                                                fstp    Vec.y

                                                fld     INT2FLT(ebx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fchs
                                                fstp    Vec.z

                                                fld     INT2FLT(ecx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.x

                                                invoke  _Store_Cube_Norm, addr Vec
                                                pop     ecx
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw
                                mov     edi, Cube_Datas[4 * 4]
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                push    ecx
                                                fld     Size_Half
                                                fstp    Vec.z

                                                fld     INT2FLT(ebx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.y

                                                fld     INT2FLT(ecx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.x

                                                invoke  _Store_Cube_Norm, addr Vec
                                                pop     ecx
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw   
                                mov     edi, Cube_Datas[5 * 4]
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                push    ecx
                                                fld     Size_Half
                                                fchs
                                                fstp    Vec.z

                                                fld     INT2FLT(ebx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fstp    Vec.y

                                                fld     INT2FLT(ecx)
                                                fadd    CFLT(0.5)
                                                fsub    Size_Half
                                                fchs
                                                fstp    Vec.x

                                                invoke  _Store_Cube_Norm, addr Vec
                                                pop     ecx
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw
                                invoke  Create_CubeMap_Texture, addr Cube_Datas, _Size, TRUE, GL_RGBA, GL_RGBA
                                mov     Texture_Cube_Id, eax
                        .endif
                        FREEMEM Cube_Datas[0 * 4]
                        FREEMEM Cube_Datas[1 * 4]
                        FREEMEM Cube_Datas[2 * 4]
                        FREEMEM Cube_Datas[3 * 4]
                        FREEMEM Cube_Datas[4 * 4]
                        FREEMEM Cube_Datas[5 * 4]
                        mov     eax, Texture_Cube_Id
                        ret
Create_Norm_CubeMap     endp

; ------------------------------------------------------
; Name: Create_NormalMap
; Desc: Compute the normal map of a texture
_Read_Texture_Pixel     proc    Bytes:dword, X:dword, Y:dword, _Width:dword
                        mov     eax, Y
                        imul    eax, _Width
                        add     eax, X
                        shl     eax, 2
                        add     eax, Bytes
                        movzx   eax, byte ptr [eax]
                        push    eax
                        fild    dword ptr [esp]
                        pop     eax
                        ret
_Read_Texture_Pixel     endp

Create_NormalMap        proc    uses ebx esi edi Bytes:dword, _Size:real4, Elevation:real4
                        local   Sobel_X:real4
                        local   Sobel_Y:real4

                        local   Normal_Dot:VERTEX

                        local   X_Width:dword
                        local   Y_Width:dword
                        local   Xm1_Width:dword
                        local   Ym1_Width:dword
                        local   Xp1_Width:dword
                        local   Yp1_Width:dword

                        local   Grad_X:real4
                        local   Grad_Y:real4

                        mov     eax, _Size
                        imul    eax, eax
                        shl     eax, 2
                        mov     edi, ALLOCMEM(eax)
                        push    edi
                        .if     edi != NULL
                                xor     ebx, ebx
                                .while  ebx < _Size
                                        xor     ecx, ecx
                                        .while  ecx < _Size
                                                mov     esi, _Size
        
                                                mov     eax, ecx
                                                dec     eax
                                                add     eax, esi
                                                cdq
                                                idiv    esi
                                                mov     eax, edx
                                                mov     Xm1_Width, eax
        
                                                mov     eax, ebx
                                                inc     eax
                                                cdq
                                                idiv    esi
                                                mov     eax, edx
                                                mov     Yp1_Width, eax
                                                
                                                mov     eax, ecx
                                                cdq
                                                idiv    esi
                                                mov     eax, edx
                                                mov     X_Width, eax
        
                                                mov     eax, ebx
                                                cdq
                                                idiv    esi
                                                mov     eax, edx
                                                mov     Y_Width, eax
        
                                                mov     eax, ecx
                                                inc     eax
                                                cdq
                                                idiv    esi
                                                mov     eax, edx
                                                mov     Xp1_Width, eax
        
                                                mov     eax, ebx
                                                dec     eax
                                                add     eax, esi
                                                cdq
                                                idiv    esi
                                                mov     eax, edx
                                                mov     Ym1_Width, eax
                                                
                                                invoke  _Read_Texture_Pixel, Bytes, Xm1_Width, Yp1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fchs
                                                fstp    Grad_Y
                        
                                                invoke  _Read_Texture_Pixel, Bytes, X_Width, Yp1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fmul    CFLT(-2.0)
                                                fadd    Grad_Y
                                                fstp    Grad_Y
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xp1_Width, Yp1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fchs
                                                fadd    Grad_Y
                                                fstp    Grad_Y
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xm1_Width, Ym1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fadd    Grad_Y
                                                fstp    Grad_Y
                        
                                                invoke  _Read_Texture_Pixel, Bytes,  X_Width, Ym1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fmul    CFLT(2.0)
                                                fadd    Grad_Y
                                                fstp    Grad_Y
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xp1_Width, Ym1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fadd    Grad_Y
                                                fstp    Grad_Y
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xm1_Width, Ym1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fchs
                                                fstp    Grad_X
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xm1_Width, Y_Width, esi
                                                fdiv    CFLT(255.0)
                                                fmul    CFLT(-2.0)
                                                fadd    Grad_X
                                                fstp    Grad_X
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xm1_Width, Yp1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fchs
                                                fadd    Grad_X
                                                fstp    Grad_X
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xp1_Width, Ym1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fadd    Grad_X
                                                fstp    Grad_X
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xp1_Width, Y_Width, esi
                                                fdiv    CFLT(255.0)
                                                fmul    CFLT(2.0)
                                                fadd    Grad_X
                                                fstp    Grad_X
                        
                                                invoke  _Read_Texture_Pixel, Bytes, Xp1_Width, Yp1_Width, esi
                                                fdiv    CFLT(255.0)
                                                fadd    Grad_X
                                                fstp    Grad_X
                        
                                                fld     Grad_X
                                                fchs
                                                fstp    Normal_Dot.x
                                                fld     Grad_Y
                                                fchs
                                                fstp    Normal_Dot.y
                                                fld     Elevation
                                                fstp    Normal_Dot.z

                                                fld1
                                                
                                                fld     Normal_Dot.x
                                                fmul    Normal_Dot.x
                                                
                                                fld     Normal_Dot.y
                                                fmul    Normal_Dot.y
                                                faddp   st(1), st(0)
                        
                                                fadd    Normal_Dot.z

                                                fsqrt
                                                fdivp   st(1), st(0)                                    
                                                
                                                fld     Normal_Dot.x
                                                fmul    st(0), st(1)
                                                fadd    CFLT(1.0)
                                                fdiv    CFLT(2.0)
                                                fmul    CFLT(255.0)
                                                fistp   Normal_Dot.x
                                                mov     eax, Normal_Dot.x
                                                stosb
        
                                                fld     Normal_Dot.y
                                                fmul    st(0), st(1)
                                                fadd    CFLT(1.0)
                                                fdiv    CFLT(2.0)
                                                fmul    CFLT(255.0)
                                                fistp   Normal_Dot.y
                                                mov     eax, Normal_Dot.y
                                                stosb
        
                                                fld     Normal_Dot.z
                                                fmulp   st(1), st(0)
                                                fadd    CFLT(1.0)
                                                fdiv    CFLT(2.0)
                                                fmul    CFLT(255.0)
                                                fistp   Normal_Dot.z
                                                mov     eax, Normal_Dot.z
                                                stosb
        
                                                or      al, -1
                                                stosb
                                                inc     ecx
                                        .endw
                                        inc     ebx
                                .endw
                        .endif
                        pop     edi
                        mov     eax, edi
                        ret
Create_NormalMap        endp

endif