OpenGL - Resize: Breiteskalierungsproblem



  • Hallo,

    ich bin gerade dabei, mein Windowsfenster mit OpenGL Resizen zu können, also dass sich die enthaltenen Elemente an die Fenstergröße anpassen.

    Ich kann alles super resizen, bis auf, dass ich die Breite des Fensters nie auf einen kleineren Wert als die Höhe des Fensters bringen kann.
    Wenn ich das mache, dann verschwindet mein angezeigtes Element sofort.
    Wenn ich das Fenster dann wieder breiter zieh, erscheint es aufeinmal wieder (nicht stückfürstück, sondern "zack" 😃 ).

    Mein Code (möglichst OOP):
    PS: Wenn ihr sonst noch Fehler findet, dann bitte Bescheid sagen 🙂

    stdafx.h:

    // ========== stdafx.H ========== //
    
    // ========== INCLUDES ========== //
    #include <Windows.h>
    
    //###### OPEN_GL - INCLUDES ######//
    #include <gl\gl.h>
    #include <gl\glu.h>
    
    //###### OPEN_GL - LIBARIES ######//
    #pragma comment( lib, "opengl.lib" )
    #pragma comment( lib, "glu.lib" )
    #pragma comment( lib, "glut32.lib" )
    

    opengl_init.cpp:

    // ========== opengl_init.CPP ========== //
    #include "stdafx.h"
    #include "opengl_init.h"
    LRESULT CALLBACK OpenGL_Init::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
    
    	switch(msg){
    		case WM_DESTROY:
    			PostQuitMessage(0);
    			break;
    		case WM_SIZE://nachricht wenn fenstergröße geändert wird 
    			opengl_resize_scene( LOWORD(lParam), HIWORD(lParam));//in LOWORD ist der width-wert nach dem resize gespeichert und in dem HIWORD-wert von lParam der height-wert
    			break;
    		default:
    			return DefWindowProc (hWnd, msg, wParam, lParam); //wenn keine besonderen events von windows dann arbeitet die defaultwindowprozedur des windows
    			break;
    	}
    	return 0;
    }
    
    LRESULT CALLBACK OpenGL_Init::StaticWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
    
    	OpenGL_Init* pOGL_Init;//Pointer auf unsere KLasse
    	if(msg == WM_CREATE){//wenn createfunktion aufgerufen wird
    		pOGL_Init = (OpenGL_Init*)( ((LPCREATESTRUCT) lParam)->lpCreateParams); //lParameter enthält die CreateSruktur(deren Werte = height,.....)
    		SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)pOGL_Init);//Userdata = wichtige Informationen des Fensters; dier werte von pOGL_Init werden dahinein gesetzt 
    	}
    	else{
    		pOGL_Init = (OpenGL_Init*) GetWindowLongPtr( hWnd, GWL_USERDATA);//hohlt sich die wichtigsten informationen des fesnters
    	}
    	return pOGL_Init->WndProc( hWnd, msg, wParam, lParam);
    }
    
    unsigned char OpenGL_Init::key_pressed(){
    	if(PeekMessage( &msg, NULL, NULL, NULL , PM_REMOVE)){//schaut ob in der messagefunktion etwas drinnen ist wenn nicht dann beendet sie sich wenn peekmessage eine messagefindet führt es das event aus, aber löscht es danach aus der messageschlange
    		if ( msg.message == WM_QUIT || msg.message == WM_KEYDOWN){ //wenn die msgstruktur "einen messagewert" quit oder tastendruck bekommt
    		return true; //gibt 1 zurück
    		}
    		//übersetzung der Message
    		TranslateMessage( &msg);
    		DispatchMessage( &msg);
    	}
    	return 0;	
    }
    
    //##### OPENGLSETUP - FUNKTION#####//
    void OpenGL_Init::opengl_setup(){
    
    	memset( &pfd, 0, sizeof( pfd )); //setzt jeden Member von pfd auf null
    	pfd.nSize			= sizeof( PIXELFORMATDESCRIPTOR );
    	pfd.nVersion		= 1; //Versionsnummer
    	pfd.dwFlags			= PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    	pfd.iPixelType		= PFD_TYPE_RGBA; //Pixel können auch transparenz bekommen
    	pfd.cColorBits		= 32; //32 FARBENBITS
    	pfd.cDepthBits		= 32;//32 TIEFENBITS
    	pfd.cAlphaBits		= 8;
    
    	hDC = GetDC( hWnd ); //legt den device context des hauptfensters fest (verbindung zum hauptfenster)
    	iFormat = ChoosePixelFormat( hDC, &pfd); //wägt das pixelformat der parameter gegeneinander ab
    	SetPixelFormat ( hDC, iFormat, &pfd);//setzt das pixelformat von hDC auf das neue pixelformat
    
    	hGLRC = wglCreateContext( hDC ); //erstellt es mit dem richtigen pixelformat
    	wglMakeCurrent( hDC, hGLRC ); 
    
    }
    
    bool OpenGL_Init::screen_setup( HINSTANCE hInst, int iCmdShow, int iWidth, int iHeight){
    
    	this->iWidth = iWidth;
    	this->iHeight = iHeight;
    
    	char szClassName[] = "MyWndClassEx";
    	char szWindowTitle[] = "Sterminio OpenGL-OOP Tutorial4";
    
    	WndClassEx.cbSize			= sizeof( WNDCLASSEX);
    	WndClassEx.style			= CS_OWNDC; //classstyle_own_dc = zum zeichnen des fensters (damit nicht jedes window ein neues braucht wird einmal eins initialisiert)
    	WndClassEx.cbClsExtra		= NULL;
    	WndClassEx.cbWndExtra		= NULL;
    	WndClassEx.hInstance		= hInst; //gibt der klasse die instance der mainfunktion -> mainwindow
    
    	WndClassEx.hbrBackground	= (HBRUSH) GetStockObject( BLACK_BRUSH);
    	WndClassEx.hIcon			= LoadIcon ( NULL, IDI_APPLICATION);
    	WndClassEx.hCursor			= LoadCursor (NULL, IDC_ARROW);
    	WndClassEx.hIconSm			= NULL;
    
    	WndClassEx.lpfnWndProc		= StaticWndProc;//WndProzedur
    	WndClassEx.lpszMenuName		= NULL;
    	WndClassEx.lpszClassName	= szClassName;
    
    	//wenn das registrieren scheitert...
    	if( !RegisterClassEx( &WndClassEx)){
    		MessageBox( NULL, "Fail to register WndClassEx", "Error", MB_OK | MB_ICONERROR);
    
    		return false;
    	}
    
    	hWnd = CreateWindow(szClassName,
    						szWindowTitle,
    						WS_OVERLAPPEDWINDOW | WS_VISIBLE, //normaler windowsfenster style
    						CW_USEDEFAULT, //x-position 
    						CW_USEDEFAULT, //y-position
    						iWidth, //breite
    						iHeight, //höhe
    						NULL,
    						NULL,
    						hInst,
    						NULL);
    
    	//wenn kein fenster erstellt werden konnte
    	if (!hWnd){
    		MessageBox( NULL, "Fail to create Window!", "Error",
    					MB_OK | MB_ICONERROR);
    		return false;
    	}
    	//ShowWindow(hWnd, iCmdShow); brauchen wir nicht mehr, da das opengl automatisch macht
    	//UpdateWindow (hWnd); "				"				"
    }
    
    void OpenGL_Init::opengl_reset_scene(){
    
    	if(this->iWidth == 0){
    		iWidth = 1;
    	}
    
    	if(this->iHeight == 0){
    		iHeight = 1;
    	}
    
    	glViewport(0, 0, this->iWidth, this->iHeight);//von wo man auf das "geschehen" schaut (ecken = parameter)
    	glMatrixMode( GL_PROJECTION); //für transformationsberechnungen
    	glLoadIdentity();//vorm arbeitewn mit einer matrix sie hiermit "leeren"
    	gluPerspective( 45.0f, this->iWidth/this->iHeight, 1.0f, 100.0f); //45.0f = grad in dem wir auf das "geschehen" schauen 3.Parameter MinfieldofView 4.Parameter Max-field_of_view
    
    	glMatrixMode(GL_MODELVIEW);//geometrische transformationen
    	glLoadIdentity();
    	glEnable(GL_DEPTH_TEST); //um tiefenzu erkennen (was verdeckt was)
    	glClearColor(0.0f, 0.4f, 0.1f, 1.0f);
    }
    
    void OpenGL_Init::opengl_resize_scene(int iWidth, int iHeight){//durch die parameter arbeitet er hier mit den aktuallisierten größen
    
    	if(iWidth == 0){
    		iWidth = 1;
    	}
    	if(iHeight == 0){
    		iHeight = 1;
    	}
    	glViewport(0, 0, iWidth, iHeight);//von wo man auf das "geschehen" schaut (ecken = parameter)
    	glMatrixMode( GL_PROJECTION); //für transformationsberechnungen
    	glLoadIdentity();//vorm arbeitewn mit einer matrix sie hiermit "leeren"
    	gluPerspective( 45.0f, iWidth/iHeight, 1.0f, 100.0f); //45.0f = grad in dem wir auf das "geschehen" schauen 3.Parameter MinfieldofView 4.Parameter Max-field_of_view	
    	glMatrixMode(GL_MODELVIEW);//geometrische transformationen
    	glLoadIdentity();
    
    }
    
    bool OpenGL_Init::opengl_draw_scene(){
    
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glMatrixMode(GL_MODELVIEW);
    	glLoadIdentity();//gehe zum Ursprung (nicht bei jedem funktionsaufruf weiterverschieben sondern immer an den festgelegten ursprung)
    	glTranslatef(0.0f, 0.0f, -10.0f);//verschiebt jede x kordinate +1 und y+1
    
    	glRotatef( 20, 1.0f, 0.0f, 0.0f);
    	glRotatef( fAngle, 0.0f, 1.0f, 0.0f);
    	glBegin( GL_QUADS );//um ein dreieck zu zeichnen	
    
    		//Front
    		glColor3f(0.0f, 1.0f, 0.0f);
    		glVertex3f( -1.0f,  1.0f, 0.0f); //zeichnet einen Eckpunkt(Vertex) mit 3 Floatwerten
    		glVertex3f( -1.0f, -1.0f, 0.0f); //zeichnet einen Eckpunkt(Vertex) mit 3 Floatwerten
    		glVertex3f(  1.0f, -1.0f, 0.0f); //zeichnet einen Eckpunkt(Vertex) mit 3 Floatwerten
    		glVertex3f(  1.0f,  1.0f, 0.0f); //zeichnet einen Eckpunkt(Vertex) mit 3 Floatwerten
    
    		//Back
    		glColor3f(0.0f, 1.0f, 0.0f);
    		glVertex3f(  1.0f,  1.0f, -2.0f);
    		glVertex3f(  1.0f, -1.0f, -2.0f); 
    		glVertex3f( -1.0f, -1.0f, -2.0f);
    		glVertex3f( -1.0f,  1.0f, -2.0f);
    
    		//Right
    		glColor3f(0.0f, 0.0f, 1.0f);
    		glVertex3f( 1.0f,  1.0f,  0.0f);
    		glVertex3f( 1.0f, -1.0f,  0.0f);
    		glVertex3f( 1.0f, -1.0f, -2.0f);
    		glVertex3f( 1.0f,  1.0f, -2.0f);
    
    		//Left
    		glColor3f(0.0f, 0.0f, 1.0f);
    		glVertex3f( -1.0f,  1.0f, -2.0f);
    		glVertex3f( -1.0f, -1.0f, -2.0f);
    		glVertex3f( -1.0f, -1.0f,  0.0f);
    		glVertex3f( -1.0f,  1.0f,  0.0f);
    
    		//Top
    		glColor3f(1.0f, 0.0f, 0.0f);
    		glVertex3f( -1.0f,  1.0f, 0.0f);
    		glVertex3f(  1.0f,  1.0f, 0.0f);
    		glVertex3f(  1.0f,  1.0f, -2.0f);
    		glVertex3f( -1.0f,  1.0f, -2.0f);
    
    		//Bottom
    		glColor3f(1.0f, 0.0f, 0.0f);
    		glVertex3f( -1.0f,  -1.0f, -2.0f);
    		glVertex3f(  1.0f,  -1.0f, -2.0f);
    		glVertex3f(  1.0f,  -1.0f, 0.0f);
    		glVertex3f( -1.0f,  -1.0f, 0.0f);
    
    	glEnd();
    
    	glBegin(GL_TRIANGLES);
    		//Roof
    
    		//front
    		glColor3f(1.0f, 0.0f, 0.0f);
    		glVertex3f(0.0f, 2.7f, -1.0f);
    		glColor3f(1.0f, 0.2f, 0.0f);
    		glVertex3f( -1.0f,  1.0f, 0.0f);
    		glColor3f(1.0f, 0.4f, 0.0f);
    		glVertex3f(  1.0f,  1.0f, 0.0f);
    
    		//Back
    		glVertex3f(0.0f, 2.7f, -1.0f);
    		glColor3f(0.0f, 0.4f, 0.0f);
    		glVertex3f(  1.0f,  1.0f, -2.0f);
    		glColor3f(1.0f, 0.4f, 0.0f);
    		glVertex3f( -1.0f,  1.0f, -2.0f);
    
    		//Right
    		glVertex3f(0.0f, 2.7f, -1.0f);
    		glColor3f(1.0f, 0.4f, 0.0f);
    		glVertex3f( 1.0f,  1.0f,  0.0f);
    		glColor3f(0.4f, 0.4f, 0.0f);
    		glVertex3f( 1.0f,  1.0f, -2.0f);
    
    		//Left
    		glVertex3f(0.0f, 2.7f, -1.0f);
    		glColor3f(0.0f, 0.4f, 0.5f);
    		glVertex3f( -1.0f,  1.0f, -2.0f);
    		glColor3f(1.0f, 0.4f, 0.2f);
    		glVertex3f( -1.0f,  1.0f,  0.0f);
    
    	glEnd();
    
    	fAngle++;
    
    	return true;
    }
    

    opengl_init.h:

    // ========== opengl_init.H ========== //
    
    class OpenGL_Init{
    
    private:
    	HWND					hWnd; //um das fenster "auszuwählen
    	MSG						msg; //um nachrichten von windows zu empfangen (global)
    	WNDCLASSEX				WndClassEx; //fensterklasse
    	//=============================//
    	HDC						hDC; //Device Context
    	HGLRC					hGLRC; //Handle gl Render Context
    	PIXELFORMATDESCRIPTOR	pfd; 
    	int						iFormat;
    	int						iWidth;
    	int						iHeight;
    	float					fAngle;
    public:
    	OpenGL_Init(){fAngle = 1.0f;}
    	inline HDC get_hDC(){ return this->hDC;}
    	unsigned char key_pressed();
    
    	LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    	static LRESULT CALLBACK StaticWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    	void opengl_setup(); //######OPENGL_SETUP funktion deklaration
    	void opengl_reset_scene();//vorbereitung zum zeichnen
    	static void opengl_resize_scene(int iWidth, int iHeight);//funktion um beim resize das bild anzupassen
    	bool screen_setup(HINSTANCE hInst,int iCmdShow, int iWidth, int iHeight);
    
    	bool opengl_draw_scene();//zeichnen
    
    };
    

    main.cpp:

    // ========== MAIN_CPP ========== //
    #include "stdafx.h"
    #include "opengl_init.h"
    
    int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int iCmdShow){
    
    	OpenGL_Init OpenGL_Start; //erstellt ein objekt der klasse OpenGL_Init
    	if (!OpenGL_Start.screen_setup( hInst, iCmdShow, 1280, 720)){
    		MessageBox(NULL, "Func: screen_setup() failed!", "Error!", MB_OK | MB_ICONERROR);
    		return false;
    	}
    
    	OpenGL_Start.opengl_setup();//#####setuped OPENGL#########////
    	OpenGL_Start.opengl_reset_scene();//bereitet das Fenster für die Nutzung vor (Opengl....)
    	while(true){
    		//keypressed = true wenn quit||keypressed, da return true;
    		if(OpenGL_Start.key_pressed()){
    			break; //beendet die schleife
    		}
    		else{
    			if (!OpenGL_Start.opengl_draw_scene() ){//führt die OpenGL funktion aus
    				break;
    			}
    			else{
    				SwapBuffers(OpenGL_Start.get_hDC() );
    			}
    
    		}
    	}
    	return 0;
    
    }
    

    Hoffe ihr könnt mir helfen und werdet von dem Code nicht "erschlagen".

    Liebe Grüße
    Tim



  • Ich vermute da mal eine Integerdivision:

    gluPerspective( 45.0f, this->iWidth/this->iHeight, 1.0f, 100.0f);
    

    😉



  • Ach und gluPerspective erwartet aber einen GLdouble-Wert (also einen standart Double).
    Also müsste ich doch einfach mittels (double) vor der Division das Ergebnis in Double umwandeln oder ?
    Nur leider funktioniert das auch nicht 😕

    Gruß
    Tim



  • silent12 schrieb:

    Nur leider funktioniert das auch nicht 😕

    Das bedeuted?



  • Gleiches Problem wie vorher:

    Objekt kann man skalieren (auch über das resizen der Breite), aber sobald die Breite des Fensters geringer ist als die Höhe, wird das Objekt nicht mehr dargestellt.

    Gruß
    Tim



  • Und wie sieht dein Aufruf von gluPerspective() jetzt aus?



  • Das

    gluPerspective( 45.0f, (double)(this->iWidth/this->iHeight), 1.0f, 100.0f);
    

    wird auch nicht funktionieren

    silent12 schrieb:

    Ach und gluPerspective erwartet aber einen GLdouble-Wert (also einen stan**** Double).
    Also müsste ich doch einfach mittels (double) vor der Division das Ergebnis in Double umwandeln oder ?
    Nur leider funktioniert das auch nicht 😕

    Gruß
    Tim



  • Meine gluPerspective-Funktion sieht einmal so aus:

    gluPerspective( 45.0f, (double)(this->iWidth/this->iHeight), 1.0f, 100.0f);
    

    und einmal so:

    gluPerspective( 45.0f, (double)(iWidth/iHeight), 1.0f, 100.0f);
    

    Ich habe gemerkt, wenn ich die Breite erhöh, indem ich das Fenster mit der Maus in der Breite resize, dann beobachte ich folgendes:

    - ein bisschen größer: Objekt mit einem Schlag ziemlich klein (aber Verhältnis der Seitenlängen stimmt)

    -um einiges größer: Objekt wird wieder größer (Verhältnis stimmt nicht mehr: breitgezogen)

    Warum kann das so nicht funktionieren ?

    Gruß
    Tim



  • @silent12
    Aua.

    gluPerspective( 45.0f, static_cast<double>(iWidth)/iHeight, 1.0f, 100.0f);
    


  • silent12 schrieb:

    Ich habe gemerkt, wenn ich die Breite erhöh, indem ich das Fenster mit der Maus in der Breite resize, dann beobachte ich folgendes:

    - ein bisschen größer: Objekt mit einem Schlag ziemlich klein (aber Verhältnis der Seitenlängen stimmt)

    -um einiges größer: Objekt wird wieder größer (Verhältnis stimmt nicht mehr: breitgezogen)

    Warum kann das so nicht funktionieren ?

    Weil du da zwei Ganzzahlen dividierst und das Ergebnis einer Ganzzahldivision eine Ganzzahl ist...



  • Mit Casten habe ichs davor schon probiert, aber damit klappt es auch nicht...

    Dadurch wird das Objekt nicht skaliert, sondern das Objekt wird einfach wenn ich resize "abgeschnitten".

    Das mit den Ganzzahlen habe ich mir gedacht, aber eine Lösung habe ich nicht gefunden, da es mit dem Casten ja auch nicht klappt...

    Gruß
    Tim



  • Natürlich klappt es mit Casten, wenn man es richtig macht.

    (double)(iWidth/iHeight)
    

    Das hier ist immer noch ein Ganzzahldivision, du castest nur das Ergebnis nach double. Was du willst ist, Dividend und/oder Divisor vor der Division in einen float zu casten, damit es eben eine Gleitkommadivision wird...



  • Um es nocheinmal zusammenzufassen:

    Probiert habe ich bis jetzt:
    gluPerspective( 45.0f, (double)(iWidth/iHeight), 1.0f, 100.0f);
    gluPerspective( 45.0f, (double)(iWidth)/iHeight, 1.0f, 100.0f);//macht für mich keinen Sinn
    gluPerspective( 45.0f, static_cast<double>(iWidth/iHeight), 1.0f, 100.0f);
    

    Ich verzweifel einfach an diesem Problem.
    Habe noch keine großen Kenntnisse von C++ und OpenGL.
    Wenn jemand möchte, kann er sich auch gerne per mail (pfeifletim@gmail.com) melden und dann mal per teamviewer drüber schauen.

    Gruß
    Tim



  • mach das

    gluPerspective( 45.0f, double(iWidth)/iHeight, 1.0f, 100.0f);//macht aber Sinn
    


  • Das Castet dann den ersten Wert und dadurch das Ergebnis gleich mit oder ?
    Nur leider funktioniert das bei mir nicht...kann es sein, dass es an etwas anderem im Code liegt (Code auf Seite 1 vollständig 🙂 )?

    Gruß
    silent12



  • silent12 schrieb:

    gluPerspective( 45.0f, (double)(iWidth)/iHeight, 1.0f, 100.0f);//macht für mich keinen Sinn
    

    warum genau?



  • silent12 schrieb:

    Nur leider funktioniert das bei mir nicht...

    Ich hoffe, dass dir bald endlich mal klar wird, dass "funktioinert nicht" keine Basis ist, auf der wir dir helfen können...



  • Habe den Sinn dahinter jetzt verstanden 🙂 (@//macht für mich keinen Sinn)

    Tut mir leid meinte Natürlich:(@funktioniert nicht)

    Dadurch wird das Objekt nicht skaliert, sondern das Objekt wird einfach wenn ich resize "abgeschnitten".

    Also es wird in den linken Rand "hineingeschoben", ohne seine Größe zu ändern.


Anmelden zum Antworten