bitmap auf fenstergröße skalieren



  • hi,

    ich versuche gerade ein ganz normales Fenster mit OpenGL zu erstellen in dem dann eine Bitmap erscheint, die immer exakt auf den Fensterrahmen angepasst ist, also immer das komplette Fenster überdeckt. Ich habe momentan allerdings noch zwei Probleme:

    1. Wenn ich das Programm starte, werden mit nur ein paar zufällige Pixel angezeigt, nicht meine Bitmap, und das obwohl sie eigentlich per WM_PAINT Nachricht gezeichnet werden sollte.

    2. Wenn ich das Fenster dann skaliere, erscheint die Bitmap und vergrößert/kleinert sich auch wunderbar mit dem Fenster. Allerdings hab ich bunte Linien, die sich durch das Bild ziehen (je kleiner die Bitmap, desto dichter die Linien)

    hier sind die beiden wichtigsten Funktionen:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        BITMAP				bitmap;
    	static int			client_x;
    	static int			client_y;
    	static int			source_x;
    	static int			source_y;
    	static HBITMAP		hBitmap;
        static HINSTANCE	hInstance;
    	HDC					hDC, hDCMem;
    	PAINTSTRUCT			ps;
    
        switch(uMsg)
        {
    		case WM_CREATE:
    		{
    			hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
    			hBitmap = (HBITMAP)LoadImage(hInstance, TEXT("menu.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    
    			GetObject(hBitmap, sizeof(BITMAP), &bitmap);
    
    			source_x = bitmap.bmWidth;
    			source_y = bitmap.bmHeight;
    
    			return 0;
    		}
    
    		case WM_SIZE:
    		{
    			client_x = LOWORD(lParam);
    			client_y = HIWORD(lParam);
    
    			return 0;
    		}
    
    		case WM_PAINT:
    		{
    			hDC = BeginPaint(hWnd, &ps);
    	        hDCMem = CreateCompatibleDC(hDC);
    
    			SelectObject(hDCMem, hBitmap);
    
    			StretchBlt(hDC, 0, 0, client_x, client_y, hDCMem,
    					   0, 0, source_x, source_y, SRCCOPY);
    
    			DeleteDC(hDCMem);
    			EndPaint(hWnd, &ps);
    
    			return 0;
    		}
    
    		case WM_DESTROY:
    		{
    			DeleteObject((HBITMAP)hBitmap);
    			PostQuitMessage(0);
    
    			return 0;
    		}
    
    		case WM_ACTIVATE:
    		{
    			if(!HIWORD(wParam))
    			{
    				active = true;
    			}
    			else
    			{
    				active = false;
    			}
    
    			return 0;
    		}
    
    		case WM_SYSCOMMAND:
    		{
    			switch(wParam)
    			{
    				case SC_SCREENSAVE:
    				case SC_MONITORPOWER:
    
    					return 0;
    			}
    
    			break;
    		}
    
    		case WM_CLOSE:
    		{
    			PostQuitMessage(0);
    
    			return 0;
    		}
    
    		case WM_KEYDOWN:
    		{
    			keys[wParam] = true;
    
    			return 0;
    		}
    
    		case WM_KEYUP:
    		{
    			keys[wParam] = false;
    
    			return 0;
    		}
    
    	}
    
    	return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	HWND			hWnd;
    	MSG				msg;
    	LOGBRUSH		background;
    	BOOL			done = false;
    
    	if(MessageBox(NULL, L"Would You Like To Run In Fullscreen Mode?",  L"Start FullScreen?",
    				  MB_YESNO | MB_ICONQUESTION) == IDNO)
    	{
    		fullscreen = false;
    	}
    
    	if(!CreateGLWindow(L"Test", 640, 480, 16, fullscreen))
    	{
    		return 0;
    	}
    
    	while(!done)
    	{
    		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    		{
    			if(msg.message == WM_QUIT)
    			{
    				done = true;
    			}
    			else
    			{
    				TranslateMessage(&msg);
    				DispatchMessage(&msg);
    			}
    		}
    		else
    		{
    			if(keys[VK_ESCAPE])
    			{
    				done = true;
    			}
    			else
    			{
    				SwapBuffers(hDC);
    
    				if(keys[VK_F1])
    				{
    					keys[VK_F1] = false;
    					KillGLWindow();
    					fullscreen = !fullscreen;
    
    					if(!CreateGLWindow(L"Test", 640, 480, 16, fullscreen))
    					{
    						return 0;
    					}
    				}
    			}
    		}
    	}
    
    	KillGLWindow();
    
    	return(msg.wParam);
    }
    


  • Ich denke nicht, dass es gut ist, auf einen OpenGL Context mit GDI Funktionen zu zeichnen... Wenn du schon OpenGL benutzt, dann zeichne auch damit.



  • das hätte ich auch gerne getan.

    aber die Methode mit StrtchBlt() ist die einzige, mit der ich eine Bitmap auf die jeweilige Fenstergröße anpassen kann. Wie das mit OpenGL geht, weiß ich leider nicht.



  • Orthografische Projektion verwenden (glOrtho, gluPerspective), den Viewport auf Bildschirm-Auflösung mappen (glViewport) dann das Bitmap als Quad mit Textur in Bildschirmgrösse rendern. Fertig 🙂
    (bei NeHe findest du Tutorials zu 2D Rendering, ist gar nicht so schwer)



  • und genau da komm ich her 🙂

    die NeHe Tutorials hab ich nämlich, wie unschwer zu erkennen, als Grundlage für das Programm benutzt. Es hängt aber hier:

    Cpp_Junky schrieb:

    dann das Bitmap als Quad mit Textur in Bildschirmgrösse rendern.

    Wie mache ich das Quad genauso groß wie den Bildschirm? Gibts da ein Makro oder etwas ähnliches?



  • Wenn der Viewport im Ortho Modus korrekt eingestellt ist zeichnest du einfach ein Quad von 0,0 nach xRes, yRes (Das ist die Auflösung in X und Y Richtung 😉 ) Ich bin mir aber nicht sicher, ob NeHe den Viewport genauso einstellt und bin auch grad zu faul zum nachgucken :p



  • und ohne ortho geht's genauso einfach:
    matrizen reseten, field of view (gluPerspective) auf 90 grad stellen und ein quad von -a,-a - +a,+a bei z=-a zeichnen.
    wenn man sich das entsprechende view-frustum vorstellt, ist auch leicht einzusehen, warum das so ist.



  • also für mich hört sich das so an:

    glBegin(GL_QUADS);
    		glTexCoord2f(0.0f, 0.0f); glVertex3f(-xRes, yRes, 0.0f);
    		glTexCoord2f(1.0f, 0.0f); glVertex3f( xRes, yRes, 0.0f);
    		glTexCoord2f(1.0f, 1.0f); glVertex3f( xRes, yRes, 0.0f);
    		glTexCoord2f(0.0f, 1.0f); glVertex3f(xRes, yRes, 0.0f);
    	glEnd();
    

    aber das funktioniert nicht. ich steh auf dem Schlauch 😞



  • hellihjb schrieb:

    z=-a

    Ich würde ja Ortho empfehlen 😉

    Schau mal hier: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=21

    Und beachte diese Zeile:

    glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f);				// Create Ortho 640x480 View (0,0 At Top Left)
    


  • richtig waer's zb so:

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerpsective(90, 1, 0.5, 2);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glBegin(GL_QUADS);
    // counter-clockwise:
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1, -1, -1);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1,  1, -1);
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1,  1, -1);
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1, -1, -1);
    glEnd();
    

    oder eben ortho...



  • also wenn ich die ortho-Methode mache, bleibt mein Fenster schwarz.

    Mit der anderen klappts ganz gut, nachdem ich glTranslatef(0.0f, 0.0f, -5.0f) weggemacht hab 🙂

    also danke schonmal



  • Ich habe hier nochmal eine Frage zu:

    Wenn ich es jetzt mit der nicht-ortho-Methode mache klappt das Zeichnen und skalieren wunderbar aber jedemal wenn die Zeichenfunktion aufgerufen wird dauert es 3 Sekunden bis er von dem glEnd() zum return true kommt und da steht sonst nichts mehr dazwischen.
    Das äußert sich natürlich dadurch dass das Fenster beim starten/skalieren/maximieren 3 Sekunden lang wie abgeschmiert wirkt bevor die Textur kommt.

    Und mit der ortho-Methode bekomme ich einen schwarzen Bildschirm. Muss ich hierbei

    glBegin(GL_QUADS);
    		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
    		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
    		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
    		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
    	glEnd();
    

    die z-Koordinaten nicht auch auf 0.0f setzen?



  • Muss ich hierbei die z-Koordinaten nicht auch auf 0.0f setzen?

    nein:
    da deine x,y-koordinaten bei der perspektivischen transformation durch z dividiert werden, wuerde dein polygon bei z=0 theoretisch unendlich gross - das willst du nicht und ist aus numerischen gruenden auch unmoeglich.

    jedemal wenn die Zeichenfunktion aufgerufen wird dauert es 3 Sekunden bis er von dem glEnd() zum return true kommt

    anhand deines bisher geposteten codes ist leider nicht nachvollziehbar wovon du redest.



  • int DrawGLScene(GLvoid)
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glLoadIdentity();
    	glBindTexture(GL_TEXTURE_2D, texture[0]);
    
    	glLoadIdentity();
    
    	glBegin(GL_QUADS);
    		glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
    		glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
    		glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
    		glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
    	glEnd();
    
    	return TRUE;
    }
    

    also, zwischen dem glEnd(); und dem return TRUE vergehen bei jedem Durchlauf ca. 3 Sekunden, auch wenn ich die Textur-Koordinaten auskommentiere.
    Erst wenn ich gar keine Textur mehr lade funktioniert es wieder reibungslos.

    Und noch eine Frage zu glOrtho: Reicht es also das gluPerspective durch glOrtho zu ersetzen? So hab ich das zumindest laut NeHe verstanden. aber warum bleibt mein Bildschirm dann schwarz?



  • glSwapBuffers vergessen?



  • while(!done)
    	{
    		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    		{
    			if(msg.message == WM_QUIT)
    			{
    				done = true;
    			}
    			else
    			{
    				TranslateMessage(&msg);
    				DispatchMessage(&msg);
    			}
    		}
    		else
    		{
    			if((active && !DrawGLScene()) || keys[VK_ESCAPE])
    			{
    				done = true;
    			}
    			else
    			{
    				SwapBuffers(hDC); // <--------------
    
    				if(keys[VK_F1])
    				{
    					keys[VK_F1] = false;
    					KillGLWindow();
    					fullscreen = !fullscreen;
    
    					if(!CreateGLWindow(L"Test", 640, 480, 16, fullscreen))
    					{
    						return 0;
    					}
    				}
    			}
    		}
    	}
    

    nein 🙂



  • benutze doch einfach den debugger um herauszufinden, wann warum keine ausgabe stattfindet - oder, aus der huefte geschossen:
    ueberleg dir mal, wann der konstante returnwert von "DrawGLScene" ueberhaupt ausgewertet werden muss, um deine bedingung fuer "glSwapBuffers" zu erfuellen.



  • naja das habe ich im Prinzip doch gemacht. Das Problem sind die 3 Sekunden, die zwischen dem glEnd() und dem return TRUE verloren gehen. Da steht kein Code dazwischen und es dauert trotzdem 3 Sekunden bis er von einer Sprungmarke zur nächsten kommt.

    Und auch das mit dem SwapBuffers sollte korrekt sein. Zum einen weil das Grundgerüst aus einem Tutorial von nehe.gamedev.net kommt und zum andern weil sich DrawGLScene() und SwapBuffers() ja immer abwechseln müssen und das tun sie auch.



  • weil mir das sehr bizarr vorkam, hab ich lesson01 von nehe geladen, deinen geposteten code reingepastet und es laeuft - wie erwartet - ohne schwierigkeiten.
    mehr zeit kann ich dir leider nicht widmen.



  • hm, dann hab ich wohl wirklich ein Treiber-Problem oder ähnliches, denn ich habe auch gerade ein Beispiel kompiliert und es passiert genau das gleiche wie bei meinem Programm.

    Habe aber in der letzten Zeit weder Treiber noch libs aktualisiert...

    /edit: ich weiß woran es liegt, es liegt an meinen Bitmaps. Mit einer Bitmap aus dem nehe Tutorial läufts einwandfrei. Aber was hab ich denn jetzt falsch gemacht? Ich hab einfach jpegs genommen und die per Paint in bmp gespeichert? Nimmt er das nicht?


Anmelden zum Antworten