Această carte începe cu ceea ce au încheiat de obicei alte cărți. Vom vorbi despre principiile DirectDraw, dar numai în termeni generali. Cititorul este un programator cu experiență, dar nu este familiarizat cu DirectDraw - va fi capabil să se descurce. Apoi continuăm cu alte subiecte care sunt la fel de interesante și utile.
Scopul acestei cărți este de a vă învăța cum să lucrați cu DirectDraw și de a nu oferi o bază structurală sau un API non-standard care ar face tot munca pentru dvs. Demoanele sunt scrise în C ++ și utilizează MFC, dar nu pentru a ascunde toate detaliile tehnice. C ++ și MFC sunt instrumente excelente, deoarece, cu ajutorul lor, orice aplicație poate fi scrisă în mai multe moduri diferite. Exemplele pentru această carte au fost scrise astfel încât s-au produs proiecte structurate și ușor de citit care arată clar ce se întâmplă în program și de ce.
În plus față de DirectDraw, multe exemple utilizează biblioteca DirectInput. În mod strict vorbind, atunci când programați grafice pentru Windows, puteți face fără DirectInput, dar trebuie încă să fie utilizat. Acesta rulează mai repede decât instrumentele tradiționale de introducere a Windows-ului și este, de asemenea, inclus în DirectX, deci nu este necesar să folosiți SDK-uri suplimentare pentru a lucra cu acesta.
Carte: Grafica pentru Windows utilizând DirectDraw
Inițializarea DirectDraw
Secțiunile de pe această pagină sunt:
Crearea reală a ferestrei (apelarea funcției CreateEx () determină Windows să trimită un mesaj WM_CREATE la aplicația noastră. Clasa DirectDrawWin interceptează acest mesaj în handlerul OnCreate (). create de ClassWizard (consultați Listing 3.1).
Listing 3.1. Funcția DirectDrawWin :: OnCreate ()
int DirectDrawWin :: OnCreate (LPCREATESTRUCT) DirectDrawEnumerate (DriverAvailable, acest lucru);
dacă (totaldrivers == 0) AfxMessageBox ("Nu s-au detectat drivere DirectDraw");
retur -1;
>
int driverindex = SelectDriver ();
dacă (driverindex<0) TRACE("No DirectDraw driver selectedn");
retur -1;
> altfel dacă (driverindex> totaldrivers-1) AfxMessageBox ("Driver selectat DirectDraw nevalid");
retur -1;
>
LPDIRECTDRAW ddraw1;
DirectDrawCreate (driver [driverindex] .guid, ddraw1, 0);
HRESULT r;
r = ddraw1-> QueryInterface (IID_IDirectDraw2, (void **) ddraw2);
dacă (r! = S_OK) AfxMessageBox ("Interfața DirectDraw2 nu este acceptată");
retur -1;
>
ddraw1-> Release (), ddraw1 = 0;
ddraw2-> SetCooperativeLevel (GetSafeHwnd (), DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX);
ddraw2-> EnumDisplayModes (0, 0, acest, DisplayModeAvailable);
qsort (displaymode, totaldisplaymodes, sizeof (DisplayModeInfo), CompareModes);
int initmode = SelectInitialDisplayMode ();
dacă (ActivateDisplayMode (initmode) == FALSE) returnează -1;
retur 0;
>
Toate inițializarea DirectDraw este efectuată în funcția OnCreate () (cu suportul mai multor funcții auxiliare). Procesul de inițializare constă în șapte pași:
• Obțineți o listă cu toate driverele DirectDraw.
• Selectați driverul DirectDraw.
• Inițializați DirectDraw utilizând driverul selectat.
• Crearea suprafețelor aplicației.
Toți acești pași sunt discutate în secțiunile următoare.
Obținerea listei de drivere DirectDraw
Funcția DirectDrawEnumerate () primește două argumente: un indicator la o funcție apelată indirect (callback) și un pointer la datele definite de aplicație, care sunt transmise la această funcție atunci când sunt apelate. În cazul nostru, argumentele sunt indirect numite DriverAvailable () și un pointer la clasa DirectDrawWin (this). Funcția DriverAvailable () este definită după cum urmează:
BOOL WinAPI DirectDrawWin :: DriverAvailable (LPGUID GUID, LPSTR desc, numele LPSTR, LPVOID p) DirectDrawWin * câștig = (DirectDrawWin *) p;
dacă (win-> totaldrivers> = MAXDRIVERS) returnați DDENUMRET_CANCEL;
DriverInfo info = win-> driver [win-> totaldrivers];
dacă (guid) info.guid = (GUID *) BYTE [sizeof (GUID)];
memcpy (info.guid, guid, sizeof (GUID));
> altfel info.guid = 0;
info.desc = strdup (desc);
info.name = strdup (nume);
win-> totaldrivers ++;
retur DDENUMRET_OK;
>
Mai întâi, pointerul către datele definite de aplicație (p) este convertit la un pointer la clasa DirectDrawWin (câștig). Deoarece funcția DriverAvailable () este declarată statică (funcțiile indirecte numite trebuie să fie statice), regulile automate de acces nu se aplică acesteia, spre deosebire de funcțiile obișnuite ale clasei; În consecință, accesul la variabilele și funcțiile clasei trebuie făcut prin pointerul câștigător.
DirectDraw apelează funcția DriverAvailable () o dată pentru fiecare driver detectat. La fiecare apel sunt transferate trei obiecte de informare: GUID, descriere și nume. GUID (identificatorul unic global) identifică în mod unificat driverul. Descrierea și denumirea sunt liniile pentru identificarea informală a conducătorului auto. Funcția DriverAvailable () stochează informații despre fiecare driver într-un driver denumit driver și urmărește numărul de drivere din variabila totaldrivers. În cele din urmă, funcția DriverAvailable () returnează DDNUMRET_OK. indicând că enumerarea conducătorilor auto ar trebui să continue. Când se primește codul de returnare, DDENUMRET_CANCEL DirectDraw oprește enumerarea driverelor.
Selecția șoferului
După ce toate driverele DirectDraw sunt listate, funcția OnCreate () selectează una dintre ele. Selecția implicită a driverului poate fi înlocuită în clasele derivate utilizând funcția virtuală SelectDriver (). Revenind la listarea 3.1, vedem că valoarea returnată de funcția SelectDriver (). Este folosit ca index al matricei driver (cu valori ale indexului pornind de la zero). Indicele arată ce GUID (și, prin urmare, driverul) ar trebui să fie utilizat pentru a inițializa DirectDraw. Versiunea SelectDriver () din clasa DirectDrawWin arată astfel:
virtual int SelectDriver () return 0;
>
int bounceWin :: SelectDriver () int numbrivers = GetNumDrivers ();
dacă (numbrivers == 1) returnează 0;
CArray
pentru (int i = 0; i
drivers.Add (desc);
>
Dialogul DriverDialog;
dialog.SetContents (drivere);
dacă (dialog.DoModal ()! = IDOK) returnează -1;
return dialog.GetSelection ();
>
Această funcție determină mai întâi numărul de drivere detectate utilizând funcția GetNumDrivers (). care returnează pur și simplu valoarea variabilelor închise total variabile. Dacă în sistem este detectat un singur driver, nu este nevoie să afișați un meniu, astfel încât funcția returnează 0 pentru a utiliza driverul principal.
Clase derivate din DirectDrawWin. poate implementa funcția SelectDriver () și în alte moduri. Implementarea descrisă aici este simplă și flexibilă, însă este posibil să doriți să inițializați fiecare driver și să îl testați pentru caracteristici specifice. În unele aplicații, funcția SelectDriver () poate fi utilizată pentru a selecta driverul care îndeplinește cel mai bine criteriile specificate.
Inițializarea DirectDraw
A treia sarcină efectuată de funcția OnCreate () este inițierea DirectDraw. Aduc din nou fragmentul corespunzător din Lista 3.1:
LPDIRECTDRAW ddraw1;
DirectDrawCreate (driver [driverindex] .guid, ddraw1, 0);
HRESULT r;
r = ddraw1-> QueryInterface (IID_IDirectDraw2, (void **) ddraw2);
dacă (r! = S_OK) AfxMessageBox ("Interfața DirectDraw2 nu este acceptată");
retur -1;
>
ddraw1-> Release (), ddraw1 = 0;
ddraw2-> SetCooperativeLevel (GetSafeHwnd (), DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX);
Fig. 3.9. Caseta de dialog pentru selectarea driverului
După ce este inițializată interfața DirectDraw, o puteți folosi pentru a obține un pointer la interfața DirectDraw2. Pentru aceasta, apelați funcția QueryInterface () și transmiteți-o GUID-ul interfeței DirectDraw2. definit ca IID_IDirectDraw2. Dacă apelul QueryInterface () nu reușește, programul afișează o casetă de dialog și se termină. De fapt, avem nevoie de prezența bibliotecii DirectX versiunea 2 și mai sus (deoarece interfața DirectDraw2 a apărut pentru prima dată în DirectX 2). Dacă apelul QueryInterface () reușește, indicatorul ddraw1 este eliberat. Alternativ, apelarea funcțiilor interfețelor DirectDraw și DirectDraw2 nu este recomandată, astfel încât eliberarea indicatorului de la interfața DirectDraw asigură faptul că numai interfața DirectDraw2 va fi utilizată în restul codului.
HRESULT WinAPI DirectDrawWin :: DisplayModeAvailable (LPDDSURFACEDESC desc, LPVOID p) DirectDrawWin * câștig = (DirectDrawWin *) p;
int count = win-> totaldisplaymodes;
dacă (count == MAXDISPLAYMODES) returnați DDENUMRET_CANCEL;
win-> displaymode [count] .width = desc-> dwWidth;
win-> displaymode [count] .height = desc-> dwHeight;
win-> displaymode [count] .depth = desc-> ddpfPixelFormat.dwRGBBitCount;
numărătoarea ++;
retur DDENUMRET_OK;
>
virtual int SelectInitialDisplayMode () = 0;
int BounceWin :: SelectInitialDisplayMode () int i, nummodes = GetNumDisplayModes ();
DWORD w, h, d;
pentru (i = 0; i
>
pentru (i = 0; i> nummodes; i ++) GetDisplayModeDimensiuni (i, w, h, d);
dacă (d == dorința dorită) returnați i;
>
retur 0;
>
În stadiul penultim, modul selectat este activat. Pentru aceasta, utilizați funcția ActivateDisplayMode (). care îndeplinește efectiv sarcina ultimei etape (crearea de suprafețe de aplicație). Codul pentru această funcție este prezentat în lista 3.2.
Listing 3.2. ActivateDisplayMode () funcția