; GIF LITE v3.0 by Willow
; Written in pure assembler by Ivushkin Andrey aka Willow
; Modified by Diamond
;
; This include file will contain functions to handle GIF image format
;
; Created: August 15, 2004
; Last changed: June 24, 2007

; Requires kglobals.inc (iglobal/uglobal macro)
; (program must 'include "kglobals.inc"' and say 'IncludeUGlobal'
; somewhere in uninitialized data area).

; Configuration: [changed from program which includes this file]
; 1. The constant COLOR_ORDER: must be one of
;    PALETTE - for 8-bit image with palette (sysfunction 65)
;    MENUETOS - for MenuetOS and KolibriOS color order (sysfunction 7)
;    OTHER - for standard color order
; 2. Define constant GIF_SUPPORT_INTERLACED if you want to support interlaced
;    GIFs.
; 3. Single image mode vs multiple image mode:
;    if the program defines the variable 'gif_img_count' of type dword
;    somewhere, ReadGIF will enter multiple image mode: gif_img_count
;    will be initialized with image count, output format is GIF_list,
;    the function GetGIFinfo retrieves Nth image info. Otherwise, ReadGIF
;    uses single image mode: exit after end of first image, output is
;    <dd width,height, times width*height[*3] db image>

if ~ (COLOR_ORDER in <PALETTE,MENUETOS,OTHER>)
; This message may not appear under MenuetOS, so watch...
  display 'Please define COLOR_ORDER: PALETTE, MENUETOS or OTHER',13,10
end if

if defined gif_img_count
; virtual structure, used internally

struct GIF_list
    NextImg rd 1
    Left   rw 1
    Top    rw 1
    Width  rw 1
    Height rw 1
    Delay  rd 1
    Displacement rd 1 ; 0 = not specified
                       ; 1 = do not dispose
                       ; 2 = restore to background color
                       ; 3 = restore to previous
if COLOR_ORDER eq PALETTE
    Image rd 1
end if
ends

struct GIF_info
    Left   rw 1
    Top    rw 1
    Width  rw 1
    Height rw 1
    Delay  rd 1
    Displacement rd 1
if COLOR_ORDER eq PALETTE
    Palette rd 1
end if
ends

; ****************************************
;   FUNCTION GetGIFinfo - retrieve Nth image info
; ****************************************
; in:
;   esi - pointer to image list header
;   ecx - image_index (0...img_count-1)
;   edi - pointer to GIF_info structure to be filled

; out:
;   eax - pointer to RAW data, or 0, if error

GetGIFinfo:
    push  esi ecx edi
    xor   eax,eax
    jecxz .eloop
  .lp:
    mov   esi,[esi]
    test  esi,esi
    jz    .error
    loop  .lp
  .eloop:
    lodsd
    movsd
    movsd
    movsd
    movsd
if COLOR_ORDER eq PALETTE
    lodsd
    mov   [edi],esi
else
    mov   eax,esi
end if
  .error:
    pop   edi ecx esi
    ret

end if

_null fix 0x1000

; ****************************************
;   FUNCTION ReadGIF - unpacks GIF image
; ****************************************
; in:
;   esi - pointer to GIF file in memory
;   edi - pointer to output image list

; out:
;   eax - 0, all OK;
;   eax - 1, invalid signature;
;   eax >=8, unsupported image attributes
;

ReadGIF:
    push esi edi
    mov  [.cur_info],edi
    xor  eax,eax
    mov  [.globalColor],eax
if defined gif_img_count
    mov  [gif_img_count],eax
    mov  [.anim_delay],eax
    mov  [.anim_disp],eax
end if
    inc  eax
    cmp  dword[esi],'GIF8'
    jne  .ex            ; signature
    mov  ecx,[esi+0xa]
    add  esi,0xd
    mov  edi,esi
    test cl,cl
    jns  .nextblock
    mov  [.globalColor],esi
    call .Gif_skipmap
  .nextblock:
    cmp  byte[edi],0x21
    jne  .noextblock
    inc  edi
if defined gif_img_count
    cmp  byte[edi],0xf9 ; Graphic Control Ext
    jne  .no_gc
    movzx eax,word [edi+3]
    mov  [.anim_delay],eax
    mov  al,[edi+2]
    shr  al,2
    and  eax,7
    mov  [.anim_disp],eax
    add  edi,7
    jmp  .nextblock
  .no_gc:
end if
    inc  edi
  .block_skip:
    movzx eax,byte[edi]
    lea  edi,[edi+eax+1]
    test eax,eax
    jnz  .block_skip
    jmp  .nextblock
  .noextblock:
    mov  al,8
    cmp  byte[edi],0x2c    ; image beginning
    jne  .ex
if defined gif_img_count
    inc  [gif_img_count]
end if
    inc  edi
    mov  esi,[.cur_info]
if defined gif_img_count
    add  esi,4
end if
    xchg esi,edi
if defined GIF_SUPPORT_INTERLACED
    movzx ecx,word[esi+4]
    mov  [.width],ecx
    movzx eax,word[esi+6]
    imul eax,ecx
if ~(COLOR_ORDER eq PALETTE)
    lea  eax,[eax*3]
end if
    mov  [.img_end],eax
    inc  eax
    mov  [.row_end],eax
    and  [.pass],0
    test byte[esi+8],40h
    jz   @f
if ~(COLOR_ORDER eq PALETTE)
    lea  ecx,[ecx*3]
end if
    mov  [.row_end],ecx
@@:
end if
if defined gif_img_count
    movsd
    movsd
    mov  eax,[.anim_delay]
    stosd
    mov  eax,[.anim_disp]
    stosd
else
    movzx eax,word[esi+4]
    stosd
    movzx eax,word[esi+6]
    stosd
    add   esi,8
end if
    push edi
    mov  ecx,[esi]
    inc  esi
    test cl,cl
    js   .uselocal
    push [.globalColor]
    mov  edi,esi
    jmp  .setPal
  .uselocal:
    call .Gif_skipmap
    push esi
  .setPal:
    movzx ecx,byte[edi]
    inc  ecx
    mov  [.codesize],ecx
    dec  ecx
if ~(COLOR_ORDER eq PALETTE)
    pop  [.Palette]
end if
    lea  esi,[edi+1]
    mov  edi,.gif_workarea
    xor  eax,eax
    lodsb               ; eax - block_count
    add  eax,esi
    mov  [.block_ofs],eax
    mov  [.bit_count],8
    mov  eax,1
    shl  eax,cl
    mov  [.CC],eax
    mov  ecx,eax
    inc  eax
    mov  [.EOI],eax
    mov  eax, _null shl 16
  .filltable:
    stosd
    inc  eax
    loop .filltable
if COLOR_ORDER eq PALETTE
    pop  eax
    pop  edi
    push edi
    scasd
    push esi
    mov  esi,eax
    mov  ecx,[.CC]
@@:
    lodsd
    dec  esi
    bswap eax
    shr  eax,8
    stosd
    loop @b
    pop  esi
    pop  eax
    mov  [eax],edi
else
    pop  edi
end if
if defined GIF_SUPPORT_INTERLACED
    mov  [.img_start],edi
    add  [.img_end],edi
    add  [.row_end],edi
end if
  .reinit:
    mov  edx,[.EOI]
    inc  edx
    push [.codesize]
    pop  [.compsize]
    call .Gif_get_sym
    cmp  eax,[.CC]
    je   .reinit
    call .Gif_output
  .cycle:
    movzx ebx,ax
    call .Gif_get_sym
    cmp  eax,edx
    jae  .notintable
    cmp  eax,[.CC]
    je   .reinit
    cmp  eax,[.EOI]
    je   .end
    call .Gif_output
  .add:
    mov  dword [.gif_workarea+edx*4],ebx
    cmp  edx,0xFFF
    jae  .cycle
    inc  edx
    bsr  ebx,edx
    cmp  ebx,[.compsize]
    jne  .noinc
    inc  [.compsize]
  .noinc:
    jmp  .cycle
  .notintable:
    push eax
    mov  eax,ebx
    call .Gif_output
    push ebx
    movzx eax,bx
    call .Gif_output
    pop  ebx eax
    jmp  .add
  .end:
if defined GIF_SUPPORT_INTERLACED
    mov  edi,[.img_end]
end if
if defined gif_img_count
    mov  eax,[.cur_info]
    mov  [eax],edi
    mov  [.cur_info],edi
    add  esi,2
    xchg esi,edi
  .nxt:
    cmp  byte[edi],0
    jnz  .continue
    inc  edi
    jmp  .nxt
  .continue:
    cmp  byte[edi],0x3b
    jne  .nextblock
    xchg esi,edi
    and  dword [eax],0
end if
    xor  eax,eax
  .ex:
    pop  edi esi
    ret

.Gif_skipmap:
; in: ecx - image descriptor, esi - pointer to colormap
; out: edi - pointer to area after colormap

    and  ecx,111b
    inc  ecx            ; color map size
    mov  ebx,1
    shl  ebx,cl
    lea  ebx,[ebx*2+ebx]
    lea  edi,[esi+ebx]
    ret

.Gif_get_sym:
    mov  ecx,[.compsize]
    push ecx
    xor  eax,eax
  .shift:
    ror  byte[esi],1
    rcr  eax,1
    dec  [.bit_count]
    jnz  .loop1
    inc  esi
    cmp  esi,[.block_ofs]
    jb   .noblock
    push eax
    xor  eax,eax
    lodsb
    test eax,eax
    jnz  .nextbl
    mov  eax,[.EOI]
    sub  esi,2
    add  esp,8
    jmp  .exx
  .nextbl:
    add  eax,esi
    mov  [.block_ofs],eax
    pop  eax
  .noblock:
    mov  [.bit_count],8
  .loop1:
    loop .shift
    pop  ecx
    rol  eax,cl
  .exx:
    xor  ecx,ecx
    ret

.Gif_output:
    push esi eax edx
    mov  edx,.gif_workarea
  .next:
    push word[edx+eax*4]
    mov  ax,word[edx+eax*4+2]
    inc  ecx
    cmp  ax,_null
    jnz  .next
    shl  ebx,16
    mov  bx,[esp]
  .loop2:
    pop  ax

    if COLOR_ORDER eq PALETTE
        stosb
    else
        lea  esi,[eax+eax*2]
        add  esi,[.Palette]

    if COLOR_ORDER eq MENUETOS
        mov  esi,[esi]
        bswap esi
        shr  esi,8
        mov  [edi],esi
        add  edi,3
    else
        movsb
        movsb
        movsb
    end if
    end if

if defined GIF_SUPPORT_INTERLACED
    cmp  edi,[.row_end]
    jb   .norowend
    mov  eax,[.width]
if ~(COLOR_ORDER eq PALETTE)
    lea  eax,[eax*3]
end if
    push eax
    sub  edi,eax
    add  eax,eax
    cmp  [.pass],3
    jz   @f
    add  eax,eax
    cmp  [.pass],2
    jz   @f
    add  eax,eax
@@:
    add  edi,eax
    pop  eax
    cmp  edi,[.img_end]
    jb   .nextrow
    mov  edi,[.img_start]
    inc  [.pass]
    add  edi,eax
    cmp  [.pass],3
    jz   @f
    add  edi,eax
    cmp  [.pass],2
    jz   @f
    add  edi,eax
    add  edi,eax
@@:
.nextrow:
    add  eax,edi
    mov  [.row_end],eax
    xor  eax,eax
.norowend:
end if

    loop .loop2
    pop  edx eax esi
    ret

uglobal
align 4
    ReadGIF.globalColor rd 1
    ReadGIF.cur_info rd 1        ; image table pointer
    ReadGIF.codesize rd 1
    ReadGIF.compsize rd 1
    ReadGIF.bit_count rd 1
    ReadGIF.CC rd 1
    ReadGIF.EOI rd 1
if ~(COLOR_ORDER eq PALETTE)
    ReadGIF.Palette rd 1
end if
    ReadGIF.block_ofs rd 1
if defined GIF_SUPPORT_INTERLACED
    ReadGIF.row_end rd 1
    ReadGIF.img_end rd 1
    ReadGIF.img_start rd 1
    ReadGIF.pass rd 1
    ReadGIF.width rd 1
end if
if defined gif_img_count
    ReadGIF.anim_delay rd 1
    ReadGIF.anim_disp rd 1
end if
    ReadGIF.gif_workarea rb 16*1024
endg