Login

Subversion Repositories NedoOS

Rev

Rev 49 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

LINEGIF=0x8000 ;адрес для сборки строк
LINEGIF_sz=0x1800 ;макс. ширина = 2048
;KEEPFRAMELINE=LINEGIF-0x4000
PAL_GLOB=0x9a00 ;,0x300 ;глобальная таблица цветов
PAL_LOCAL=0x9d00 ;,0x300 ;локальная таблица цветов
ROL_TAB=0xa000 ;,0x1000 ;L0>>n (16 bit)

;процедуры чтения на входе хотят NC, иначе могут насквозь вернуть C даже без ошибки
        macro GIFINITCY
        ;or a
        endm

        macro GIFRETIFDISKERR
        ;ret c
        endm

        macro GIFJRIFDISKERR addr
        ;jr c,addr
        endm

        macro GIFGETBYTE
        rdbyte
        GIFRETIFDISKERR
        endm

        macro GIFGETBYTE_noret
        rdbyte
        endm

        macro GIFGETWORD
        call GIF_GETWORD
        GIFRETIFDISKERR
        endm

;Производит поиск элемента с кодом в HL по таблице цепочек
;  1,x-начальный (корневоЙ) элемент таблицы (при LZW_SIZE=8 всего их будет 256)
;  0,0-элемента не существует
;  0,1-код очистки
;  0,2-код завершения данных EOI
;  остальные величины означают адрес, по которому сидит предыдущий элемент цепочки +256
;и третий байт - собственно сам символ
;out: HL=адрес элемента. Если элемент равен CC,EOI или отсутствует, то Z=1, А=0-нет элемента,1-CC,2-EOI
;==========================================
        macro GIFRECODE ;out: HL=адрес элемента. Если элемент равен CC,EOI или отсутствует, то Z=1, А=0-нет элемента,1-CC,2-EOI
        LD C,L
        ;LD a,H
         or 0xc0
         ld b,a
        ADD HL,HL
        ADD HL,BC
        LD A,(HL)
         or a
        endm

        macro GIFGETCHAR
        ex af,af'
        dec a
        call z,GETCHRnewblock
        ex af,af'

        GIFGETBYTE_noret
        GIFRETIFDISKERR
        endm        

        macro GIFGETCODE
        call GETCODE_
        GIFRETIFDISKERR
        endm

readgif
        ld hl,LINEGIF
        ld de,LINEGIF+1
        ld (hl),BACKGROUNDCOLORLEVEL
        ld bc,LINEGIF_sz-1
        ldir ;чтобы справа в остатке знакоместа была чернота (потом можно убрать, когда readchr будет это делать)
       
        xor a
        ld (gifdisposalmethod),a
       
        ld a,GIFTRANSP_off
        ld (giftransparencyflag),a
        CALL ROL_INSTALL
        CALL GIFSEARCH
        RET C
        CALL GIF_LOGSCR ;обработка дескриптора картинки вместе с палитрой (PAL_GLOB) ;заказывает память под bmp
        RET C
GIF_newframe
GIF_parsechunk
        GIFINITCY
        GIFGETBYTE
        CP #2C
        jr Z,GIF_IMG
        CP #21
        ;JR Z,GIF_SPEC
        ;CP #3B ;???
        ;ret z
        ret nz ;неопознанный блок, выход по ошибке
;GIF_SPEC ;специальный блок
        GIFINITCY
        GIFGETBYTE
        cp #f9 ;graphic control extension
        jr z,GIF_GFXCTRLEXT
;       CP #FF
;       JR NZ,GIF_fail
GIF_HELP
        GIFGETBYTE
        OR A
        jr z,GIF_parsechunk;newframe
        LD B,A
GIF_HP0
        GIFGETBYTE    ;Пропустить HELP...
        DJNZ GIF_HP0
        JR GIF_HELP

;graphic control extension
GIF_GFXCTRLEXT
        GIFGETBYTE ;=4
gifdisposalmethod=$+1
         ld a,0
         ld (gifwasdisposalmethod),a
        GIFGETBYTE ;bit0 = transparent color present, bit4..2 = disposal method (0=not specified(?), 1=do not dispose(?), 2=overwrite with bg color, 3=overwrite with prev frame(?))
;6908fast.gif, 6914fast.gif, 6911sled.gif: a=5 (transparent color present, do not dispose), 5, 5...
;6906wrbg.gif: a=5, 5, 5, 9 (то есть указанный dispose надо делать после картинки?)
;5scroll.gif: a=4...
;sprites.gif: a=1 (transparent color present, disposal not specified)
;animatie.gif: a=9 (transparent color present, overwrite with bg color), 9, 9...
;zajchik.gif: a=5...
;voloki.gif: a=0
;ris4.gif: a=0
;optic_14.gif: a=0
;optic_15.gif: a=0
;multipal.gif, melnchud.gif, melnchil.gif (все из Photoshop) - нет graphic control extension - TODO не заказывать память под bmp и не делать putline?
        ld (gifdisposalmethod),a
         ;cp 9
         ;ret z
        ;jr $
         rra;bit 0,a
         ld a,GIFTRANSP_on
         jr c,$+4;nz
         ld a,GIFTRANSP_off
         ld (giftransparencyflag),a
        GIFGETBYTE ;delayLSB
        ld l,a
        GIFGETBYTE ;delayHSB
        ld h,a
         or l
         jr nz,$+4
         ld l,10 ;0 s => 0.1 s
        ld (gifframetime),hl
        GIFGETBYTE ;transparent color index
         ld (giftransparentcolor),a
        GIFGETBYTE ;=0
        jp GIF_parsechunk

;"""""""""""""""""""""""
GIF_IMG ;Обработка блока изображения.
        call initframe ;один раз на кадр после setpicwid, setpichgt и после установки gifframetime ;заказывает память под конверченный кадр
         ld (gifconvertedframeaddr),hl
         ld (gifconvertedframeaddrHSB),a

        GIFINITCY
        GIFGETWORD
        ex de,hl;ld (localx),hl ;локальное начало строки        
        GIFGETWORD
        ;ld (starty),hl ;локальная первая строка
        ld b,h
        ld c,l
        GIFGETWORD
        LD (DX_IMG),HL ;локальная ширина
         LD (pixelcounter_back),HL
        GIFRETIFDISKERR
        GIFGETWORD
        LD (DY_IMG),HL ;локальная высота
        ld h,d
        ld l,e ;локальное начало строки
        add hl,hl
        add hl,de
        ex de,hl ;de=localx*3
        ld hl,LINEGIF
        add hl,de
        ld (linebufstart_local),hl
        ld (linebufpointer),hl

gifrasteraddr=$+1
        ld hl,0;(putchar_hl)
gifrasteraddrHSB=$+1
        ld a,0;(putchar_a)
        call setputlineaddr

;пропустить строки до starty (скопировать из предыдущего кадра) TODO что если это первый кадр, а строк нет? так не бывает?
;starty=$+1
;        ld bc,0
;bc=локальная первая строка
        call gifpreparepic_skiplines

        if 1==0
;ищем, в какое место bmp класть начальную строчку кадра:
        ld bc,(cury);(Y_IMG)
         srl b
         rr c ;TODO с учётом зума
        inc bc
        jr gifrasterstart0loop
gifrasterstart0
        call nextscreenline
        call nextputlineaddr
gifrasterstart0loop
        cpi
        jp pe,gifrasterstart0
        endif
       
        GIFINITCY
        GIFGETBYTE
        if 1==0
        BIT 6,A ;необходимо проверить бит 6 на предмет наличия чередования строк
        JR Z,GIF_IMG_NORM
;чередование строк. TODO поддержать чередование строк (0,2,1,3? - разницу будет видно только с зумом)
         SCF
         RET

GIF_IMG_NORM
        endif
        push af

;for PUTCHAR:
        call PUTCHARgetline_ifvisible ;устанавливает PUTCHARaddr, PUTCHARputaddr
        CALL gifsetpgLZW
linebufpointer=$+1
        ld de,0 ;Адрес для вывода байта в LINEGIF
pixelcounter_back=$+1
        ld bc,0
        exx

        pop af ;A bit 7: признак наличия палитры, 2..0: число цветов
        LD HL,PAL_LOCAL
        CALL GIF_PAL
        RET C

;начало разборки отдельного блока графики
        XOR A
        ld lx,a;LD (GETCOD0+1),A ;количество бит в наличии
        LD (GIF_IMG_ENDcode),A

        inc a ;ld a,1
        ex af,af'
        GIFINITCY
        GIFGETBYTE
        LD (LZW_SIZE),A
         push hl
;"""""""""""""""""""""""
GIF_IMGclearLZW ;очистка LZW
         pop hl
        CALL LZW_INSTALL
        GIFGETCODE
        GIFRECODE ;out: HL=адрес элемента. Если элемент равен CC,EOI или отсутствует, то Z=1, А=0-нет элемента,1-CC,2-EOI
        push hl ;запоминаем адрес элемента, чтобы после NEW_CODE присвоить его значение LZW_OLD'
у
        JR nz,GIF_IMGputstring
         inc hl
         ld a,(hl)
        dec a;CP 1
        JR Z,GIF_IMGclearLZW ;код очистки
        dec a;CP 2
        jr Z,GIF_IMG_END ;код конца данных...
;элемент отсутствует - ошибка
         pop hl
        SCF
        RET
GIF_IMGputstring
        CALL PUTSTRING ;вывод цепочки из таблицы цепочек
        jr GIF_IMGunpackloop

GIF_IMGputstring_newcode
        ;nop ;4t = 0.04 s
        CALL PUTSTRING ;вывод цепочки из таблицы цепочек
GIF_IMGnewcode_unpackloop
;добавить в таблицу цепочек элемент, состоящий из ссылки на OLD и символа А
NEW_COD0 LD HL,0
        LD DE,(LZW_OLD)
         inc d
        LD (HL),d;E
        INC HL
        LD (HL),e;D
        INC HL
        LD (HL),A
        INC HL
        LD (NEW_COD0+1),HL
NEW_COD1 LD HL,0        
        INC HL
        LD (NEW_COD1+1),HL
NEW_CODmask=$+1
        LD DE,0 ;маска+1
        OR A
        SBC HL,DE
        call z,gif_inccodemask ;сначала одни 111, затем 000... - увеличить LZW_SIZW
GIF_IMGunpackloop
;главный цикл распаковки
        pop hl
        LD (LZW_OLD),HL
        GIFGETCODE
        GIFRECODE ;out: HL=адрес элемента. Если элемент равен CC,EOI или отсутствует, то Z=1, А=0:нет элемента,1:CC,2:EOI
        push hl ;запоминаем адрес элемента, чтобы после NEW_CODE присвоить его значение LZW_OLD'у
        jp nz,GIF_IMGputstring_newcode
         inc hl
         ld a,(hl)
        dec a;CP 1
        JR Z,GIF_IMGclearLZW ;код очистки
        dec a;CP 2
        jr Z,GIF_IMG_END;конец блока
;элемент отсутствует
        ;nop ;4t < 0.02 s
LZW_OLD=$+1
        LD HL,0
        CALL PUTSTRING ;вывод цепочки из таблицы цепочек
PUTCHARaddr2=$+1
        CALL PUTCHAR ;если не патчить на невидимых строках, видно следы ;keeps de
         ld a,(de) ;первый символ цепочки
        jp GIF_IMGnewcode_unpackloop

GIF_IMG_END
         pop hl
GIF_IMG_END0
;найден код конца LZW-данных
;необходимо считать след. блок, и если его длина=0, то конец кадра
        GIFINITCY
        call GETCHAR_ ;чтобы была правильная глубина стека при нахождении блока с длиной 0 (он пропускает чтение следующего байта через снятие адреса со стека)
;установит переменную GIF_IMG_ENDcode, если пойдёт блок с длиной 0, а пока дочитываем текущий блок
        GIFRETIFDISKERR
GIF_IMG_ENDcode=$+1
        LD A,0 ;/0xff, если встретился блок с длиной 0
        OR A
        jr z,GIF_IMG_END0 ;т.е. ещё не конец блока.
;встретился блок с длиной 0 - конец изображения

        ld bc,(curpichgt)
        ;jr $
        call gifpreparepic_skiplines
       
        ld hl,(nframes)
        inc hl
        ld (nframes),hl

gifconvertedframeaddr=$+1
        ld hl,0
gifconvertedframeaddrHSB=$+1
        ld a,0
        ld (gifoldconvertedframeaddr),hl
        ld (gifoldconvertedframeaddrHSB),a
         ;ld a,(nframes)
         ;cp 2
         ;ret z
        JP GIF_newframe ;следующий кадр
       
;bc=номер строки выхода
gifpreparepic_skiplines0
;TODO копировать прямо из памяти (окна 1,2) в память (окно 3)
         push bc
        call islinevisible ;nz=invisible
        jr nz,gifpreparepic_skiplines_invisible
        ld hl,(gifoldconvertedframeaddr)
        ld a,(gifoldconvertedframeaddrHSB)
        ld de,LINEPIXELS
        ld bc,(keepframe_linesize_bytes)
        call getfrommem ;берём сконверченную строку из предыдущего кадра
        call nextoldconvertedframeaddr ;смещаем адрес, откуда брать сконверченную строку из предыдущего кадра (gifoldconvertedframeaddr)
        call keepconvertedline ;запоминаем сконверченную строку из LINEPIXELS, смещаем адрес, куда класть (keepframeaddr)
         call nextscreenline
         call nextputlineaddr
gifpreparepic_skiplines_invisible
        call inccury
         pop bc
gifpreparepic_skiplines
;вход тут
        ld hl,(cury)
        or a
        sbc hl,bc
        jr nz,gifpreparepic_skiplines0
        ;call gifsetpgLZW
        ret

nextoldconvertedframeaddr
gifoldconvertedframeaddr=$+1
        ld bc,0
gifoldconvertedframeaddrHSB=$+1
        ld a,0
        ld hl,(keepframe_linesize_bytes)
        add hl,bc
        adc a,0
        ld (gifoldconvertedframeaddr),hl
        ld (gifoldconvertedframeaddrHSB),a
        ret

DX_IMG  DEFW 0  ;размер отдельного изображения
DY_IMG  DEFW 0
;===========================
;затычка для неиспользуемых строк (вызывается только в двух местах)
PUTCHAR_DUMMY
        exx
        cpi
        exx
        ret pe
        jp PUTCHARendline

PUTCHARtransparent
        inc de
        inc de
        inc de
        cpi
        exx
        ret pe
        jp PUTCHARendline

PUTCHAR
;Вывод символа в поток (строку)...
;портит a
;de'=linebufpointer, bc'=counter
        exx
giftransparentcolor=$+1
         cp 0
giftransparencyflag=$
         jr z,PUTCHARtransparent ;/ld l,
GIFTRANSP_on=0x28 ;"jr z"
GIFTRANSP_off=0x2e ;"ld l"
         ;nop ;4t = 0.1 s
putchar_palH=$+1
        ld h,PAL_GLOB/256
        ld l,a
        ld a,(hl)
        ld (de),a
        inc de
        inc h
        ld a,(hl)
        ld (de),a
        inc de
        inc h
        ldi
        exx
        ret pe ;строка не кончилась
PUTCHARendline
;end of line
        push bc
        push de
        push hl
        call inccury
PUTCHARputaddr=$+1
        jp 0 ;jr nz,PUTCHARskipline
PUTCHARputline
        ld bc,(curpicwidx3)
        ld hl,LINEGIF
;hl=откуда копируем строку
;bc=сколько байт копируем
        push hl
        call putline ;TODO для анимированных ;кладёт в bmp
        pop hl
        call drawscreenline_frombuf ;конвертируем LINEGIF в LINEPIXELS и выводим её на экран
        call keepconvertedline ;запоминаем сконверченную строку из LINEPIXELS
         ;call setpgtemp8000 ;drawscreenline_frombuf сама восстанавливает
         ;call setpgcode4000 ;drawscreenline_frombuf сама восстанавливает
        call nextoldconvertedframeaddr ;смещаем адрес, откуда брать сконверченную строку из предыдущего кадра (gifoldconvertedframeaddr)
PUTCHARskipline
        call PUTCHARgetline_ifvisible ;берём строку из bmp, если она видимая и если надо рисовать поверх ;устанавливает PUTCHARaddr
        call gifsetpgLZW
        pop hl
        pop de
        pop bc
        exx
        ld bc,(DX_IMG) ;локальная ширина
linebufstart_local=$+1
        ld de,0 ;локальное начало строки
        exx
        ret

PUTCHARgetline_ifvisible
;устанавливает PUTCHARaddr, PUTCHARputaddr
         ld hl,PUTCHAR_DUMMY
         ld de,PUTCHARskipline
        call islinevisible ;nz=invisible
        jr nz,PUTCHARgetline_ifvisibleq
;getline, если DX_IMG!=curpicwid или если есть прозрачность ;TODO делать эту проверку один раз за кадр
         ld hl,(DX_IMG)
         ld de,(curpicwid)
         or a
         sbc hl,de
        ld bc,(curpicwidx3)
        ld de,LINEGIF
        jr nz,PUTCHARgetline
;de=куда достаём строку
;bc=сколько байт достаём
        ld a,(giftransparencyflag)
        cp GIFTRANSP_off
PUTCHARgetline
        call nz,getline ;TODO для анимированных: если не первый кадр, прочитать строку из памяти в LINEGIF (чтобы рисовать поверх неё)
         ld hl,PUTCHAR
         ld de,PUTCHARputline
PUTCHARgetline_ifvisibleq
         ld (PUTCHARaddr),hl
         ld (PUTCHARaddr2),hl
         ld (PUTCHARputaddr),de
        ret

;__________________________________
PUTSTRING
;выводит цепочку с нач. адресом в HL в поток символов
;out: А=первый символ этой цепочки
;портит bc,de,hl
;использует буфер по адресу -1..-4096
        ld bc,0
PUTSTR0 ;
        dec bc
        ld d,(hl);e
        inc hl
        ld e,(hl);d
        inc hl
        ld a,(hl)
        ld (bc),a
        ex de,hl
         ;BIT 4,B
         ;JR Z,PUTSTR_fail ;ошибка (длина 4096 элементов, больше нет места) ;но реально такого не может быть в составленной нами таблице
         ;nop ;4t = 0.1 s
         dec h
        jp nz,PUTSTR0 ;пока не перейдём к корневой цепочке
PUTSTR2 ld a,(bc)
PUTCHARaddr=$+1
        call PUTCHAR
        inc c
        jp nz,PUTSTR2
        inc b
        jp nz,PUTSTR2
         ld a,(de) ;первый символ цепочки
        ret

;________________________________________________
LZW_INSTALL
;Инсталляция таблицы цепочек в 0xc000
;Структура таблицы - трёхбайтные элементы:
;  1,x-начальный (корневоЙ) элемент таблицы (при LZW_SIZE=8 всего их будет 256)
;  0,0-элемента не существует
;  0,1-код очистки
;  0,2-код завершения данных EOI
;  остальные величины означают адрес, по которому сидит предыдущий элемент цепочки +256
;и третий байт - собственно сам символ
        ld hl,0xc000
        push hl
        ld de,0xc001
        ld bc,0x3fff
        ld (hl),l;=0
        ldir
LZW_SIZE=$+1
        ld b,0 ;начальный размер кода LZW (расширяться будет не здесь, а в LZW_SIZW)
        ld hl,1
        add hl,hl
        djnz $-1
        LD C,L
        LD B,H
        INC HL
        INC HL
        LD (NEW_COD1+1),HL
        pop hl ;0xc000
        xor a
        ld e,a;0
LZW_INS1
        LD (HL),1;0
        INC HL
        LD (HL),a;0
        INC HL
        LD (HL),E
        INC E
        cpi
        jp pe,LZW_INS1
        LD (HL),a;=0;#FF
        INC HL
        LD (HL),1
        INC HL
        LD (HL),A;0
        INC HL
        LD (HL),a;=0;#FF
        INC HL
        LD (HL),2
        INC HL
        LD (HL),A;0
        INC HL
        LD (NEW_COD0+1),HL ;Адрес первого свободного Элемента в таблице цепоЧек.
        LD A,(LZW_SIZE)
        INC A
gif_setcodemask
;a=codesize=1..12
;out: CY=0
        ld b,a
         add a,a
         add a,ROL_TAB/256-2
        LD (LZW_SIZW),A ;1..12 *2 +(ROL_TAB/256-2)
        ld hl,0
        add hl,hl
        inc hl
        djnz $-2
        ld a,l
        ld (GETCODmasklow),a
        ld a,h
        ld (GETCODmaskhigh),a
         inc hl
        ld (NEW_CODmask),hl ;маска+1
        ret
gif_inccodemask
        ld a,(LZW_SIZW) ;1..12 *2 +(ROL_TAB/256-2)
         sub ROL_TAB/256-2
         rrca
        cp 12
        adc a,0
        ;JR NC,$+3
        ; INC A
;a=codesize=1..12
        jp gif_setcodemask ;out: CY=0
;__________________________
GETCHAR_
;для GIF_IMG_END
        GIFGETCHAR ;может вывалиться с C (ошибка) или NC (найден блок с длиной 0)
        ret
       
GETCHRnewblock
;текущий блок закончился
        GIFGETBYTE_noret
        GIFJRIFDISKERR GETCHRnewblock_fail
        or a
        ret nz ;установить длину блока и читать байт
;блок нулевой длины - определить конец данных
;нужно только в GIF_IMG_END
         ex af,af'
         pop af ;выход на уровень выше, чтобы не читать данное (ret будет эквивалентно ret nc из GIFGETCHAR)
        LD A,#FF
        LD (GIF_IMG_ENDcode),A
        GIFINITCY
        RET
GETCHRnewblock_fail
         ex af,af'

        pop af ;выход на уровень выше (ret будет эквивалентно ret c в GIFGETCHAR)
        scf
        ret

;__________________________
GETCODE_ ;читает код в HL с заданным количеством бит (см. LZW_SIZW)
GETCOD00 LD L,0 ;оставшиеся данные.
        ld a,lx ;количество бит в наличии *2
        or a;ADD A,A
        JP NZ,GETCOD1
        GIFGETCHAR
        LD L,A
        LD (GETCOD00+1),A
        LD A,16;8
         ld lx,a
         ;add a,a
GETCOD1
        ADD A,ROL_TAB/256-2
        LD H,A

       ;LD A,lx ;количество бит в наличии *2
       SUB 0
LZW_SIZW=$-1 ;текущий размер кода LZW *2 +1 +(ROL_TAB/256-2)
        JR NC,GETCODneed0bytes ;имеем достаточно бит в наличии
        ADD A,16;8
        jr nc,GETCODneed2bytes ;надо взять дополнительно 2 байта
;GETCODneed1byte
;надо взять дополнительно 1 байт (самый частый случай)
        LD lx,a;(GETCOD0+1),A ;количество бит в наличии
        LD E,(HL) ;LSB (L>>n)
        GIFINITCY
        GIFGETCHAR
        LD (GETCOD00+1),A
        LD L,A
        LD D,(HL) ;LSB (L>>n)
        inc h
        LD A,(HL) ;HSB (L>>n)
        OR E
        ;JP GETCODq
GETCODq
GETCODmasklow=$+1
        and 0
        LD L,A
GETCODmaskhigh=$+1
        LD A,0
        AND d
        LD H,A
        RET ;NC=OK, HL=код
GETCODneed2bytes
;надо взять дополнительно 2 байта
        ADD A,16;8
        LD lx,a;(GETCOD0+1),A ;количество бит в наличии
        LD E,(HL) ;LSB (L>>n)
        GIFINITCY
        GIFGETCHAR
        LD L,A
        LD D,(HL) ;LSB (L>>n)
        inc h
        LD A,(HL) ;HSB (L>>n)
        OR E
        LD E,A
        GIFGETCHAR
        LD (GETCOD00+1),A
        LD L,A
        LD A,(HL) ;HSB (L>>n)
        OR D
        LD D,A
        ld a,e
        JP GETCODq
GETCODneed0bytes
;имеем достаточно бит в наличии
        LD lx,a;(GETCOD0+1),A ;количество бит в наличии
        LD D,0
        ld a,(hl)
        JP GETCODq
;________________________________________
GIF_LOGSCR
;обработка дескриптора картинки
         ld a,PAL_GLOB/256
         ld (putchar_palH),a
        GIFINITCY
        GIFGETWORD
        call setpicwid
        GIFGETWORD
        call setpichgt
       
        ld hl,(freemem_hl)
        ld (gifrasteraddr),hl
        ld a,(freemem_a)
        ld (gifrasteraddrHSB),a
        call reserve_bmp_pages ;TODO для анимированных
        call reservefirstframeaddr
       
        GIFINITCY
        GIFGETBYTE ;d7=palette on, d6..d4=bits of color resolution(add 1), d3=0, d2..d0=bits/pixel in image(add 1)
        LD C,A
        GIFGETBYTE
        LD (gifbgcolor),A
        GIFGETBYTE ;aspect ratio? (0 in GIF87)
        LD A,C
        LD HL,PAL_GLOB
        ;JP GIF_PAL
;_______________________________
GIF_PAL
;чтение палитры
;HL=адрес, куда класть палитру (768 b), А=флаг палитры (7) и число цветов (2..0)
        OR A
        ret p ;нет палитры
        AND 7
        INC A
        LD B,A ;число битов палитры 1..8
        ld a,h
        ld (putchar_palH),a
        LD a,1
        add a,a
        djnz $-1
        ld b,a ;B=длина палитры в триплетах RGB (min=2, max=256)
        GIFINITCY
GIF_PAL1
        inc h
        inc h
        GIFGETBYTE
        ld (hl),a
        dec h
        GIFGETBYTE
        ld (hl),a
        dec h
        GIFGETBYTE
        ld (hl),a
        inc l
        djnz GIF_PAL1
;zajchik.gif - в локальных палитрах последний цвет чёрный
        XOR A
        RET

GIF_GETWORD
        GIFINITCY
        GIFGETBYTE
        LD L,A
        GIFGETBYTE_noret
        LD H,A
        RET
;_______ _______________________
GIF_HEAD0 db "IF87a"
GIF_HEAD1 db "IF89a"

GIFSEARCH
        GIFINITCY
        LD HL,GIF_HEAD0
        LD DE,GIF_HEAD1
        LD B,6-1
GIFSEARCH0
        GIFGETBYTE
        CP (HL)
        JR Z,GIFSEARCH1
        EX DE,HL
        CP (HL)
        EX DE,HL
        scf
        ret nz ;CY=fail
GIFSEARCH1
        INC HL
        INC DE
        DJNZ GIFSEARCH0
        XOR A ;OK
        RET

;=============================
ROL_INSTALL
;Инсталятор таблички для ускорения процедуры GETCODE
;L0>>n (16 bit)
        LD HL,ROL_TAB+#0E00
        ld de,0x08FF
ROL_I00
ROL_I01
        ld b,d
        ld a,l
        rlca
        djnz $-1
        ld c,a
        and e
        LD (HL),A ;LSB
        INC H
        xor c
        LD (HL),A ;HSB
        DEC H
        INC L
        jr nz,ROL_I01
        DEC H
        DEC H
        srl e ;0xff >> n
        dec d
        jr nz,ROL_I00
        ret