ifndef                  _BMP_ASM
_BMP_ASM                equ     1

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

; ------------------------------------------------------
; Structures
BMP                     struct
Datas                   dword   ?
_Width                  dword   ?
Height                  dword   ?
Bits                    dword   ?
Orig_Width              dword   ?
Orig_Height             dword   ?
BMP                     ends

; ------------------------------------------------------
; Name: Load_BMP
; Desc: Load a 24 or 32 bits BMP file into memory
Load_BMP                proc    uses ebx esi edi BMP_FName:dword, BMP_Struct:dword, Color_Key:dword
                        local   BMP_Buffer:dword
                        local   FSize:dword
                        local   DatOffset:dword
                        local   _Modulo:dword
                        local   _Width:dword
                        local   _Height:dword

                        mov     esi, BMP_Struct
                        mov     [esi + BMP.Datas], NULL

                        ; Load texture into memory
                        invoke  Load_File, BMP_FName, addr FSize
                        test    eax, eax
                        jz      Err_BMP_Load
                        mov     BMP_Buffer, eax

                        ; Decode the BMP file
                        mov     ebx, eax
                        mov     edi, eax
                        mov     ax, "MB"
                        cmp     word ptr [edi + BITMAPFILEHEADER.bfType], ax
                        jne     Err_BMP_Format
                        mov     eax, FSize
                        cmp     dword ptr [edi + BITMAPFILEHEADER.bfSize], eax
                        jne     Err_BMP_Format

                        mov     DatOffset, CMEM([edi + BITMAPFILEHEADER.bfOffBits])     
                        lea     edi, [edi + sizeof BITMAPFILEHEADER]

                        mov     eax, dword ptr [edi + BITMAPINFOHEADER.biWidth]
                        test    eax, eax
                        js      Err_BMP_Format
                        jz      Err_BMP_Format
                        ; Fix the raster lines stuff
                        mov     [esi + BMP._Width], eax
                        mov     _Width, eax
                        imul    eax, 3
                        cdq
                        mov     ecx, 4
                        idiv    ecx
                        xchg    edx, eax
                        mov     _Modulo, 0
                        .if     eax != 0
                                sub     ecx, eax
                                mov     _Modulo, ecx
                        .endif
                        movzx   eax, word ptr [edi + BITMAPINFOHEADER.biHeight]
                        test    eax, eax
                        js      Err_BMP_Format
                        jz      Err_BMP_Format
                        mov     [esi + BMP.Height], eax
                        mov     _Height, eax

                        movzx   eax, word ptr [edi + BITMAPINFOHEADER.biBitCount]
                        mov     [esi + BMP.Bits], eax
                        cmp     eax, 24                                 ; Must be 24 bits (bottom left)
                        je      GoodTextureFormat
                        cmp     eax, 32                                 ; or 32 bits
                        je      GoodTextureFormat
Err_BMP_Format:         FREEMEM BMP_Buffer
Err_BMP_Load:           xor     eax, eax                                ; Not loaded
                        ret
GoodTextureFormat:      mov     eax, [esi + BMP._Width]
                        mov     ecx, [esi + BMP.Height]
                        mov     [esi + BMP.Orig_Width], eax
                        mov     [esi + BMP.Orig_Height], ecx
                        ; Fix the sizes
                        .if     eax > ecx
                                mov     [esi + BMP.Height], eax
                        .endif
                        .if     eax < ecx
                                mov     [esi + BMP._Width], ecx
                        .endif

                        imul    eax, ecx
                        push    eax
                        mov     eax, [esi + BMP._Width]
                        imul    eax, [esi + BMP.Height]
                        shl     eax, 2
                        mov     eax, ALLOCMEM(eax)
                        pop     ecx
                        test    eax, eax
                        jz      Err_BMP_Format
                        mov     [esi + BMP.Datas], eax
                        mov     edi, eax
                        mov     eax, DatOffset

                        .if     [esi + BMP.Bits] == 32
                                lea     esi, [ebx + eax]                ; 24 bits image datas
                                mov     ecx, _Height
Loop_32Bits_Y:                  push    ecx
                                mov     ecx, _Width
Loop_32Bits_X:                  lodsb
                                ror     eax, 8
                                lodsb
                                ror     eax, 8
                                lodsb
                                ror     eax, 8 
                                lodsb
                                bswap   eax
                                and     eax, 000ffffffh
                                mov     edx, Color_Key
                                test    edx, edx
                                js      _No_Set_Alpha_32
                                and     edx, 000ffffffh
                                cmp     edx, eax
                                jne     _No_Set_Alpha_32
                                mov     eax, 0ff000000h                 ; Turn alpha channel on for this color
_No_Set_Alpha_32:               xor     eax, 0ff000000h
                                stosd
                                loop    Loop_32Bits_X
                                pop     ecx
                                loop    Loop_32Bits_Y
                        .else
                                lea     esi, [ebx + eax]                ; 24 bits image datas
                                mov     ecx, _Height
Loop_24Bits_Y:                  push    ecx
                                mov     ecx, _Width
Loop_24Bits_X:                  or      eax, -1
                                lodsb
                                shl     eax, 8
                                lodsb
                                shl     eax, 8 
                                lodsb
                                and     eax, 000ffffffh
                                mov     edx, Color_Key
                                test    edx, edx
                                js      _No_Set_Alpha_24
                                and     edx, 000ffffffh
                                cmp     edx, eax
                                jne     _No_Set_Alpha_24
                                mov     eax, 0ff000000h                 ; Turn alpha channel on for this color
_No_Set_Alpha_24:               xor     eax, 0ff000000h
                                stosd
                                loop    Loop_24Bits_X
                                add     esi, _Modulo
                                pop     ecx
                                loop    Loop_24Bits_Y
                        .endif
                        FREEMEM BMP_Buffer
                        mov     eax, TRUE                               ; Loaded
                        ret
Load_BMP                endp

; ------------------------------------------------------
; Name: Unload_BMP
; Desc: Free an allocated BMP picture
Unload_BMP              proc    uses esi BMP_Struct:dword
                        mov     esi, BMP_Struct
                        test    esi, esi
                        jz      @F
                        mov     eax, [esi + BMP.Datas]
                        test    eax, eax
                        jz      @F
                        FREEMEM eax
@@:                     ret
Unload_BMP              endp

endif
