Ansicht von 11 Beiträgen - 1 bis 11 (von insgesamt 11)
  • Autor
    Beiträge
  • #1149
    azrael
    Teilnehmer

    Aus den selben Gründen, aus welchen ich auch das C++ Tutorial schreibe, schreib ich nun ein DirectX – Tutorial. Hierzu sei gesagt, dass die Voraussetzung für dieses Tutorial die Kenntnis der Programmiersprache C++ und der WinAPI, ist. Zu beiden Themen schreibe ich auch Tutorials.

    Aber nun erstmal: Was ist DirectX?

    Es ist eine Sammlung von APIs (Application Programming Interfaces), die vor allem für das Programmieren von Spielen geeignet ist. Verwendet wird DirectX auf Windows-PCs und der Xbox. Das „direct“ sagt aus, dass die APIs direkt auf die Hardware zugreifen können, das heißt, dass die damit erstellten Programme/Spiele sehr schnell sind.

    Wichtigste Bestandteile von DirectX:

    Direct3D: Die API für das Programmieren von Grafiken, sowohl 3D als auch 2D, früher gab es noch DirectDraw, in den neusten Versionen nicht mehr

    DirectSound: Die API für Soundprogrammierung. Hat mehr Effekte als ein Heavy Mettaler für seine E-gitarre ;)

    DirectInput: Die API für Eingabeprogrammierung, d.h: Maus, Tastatur, Joystick, Gamepad, Lenkrad usw… Wird z.B für force-feedback benötigt.

    DirectPlay: API für Netzwerkprogrammierung, verursacht extremen Overhead, deswegen verwenden Spieleentwickler meistens WinSock dafür.

    Nun zum Tutorial ( Wieder aus meinem Forum kopiert =) ) :

    Nach ein wenig Überlegung, hab ich mich entschieden, parallel zum C++ Tutorial ein DirectX Tutorial zu schreiben. Da ich das ja nicht nur dazu mache, um Informationen an andere weiterzugeben, sondern auch, um mein eigenes Wissen zu festigen, finde ich das besser, wenn ich beide Tutorials gleichzeitig schreibe.
    Die Voraussetzung für dieses Tutorial ist Kenntnis der Programmiersprache C++ sowie die Grundlagen der WinAPI (zu welcher ich logischerweise erst später ein Tutorial schreiben werde >.<). Als Compiler verwende ich hierbei das Microsoft Visual C++ 2005 Express Edition, welches hier kostenlos runtergeladen werden kann. Um mit DirectX jedoch arbeiten zu können, muss man einige Änderungen vor dem Start vornehmen. 1) Benötigte SDKs
    Als erstes braucht man das Plattform SDK von Microsoft, die aktuellste Version gibt es immer hier.

    Achtung:
    Wenn man kein Windows Prof. 64 Bit Edition installiert hat, dann lädt man die PSDK-x86.exe Datei runter, egal, welchen Prozessor man hat. Hat man die 64 Bit Version, dann lädt man für eine 64 Bit CPU von AMD die Datei PSDK-amd64.exe und für eine Intel CPU die Datei PSDK-ia64.exe runter.

    Die SDK solltet ihr nun installieren, habt ihr das geschafft, geht’s mit der nächsten schon weiter – der DirectX SDK (Dowloadlink <- August 2006). Installieren. Das war’s mit der Installation… Jetzt kommt die Konfiguration – und zwar von Microsoft Visual C++ 2005 Express Edition. 2) Konfiguration
    1 Schritt: Die Pfadangaben ergänzen
    Klickt euch in das Installationsverzeichnis von MS VC++ 2005 EE und von dort aus in das Unterverzeichnis VCvcpackages dort öffnet ihr die Datei „VCProjectEngine.Dll.Express.Config“ mit dem Editor. Dort sollte ungefähr sowas stehen:

    Code:

    Nun müsst ihr sechs Zeilen hinzuschreiben, so dass die Datei danach so aussieht:

    Code:

    Wobei ihr nun aufpassen müsst, wohin ihr das Platform SDK und die DirectX SDK installiert habt, die Eingabe C:ProgrammeMicrosoft Platform SDK und C:ProgrammeMicrosoft DirectX SDK (August 2006) kann bei euch anders sein – es ist aber immer das Installationsverzeichniss vom PSDK.

    2 Schritt:
    Zusätzliche Abhängigkeiten vom Linker
    Danach geht’s ins Verzeichnis VCVCProjectDefaults (vom Installationspfad des VC++). Dort findet ihr die Datei corewin_express.vsprops, diese öffnet ihr auch und ergänzt die Zeile AddtionalDependencies – danach sollte sie so aussehen

    AddtionalDependencies = „kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib” />

    3 Schritt WIn32 Projekte ermöglichen:
    Und die letzte Datei für die allgemeine Einstellung – AppSettings.htm im Unterordner VCVCWizardsAppWizGenericApplicationhtml1031 (mit editor öffnen)

    Dort macht ihr in den Zeilen 441 bis 444 die Schrägstriche vor den Zeilen Weg, sollte dann so aussehen:

    Code:
    WIN_APP.disbled = true;
    WIN_APP_LABEL.disabled = true;
    DLL_APP.disabled = true;
    DLL_APP_LABEL.disabled = true;

    4 Schritt Abhängigkeiten eines Projektes
    Die allgemeine Konfiguration ist vorbei, jetzt zur Projektkonfiguration: das müsst ihr immer machen, wenn ihr ein DirectX-Projekt erstellt.

    Nach der Erstellung des Projektes geht ihr in der symbolleiste auf Projekt -> {Projektname}-Eigenschaften-> Konfigurationseigenschaften ->Linker->Eingabe bei zusätzliche Abhängigkeiten drückt ihr auf die drei Punkte und fügt folgende libs hinzu:

    d3dxof.lib
    dxguid.lib
    d3dx9d.lib
    d3d9.lib
    winmm.lib
    comctl32.lib
    dsound.lib
    dinput8.lib
    shlwapi.lib

    Jedes von den libs muss in eine neue Zeile geschrieben werden. So – endlich fertig mit der Konfiguration – ich muss ehrlich zugeben ich hab teilweise aus dem Buch „Inside Microsofts DirectX 9 Spieleprogrammierung“ die Sachen abgeschrieben,. Naja die rechte liegen beim Autor oder so – ich kenn mich mit Copyright nicht so wirklich aus^^
    Jetzt geht’s aber an den Quellcode.

    3) Der Code
    Was soll das Programm überhaupt machen? Es wird ein Fenster erzeugt, in welchem ein Direct3D Device erstellt wird, mit welchen das Fenster gesäubert wird. Klingt einfach? Im Vergleich zu HDR Rendering, Displacement mapping usw. ist es einfach, aber im Vergleich zum klassische „Hello World“, wenn man eine Programmiersprache…. Egal – ihr werdet’s selber sehen.

    Fügt dem leeren Win32-Projekt eine neue C++ Datei hinzu und los geht’s:

    Code:
    #include //die DirectX-Header Datei

    Was das jetzt ist, sollte euch klar sein, oder ihr seid hier mächtig falsch – lernt C++ zuerst ;)
    Die windows.h (für WinAPI) brauchen wir nicht extra einzufügen – die ist in der d3d9.h includet
    Übrigens: lest die Kommentare, die Information ist zum größten Teil in denen enthalten.

    Code:
    LPDIRECT3D9 g_pD3D = NULL; // Das Direct3D Device
    LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Das Rendering-Device

    LP im Namenvorsatz heißt long pointer (to), da er auf eine Struktur zeigt, handelt es sich hierbei um einen Handle (Vielen Dank an Skabus, dass er mir das endlich erklärt hat >.<) Mehr zu Handles im kommenden WinAPI-Tutorial.
    Der Präfix g_p heißt global pointer.

    Code:
    HRESULT InitD3D( HWND hWnd )
    {
    // Ein D3D Objekt erstellen, dass für die Erstellung des D3DDevice
    // benötigt wird
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
    return E_FAIL;

    Die Funktion erstellt ein Direct3D Device für das Fenster, das via Handle übergeben wird.
    Hier sollte ich was dazu sagen: HRESULT ist der Rückgabecode einer Schnittstelle. Er ist immer 0, wenn die Funktion erfolgreich war. Sollte sie fehlschlagen, wird der Fehlercode zurückgegeben, dass ist dann immer das, was man so gerne am Bildschirm sieht: „blablabla unter der Adresse 0xFF5100AB blabla bla fehler code 0xF0A05F32 blablabla“. Jetzt fällt einem aber auf -> das ist doch eine if-anweisung, da wird doch nichts erstellt!
    Doch wird es^^. Man erinnere sich an den typischen Programmierfehler: = anstatt ==, wenn man etwas vergleichen will. Hier wird das ausgenutzt – g_pD3D wird gleichzeitig etwas zugewiesen und mit Null verglichen. Praktisch – ist es dann = NULL, dann gibt die ganze Funktion E_FAIL zurück (wen das interessiert: E_FAIL ist 0x80004005)

    Code:
    // Hier wird mit der Struktur D3DPRESENT_PARAMETERS d3dpp deklariert
    // und teilweise definiert
    // Wir stellen Windowed auf TRUE, da wir das ganze ja in einem
    // Fenster sehen wollen
    // SwapEffect wird auf discard gestellt, soll angeblich die beste
    // Methode sein, den Backbuffer mit dem Frontbuffer zu vertauschen
    // (der Swap – Befehl vertauscht die beiden, wer mehr erfahren will,
    // geht auf de.wikipedia.org/wiki/Backbuffering)
    // das BackBufferFormat stellt man auf D3DFMT_UNKNOWN, was bedeutet,
    // dass das Format vom Display automatisch verwendet wird
    // Zero Memory füllt einen Speicherbereich mit Nullen, der erste
    // Parameter ist die anfangsadresse für den Speicherblock und der
    // zweite die Länge des zu füllenden Speicherbereich

    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

    // Wir erzeugen ein D3DDevice – dafür ist die Funktion CreateDevice
    // zuständig – der erste Parameter ist der Video Adapter, also die
    // Grafikkarte, die genutzt wird, die meisten PCs haben ja nur eine,
    // bzw. SLI wird ja auch als einzelner Adapter genutzt – also
    // schreiben wir D3DADAPTER_DEFAULT hin, um den Standartadapter zu
    // nutzen, der zweite Parameter ist der Device Typ – mit
    // D3DDEVTYPE_HAL sagen wir dem Programm, lieber Hardware als
    // Software zu benutzen. Der dritte Parameter ist der Handle zum
    // Fenster. Danach kommen die Verhaltensflags (mit einem | getrennt
    // mehrere angaben möglich). D3DCREATE_SOFTWARE_VERTEXPROCESSING
    // läuft auf allen Karten, ist hardware vertexprocessing unterstützt,
    // dann ist die ersetzung des software durch hardware eine
    // leistungsbeschleunigung. Eins von denen (oder …_MIXED_…) muss
    // aber vorkommen, D3D…_NOWINDOWCHANGES zeigt an, dass Direct3D das
    // Fokus-Fenster nicht verändern darf, der nächte Parameter ist die
    // adresse zu einer D3DPRESENT_PARAMETERS – Struktur und der letzte
    // ist die Adresse von einem pointer zu dem Zurückzugebenden
    // IDirect3DDevice9.
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
    hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_NOWINDOWCHANGES,
    &d3dpp,
    &g_pd3dDevice ) ) )
    {
    return E_FAIL; // ist gleich 0x80004005 ^^
    }

    // Originalkommentar: Device state would normally be set here. Punkt

    return S_OK;
    }

    Jetzt ist der Initialisierungsfunktion fertig ;). Jetzt brauchen wir noch die umgekehrte Funktion: die die alles wieder freigibt.

    Code:
    VOID Cleanup()
    {
    if( g_pd3dDevice != NULL)
    g_pd3dDevice->Release(); //lässt wörtlich das Device los

    if( g_pD3D != NULL)
    g_pD3D->Release(); //dasselbe hier
    }

    Warum ist das destruktive immer einfacher?^^
    Nun brauchen wir noch die Renderfunktion (Das, was das bild ans fenster malt)

    Code:
    VOID Render()
    {
    if( NULL == g_pd3dDevice )
    return;

    // Die Funktion löscht den BackBuffer und füllt ihn mit i-ner Farbe
    // Die Funktion arbeitet mit Rechtecken (D3DRECT – Strukturen) – der
    // erste Parameter ist die anzahl der Rechtecke im Array, das im
    // zweiten Parameter übergeben wird, im dritten Parameter wird
    // gesagt, dass das Renderziel gesäubert werden soll, der nächste
    // gibt die Farbe im ARGB Format an (die Werte in der Klammer: zuerst
    // rot, dann Grün, dann Blau), der nächte Wert ist die Tiefe des
    // Tiefenbuffers (von 0 bis 1, float) und danach worauf der stencil
    // Buffer gesetzt wird. Ich empehle übrigens, in der Directx SDK
    // Dokumentation alle funktionen nachzublättern, da könnt ihr einige
    // Informationen finden
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(40,100,150), 1.0f, 0 );

    // Beginn der Szene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
    // Hier wird alles gerendert, was gerendert werden soll

    // die Szene beenden
    g_pd3dDevice->EndScene();
    }

    // den Inhalt des Backbuffers auf den Bildschirm zaubern
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
    }

    // Den Messagehandler werde ich hier nicht erklären, erstens weil das
    // Tutorial eh riesig ist und zweitens weil ich das im WinAPI tut machen
    // werde
    LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
    {
    switch( msg )
    {
    case WM_DESTROY:
    Cleanup(); // Devices releasen
    PostQuitMessage( 0 );
    return 0;

    case WM_PAINT:
    Render(); // Sachen rendern
    ValidateRect( hWnd, NULL ); // Zeigt einen Rechteckigen
    // Bereich im Fenster (1 Param)
    // indem ein RECT (2 Param) von
    // der sich aktualisierenden
    // Fläche entfernt wird, bei NULL
    // wird alles angezeigt
    return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
    }

    // WinMAIN (main funktion der WinAPI)
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
    {
    // Fensterklasse registrieren (wird im WinAPI – tut näher erklärt)
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
    GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, „D3D Tutorial“, NULL };

    RegisterClassEx( &wc );

    // Fenster der Anwendung erstellen (näheres im WinAPI – tut)
    HWND hWnd = CreateWindow( „D3D Tutorial“, „D3D Tutorial 01: CreateDevice“,
    WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
    NULL, NULL, wc.hInstance, NULL );

    // Direct3D initialisieren – der Folgende code soll nur ausgeführt
    // werden, wenns klappt
    if( SUCCEEDED( InitD3D( hWnd ) ) )
    {
    // Das Fenster zeigen
    ShowWindow( hWnd, SW_SHOWDEFAULT );
    UpdateWindow( hWnd );

    // Messageschleife (näheres im WinAPI-tut)
    MSG msg;
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
    TranslateMessage( &msg );
    DispatchMessage( &msg );
    }
    }
    // Die Fensterklasse unregistrieren
    UnregisterClass( wc.lpszClassName, wc.hInstance );
    return 0;
    }

    Und für dieses bisschen nichts habe ich so lange gebraucht >.<. Jetzt schreib ich den nächsten Teil des C++ Tuts. Kritik bitte in den dazugehörigen Kritik-Thread

    Achso: Tutorial © by Azrael, il Meraz

    Hab ne tolle Seite gefunden: auf http://www.directx9.de/ hat man immer die Links zu der aktuellstens DirectX SDK

    #3143
    me1357
    Teilnehmer

    Hmm .. void schreibt man in C++ eigentlich üblicherweise klein, und nicht gross (VOID) so wie du das gemacht hast.
    Ob und bei welchen Compilern das zu einem Fehler führen könnte, weiss ich zwar nicht, aber auf jeden Fall sieht der Code dadurch reichlich merkwürdig aus.
    Selbiges auch zu int.

    #3144
    azrael
    Teilnehmer

    Das sind keine üblichen C++ – Datentypen, sondern Windows – Datentypen, wenn du eine Übersicht haben willst – http://windowssdk.msdn.microsoft.com/en-us/library/ms736992.aspx das würde bei vielen Compilern zu fehlern führen, wenn man die d3d9.h nicht einbindet ;)

    #3145
    me1357
    Teilnehmer

    Windows-Datentypen .. ich seh schon, da war Microsoft ja echt kreativ.

    Der dazugehörige Code:

    Code:
    #define VOID void

    :floet:
    Manchmal frag man sich echt, was die Programmierer da den ganzen Tag lang machen.

    Gibt es einen ernstzunehmenden Grund dafür VOID statt void zu benutzen?

    #3146
    azrael
    Teilnehmer

    nein.

    öhm – das ist so ne Sache – auf so fragen würden dir Microsoftler wohl die selbe Antwort liefern, wie google, wenn du nach „the answer to life, the universe and everything“ (ohne anführungsstriche) suchst. naja, das war wohl OT und ich muss mal den zweiten Teil des C++ Tuts schreiben :wtf:

    #3147
    whitenexx
    Teilnehmer

    Habe gelesen, dass nur Windows Vista DirectX10 haben/unterstützen wird. Deswegen werden Gamer nicht an Vista vorbeikommen. Wenn das stimmt, heißt das, dass man seine entwickelten Spiele/Games nur unter Microsoft Produkten spielen/ausführen kann?
    Oder gibt es eine Möglichkeit die Games auch für andere Systeme wie z.B. Linux zu kompilieren?

    #3148
    azrael
    Teilnehmer

    wenn man plattformunabhängige APIs nutzt, wie z.B: Allegro oder OpenGL, dann lässt sich das Problem vermeiden. DirectX ist aber die Schnellste, (Obwohl – OpenGL ist glaub ich gleich schnell), außerdem werden sich die meisten nicht die Mühe machen, eine andere API zu lernen – DirectX ist schon wahnsinnig groß und komplex.

    btw: Unter Linux gabs doch immer Emulatoren für DirectX – wenn die Hardware stark genug ist, dann lässt sich jedes Spiel problemlos Spielen

    #3149
    whitenexx
    Teilnehmer

    Es gibt für fast alles Emulatoren und Virtuallisierungssoftware.
    Aber das ist nicht das wahre. Naja aber es gibt ja dann noch OpenGL…das freut mich.
    Die Games die man mit C++ und DirectX entwickelt, laufen die auch auf der XboX? Oder muss man da wieder andere Sachen beachten? Ausser jetzt die EingabeHarware.
    MfG

    #3150
    azrael
    Teilnehmer

    Zitat aus Wikipedia:

    Quote:
    DirectX [dajÌr[ktÈ[ks] ist eine Sammlung von Application Programming Interfaces (APIs) für Multimediaprogramme (besonders Spiele) auf der Windows-Plattform und findet auch auf der Spielekonsole Xbox Verwendung.

    Ja das geht, aber der Umgang mit DirectInput ist etwas anders als bei PC. Ansonsten: PC Spiele lassen sich wunderbar auf die XBox portieren. Naja – manchmal klappt das nicht so mit der Leistung^^ aber XBox360 ist ja schneller

    #3151
    whitenexx
    Teilnehmer

    Schön schön :piece: Und hast du schon welche Spiele entwickelt oder rausgebracht/veröffentlicht?

    #3152
    azrael
    Teilnehmer

    das was ich entwickelt habe, würde die Welt in Schrecken versetzen, wenn ich es veröffentlichen würde…

    öhm – ein vertikal Shooter im welchem man nicht sterben konnte (nicht mal mit DirectX geproggt >.<) und ein ziemlich langes Textadventure. Beide Spiele sind nicht mehr existent, weil sie mir peinlich waren :wtf: mein nächstes projekt ( nach dem lernen von DirectX ) wird wohl was RPG - mäßiges sein. Aber ich glaube mal ich werde das dann auf meinem Forum präsentieren...

Ansicht von 11 Beiträgen - 1 bis 11 (von insgesamt 11)
  • Du musst angemeldet sein, um auf dieses Thema antworten zu können.