Ich möchte einen Text mit DirectX 9 (August) ausgeben



  • Hallo,

    ich bin blutiger Anfänger mit DirectX, also ein bischen Gnade walten lassen. 😉

    Ich kann zwar ein blaues Fenster erzeugen, aber wenn ich dann die Schrift ausgeben will, gibt es einen Fehler.

    Der Kompiler gibt mir folgende Meldung in einer MessageBox aus "Unbehandelte Ausnahme bei 0x004118c9 in erstes DirectX win.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00000000."

    Wenn ich die Zeile

    lpD3DFont->DrawTextA(NULL,reinterpret_cast<LPCSTR>(psz),-1, &r, DT_CALCRECT, TextColor);
    

    weglasse, dann wird das Programm normal ausgeführt. Allerdings ohne Schrift 😞
    Ich schätze mal, dass der fehler in der CreateD3DFont(void) liegt.

    Programmiert habe ich das ganze mit Visual Studio 2005

    //für den Code siehe unten :-)
    


  • schreib einfach

    lpD3DFont->DrawTextW(NULL,psz,-1, &r, DT_CALCRECT, TextColor);
    

    warum nutzt du überhaupt Unicode-Strings und nutzt aber Multibytefunktionen?



  • also scheinbar ist ja dein Prog eine Unicode-Anwendung, dann sollte es also auch reichen, wenn du nur DrawText schreibst, denn der Compiler kümmert sich dann drum



  • Hallo,

    danke für die schnelle Antwort. Ich habe die besagte Zeile geändert und siehe da ich brauche keinen Cast anzustellen.

    Jedoch tritt beim Ausführen die gleiche Exception auf. Irgendwas scheint noch nicht in Ordnung zu sein. Ich poste mal mein komplettes Programm (sobald die Textausgabe funktioniert, wollte ich DirectX in einer ersten DirectX Klasse auslagern).

    Grüße

    Fireball

    // Headerdatei
    #include <d3d9.h>
    #include <d3dx9.h>
    #include <wchar.h>
    #include <string>
    #include <iostream>
    using namespace std;
    
    // Anwendungsfenster erzeugen
    HWND CreateMainWindow(HINSTANCE hInstance);
    
    // Callback Funktion zur Nachrichtenbehandlung
    LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
    
    // Funktion zur Initialisierung von Direct3D
    BOOL InitDirect3D(HWND hWnd);
    
    // Direct3D-Objekte wieder freigeben
    void CleanUpDirect3D(void);
    
    // Font erstellen
    void CreateD3DFont(void);
    
    // Zeiger auf das Direct3D-Objekt (Interface)
    LPDIRECT3D9       lpD3D       = NULL;
    
    // Zeiger auf das Direct3D-Device
    LPDIRECT3DDEVICE9 lpD3DDevice = NULL;
    
    // Das Fensterhandle
    HWND hWnd = 0;
    
    // Zeiger auf das Direct3D-Font-Objekt
    LPD3DXFONT        lpD3DFont   = NULL;
    
    int WINAPI WinMain(HINSTANCE hInstance,//instance der Anwendung
    				   HINSTANCE hPrevInstance,
    				   LPSTR lpCmdLine,
    				   int nCmdShow)
    {
    	// Fenster erzeugen und das Handle speichern
    	hWnd = CreateMainWindow(hInstance);
    
    	//prüfen ob das Fenster erzeugt werden konnte
    	if(hWnd == 0)
    	{
    		MessageBox(0,TEXT("Das Fenster konnte nicht erzeugt werden"), TEXT("Fehler"),MB_OK);
    		return -1;
    	}
    
    	//DirectX initialisieren
    	if(!InitDirect3D(hWnd))
    	{
    		MessageBox(0,TEXT("DirectX konnte nicht initialisiert werden"), TEXT("Fehler"),MB_OK);
    		return -1;
    	}
    	else
    	{
    		MessageBox(0,TEXT("DirectX wurde initialisiert"), TEXT("Info"),MB_OK);
    	}
    
    	// Schrift erzeugen
        CreateD3DFont();
    
    	// Struktur, in der Informationen zur Nachricht gespeichert werden
    	MSG msg;
    
    	//Endlosschleife, die solange läuft, bis die Nachricht WM_QUIT empfangen wird
    	while(GetMessage(&msg,NULL,0,0))
    	{
    		// Nachricht dan die Callback Funktion senden
    		TranslateMessage(&msg);
    		DispatchMessage(&msg); //damit Windows die Callback Funktion aufrufen kann
    	}
    
    	CleanUpDirect3D();
    	return 0;
    }
    
    BOOL InitDirect3D(HWND hWnd)
    {
    	lpD3D = Direct3DCreate9(D3D_SDK_VERSION);
    
    	if(lpD3D == NULL)
    	{
    		return FALSE;
    	}
    
    	// Parameter für den Modus festlegen
    	D3DPRESENT_PARAMETERS PParams;
    	ZeroMemory(&PParams, sizeof(PParams));
    
    	PParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
    	PParams.hDeviceWindow = hWnd;
    	PParams.Windowed = TRUE;
    
    	PParams.BackBufferWidth = 800;
    	PParams.BackBufferHeight = 600;
    	PParams.BackBufferFormat = D3DFMT_A8R8G8B8; //Farbtiefe des BackBuffer ACHTUNG genau hingucken!!!
    
    	//Direct3D-Gerät anlegen
    	if(FAILED(lpD3D->CreateDevice(
    		D3DADAPTER_DEFAULT, //primäre GFX karte, man kann auch mehrere nutzen!!!
    		D3DDEVTYPE_HAL, //ja gib mir alles, GFX Hardwarebeschleunigung
    		hWnd, //wo soll DirectX reinzeichnen, wie übergeben dazu das Handle unseres Fenster
    		D3DCREATE_SOFTWARE_VERTEXPROCESSING, //bei Geometrieverarbeitung die GFX Karte nutzen
    		&PParams, //Zeiger auf unsere Einstellung
    		&lpD3DDevice
    		)))
    	{
    
    		return FALSE;
    	}
    
    	return TRUE;	
    }
    
    LRESULT CALLBACK MessageHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	D3DCOLOR ClearColor = D3DCOLOR_XRGB(0,0,0xFF); //blau
    
    	switch(msg)
    	{
    		case WM_DESTROY:
    				PostQuitMessage(0);
    				return 0;
    			break;
    
    		case WM_KEYDOWN:
    			switch(wParam)
    			{
    			case VK_ESCAPE: //bei ESC beenden
    					DestroyWindow(hWnd);
    				break;
    			}
    
    		//Das Fenster soll gezeichnet werden
    		case WM_PAINT:
    			D3DCOLOR TextColor = D3DCOLOR_XRGB(0xFF,0,0);
    
    				//blau zeichnen
    				lpD3DDevice->Clear(0,0,
    					D3DCLEAR_TARGET,
    					ClearColor,
    					0,0);
    
    				RECT r = {100, 100, 0, 0 };
    
    				wstring wstr = L"wide char string";
    				LPCWSTR psz = wstr.c_str();
    
    				lpD3DDevice->BeginScene(); 
    
    				lpD3DFont->DrawText(NULL,psz,-1, &r, DT_CALCRECT, TextColor);
    
    				lpD3DDevice->EndScene();
    
    				lpD3DDevice->Present(0,0,0,0);
    			break;
    	}
    
    	return DefWindowProc(hWnd,msg,wParam,lParam);
    }
    
    HWND CreateMainWindow(HINSTANCE hInstance)
    {
    	TCHAR szAppName[] = TEXT ("WindowClass"); //name der Anwendung
    	TCHAR szWindowName[] = TEXT ("DirectX"); //name des fensters
    
    	WNDCLASSEX wndClass = {
    		sizeof(WNDCLASSEX), //größe
    		CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW,	//stile
    		MessageHandler, //callback funktion
    		0,	
    		0,
    		hInstance,	//Anwendungsinstance
    		LoadIcon(NULL,IDI_WINLOGO),
    		LoadCursor(NULL, IDC_ARROW),
    		(HBRUSH)GetStockObject(WHITE_BRUSH),
    		NULL,
    		szAppName,
    		LoadIcon(NULL,IDI_WINLOGO)
    	};
    
    	//Fensterklasse registrieren, damit CreateWindowEx diese nutzen kann
    
    	RegisterClassEx(&wndClass);
    
    	return CreateWindowEx(
    		NULL,
    		szAppName,
    		szWindowName,
    		WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    		0, 0,
    		800, 600,
    		NULL,
    		NULL,
    		hInstance,
    		NULL);
    }
    
    void CleanUpDirect3D(void)
    {
    	//Objekte müssen in der Reihenfolge freigegeben werden, wie sie auch angelegt worden sind!
    	if(NULL != lpD3DFont)
        {
            lpD3DFont->Release();
            lpD3DFont = NULL;
        }
    
    	if(NULL != lpD3DDevice)
    	{
    		lpD3DDevice->Release();
    		lpD3DDevice = NULL;
    	}
    
    	if(NULL != lpD3D)
    	{
    		lpD3D->Release();
    		lpD3D = NULL;
    	}
    }
    
    void CreateD3DFont(void)
    {
    	// Struktur für das Font festlegen
    	LOGFONT font = {0};
    
    	wchar_t *Widen = L"Arial";
    	wcscpy(font.lfFaceName,Widen);
    
    	D3DXCreateFontIndirect(lpD3DDevice,reinterpret_cast<D3DXFONT_DESCW*>(&font),reinterpret_cast<LPD3DXFONT*>(lpD3DFont)); //es gibt 9 Möglichkeiten zu casten!!! *kotz*
    }
    


  • Ich hab den Fehler erst nicht gefunden, deshalb zunächst das, was ich erst schreiben wollte.

    Also dein Problem ist, dass das D3DXCreateFontIndirect fehlschlägt. Probier vielleicht einmal D3DXCreateFont aus. Außerdem kommts mir etwas merkwürdig vor, die LOGFONT Struktur einfach komplett auf 0 zu setzen. Ach ja, und warum nimmst du überhaupt eine LOGFONT-Struktur anstatt einer D3DXFONT_DESC?
    Der Error-Code, den D3DXCreateFontIndirect ausgibt, ist D3DERR_INVALIDCALL.

    So, aber dein eigentlicher Fehler: Hier

    reinterpret_cast<LPD3DXFONT*>(lpD3DFont)

    .
    Casts sind schon eine gefährliche Sache, hm? Müsste eigentlich "&lpD3DFont" sein.
    Text zeigts bei mir zwar auch nicht an, aber es gibt keine NULL-Pointer-Exception



  • Hallo!

    Danke, danke, danke!!!

    Es funktioniert nun, ich habe alle Ratschläge befolgt und bin nun an mein Ziel gelangt.

    Nun woran lag es?

    1. Unicode wurde in meinem Projekt verwendet, dass habe ich erstmal ausgestellt.
    So konnte ich mir einige blöde Casts sparen.

    2. Meine CreateFont Methode sieht nun so aus ...

    void CreateD3DFont(void)
    {
    // Create a colour for the text - in this case blue
    D3DCOLOR fontColor = D3DCOLOR_ARGB(255,0,0,0);  
    
    // Create a rectangle to indicate where on the screen it should be drawn
    RECT rct;
    rct.left=2;
    rct.right=780;
    rct.top=10;
    rct.bottom=rct.top+20;
    
    //Das folgende habe ich von http://www.toymaker.info/Games/html/text.html
    D3DXCreateFont( lpD3DDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial", &lpD3DFont );
    
    lpD3DFont->DrawText(NULL, "Hello World", -1, &rct, 0, fontColor );
    }
    

    3. Der Aufruf fand dann wie folgt statt.

    lpD3DDevice->BeginScene(); 
    
    CreateD3DFont(); //Schriftzug ausgeben
    
    lpD3DDevice->EndScene();
    

    Grüße

    Fireball



  • nur so ganz nebenbei ... ich hab da mein problem mit diesem D3DXFONT ... hab das aber auch schon anders gelösst ...

    also jedes mal nen font zu generieren (CreateFont...) ist doch in 99,9% aller fälle das selbe -> es müsste doch nur einmal gemacht werden -> hab es bei der init prozedur reingenommen und das font objekt mit in die klasse wo die ganze DX-api aufrufe bearbeitet werden gelegt -> per cut & paste ... aber da kamms zum Error ähnlich wie zum anfang beschrieben also hab ich mir nix dir nixh die zwei sachen wieder vor DrawText gesetzt und was passiert - es funktioniert ... wieder zurück ... error;

    also wenn ich das selbe bei Texturen, Vertexbuffer und etc mache hab ich am ende bei nur einem polygon doch nur noch eine 1fps und so musses doch beim font doch auch möglich sein den font vorzeitig zu initialisieren und dann nur noch zu "drawen"

    aber wie gesagt ich hab jetzt meinen eigene "Drawtext"-api gemacht 😉 und das ist auch für Console optimiert.

    ich mach das mit nem bmpfile im Speicher sobald was in die console kommt wird diese "aktuallisiert" und die consolen textur geupdated und wenn console an ist wird nur die textur gezeichnet - ok hat bislang den "bug" das es nur xzeichen lang sein darf aber das werd ich beim nächsten optimieren beheben 😉 mir viel auch eben was ein 🕶



  • FireballGFX schrieb:

    Nun woran lag es?

    Haettest du mal den Debugger genommen und selbst nach dem Fehler gesucht anstatt hier dumm zu fragen, dann wuesstest du es. Das hier keiner eine Glaskugel hat, ist dir schon klar. f'`8k

    Autocogito

    Gruß, TGGC (\-/ has leading)



  • für dich mal so ganz neben bei TGGC:

    es liegt daran das man

    ID3DXFont myfont;
    myfont->create(.......);
    myfont->drawtext(.........);

    so nach einander aus führen muss, ich habs versucht myfont in die klasse von mein 3drenderer objekt zu definieren bei init3d als letztes myfont->create durch zufüren ... aber wie ichs schon beschrieben hatte funktionierte dies nicht, obwohl ichs per copy & paste verändert hatte



  • nur dumme Antworten!

    Dieses Zitat finde ich passend, stand auf deinem tollen Link 🙂

    "Falls du bereits gesucht hast, bist du wahrscheinlich falsch an die Sache herangegangen. Wenn du alle oben genannten Hinweise ausprobiert hast trotzdem noch keine Loesung gefunden hast, frag' einfach nach."

    Aber ich bin trotzdem Froh, dass es doch noch nette Menschen gibt, die sich etwas Zeit genommen haben und mir zur Seite Standen!

    Gruß

    Fireball



  • @FireballGFX: np, verteile gerne meine Weisheit.

    @LinkeT: Bitte hoer auf anderen Scheisse zu erzaehlen, nur weil du zu dumm zum Programmieren bist. f'`8k

    Autocogito

    Gruß, TGGC (\-/ has leading)



  • Du hast Recht, ich sollte das nächste mal erstmal genauer hingucken und keine MessageBox ausgeben, bevor nicht wirklich alles initialisiert wurde. Nachdem ich diese rausgenommen hatte funktionierte es wie in meinem DirectX Buch beschrieben.

    So und das soll es jetzt von meiner Seite aus gewesen sein.

    Aber vielleicht trifft man sich ja mal auf der Breakpoint. Wer hat dicke E***? 🙂

    Gruß
    Fireball



  • TGGC schrieb:

    @FireballGFX: np, verteile gerne meine Weisheit.

    @LinkeT: Bitte hoer auf anderen Scheisse zu erzaehlen, nur weil du zu dumm zum Programmieren bist. f'`8k

    Autocogito

    Gruß, TGGC (\-/ has leading)

    ja aber mal nicht gleich beleidiggen 😉
    deine weisheiten helfen aber keinem weiter aber :psst: ich nems nich persönlich nicht jeder kann seine dumme kommentare einfachmal weglassen ....

    EDIT ich könnt auch in meinem Profil Softwareentwickler eintragn und keine fragen stellen und nur dumme Kommentare abgeben - würd gar net auffallen ...


Anmelden zum Antworten