1

Temat: Rysowanie na ekranie a mruganie, synchronizacja etc

Robilem podejscie do efektu plasmy i o ile udalo mi sie uzyskac statyczny (bez animacji od funkcji czasu) efekt "plasmopodobny" to zorientowalem sie ze sama moja procedura rysowania punktow na ekranie jest bardzo niewydajna.
Jakie byly moje zalozenia:
- uzylem trybu z 16 odcieniami jednego koloru
- sinus etc mam ztablicowane
- mam wskaznik 16bitowy na aktualnie przetwarzany bajt pamieci ekranu
- zwiekszam kolejno wskaznik i dla odpowieniego X,Y obliczam sobie odcien i aktualizuje pamiec

Tak jak napisalem statyczny obraz mam cool, ale proba animowania tego konczy sie starsznym mruganiem ekranu w roznych jego czesciach. Wyrzucilem wiec dla testow samo obliczanie odcienia (zmieniam 2 kolory naprzemiennie) by przetestowac predkosc samego rysowania. No i dla 80pixeli w 80 liniach obraz strasznie mruga (no ale nie caly obraz na raz, tylko w srodku w rozsynchronizowany sposob). Moje pierwsze podejrzenie padlo na to ze w srodku rysowania sceny (pelne 80linii jednym z dwu naprzemiennie zmienianych kolorow) konczy sie ramka i musze to jakos synchronizowac.
Dla testow dodalem tez w ostatniej linii przewanie DLI z petla nieskonczona by sprawdzic ile jestem w stanie wyrenderwac w jednej ramce - no i okazuje sie to jest na oko nie wiecej niz kilkanascie linii obrazu w tej rozdzielczosci.

No i zastanawiam sie co moge zrobicby usyskac plynnosc.
- czy macie pomysl jak samo rysowanie takiej ilosci pixeli zrobic duzo wydajniej?
- jak zadbac o plynnosc gdy procedura rysowania nie miesci sie w jedej ramce? tzn niech zmiany "animacyjne" beda wolniejsze ale obraz nie mrugal etc

Wrzucam moj przykladowy kod testowy:

      org $8000   

      lda #0
      sta 559
    
      ldx <antic     
      ldy >antic     
      stx 560        
      sty 561   
      
      ;gtia
      lda #%01000000
      sta 623
 
      lda <dli
      sta $200
      lda >dli
      sta $201
      
      ; dli config
      lda #$c0      
      ; ODKOMENTUJ BY SPRAWDZIC ILE WYRYSUJEMY W JEDNEJ RAMCE      
      ;sta $d40e 
  
      ;antic
      lda #%00100010
      sta 559      

; poczatek pamieci ekranu      
GFX_MEM=$9000
; adres gdzie trzymam 16bit pointer na aktualnie rysowany punkt ekranu
GFX_PTR=$32
; pozycje X,Y uzywane docelowo do obliczenia koloru etc
POS_X=$8000 ; pozycja x
POS_Y=$8001 ; pozycja y
COLOR=$8002 ; odcien 2 pixeli (4bit+4bit)
      
init 
      ; powiedzmy ze najpierw rysujemy na bialo
      lda #%11111111
      sta COLOR

rysObrazuLoop

      ; ustawiamy pointer na poczatek pamieci obrazu
      ldx <GFX_MEM     
      ldy >GFX_MEM     
      stx GFX_PTR        
      sty GFX_PTR+1
      ; zerujemy zapamietane pozycje x/y
      ldy #0
      ldx #0
      stx POS_X
      stx POS_Y
  
      ;czekamy na ramke
      lda 20   
      cmp 20
      beq *-2 
  
rysPixeliLoop  
     lda COLOR

     ; y=0 - po prostu 16bit pointer, ktory jest przesuwany, i tylko dlatego ten tryb aderesowania
     ; trace na tym pewnie 1 czy 2 cykli, ale to chyba nie powinno byc kluczowe
     sta (GFX_PTR),y
         
     ; przesuwamy pointer na aktualnie wypelniany bajt pamieci obrazu
     lda GFX_PTR
     clc
     adc #1
     sta GFX_PTR     
     bcc noCC
     ; jesli mniej znaczacy bajt sie "przekrecil" to zmiekszamy bardziej znaczacy
     lda GFX_PTR+1
     clc
     adc #1
     sta GFX_PTR+1
noCC
     ; aktualizyjemy zapisana pozycje X (2 razy bo aktualizujemy 2 pixele na raz)
     ldx POS_X
     inx
     inx
     stx POS_X
     
     ; 80 pkt w linii
     cpx #80
     bcc rysPixeliLoop
     
     ; to byl koniec linii wiec zerujemy pozycje X
     ldx #0
     stx POS_X
     
     ;ilosc linii
     ldx POS_Y
     inx
     stx POS_Y     
     cpx #80
     bcc rysPixeliLoop     
     
     ; ostatnia linia czyli zmieniamy kolor obu pixeli w bajcie
     ; odcien zmieniamy naprzemiennie by bylo widac, jak wolno generuje sie obraz
     lda COLOR
     cmp #%00110011
     beq cl1
     lda #%00110011
     jmp stCl
cl1     lda #%11111111
stCl sta COLOR

     ; rysujemy od nowa z nowym kolorem
     jmp rysObrazuLoop     
    
; DLI IMPL - inf loop aby zobaczyc ile jestem w stanie narysowac w jednej ramce
dli    
        jmp dli
    
antic dta b($70,$70,$70)
      dta b($00),b($4f),a($9000),b($f,$f,$f,$f,$f,$f,$f,$f,$f)
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
      
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)    
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f) 
      dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f+$80)     
      
      dta b($41),a(antic)  

Macie jakies hint'y ??? W sumie to interesuja mnie 2 problemy niezaleznie czyli kwestia szybkiego rysowania i synchornizacji i niemrugania podczas rysowania czegos co zajmuje kilka ramek. Oraz druga sprawa dotyczaca samej plazmy czy taki sposob ma szanse powodzenia czy zabieram sie za to od .... strony;)

Maciek
--------
Atari 65XE + Ultimate 1MB + Stereo + SIO2SD | Atari 520STE + 4MB + UltraSatan | Atari Falcon 030 + CT60e + 14MB ST + 256MB TT + 68882  + CF + Netusbee | Amiga 500 + 1MB + Gotek | Amiga 600 + 2MB Chip + 8MB Fast + CF

2

Odp: Rysowanie na ekranie a mruganie, synchronizacja etc

rysuj na 2 ekranach i wyswietlaj ten ktory zostal juz narysowany, a rysuj na niewidocznym, przelaczasz na vblanku.

3

Odp: Rysowanie na ekranie a mruganie, synchronizacja etc

ponizej przyklad pseudoplasmy z uzyciem podwojnego buforowania

gfx_mem        equ $8000 ; mlodszy bajt musi miec wartosc 00!
gfx_mem2    equ $a000 ; mlodszy bajt musi miec wartosc 00!
pos_x        equ $80
pos_y        equ $81
color        equ $82
sinval        equ $83
licznik        equ $84

;
    org $4000

;
; Start
;
Start
    ldx #<antic
    ldy #>antic
    stx 560
    sty 561

    lda #%01000000
    sta 623

    lda #%00100010
    sta 559      

;
; Init
;
Init
    lda #>GFX_MEM
    sta SCRBUF_PTR+1 ; ustawiamy bufor na GFX_MEM

;
; glowna petla efektu
;
Loop
    lda 20
    cmp 20
    beq *-2 ; czekamy ramke

    lda scrbuf_ptr
    sta gfx_ptr
    lda scrbuf_ptr+1
    sta gfx_ptr+1 ; ustawiamy bufor na ktorym chcemy rysowac

    lda scrbuf_ptr+1 ; podmieniamy bufor ekranu, 
    eor #>GFX_MEM ^ >GFX_MEM2 ; tak zeby bufor na ktorym
    sta scrbuf_ptr+1 ; chcemy rysowac nie byl wyswietlany

;
; tu zaczynamy rysowac nasz efekt
;
    inc licznik
    ldx licznik
    ldy 20
    clc
    lda sintab,x
    adc sintab,y
    sta sinval ; takie cos, co spowoduje, ze plasma bedzie sie ruszac

    ldy #0 ; Y bedzie zawierac pozycje Y

Loop_Y
    ldx #0 ; X bedzie zawierac pozycje X (podzielona przez 2)

Loop_X
    sty pos_y ; zapisujemy aktualna pozycje Y

; liczymy kolor dla parzystego pixela
    tya
    clc
    adc 20 ; dodajemy wartosc licznika aby uzyskac jakis ruch
    tay

    clc
    lda sintab,x
    adc sintab,y ; liczymy kolor uzywajac wsporzednych X i Y
    adc sinval
;    lsr @  ; sin(x)+sin(y)+sinval da w wyniku wartosc z 
;    lsr @  ; zakresu 0-255, musimy wiec podzielic przez 16
;    lsr @  ; aby miec wartosc z zakresu 0-15
;       lsr @
;    asl @
;    asl @
;    asl @
;    asl @ ; a teraz przesuwamy o 4 bity w lewo
    and #$f0 ; robi dokladnie to samo co ten ciag lsr i asl u gory ;)
    sta color ; zapisujemy chwilowo kolor

; nastepny pixel (pixel nieparzysty)
    inx 
    clc
    lda sintab,x
    adc sintab,y ; liczymy kolor uzywajac wsporzednych X i Y
    adc sinval
    lsr @  ; sin(x)+sin(y)+sinval da w wyniku wartosc z 
    lsr @  ; zakresu 0-255, musimy wiec podzielic przez 16
    lsr @  ; aby miec wartosc z zakresu 0-15
    lsr @
    ora color ; "dodajemy" pixel parzysty do nieparzystego
    sta color ; zapamietujemy kolor

    txa
    lsr @
    tay       ; dzielimy X przez 2 aby wskazywal na odpowiednie miejsce na ekranie

    lda color
gfx_ptr    equ *+1
    sta $ffff,y 

    ldy pos_y

    inx ; nastepny pixel
    cpx #64 ; 64 pixeli w poziomie
    bcc Loop_X

; nastepna linia
    clc
    lda gfx_ptr
    adc #40
    sta gfx_ptr ; dodajemy do wskaznika ekranu 40 aby przejsc do nowej lini
    bcc Skip
    inc gfx_ptr+1

Skip
    iny ; nastepna linia
    cpy #90 ; 90 linie w pionie
    bcc Loop_Y

    jmp Loop

;
antic
    dta b($70,$70,$70)
    dta b($00)
scrbuf_ptr equ *+1
    dta b($4f),a($9000)
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f)
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
    
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)    
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f) 
    dta b($f,$f,$f,$f,$f,$f,$f,$f,$f,$f)  
    dta b($41),a(antic) 

; tablica sinusa - zawiera wartosci od 0 do 63
sintab
costab    equ sintab+64
    dta sin(32, 31, 64, 0, 256+64)


;
    run Start

kod jest bardzo wolny, ale chcialem zeby byl dosc przejrzysty i latwy do zrozumienia

plasmy nie powinny migac nawet jesli nie uzywamy podwojnego buforowania - usun: eor #>GFX_MEM ^ >GFX_MEM2 z powyzszego przykladu zeby wylaczyc podwojne buforwania - widac co prawda jak sie ekran rysuje ale nie jest to miganie...

nie uzyskasz plynnej plasmy (50fps czy nawet 25fps) w tak wysokiej rozdzielczosci (80x192) - bez uzycia trickow z LMS (powtarzanie lini przez display liste) jest to technicznie niemozliwe - sam zapis wartosci koloru na ekran w 80x192 wymaga az 7680 sta! (40*192) - a to w najlepszym przypadku 30720cykli - czyli prawie cala ramka

jesli chodzi o optymalizacje to powinienes dazyc aby LoopX wygladal mniej wiecej tak:

Loop
       lda t1
       clc
       adc #2
       sta t1
       sta _sin1+1
       ...
       lda t2
       clc
       adc #3
       sta t2
       sta _sin2+1

LoopY
       ...
_sin2 lda sintab,x
       adc sintab,y
       sta _sin0+1
       ....

       ldx #39
LoopX
_sin0 lda #0
_sin1 adc sintab,x
         tay
         lda colortable,y
_scr   sta screen,x
         dex
         bpl LoopX

i zamaist bawic sie w pixele parzyste i nieparzyste zrobic sobie rozdzielczosc pozioma 40pixeli zamiast 80 (czyli kolor 15 ma wartosc $FF, kolor 3 wartosc $33 itp) - to bardzo przyspiesza obliczenia

ogolnie najlepiej do plasm uzywac trybu textowego ze specialnym zestawem znakow - szybki i prosty w uzyciu, a plasmy w tym trybie niedosc ze chodza szybciej (mozliwe zrobienie plasmy w 1 ramce bez uzycia trickow LMS) to w dodatku wygladaja lepiej...

Ostatnio edytowany przez pr0be (2011-11-06 22:34:30)

4

Odp: Rysowanie na ekranie a mruganie, synchronizacja etc

"Ze specjalnym zestawem znaków" - czyli zrobić plasmę w 40x24? Hmmm, na dobry początek cieszy, ale potem te wielgachne piksele po prostu rażą w oczy.

Natomiast co proponujesz dla osób chcących bawić się w piksele parzyste i nieparzyste w efektach typu "fire", gdzie trzeba jeszcze czytać z ekranu?

Oj pomęczę cię pr0be za kilka dni :P

grzybson/SSG^NG

5

Odp: Rysowanie na ekranie a mruganie, synchronizacja etc

http://atari.fandal.cz/detail.php?files_id=316 - plasme w trybie znakowym - dodam, ze uzywa ona tylko 16znakow (16kolorow), przy 128znakach (128 ditherowanych "kolorach") nie widac wogole, ze to jest tryb znakowy.... wyglada jak ditherowana plasma w 160x192...

a co do pixeli parzystych i nieparzystych to duzej filozofi nie ma:

; zapis
lda color ; color zawiera kolor dla pixela nieparzystego
ora mul16tab,x ; x zawiera kolor dla pixela parzystego
sta screen,y
...

mul16tab dta $00,$10,$20,$30,$40,$50,$60,$70,$80,$90,$a0,$b0,$c0,$d0,$e0,$f0

; odczyt
lda screen,y
tax
and #$0f
... ; tu cos robimy z pixelem nieparzystym

lda div16tab,x
... ; tu cos robimy z pixelem parzystym

6

Odp: Rysowanie na ekranie a mruganie, synchronizacja etc

No to teraz juz chyba wiem wszystko. Dzieki bardzo za obszerne odpowiedzi. Dokoncze ta plazme uzywajac dwubuforowania tak czy inaczej w tej rozdzielczosci by zobaczyc jak to dziala. I sie czegos nauczyc przy okazji.
PrObe, bede potrzebowal chwili by przetrawic Twoje kody. Jesli czegos w nich nie skumam, albo znowu na czyms utkne to bede Was tu dalej meczyc;)

Maciek
--------
Atari 65XE + Ultimate 1MB + Stereo + SIO2SD | Atari 520STE + 4MB + UltraSatan | Atari Falcon 030 + CT60e + 14MB ST + 256MB TT + 68882  + CF + Netusbee | Amiga 500 + 1MB + Gotek | Amiga 600 + 2MB Chip + 8MB Fast + CF