1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

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:
    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:
    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