Systeemi versio 5 ================= Tämä on systeemi demojen tekemiseen helposti C-kieltä käyttäen. Demoista ei sinänsä ole mitään hyötyä, mutta niitä on kiva tehdä ja samalla voi oppia vaikka ohjelmoimaan. Hienot demot on kivoja katsoa ja hyvällä tuurilla niillä voi voittaa muutaman markan jostain kilpailusta. Tämä systeemi ei ole kovin monimutkainen, eikä siinä ole mielestäni mitään turhia ominaisuuksia. Systeemi ei välttämättä ole kovin tehokas, mutta sitä voi parannella mielensä mukaan. Kuten tavallista en voi antaa mitää takuuta siitä, että systeemi toimii. Toisaalta sinulla on oikeus tehdä mukana tulevilla lähdekoodeilla mitä haluat, eli hylkään kaikki tekijänoikeudet niihin. Tälläisiä ohjelmia kutsutaan yleisesti julkisohjelmiksi, eli englanniksi Public Domain -ohjelmiksi. Hauskoja hetkiä demojen näpertelyn merkeissä. Systeemin taustaa ================= C-kieli on varsin näppärä ohjelmointikieli, koska se tarjoaa mahdollisuuden korkeantason ohjelmointiin kuten myös hyvin laiteläheiseen ohjelmointiin. Yleensä Amigalla kuten varmaan PC:lläkin aikanaan on demot tehty assemblerilla siitä yksinkertaisesta syystä, että siten luodut ohjelmat ovat nopeita. Ongelmana assemblerilla ohjelmoidessa on se, että suurempien kokonaisuuksia rakentaminen vaati kohtuuttoman suuren assembler koodin kirjoittamista. Lisäksi kun tekee pienen ohjelmoiti virheen se saattaa kaataa vaikka koko koneen, tämä ongelma vaivaa ainakin Amigan kivikautista käyttöjärjestelmää. Toisaalta onnistuu systemin kaataminen myös C:lläkin, mutta sen estämikseksi kannattaa koodiin laittaa pieniä tarkistuksia. Ne eivät merkittävästi hidasta ohjelman suoritusta, vaan pikemminkin säästävät ohjelmoijan hermoja. Tästä syystä C:llä kirjoitettu demo on paljon houkuttelevampi vaihtoehto. Koodi on selkeempää ja helpommin siirrettävissä muillekin prosessoreille. C++:lla voisi varmaan myös systeemin luoda, mutta omien kokemusten mukaan C++ kääntäjät ovat huomattavasti hitaampia kuin C-kääntäjät. Useasti kuulee väitteen, että C-koodi on hitaampaa kuin assemblerilla kirjoittettu koodi, näin varmasti saataa ollakin, mutta useimminten kääntäjät tekevät yhtä hyvää assembler-koodia kuin käsinkirjoittetuna. Ja toisaalta C:n kirjoittaminen on huomattavasti nopeampaa kuin assembler-koodin vääntäminen. Lisäksi jos nopeutta vaaditaan, kannattaa optimoida ohjelmasta vain kaikkein kriittisimmät kohdat assemblerilla, näin päästään hyvää kompromissiin: ohjelmien kehitysaika on lyhyempi ja ohjelma suorituskyky on samaa luokkaa kuin vastaavan assembler-ohjelman. Oman ohjelman rakentaminen ========================== Ensimmäinen ohjelma ******************* Yksinkertaisin ohjelma, joka ei varsinaisesti tee mitään, mutta käyttää kumminkin systeemiä on tässä: -- /* oma1.c -- kokeillaan systeemiä */ #include "sys.h" void user_autoshutdown(void); int main(void) { init_system(); shutdown_system(RETURN_OK); return 0; } void user_auto_shutdown(void) { } /* Ohjelma käännetään seuraavasti : SAS/C -- sc oma1.c sys.c link to oma1 gcc -- gcc oma1.c sys.c -o oma1 vbcc -- vc oma1.c sys.c -o oma1 -lmieee */ -- Tälläisen rakenne pitää vähintään löytyä kaikista ohjelmasta, jotka toteutetaan tällä systeemillä. Aluksi systeemi alustetaan init_system() kutsulla, jonka jälkeen se on käytettävissä. Lopuksi systeemi suljetaan shutdown_system() kutsulla, jonka mukana annetaan koodi siitä onnistuiko ohjelman suoritus vai ei. Funktiota user_auto_shutdown() kutsuu itse systeemi, kun ohjelma loppuu tai jos jokin menee pieleen. Näin annetaan käyttäjälle mahdollisuus vapauttaa kaikki varaamansa palvelut, kuten sulkea avatut näytöt yms. Jäljempänä on selitetty yksityiskohtaisesti mitä mikin funktio tekee. Toinen ohjelma ************** Tällä kertaa avaamme näytön, ja suljemme sen heti perään. -- /* oma2.c -- avataan ja suljetaan näyttö */ #include "sys.h" struct display naytto1; void user_autoshutdown(void); int main(void) { init_system(); open_display(&naytto1, 320, 200, 8); delay(3.0); shutdown_system(RETURN_OK); return 0; } void user_auto_shutdown(void) { close_display(&naytto1); } -- Ohjelma näyttää likimain samanlaiselta kuin ensimmäinenkin ohjelma, mutta pieniä lisäyksiä löytyy. Aluksi määritellään globaali rakenne nimeltä naytto1. Käsittääkseni hyvää ohjelmointi tyyliin kuuluu välttää mahdollisimman paljon mitään globaaleja määrityksiä, tässä sellaista on kumminkin käytetty. Peruste on ohjelman yksinkertaistuminen, koska naytto1-rakenne on sellainen, että sitä tarvitaan eri funktioiden välillä. Seuraavaa uusi funktio on open_display(), jolla itse näyttö avataan. Sille annetaan parametreiksi naytto1-rakenteen osoite, toivotun näytön leveys ja korkeus pikseleinä sekä kuinka monta bittiä pikseliä kohden väri-informaatiota tarvitaan. Eli 2 potensiin 8 on 256, eli näyttöllä voi käyttää 256:ta eri väriä. Sitten kutsutaan delay()-funktiota, joka tässä tapauksessa aiheuttaa kolmen sekunnin viiveen. Näin kerkiämme huomata, että näyttö on todella auki. Sitten kutsumme shutdown_system()-funktiota, joka puolestaan kutsuu user_auto_shutdown()-funktiota, jossa näyttö suljetaan. Syy miksi näyttöä ei suljettu main()-funktiossa on seuraava: Olettaan vaikkapa että delay()-funktion suorittaminen ei onnistu ja systeemi joudutaan sulkemaan ennenaikaisesti. Tällöin kaikki ne komennot, jotka seuraavat delay()-funkiota jäävät suorittamatta. Jos meidän näytönsulku kutsumme olisi ollut siellä, olisi näytömme jäänyt auki. Mutta nyt kun näytönsulku funktiomme sijaitsee user_auto_shutdown() -funktiossa sitä kutsutaan aina, jolloin näyttö ei voi jäädä auki. Varmuuden lisäämiseksi close_display()-funktio vielä tarkistaan, että näyttö on auki, ennenkuin sitä yritetään sulkea. Kolmas ohjelma ************** Piirellää näytölle viivoista teksti: "MOI". -- /* oma3.c -- piiretään näyttölle */ #include "sys.h" #include "2dlib.c" struct display naytto1; UBYTE *puskuri1 = NULL; void user_autoshutdown(void); int main(void) { struct wcPoints M[5]; struct wcPoints O[5]; init_system(); open_display(&naytto1, 320, 200, 8); select_display(&naytto1); puskuri1 = allocvec( (naytto1.display_x * naytto1.display_y) ); select_buffer(puskuri1); M[0].x = 0; /* 1. (0,0) 3. (100,0) */ M[0].y = 100; /* |\ /| */ M[1].x = 0; /* | \ / | */ M[1].y = 0; /* | \ / | */ M[2].x = 50; /* | \ / | */ M[2].y = 50; /* | \ / | */ M[3].x = 100; /* | \/ | */ M[3].y = 0; /* | 2. (50,50) | */ M[4].x = 100; /* | | */ M[4].y = 100; /* 0. (0,100) 4. (100,100) */ O[0].x = 110; /* 0. (110,0) 1. (210,0) */ O[0].y = 0; /* -------------- */ O[1].x = 210; /* | 4. (110,0) | */ O[1].y = 0; /* | | */ O[2].x = 210; /* | | */ O[2].y = 100; /* | | */ O[3].x = 110; /* | | */ O[3].y = 100; /* | | */ O[4].x = 110; /* -------------- */ O[4].y = 0; /* 3. (110,100) 2. (210, 100) */ set_color(1); polyline(5, M); set_color(2); polyline(5, O); set_color(3); line(220, 0, 220, 100); /* line(x1, y1, x2, y2) */ display_buffer(); delay(3.0); shutdown_system(RETURN_OK); return 0; } void user_auto_shutdown(void) { if (puskuri1 != NULL) freevec(puskuri1); close_display(&naytto1); } /* Ohjelma käännetään seuraavasti: Aluksi kaikilla: phxass noexe quiet c2p1x1_8_c5_bm.s sitten: SAS/C -- sc oma3.c sys.c c2p1x1_8_c5_bm.o link to oma3 gcc -- gcc oma3.c sys.c c2p1x1_8_c5_bm.o -o oma3 -- Tämä ohjelma onkin jo vähän monimutkaisempi. Käydään läpi vain mitä uutta koodiin on tullut. Aluksi lisätään koodin uusi palanen "2dlib.c" eli 2-ulotteisen grafiikan funktiota. Ne lisätään mukaan lähdekoodiin ihan C-kielisinä versioina, eikä vain funktioiden protyyppeinnä, kuten sys.h tiedossa tehdään, jotta funktioda voidaan kutsua nopeammin itse pääohjelmasta. Nopeushan on hyvin tärkeätä kun luodaan suurempia grafiikka kokonaisuuksia, ja varsinkin silloin kun grafiikkaa luodaan reaaliaikaisesti eli grafiikka piirretään sitä mukaan kuin se näyttölle laitetaan. Seuraavaksi määritellään puskuri1-taulukko, johon voidaan sitten itse kuvio piirtää. Taulukossa olevat tavut vastaavat näytöllä olevaa pistettä ja sen väriarvoa. Taulukossa pisteet ovat lineaarisesti eli tässä tapauksessa taulukon 320 ensimmäistä tavua muodostaa ensimmäisen rivin ruudulla olevasta grafiikasta ja seuraavat 320 tavua seuraavan rivin ja niin edelleen. Itse ohjelmassa varataan puskurille muistia dynaamisesti sen mukaan kuinka suuri näyttö on. Tämä tapahtuu allocvec()-muistinvarausfunktion avulla. Puskurin voisi luoda myös ihan tavallisena taulukkona, mutta jos puskureita on paljon käytössä kuluu muistiakin paljon. Mutta tässä tapauksessa oli lähinnä esimerkkinä näyttää kuinka allocvec()-funktio toimii. Tarkoituksenahan oli kirjoittaa näytölle teksti MOI, tehdään se piirtämällä kirjaimet viivoilla. Joten seuraavaksi määritelläänkiin miten M- ja O-kirjaimet piirretään viivoina. I kirjaihan on pelkkä yksi viiva, joten se on helppo piirää pelkkänä pystysuorana viivana. Seuraavaksi piirretään kirjaimet valitulla värillä, ja lopuksi laitetaan koko puskuriin piirretty komeus näytölle display_buffer() kutsulla. On huomattava, että ennen display_buffer()-funktion kutsumista on koodissa edellä valittu käytettävä näyttö ja puskuri select_diplay()- ja select_buffer()-funktioiden avulla. Mikäänhän ei estä käyttämästä useampia näyttöjä ja puskureita yhtä aikaa kuten ohjelmassa neljä tehdään. Neljäs esimerkki ohjelma ************************ Tiedostossa showpic-r124.c on hieman suurempi esimerkkiohjelma, joka käyttää edellä kuvattuja funktioita. Ohjelma on hyvin samanlainen kun edellisetkin ohjelmat, mutta siinä on käytetään myös tiedostoja, joista haetaan esimerkiksi kuva näytölle ja kuvan tarvitsema paletti. Näytölle haettava kuva on hakemistossa oleva 16-9.gif, joka muutettu edelläkuvattuun puskuri muotoon, näin kuvan käsittely on nopeampaa vaikka se viekin vähän enemmän tilaa. Esimerkki ohjelma piirtää viivoja näytölle, kuten edelläkin ja lopuksi tekee yksinkertaisen, mutta nätin kuviohan näytölle, joka liikkuu syklisesti. Funktioiden kuvaukset ===================== Pääsysteemin funktioiden prototyypit ovat tiedostossa "sys.h". Lisäksi tiedosta löytyy systeemin kannalta tärkeän display-rakenteen määritelmä. Tiedostossa on myös määritelty näppärä tapa välittää funktio kutsun mukana tieto siitä mistä tiedostosta ja miltä riviltä jotakin funktiota on kutsuttu. Näitä tietoja käyttää hyödyksi print_fault-funktio virheilmoituksia luodessaan. sys.h ***** allocvec -------- Tällä funtiolla varataan muistia. Parametriksi annetaan tarvittavien tavujen määrä. Funktio palauttaa osoitteen muistialueen alkuun. Muisti on käytettävissä osoittimesta eteenpäin. Mikäli muistia ei saada, funktio kertoo kertoo lähdekooditiedoston ja rivin, josta funktiota kutsuttiin. Tämä jälkeen systeemi ajetaan hillitysti alas. Funktiolla freevec vapautetaan varattu muisti. Kaikki varattu muisti pitää vapauttaa. Ohjelma tulee rakentaa siten, että user_auto_shutdown funktiota voidaan kutsua milloinvain siten, että kaikki muisti vapautetaan. close_display ------------- Tällä funtiolla suljetaan open_display-funktiolla avattu näyttö. close_file ---------- Tällä funktiolla suljetaan open_file-funktiolla avattu tiedosto. delay ----- Funktiolla luodaa viive. Viiveen suuruus mitataan sekunneissa. file_size --------- Kertoo parametriksi annetun tiedoston koon. Tätä voidaan käyttää hyödyksi kun haluataan varata muistia saman verran kuin tiedoton koko on. freevec ------- Vapautaa muistia. Parametriksi annetaan allocvec-funktiolta saatu osoitin. Tulostaa virheilmoituksen, jos osoittin oli tyhjä, muttei sulje systeemiä. error_output ------------ Virheen varatulostus funktio. Käytetään silloin kun print_fault funktio ei toimi tai kun sitä ei voida käyttää. init_system ----------- Alustaa systeemin. Tätä funktiota täytyy kutsua ensimmäisenä ohjelmassa. load_file --------- Hakee tiedoston muistiin ja palauttaa osoittimen muistiin, jonne tiedosto on laitettu. Muistialuetta voi käyttää vapaasti, se ei vaikuta mitenkään levyllä olevaan tiedostoon. Muisti vapautetaan tavalliseen tapaan freevec-funktiolla. Tiedostoa ei tarvitse sulkea tms. ei tarvitse tehdä. open_file --------- Tällä funtiolla avataan tiedosto. Palauttaa osoittimen tiedostorakenteeseen. (Katso lisää dos.library/Open() tai käytä load_file funktiota.) open_display ------------ Avaa näytön, johon voidaan sitten piirellä kaikkea kivaa "2dlib.h" tiedossa määritellyllä funktiolla. print_fault ----------- Näyttää virheilmoituksen, jos joku meni pieleen. Näyttää myös tiedoston ja rivin mistä kutsuttiin funktiota, joka aiheutti virhetoiminnon. set_palette_from_file --------------------- Hakee paletin 8-bittiselle näytölle tiedostosta. Paletin formaatti on sama kuin graphics/LoadRGB32-funktio käyttää. Formaati on: yksi sana kertoo värien määrän, jos värejä ei ole 256 kappaletta jää loppupään värit ennalleen; seuraava sana kertoo ensimmäisen asetettavan värinpaikan numeron, tavallisesti nolla; sitten kolme pitkää sanaa jotka kertovat punaisen, vihreän ja sinisen määrän, näitä kolmen pitkänsanan ryhmiä on yhtä paljon kuin asetettavia värejä; lopuksi nolla. shutdown_system --------------- Sulkee systeemin. Mukana annetaan koodi, onnistuiku ohjelman suoritus oikein. (RETURN_OK tai RETURN_WARN tai RETURN_ERROR tai RETURN_FAIL) user_auto_shutdown ------------------ Funktion toteutus jätetään käyttäjälle. Tarkoituksena on sulkea systeemi tässä funktiossa. Funktio tulee suunnitella siten, että sitä voidaan kutsua milloin vain, niin että kaikki muisti vapautetaan, näytöt suljetaan jne. Eli systeemi ajetaan hillitysti alas tämän funktion avulla. ********************************************************************** Tässä olivat käyttäjän käytetävissä olevat funktiot "sys.c" muodostamasta perussysteemistä. Seuraavaksi tarkastellaan "2dlib.h" tiedostossa määriteltyjä näytön käsittelyyn käytettäviä funktiota. 2dlib.h ******* display_buffer -------------- Siirtää käytössä olevan näyttöpuskurin sisältämän grafiikan näytölle. Ennen funktion käyttö tulee kutsua select_buffer ja select_display funktioita. fill_screen ----------- Täyttää koko ruudun annetulla paletin värillä. Funktiota select_display tulee kutsua ennen tämän funktion kutsumista. line ---- Piirtää viivan ruudulle. Funktioita select_buffer ja set_color tulee olla kutsuttu ennen tämän funktion kutsumista. polyline -------- Piirtää viivoja jotka on yhdistetty toisiinta. Kutsuu line funktiota. select_buffer ------------- Valitsee puskurin jonne grafiikka piirretään. Puskurin saa varattua helposti allocvec-funktiolla. Puskurin koko tavuissa on helppo laskea: se on 8-bittisellä ruudulla ruudun leveys ja korkeus pikselinä kerrotuna toisillaan. select_display -------------- Valitsee fyysisen näytön jolle grafiikka tulostetaan. Parametriksi annetaan sama rakenne kuin open_display funktiolle. set_color -------- Valitsee käytöön paletin värin. set_pixel -------- Asettaa näytölle yhden pisteen. Funktiota select_buffer täytyy kutsua ennen tämän funktion käyttöä. -- LOPPU --