#define WIN32_LEAN_AND_MEAN // Dieses #define klammert selten benötigte Windows-Funktionen aus
#include <windows.h>
#include <D3DX8.h>
#define WNDCLASSNAME "DirectX8 Einführung 1"
//
// Einbinden der DirectX-Bibliotheken. Sollte man eigentlich in den
// Projekteinstellungen tätigen, aber so kann man die .cpp-Datei einfach in
// ein neues Projekt einfügen und es funktioniert.
//
#pragma comment(lib, "d3d8.lib")
#pragma comment(lib, "d3dx8.lib")
//
// Funktionsprototypen
//
void createWindow();
void removeWindow();
void initDirect3D();
void releaseDirect3D();
void render();
void exitOnError(const char *ErrorMessage);
void exitOnError(HRESULT res, const char *ErrorMessage);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
//
// Globale Variablen
//
HWND g_HWnd = NULL; // Das Handle unseres Fensters für den Empfang von Windows-Nachrichten
HINSTANCE g_Instance = NULL; // Das Handle unseres Programms
LPDIRECT3D8 g_pD3D = NULL; // Zeiger auf unsere Instanz von Direct3D
IDirect3DDevice8 *g_pD3DDevice = NULL; // Zeiger auf unsere Instanz des Direct3DDevices
bool g_Quit = false; // Zeigt an, ob unser Programm verlassen werden soll, weil der Benutzer [ESC] gedrückt hat
int g_Green = 0; // Der Grünanteil der Farbe, mit welcher der Hintergrund gefüllt wird
/*--------------------------------------------------------------------------------
Name: initDirect3D
Description:
Initialisiert Direct3D und das Direct3DDevice.
--------------------------------------------------------------------------------*/
void initDirect3D()
{
HRESULT res;
D3DPRESENT_PARAMETERS PresentParams;
//
// Unsere Instanz von Direct3D erzeugen
//
g_pD3D = Direct3DCreate8(D3D_SDK_VERSION);
if (g_pD3D == NULL)
exitOnError("Direct3DCreate8() fehlgeschlagen!\n");
// Die Struktur vor dem Benutzen löschen
ZeroMemory(&PresentParams, sizeof(PresentParams));
//
// Festlegen der Parameter für unser Direct3DDevice
//
PresentParams.Windowed = FALSE; // Unser Programm soll im Vollbildmodus laufen
PresentParams.hDeviceWindow = g_HWnd; // Handle unseres Fensters
PresentParams.BackBufferCount= 1; // Wir wollen 1 Backbuffer für Double Buffering
PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD; // Nach dem Anzeigen interessiert uns der Backbuffer nicht mehr
PresentParams.BackBufferWidth = 640; // Breite
PresentParams.BackBufferHeight = 480; // Höhe
PresentParams.BackBufferFormat = D3DFMT_R5G6B5; // Farbtiefe. Diese Farbtiefe wird von fast allen Grafikkarten unterstützt
//
// Erzeugen der Direct3DDevice
//
res = g_pD3D->CreateDevice
(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
g_HWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&PresentParams,
&g_pD3DDevice
);
if (FAILED(res))
exitOnError(res, "CreateDevice() fehlgeschlagen!\n");
}
/*--------------------------------------------------------------------------------
Name: releaseDirect3D
Description:
Gibt Direct3D und das Direct3DDevice frei.
--------------------------------------------------------------------------------*/
void releaseDirect3D()
{
// Wurde ein Direct3DDevice erstellt?
if (g_pD3DDevice)
{
// Ja! Dann freigeben
g_pD3DDevice->Release();
g_pD3DDevice = NULL;
}
// Wurde eine Instanz von Direct3D erzeugt?
if (g_pD3D)
{
// Ja! Dann freigeben
g_pD3D->Release();
g_pD3D = NULL;
}
}
/*--------------------------------------------------------------------------------
Name: render
Description:
Zeigt die Grafik auf dem Bildschirm an.
Remarks:
Momentan wird einfach nur der Bildschirm gelöscht.
--------------------------------------------------------------------------------*/
void render()
{
// Den Grünton zum Füllen des Hintergrundes verändern
g_Green = (g_Green + 1) % 256;
//
// Den Hintergrund mit einem Grünton füllen
//
g_pD3DDevice->Clear
(
0, // Anzahl der Rechtecke, die zum Löschen angemeldet werden. Muss 0 sein, wenn der 2. Parameter NULL ist
NULL, // Zeiger auf Array mit Rechtecken. Bei NULL nimmt Direct3D ein Rechteck für den ganze Bildschirm an
D3DCLEAR_TARGET, // Einfach nur Hintergrund löschen
D3DCOLOR_XRGB(0, g_Green, 0), // Hintergrundfarbe angeben
0.0f, // Füllwert für den ZBuffer (wird momentan nicht benutzt)
0 // Füllwert für den Stencil-Buffer (wird momentan nicht benutzt)
);
g_pD3DDevice->BeginScene();
//
// Momentan wird noch keine eigentliche Grafik gezeichnet
//
g_pD3DDevice->EndScene();
// Den neu gezeichneten Backbuffer zum Frontbuffer machen und damit anzeigen
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
/*--------------------------------------------------------------------------------
Name: createWindow
Description:
Erzeugt das Fenster des Programms.
--------------------------------------------------------------------------------*/
void createWindow()
{
WNDCLASSEX wc;
//
// Erzeugen unserer Fensterklasse
//
// Struktur mit Eigenschaften unserer Fensterklasse füllen
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_OWNDC;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_Instance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WNDCLASSNAME;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// Die neue Fensterklasse registrieren
if (!RegisterClassEx(&wc))
exitOnError("RegisterClassEx() fehlgeschlagen!\n");
//
// Fenster für die Applikation erstellen
//
g_HWnd = CreateWindowEx
(
NULL,
WNDCLASSNAME,
"Kapitel 1",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0,
400, 400,
NULL,
NULL,
g_Instance,
NULL
);
if (!g_HWnd)
exitOnError("CreateWindowEx() fehlgeschlagen!\n");
//
// Das neue Fenster anzeigen und fokusieren
//
ShowWindow(g_HWnd, SW_SHOW);
UpdateWindow(g_HWnd);
SetFocus(g_HWnd);
}
/*--------------------------------------------------------------------------------
Name: removeWindow
Description:
Meldet das Fenster des Programms ab.
--------------------------------------------------------------------------------*/
void removeWindow()
{
// Wurde ein Fenster erzeugt?
if (g_HWnd)
{
// Ja! Dann abmelden!
if (!DestroyWindow(g_HWnd))
MessageBox(NULL, "Destroy Window Failed", WNDCLASSNAME, MB_OK | MB_ICONERROR | MB_TOPMOST);
g_HWnd = NULL;
}
}
/*--------------------------------------------------------------------------------
Name: exitOnError
Description:
Gibt eine Fehlermeldung aus.
Parameters:
pErrorMessage - Zeiger auf den Text der den Fehler beschreibt
--------------------------------------------------------------------------------*/
void exitOnError(const char *pErrorMessage)
{
//
// Eventuell angemeldete Ressourcen freigeben
//
releaseDirect3D();
removeWindow();
// Die Fehlermeldung in der Debugausgabe ausgeben
OutputDebugString(pErrorMessage);
OutputDebugString("\n");
// Die Fehlermeldung ebenfalls als MessageBox() anzeigen
MessageBox(NULL, pErrorMessage, WNDCLASSNAME, MB_OK);
// Das Programm mit einem Fehlercode verlassen
exit(-1);
}
/*--------------------------------------------------------------------------------
Name: exitOnError
Description:
Gibt eine Fehlermeldung aus.
Parameters:
res - DirectX Fehlercode
pErrorMessage - Zeiger auf zusätzliche Nachricht, die den Fehler
beschreibt
Remarks:
Ruft zur eigentlichen Ausgabe exitOnError(const char *pErrorMessage) auf.
--------------------------------------------------------------------------------*/
void exitOnError(HRESULT res, const char *pErrorMessage)
{
char Buffer[256];
//
// Eine Beschreibung des DirectX-Fehlercodes anfordern
//
D3DXGetErrorStringA(res, Buffer, 200);
//
// Mit der eigentlichen Fehlermeldung verbinden
//
strcat(Buffer, "\n");
strcat(Buffer, pErrorMessage);
//
// Programm mit Fehlermeldung beenden
//
exitOnError(Buffer);
}
/*--------------------------------------------------------------------------------
Name: WindowProc
Description:
Behandlungsroutine für eingehende Nachrichten unseres Fensters.
Parameters:
hwnd - Das Handle des Fensters, für das die Nachricht gedacht ist.
msg - Die Nachrichten-ID, die an das Fenster gesand wurde.
wparam - Parameter 1 der Nachricht.
lparam - Parameter 2 der Nachricht.
Return Value:
0, wenn die Nachricht bearbeitet wurde.
Remarks:
Auf den Tastendruck [ESC] wird das Flag zum Beenden des Programms
gesetzt.
--------------------------------------------------------------------------------*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
//
// Auf Tastendruck von [ESC] das Flag zum Beenden des Programms setzen
//
case WM_KEYDOWN:
switch(wparam)
{
case VK_ESCAPE:
g_Quit = true;
}
return 0;
//
// Bei eingehender WM_CLOSE-Nachricht das Programm beenden
//
case WM_CLOSE:
g_Quit = true;
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
//
// Alle unbehandelten Nachrichten an die Standard-Behandlung weiterleiten
//
return (DefWindowProc(hwnd, msg, wparam, lparam));
}
/*--------------------------------------------------------------------------------
Name: WinMain
Description:
Hauptschleife
Parameters:
Instance - Handle unseres Programms
PrevInstance - Handle einer zuvor geöffneten Instanz unseres Programms.
Meist NULL, weil das Programm nur einmal geöffnet wird.
pCmdLine - Die Kommandozeilenparameter
Show - Gibt an, ob das Programm normal, maximiert, ninimiert angezeigt
werden soll. Für uns nicht wichtig.
Return Value:
Exit-Code des Programms. Bei fehlerfreier Beendigung 0.
--------------------------------------------------------------------------------*/
int APIENTRY WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR pCmdLine, int Show)
{
MSG msg;
// Wir merken uns das Handle unserer Instanz, da wir es später noch
// benötigen
g_Instance = Instance;
// Fenster der Applikation erzeugen
createWindow();
// Direct3D initialisieren
initDirect3D();
//
// Nachrichten "pumpen" bis der Benutzer das Programm verlassen will
//
while (g_Quit == false)
{
// Liegen Nachrichten in der Nachrichten-Schlange?
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)
{
// Ja! Dann Standard-Weiterleitung
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Unsere Grafik anzeigen
render();
}
// Direct3D freigeben
releaseDirect3D();
// Fenster der Applikation entfernen
removeWindow();
// Programm mit Fehlercode 0 (kein Fehler) beenden
return 0;
}
|