kategoria: ANSI C
[#1] pisanie GRY w C pod A500
Ostatnio zagłębiłem się w programowanie na Amidze 68k i już mniej więcej ogarnąłem na czym polega Intuition i graphics.library (screeny, okienka, rysowanie figur, obsługa zdarzeń, requestery, menu). A zatem zasadę pisania programów pod AmigaOS mam w stopniu podstawowym opanowaną.

I co dalej? Docelowo chcę przeportować grę z innego systemu. Jaką? Niech to pozostanie póki co tajemnicą. O to, że A500 się zadławi nawet się nie mam co martwić. Nie mam za bardzo pomysłu jak się zabrać za cokolwiek dalej, bo tutoriale w necie zdają się w ogóle nie dążyć w kierunku informacji, które potrzebuję. Mam szereg wątpliwości, które potrzebują wyjaśnienia:

  • z tego co zauważyłem, to graphics.library służy do wysokopoziomowego rysowania grafiki i właściwie nie pozwala na wykonywanie żadnych operacji sprzętowo, stąd można zapomnieć o robieniu poważniejszej gry pod tą biblioteką?
  • jeśli nie korzystać z graphics.library to z czego? SDL i inne tego kalibru odpadają, nie po to piszę pod Ami żeby się w nienatywność bawić
  • jak właściwie należałoby napisać init takiej gry? Dobrą ścieżką jest otwarcie własnego screena z konkretną rozdzielczością i bpp (jak włączyć EHB?), na nim okienka borderless i na nim rysowanie? Czy też trzeba zrobić jakiś chocek klocek żeby jechać bezpośrednio na sprzęcie? Ale jak? Są do tego jakieś logiczne zestawy funkcji pod C?


Zdaję sobie sprawę, że na wszystko można odpowiedzieć w formie 'i tak, i nie'. Dlatego jeszcze przedstawię listę rzeczy, których bym w grze potrzebował:

  • rozdzielczość 320 PAL/NTSC bez przeplotu, nic wyżej nie będzie potrzebne
  • fullscreen, działanie w niepełnym oknie nie jest nawet brane pod uwagę
  • dość dużo kolorów, prawdopodobnie skończy się potrzebą trybu EHB
  • będzie dość dużo sprite'ów, większość to tło, ze dwie postaci na ekranie, rzadko kiedy czymś przykrywane, ale jak już to raczej kształtem nie kwadratowym tylko czymś ażurowym. Blittowanie przez maskę będzie nieocenione
  • start z dyskietki, może być bez własnego bootblocka tylko DOS+startup-sequence
  • fajnie by było dać możliwość odpalania z dysku twardego pod WB. Wydaje mi się, że powyższe rozwiązanie dyskietkowe załatwi sprawę (przeciągnij pliki gry na dysk twardy i tyle?)
  • fajnie by też było zrobić wyjście z gry do systemu operacyjnego, stąd uśmiercanie systemu nie jest pożądane :)
  • interesuje mnie przede wszystkim A500, kick 1.3. Współpraca z kartami graficznymi nie jest ważna. Może później, najpierw ma być wersja typowo na sprzęt, który posiadam :)


Zapał mam, skilla też, tylko może niekoniecznie amigowego. 6 lat programowania na różnych platformach już za mną, bezpośrednio pamięcią podzespołów pecetowych też się bawiłem, także nic mi nie jest straszne. :) Potrzebuję tylko parę odpowiedzi i najlepiej paru krótkich, zwięzłych przykładów.

Zamieszczam to w dziale C, bo tego języka bym się chciał trzymać. Wstawki asm tylko w newralgicznych punktach.
[wyróżniony] [#2] Re: pisanie GRY w C pod A500

@teh_KaiN, post #1

Napiszę głównie o blitowaniu:

z tego co zauważyłem, to graphics.library służy do wysokopoziomowego rysowania grafiki i właściwie nie pozwala na wykonywanie żadnych operacji sprzętowo, stąd można zapomnieć o robieniu poważniejszej gry pod tą biblioteką?

Do rysowania polecam używać bezpośrednio Blittera. Umiesz się nim posługiwać (używać rejestrów sprzętowych)? W C można to zrealizować, choć zalecany jest asembler.

rozdzielczość 320 PAL/NTSC bez przeplotu, nic wyżej nie będzie potrzebne

Polecam użyć systemowych View. Masz przykłady w "ROM Kernel Reference Manual: Libraries". Jest to stosunkowo proste. Jeśli chcesz mogę napisać przykład. Jest to najniższy możliwy sposób ingerencji w obraz za pomocą graphics.library. Używając go uzyskasz szybką animację. Niżej jest tylko Copper sprzętowo, którego nie polecam w C.

będzie dość dużo sprite'ów, większość to tło, ze dwie postaci na ekranie, rzadko kiedy czymś przykrywane, ale jak już to raczej kształtem nie kwadratowym tylko czymś ażurowym. Blittowanie przez maskę będzie nieocenione

Ile kolorów mają mieć sprajty? Jeśli do 3 - możesz użyć sprajtów sprzętowych. Jeśli więcej: użyj obiektów Blittera. Koniecznie sprzętowo (procedury w systemie są za wolne). Co do przykrywania: użyj obiektów Blittera, które rysowane są na bieżąco, ale nie mają odrysowywanego tła, bo się nie poruszają.
[#3] Re: pisanie GRY w C pod A500

@Hextreme-Attic, post #2

Dzięki za odpowiedź.

Do blittera nie dotarłem, bo nigdzie nie widziałem jak by można było coś nim robić. Odwołanie do kursów/refów/tutoriali mile widziane, a podstawowe przykłady jeszcze bardziej :). Co do ilości kolorów to nie jestem pewien, istnieje spore prawdopodobieństwo że będzie ich więcej niż 3.

Co do view to dzięki, przyjrzę się temu jutro. Możesz mi jeszcze podrzucić jakiś punkt zaczepienia, żebym wiedział czego szukać, np. jakaś nazwa funkcji, którą się tam wykorzystuje? Tak żebym nie szukał słowa 'view' jak głupi :)

Obiekty blittera wydają się być w takim razie tym, czego szukam do rysowania sprajtów.

Ostatnia aktualizacja: 08.06.2013 21:31:06 przez teh_KaiN
[wyróżniony] [#4] Re: pisanie GRY w C pod A500

@teh_KaiN, post #3

Ta płytka jest moim zdaniem konieczna dla dewelopera piszącego na Amidze:
http://www.vesalia.de/e_developer2.htm
Podkreślam, że jest warta swojej ceny. Znajdziesz tam pełną dokumentację "ROM Kernel Reference Manual" dla systemu w wersji 2 w języku angielskim. Na sieci istnieje też NDK 3.9 (Native Developer Kit), może ktoś zapoda linka.

Opis użycia View masz w dokumentacji na płytce. Postaram się opisać jak to się robi:
1. Inicjujesz nowe View funkcją InitView():
InitView( &view );

2. Alokujesz bitmapę funkcjami InitBitMap() oraz AllocRaster(). DEPTH to stała oznaczająca głębokość obrazu:
InitBitMap( &bitmap, DEPTH, 320, 256 );
for (i = 0; i < DEPTH; i++ )
   bitmap.Planes[ i ] = AllocRaster( 320, 256 );

3. Inicjujesz ViewPort i łączysz struktury w ten sposób (dochodzi struktura RasInfo):
InitVPort( &vport );
vport.DxOffset = 0;
vport.DyOffset = 0;
vport.DWidth = 320;
vport.DHeight = 256;
vport.RasInfo = &rasinfo;
vport.Next = NULL;
view.ViewPort = &vport;
rasinfo.BitMap = &bitmap;
rasinfo.RxOffset = 0;
rasinfo.RyOffset = 0;
rasinfo.Next = NULL;

4. Pobierasz mapę kolorów funkcją GetColorMap():
vport.ColorMap = GetColorMap( 1 << DEPTH );

5. I na koniec tworzysz i ładujesz nasz nowo-stworzony View:
MakeVPort( &view, &vport );
MrgCop( &view );
LoadView( &view );
WaitTOF();

W ten sposób stworzyłeś pojedynczo-buforowany obraz.

Kiedy twój program kończy działanie zwalniasz zasoby tak:
/* Zwolnienie zasobów */
LoadView( NULL );
WaitTOF();
FreeCprList( view.LOFCprList );
FreeVPortCopLists( &vport );
FreeColorMap( vport.ColorMap );
for (i = 0; i < DEPTH; i++)
FreeRaster( bitmap.Planes[ i ], 320, 256 );
[#5] Re: pisanie GRY w C pod A500

@teh_KaiN, post #3

Zapomniałem napisać o jednej rzeczy: Sprajty sprzętowe mogą mieć też do 15 kolorów (tzw. sprajty połączone).
[#6] Re: pisanie GRY w C pod A500

@teh_KaiN, post #1

z tego co zauważyłem, to graphics.library służy do wysokopoziomowego rysowania grafiki i właściwie nie pozwala na wykonywanie żadnych operacji sprzętowo, stąd można zapomnieć o robieniu poważniejszej gry pod tą biblioteką?


dlatego najlepiej miec wlasne procedury i to korzystajace z blittera na poziomie rejestrow.

jeśli nie korzystać z graphics.library to z czego? SDL i inne tego kalibru odpadają, nie po to piszę pod Ami żeby się w nienatywność bawić


to sa proste prodki, wiec nie potrzeba jakis bibliotek :)

Czy też trzeba zrobić jakiś chocek klocek żeby jechać bezpośrednio na sprzęcie? Ale jak? Są do tego jakieś logiczne zestawy funkcji pod C?


jechac na sprzecie, olac C, tylko asm 68000 + rejestry OCS/ECS. C mozesz sobie wykorzystac do napisania drobnych utilkow...

rozdzielczość 320 PAL/NTSC bez przeplotu, nic wyżej nie będzie potrzebne


trywialnie otwiera sie ekran w takiej rozdzialce uzywajac asm i rejestrow, doslownie kilka instrukcji i prosta copperlista.

dość dużo kolorów, prawdopodobnie skończy się potrzebą trybu EHB


tylko copper da Ci duzo kolorow :)

będzie dość dużo sprite'ów


ile, jak duzych, w ilu kolorach ?

start z dyskietki, może być bez własnego bootblocka tylko DOS+startup-sequence


olac DOS i startup - sequence :)

fajnie by było dać możliwość odpalania z dysku twardego pod WB.


moze ktos przerobi na WHDLoad :).

fajnie by też było zrobić wyjście z gry do systemu operacyjnego


olac system i tak musisz go usmiercic zeby miec pelna moc.

interesuje mnie przede wszystkim A500, kick 1.3.


wystarczy A500/A1000, a kick chocby 1.0 :), wazniejsze, ile RAM potrzebujesz ?

Współpraca z kartami graficznymi nie jest ważna.


olac karty graficzne, do kart graficznych jest UAE.

Zapał mam, skilla też, tylko może niekoniecznie amigowego.


Zazdroszcze

6 lat programowania na różnych platformach już za mną


za mna wiecej, i co z tego, nic mi sie nie chce

Potrzebuję tylko parę odpowiedzi i najlepiej paru krótkich, zwięzłych przykładów.


moge sluzyc bardzo zwiezlymi.

Zamieszczam to w dziale C, bo tego języka bym się chciał trzymać.


lepiej sie nie trzymac na A500.

Wstawki asm tylko w newralgicznych punktach.


a dlaczego nie calosc, przeciez to sa naprawde krotkie fragmenty nie wymagajace jakis optymalizacji etc.. najtrudniej chyba opanowac na poczatek obsluge dyskietki odczyt/zapis sektorow/sciezek, musisz stworzyc cos na wzor wlasnego fs z prosta organizacja i kompersja roznych rodzajow danych. jak to przeszkoczysz, to reszte bez problemu, bo reszte widac, slychac i czuc.
[#7] Re: pisanie GRY w C pod A500

@teh_KaiN, post #1

nie pozwala na wykonywanie żadnych operacji sprzętowo


Bardzo dziwne stwierdzenie. Po to właśnie powstały łatki typu FBlit, aby uniezależnić graphics.library od sprzętu (czyli blittera).
[#8] Re: pisanie GRY w C pod A500

@cholok, post #7

Pewnie nie był świadom, że odwoływanie się bezpośrednio do sprzętu to co innego niż korzystanie z graphics.library, która jest zbiorem funkcji do zadań graficznych korzystających z sprzętu, a to że jest to zbyt wolne do pisania gier na A500 to inna sprawa (róznica taka jak pisanie bezpośrednio pod układ karty graficznej a korzystaniu ze sterownika).
[#9] Re: pisanie GRY w C pod A500

@rafgc, post #8

Z czystej ciekawosci, czy ktos moze podac o ile wolniejsza jest operacja graficzna z graphics.lib od takiej samej sprzetowej?
[#10] Re: pisanie GRY w C pod A500

@selur, post #9

O ile wolniejsza to nie wiem, ale nie masz możliwości stosowania żadnych tricków sprzętowych z pomocą graphics.library, bo to jest zestaw funkcji do rysowania grafiki na ekranie a nie "jeżdżenia po rejestrach", do prostych gierek jak robbo, może i graphics.library się nadaje, ale w sytuacjach, gdzie potrzebne jest indywidualne podejście do sposobu generowania grafiki (czyli precyzyjne operacje na blitterze, copperze i procesorze - inymi słowy "strategia" ) najczęściej trzeba napisać własne procedurki w assemblerze pod konkretne operacje. Prosty przykład, sprawdź w AIBB test writepixel na gołej A500 lub A600, a zobaczysz jak mozolna jest ta procedura, ilość px/s jest naprawdę niewielka (8000px/s na moim akceleratorze z włączonym mapromem) albo przełącz WB na 16 kolorów i sprawdź jak działa, potem zastanów się dlaczego gierki w 16 i 32 kolorach śmigają, a WB z graphics.library nie.

Ostatnia aktualizacja: 09.06.2013 14:48:55 przez rafgc
[#11] Re: pisanie GRY w C pod A500

@Hextreme-Attic, post #4

No, udało mi się ładnie ukraść ekran, wyświetlić szmelc z pamięci i wrócić po sekundzie do WB :)
To ostatnie osiągnąłem tym, że se zapisałem workbenczowy view:
oldView = GfxBase->ActiView

a potem go przywróciłem modyfikując Twoje zwalnianie zasobów:
/* Zwolnienie zasobów */
LoadView(oldView);


@gx: wiem o co Ci chodzi, wiem że w gruncie rzeczy masz rację, ale na to przyjdzie czas później. :) Uparłem się i chcę zobaczyć jak daleko w tym uporze zajdę. Zwłaszcza, że w C mi się pisze szybciej, a programowego Amigowania dopiero się uczę i łatwiej mi będzie wyłapywać błędy merytoryczne.

@cholok, rafgc: bardzo dziwne stwierdzenie rzeczywiście, wynikające z mojego kształtującego się dopiero stanu wiedzy. Teraz widzę, że graphics.library to nie tylko rysowanie po okienkach na modłę łyndołsowego GDI, ale też dostęp do całego ekranu bez bawienia się w intuitionowe Screen i Window i dopiero rysowania na nim.

Jako że init okna mam za sobą, to teraz pora na sprajty. Ich chyba już tak dużo nie będzie jak myślalałem, bo większość da radę wlepić na stałe w tło. Teraz tylko rozgryźć jak się je rysuje. Zabieram się do lektury nowo odkrytej dzięki Wam dokumentacji, ale jak ktoś chce mi rzucić przykładem prostego rysowania sprajtów i operacji z maskami, to będę wdzięczny. Samo gęste mile widziane. :)

Mam tylko teraz takie pytanie z lenistwa, bo nie chce mi się z tym eksperymentować na tym etapie. Dokumentacja twierdzi, że do zrobienia viewporta i viewa pod 2.0x i wyżej trzeba wypełniać dodatkowe struktury. Ja poszedłem trybem initowania kompatybilnym z 1.3 (czyli bez tych struktur) i na moim UAE pod OS3.1 taki init działa bez problemu. O co chodzi? Można te struktury olać?
[#12] Re: pisanie GRY w C pod A500

@teh_KaiN, post #11

Czyścisz bitplany funkcją BltClear(), zapomniałem dodać (bo ja używam AllocBitMap(), ale ta funkcja dostępna dopiero od OS3.0).

Co do pytania o struktury z OS2.0: ViewExtra i ViewPortExtra: można te struktury olać, one są potrzebne w gruncie rzeczy tylko do tego, by otwierać View za pomocą innego monitora niż PAL, do tego rzekomo dochodzi kilka jakichś nowych możliwości, ale spokojnie można się bez tych struktur obejść.

Ostatnia aktualizacja: 09.06.2013 16:50:33 przez Hextreme-Attic
[#13] Re: pisanie GRY w C pod A500

@teh_KaiN, post #11

Być może to http://aminet.net/package/dev/src/ScrollingTrick cię to zainteresuje, są tam przykłady zdaje się i w asm i w C.
[#14] Re: pisanie GRY w C pod A500

@teh_KaiN, post #1

Mam pytanie, jakiego kompilatora C używasz ?
[#15] Re: pisanie GRY w C pod A500

@asman, post #14

gcc z obrazu dysku developerskiego z amiga.sourceforge.net. Pewnie nie jest to najnowsza wersja, ale o to będę się martwił gdy mój kod wyjściowy będzie za wolny lub za duży, albo tuż przed skończeniem projektu :)

Czemu ten? A bo sas/c jakiś taki dziwny był. Ale to może dlatego że go odpalałem na WB1.3 i właściwie bawiłem się nim tylko chwilę i to kwestia pierwszego wrażenia. Obecnie to wygląda tak, że mam obraz dysku z narzędziami z SF, dodatkowo dysk katalogowy z projektami, w nich edytuję kod przez notepad++ a w UAE mam po prostu odpalone CLI i sobie w nim tylko kompiluję i uruchamiam.

Żeby nie było, że się w wątku nie odzywam - ostatnio pracuję nad toolem, którym mam nadzieję zautomatyzować sobie większość konwersji grafik z kolorów SNESowych na amigowe. Szału nie ma, po prostu pozwala na szybką zamianę palety na amigowe RGB4, być może potem dorobię do tego symulator HAM/EHB. Tool oczywiście udostępnię, jak tylko go skończę na tyle, że będzie warty pokazywania :)

Tak się zastanawiam, być może uda mi się zejść do 32 różnych kolorów na linię bez drastycznego przemalowywania grafik. Pytanie, czy copper pozwoli mi przeładować całą paletę kolorów w czasie między liniami? Wyczytałem, że jedna copperowa instrukcja trwa około 4 loresowe piksele poziome, zatem jeśli trzymać się rozdzielczości 320 i założyć pole gry zgodne z oryginałem (200px szerokości), to mam 120px czasu na przeładowanie palety, co pozwoli na zmianę 120/4 = 30 kolorów. Czy to tak mniej więcej będzie wyglądać, czy można doliczyć jeszcze jakiś overscan, albo coś jeszcze odliczyć? Oczywiście zakładam tu przypadek ekstremalny, czyli konieczność przeładowania naraz całej palety między liniami, który najprawdopodobniej nigdy nie nastąpi.

Ostatnia aktualizacja: 11.06.2013 18:10:09 przez teh_KaiN
[#16] Re: pisanie GRY w C pod A500

@teh_KaiN, post #15

Co do przeładowania kolorów: najlepiej zrobić kilka ViewPortów, każdy ma oddzielną paletę. Różnica między liniami musi wynosić co najmniej jeden.

Amigowy system umożliwia także własne manipulowanie systemową copperlistą za pomocą tzw. copperlisty użytkownika. Umożliwia ona wprowadzanie dowolnych zmian do copperlisty zgodnie z systemem! Można w ten sposób przykładowo wywoływać przerwania coppera dla pełno-klatkowej animacji. System nie umożliwia tylko tzw. dynamicznych copperlist.

Jeszcze jedna sprawa: Czemu GCC? Toż to najwolniejszy kompilator jaki działa na Amidze, prócz tego tworzy duży kod wynikowy. Na A500 zdecydowanie nie polecany. Polecam inne kompilatory - np. DICE C (darmowy, pobierzesz z Aminetu) lub MaxonC++ (komercyjny). Ja właśnie kupiłem sobie MaxonC++ i jestem bardzo pozytywnie zaskoczony szybkością kompilacji i wielkością kodu wynikowego.

Na koniec: życzę Ci powodzenia w nauce pisania na Amidze i adaptacji tej SNESowej gry :)
[#17] Re: pisanie GRY w C pod A500

@Hextreme-Attic, post #16

Kompilator to póki co żaden priorytet, jak na razie wszystko się kompiluje i działa. Jak napisałem, jak będzie za wolno lub za ciężko, to się przerzucę na inny. :) Na razie nie chce mi się bawić w konfigurowanie kolejnych kompilatorów i testowanie, który sobie lepiej poradzi. Zajmę się tym na koniec lub gdy zajdzie potrzeba.

Właśnie miałem na myśli te własne copperlisty i za ich pomocą manipulowanie kolorami. Chodzi o to, że np. ogryginalne tło ma 64-90 kolorów nijak dostosowanych do EHB (HAM chyba też odpada, bo to bardzo zorientowana na pixel grafika), ale jakby się przyjrzeć, to w linii występuje właśnie ~32 kolory. Stąd pytanie - na ile własna copperlista pozwoli mi modyfikować kolory co linię przy założeniu, że ekran gry ma szerokość 200px czyli mam do dyspozycji 120px czasu + offscreen? Czy będzie to wyliczone przeze mnie ~30?
[#18] Re: pisanie GRY w C pod A500

@teh_KaiN, post #17

W zasadzie na pewno co dwie linie mógłbyś mieć inne kolory z palety 32 kolorów, ale uważam to za lekką przesadę. Myślę, że mordęgą byłoby dostosowanie tła do takiego układu graficznego. Chyba żadna gra na Amigę nie stosuje aż takich intensywnych manipulacji. Sugeruję dobrze zredukować paletę do 32 kolorów za pomocą programu graficznego (ew. dorzucić kolory EHB), albo przerzucić się na AGA, ale jak widzę masz Amigę 500 i rozumiem, że chcesz by gra na niej zadziałała.

Co do kompilatora: DICE jest prosty w konfiguracji, potrzeba parę assignów (DLIB i DINCLUDE), oraz ścieżki do kompilatora, zaś MaxonC++ to zintegrowany edytor i kompilator więc jest jeszcze prostszy w obsłudze.
[#19] Re: pisanie GRY w C pod A500

@Hextreme-Attic, post #18

Nikt nie powiedział, że ma być łatwo :)

Nie ma co spekulować zanadto, ale mam cichą nadzieję, że jednak się skończy na zmianie około 5-10 kolorów co linię - wtedy myślę, że takie coś będzie jak najbardziej wykonalne. W planie mam dodać do tego swojego toola automatyczną konwersję do bitplane'ów + wygenerowanie copperlisty dla całego ekranu, tak że każdy jej wolny zasób będzie w miarę możliwości wykorzystywany do zmiany palety. Oczywiście narzędzie będzie automatycznie dostosowywać indeksy kolorów pod dostępną w danym momencie paletę.

Pytanie jeszcze z innej beczki, trochę na wyrost bo jeszcze nawet na to zagadnienie nie patrzyłem, bo bawię się póki co tylko grafiką - z jakich bibliotek/includów korzystać, co by obsługiwać input z klawiatury/myszy/joysticka? Znowu nazwy funkcji jako element zaczepienia mile widziany :)

Na koniec screen z zaczętego przedwczoraj narzędzia: KLIK, przy okazji naprowadzenie, jaką grę staram się przeportować. :) Jeszcze pozostaje dodać trochę więcej statystyk, wywalanie kwantylu 5% kolorów lub brute redukcję do n najczęstszych w linii, ew. ręczne dopasowywanie kolorów. No i jeszcze rezerwowanie kolorów w dolnych liniach na sprajty, bo raczej tylko tam się będą znajdować.
[#20] Re: pisanie GRY w C pod A500

@teh_KaiN, post #19

Jedno mnie zastanawia. Skoro wykorzystasz cala 32 kolorowa palete na tlo, to jak zamierzasz wyswietlac bohaterow ?

ps. pamietaj takze, ze zbyt dluga lista rozkazow coppera ogranicza wydajnosc...
[#21] Re: pisanie GRY w C pod A500

@gx, post #20

To też przewidziałem i zamierzam w dolnych liniach ograniczyć paletę kolorów, myślę że trudne to nie będzie, chociaż kto wie, mogę się z tym przeliczyć.

Gra jest naprawdę prosta, audio jest praktycznie nieobecne, także myślę, że mogę większość zasobów całego sprzętu przeznaczyć na zabawę ekranem.

W sumie nie ma co tu dużo spekulować, po prostu trzeba by zakodować jeden pokój razem ze sprajtem postaci i zobaczyć ile da się z tego wycisnąć. Myślę, że jutro będę miał już cały narzędziowy rozkład bitmap na bitplane'y z ostateczną redukcją kolorów, może nawet copperlisty uda mi się ugryźć. Do końca tygodnia powinno się wyjaśnić, czy tego typu zagrywki ze sprzętem mają w ogóle rację bytu.

Pozostaje jeszcze prośba o obsługę inputa. Zarzuci ktoś jakimiś funkcjami jako punkt zaczepienia?
[#22] Re: pisanie GRY w C pod A500

@teh_KaiN, post #19

Myślę, że język C do takich zabiegów może być mało optymalny, nawet w przypadku assemblera nie było wcale łatwo i trzeba było czasem iść na kompromis. Dotyczy to głównie DMA, jak pewnie wiesz, z pamięci chip korzysta i Paula i Denise, nie pamiętam dokładnie, ale chyba powyżej 8 kolorów procesor przestaje mieć swobodny dostęp do pamięci chip, bo obciąża ją Denise, im więcej kolorów, tym większy nacisk na dokładnie przemyślaną strategię wykonywania kodu czyli słynne "liczenie cykli", a nawet uwzględnianie/wykorzystywanie faktu w jakiej pozycji znajduje się wiązka elektronów, kreśląca linię na ekranie telewizora.

Proponuję (jeśli nie masz problemu z angielskim), zapoznać się z materiałami zawartymi na stronie codetappera http://www.codetapper.com/amiga/, znajdziesz tam wywiady z ludźmi, którzy tworzyli silniki gier na Amigę (niektórzy pamiętają dość dokładnie) i techniki jakie zostały w nich zastosowane.
[wyróżniony] [#23] Re: pisanie GRY w C pod A500

@teh_KaiN, post #21

Pozostaje jeszcze prośba o obsługę inputa. Zarzuci ktoś jakimiś funkcjami jako punkt zaczepienia?

W zgodzie z Os możesz użyć input.device bądź gameport.device. A bez Os jest łatwiej bo jedziesz bezpośrednio z $dff00c ( joystick w porcie 2 ) - sprawdź sobie żródła w C gry SnakeGame (jest na aminecie ). A jeśli chodzi o klawiaturę to robisz okno (intuition) tak duże jak ekran z intuition i masz eventy z okna i tam jest typ RAWKEY albo VANILAKEY. Klawiaturę bez OS to najlepiej wykorzystać PORTS przerwanie.
[#24] Re: pisanie GRY w C pod A500

@teh_KaiN, post #19

Dzięki za odpowiedź w sprawie wyboru kompilatora. Z tego co pamiętam gcc 2.95.3 generuje bardzo dobry kod. Jak dobrze zrozumiałem Twoje posty to chodzi o to, żeby programować w C i zejść najniżej jak się da, czyli jak niektórzy mówią "walenie po rejestrach". Wszystko zależy jak dużo wiesz na temat wnętrzności Amigi 500. Jeśli niewiele to na początek trzeba przeczytać literaturę Amiga Developer Docs. A na dobry początek przydałoby się zamrozić OS i na końcu programu go odmrozić. Najpierw przypadek łatwiejszy. Załóżmy że nie będziesz używał przerwań, ale i tak je zatrzymujemy. To wtedy takie procedury DisableOs i EnableOs wyglądają tak:
#include <proto/exec.h>
#include <proto/graphics.h>

#include <hardware/custom.h>

struct GfxBase* GfxBase;
extern struct ExecBase* SysBase;

static struct View* oldView = NULL;

static UWORD oldIntena;
static UWORD oldDmacon;

static ULONG oldVertb;
static ULONG oldPorts;

void DisableOs
{
    //otwarcie graphics library
    GfxBase = (struct GfxBase*)OpenLibrary("graphics.library",0);

    //zapamiętanie starego view ekranu
    oldView = GfxBase->ActiView;

    //zresetowanie ekranu
    LoadView(NULL);
    WaitTOF();
    WaitTOF();

    //wyłączenie multitaskingu
    Forbid();
    
    //dostęp do blittera tylko dla naszego programu
    OwnBlitter();
    
    //zapamiętanie rejestrów hardware
    oldIntena = custom.intenar | 0xc000;
    oldDmacon = custom.dmaconr | 0x8000;
    
    //zatrzymanie przerwań i dma
    custom.intena = 0x7fff;
    custom.dmacon = 0x7fff;
    custom.intreq = 0x7fff;
}

void EnableOs
{
    //zatrzymanie przerwań i dma
    custom.intena = 0x7fff;
    custom.dmacon = 0x7fff;
    custom.intreq = 0x7fff;

    //odtworzenie przerwań i dma
    custom.dmacon = oldDmacon;
    custom.intena = oldIntena;

    //oddajemy blitter
    WaitBlit();
    DissownBlitter();
    
    //odtworzenie systemowej copperlisty
    custom.cop1lc = (ULONG)GfxBase->copinit;

    //załadowanie starego view
    LoadView(oldView)
    WaitTOF();
    WaitTOF();
    
    //włączamy multitasking
    Permit();

    //zamykamy bibliotekę graphics
    CloseLibrary((struct Library*)GfxBase);
}


W powyższym przykładziku mogą być błędy, bo pisałem na sucho z asemblera, używając zmęczonych własnych zwojów mózgowych jako translatora do C. Jeśli coś jest niejasne to zadawać pytania. A gdy najdzie ochota na użycie przerwań, mam na myśli chociażby VERTB i PORTS to trzeba będzie użyć wstawki asm by pobrać adres VBR dla procesorów wyższych niż 68000. Chyba, że ktoś zna jakiś magiczny sposób jak to zrobić w C to z utęsknieniem czekam na posta. Ufff, z tego to można by książkę napisać. Mając już ubity system i ekran zrestwoany właśnie do lowresu, możemy zająć się wyświetlaniem czarnego ekranu 320x256x5. Do tego celu w tym przypadku (kości OCS/ECS) najlepiej użyć zwyczajowego AllocMem z exec.library, można by użyć AllocRaster (który notabene to wywołuje AllocMem z atrybutami MEMF_CHIP i MEMF_PUBLIC bodajże) ale w naszym przypadku możemy dodatkowo poprosić o wyczyszczenie pamięci zadając MEMF_CLEAR. Następnie trzeba by zaalokować pamięć CHIP na copperlistę. Wypełnić ją, dodać czekanie na lewy klawisz myszki i gotowe. Jeśli są chętni to mogę napisać taki przykładzik w C i go zamieścić tutaj.
[#25] Re: pisanie GRY w C pod A500

@asman, post #24

Mając już ubity system i ekran zrestwoany właśnie do lowresu, możemy zająć się wyświetlaniem czarnego ekranu 320x256x5. Do tego celu w tym przypadku (kości OCS/ECS) najlepiej użyć zwyczajowego AllocMem z exec.library, można by użyć AllocRaster (który notabene to wywołuje AllocMem z atrybutami MEMF_CHIP i MEMF_PUBLIC bodajże) ale w naszym przypadku możemy dodatkowo poprosić o wyczyszczenie pamięci zadając MEMF_CLEAR.

Podałem już przykład wyżej: Do alokacji bitmapy pod 1.3 najlepiej użyć AllocRaster() oraz BltClear(). AllocRaster() jest funkcją specjalizującą się w alokacji bitmap, które da się wyświetlić.

Twoja procedura wyłączenia systemu jest OK, ale jeśli autor wątku zapragnie użyć input.device do obsługi klawiatury/myszy to będzie miał problem, bo urządzenie to korzysta z przerwań. W przypadku wyłączenia zupełnego ich przez program, input.device nie będzie działał. Pozostanie mu odczyt sprzętowy z klawiatury a to nie jest najlepszy pomysł. Recepta jest prosta: zainstalować handler na input.device o najwyższym priorytecie. Podobnie postąpić z serwerami VERTB i innych przerwań. Wtedy nasz serwer będzie wywoływany zawsze jako pierwszy. Kod przerwania powinien zerować flagę Z na końcu, ażeby następne serwery nie zostały wykonane, dzięki czemu przejęliśmy system, ale możemy z niego korzystać.

Po przejęciu VERTB na najwyższym priorytecie i wyłączeniu następnych serwerów, oczywiście do nas należy zadanie śledzenia postępu animacji, funkcja WaitTOF() przestanie działać, bo korzysta ona z serwera VERTB o niższym priorytecie. Czyni się to w ten sposób, że sygnalizuje się nasz Task z kodu przerwania, że nastąpiło wygaszanie pionowe. Zawsze jest to też szybsza metoda, aniżeli czekanie na WaitTOF() w zwykłych warunkach.

Ostatnia aktualizacja: 12.06.2013 01:15:35 przez Hextreme-Attic
[#26] Re: pisanie GRY w C pod A500

@Hextreme-Attic, post #25

Do alokacji bitmapy pod 1.3 najlepiej użyć AllocRaster() oraz BltClear(). AllocRaster() jest funkcją specjalizującą się w alokacji bitmap, które da się wyświetlić.

Nie zgadzam się z tym. Weźmy ekran 320x256x5 (szerokość x wysokość x ilośc bitplanów). W twoim przypadku alokujesz 5 razy bitmapę. I wtedy gdy chcemy skopiować blok 16x16x5 to musimy użyć 5 blitów by go skopiować. By użyć 5 blitów musimy 5 razy czekać aż blitter skończy poprzednią operację. Wygodniej i szybciej byłoby użyć tylko jednego blitu, nieprawdaż ? Według mnie najlepiej napisać własną funkcję alokującą bitmapę (MyAllocBitmap), zyskamy i prędkość i, elastyczność.

Przyjrzyjmy się teraz bliżej AllocRaster z kick 3.1.

AllocRaster:
	BSR.S	lbC0081BA
	MOVEQ	#3,D1 ;MEMF_PUBLIC|MEMF_CHIP
	MOVE.L	A6,-(SP)
	MOVEA.L	4.W,A6
	JSR	-$C6(A6) ;AllocMem z exec.library
	MOVEA.L	(SP)+,A6
	RTS


Na samym początku wywołana zostaje procedura obliczająca rozmiar rastra w bajtach i wygląda ona tak:

lbC0081BA:
	ADD.W	#15,D0
	ASR.W	#3,D0
	AND.W	#$FFFE,D0
	MULU.W	D1,D0
	RTS


I co my tu mamy: Wyrównanie szerokości rastra do słowa, obliczenie ilości bajtów szerokości i mnożenie przez wysokość. Powróćmy do AllocRaster, w D0 po powrocie z procedury obliczającej rozmiar mamy zatem ilość bajtów jaką potrzebujemy do zaalokowania. To też czynimi funkcją AllocMem. Alokujemy pamięc CHIP i koniec. Nie widzę tu nic specjalnego jeśli chodzi o alokacje bitmapy w tej funckji. Nawet nie ma wyrównania do adresu podzielnego przez 64. Co w przypadku maszyny z kościami AGA ma znaczenie.

Pozostanie mu odczyt sprzętowy z klawiatury a to nie jest najlepszy pomysł.
A to dlaczego, mógłbyś rozwinąć, dziękuje

Recepta jest prosta: zainstalować handler na input.device o najwyższym priorytecie. Podobnie postąpić z serwerami VERTB i innych przerwań.
Recepta jest skomplikowana, trzeba zainstalować handlery dla PORTS, COPER, VERTB, EXTER i to tylko po to by przejąć system (dla mnie to pisanie zbędnego kodu) i jak piszesz z możliwością korzystania z niego. Z drugiej strony piszesz że WaitTOF wtedy przestaje działać, to znaczy że jednak nie można korzystać z systemu, czy coś przeoczyłem ?

Czyni się to w ten sposób, że sygnalizuje się nasz Task z kodu przerwania, że nastąpiło wygaszanie pionowe
Bardzo mnie to ciekawi, w jaki sposób zasygnalizujesz nasz Task (w szczególności gdy wszystkie przerwania są przejęte powyższym sposobem), mógłbyś to bardziej szczegółowo opisać bądź podać przykład, dziękuje.

Ostatnia aktualizacja: 12.06.2013 10:02:01 przez asman

Ostatnia aktualizacja: 12.06.2013 10:05:37 przez asman
[#27] Re: pisanie GRY w C pod A500

@asman, post #26

Weźmy ekran 320x256x5 (szerokość x wysokość x ilośc bitplanów). W twoim przypadku alokujesz 5 razy bitmapę. I wtedy gdy chcemy skopiować blok 16x16x5 to musimy użyć 5 blitów by go skopiować. By użyć 5 blitów musimy 5 razy czekać aż blitter skończy poprzednią operację. Wygodniej i szybciej byłoby użyć tylko jednego blitu, nieprawdaż ? Według mnie najlepiej napisać własną funkcję alokującą bitmapę (MyAllocBitmap), zyskamy i prędkość i, elastyczność.

Alokacja 5 rastrów w większości przypadków jest lepsza, ponieważ może nie być wystarczająco dużo ciągłej wolnej pamięci CHIP. Oczywiście zgadzam się, że 1 duży blit jest lepszy niż 5 małych, to jest walor alokacji bitmapy typu interleaved.

A to dlaczego, mógłbyś rozwinąć, dziękuje

Ponieważ autor wątku dopiero zaczyna zabawę z programowaniem na Amidze chciałbym, żeby korzystał z systemowych rozwiązań, czyli input.device. Ale oczywiście decyzja będzie należeć do niego.

Recepta jest skomplikowana, trzeba zainstalować handlery dla PORTS, COPER, VERTB, EXTER i to tylko po to by przejąć system (dla mnie to pisanie zbędnego kodu) i jak piszesz z możliwością korzystania z niego. Z drugiej strony piszesz że WaitTOF wtedy przestaje działać, to znaczy że jednak nie można korzystać z systemu, czy coś przeoczyłem ?

WaitTOF() przestaje działać tylko wtedy, gdy nasz serwer VERTB kasuje znacznik Z na końcu kodu obsługi przerwania. Jeśli ustawi ten znacznik to wywołane zostaną pozostałe serwery o niższych priorytetach. To jest przypadek gdy chciałbym zastąpić WaitTOF(), który czeka aż zostaną wywołane wszystkie serwery VERTB przez procedurę, która sygnalizuje nasz program natychmiast gdy zostanie osiągnięty szczyt ramki.

Bardzo mnie to ciekawi, w jaki sposób zasygnalizujesz nasz Task (w szczególności gdy wszystkie przerwania są przejęte powyższym sposobem), mógłbyś to bardziej szczegółowo opisać bądź podać przykład, dziękuje.

Żeby skorzystać z dobrodziejstw sygnałów i portów rzecz jasna multitasking musi być włączony. Ale zauważ, że przejęcie całego wejścia (założenie handlera input.device o najwyższym priorytecie i wracanie ze skasowanym znacznikiem Z) odciąża system z ogromnego ładunku, który to przerwanie domyślnie generuje. W praktyce równa się to wyłączeniu systemu.

Na koniec przypomnę, że istnieje rozkaz Disable() z exec.library, który w zgodzie z systemem wyłącza przerwania (Enable() je na powrót włącza). Dokumentacja jednak jest bezlitosna: takie instrukcje jak Forbid() i Disable() powinny być używane tylko naprawdę kiedy jest taka konieczność i najlepiej na bardzo krótko.

Ostatnia aktualizacja: 12.06.2013 10:46:52 przez Hextreme-Attic
[#28] Re: pisanie GRY w C pod A500

@teh_KaiN, post #21

EDYT: miało być jako odpowiedź na post Asmana

Dzięki za snejka, mam z niego inputa joya i póki co sprawuje się dobrze.

Początek zabaw z UserCopperList i już mam serię pytań :)

  • Wyczytałem, że jest takie cudo jak CINIT i ono w argumencie przyjmuje liczbę instrukcji w copperliście. Z tym nie mam problemu, ale pojawia się pytanie - o jaką liczbę chodzi? Trzeba uwzględniać do niej CINIT i CEND?
  • Wyczytałem też, że np. CMOVE tak naprawdę wywołuje CMove i CBump, czyli co, traktowane to jest jako dwie instrukcje?
  • Na tej samej stronie w przykładach znalazłem ciekawy kod:
    CINIT(uCopList, NUMCOLORS);
    
                    scanlines_per_color = screen->Height/NUMCOLORS;
    
                    /*  Load in each color.  */
                    for (i=0; i<NUMCOLORS; i++)
                            {
                            CWAIT(uCopList, (i*scanlines_per_color), 0);
                            CMOVE(uCopList, custom.color[0], spectrum[i]);
                            }
    Wynika z tego, że CWAIT i CMOVE liczone są jako jedna instrukcja. O co chodzi? Jeżeli zlepek CWAIT i CMOVE jest liczony jako jedno, to ile instrukcji na liście zajmie zlepek CWAIT CMOVE CMOVE CMOVE?
  • Pojawia mi się jeszcze jeden problem, mianowicie nielegalność czekania na pozycję x większą niż 222. Przydałaby mi się pozycja 280. Ktoś ma jakiś pomysł, co z tym zrobić?


Teraz jeszcze coś niezwiązanego z copperem. Gra ma być sterowalna za pomocą kursora ekranowego, ale ten ma być sterowalny za pomocą klawiatury/myszki/joysticka, najlepiej przyjmowanie inputa ze wszystkich trzech rzeczy naraz. Dodatkowo, kursor ma być przyciągany do konkretnych elementów ekranu:
  • załóżmy że na pozycji 100,100 jest prostokąt zainteresowania 32x32.
  • Gra sobie odnotowuje gdzieś w pamięci faktyczne współrzędne kursora.
  • I teraz, jeśli faktyczne współrzędne kursora znajdują się w zakresie (100-131),(100-131), to kursor jest wyświetlany cały czas na środku punktu zainteresowania, czyli na 115,115.
  • Ruch myszy jest wtedy nadal rejestrowany i zapisywany jako faktyczne współrzędne kursora
  • Gdy współrzędne faktyczne wyjadą poza obszar zainteresowania (załóżmy 110,132) to kursor ma płynnie przejść ze 115,115 na tamte współrzędne.
  • Dodatkowo kursor ma mieć animację przyciągnięcia i odwrotną odciągnięcia.


Brzmi strasznie, ale w oryginale fajnie to działa. Pytanie - jak to zrobić? Czy wykorzystać kursor systemu, przemalowywać go wg potrzeb, odnotowywać gdzieś oddzielnie jego faktyczne współrzędne na bazie dx,dy i w razie potrzeby blokować jego położenie na punktach zainteresowania? Czy też należałoby schować kursor i traktować go jako źródło współrzędnych faktycznych, a blokowalny i animowany kursor zrobić z oddzielnego sprite'a? Osobiście poszedłbym drugą drogą, bo wydaje się prostsza, tyle że i tak musiałbym trzymać w pamięci faktyczne współrzędne i modyfikować je o dx,dy joya/myszki/klawiatury

Ostatnia aktualizacja: 13.06.2013 11:25:19 przez teh_KaiN
[wyróżniony] [#29] Re: pisanie GRY w C pod A500

@teh_KaiN, post #28

Instrukcja to jedna instrukcja coppera. Trzeba policzyć każdy cmove, cwait oprócz cend. Powyższy przykład akurat ignoruje argument n, ponieważ wcześniej sam alokuje ucoplist. Gdyby był =0 to ten przykład bylby błędny. Co do pozycji to chodzi o pozycje hardwarowe coppera, a nie ekranowe, więc 222 nie jest dużym ograniczeniem, zwłaszcza, że max jest 226 (OCS). Inaczej, rozdzielczość pozioma coppera jest dużo mniejsza niż obrazu.
[#30] Re: pisanie GRY w C pod A500

@cholok, post #29

Czyli te co się liczą to CMOVE i CWAIT, bo one są faktycznymi rozkazami Coppera, a CMove, CBump i CWait, które się składają na makra CMOVE i CWAIT to pomocnicze makra, których w ogóle się nie powinno brać pod uwagę?

Poszedłem tropem Twojej podpowiedzi co do rozdzielczości coppera i znalazłem trochę informacji o tym, jednak przez to mam jeszcze więcej wątpliwości. :)

Wyczytałem, że copper ma rozdzielczość 226x312 na ekranie PAL a na NTSC 226,262. Za to nie znalazłem nigdzie żadnej informacji o tym, jak przełożyć pozycję ekranową na pozycję coppera. Wiem, że nie będzie 1:1, ale chciałbym wiedzieć orientacyjne jak to wypada. Tam gdzieś jest uwzględniony offscreen? Jeśli tak, to ile go trzeba odliczyć? Czy bezpiecznie jest bawić się copperem na offscreenie z lewej przed zerowym pikselem? Jakaś informacja mi przed oczami przeleciała, że wtedy są cykle przeznaczone na inne rzeczy i bawienie się wtedy może zablokować korzystanie z paru sprajtów.

Docelowo chodzi mi o to żeby poczekać na pixel ekranowy ~280 i wtedy pozmieniać parę kolorów. Chciałbym też użyć pikseli ekranowych x <= 40, bo dopiero wtedy mi się zaczyna grafika.

Ostatnia aktualizacja: 13.06.2013 20:04:08 przez teh_KaiN
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem