Simple OpenGL interface for creating 2D-graphical Win32 windows

Discussion in 'Win32' started by AhmedHan, Jan 5, 2012.

  1. AhmedHan

    AhmedHan New Member

    Joined:
    Oct 11, 2005
    Messages:
    30
    Likes Received:
    0
    Trophy Points:
    0
    Home Page:
    http://www.stirve.com
    I needed a very very simple OpenGL interface for drawing graphics on Win32 windows. My aim was/is to simply put a pixel on a window. If you are able to put a pixel, you can draw anything, isn't it?

    For this purpose, I wrote the class below:

    GLWindow.h
    Code:
    #ifndef GLWINDOW_H
    #define GLWINDOW_H
    
    #include <Windows.h>
    #include <gl/GL.h>
    
    class GLWindow
    {
    	public:
    		GLWindow(HWND hWindowHandle, UINT uiPixelWidth, UINT uiPixelHeight);
    		~GLWindow(){};
    
    		// Thrown exception values and their meanings:
    		// 1: Failed: GetDC()
    		// 2: Failed: ChoosePixelFormat()
    		// 3: Failed: SetPixelFormat()
    		// 4: Failed: wglCreateContext()
    		// 5: Failed: wglMakeCurrent()
    		void Initialize() throw(int);
    
    		// Thrown exception values and their meanings:
    		// 1: Failed: wglMakeCurrent()
    		// 2: Failed: wglDeleteContext()
    		void Destroy() throw(int);
    
    		void SetColor(GLubyte ubRed, GLubyte ubGreen, GLubyte ubBlue) const;
    
    		void PutPixel(UINT x, UINT y) const;
    
    		void ClearScreen() const;
    
    		// Thrown exception values and their meanings:
    		// 1: Failed: SwapBuffers()
    		void SwapBuffers() const throw(int);
    
    	protected:
    		double	m_dbWidth;
    		double	m_dbHeight;
    		HWND	m_hWnd;
    		HDC	m_hDC;
    		HGLRC	m_hGLRC;
    };
    
    #endif

    GLWindow.cpp
    Code:
    #include "GLWindow.h"
    #include <gl/GL.h>
    
    
    GLWindow::GLWindow(HWND hWindowHandle, UINT uiPixelWidth, UINT uiPixelHeight)
    {
    	m_hWnd = hWindowHandle;
    	m_dbWidth = static_cast<double>(uiPixelWidth);
    	m_dbHeight = static_cast<double>(uiPixelHeight);
    }
    
    void GLWindow::Initialize() throw(int)
    {
    	m_hDC = GetDC(m_hWnd);
    	if (m_hDC == NULL) throw(1);
    
    	PIXELFORMATDESCRIPTOR Pfd;
    	ZeroMemory(&Pfd, sizeof(Pfd));
    	Pfd.nSize = sizeof(Pfd);
    	Pfd.nVersion = 1;
    	Pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    	Pfd.iPixelType = PFD_TYPE_RGBA;
    	Pfd.cColorBits = 24;
    	Pfd.cDepthBits = 16;
    	Pfd.iLayerType = PFD_MAIN_PLANE;
    
    	int iFormat = ChoosePixelFormat(m_hDC, &Pfd);
    	if (iFormat == 0) throw(2);
    
    	if (SetPixelFormat(m_hDC, iFormat, &Pfd) == FALSE) throw(3);
    
    	m_hGLRC = wglCreateContext(m_hDC);
    	if (m_hGLRC == NULL) throw(4);
    
    	if (wglMakeCurrent(m_hDC, m_hGLRC) == FALSE) throw(5);
    
    	////////////////
    
    	glEnable(GL_DEPTH_TEST);
    	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glLoadIdentity();
    	glPushMatrix();
    		glLoadIdentity();
    		glScaled(2.0 / m_dbWidth, 2.0 / m_dbHeight, 1.0);
    		glTranslated(-m_dbWidth / 2.0, -m_dbHeight / 2.0, 0.0);
    		glBegin(GL_POINTS);
    }
    
    void GLWindow::Destroy() throw(int)
    {
    		glEnd();
    	glPopMatrix();
    	glFlush();
    
    	if (wglMakeCurrent(m_hDC, NULL) == FALSE) throw(1);
    	if (wglDeleteContext(m_hGLRC) == FALSE) throw(2);
    }
    
    void GLWindow::SetColor(GLubyte ubRed, GLubyte ubGreen, GLubyte ubBlue) const
    {
    	glColor3ub(ubRed, ubGreen, ubBlue);
    }
    
    void GLWindow::PutPixel(UINT x, UINT y) const
    {
    	glVertex3i(static_cast<GLint>(x), static_cast<GLint>(y), 0);
    }
    
    void GLWindow::ClearScreen() const
    {
    	glEnd();
    	glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glBegin(GL_POINTS);
    }
    
    void GLWindow::SwapBuffers() const throw(int)
    {
    	glEnd();
    	if (::SwapBuffers(m_hDC) == FALSE) throw(1);
    	glBegin(GL_POINTS);
    }

    Yes, this class is only for printing a custom colored pixel on a window, and it does nothing else. I know how vast the capabilities of OpenGL is, but my requirement was as simple as this.

    The below is my code that uses this class:

    main.cpp
    Code:
    #include <Windows.h>
    #include <string>
    #include <gl/GL.h>
    #include <math.h>
    #include "GLWindow.h"
    
    HWND g_hWnd;
    const UINT WIN_WIDTH = 600;
    const UINT WIN_HEIGHT = 400;
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
    	std::string ClassName("MyWindowClass");
    	WNDCLASSEX wcx;
    	wcx.cbSize		= sizeof(wcx);
    	wcx.style		= 0;
    	wcx.lpfnWndProc		= DefWindowProc;
    	wcx.cbClsExtra		= 0;
    	wcx.cbWndExtra		= 0;
    	wcx.hInstance		= hInstance;
    	wcx.hIcon		= NULL;
    	wcx.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcx.hbrBackground	= (HBRUSH) 2;
    	wcx.lpszMenuName	= NULL;
    	wcx.lpszClassName	= ClassName.c_str();
    	wcx.hIconSm		= NULL;
    
    	ATOM Atom = RegisterClassEx(&wcx);
    	
    	std::string WindowName("GLWindow Test");
    	g_hWnd = CreateWindowEx(0,
    		ClassName.c_str(),
    		WindowName.c_str(),
    		WS_OVERLAPPED | WS_VISIBLE | WS_TILEDWINDOW,
    		1300, 650,
    		WIN_WIDTH, WIN_HEIGHT,
    		HWND_DESKTOP,
    		(HMENU) NULL,
    		hInstance,
    		(LPVOID) NULL);
    
    
    	GLWindow glWnd(g_hWnd, WIN_WIDTH, WIN_HEIGHT);
    	glWnd.Initialize();
    
    	///////////////////////////////////////////////////////////////////////
    	///////////////////////////////////////////////////////////////////////
    	//////////////// MY CODE STARTS HERE //////////////////////////////////
    
    	// Draw a diagonal line
    	for (UINT x=0, y; x<WIN_WIDTH; x++)
    	{
    		glWnd.SetColor(255,	(GLbyte) (255.0 * x / (double) WIN_WIDTH),
    					(GLbyte) (255.0 * x / (double) WIN_WIDTH));
    		y = ((double) WIN_HEIGHT / WIN_WIDTH) * x;
    		glWnd.PutPixel(x, y);
    	}
    	
    	// Display it on the screen
    	glWnd.SwapBuffers();
    
    	// Draw a quarter of a circle
    	UINT x, y;
    	for (double teta=0.0; teta<1.5708 /* PI/2 */; teta+=0.001)
    	{
    		x = WIN_HEIGHT * cos(teta);
    		y = WIN_HEIGHT * sin(teta);
    		glWnd.SetColor(	(GLbyte) (150.0 * teta),
    				(GLbyte) (256.0 - 150.0 * teta),
    				128.0);
    		glWnd.PutPixel(x, y);
    	}
    
    	// Switch between line and circle several times
    	for (UINT i=0; i<10; i++)
    	{
    		glWnd.SwapBuffers();
    		Sleep(1000);
    	}
    	
    	// Close OpenGL engine
    	glWnd.Destroy();
    
    	// Quit the program
    	PostQuitMessage(0);
    
    	/////////////// MY CODE ENDS HERE /////////////////////////////////////
    	///////////////////////////////////////////////////////////////////////
    	///////////////////////////////////////////////////////////////////////
    
    	MSG Msg;
    	const UINT wMsgFilterMin = 0;
    	const UINT wMsgFilterMax = 0;
    	while (GetMessage(&Msg, (HWND) NULL, wMsgFilterMin, wMsgFilterMax) > 0)
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return 0;
    }
    My code above (which is in the main.cpp file) works very fine. Try it yourself if you have time.

    Now, I want two things from you guys.

    1. Criticize my code. Do you see any flaw? Would it work in all cases (except for the problem I stated in (2))?
    2. I feel that this code won't work when I use two objects of this class under the same process. And I feel that every GLWindow object must check if they are the "current", if not, they must make themselves the "current" by somehow using the function wglMakeCurrent(). But I don't know how to do it, because I don't know much about OpenGL at all. How do I do it?
     
  2. AhmedHan

    AhmedHan New Member

    Joined:
    Oct 11, 2005
    Messages:
    30
    Likes Received:
    0
    Trophy Points:
    0
    Home Page:
    http://www.stirve.com
    Dudes, I did that!

    I kept an ID for each class instance, and before calling any OpenGL function, I check if the GLWindow object is the "current" object, if not I made it current with the wglMakeCurrent() function.

    GLWindow.h
    Code:
    #ifndef GLWINDOW_H
    #define GLWINDOW_H
    
    #include <Windows.h>
    #include <gl/GL.h>
    
    class GLWindow
    {
    	public:
    		GLWindow(HWND hWindowHandle, UINT uiPixelWidth, UINT uiPixelHeight);
    		~GLWindow(){};
    
    		// Thrown exception values and their meanings:
    		// 1: Failed: GetDC()
    		// 2: Failed: ChoosePixelFormat()
    		// 3: Failed: SetPixelFormat()
    		// 4: Failed: wglCreateContext()
    		// 5: Failed: wglMakeCurrent()
    		void Initialize() throw(int);
    
    		// Thrown exception values and their meanings:
    		// 1: Failed: wglMakeCurrent()
    		// 2: Failed: wglDeleteContext()
    		void Destroy() throw(int);
    
    		void SetColor(GLubyte ubRed, GLubyte ubGreen, GLubyte ubBlue) const;
    
    		void PutPixel(UINT x, UINT y) const;
    
    		void ClearScreen() const;
    
    		// Thrown exception values and their meanings:
    		// 1: Failed: SwapBuffers()
    		void SwapBuffers() const throw(int);
    
    	protected:
    		double	m_dbWidth;
    		double	m_dbHeight;
    		HWND	m_hWnd;
    		HDC	m_hDC;
    		HGLRC	m_hGLRC;
    
    		static unsigned int LAST_OBJECT_ID;
    		static unsigned int ACTIVE_OBJECT_ID;
    		unsigned int m_uiObjectId;
    		bool MakeCurrent() const;
    };
    
    #endif
    GLWindow.cpp
    Code:
    #include "GLWindow.h"
    #include <gl/GL.h>
    
    unsigned int GLWindow::LAST_OBJECT_ID = 0;
    unsigned int GLWindow::ACTIVE_OBJECT_ID = 0;
    
    GLWindow::GLWindow(HWND hWindowHandle, UINT uiPixelWidth, UINT uiPixelHeight)
    {
    	m_hWnd = hWindowHandle;
    	m_dbWidth = static_cast<double>(uiPixelWidth);
    	m_dbHeight = static_cast<double>(uiPixelHeight);
    	LAST_OBJECT_ID++;
    	m_uiObjectId = LAST_OBJECT_ID;
    }
    
    void GLWindow::Initialize() throw(int)
    {
    	m_hDC = GetDC(m_hWnd);
    	if (m_hDC == NULL) throw(1);
    
    	PIXELFORMATDESCRIPTOR Pfd;
    	ZeroMemory(&Pfd, sizeof(Pfd));
    	Pfd.nSize = sizeof(Pfd);
    	Pfd.nVersion = 1;
    	Pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    	Pfd.iPixelType = PFD_TYPE_RGBA;
    	Pfd.cColorBits = 24;
    	Pfd.cDepthBits = 16;
    	Pfd.iLayerType = PFD_MAIN_PLANE;
    
    	int iFormat = ChoosePixelFormat(m_hDC, &Pfd);
    	if (iFormat == 0) throw(2);
    
    	if (SetPixelFormat(m_hDC, iFormat, &Pfd) == FALSE) throw(3);
    
    	m_hGLRC = wglCreateContext(m_hDC);
    	if (m_hGLRC == NULL) throw(4);
    
    	if (this->MakeCurrent() == FALSE) throw(5);
    
    	////////////////
    
    	glEnable(GL_DEPTH_TEST);
    	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glLoadIdentity();
    	glPushMatrix();
    		glLoadIdentity();
    		glScaled(2.0 / m_dbWidth, 2.0 / m_dbHeight, 1.0);
    		glTranslated(-m_dbWidth / 2.0, -m_dbHeight / 2.0, 0.0);
    		glBegin(GL_POINTS);
    }
    
    void GLWindow::Destroy() throw(int)
    {
    		glEnd();
    	glPopMatrix();
    	glFlush();
    
    	if (wglMakeCurrent(m_hDC, NULL) == FALSE) throw(1);
    	ACTIVE_OBJECT_ID = 0;
    	if (wglDeleteContext(m_hGLRC) == FALSE) throw(2);
    }
    
    void GLWindow::SetColor(GLubyte ubRed, GLubyte ubGreen, GLubyte ubBlue) const
    {
    	this->MakeCurrent();
    	glColor3ub(ubRed, ubGreen, ubBlue);
    }
    
    void GLWindow::PutPixel(UINT x, UINT y) const
    {
    	this->MakeCurrent();
    	glVertex3i(static_cast<GLint>(x), static_cast<GLint>(y), 0);
    }
    
    void GLWindow::ClearScreen() const
    {
    	this->MakeCurrent();
    	glEnd();
    	glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glBegin(GL_POINTS);
    }
    
    void GLWindow::SwapBuffers() const throw(int)
    {
    	this->MakeCurrent();
    	glEnd();
    	if (::SwapBuffers(m_hDC) == FALSE) throw(1);
    	glBegin(GL_POINTS);
    }
    
    bool GLWindow::MakeCurrent() const
    {
    	bool bReturn;
    	if (ACTIVE_OBJECT_ID == m_uiObjectId) return true;
    	bReturn = wglMakeCurrent(m_hDC, m_hGLRC);
    	if (bReturn) ACTIVE_OBJECT_ID = m_uiObjectId;
    	return bReturn;
    }
    main.cpp
    Code:
    #include <Windows.h>
    #include <string>
    #include <gl/GL.h>
    #include <math.h>
    #include "GLWindow.h"
    
    HWND g_hWnd;
    const UINT WIN_WIDTH = 600;
    const UINT WIN_HEIGHT = 400;
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
    	std::string ClassName("MyWindowClass");
    	WNDCLASSEX wcx;
    	wcx.cbSize		= sizeof(wcx);
    	wcx.style		= 0;
    	wcx.lpfnWndProc		= DefWindowProc;
    	wcx.cbClsExtra		= 0;
    	wcx.cbWndExtra		= 0;
    	wcx.hInstance		= hInstance;
    	wcx.hIcon		= NULL;
    	wcx.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcx.hbrBackground	= (HBRUSH) 1;
    	wcx.lpszMenuName	= NULL;
    	wcx.lpszClassName	= ClassName.c_str();
    	wcx.hIconSm		= NULL;
    
    	ATOM Atom = RegisterClassEx(&wcx);
    	
    	std::string WindowName("GLWindow Test");
    	g_hWnd = CreateWindowEx(0,
    				ClassName.c_str(),
    				WindowName.c_str(),
    				WS_OVERLAPPED | WS_VISIBLE | WS_TILEDWINDOW,
    				1300, 650,
    				WIN_WIDTH, WIN_HEIGHT,
    				HWND_DESKTOP,
    				(HMENU) NULL,
    				hInstance,
    				(LPVOID) NULL);
    
    	const UINT STATIC1_WIDTH  = WIN_WIDTH  / 2;
    	const UINT STATIC1_HEIGHT = WIN_HEIGHT / 2;
    	HWND hWndStatic1 = CreateWindowEx(	0,
    						"STATIC",
    						"My Static #1",
    						WS_VISIBLE | WS_CHILD,
    						0, 0,
    						WIN_WIDTH/2, WIN_HEIGHT/2,
    						g_hWnd,
    						(HMENU) NULL,
    						hInstance,
    						(LPVOID) NULL);
    
    	GLWindow glWnd1(hWndStatic1, WIN_WIDTH/2, WIN_HEIGHT/2);
    	glWnd1.Initialize();
    	
    	const UINT STATIC2_WIDTH  = WIN_WIDTH  / 2;
    	const UINT STATIC2_HEIGHT = WIN_HEIGHT / 2;
    	HWND hWndStatic2 = CreateWindowEx(	0,
    						"STATIC",
    						"My Static #2",
    						WS_VISIBLE | WS_CHILD,
    						WIN_WIDTH/2, WIN_HEIGHT/2,
    						WIN_WIDTH/2, WIN_HEIGHT/2,
    						g_hWnd,
    						(HMENU) NULL,
    						hInstance,
    						(LPVOID) NULL);
    
    	GLWindow glWnd2(hWndStatic2, WIN_WIDTH/2, WIN_HEIGHT/2);
    	glWnd2.Initialize();
    
    	///////////////////////////////////////////////////////////////////////
    	///////////////////////////////////////////////////////////////////////
    	//////////////// MY CODE STARTS HERE //////////////////////////////////
    
    	//////////////// STATIC CONTROL #1 ////////////////////////////////////
    
    	// Draw a diagonal line
    	for (UINT x=0, y; x<STATIC1_WIDTH; x++)
    	{
    		glWnd1.SetColor(255,	(GLbyte) (255.0 * x / (double) STATIC1_WIDTH),
    					(GLbyte) (255.0 * x / (double) STATIC1_WIDTH));
    		y = ((double) STATIC1_HEIGHT / STATIC1_WIDTH) * x;
    		glWnd1.PutPixel(x, y);
    	}
    	
    	// Display it on the screen
    	glWnd1.SwapBuffers();
    
    	// Draw a quarter of a circle
    	UINT x, y;
    	for (double teta=0.0; teta<1.5708 /* PI/2 */; teta+=0.001)
    	{
    		x = STATIC1_HEIGHT * cos(teta);
    		y = STATIC1_HEIGHT * sin(teta);
    		glWnd1.SetColor((GLbyte) (150.0 * teta),
    				(GLbyte) (256.0 - 150.0 * teta),
    				128.0);
    		glWnd1.PutPixel(x, y);
    	}
    
    	//////////////// STATIC CONTROL #2 ////////////////////////////////////
    
    	// Draw a rectangle
    	for (UINT x=STATIC2_WIDTH/4; x<3*STATIC2_WIDTH/4; x++)
    	{
    		glWnd2.SetColor(255, 128, 0);
    		glWnd2.PutPixel(x,   STATIC2_HEIGHT/4);
    		glWnd2.SetColor(0, 128, 255);
    		glWnd2.PutPixel(x, 3*STATIC2_HEIGHT/4);
    	}
    	for (UINT y=STATIC2_HEIGHT/4; y<3*STATIC2_HEIGHT/4; y++)
    	{
    		glWnd2.SetColor(192, 128, 0);
    		glWnd2.PutPixel(  STATIC2_WIDTH/4, y);
    		glWnd2.SetColor(0, 128, 192);
    		glWnd2.PutPixel(3*STATIC2_WIDTH/4, y);
    	}
    	
    	// Display it on the screen
    	glWnd2.SwapBuffers();
    
    	// Draw a filled rectangle
    	for (UINT x=STATIC2_WIDTH/4; x<3*STATIC2_WIDTH/4; x++)
    	{
    		for (UINT y=STATIC2_HEIGHT/4; y<3*STATIC2_HEIGHT/4; y++)
    		{
    			glWnd2.SetColor(rand() % 256, rand() % 256, rand() % 256);
    			glWnd2.PutPixel(x, y);
    		}
    	}
    
    	/////////////// FINALIZE //////////////////////////////////////////////
    
    	// Switch between line and circle several times
    	for (UINT i=0; i<10; i++)
    	{
    		glWnd1.SwapBuffers();
    		glWnd2.SwapBuffers();
    		Sleep(1000);
    	}
    	
    	// Close OpenGL engines
    	glWnd1.Destroy();
    	glWnd2.Destroy();
    
    	// Quit the program
    	PostQuitMessage(0);
    
    	/////////////// MY CODE ENDS HERE /////////////////////////////////////
    	///////////////////////////////////////////////////////////////////////
    	///////////////////////////////////////////////////////////////////////
    
    	MSG Msg;
    	const UINT wMsgFilterMin = 0;
    	const UINT wMsgFilterMax = 0;
    	while (GetMessage(&Msg, (HWND) NULL, wMsgFilterMin, wMsgFilterMax) > 0)
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	return 0;
    }
    In this code, I'm running OpenGL on two independent STATIC windows. The code and its exe file are attached.
     

    Attached Files:

  3. sura

    sura Banned

    Joined:
    Aug 4, 2011
    Messages:
    47
    Likes Received:
    1
    Trophy Points:
    0
    Location:
    India,Tamil Nadu.
    i like it ................
     
  4. Scripting

    Scripting John Hoder

    Joined:
    Jun 29, 2010
    Messages:
    421
    Likes Received:
    57
    Trophy Points:
    0
    Occupation:
    School for life
    Location:
    /root
    Awesome dude!
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice