Gönderen Konu: Parallax mantığı  (Okunma sayısı 32743 defa)

0 Üye ve 1 Ziyaretçi konuyu incelemekte.

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: Parallax mantığı
« Yanıtla #15 : 20 Kasım 2014, 00:40:47 »
İşin içine $d016'yı da ekleyerek scroller'ı biraz daha smooth hale getirdim. Bayağı bir optimizasyon da yaptım. Yine de sormak istediğim hoşuma gitmeyen bazı şeyler var. Öncelikle kaynak kodlarının github linkleri:

scroller.asm
scroller-subroutines.asm

prg dosyası github'da da var. İsterseniz aşağıda ekler kısmından da alabilirsiniz.

Programın başında kullanacağım zero page adreslerini $02'den başlayarak sıralıyorum. Kernal IRQ'ları kapattığım için sorun olmuyor. Eğer kernel IRQ'ları kullanacak olsaydım. Hangi ZP adreslerini kullanabilirim?

Kullandığım counter rutininden memnun değilim. Örneğin part2 ilk iki frame'de kayıyor, sonraki iki frame bekliyor. Eğer bir frame kayıp, bir frame beklese efekt daha yumuşak olacak. Farklı bir bekleme/sayaç mantığı nasıl kurulabilir bilemedim.

Kod: [Seç]
.delay  inc COUNTER ;increase the COUNTER
  ldx COUNTER
cpx #05
bne .delay2

ldx #00
stx COUNTER

.delay2 cpx #04 ;Skip clculation parts as per
beq .part2 ;delay value
cpx #03
beq .part3
cpx #02
beq .part4
cpx #01
beq .part5

Bu soru iki türlü algılanabilir:
1- kodu 4 kere yazmaktan rahatsızsın ama bellekte 4 kere yer kaplaması OK
2- kodun bellekte de 4 kat yer kaplamasından rahatsızsın

Üniversitedeki C sınıfından mı, yoksa çok eskiden okuduğum bir makaleden mi bilmiyorum aklıma kazınmış "Bilgisayarın yapabileceği rutin işi sen yapma" şeklinde bir söz var. Bunu ben hep aynı şeyi iki kere yazıyorsan optimizasyon hatası yapıyorsun olarak algıladım. 6502 evreninde işlerin tam bu şekilde yürümediğin yavaş yavaş kavramaya başlıyorum. Kodun bellekte 4 kere yer kaplamasını yarı hızda çalışmasına yeğliyorum.

Makro konusundaki örnek için de çok teşekkürler. Şimdilik makrolara girmek istemedim. Çünkü şu kodu çalıştırıp, bir de internete yüklemek için 6502'nin yanında ayrıca giriş seviyesinde bash, git ve vim öğrenmem gerekti. Bu yaştan sonra bünye kaldırmıyor. Daha sonra koda renk geçişleri eklemeyi düşünüyorum. Artık makrolara bir da o zaman bakarım.
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 3093
  • Advanced User Simulator
    • ae unutmadan
Ynt: Parallax mantığı
« Yanıtla #16 : 20 Kasım 2014, 01:04:35 »
İşin içine $d016'yı da ekleyerek scroller'ı biraz daha smooth hale getirdim.

....

Üniversitedeki C sınıfından mı, yoksa çok eskiden okuduğum bir makaleden mi bilmiyorum aklıma kazınmış "Bilgisayarın yapabileceği rutin işi sen yapma" şeklinde bir söz var.

Biraz değil, smooth olmuş. Eskisi karakter tabanlı scrolling yapıyordu. Çok da güzel olmuş.

z80 dünyası da unrolled loop'larla dolu. Başta ben de yadırgamıştım, 2-3kb dolusu manuel kopyalama komutunu görünce, LDIR'in nesi vardı diyorsun ama sonra aradaki hız farkının tam iki kat olduğunu görünce doğru hesabı yapıyor insan. Asmp ekran modunun z80 kodunu yazarkende mecburen böyle bir işe girişmiştim, makro ile oluşturulan kod 6kb'ı buluyordu. Bu sebepten, bizim gibi yavaş cpu'lara asm yazan kişilerin ilk öğrenmesi gereken şey makro dili. iyi kalpli Nightlord zaten söylemiş nasıl kullanacağını, makro olmadan bu tür 4-5 kere yazılmış kodun bakımını yapmak çok zor oluyor.

Çevrimdışı nightlord

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 389
    • Night Network
Ynt: Parallax mantığı
« Yanıtla #17 : 20 Kasım 2014, 01:27:34 »
amanin ikinci joker vakasi :) ellerine saglik wizofwor. ilk firsatta koda daha detayli bakip yorumlarimi aticam

Çevrimdışı Wisdom

  • RAAT
  • Retroman
  • *
  • İleti: 44
Ynt: Parallax mantığı
« Yanıtla #18 : 20 Kasım 2014, 03:55:36 »
Bu basligi daha yeni gordum, guzel konuymus, kacirmisim.

Genel bir sey eklemek istedim sadece: C64'te (ve muhtemelen raster duzeyinde ekrani update edebildiginiz diger sistemlerde), ekranla ilgili yapilan degisikliklerin mutlaka ekranin gorunebilir alani disinda olmasi gerekmiyor (titremeleri onlemek, efekti smooth yapabilmek adina). Bunun icin tek bir kaide var; bulundugunuz raster satirinda o satiri degistirmemek. Yani 40x25 scrolling yaparken ekranda tearing (titreme vb) olmasini engellemek icin kaydirmaya border'dan baslamak yerine kaydirilan video/color ram satirinin bir alt satirindan baslamak sorunu ortadan kaldiracaktir (her bir ekran satirini islemenin yine bir ekran satiri kadar raster zamani harcadigi ve butun bu islemi de 1 frame suresi icinde tamamladiginiz varsayimi ile). Ilk satir zaten gosterildigi icin ikinci satirda ilk satiri degistirmeniz ancak bir sonraki frame'de gorunebilir olacaktir, bu islemi tum kalan satirlar icin yaptiginizda da gorsel olarak bir problem yasamazsiniz.

Eger update yapan rutin raster'in ilerleme hizina yetisiyorsa o zaman yukaridakinden biraz farkli olarak ilk baslayacaginiz satiri daha ileri almak durumunda kalabilirsiniz. (Yani birinci satiri ikinci satir civarinda update etmek yerine, 5. ya da 10. satirda update etmeye baslamak isteyebilirsiniz).

Biraz kotu anlattim ama dilerim ilgilenen arkadaslara bir faydasi olur.

Çevrimdışı witchdoktor

  • RAAT
  • Normalleşmiş Retroman
  • *
  • İleti: 757
Ynt: Parallax mantığı
« Yanıtla #19 : 20 Kasım 2014, 09:49:30 »
C64 memory map'de zeropage'de 10-15 byte'lık serbest alan görülüyor.

http://sta.c64.org/cbm64mem.html

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: Parallax mantığı
« Yanıtla #20 : 20 Kasım 2014, 10:58:15 »
10-15 byte boş görünüyor dediğin $03-$12 arası mı? Bu arada BASIC rutinlerinin kullandığı alanlar var. Eğer BASIC rutinlerini kullanmıyorsak $90'a kadar yardıramaz mıyız?
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı nightlord

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 389
    • Night Network
Ynt: Parallax mantığı
« Yanıtla #21 : 20 Kasım 2014, 11:04:29 »
evet once basic'ten vazgec ve $2'den $90'a kadar yardir. sonra kernel'den de vazgec (su an kernelden kullandigin tek sey irq entry ve exit rutinleri yani ff48 ve ea81. bunlara bakarsan yaptiklari tek seyin registerlari hatirlamak oldugunu goreceksin. bu kodu kendin yazip irq vektor olarak 314 315 yerine fffe ffff kullanirsan kerneli kapatip butun zero page'i de kullanabilirsin)

daha timing counter'larin ile ilgili yorum yazicam ama bu gece firsat olmadi

Çevrimdışı nightlord

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 389
    • Night Network
Ynt: Parallax mantığı
« Yanıtla #22 : 26 Kasım 2014, 21:43:15 »
senin kodunu nacizane analiz edeyim ve bence neden zorlandigini aciklamaya calisayim. sonra da timing olayini ben olsam nasil cozerdim onu aciklamaya calisayim.

analiz:
su anki halinde yasadigin problem bence scrollar.asm 74-121. satirlar arasindaki rutinin yeterince parcalanmamis olmasindan kaynaklaniyor. kodun bu bolumu ard arda dizilmis islemler iceriyor ve siralari onemli. 56-71. araligindaki kosullarla 74-121 araliginda tek noktaya atliyorsun ve ondan sonrasi calismak zorunda kaliyor. bu part1, part2 part3 vs'nin birbirinin arkasindan calisiyor olmasi bana gore gereksiz bir  "coupling" halbuki bu partlarin yaptigi isler birbirinden bagimsiz isler.

burada hemen nacizane bazi rename onerilerimi sunacagim, bunlar sonraki cozum onerimin daha kolay anlasilmasini saglayacak.

genel olarak butun yazilim islerinde isimlere cok onem vermek lazim. iyi isimlendirmeye onem verirsek dusunusumuz de berraklasiyor. iyi bir isim o parcanin ne yaptigini berrakca anlatan en kisa ifade olmali. her zaman super isimler bulmak kolay degil ama cabanin bile kendi basina faydasi var. ben genel prensip olarak fonksiyon/method/subroutine isimlerine "fiil + nesne ismi" gibi bir format kullanmaya calisirim. "calculateDelay" "scrollLine" "moveChars" "initEffect" vs gibi... Bazen bunun hafif disina cikarim daha aciklayici oldugunu hissedersem. super lokal looplarda atlama yeri etiketleri falan icin cok kasmam ama subroutine isimleri onemli.

Bu dogrultuda part1 part2 gibi isimler biraz generic/ambiguous kaliyor. keza shift1 shift2 gibi isimler de ilk bakista ne yaptigini isminden cikaramadigim seyler. shift2 mesela karakterleri kaydiriyor ama d016 kaydirmasini da yapiyor olabilirdi. shift2'nin koduna bakmadan bunu anlamak mumkun degil. Bu yuzden ben olsam shift1 shift2 vs isimlerini, charScrollLine1 charScrollLine2 falan yaparim. part1 part2 falan bolumlerini de her birini bagimsiz bir subroutine haline getirir ve isimlerine pixelScrollLine1 pixelScrollLine2 falan yaparim. yani mesela
Kod: [Seç]
pixelScrollLine2:
!zone{
        lda offset2 ;Calculate offset for line 2
sec
sbc #01
and #07
sta offset2

cmp #07 ;when offset value is not 7
bne .end ;skip char shifting part
jsr charScrollLine2
.end:
        rts
}

timing cozum: birinci adim yukaridaki gibi part1,part2 vs'yi birbirinden bagimsiz pixel scroll rutinleri haline getirmek. Bu rutinlerin yaptigi is artik bagimsiz olarak tanimli pixelScrollLine2 cagirdigim zaman biliyorum ki line2 bir pixel kayacak (eger icinde zamani galmisse karakterler de kayacak ama bu kaygi artik pixelScroll rutininin icindeki bir ic detay haline geldi. pixelScroll rutininin musterisi artik bunu dusunmek zorunda degil.)

ikinci adim da 56-71 arasinda atlanilan yerlerde yapilan isi degistirmek. Burada 5 durumlu bir counter kurmus durumdasin. Bu 5 durumun her birinde ne olmasini istiyorsan bunu artik tek tek yapabilirsin. her durumda hangi satirlari scroll edip hangilerini etmemeyi kontrol etmek cok kolay. mesela
1 nolu durum: logo scroll ama satirlar beklesin
2 nolu durum: satir 4 scroll etsin digerleri beklesin
3 nolu durum: satir 2 ve satir 4 scrol etsin

vs...

bu durumda yine bi onemsiz gorunen rename. beq ile atladigin yerleri part1 part2 diye isimlendirmek yerine "state1, state2 vs" ya da counter oldugunu ifade etmek icin "cycle1, cycle2 vs" diye isimlendirmek bence daha seffaf

diger bir ufak oneri genelde bu tip counter tabanli loop gorunumlu seylerde "off by 1" hatasi yapmak cok kolaydir. Bunu engellemenin en iyi yolu genel olarak hep ayni yapiyi kullanmak. yani counter'i ne zaman artiriyoruz ne zaman kontrol ediyoruz. vs. ben asagida bunu hafif degistiriyorum

Kod: [Seç]

.delay 
  ldx COUNTER
cpx #00
        beq .cycle0
cpx #01
        beq .cycle1
cpx #02
        beq .cycle2
cpx #03
        beq .cycle3
cpx #04
        beq .cycle4

        ; if we are here Counter == 5 and it's time to reset.
ldx #00
stx COUNTER

.cycle0:
        ...
        jmp .end

.cycle1:
        ...
        jmp .end
.cycle2:
        ...
        jmp .end

.cycle3:
        ...
        jmp .end

.cycle4:
        ...
        jmp .end

.end:
        inc COUNTER
        ; then go on to the action part


simdi en basta bahsettigin herhangi bir satirin "2 kaydi 2 kaymadi yerine bir kayip bir kaymadi" olayini yapabilirsin. 5 cycle'dan hangilerinde kaymasini istiyorsan (mesela cycle 1, 3, te kaysin 0 2 4'de kaymasin) o cycle'larin bolumune birer jsr pixelScrollLineX yerlestirmen yeterli.

Burada yaptigimiz sey temel olarak su: "Bilgisayar bilimlerindeki pek cok problem bir seviye fazla araci katarak cozulebilir" (most problems in computer science can be solved by adding a level of indirection). burada scroll yapan rutinleri birbiri ardina dizip cycle'a bakarak aradaki bir noktaya atlamak yerine, scroll rutinlerini bagimsiz rutinler haline getirip araya o rutinleri dogru cycle'larda cagiran bir araci seviye (.cycleN rutinleri) ekledik. Bu bize her cycleda hangi satirlari istersek kaydirabilme sansi verdi.


Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: Parallax mantığı
« Yanıtla #23 : 27 Kasım 2014, 08:37:40 »
Değerli tavsiyelerin için teşekkürler. Çok faydası olduğuna emin olabilirsin.
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 3093
  • Advanced User Simulator
    • ae unutmadan
Ynt: Parallax mantığı
« Yanıtla #24 : 28 Kasım 2014, 19:42:56 »
Burada yaptigimiz sey temel olarak su: "Bilgisayar bilimlerindeki pek cok problem bir seviye fazla araci katarak cozulebilir" (most problems in computer science can be solved by adding a level of indirection).

Güzel bir öğütmüş, kulağımıza küpe yapalım. Yalnız burada "ne zaman bir yönlendirme daha eklemeliyim?" sorusunun cevabı yok, sanırım cevap "tecrübe" olsa gerek.



edit: Bu konu bölünmüştür. Konunun bölünmüş başlığı aşağıdaki bağlantıdan takip edilebilir:
http://retrojen.org/pano/index.php?topic=763.msg6321;topicseen#msg6321

Çevrimdışı nightlord

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 389
    • Night Network
Ynt: Parallax mantığı
« Yanıtla #25 : 02 Aralık 2014, 03:54:35 »
Güzel bir öğütmüş, kulağımıza küpe yapalım. Yalnız burada "ne zaman bir yönlendirme daha eklemeliyim?" sorusunun cevabı yok, sanırım cevap "tecrübe" olsa gerek.

"Ne zaman" sorusunun cevabi bu sozun baglaminda su: yonlendirmeyi eklemeden problemi cozemedigin zaman.

Cunku bu soz konuya fonksiyonel dogruluk acisindan yaklasiyor. Amac once yapmak istedigin seyi fonksiyonel olarak yapabilmek (perf olarak yavas olabilir o ayri konu). Sorunu cozdukten sonra perf optimizasyonuna gidecegin soylenebilir. Baska deyisle: Oncelikle "calistir" sonra "optimize et"

isin tecrube ile ilgili olan kismi bazi durumlarda bazi indirection'larin performansi kabul edilemez kilacagini bastan bilmek ve o yola bastan sapmamak. Bazen bu "tecrube" geri de tepebilir. yani calistirmadan optimize etmeye calisanlarin basina belalar geldigi cok gorulmustur. Tabi CS camiasinda bunun icin de ozlu soz var. Knuth Baba'dan tum sevenlere gelsin:

"Vaktinden once yapilan optimizasyon butun kotuluklerin anasidir" (Premature optimization is the root of all evil)

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: Parallax mantığı
« Yanıtla #26 : 06 Ocak 2015, 00:50:48 »
Herkese mutlu yıllar. Bu başlığa ilk çalışan kodu geçen yılın ilk günü atmışım. Geriye dönüp bakınca benim için oldukça verimli bir yıl oldu diyebilirim. Belki alışkanlık haline getiririm temennisiyle, biraz aceleye getirsem de yine çalışan bir şeyler paylaşıyorum.

Scroller #04 (github link)

Bu sefer bir önceki programdan tamamen farklı bir yaklaşım izledim. Metin yerine basit bir petscii garafik hazırladım. Irq rutinini de elimden geldiğince basit tutmaya çalıştım. Bu rutini her satır için (25 defa) tekrar çağırıyorum.

Kod: [Seç]
;====================================================================
; IRQ routine:
; Sets x-scroll register and for each raster zone
; and sets scrollFlag on Each screen refresh
; ===================================================================

irq:
!zone {
;dec $d020
;-------------/ wait for next raster for stable effect /-
ldx irqIndex
lda scrollRasterLo,x
clc
adc #$01
- cmp $d012
bne -
   
  ;--------------/ set XSCROLL /--------------------------
  lda scrollOffset,x
  sta $d016
;--------------/ increase irqIndex /--------------------
  inx
  cpx #25
  bne + ; index != 25, skip
  ldx #00 ; reset index
  lda #01 ; set scrollFlag
  sta scrollFlag
+ stx irqIndex ;store updated index value
lda scrollRasterLo,x    ;update raster row for next irq
sta $d012
.end
;inc $d020
dec $d019 ;acnowledge IRQ register
jmp $ea81 ;return to kernel
}

Geri kalan hesaplamaları main loop içinde yaptırdım. Main loop ile irq arasındaki senkronizasyon için zeropage'de bir byte'ı bayrak olarak kullandım. Hareketi yavaşlatmak için Ref'in önerdiği maske sistemini kullanmayı denedim.

Kod: [Seç]
ldy scrollSpeed,x ;chech the speed mask
lda speedMask,y
bit counter
bne +

...
...
scrollSpeed:
!by 4,3,2,1,0,0,0,0,0,0
!by 0,0,0,0,0,1,2,1,2,3
!by 2,3,4,3,4
speedMask
!by %111111,%110111,%101010,%001001,%000000

Sonuçta sağda solda pek çok glitch olsa da çalışan bir şeyler etmeyi başardım. Şimdilik kodu paylaşmakla yetiniyorum. Sorularım daha sonra gelecek.


 
Gosub ile gidilen yerden goto ile dönen adam

Çevrimdışı Ref

  • Yönetici
  • Özgür Retrocu
  • *
  • İleti: 3093
  • Advanced User Simulator
    • ae unutmadan
Ynt: Parallax mantığı
« Yanıtla #27 : 06 Ocak 2015, 14:36:15 »
Eline sağlık wiz, süper olmuş. Dalgaları bu kadar basit bir şekilde çözebilmen de etkileyici. Bir göz aldanması var ve işe yarıyor.

Yukarıdaki bulutlarda bazı "glitch"ler var, timing ile ilgili büyük ihtimal. Bad raster işleri falan vardı c64'te bu tür bir sorun mu acaba?

Müzik kime ait?

Kodu inceliyeceğim çünkü orta kısımdaki karakter tabanlı grafik hi-res şekilde 1 pixellik bir kayma yapıyor, bakıcam oraya. Benim mask sistemini anlamış olmanın yanı sıra, uygulamış olmanı heyecanla karşıladım :D Lakin ben bile dönüp okuduğumda neden bahsettiğimi pek anlayamıyorum :) Niye bitmaskla uğraşıp zaman kaybetmeyi önermişim acaba? Hayırlamıyorum valla :D Ama işe yaramış galiba.

Diğer taraftan ekran görüntüsü niye pdf onu pek çözemedim işte :D

Çevrimdışı witchdoktor

  • RAAT
  • Normalleşmiş Retroman
  • *
  • İleti: 757
Ynt: Parallax mantığı
« Yanıtla #28 : 06 Ocak 2015, 15:08:22 »
Benim mask sistemini anlamış olmanın yanı sıra, uygulamış olmanı heyecanla karşıladım :D Lakin ben bile dönüp okuduğumda neden bahsettiğimi pek anlayamıyorum :) Niye bitmaskla uğraşıp zaman kaybetmeyi önermişim acaba? Hayırlamıyorum valla :D Ama işe yaramış galiba.

Senin mask sistemini anlayabildiğine göre oldukça kabiliyetli biri olmalı wizofwor, daha bir saygı duydum şimdi. Sen bile zaman zaman zorlanıyorsun. Ayrıca gönderilerinle ilgili bir 'brain buffer' tutsan güzel olacak, zaman zaman 'Memento' vari senaryolar çıkıyor ortaya :)

Gizli Not: Bu zamanlama hilesini mucidi açıklamadan kullanmayı düşünüyorum. Yakalarsan kızar mısın? ;)

Çevrimdışı wizofwor

  • RAAT
  • Tedavideki Retromanik
  • *
  • İleti: 398
Ynt: Parallax mantığı
« Yanıtla #29 : 06 Ocak 2015, 15:28:46 »
Müzik son dakikada hvsc'den rastgele indirilmiş bir şey. Kafa ütülemekten başka bir işe yaramıyor galiba. Küçük bir itirafta bulunmam gerekirse bitmask'la ilgili olarak ne önerdiğini ilk başta anlamamıştım. Ama kafamda oluşan fikirler, biraz deneme yanılmayla beni gördüğün sonuca ulaştırdı. Hala da nasıl çalıştığından tam emin değilim. Maskedeki kapalı bitleri arttırdıkça efekt hızlanıyor. Halbuki ben tam tersini yapmak istemiştim. Yalnız bunun önceki switch/case tarzı koda göre çok daha efektif bir sistem olduğunu rahatlıkla söyleyebilirim. Her karakterin satırının hızını ayrı tutuyorum. Eski sistemle çok uzun bir kod yazmam gerekirdi.

Zamanlama sıkıntılarına gelince. İki ayrı sorun var. Birincisi bulutlarda ekran kaydırma için istediğim satırı bir türlü tutturamıyorum. Irq'ya bir satır erken girip, asıl satırı beklemek için aşağıdaki kodu eklediysem de irq rutinim stable falan olmadı.

Kod: [Seç]
ldx irqIndex       ;irq sıra numarası
lda scrollRasterLo,x    ;irq satır numarası
clc
adc #$01
- cmp $d012
bne -

İkincisi ise karakter kaydırma rutiniyle ilgili bir sıkıntı. O gördüğün kaymanın VIC'in karakter kopyalayan rutine tur bindirmesinden kaynaklandığını düşünüyorum. Sonuçta bu rutin irq dışında çalışıyor ve zamanlamasını kontrol etmiyorum.
Gosub ile gidilen yerden goto ile dönen adam