Työskentely API:en ja SDK:ien kanssa



Samankaltaiset tiedostot
Kuvaruudun striimaus tai nauhoitus. Open Broadcaster Software V.20. Tero Keso, Atso Arat & Niina Järvinen (muokattu )

Skype for Business ohjelman asennus- ja käyttöohje Sisällys

Microsoft Outlook Web Access. Pikaohje sähköpostin peruskäyttöön

Sähköposti ja uutisryhmät

Kuvaruudun striimaus tai nauhoitus. Open Broadcaster Software V.20. Tero Keso, Atso Arat, Niina Järvinen & Valtteri Virtanen (muokattu 20.2.

Pedacode Pikaopas. Java-kehitysympäristön pystyttäminen

Osoitin ja viittaus C++:ssa

ELOKUVATYÖKALUN KÄYTTÖ ANIMAATION LEIKKAAMISESSA. Kun aloitetaan uusi projekti, on se ensimmäisenä syytä tallentaa.

erasmartcardkortinlukijaohjelmiston

Maastotietokannan torrent-jakelun shapefile-tiedostojen purkaminen zip-arkistoista Windows-komentojonoilla

Hiirisanomiin vastaaminen

Zeon PDF Driver Trial

Ohjelmoinnin peruskurssi Y1

Mainosankkuri.fi-palvelun käyttöohjeita

Sisältö. 22. Taulukot. Yleistä. Yleistä

Android. Sähköpostin määritys. Tässä oppaassa kuvataan uuden sähköpostitilin käyttöönotto Android Ice Cream Sandwichissä.

Jypelin käyttöohjeet» Ruutukentän luominen

Windows Phone. Sähköpostin määritys. Tässä oppaassa kuvataan uuden sähköpostitilin käyttöönotto Windows Phone 8 -puhelimessa.

Sisältö. 2. Taulukot. Yleistä. Yleistä

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

Käyttöohje. Ticket Inspector. Versio 1.0. Sportum Oy

LoCCaM Riistakamerasovellus. Dimag Ky dimag.fi

Transkribuksen pikaopas

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

CUDA. Moniydinohjelmointi Mikko Honkonen

Peilaus pisteen ja suoran suhteen Pythonin Turtle moduulilla

JOVISION IP-KAMERA Käyttöohje

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Teams-ohjelman asennus- ja käyttöohje vertaisohjaajille

Viva-16. Käyttöohje Veikko Nokkala Suomen Videovalvonta.com

Windows 10 käyttöjärjestelmän helppokäyttötoiminnot ja asetukset

SSH Secure Shell & SSH File Transfer

Ilmoitus saapuneesta turvasähköpostiviestistä

KUVAN TUOMINEN, MUOKKAAMINEN, KOON MUUTTAMINEN JA TALLENTAMINEN PAINTISSA

Kieliversiointityökalu Java-ohjelmistoon. Ohje

Skype for Business ohjelman asennus- ja käyttöohje Sisällys

OpenOffice.org Impress 3.1.0

Ohjelmoinnin perusteet Y Python

Aimo-ohjauspaneelin käyttöohje Sisällys

Ohjeet e kirjan ostajalle

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

Valintanauhan komennot Valintanauhan kussakin välilehdessä on ryhmiä ja kussakin ryhmässä on toisiinsa liittyviä komentoja.

Ohjelmoinnin perusteet Y Python

BaseMidlet. KÄYTTÖOHJE v. 1.00

Sähköpostitilin käyttöönotto

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

Skype for Business ohje

Lupa opetuskäyttöön pyydettävä. Näppäimistö. Kohdistimen ohjausnäppäimistö. Funktionäppäimistö. Kirjoitusnäppäimistö

Moodle 2.2 pikaohje. 1. Kirjautuminen ja omat kurssit (Työtilat) 1. Mene internet-selaimella osoitteeseen

Taulukot. Jukka Harju, Jukka Juslin

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

E-kirjan lainaaminen ja lukeminen

Lumon tuotekirjaston asennusohje. Asennus- ja rekisteröintiohje

OFFICE 365 PIKAOHJE

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

Tietueet. Tietueiden määrittely

Sonera Yrityssähköposti. Outlook 2013 lataus ja asennus

Apple iphone 4 puhelimen käyttöönotto:

Muuttujien määrittely

MPCC-työkalua voidaan käyttää yhden laitteen valvontaan ja yhden tai useamman laitteen konfigurointiin (Modbus broadcast, osoite 0).

Ennen varmenteen asennusta varmista seuraavat asiat:

Epooqin perusominaisuudet

ipad maahanmuuttajien ohjauksessa Laitteen käyttöönotto Kotomaatti 2016

WCONDES OHJEET ITÄRASTEILLE (tehty Condes versiolle 8)

Machine Control Studio - Kuinka päästä alkuun. Ohjelmointiympäristö Unidrive M ja MCi2x0 laitteille

Visma Nova. Visma Nova ASP käyttö ja ohjeet

Toinen harjoitustyö. ASCII-grafiikkaa 2017

Kahoot! Kirjautuminen palveluun. Sinikka Leivonen

Office 365 palvelujen käyttöohje Sisällys

SÄHKÖPOSTIPALVELUIDEN KÄYTTÖÖNOTTO LOUNEA OY

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

Muuttujien roolit Kiintoarvo cin >> r;

CEM DT-3353 Pihtimittari

Audio- ja videotiedostoja sisältävän PowerPoint-esityksen pakkaaminen

KServer Etäohjaus Spesifikaatio asiakaspuolen toteutuksille

Ohjeistus yhdistysten internetpäivittäjille

Rakenteiset tietotyypit Moniulotteiset taulukot

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Videokuvan siirtäminen kamerasta tietokoneelle Windows Movie Maker -ohjelman avulla

Esimerkkinä - ilmainen blogi-julkaisujärjestelmä. WordPress:stä on myös palvelimelle asennettava versio (WordPress.

Webmailin käyttöohje. Ohjeen sisältö. Sähköpostin peruskäyttö. Lomavastaajan asettaminen sähköpostiin. Sähköpostin salasanan vaihtaminen

Salasanojen hallinta. Salasanojen hallintaopas RESTAURANT ENTERPRISE SOLUTION

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

Webforum. Version 15.1 uudet ominaisuudet. Päivitetty:

Pedanet oppilaan ohje Aleksanteri Kenan koulu Eija Arvola

Autentikoivan lähtevän postin palvelimen asetukset

FOTONETTI BOOK CREATOR

Luento 5. Timo Savola. 28. huhtikuuta 2006

Edico Lite ja S Käyttöohje istunnon pitäjälle ja kutsutulle

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

Gree Smart -sovelluksen (WiFi) asennus- ja käyttöohje: Hansol-sarjan ilmalämpöpumput WiFi-ominaisuuksilla

Maxivision Go käyttöliittymän ohje

Office ohjelmiston asennusohje

sivu 1 Verkkopäätteen muuttaminen Anvian uuteen tekniikkaan Ohje käy seuraaviin verkkopäätteisiin

BlueJ ohjelman pitäisi löytyä Development valikon alta mikroluokkien koneista. Muissa koneissa BlueJ voi löytyä esim. omana ikonina työpöydältä

Sen jälkeen Microsoft Office ja sen alta löytyy ohjelmat. Ensin käynnistä-valikosta kaikki ohjelmat

MEM-O-MATIC järjestelmä

Transkriptio:

OSA VII 679 LUKU 28 28 LUKU Työskentely API:en ja SDK:ien kanssa Opi, kuinka käytetään Visual C++-ohjelmoijille tarkoitettuja eri API-rajapintoja ja SDK-kehitysympäristöjä Tosi nopeiden ääni- ja grafiikkasovellusten luominen DirectX:llä Sähköpostin lähettäminen ja vastaanottaminen MAPI-arkkitehtuuria käyttäen Media Control rajapinnan käyttö multimediaäänen ja videon esittämiseen

680 Mistä API- ja SDKkehityspaketit saa? Kaikkia API- ja SDK-paketteja ei toimiteta Visual C++:n mukana, mutta useimmat voidaan ladata Microsoftin sivustosta (msdn.microsoft.com) ilmaiseksi. Vaikka käyttämäsi API tai SDK olisikin toimitettu Visual C++:n mukana, kannattaa tarkistaa Webistä uusin versio. Kehittyneet tekniikat Mitä ovat API:t ja SDK:t APIt (Application programming interface) ovat funktiokokoelmia, jotka on yleensä tallennettu dynaamisiin linkkikirjastoihin (.dll) tai staattisiin kirjastoihin (.lib). Näiden avulla voidaan toteuttaa helpommin erityyppisten sovellusten toimintoja, kuten grafiikan, äänen, tietokannan käsittelyn tai tiedonsiirron toimittamalla koodikerroksen sovelluksesi ja laitteiston väliin. Eri API-kirjastoja on lukuisia ja ne helpottavat sovellusten rakentamista sekä yhtenäistävät alan toiminnot standardiksi funktiokutsujoukoksi. COMin ja OLEn kehitys on saanut aikaan sen, että useimmat näistä API-kirjastoista on toteutettu COM-objekteina, mikä helpottaa merkittävästi eri.dll-versioista johtuneita versionhallintaongelmia. SDK:t (Software development kit) ovat API-kirjastoja, joiden mukana toimitetaan dokumentointi sekä esimerkkiohjelmia. Nämä auttavat eri tyyppisten sovellusten kehittämistä, kuten Game SDK pelien ja OLE DB SDK OLE-pohjaisten tietokantasovellusten. Yleensä API-funktiot eivät sisälly projektisi oletuksena linkitettäviin kirjastoihin ja joudut sitä varten linkittämään projektiisi erityiseen kirjastoon. Voit yleensä lisätä kaikkien tarvitsemiesi API-funktioiden prototyypit ja makromäärittelyt sovellustiedostoosi lisäämällä APIkohtaisen.h header-tiedoston käännökseen #include-lauseella. KATSO MYÖS OLEn ja COMin perusteet luvusta 25. Nopean äänen ja näytön toteuttaminen DirectX:llä DirectX APIt luotiin ratkaisemaan näyttö- ja äänilaitteisiin liittyvät suorituskykyongelmat. Vaikka Windows tarjoaakin kehittyneen vakiografiikan ja äänitoimintojen tuen, nämä eivät olleet riittävän nopeita tai joustavia nopeiden toimintapelien ja esitysohjelmistojen kirjoittajille. Pitkän aikaa ainoa ratkaisu oli kirjoittaa ohjelmisto DOSsovelluksena ja menettää näin Windowsin laitteistoriippumattomuus, konfigurointitiedot ja muut palvelut. Microsoft on täyttänyt tämän puutteen joukolla laiteriippumattomia API-rajapintoja, jotka tarjoavat nopeamman ja suoremman pääsyn

OSA VII LUKU 28 681 näyttö-, ääni- ja syöttölaitteisiin. Nämä APIt ovat DirectSound, DirectDraw, Direct3D, DirectPlay, DirectMusic, DirectAnimation, DirectInput ja DirectSetup; yhdessä ne muodostavat Game SDK:n (peli-sdk), joka on ollut hyvin suosittu pelintekijöiden ja esitysgrafiikkateollisuuden joukossa. Kaikki nämä APIt on toteutettu komponenttiobjektimallia (COM) käyttäen ja siksi funktiokutsut on ryhmitelty ne toteuttavan COMobjektin tiettyyn COM-liittymään. Windows 95 ei asenna näiden APIen vaatimia dll-kirjastoja, mutta ne ovat vapaasti jaeltavissa ja toimitetaan yleensä niitä käyttävien pelien mukana. Nämä voidaan myös ladata Microsoftin webbipalvelusta osoitteesta www.microsoft.com/directx. KATSO MYÖS OLEn ja COMin perusteet luvusta 25. DirectSoundin käyttö DirectSound APIn avulla pääset käsiksi suoraan äänikorttisi laitteistoon tehdäksesi ääntä aaltomuotopuskurin (waveform buffer) sisällön perusteella. Puskuri tarkoittaa vain suoraa muistialuetta, jota äänikortin laitteisto lukee ja muuttaa arvot äänitasoiksi. Yksinkertaisin koodaustekniikka on antaa jokaisen puskurin tavun edustaa 256 äänenvoimakkuustasoa, mikä vastaa suoraan kaiuttimen kartion asemaa äänikorttiisi kytketyssä kaiuttimessa. Kun puskurin arvot asetetaan vastaamaan haluttua aaltomuotoa, voi määrätä suoraan äänen korkeuden. Kun muutat tämän aaltomuodon amplitudia puskurin eri kohdissa, saat eri efektejä aaltomuotoa moduloimalla. Tätä aaltomuotopuskuria kutsutaan DirectSoundin ensisijaiseksi puskuriksi. Ensisijaista puskuria ei yleensä suoraan luoda, vaan tavallisesti luodaan toissijaisia puskureita ja näitä puskureita toistettaessa ne sekoittuvat automaattisesti ja tuottavat ensisijaisen puskurin. Useaa toissijaista puskuria ja sekoittamista käyttäen voidaan helposti saada aikaan hyvinkin mutkikkaita äänitehosteita. Kuva 28.1 esittää kahden hyvin erilaisen toissijaisen puskurin sekoittavan esimerkkiohjelman tulostusta. Ylempi puskuri on puhdas vaimeneva siniaalto ja keskimmäinen esittää amplitudiltaan (voimakkuudeltaan) kasvavaa satunnaiskohinaa. Alimmainen aaltomuoto on ensisijaisen puskurin sisältö eli kahden edellisen esittämisen aikaansaama sekoitus. Tuloksena Nopean grafiikan ongelmat Graafisten animaatioiden kirjoittamisen keskeisin ongelma on puhdas suorituskyky. Ihminen näkee peräkkäin esitetyt kuvat liikkeenä, kun kuvia näytetään noin 24 kertaa sekunnissa. 256- värin 800x600 näytöllä on 480 000 kuvapistettä ja jos jokaisen kuvapisteen arvo vaihdetaan, tarvitaan sekunnissa 11 520 000 operaatiota. Kuvapisteen asettaminen vie noin 12 kellojaksoa, joten pelkkä näytön päivittäminen vaatisi 138 240 000 kellojaksoa. 500 MHz prosessorilla tuo olisi neljännes koko CPU ajasta, 266 MHz prosessorilla jo puolet. Silti toinen puoli ajasta menisi vielä mutkikkaaseen ja raskaaseen kolmiulotteiseen laskentaan, pintakuvioinnin tekemiseen, bittikarttojen skaalaamiseen ja käyttäjän toimiin.

682 DirectSoundCreate()- funktion käyttö Jos käytät DirectSoundCreate()- funktiota, joudut linkittämään projektiisi myös dsound.libkirjaston Project Settingsvalintaikkunan Link-välilehden Object/Library Modules -ruutuun. CoCreateInstance()-tapaa käyttämällä tätä kirjastoa ei tarvita, mutta luokan ja liittymän tunnukset tarvitaan (CLSID ja IID). Kehittyneet tekniikat saadaan aikaan puhdas ääni, joka nopeasti muuttuu esitettäessä kohinaksi. Voit sekoittaa haluamiasi ääniä toisten kanssa, esimerkiksi sakara-aaltoa, kolmioaaltoa tai muuta puskurin sisältöä (myös äänitettyä) tuottaaksesi haluamasi äänen. Ensimmäinen tehtävä DirectSound APIa käytettäessä on IDirectSound-liittymän luominen joko kutsumalla suoraan CoCreateInstance()-funktiota (kts. luku 25) tai käyttämällä pikavalintafunktiota DirectSoundCreate(). DirectSoundCreate() käyttää kolmea parametriä: ensimmäinen on osoitin GUID-tunnukseen, joka määrittää käytettävän äänilaitteen. Nämä äänilaitteen GUID-tunnukset saadaan selville asettamalla DirectSoundEnumerate()-funktiolla callback-funktio. Vaihtoehtoisesti parametrinä voidaan antaa NULL, jolloin käytetään oletusäänilaitetta. Toinen parametri on osoitin DirectSound-liittymäobjektin osoittimeen, jonka avulla asetetaan sovelluksesi osoitin uuteen objektiin. Kolmas parametri asetetaan yleensä arvoon NULL, ellet joudu käyttämään COM-aggregaatio tekniikkaa. Jos tämä funktio onnistuu, palautettu osoitin osoittaa IDirectSoundliittymään, joka voidaan vapauttaa muiden COM-liittymien tapaan liittymän Release()-funktiolla. Kun IDirectSound-liittymä on saatu, sen yhteiskäyttötaso (cooperative level) tulee säätää välittömästi. Useilla DirectX API kirjastoilla käytetään tällaisia tasoja, jotka määrittävät, kuinka niiden käyttämää laitteistoa pitäisi jakaa eri sovellusten kesken. Voit asettaa tämän tason IDirectSound-liittymän SetCooperativeLevel()- funktiolla syöttämällä sille oman sovelluksesi Windows-kahvan. Joudut myös syöttämään lipputietona halutun yhteiskäyttötason. Tavallisesti käytettävä DSSCL_NORMAL-arvo sallii täyden yhteiskäytön muiden sovellusten kanssa. Tämän jälkeen voit luoda toissijaiset äänipuskurit IDirectSoundliittymän CreateSoundBuffer()-funktiolla. Funktio käyttää kolmea parametriä. Ensimmäinen näistä on DSBUFFERDESC-tietorakenne, joka kertoo luotavaksi halutun puskurin tyypin. Toinen parametri on uutta puskuria varten oleva sovelluksesi IDirectSoundBuffer -liittymäosoitin. Kolmas parametri asetetaan yleensä arvoon NULL, ellet joudu käyttämään COM-aggregaatio tekniikkaa.

DSBUFFERDESC-tietorakenne määritellään typedef struct _DSBUFFERDESC{ DWORD dwsize; DWORD dwflags; DWORD dwbufferbytes; DWORD dwreserved; LPWAVEFORMATEX lpwfxformat; } DSBUFFERDESC, *LP DSBUFFERDESC; DSBUFFERDESC-tietorakenteen jäsenet edustavat seuraavaa: dwsize on tietorakenteen koko (joka saadaan sizeof()- operaattorilla). dwflags-lippuina voidaan määritellä useita ohjausasetuksia, kuten stereoääni ja äänenvoimakkuus. Hyvät oletusarvot saadaan lipulla DSBCAPS_CTRLDEFAULT. dwbufferbytes kertoo, kuinka monta tavua uuteen puskuriin tulee mahtua. Pitkille ääninäytteille ja mutkikkaille äänille tarvitaan suurempia puskureita; pienempi puskuri käy lyhyisiin tai toistuviin ääniin. Puskureita voidaan toistaa silmukassa, jolloin puskurin sisältö käytetään ääntä tuotettaessa uudelleen ja uudelleen ja näin saadaan aikaan pitkiä toistuvia ääniä. lpwfxformat osoittaa WAVEFORMATEX-tietorakenteeseen, jossa on tiedot äänikortille siitä, kuinka äänitehoste esitetään. OSA VII LUKU 28 683 WAVEFORMATEX-tietorakenteessa on tietoa muun muassa puskurin esitysnopeudesta sekä siitä, kuinka monta puskurin tavua tarvitaan yhden ääniarvon esittämiseen. Siinä on myös kerrottu laitteistosta riippuva äänen esittämistekniikka, mutta useimmat äänikortit tukevat aiemmin esiteltyä yksinkertaista WAVE_FORMAT_PCM-tekniikkaa. Kun toissijainen puskuri on käytettävissä, voit asettaa sen arvot joko lataamalla ne.wav-tiedostosta tai määrittämällä ne ohjelmassa. Saatiinpa puskurin tiedot kummalla tavalla tahansa, puskurin käsittelyä ohjaa IDirectSoundBuffer-liittymän Lock()-funktio, joka palauttaa puskurin osoitteen ja koon. Tämän funktion kutsumisen jälkeen voit kirjoittaa puskuriin haluttua aaltomuotoa vastaavat arvot ja kutsua lopuksi puskurin vapauttamiseksi Unlock()-funktiota. Kun puskurin arvot on asetettu, voit esittää sen IDirectSoundBuffer-liittymän Play()-funktiolla. Play()-funktio tarvitsee kolme parametriä, joista kaksi ensimmästä ovat varattuja ja ne Puskurin lukitseminen ja avaaminen Äänipuskuria ei kannata lukita pitkäksi aikaa, muuten lukittua puskurin osaa tarvitseva toistettava ääni aletaan esittää kohinana. Joillakin äänikorteilla on puskuri, jota ei pääse suoraan käyttämään prosessorin osoiteavaruudesta. Tällaisessa tapauksessa Lock()- ja Unlock()- funktiot myös siirtävät tiedon kortilta keskusmuistiin, jossa ohjelmasi voi sitä päivittää ja siirtää sitten takaisin toistettavaksi kortille.

684 Kehittyneet tekniikat tulee asettaa nollaksi. Kolmas parametri voi olla DSBPLAY_LOOPING puskurin sisällön toistamiseksi tai nolla, jolloin puskurin sisältö esitetään ainoastaan kerran. Esittäminen voidaan lopettaa kutsumalla Stop()-funktiota. Listauksessa 28.1 esitetään, kuinka DirectSoundia voidaan käyttää yksinkertaisen, mutta vaikuttavan näppäimistöltä käytettävän syntetisaattoriäänen tuottamiseen yksinkertaisen SDI-sovelluksen näkymäluokasta. Ohjelma luo ja näyttää kahden toissijaisen äänipuskurin sisällön punaisena ja vihreänä viivana, jotka asetetaan vaimenevaksi siniaalloksi ja voimakkuudeltaan kasvavaksi kohinaksi (kuva 28.1). KUVA 28.1 SoundView-esimerkki esittää kaksi puskuria ja tuloksena saadun niistä sekoitetun aaltomuodon. Tämän jälkeen sovellus esittää molemmat puskurit yhtä aikaa käyttäjän painaessa näppäintä, jolloin saadaan aikaan kohinan katoava siniaalto ensisijaisesta puskurista (yhdistetty aaltomuoto on alin sininen viiva). Siniaallon tuottama äänen korkeus määräytyy painetun näppäimen ASCII-koodin perusteella, joten aakkosten loppupään merkit saavat aikaan korkeampia ääniä. Luonnollisesti tämä esimerkki vaatii äänikortin. LISTAUS 28.1 LST28_1.CPP Yksinkertainen näppäimistöltä soitettava, kahta äänipuskuria sekoittava syntetisaattoriohjelma 1 CSoundView::CSoundView() 2 { 3 m_pdsobject = NULL;

OSA VII LUKU 28 685 4 m_pdsbuffer = NULL; 5 m_pdsmix = NULL; 6 } 7 CSoundView::~CSoundView() 8 { 9 if (m_pdsmix) m_pdsmix->release(); 1 10 if (m_pdsbuffer) m_pdsbuffer->release(); 11 if (m_pdsobject) m_pdsobject->release(); 12 } 1 DirectSound COM-objektit tulee vapauttaa hallitusti Release()-funktiolla. 13 void CSoundView::PlayFreq(double dfreq) 14 { 15 if (!m_pdsobject) 16 { 17 // ** Create the Direct Sound Object 18 if(ds_ok == DirectSoundCreate(NULL, &m_pdsobject, NULL)) 19 { 20 // ** Set the Co-Operation level 21 m_pdsobject->setcooperativelevel(m_hwnd, DSSCL_NORMAL); 22 // ** Clear the direct sound buffer 23 memset(&m_dsbufferdesc,0,sizeof(dsbufferdesc)); 24 // ** Setup a secondary buffer 25 m_dsbufferdesc.dwsize = sizeof(dsbufferdesc); 26 m_dsbufferdesc.dwflags = DSBCAPS_CTRLDEFAULT; 27 m_dsbufferdesc.dwbufferbytes = 4096; 28 // ** Set a wave format for 22.0Khz, 1 byte DtoA 29 static WAVEFORMATEX swave = { 30 WAVE_FORMAT_PCM,1,22000,22000,1,8,0 }; 31 m_dsbufferdesc.lpwfxformat = &swave; 32 33 // ** Create the First Secondary buffer 34 m_pdsobject->createsoundbuffer( &m_dsbufferdesc,&m_pdsbuffer,null); 35 // ** Create the Second Secondary buffer 36 m_pdsobject->createsoundbuffer( &m_dsbufferdesc,&m_pdsmix,null); 37 } 38 } 39 // ** if the DirectSound object is valid... 40 if (m_pdsobject) 41 { 42 // ** Declare buffer pointers 43 LPBYTE pbuffer1,pbuffer2; 44 LPBYTE penv1,penv2; 45 DWORD dwsize1,dwsize2; 46 // ** Erase the background 47 CClientDC dcclient(this);

686 Kehittyneet tekniikat 48 CRect rcclient; 49 GetClientRect(&rcClient); 50 int yoff = (rcclient.height()-24)/3; 51 dcclient.fillsolidrect(rcclient,rgb(255,255,255)); 2 Lock()-funktio lukitsee muistin ja palauttaa ohjelmasi käyttämien puskureiden osoitteet. 52 // Lock the sound buffer 53 m_pdsbuffer->lock(0,m_dsbufferdesc.dwbufferbytes, &pbuffer1,&dwsize1,&pbuffer2, &dwsize2,0); 2 54 m_pdsmix->lock(0,m_dsbufferdesc.dwbufferbytes, &penv1,&dwsize1,&penv2,&dwsize2,0); 55 // ** Set the two buffers 56 double drange = 128.0 / (double)dwsize1; 57 double dxrange = (double)rcclient.width() / (double)dwsize1; 58 for(int i=0;i<(int)dwsize1;i++) 59 { 60 double damplitude = 1.0 + drange * (double)i; 61 BYTE b1 = (BYTE)(127 + (128.0 - damplitude) 62 * sin((double)i / (0.147 * dfreq))); 63 BYTE b2 = (BYTE)(rand()%(int)dAmplitude)>>1; 64 *(pbuffer1+i) = b1; 65 *(penv1+i) = b2; 66 BYTE b3 = b1 + b2; 3 Aaltomuodon arvot myös piirretään, jotta näkisit puskurin sisällön. 4 Puskurit asetetaan avaamisen jälkeen esittämään sisältönsä. 67 // ** Draw the waveform 3 68 int x = (int)(dxrange * (double)i); 69 dcclient.setpixelv(x,(b1>>1),rgb(255,0,0)); 70 dcclient.setpixelv(x,yoff+64 + b2>>1), RGB(0,255,0)); 71 dcclient.setpixelv(x,yoff*2 + (b3>>1), RGB(0,0,255)); 72 } 73 // ** Unlock the buffers and play the sound 4 74 m_pdsbuffer->unlock(pbuffer1, dwsize1,pbuffer2,dwsize2); 75 m_pdsmix->unlock(penv1,dwsize1,penv2,dwsize2); 76 m_pdsbuffer->play(0,0,0); 77 m_pdsmix->play(0,0,0); 78 } 79 } 80 void CSoundView::OnKeyDown(UINT nchar, UINT nrepcnt, UINT nflags) 81 { 82 CView::OnKeyDown(nChar, nrepcnt, nflags); 83 // ** Play the note with a freqency of the key value 84 if (nrepcnt==1) PlayFreq((double)nChar); 85 }

Listauksessa 28.1 esitetty koodi tulee sijoittaa tavallisen AppWizardin tekemän SDI-sovellusrungon (nimeltään Sound) näkymäluokkaan. Koska tässä on lisätty koodia näkymäluokkaan (SoundView.cpptiedostoon), joudut myös lisäämään uusia jäsenmuuttujia varten seuraavat rivit luokan määrittelyn header-tiedostoon (SoundView.h): IDirectSound* m_pdsobject; IDirectSoundBuffer* m_pdsbuffer; IDirectSoundBuffer* m_pdsmix; DSBUFFERDESC m_dsbufferdesc; void PlayFreq(double dfreq); Nämä rivit määrittelevät DirectSound-liittymää varten tarvittavan liittymäosoitinjäsenmuuttujan, kaksi äänipuskuria ja puskurinkuvaustietorakenteen. Myös äänitehosteen toteutuksessa tarvittava PlayFreq()-funktio määritellään. Lisää ClassWizardilla OnKeyDown()-käsittelijä WM_KEYDOWN-sanoman käsittelemistä varten. ClassWizard huolehtii myös vaadittujen headertiedostojen tekemisestä sekä sanomakartan alkion lisäämisestä. Jotta kääntäjä saisi vaadittavat tiedot liittymäosoittimesta, aaltomuototietorakenteesta toteutuksessa ja käytetystä sinifunktiosta, joudut lisäämään seuraavat #include-lauseet näkymäluokan määrittelytiedoston alkuun (soundview.h): OSA VII LUKU 28 687 #include mmsystem.h #include DSOUND.H #include math.h Listauksessa 28.1 riveillä 1 6 esitetty näkymäluokan muodostin alustaa osoittimet DirectSound-objektiin m_pdsobject ja kaksi osoitinta puskureihin, m_pdsbuffer ja m_pdsmix, arvoon NULL. Vastaava tuhoajafunktio riveillä 7 12 tuhoaa nämä COM-objektit kutsumalla niiden liittymän Release()-funktiota ja vapauttaen niiden viittausluvut (reference count). Pääfunktion PlayFreq() riveillä 15 38 alustetaan funktion ensimmäisellä kutsukerralla vaadittu DirectSound-objekti ja puskurit. Alustus täytyy suorittaa tässä vaiheessa, koska rivillä 21 kutsuttava SetCooperativeLevel()-funktio tarvitsee voimassa olevan ikkunakahvan, m_hwnd, joka ei ole vielä olemassa muodostinta suoritettaessa. Jos DirectSound-objektin alustaminen onnistuu rivillä 18, luodaan kaksi toissijaista puskuria kutsumalla funktiota CreateSoundBuffer() vaadittujen puskurin tietojen Yhteiskäyttötasot (cooperative levels) DirectSound-objektilla on käytettävissä neljä eri yhteiskäyttötasoa. DSSCL_EXCLUSIVE antaa sovelluksellesi (jos se ehtii ensin) äänikortit käyttöön kokonaan ja muut sovellukset eivät saa ääntä esitettyä. DSSCL_NORMAL-tasolla äänikorttia käytetään moniajon mukaan joustavasti sovellusten välillä. DSSCL_PRIORITY antaa sovelluksellesi etusijan äänikortin käyttöön muihin sovelluksiin nähden. DSSCL_WRITEPRIMARY on korkein etuoikeustaso, jolloin sovelluksesi pääsee käsiksi ensisijaiseen äänipuskuriin ja voi estää (muiden sovellusten) toissijaisten puskureiden esittämisen.

688 Äänipuskureiden sekoittaminen Kahta yhtäaikaa esitettävää toissijaista puskuria sekoittamalla aaltomuodolla saadaan moduloitua toista. Tällä tekniikalla voidaan esimerkiksi korkeataajuista ensimmäistä puskuria moduloida matalataajuisella toisella puskurilla, mikä tekee esitettävästä äänestä värisevän tai karkeamman. Kehittyneet tekniikat m_dsbufferdesc-jäseneen ja WAVEFORMATEX-tyyppiseen swavetietorakenteeseen asettamisen jälkeen. PlayFreq()-funktion jälkimmäinen puolisko asettaa äänipuskurit, piirtää aaltomuodot ja esittää äänen dfreq-parametrin mukaan. Riveillä 47-51 alustetaan ikkunapiirtopinta, tyhjennetään näkymä ja alustetaan koko näkymän työalue. Riveillä 53-54 suoritetaan kahdelle toissijaiselle puskurille Lock()-toiminto, joka palauttaa osoittimet niihin. Riveillä 58-72 on toteutettu silmukka, jossa näihin kahteen puskuriin generoidaan arvot ja ne myös piirretään näkymään. Rivillä 61 lasketaan siniaallon arvo b1, joka perustuu taajuuteen, silmukkamuuttujan i edustamaan paikkaan puskurissa ja pienenevään damplitude-voimakkuusarvoon. Tämä arvo tallennetaan kahdesta puskurista ensimmäiseen rivillä 64 ja sen perusteella piirretään rivillä 69 kolmas aalto punaisena SetPixelV()-funktiolla. Toisen puskurin kohinasignaalin arvo, b2, saadaan puolittamalla satunnaislukufunktiolla rand() saadun arvon ja äänisignaalin voimakkuuden jakojäännös (rivi 63). Tämä arvo kirjoitetaan puskuriin rivillä 65 ja näytetään vihreänä kuvapisteenä rivillä 70. Kolmas arvo, b3, joka vastaa esitettäessä ensisijaisen puskurin arvoa, lasketaan rivillä 66 yksinkertaisesti sekoittamalla (laskemalla yhteen) b1 + b2. Tämä arvo näytetään sekoitettuna aaltomuotona sinisellä kuvapisteellä rivillä 71. Riveillä 74-75 suoritetaan kahdelle puskurille Unlock()-toiminto niiden sisällön esittämiseksi Play()-funktiolla riveillä 76 ja 77. Kun ensimmäistä Play()-funktiota kutsutaan, muodostetaan ensisijainen puskuri automaattisesti tämän toissijaisen puskurin vaatimusten mukaisesti ja siitä kirjoitetaan äänisignaali suoraan toistavalle laitteistolle. Seuraava Play()-funktiokutsu saa aikaan toisen toissijaisen puskurin sisällön sekoittamisen ensisijaiseen puskuriin, jolloin haluttu äänitehoste saadaan aikaan. Lopuksi voidaan vielä lisätä OnKeyDown()-käsittelijä New Windows Message/Event valintaikkunan avulla näppäinpainallusten käsittelemiseksi ja PlayFreq()-funktion kutsumiseksi. Kunkin näppäimen ASCII-koodi vastaa esitettyä taajuutta, jolla saadaan aikaan vaikutelma yksinkertaisesta, näppäimistöltä ohjattavasta syntetisaattorista. Ennen tämän sovelluksen kääntämistä joudut ottamaan linkitykseen mukaan dsound.lib-kirjaston Project Settings valintaikkunan Link välilehdeltä lisäämällä sen Object/Library Modules-riville. Saat tämän valintaikkunan esiin näppäilemällä Alt+F7 tai valitsemalla Projectvalikosta Settings.

Kun käännät ja ajat sovelluksesi, saat aaltomuodot esiin käyttämällä näppäimistön eri kirjaimia. Kuulet samalla myös ASCII-koodia vastaavan äänen tehosteineen. OSA VII LUKU 28 689 KATSO MYÖS OLEn ja COMin perusteet luvusta 25. DirectDraw:n käyttö DirectDraw API:lla voidaan kirjoittaa hyvin nopeita, välkkymättömiä grafiikkasovelluksia. Toimintapeleille ja animaatio-ohjelmille DirectDraw:n synkronoitu kaksoispuskurointitekniikka on välttämätöntä. DirectDraw:lla saadaan käyttöön koko Windowsin näyttö ja eri näyttötilat (myös vähemmän tunnettu ModeX, jota Doom2-pelin väitetään käyttäneen). Ohjelmat piirtävät näytettävän kuvan piilossa olevalle taustanäytölle, joka kuvan valmistuttua vaihdetaan esillä olevan tilalle. Tämä vaihto voidaan tahdistaa tehtäväksi näytön elektronisuihkun palatessa viimeisestä pisteestä alkuun, jolloin animaatio saadaan välkkymättömäksi. Voit myös jättää Windows-näytön ennalleen ja käyttää tavallisen ikkunan sisällä nopeampaa piirtotekniikkaa. DirectDraw:lla saadaan piirto- ja lohkon kopiointitoiminnot nopeammiksi kahta ohjelmistokerrosta, HAL (Hardware Abstraction Layer, laitteiston piilotus) ja HEL (Hardware Emulation Layer, laitteiston mallinnus), käyttäen. DirectDraw-pinnan piirto- ja kopiointitoiminnot käyttävät näistä HALia. Näin saadaan aikaan laiteriippumaton toiminta, jolloin samalla ohjelmakoodilla voidaan käyttää erilaisia näyttökortteja. Mikäli näyttökortti osaa suoraan jonkin piirtotoiminnon, tämä laitteistokiihdytys nopeuttaa piirtoa huomattavasti; ellei osaa, HEL-kerros mallintaa kortin toimintoja ohjelmallisesti ja tällöinkään näyttökortin ominaisuudet eivät rajoita piirtotoiminnon käyttöä. DirectDraw APIssa on COM-liittymien kautta käytettävissä ainoastaan neljä COM-objektia, jotka on esitetty taulukossa 28.1. Taulukosta muutamien liittymien nimen lopussa oleva numero 2 kertoo, että kyseessä on uudempi versio COM-liittymästä, jonka alkuperäinen versio on vielä käytettävissä vanhemmille sovelluksille. Taulukosta ilmenee myös, että tärkein objekti on DirectDrawSurface. DirectDraw-pääobjekti luo näitä pintoja (surface), joita voidaan rajata DirectDrawClipper-objekteilla ja maalata DirectDrawPaletteobjektin väreillä. ModeX ModeX on dokumentoimaton VGA-näyttötila. Useimmat pelintekijät joutuivat valitsemaan nopeussyistä monivärisen heikkoresoluutiotilan animaatioiden esittämiseen. Tuloksena paras VGA-tila oli 0x13 (heksadesimaalisena), jolla saadaan erottelutarkkuudeksi 320x200 kuvapistettä. Erikoinen ModeX antaa kuitenkin pystysuunnassa hieman paremman arvon, 320x240.

690 Kehittyneet tekniikat TAULUKKO 28.1 DirectDraw-objektit ja niiden toiminnot DirectDraw-objekti COM-liittymä Toiminto DirectDraw IDirectDraw2 Käsittelee näyttötilat ja laitteiston ominaisuudet ja luo muut objektit. DirectDrawSurface IDirectDrawSurface2 Käsittelee ensisijaiset ja toissijaiset bittikartat, kaksoispuskuroinnin ja piirto- ja kopiointifunktiot. Tätä pintaa voidaan rajata DirectDrawClipperobjekteilla ja maalata DirectDrawPaletteobjektin väreillä. DirectDrawClipper IDirectDrawClipper Käsittelee pintojen rajaamisen tiedot. DirectDrawPalette IDirectDrawPalette Käsittelee väripaletin alkiot ja pinnalla käytettävien värien tiedot. COM-aggregaatio Aggregaatio on COM-tekniikka, jolla komponentteja sisältävä toinen komponentti voi hyödyntää sisältämänsä komponentin toimintoja. Ulompi komponentti tarjoaa asiakasohjelmilleen liittymän, joka on itse asiassa sen sisältämän komponentin liittymä. Asiakkaan pyytäessä osoitinta tuohon littymään ulompi komponentti palauttaa suoran osoittimen sisemmän komponentin liittymään. Tämän kolmannen parametrin tarjoamalla DirectDraw-objekti antaa muiden komponenttien upottaa sen sisälleen. DirectX-kirjaston vanhemmissa versioissa tätä ominaisuutta ei välttämättä tueta, jolloin DirectDrawCreate()- palauttaa virhekoodin. Saat luotua DirectDraw pääobjektin ddraw.lib-kirjaston funktiolla DirectDrawCreate() tai kutsumalla suoraan CoCreateInstance()- funktiota. DirectDrawCreate()-funktio tarvitsee kolme parametriä. Ensimmäinen on käytettävän näyttöajurin GUID-tunnus. Näyttöajurin tunnuksena annetaan yleensä NULL, jolloin valitaan käytettäväksi sillä hetkellä aktiivisena oleva ajuri. Muiden ajurien tunnukset löytyvät vastaavalla enumerate-funktiolla. Toinen parametri on osoitin uuden objektin IDirectDraw-liittymäosoittimeen. Jos käytät tätä metodia, joudut hankkimaan tämän jälkeen osoittimen uudempaan IDirectDraw2- liittymään COMin QueryInterface()-funktiolla. Kolmas parametri asetetaan tavallisesti arvoon NULL. Muita arvoja käytetään ainoastaan COM aggregaatio tekniikkaa käytettäessä. COM-objekti on mahdollisesti helpompi luoda CoCreateInstance()- funktiolla, koska tällöin päästään suoraan käsiksi IDirectDraw2- liittymään eikä linkittämistä ddraw.lib-kirjastoon tarvita. Funktiota käytetään välittämällä sille luokkatunnuksena CLSID_DirectDraw ja

OSA VII LUKU 28 691 liittymäviittauksena IID_IDirectDraw2; nämä tunnukset löytyvät header-tiedostosta DrawDlg.h. Tämän jälkeen joudut kutsumaan Initialize()-funktiota näyttöajurin määrittävällä GUID-tunnuksella (tavallisesti NULL). Kun käytössä on DirectDraw-objekti, sen yhteiskäyttötaso joudutaan asettamaan IDirectDraw::SetCooperativeLevel()-funktiolla. Tälle funktiolle syötetään ensimmäisenä parametrinä omistajasovelluksen tunnuksena toimiva ikkunakahva ja toisena lippumääreet. Voit käyttää DirectDraw-objektia yhdessä muiden sovellusten kanssa tavallista Windows-näyttöä käytettäessä (lippu DDSCL_NORMAL), mutta halutessasi koko näytön käyttöön, on yhdistettävä liput DDSCL_EXCLUSIVE ja DDSCL_FULLSCREEN. Tahdistettua kaksoispuskurointia varten on koko näyttö otettava käyttöön. Pintoja piirtämistä ja kopioimista varten luodaan DirectDraw-objektin CreateSurface()-funktiolla välittämällä sille DDSURFACEDESCtietorakenne pinnan määreenä. Tässä tietorakenteessa määritellään monenlaisia pintoja. Tavallisesti luodaan yksi ensisijainen pinta DDSCAPS_PRIMARYSURFACE-lipulla ja mahdollisesti useita taustapintoja kopiointia ja kaksoispuskurointia varten. Kaksoispuskuroinnin sivun vaihtamista varten taustapuskurit voidaan luoda ja linkittää samalla CreateSurface()-kutsulla kuin ensisijainenkin puskuri. Tällöin puskureiden lukumäärä annetaan tietorakenteen dwbackbuffercountjäsenessä ja määritellään DDSD_BACKBUFFERCOUNT-lippu. Voit myös luoda useita clipper-objekteja rajausluetteloiden luomiseksi. Tämä ovat hyödyllisiä käytettäessä DirectDraw:lle tavallista Windowsin näyttöä, koska isäikkunaa rajaamalla estetään oman ikkunan alueen ulkopuolelle piirtäminen. Näitä objekteja voidaan luoda DirectDraw-objektista CreateClipper()-funktiolla, minkä jälkeen ne valitaan pinnalla käytettäviksi pinnan SetClipper()- funktiolla. Värien kierrättämistä tukevia värivalikoimia (paletteja) voidaan luoda DirectDraw-pääobjektista CreatePalette()-funktiolla. Värien arvot voidaan alustaa valikoimaan joukolla COLORREF-arvoja, minkä jälkeen ne voidaan valita pinnalle pinnan SetPalette()-funktiolla. DirectDraw-pinnalle voidaan piirtää tavallisilla GDI-funktioilla. Aluksi pinta lukitaan omaan käyttöön ja vastaava piirtopinta haetaan GetDC()-funktiolla. Piirtämisen jäljeen tämä vapautetaan ReleaseDC()-funktiolla. Käytettävissä on myös joukko nopeita bit Animointi värejä kierrättämällä Värejä kierrättämällä saadaan liikkuvaa kuvaa ilman raskasta laskentaa. Animointi ilman ylimääräistä piirtämistä on aina kannattavaa. Ottamalla käyttöön värivalikoimasta muutamia värejä värien kierrätykseen saadaan jollekin näytön alueelle toistuvaa liikettä ilman uudelleenpiirtämistä. Jos esimerkiksi tarvitaan samaan pisteeseen neljä kooltaan kasvavaa ympyrää, voitaisiin kolme väriä määrittää mustaksi ja yksi valkoiseksi. Valkoinen väri voitaisiin sitten muuttaa värivalikoimassa toiseen näistä neljästä paikasta, jolloin jokaisella mustalla piirretty ympyrä pääsisi vuorollaan esiin.

692 Bit blit- ja GDI-funktioiden käyttö Ole tarkkana, ettet kutsu bit blit - funktiota (lohkon kopiointi), kun käytät GetDC():llä saatua piirtopintaa. GetDC() lukitsee piirtopinnan ja bit blit -toiminto ei onnistu - joudut kutsumaan ReleaseDC()-funktiota ennen muiden bit blit -funktioiden käyttöä. 1 CoInitialize alustaa COMkirjastot. Kehittyneet tekniikat blitting kopiointifunktioita (kuten Blt), joilla pintoja voidaan kopioida ja värittää erilaisin tekniikoin, esimerkiksi kokoa muuttaen (stretch) tai pintakuviointia käyttäen (texture mapping). Ensisijainen puskuri voidaan vaihtaa taustapuskurin kanssa ensisijaisen pinnan Flip()-funktiolla, joka osaa odottaa seuraavaa juovanpaluujaksoa. Voit joko syöttää sille lipun päivityksen odottamiseksi tai käyttää DirectDraw-objektin WaitForVerticalBlank()-funktiota. Hyödyllisiä näyttöön liittyviä funktioita ovat myös GetMonitorFrequency() sekä GetScanLine(). Listauksessa 28.2 esitetään DirectDraw-esimerkkisovellus, joka esittää Windowsin näytön haltuun ottamisen jälkeen nopean, kaksoispuskurointia käyttävän, pyörivää kierrettä esittävän animaation. Sovellukseen ei jouduta linkittämään ddraw.lib-kirjastoa, koska siinä luodaan DirectDraw-objekti CoCreateInstance()-funktiolla ja palautetaan Windowsin näyttö ennalleen Esc-näppäintä painettaessa. Tämä esimerkki pohjautuu valintaikkunasovellukseen Draw, jonka OnInitDialog()-funktiossa alustetaan näyttö ja kuva piirretään taustapuskuriin Widowsin ajastimenkäsittelijässä OnTimer(). Kun tämä nopea ja mutkikas piirros on valmis, edusta- ja taustapuskurit vaihdetaan keskenään, jotta uusi kuva tulisi välittömästi esiin sen välkkymättä. LISTAUS 28.2 LST28_2.CPP Kaksoispuskurointia käyttäen tehty pyörivää kierrettä esittävä välkkymätön DirectDrawanimaatio 1 CDrawDlg::CDrawDlg(CWnd* pparent /*=NULL*/) 2 : CDialog(CDrawDlg::IDD, pparent) 3 { 4 //{{AFX_DATA_INIT(CDrawDlg) 5 // NOTE: the ClassWizard will add member initialization here 6 //}}AFX_DATA_INIT 7 // Note that LoadIcon does not require a subsequent 8 m_hicon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 9 10 m_pidraw = NULL; 11 m_pimainsurface = NULL; 12 13 CoInitialize(NULL); 1 14 } 15 16 CDrawDlg::~CDrawDlg() 17 { 18 if (m_pimainsurface) 19 {

OSA VII LUKU 28 693 20 m_pidraw->setcooperativelevel(m_hwnd,ddscl_normal); 21 m_pidraw->restoredisplaymode(); 2 22 m_pimainsurface->release(); 23 } 24 if (m_pidraw) m_pidraw->release(); 25 CoUninitialize(); 26 } 27 28 BOOL CDrawDlg::OnInitDialog() 29 { 30 CDialog::OnInitDialog(); 31 32 // ** Initialize the OLE / COM library 33 if (FAILED(CoInitialize(NULL))) return FALSE; 34 35 // ** Create a direct draw object and interface 36 HRESULT hr = CoCreateInstance(CLSID_DirectDraw,NULL, 37 CLSCTX_ALL, IID_IDirectDraw2, (void**)&m_pidraw);3 38 39 if(!failed(hr)) 40 { 41 hr = m_pidraw->initialize((struct _GUID*)NULL); 42 if (hr!=dd_ok) return FALSE; 43 } 44 45 // ** Set exclusive full screen mode 46 m_pidraw->setcooperativelevel(m_hwnd, 47 DDSCL_EXCLUSIVE DDSCL_FULLSCREEN DDSCL_ALLOWREBOOT); 48 49 // ** Set up a surface description structure 50 DDSURFACEDESC DrawSurfaceDesc; 51 memset(&drawsurfacedesc,0,sizeof(drawsurfacedesc)); 52 DrawSurfaceDesc.dwSize = sizeof(drawsurfacedesc); 53 DrawSurfaceDesc.dwFlags = DDSD_CAPS 54 DDSD_BACKBUFFERCOUNT; 4 55 DrawSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_COMPLEX 56 DDSCAPS_FLIP DDSCAPS_PRIMARYSURFACE; 57 DrawSurfaceDesc.dwBackBufferCount = 1; 58 // ** Create the primary surface 59 hr = m_pidraw->createsurface(&drawsurfacedesc, 60 (IDirectDrawSurface**)&m_pIMainSurface,NULL); 61 if (FAILED(hr)) return FALSE; 62 63 // ** Find the back buffer 64 DrawSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; 65 hr = m_pimainsurface->getattachedsurface( &DrawSurfaceDesc.ddsCaps,&m_pIFlipSurface); 5 66 68 SetTimer(1,50,0); // ** Start the 50ms Timer 69 70 return TRUE; // return TRUE unless you set the focus 71 } 2 Näyttötila asetetaan normaaliksi ja COM-objektit vapautetaan. 3 CoCreateInstance():lla haetaan osoitin uuden DirectDraw-objektin IDirectDraw2-liittymään. 4 DrawSurfaceDesc-tietorakenteessa esitetään ensisijainen puskuri, jolla on yksi taustapuskuri. 5 Taustapuskurin osoitin saadaan GetAttachedSurface()- funktiolla.

694 6 Blt()-funktiolla pinta voidaan täyttää halutulla värillä pinnan kopioinnin sijaan. 7 Nämä matematiikkaa sisältävät rivit tuottavat kaksi mutkikasta kiertyvää kuviota. Kehittyneet tekniikat 72 73 void CDrawDlg::OnTimer(UINT nidevent) 74 { 75 CDialog::OnTimer(nIDEvent); 76 77 static RECT rc={0,0,0,0}; 78 static double dpetals=2.0; 79 80 // ** Clear the surface quickly with a blit 81 if (rc.right>0) 82 { 83 DDBLTFX dbltfx; 84 dbltfx.dwsize=sizeof(ddbltfx); 85 dbltfx.dwfillcolor=rgb(0,0,0); 86 HRESULT hr = m_piflipsurface->blt(&rc,null, 87 &rc,ddblt_colorfill,&dbltfx); 6 88 } 89 HDC hdc = NULL; 90 91 // ** Get a device context for the surface 92 if (m_piflipsurface->getdc(&hdc) == DD_OK) 93 { 94 if (hdc) 95 { 96 CDC dc; 97 dc.attach(hdc); 98 99 rc.right = dc.getdevicecaps(horzres); 100 rc.bottom = dc.getdevicecaps(vertres); 101 102 double mx = (double)(rc.right>>1); 103 double my = (double)(rc.bottom>>1); 104 105 CPen pscol(ps_solid,1,rgb(0,255,0)); 106 CPen* ppsold = dc.selectobject(&pscol); 107 108 double sx = mx/2; 109 double sy = my/2; 110 double sangle = 0.0; 111 112 // ** draw the graphical animation 113 for(i=0;i<(int)dpetals;i++) 114 { 115 double s1a = sin(sangle); 7 116 double c1a = cos(sangle); 117 double s2a = sin(sangle * dpetals); 118 double c2a = sin(sangle * dpetals); 119 int x = (int)(mx+sx*c1a+sx*c2a); 120 int y = (int)(my+sy*s1a+sy*s2a); 121 if (i==0) dc.moveto(x,y); 122 else dc.lineto(x,y); 123 sangle+=0.01745;

OSA VII LUKU 28 695 124 } 125 126 dpetals+=0.1; 127 dc.selectobject(ppsold); 128 dc.detach(); 129 } 130 m_piflipsurface->releasedc(hdc); 131 } 132 133 // ** Show the newly drawn surface 134 m_pimainsurface->flip(null,ddflip_wait); 8 135 } 8 Flip()-funktio odottaa juovanpaluuta ja vaihtaa näyttösivut ilman vajaan puoliksi piirretyn sivun aiheuttamaa välkyntää. Listauksen 28.2 lisäksi joudut lisäämään seuraavat #include-lauseet DrawDlg.cpp-toteutustiedoston alkuun, jotta GUID-arvot ja kosinifunktion määrittely tulisivat kääntämiseen mukaan: #include <initguid.h> #include DrawDlg.h #include math.h DirectDraw-liittymien määrittelyt saadaan mukaan liittämällä seuraava #include-lause DrawDlg.h-tiedoston alkuun: #include <ddraw.h> Myös seuraavat liittymäosoittimet joudutaan määrittelemään CDrawDlg-luokan jäseniksi DrawDlg.h-tiedostoon: IDirectDraw2* m_pidraw; IDirectDrawSurface2* m_pimainsurface; IDirectDrawSurface2* m_piflipsurface; Listauksessa 28.2 nämä liittymäosoittimet asetetaan CDrawDlg-luokan muodostimessa arvoon NULL (rivit 10 11) ja tämän jälkeen COMkirjasto alustetaan funktiolla CoInitialize() rivillä 13. OnInitDialog()-funktiolla luodaan DirectDraw-objekti kutsumalla rivillä 36 CoCreateInstance()-funktiota. Objekti saadaan käyttövalmiiksi alustamalla se vielä rivin 41 Initialize()-funktiolla, missä määritellään näyttöajuriksi käytössä oleva. Objektin yhteiskäyttötasoksi asetetaan rivillä 47 yksinoikeus kokoruutunäyttöön (exclusive, full screen). Rivillä 50 määritellään DDSURFACEDESC-tietorakenne DrawSurfaceDesc ja se alustetaan määrittämään ensisijaisen puskurin lisäksi yksi taustapuskuri kaksoispuskurointia varten. Tämän jälkeen DrawSurfaceDesc-tietorakennetta käyttäen voidaan luoda pinta rivin 59 CreateSurface()-kutsulla; taustapinnan liittymäosoitin saadaan

696 Juovanpaluujakso Kun CRT-monitorisi piirtää näytettävän kuvan, sen elektronisäde piirtää yhden rivin kerrallaan vasemmalta oikealle. Näytön sisäpinnan fosfori hehkuu hetken elektronisuihkun osuttua siihen, joka saa aikaan kuvapisteen näkymisen. Kun elektronisäde pääsee näytön alalaitaan, sen on palattava takaisin ylös pisteitä piirtämättä, joten elektronisäde katkaistaan täksi aikaa. Tällöin näyttökortti asettaa paluujaksosta kertovan lipun. Elektronisuihkun ollessa sammutettuna on paras hetki vaihtaa näytölle esitettävä muistilohko, koska vaihtaminen ei näy. Kehittyneet tekniikat tämän jälkeen rivin 65 GetAttachSurface()-kutsulla. Lopuksi rivillä 68 asetetaan 50 ms ajastin (timer) kutsumaan OnTimer()-funktioon (rivi 73) toteutettua piirtofunktiota. Tämä OnTimer()-funktio kannattaa lisätä ClassWizardilla käsittelemään WM_TIMER-sanomaa. Näin toimimalla varmistetaan luokkamäärittelyjen päivittäminen ja sanomakartan rivien lisääminen. Piirrettäessä asetetaan aluksi oletusarvoja, jonka jälkeen rivin 86 Blt()-funktiolla pyyhitään taustapuskurin edelliset kuviot asettamalla sen taustaväri mustaksi. Rivillä 92 hankitaan GDI:ltä piirtopintaosoitin GetDC()-funktiolla taustapinnalle piirtämiseksi. Tämä kahva voidaan sitten liittää CDCluokkaan, kuten rivillä 97 on esitetty. Riveillä 99 126 käytetään tavallisia GDI-kutsuja ja CPen-oliota viivojen piirtoon pinnalle, jolloin saadaan piirrettyä hyvin nopeasti yksi ruutu monimutkaisesta kierreanimaatiosta. Piirtopinta vapautetaan rivillä 130 ja juuri piirretty puskuri vaihdetaan näytössä olevan tilalle Flip()-funktiolla. Funktion parametri DDFLIP_WAIT saa vaihtamisen odottamaan seuraavaa juovanpaluujaksoa. Rivien 16 25 tuhoajafunktio palauttaa tavallisen Windowsin työpöydän nollaamalla yhteiskäyttötason ja kutsumalla RestoreDisplayMode()-funktiota näytön palauttamiseksi ennalleen. Release()-kutsu vapauttaa liittymät ja COM-kirjaston alustus purkautuu hallitusti. Jos teet nämä muutokset tavalliseen valintaikkunasovelluksen runkoon, voit kääntää sovelluksen ilman ylimääräisiä API-kirjastoja, mikä osoittaa aitojen COM-objektien vahvuuden. Tämän jälkeen voit suorittaa ohjelmasi ja nauttia sujuvasta ja nopeasta, välkkymättömästä tietokonegrafiikasta, joka havainnollistaa hyvin DirectX:n todellista voimaa. Saat lopetettua sovelluksen missä vaiheessa tahansa Escnäppäintä painamalla (joka on itse asiassa vielä aktiivisena olevan valintaikkunan Cancel-painike). Tämän tehtyäsi tavallinen työpöytä palautetaan hallitusti ja sovellus suljetaan. KATSO MYÖS OLEn ja COMin perusteet luvusta 25. Lisätietoja piirtopinnoista ja GDI:llä piirtämisestä luvusta 15.

OSA VII LUKU 28 697 Direct3D:n käyttö Direct3D API:lla saat käyttöösi uusimpien näyttökorttien 3D-ominaisuudet. Direct3D toimii yhdessä DirectDraw:n kanssa peleissä ja virtuaalimaailmasovelluksissa nähdyn perspektiivigrafiikan tuottamiseksi. Direct3D käyttää kolmesta osasta koostuvaa piirtokoneistoa, joka tukee koordinaattien matriisimuunnoksia, piste- ja hajavalotehosteita ja saadun näkymän rasteroimista sen piirtämistä varten. Direct3D:n toiminnot ovat tarjolla usean liittymän kautta. Näiden avulla saadaan muodostettua ja esitettyä mutkikkaita kolmiulotteisia näkymiä kahdessa eri piirtotilassa, jotka ovat immediate-mode ja retained-mode. Immediate-mode tilan kappaleet ovat alemman tason yksinkertaisia ja nopeasti esitettäviä peruskappaleita (joiden liittymät on esitetty taulukossa 28.2). Näiden päälle on rakennettu korkean tason kappaleita, joiden avulla voidaan tehdä edistyneitä korkeatasoisia reaaliaikaisia 3D näkymiä ja animaatioita. Uudet 3D-kortit Viime vuosina on tullut yhä enemmän käyttöön 3Dnäyttökortteja, jotka toteuttavat omilla piireillään useita kolmiulotteisen kuvan esittämisessä tarvittavia toimenpiteitä. Grafiikkaprosessori suorittaa mutkikkaat koordinaattilaskennan selvästi pelkkää ohjelmallista toteutusta nopeammin. Tämä vapauttaa myös prosessoriaikaa, jotta CAD- ja peliohjelmistojen kehittäjille jäisi enemmän prosessoriaikaa pelin laadun ja kuvan laadun muuhun kehittämiseen. TAULUKKO 28.2 Direct3D:n liittymät ja niiden toiminnot Direct3D-liittymä Toiminnot IDirect3D Alustaa ympäristön ja luo Light-, Material- ja Viewport-objektit. IDirect3DDevice Käsittelee allaolevan 3D-laitteiston ja ympäris tön ominaisuuksien konfiguroinnin. Tällainen liittymä saadaan DirectDraw-pinnalta QueryInterface()-kutsulla. IDirect3DExecuteBuffer Suorituspuskureissa pidetään piirtokäskyjä ja 3Dperusobjektien tietoja valmiina kerralla piirrettäviksi. IDirect3DLight Konfiguroi näkymän valonlähteiden tiedot. IDirect3DMaterial Ylläpitää materiaalien ominaisuuksia ja niiden heijastavuus- ja läpinäkyvyystietoja. IDirect3DTexture Ylläpitää ylläolevien 3D-pintojen pintakuviobittikarttoja. IDirect3DViewport Ryhmittää valot, pintakuviot ja taustatehosteet paikalleen näytöllä. Tämän jälkeen useita viewport-projektioita yhdistetään ja tulos on valmis piirrettäväksi laitteelle peruskappaleiden koodrinaattitietojen kera.

698 DirectPlayn verkkoprotokollatuki DirectPlay API tukee tiedonsiirtoa koneiden välillä, jotka on kytketty yhteen sarjakaapelilla, TCP/IPlähiverkolla, puhelinverkkoliitynnällä tai suoralla Internetliitynnällä, Netwarella ja monella muullakin verkkototeutuksella. Kehittyneet tekniikat DirectPlayn käyttö DirectPlayn avulla voidaan helposti toteuttaa monen pelaajan verkkopelejä ilman tarvetta räätälöidä jokaista verkkotyyppiä erikseen. DirectPlayn liittymät, IDirectPlay2 ja IDirectPlayLobby, huolehtivat verkkopelaamiseen liittyvistä objekteista ja istuntojen hallinnasta. DirectInputin käyttö DirectInputin avulla päästään näppäimistöön ja hiireen tavallista Windowsin syöttömekanismia nopeammin. DirectInput tukee myös monipainikkeisia ja akselisia ohjainsauvoja ja auttaa niiden kalibroinnissa. Tämä API on yksinkertainen mutta joustava, ja se on toteutettu kahdella COM-liittymällä. IDirectInput-liittymällä hallitaan järjestelmän syöttölaitteita ja niiden tilaa. Sillä voidaan myös luoda ilmentymiä IDirectInputDevice-liittymästä yksittäisen laitteen konfiguroimiseksi ja syötteen lukemiseksi. DirectMusic DirectMusic on DirectX-perheen uusin tulokas. Sen avulla voidaan peleihin luoda keinotekoista musiikkia midiäkin monipuolisemmin. Taustamusiikkia varten käytettävissä ovat myös samplatut ääninäytteet. DirectSetupin käyttö DirectSetup API on kenties kaikken pienen API-rajapinta. Siinä on vain kaksi funktiota: DirectXSetup(), joka automatisoi kaikkien DirectX-osien asennuksen ja DirectXRegisterApplication(), joka rekisteröi pelin DirectPlayLobby-enabloiduksi monen pelaajan verkkosovellukseksi. Viestien ja sähköpostin luominen MAPIlla Microsoft Messaging API (MAPI) ei ole oikeastaan funktiokirjastorajapinta, vaan arkkitehtuurin muodostava standardikokoelma. Näitä standardeja seuraamalla ohjelmiston kehittäjät voivat keskittyä tekemään sähköpostijärjestelmän eri osia.