Go4Expert

Go4Expert (http://www.go4expert.com/)
-   Win32 (http://www.go4expert.com/forums/win32/)
-   -   Simple OpenGL interface for creating 2D-graphical Win32 windows (http://www.go4expert.com/forums/simple-opengl-interface-creating-2d-t27543/)

AhmedHan 6Jan2012 05:00

Simple OpenGL interface for creating 2D-graphical Win32 windows
 
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?

AhmedHan 7Jan2012 02:51

Re: Simple OpenGL interface for creating 2D-graphical Win32 windows
 
1 Attachment(s)
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.

sura 7Jan2012 20:08

Re: Simple OpenGL interface for creating 2D-graphical Win32 windows
 
i like it ................

Scripting 8Jan2012 02:29

Re: Simple OpenGL interface for creating 2D-graphical Win32 windows
 
Awesome dude!


All times are GMT +5.5. The time now is 19:16.