Názory k článku Vykreslování spritů a animací na ZX Spectru

  • Článek je starý, nové názory již nelze přidávat.
  • 25. 7. 2023 5:18

    _dw

    Z kapitoly 7:
    Poznámka2: dokážete přijít na to, za jakých podmínek a zda vůbec NEbude vykreslovací rutina korektní?

    Moje reseni: Emork ohot ez es ejurtesoen yndaz z ujarko ykvozarbo, kat ot etsej ezles v udohcerp nitert a ot zu ej aklev teslob, ezotorp yt ejarko es ijad tiser i mit ez es ilserkyv avon akvozarbo. Ela aretkolam arh am ukvozarbo nej rtinvu ynitert.

    Jinak ten kod:

    draw_sprite:
            ld hl, SPRITE_ADR        ; 3:10 adresa, od níž začíná maska spritu
            push de                  ; 1:11
            call draw_8_lines        ; 3:17 vykreslit prvních 8 řádků spritu
    
            pop  de                  ; 1:10
            add_e 32                 ; 3:15 zvýšit E o hodnotu 32
            push de                  ; 1:11
            call draw_8_lines        ; 3:17 vykreslit druhých 8 řádků spritu
    
            pop  de                  ; 1:10
            add_e 32                 ; 3:15 zvýšit E o hodnotu 32
            call draw_8_lines        ; 3:17 vykreslit třetích 8 řádků spritu
    
            ret                      ; 1:10 návrat z podprogramu
                                    ;[23:143]
    
    draw_8_lines:
            ld b, 8                  ; 2:7          počitadlo zapsaných řádků
    
    loop:
            ld  a,(hl)               ; 1:7          načtení jednoho bajtu z masky
            ld  (de),a               ; 1:7          zápis hodnoty na adresu (DE)
            inc hl                   ; 1:6          posun na další bajt masky
            inc e                    ; 1:4
    
            ld  a,(hl)               ; 1:7          načtení jednoho bajtu z masky
            ld  (de),a               ; 1:7          zápis hodnoty na adresu (DE)
            inc hl                   ; 1:6          posun na další bajt masky
            inc e                    ; 1:4
    
            ld  a,(hl)               ; 1:7          načtení jednoho bajtu z masky
            ld  (de),a               ; 1:7          zápis hodnoty na adresu (DE)
            inc hl                   ; 1:6          posun na další bajt masky
    
            inc d                    ; 1:4          posun na definici dalšího obrazového řádku
            dec e                    ; 1:4          korekce - posun zpět pod první osmici pixelů
            dec e                    ; 1:4          dtto
            djnz loop                ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
            ret                      ; 1:10         návrat z podprogramu
                                    ;[19:756=7+8*93-5+10]

    By sel napsat rychleji a mensi:

    draw_sprite:
       ...
                                    ;[23:143]
    
    draw_8_lines:
            ld  bc, 8*(256+2)        ; 3:10         počitadlo zapsaných řádků
    loop:
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ld  a,(hl)               ; 1:7          načtení jednoho bajtu z masky
            ld  (de),a               ; 1:7          zápis hodnoty na adresu (DE)
            inc hl                   ; 1:6          posun na další bajt masky
            dec e                    ; 1:4          korekce
            dec e                    ; 1:4          korekce
            inc d                    ; 1:4          posun na definici dalšího obrazového řádku
            djnz loop                ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
            ret                      ; 1:10         návrat z podprogramu
                                    ;[16:631=10+8*77-5+10]

    A pokud by me restit i ten zasadni problem s korektnosti tak by sel udelat jeste mensi, pokud bude automaticky vracet spravne nastavene DE.

    draw_sprite:
            ld hl, SPRITE_ADR        ; 3:10         adresa, od níž začíná maska spritu
            call draw_8_lines        ; 3:17         vykreslit prvních 8 řádků spritu
            call draw_8_lines        ; 3:17         vykreslit druhých 8 řádků spritu
            call draw_8_lines        ; 3:17         vykreslit třetích 8 řádků spritu
            ret                      ; 1:10         návrat z podprogramu
                                    ;[13:71]
    
    draw_8_lines:
            ld  bc, 8*(256+2)        ; 3:10         počitadlo zapsaných řádků
    loop:
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ld  a,(hl)               ; 1:7          načtení jednoho bajtu z masky
            ld  (de),a               ; 1:7          zápis hodnoty na adresu (DE)
            inc hl                   ; 1:6          posun na další bajt masky
            dec e                    ; 1:4          korekce
            dec e                    ; 1:4          korekce
            inc d                    ; 1:4          posun na definici dalšího obrazového řádku
            djnz loop                ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
            ld  a, e                 ; 1:4
            add a, 32                ; 2:7
            ld  e, a                 ; 1:4
            ret c                    ; 1:5/11
            ld  a, d                 ; 1:4
            sub 8                    ; 2:7
            ld  d, a                 ; 1:4
            ret                      ; 1:10         návrat z podprogramu
                                    ;[25:647/666 =10+8*77-5+26/10+8*77-5+45]

    A kdyz uz spamuji tak rovnou pridam muj skript nakompilaci asm zdrojaku a rovnou spusteni v emulatoru. S tim ze jde parametrem i menit adresa na jakou se to zkompiluje. Staci mit v kodu neco jako:

    ifdef __ORG
      org __ORG
    else
      org 0x8000
    endif

    kde 0x8000 je default ale skript nastavuje __ORG kdyz mu ho zadate. Tim mu i reknete ze to ma spustit v emulatoru a nejen kompilovat binarku.

    Neni ani potreba definovat nejaky entry point. Protoze se to zkompiluje jako binarka a pres zmakebas to vytvari z basic loaderu tapku. Loader je nastaven na testovani rychlosti programu.

    https://github.com/DW0RKiN/M4_FORTH/blob/master/from_asm.sh

  • 25. 7. 2023 14:33

    Pavel Tišnovský
    Zlatý podporovatel

    Diky za doplneni.

    Ten fix, co tam naznacujes, planuju na priste (ted by bylo dobre, aby si to lidi vyzkouseli a zjistili, proc to nejede dobre a hlavne kdy). A ten trik s LDI*, to jsem uplne zapomel - si s dovolenim a diky zase vezmu :)

    * porad to pisu dost mechanicky jako na stare dobre 6502

  • 26. 7. 2023 0:46

    _dw

    No ja pri tom narazil na to ze inc/dec reg_8bit nastavuje vlajku p/v! Myslel jsem, ze podteceni nemam jak pomoci inc/dec zjistit a ono to jde... (preteceni je jasne, to se nastavi zero)

    A to ani pokud je to v A. Takze jsem celou dobu delal SUB 0x01 misto DEC A... lol. Musim vyzkouset.

    Jinak jsem ten kod jeste vylepsil kdyz jsem se na nej ted kouknul. Protoze to pricitani 32 se da udelat pres registr C kdyz je volny.

    draw_8_lines:
            ld  bc, 8*(256+3)+32-3   ; 3:10         počitadlo zapsaných řádků
            ld  a, e                 ; 1:4          save E
    loop:
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ld  a,(hl)               ; 1:7          načtení jednoho bajtu z masky
            ld  (de),a               ; 1:7          zápis hodnoty na adresu (DE)
            inc hl                   ; 1:6          posun na další bajt masky
            dec e                    ; 1:4          korekce
            dec e                    ; 1:4          korekce
            inc d                    ; 1:4          posun na definici dalšího obrazového řádku
            djnz loop                ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
            ld  a, e                 ; 1:4
            add a, c                 ; 1:4
            ld  e, a                 ; 1:4
            ret c                    ; 1:5/11
            ld  a, d                 ; 1:4
            sub 8                    ; 2:7
            ld  d, a                 ; 1:4
            ret                      ; 1:10         návrat z podprogramu
                                    ;[24:644/663 =10+8*77-5+26/10+8*77-5+45]

    ...a pak vyzkousel 3x ldi a vysla uplne nejlepsi rutina jenze... mela drobnou chybku na krase...
    Ale i pres opravu te chybky je to nejlepsi reseni. A pokud mas ramecek okolo obrazovky tak muzes ten fix zrusit.

    draw_sprite:
            ld hl, SPRITE_ADR        ; 3:10         adresa, od níž začíná maska spritu
            call draw_8_lines        ; 3:17         vykreslit prvních 8 řádků spritu
            call draw_8_lines        ; 3:17         vykreslit druhých 8 řádků spritu
            call draw_8_lines        ; 3:17         vykreslit třetích 8 řádků spritu
            ret                      ; 1:10         návrat z podprogramu
                                    ;[13:71]
    
    draw_8_lines:
            ld  bc, 8*(256+3)+32-2   ; 3:10         počitadlo zapsaných řádků
            ld  a, e                 ; 1:4          save E
    loop:
            ld  e, a                 ; 1:4          load E
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            ldi                      ; 2:16         [DE++] = [HL++]; BC--
            dec de                   ; 1:6          fix fail pri tisku posledniho znaku v tretine! ldi zvedne D pro kazdy radek...
            inc d                    ; 1:4          posun na definici dalšího obrazového řádku
    
            djnz loop                ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
            ld  a, e                 ; 1:4
            add a, c                 ; 1:4
            ld  e, a                 ; 1:4
            ret c                    ; 1:5/11
            ld  a, d                 ; 1:4
            sub 8                    ; 2:7
            ld  d, a                 ; 1:4
            ret                      ; 1:10         návrat z podprogramu
                                    ;[24:632/651 =10+8*75-5+26/10+8*75-5+45]

    ...ale ldi je ti stejne k nicemu pokud budes delat nejake xor .)))

    26. 7. 2023, 00:47 editováno autorem komentáře

  • 26. 7. 2023 1:44

    _dw

    Vsechno jinak! .) Tak z "detects overflow" z https://clrhome.org/table/ se v originalnim manualu k Z80 vyklubalo ze pokud pred odectenim obsahuje registr hodnotu 0x80, tak se ten priznak nastavi, v ostatnich 255 pripadech se vynuluje.

    Takze to dela neco jineho... ale zase existuje dalsi zpusob jak rychle testovat hodnoty 0x80 (dec) nebo 0x7F (inc).

    Pridava dalsi slozitost pro hledani optimalnich reseni...

    Existuje testovani bitu... 2:8 pokud nas zajima jen 7. bit

    Rotace 2:8 pokud nas zajima 0. nebo 7. bit

    "sla reg" by u 0x80 nastavila ZERO a CARRY, ale to nejde testovat najednou takze bez pouziti A snad:

    rlc reg 2:8
    dec reg 1:4

    nastavi ZERO jen pri puvodni hodnote 0x80

    ld A,reg 1:4
    xor 0x80 2:7 nastavi ZERO

    atd. atd.

  • 25. 7. 2023 16:39

    Josef Pavlik

    S tim predpripravenim spritu shiftnutych o 0-7 bitu - on by se dal udelat kompromis. Mit 3 vykreslovaci rutiny - jednu ktera by vykreslovala primo ten sprite, druha shiftnuty o 1 doleva, treti by vykreslovala sprite shiftnuty o 1 doprava. Pak by stacilo pripravit jenom 3 predpocitane sprity - shift o 0, 3 a 6 a kombinaci verze spritu a rutiny by se dokazal vykreslit jakkoliv shiftnuty sprite. Shift o jeden bod ten program az tak moc nezpomali, byl by to kompromis mezi rychlosti a mnozstvim zabrane pameti.

    Jinak diky za serii clanku, musim opet zamacknout slzu - zx spectrum byl muj prvni computer a hex kody instrukci Z80 znam dodnes zpameti (dnes uz jenom nektere...)

  • 25. 7. 2023 19:24

    johny

    Tak o ZX Spectre som tak mohol snívať. V detstve sme si zaobstarali Didaktik M, čo bol kompatibilný počítač so spectrom. V assembleri som to dotiahol do jednoduchým animácií.

    Veľa si toho už ale nepamätám. No marí sa mi, že sa na obrazovke vykresľovala postupne striedavo každá ôsma čiara. 48 KB bolo spolu s 8 KB ROM a ďalej časť patrila obrazovke.

    O mnohých detailoch čo sa uvádzajú v článku človek vôbec netušil. Lebo to nemal odkiaľ vedieť. Literatúry bolo minimum, poradiť nemal kto.

    Robiť v tom bolo nesmierne náročné. Najmenšia chyba zmrazila počítač a vy ste ho museli resetnúť a znova načítať. Čo mohlo travať možno 5-10 minút.

  • 26. 7. 2023 21:46

    _dw

    Vyzkousel jsem jeste rutinu co zabira pro kazdy sprite dvojnasobek pameti, protoze ma pribalenou jeste masku pro mazani sveho okoli.
    Kazdy bajt je ulozen jako 16 bitova hodnota. Spodnich 8 bitu je ten sprite a hornich 8 bitu je maska. Nacita se to pres nastaveni SP na adresu spritu.
    Na zacatku vykresluji jeste pozadi, aby bylo videt co to dela.

    SCREEN_ADR      equ $4000
    ENTRY_POINT     equ $8000
    
            org ENTRY_POINT
    
    start:
            ld  a, %01010101
            ld de, 0x0020
            ld hl, 0x4000
            ld  c, 24
    chessboard_pattern:
            ld  b, 8
            ld (hl), a
            add hl, de
            djnz $-2
            cpl
            dec c
            jr nz, chessboard_pattern
    
            push hl                 ; 0x5800
    finish:
            pop  hl
            ld   de, -0x0020
            add  hl, de
            bit  6, h
            jr  nz, $+5
            ld   hl, 0x57E0
            push hl
    
            ld   d, h
            ld   e, l
            inc  e
            ld   a,(hl)
            rrca
            ld (hl), a
            ld  bc, 31
            ldir                     ; nakresli jeden pixelovy radek sachoveho pozadi
    
            ld b, 15                 ; x-ová souřadnice
            ld c, 3                  ; y-ová souřadnice
            call calc_sprite_address ; výpočet adresy spritu
            call draw_sprite
    
            ld b, 29                 ; x-ová souřadnice
            ld c, 21                 ; y-ová souřadnice
            call calc_sprite_address ; výpočet adresy
            call draw_sprite
    
    
            jr finish                ; žádný návrat do systému
    
    
    calc_sprite_address:
            ; parametry:
            ; B - x-ová souřadnice (ve znacích, ne pixelech)
            ; C - y-ová souřadnice (ve znacích, ne pixelech)
            ;
            ; návratové hodnoty:
            ; DE - adresa pro zápis bloku
            ;
            ; vzor adresy:
            ; 0 1 0 Y4 Y3 0 0 0 | Y2 Y1 Y0 X4 X3 X2 X1 X0
            ld  a, c
            and %00000111            ; pouze spodní tři bity y-ové souřadnice (řádky 0..7)
            rrca
            rrca
            rrca                     ; nyní jsou čísla řádků v horních třech bitech
            or  b                    ; připočítat x-ovou souřadnici
            ld  e, a                 ; máme spodní bajt adresy
                                     ; Y2 Y1 Y0 X4 X3 X2 X1 X0
    
            ld  a, c                 ; y-ová souřadnice
            and %00011000            ; dva bity s indexem "bloku" 0..3 (dolní tři bity už máme zpracovány)
            or  %01000000            ; "posun" do obrazové paměti (na 0x4000)
            ld  d, a                 ; máme horní bajt adresy
                                     ; 0 1 0 Y5 Y4 0 0 0
            ret                      ; návrat z podprogramu
    
    
    draw_sprite:
            ld hl, SPRITE_ADR        ; 3:10
            ld  c, 3                 ; 2:7          výška spritu v řádcích
    draw_sprite_1:
            di                       ; 1:4
            ld (draw_sprite_e+1), sp ; 4:20
            ld sp, hl                ; 1:6          adresa, od níž začíná maska spritu
            ex de, hl                ; 1:4
                                    ;[12:51]
    draw_sprite_2:
            ld  b, 8                 ; 2:7          počitadlo zapsaných řádků
    
    
    draw_sprite_3:
            pop de                   ; 1:10         ; první sloupec
            ld  a, (hl)              ; 1:7
            and d                    ; 1:4
            xor e                    ; 1:4
            ld (hl), a               ; 1:7
    
            inc l                    ; 1:4
    
            pop de                   ; 1:10         ; druhý sloupec
            ld  a, (hl)              ; 1:7
            and d                    ; 1:4
            xor e                    ; 1:4
            ld (hl), a               ; 1:7
    
            inc l                    ; 1:4
    
            pop de                   ; 1:10         ; třetí sloupec
            ld  a, (hl)              ; 1:7
            and d                    ; 1:4
            xor e                    ; 1:4
            ld (hl), a               ; 1:7
    
            dec l                    ; 1:4
            dec l                    ; 1:4
            inc h                    ; 1:4          posun na definici dalšího obrazového řádku
            djnz draw_sprite_3       ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
                                    ;[22:1027=8*129-5]
    
    
            dec c                    ; 1:4
            jr  z, draw_sprite_e     ; 2:7/12
    
            ld  a, l                 ; 1:4
            add a, 0x20              ; 2:7
            ld  l, a                 ; 1:4
            jr  c, draw_sprite_2     ; 2:7/12
    
            ld  a, h                 ; 1:4
            sub 0x08                 ; 2:7
            ld  h, a                 ; 1:4
            jr  draw_sprite_2        ; 2:12
    
    draw_sprite_e:
            ld  sp, 0x0000           ; 3:10
            ei                       ; 1:4
            ret                      ; 1:10         návrat z podprogramu
    
    
    SPRITE_ADR
            db %00000000, %11111111, %00000000, %11111111, %00000000, %11111111   ; 1
            db %00000000, %11111110, %00000000, %00001111, %00000000, %11101111
            db %00000001, %11111100, %11110000, %00000111, %00010000, %11000111
            db %00000011, %11111000, %00111000, %00000000, %00010000, %11000111
            db %00000101, %11110000, %11010111, %00000000, %00010000, %00000111
            db %00000101, %11110000, %11001100, %00000000, %00010000, %11000111
            db %00000101, %11110000, %00110000, %00000001, %00010000, %11000111
            db %00000100, %11110000, %11001000, %00000001, %00010000, %11000111
            db %00000111, %11110000, %00110110, %00000000, %00010000, %11000111   ; 2
            db %00001100, %11100000, %11111110, %00000000, %00111000, %00000011
            db %00011111, %11000000, %11111000, %00000000, %00000000, %00000111
            db %00000000, %11100000, %00000000, %00000000, %00110000, %00000111
            db %00000011, %11111000, %11111111, %00000000, %10110000, %00000111
            db %00000101, %11110000, %11111110, %00000000, %11100000, %00001111
            db %00001110, %11100000, %11111101, %00000000, %11000000, %00011111
            db %00011000, %11000000, %11111100, %00000000, %00000000, %00111111
            db %00011000, %11000000, %00000000, %00000011, %00000000, %11111111   ; 3
            db %00000001, %11100100, %11111000, %00000011, %00000000, %11111111
            db %00000011, %11111000, %11111100, %00000001, %00000000, %11111111
            db %00000001, %11111100, %10110000, %00000011, %00000000, %11111111
            db %00000010, %11111000, %00001100, %00000001, %00000000, %11111111
            db %00000111, %11100000, %00001110, %01100000, %00000000, %01111111
            db %00011110, %11000000, %00000111, %11110000, %10000000, %00111111
            db %00000000, %11100001, %00000000, %11111000, %00000000, %01111111
    
    end ENTRY_POINT
  • 26. 7. 2023 21:55

    _dw

    Jde to vlastne i rovnou pomoci DE

    draw_sprite:
            ld hl, SPRITE_ADR        ; 3:10
            ld  c, 3                 ; 2:7          výška spritu v řádcích
    draw_sprite_1:
            di                       ; 1:4
            ld (draw_sprite_e+1), sp ; 4:20
            ld sp, hl                ; 1:6          adresa, od níž začíná maska spritu
                                    ;[11:47]
    draw_sprite_2:
            ld  b, 8                 ; 2:7          počitadlo zapsaných řádků
    
    
    draw_sprite_3:
            pop hl                   ; 1:10         ; první sloupec
            ld  a, (de)              ; 1:7
            and h                    ; 1:4
            xor l                    ; 1:4
            ld (de), a               ; 1:7
    
            inc e                    ; 1:4
    
            pop hl                   ; 1:10         ; druhý sloupec
            ld  a, (de)              ; 1:7
            and h                    ; 1:4
            xor l                    ; 1:4
            ld (de), a               ; 1:7
    
            inc e                    ; 1:4
    
            pop hl                   ; 1:10         ; třetí sloupec
            ld  a, (de)              ; 1:7
            and h                    ; 1:4
            xor l                    ; 1:4
            ld (de), a               ; 1:7
    
            dec e                    ; 1:4
            dec e                    ; 1:4
            inc d                    ; 1:4          posun na definici dalšího obrazového řádku
            djnz draw_sprite_3       ; 2:13/8       vnitřní smyčka: blok s 3x osmi zápisy
                                    ;[22:1027=8*129-5]
    
    
            dec c                    ; 1:4
            jr  z, draw_sprite_e     ; 2:7/12
    
            ld  a, e                 ; 1:4
            add a, 0x20              ; 2:7
            ld  e, a                 ; 1:4
            jr  c, draw_sprite_2     ; 2:7/12
    
            ld  a, d                 ; 1:4
            sub 0x08                 ; 2:7
            ld  d, a                 ; 1:4
            jr  draw_sprite_2        ; 2:12
    
    draw_sprite_e:
            ld  sp, 0x0000           ; 3:10
            ei                       ; 1:4
            ret                      ; 1:10         návrat z podprogramu

    26. 7. 2023, 21:55 editováno autorem komentáře