• Keine Ergebnisse gefunden

Erstellen der IDirect3D9-Schnittstelle

Kontakt und Updates

2.4 Initialisierung von Direct3D

2.4.1 Erstellen der IDirect3D9-Schnittstelle

Der erste Schritt in der Initialisierung von Direct3D ist das Anlegen der IDirect3D9 -Schnittstelle, mit deren Hilfe wir an Informationen über die auf dem System zur Verfügung stehenden Adapter kommen. Hier ist die Angelegenheit noch sehr einfach: Es reicht, eine ein-zige Funktion namens Direct3DCreate9 aufzurufen, und schon erhalten wir eine nagelneue Schnittstelle.

Die Funktion erwartet einen Parameter, welcher die Versionsnummer der zu erstellenden Schnittstelle beinhaltet. Man gibt dort immer D3D_SDK_VERSION an – dies ist ein Makro, das in der Direct3D-Headerdatei deklariert ist und immer die Version des installierten DirectX-SDKs bereithält. Indem wir den zurückgelieferten Schnittstellenzeiger mit NULL vergleichen, prüfen wir, ob ein Fehler auftrat. Wenn dies der Fall ist, ist der Grund dafür meistens eine falsche (al-so zu niedrige) Version von DirectX, was man dem Benutzer dann auch mitteilen (al-sollte.

// Schnittstelle erzeugen

PDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION);

if(!pD3D) {

// Fehler beim Erstellen der Schnittstelle!

MessageBox(NULL, "Direct3D 9 konnte nicht initialisiert werden!\n“

“Installieren Sie bitte die neueste DirectX-Version.", "Fehler", MB_OK | MB_ICONEXCLAMATION);

}

else pD3D->Release(); // Wenn es geklappt hat, wieder freigeben.

Listing 2.50 Anlegen und Freigeben der IDirect3D9-Schnittstelle

2.4.2 Adapterinformationen

Im nun folgenden Teil beschäftigen wir uns mit der Aufgabe, so viele Informationen wie mög-lich über die auf einem System verfügbaren Adapter zu sammeln.

2.4.2.1 Auflisten aller Adapter

Anzahl der Adapter

Nun ist es an der Zeit herauszufinden, wie viele und welche Adapter auf dem System instal-liert und verfügbar sind. Deren Anzahl erhalten wir durch die Methode GetAdapterCount der

IDirect3D9-Schnittstelle. Sie erwartet keine Parameter und liefert die Adapteranzahl im Rück-gabewert zurück. Ein Wert von 0 sollte einem dabei schon zu denken geben … Ein Adapter wird von nun an nur noch durch seine ID-Nummer angesprochen, wobei 0 (oder

D3DADAPTER_DEFAULT) den ersten Adapter darstellt, 1 den zweiten und so weiter.

Beschreibungen der Adapter

Nun können wir jeden einzelnen Adapter durchgehen und Informationen über ihn abfragen, die in einer Struktur namens D3DADAPTER_IDENTIFIER9 gespeichert werden. Die Methode

IDirect3D9::GetAdapterIdentifier ist für das Füllen zuständig. Sie erwartet folgende Parame-ter:

Tabelle 2.7 Die Parameter der Methode IDirect3D9::GetAdapterIdentifier

Parameter Beschreibung

UINT Adapter ID des Adapters, für den eine genauere Beschreibung ge-wünscht wird

DWORD Flags Geben Sie hier 0 für den normalen Modus an oder D3DENUM_WHQL_LEVEL, um das manchmal recht zeitaufwändi-ge Zertifikationsverfahren ausführen zu lassen, welches das letzte Prüfdatum seitens des Windows Hardware Quality Labs (WHQL) ermittelt, um hundertprozentige Kompatibilität zwischen Adapter und Treiber sicherzustellen. Ein bis zwei Sekunden können gespart werden, wenn man dieses Flag nicht angibt, also null verwendet.

D3DADAPTER_IDENTIFIER9* pAdapter Zeiger auf die Struktur, die gefüllt werden soll

Auf diese Weise bringt man wichtige Informationen über den Adapter und den verwendeten Treiber in Erfahrung, die man dann dem Benutzer bei der Adapterauswahl präsentieren kann (vor allem natürlich den Adapternamen).

Tabelle 2.8 Die wichtigsten Elemente der D3DADAPTER_IDENTIFIER9-Struktur Element Beschreibung

char Driver[512] Dateiname des Treibers, der für diesen Adapter verwendet wird (zum Beispiel „NV4_disp.dll“)

char Description[512] Anzeigefreundlicher Name des Adapters (beispielsweise „NVIDIA GeForce2 MX/MX 400“)

LARGE_INTEGER DriverVersion Version des Treibers

Beispielprogramm

Das folgende Beispielprogramm demonstriert den Umgang mit der IDirect3D9-Schnittstelle und zeigt, wie man auf eine einfache Weise alle Adapter des Systems auflisten und anzeigen kann (das geschieht hier durch Message-Boxes).

#include <Windows.h>

#include <StdIO.h>

#include <D3D9.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char* pcCmdLine, int iShowCmd) {

// Schnittstelle für Direct3D erzeugen

PDIRECT3D9 pD3D = Direct3DCreate9(D3D_SDK_VERSION);

if(!pD3D) {

MessageBox(NULL, "Fehler beim Erzeugen der Direct3D-Schnittstelle!", "Fehler", MB_OK | MB_ICONEXCLAMATION); // Fehler!

return 1;

}

// Anzahl der Adapter ermitteln

int iNumAdapters = pD3D->GetAdapterCount();

// Speicher reservieren und Informationen über jeden Adapter sammeln

D3DADAPTER_IDENTIFIER9* pAdapters = new D3DADAPTER_IDENTIFIER9[iNumAdapters];

for(int iAdapter = 0; iAdapter < iNumAdapters; iAdapter++) {

if(FAILED(pD3D->GetAdapterIdentifier(iAdapter, 0,

&pAdapters[iAdapter]))) {

// Fehler!

MessageBox(NULL, "Adapterinformationen konnten nicht abgefragt werden!", "Fehler", MB_OK | MB_ICONEXCLAMATION);

// Aufräumen pD3D->Release();

delete[] pAdapters;

return 1;

}

// Adapterinformationen anzeigen char acAdapterInfo[1024];

sprintf(acAdapterInfo, "Adapter-ID: %d\n“

“Name: %s\n“

“Treiber: %s\n“

“nTreiberversion: %d", iAdapter,

pAdapters[iAdapter].Description, pAdapters[iAdapter].Driver, pAdapters[iAdapter].DriverVersion);

MessageBox(NULL, acAdapterInfo, "Adapter gefunden", MB_OK | MB_ICONINFORMATION);

}

// Aufräumen pD3D->Release();

delete[] pAdapters;

return 0;

}

Listing 2.51 Auflisten und Anzeigen aller auf dem System verfügbaren Direct3D-Adapter

Abbildung 2.18 Adapterinformationen

Wichtig: In meinem Forum wird immer wieder gefragt, warum dieses erste Beispielpro-gramm bei der Kompilierung einen Linker-Fehler bezüglich Direct3DCreate9 verursacht. In diesem Fall hat man ganz einfach nur vergessen, die Datei D3D9.LIB bei den Projekteinstel-lungen zu den Bibliotheksdateien hinzuzufügen. DXERR9.LIB sollte für die nächsten Bei-spielprogramme ebenfalls mitgelinkt werden!

Auch wird immer wieder der Fehler gemacht, in Visual C++ eine Win32-Konsolenanwendung zu erstellen anstatt einer normalen Win32-Anwendung. Achten Sie al-so darauf, wenn Sie sich mit Visual C++ noch nicht gut auskennen!

2.4.2.2 Videomodi eines Adapters

Die wenigsten Spiele laufen im normalen Fenstermodus, unter anderem, weil dadurch viel Atmosphäre verloren geht. Wer will schon glauben, dass er in einem Flugzeug sitzt, wenn im Hintergrund noch der Windows-Desktop zu sehen ist? Daher schaltet man meistens in den Vollbildmodus um. Dieser muss aber ganz genau beschrieben werden, mit Breite, Höhe, An-zahl der Bits pro Pixel und Bildwiederholfrequenz. Klar ist auch, dass nicht jede Grafikkarte und nicht jeder Monitor in der Lage ist, einen Videomodus von 1600 x 1200 zu verkraften.

Vorbildliche Spiele legen sich deshalb nicht auf einen bestimmten Videomodus fest, sondern verhalten sich flexibel und überlassen dem Benutzer die Auswahl.

Anzahl der Videomodi

Um herauszufinden, welche Videomodi ein Adapter unterstützt, rufen wir zuerst die Methode

IDirect3D9::GetAdapterModeCount auf. Sie liefert uns dann zunächst die Anzahl der unterstütz-ten Videomodi. Der Methode wird die Adapter-ID sowie ein Pixelformat angegeben, und sie liefert dann die Anzahl der Videomodi, die mit diesem Pixelformat kompatibel sind. So kann man zum Beispiel gezielt nach 16-Bit-Formaten suchen lassen. Intern wird nicht zwischen den verschiedenen Bitverteilungen bei 16-Bit-Formaten unterschieden: D3DFMT_R5G6B5 und

D3DFMT_X1R5G5B5 sollten also die gleichen Ergebnisse bringen.

Beschreibung der Videomodi

Nun geht man – ähnlich wie beim Abfragen von Adapterinformationen – jeden Videomodus durch (wobei wieder jeder durch seine ID angesprochen wird, 0 ist der erste Videomodus) und fragt weitere Informationen über ihn ab, und zwar mit der Methode EnumAdapterModes, die e-benfalls zur Schnittstelle IDirect3D gehört. Der Name dieser Methode täuscht ein wenig: Tat-sächlich wird hier nur ein Videomodus unter die Lupe genommen und nicht mehrere, wie der Name nahe legt.

Tabelle 2.9 Die Parameter der Methode IDirect3D9::EnumAdapterModes

Parameter Beschreibung

UINT Adapter ID des Adapters, dessen Videomodus abgefragt wird

D3DFORMAT Format Geben Sie hier ein Format an, mit dem alle aufgelisteten Videomodi kom-patibel sein sollen. Es werden dann nur passende Modi aufgelistet. Ver-wenden Sie das gleiche Format, was Sie zuvor auch schon bei GetAdapterModeCount verwendet haben.

UINT Mode Die ID des Videomodus (0: erster Modus), über den wir die Informationen erhalten wollen. Der maximale Wert ist Anzahl der Adapters minus 1.

D3DDISPLAYMODE* pMode Zeiger auf die zu füllende D3DDISPLAYMODE-Struktur

Tabelle 2.10 Die Elemente der Struktur D3DDISPLAYMODE

Element Beschreibung

UINT Width Horizontale Anzahl der Pixel in diesem Videomodus (Pixel pro Zeile; Breite) UINT Height Vertikale Anzahl der Pixel dieses Videomodus (Pixel pro Spalte; Höhe) UINT RefreshRate Bildwiederholfrequenz in Hz oder 0 für Standard

D3DFORMAT Format Format dieses Videomodus (zum Beispiel D3DFMT_R5G6B5 für 16 Bits)

Kurz zusammengefasst: Erst die Anzahl der zu einem bestimmten Format kompatiblen Vi-deomodi mit GetAdapterModeCount abfragen und dann weitere Informationen über jeden dieser Videomodi mit EnumAdapterModes sammeln.

Aktueller Videomodus

Im Fenstermodus wird der Videomodus nicht verändert. Daher sollte dann der Bildpuffer auch das gleiche Format haben wie der aktuelle Videomodus. Beispiel: Wenn das System gerade mit 16-Bit-Grafik läuft, wird ein 32-Bit-Bildpuffer im Fenstermodus wahrscheinlich Probleme bereiten. Es gibt zwar in DirectX 9 die Möglichkeit der automatischen Formatkonvertierung, aber darauf sollte man sich nicht unbedingt verlassen, da diese Fähigkeit noch längst nicht bei allen Grafikkarten vorhanden ist. Möchte man also den Fenstermodus verwenden, muss vorher

der aktuelle Videomodus bekannt sein. Diesen fragen wir mit Hilfe der Methode

IDirect3D9::GetAdapterDisplayMode ab. Sie erwartet als ersten Parameter die ID des Adapters, dessen Videomodus abgefragt werden soll, und als zweiten Parameter einen Zeiger auf eine

D3DDISPLAYMODE-Struktur, welche die Methode dann ausfüllt.

2.4.2.3 Beispielprogramm

Das nun folgende kleine Listing ist als Erweiterung für das vorherige gedacht. Es startet, nachdem die Message-Box mit den Adapterinformationen angezeigt wurde, und listet nun noch alle 16-Bit-Formate auf, die von diesem Adapter unterstützt werden.

// Die Variable iAdapter enthält die ID des gerade aufgelisteten Adapters.

// Ermitteln, wie viele 16-Bit-Videomodi verfügbar sind

int iNumModes = pD3D->GetAdapterModeCount(iAdapter, D3DFMT_R5G6B5);

if(iNumModes > 0) {

// Speicherplatz reservieren und den String zurücksetzen D3DDISPLAYMODE* pModes = new D3DDISPLAYMODE[iNumModes];

char acModes[16384] = "";

// Jeden Videomodus durchgehen

for(int iMode = 0; iMode < iNumModes; iMode++) {

// Informationen über diesen Modus abfragen

pD3D->EnumAdapterModes(iAdapter, D3DFMT_R5G6B5, iMode, &pModes[iMode]);

// Nummer, Breite, Höhe und Bildwiederholfrequenz in den String schreiben sprintf(acModes, "%s\nModus %d: %dx%d bei %d Hz (0: Standard)",

acModes, iMode,

pModes[iMode].Width, pModes[iMode].Height, pModes[iMode].RefreshRate);

}

// Videomodi anzeigen

MessageBox(NULL, acModes, "Verfügbare 16-Bit-Videmodi", MB_OK | MB_ICONINFORMATION);

// Speicher wieder freigeben delete[] pModes;

}

Listing 2.52 Auflisten aller Videomodi, die zu einem bestimmten Format kompatibel sind

Erschrecken Sie sich nicht, wenn Sie das Programm ausführen: Die erzeugte Message-Box ist meistens so groß, dass sie gar nicht mehr auf den Bildschirm passt. Das liegt daran, dass jeder Videomodus in verschiedenen Bildwiederholfrequenzen aufgelistet wird. Wenn eine Grafik-karte dann über eine recht große Bandbreite von Frequenzen und Auflösungen verfügt, können leicht über einhundert verschiedene Videomodi zusammenkommen. Die Frage ist dann, wie man sie dem Benutzer allesamt übersichtlich präsentieren kann.