Threads and OpenGL

Started by
6 comments, last by Death100 17 years, 1 month ago
I've been messing around with threads, and I want to create a thread for the drawing of a opengl scene, and one for handling windows messages. This is what i've got so far: main.cpp
[source lang="cpp]
//includes
#include <gl/gl.h>
#include <gl/glu.h>
#include <windows.h>

//classes
#include "classes.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmd, int show) {
    GAME gam("This is a Window", 400, 400, false, show);
    gam.go();
    
    system("PAUSE");
}



classes.h

//global vars
bool REG = false;

//global functions
bool resize(RECT _rect) {
   int h;
   int w;
   
   w = _rect.right;
   h = _rect.bottom;
   
   if (_rect.right == 0)
      h = 1;
      
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   
   glViewport(0, 0, w, h);
   
   gluPerspective(45, 1.0 * w / h, 1, 1000);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   
   gluLookAt(0.0,1.0,1.0, 
		      0.0,0.0,0.0,
			  0.0f,1.0f,0.0f);

}

bool drawCube(float _size) {
     glBegin(GL_QUADS);
                       glColor3f(1.0, 0.0, 0.0);
                       glVertex3f(1.0, -1.0, 1.0);
                       glVertex3f(1.0, 1.0, 1.0);
                       glVertex3f(-1.0, 1.0, 1.0);
                       glVertex3f(-1.0, -1.0, 1.0);
                       
                       glColor3f(0.0, 1.0, 0.0);
                       glVertex3f(-1.0, -1.0, 1.0);
                       glVertex3f(-1.0, 1.0, 1.0);
                       glVertex3f(-1.0, 1.0, -1.0);
                       glVertex3f(-1.0, -1.0, -1.0);
                       
                       glColor3f(0.0, 0.0, 1.0);
                       glVertex3f(1.0, -1.0, 1.0);
                       glVertex3f(1.0, 1.0, 1.0);
                       glVertex3f(1.0, 1.0, -1.0);
                       glVertex3f(1.0, -1.0, -1.0);
                       
                       glColor3f(1.0, 0.0, 0.0);
                       glVertex3f(1.0, -1.0, -1.0);
                       glVertex3f(1.0, 1.0, -1.0);
                       glVertex3f(-1.0, 1.0, -1.0);
                       glVertex3f(-1.0, -1.0, -1.0);
                       
                       glColor3f(0.0, 1.0, 0.0);
                       glVertex3f(-1.0, -1.0, 1.0);
                       glVertex3f(1.0, -1.0, 1.0);
                       glVertex3f(1.0, -1.0, -1.0);
                       glVertex3f(-1.0, -1.0, -1.0);
     glEnd();
}

class WINDOW {
      public:
             bool makeWindow(char *_title, int _x, int _y, bool _fullscreen, int _show) {
                             WNDCLASSEX wc;
                             
                             ZeroMemory(&wc, sizeof(WNDCLASSEX));
                             
                             if (!REG) {
                                       wc.cbSize = sizeof(WNDCLASSEX);
                                       wc.style = CS_OWNDC;
                                       wc.lpfnWndProc = WndProc;
                                       wc.hInstance = GetModuleHandle(0);
                                       wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
                                       wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
                                       wc.hCursor = LoadCursor(NULL, IDC_ARROW);
                                       wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);;
                                       wc.lpszMenuName = NULL;
                                       wc.lpszClassName = "window";
                                       
                                       RegisterClassEx(&wc);
                                       REG = true;
                             }
                             
                             hwnd = CreateWindowEx(
                                    0,
                                    "window",
                                    _title,
                                    WS_OVERLAPPEDWINDOW,
                                    CW_USEDEFAULT, CW_USEDEFAULT,
                                    _x, _y,
                                    NULL, NULL, GetModuleHandle(0), NULL);
                                  
                             dc = GetDC(hwnd); 
                                   
                             PIXELFORMATDESCRIPTOR pfd;
                             
                             ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
                             pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
                             pfd.nVersion = 1;
                             pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
                             pfd.cColorBits = 32;
                             pfd.cDepthBits = 16;
                             pfd.iLayerType = PFD_MAIN_PLANE;
                             pfd.iPixelType = PFD_TYPE_RGBA;
                             
                             int i = ChoosePixelFormat(dc, &pfd);
                             SetPixelFormat(dc, i, &pfd);
                             
                             rc = wglCreateContext(dc);
                             
                             wglMakeCurrent(dc, rc);  
                             
                             ShowWindow(hwnd, _show);
             }
             
             //WndProc
             static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM w, LPARAM l) {
                    static RECT rect;
                    switch (message) {
                           case WM_CLOSE:
                                exit(0);
                                
                           case WM_SIZE:
                                GetClientRect(hwnd, &rect);
                                
                                //resize
                                resize(rect);
                                
                                return 0;
                                
                           default:
                                   break;
                    }
                    return DefWindowProc(hwnd, message, w, l);
             }
             
             //vars
             HWND hwnd;
             MSG message;
             HGLRC rc;
             HDC dc;
             
      private:
              
};


class GAME {
      public:
             GAME(char *_title, int _x, int _y, bool _fullscreen, int _show) {
                    win.makeWindow(_title, _x, _y, _fullscreen, _show);
                    QUIT = false;
                    
                    //initiate opengl properly
                    glEnable(GL_DEPTH_TEST);
                    glDepthFunc(GL_LEQUAL);
                    glClearDepth(1.0);
             }
             
             GAME() {}
             
             bool go() {
                  thread = CreateThread(NULL, 0, StartThreadDraw, (LPVOID)this, NULL, &threadID); 
                  while (!QUIT) {
                      if (PeekMessage(&win.message, NULL, 0, 0, PM_REMOVE)) {
                            TranslateMessage(&win.message);
                            DispatchMessage(&win.message);
                     }
                  }
             }
             
             //vars
             WINDOW win;
             float theta;
             bool QUIT;
             HANDLE thread;
             DWORD threadID;
             
      private:
              static DWORD WINAPI StartThreadDraw(LPVOID pthis) {
                     GAME *game = (GAME*)pthis;
                     
                     game->draw();

                     //shouldn't get here
              }
              
           //draw
           bool draw() {
                wglMakeCurrent(win.dc, win.rc);
                while (!QUIT) {
                    glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
                    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
                    glPushMatrix ();
                    glRotatef (theta, 0.0f, 0.3f, 1.0f);
                    
                    drawCube(0.4);
                    
                    glPopMatrix();
        
                    SwapBuffers(win.dc);
        
                    theta += 1.0f;
                    Sleep (1);
                }
            }
};



this compiles, but all i get is this:
http://furboxes.com/forum
Advertisement
I'm not totally sure, but what are you drawing ??

while (!QUIT) {if (PeekMessage(&win.message, NULL, 0, 0, PM_REMOVE)) {TranslateMessage(&win.message);DispatchMessage(&win.message);}


Your loop does not do anything, but check messages !!

Plus you have 2 'while' loops (1 message & 1 render)
I would imagine you are stuck in the message loop until QUIT is true.

plus I wouldn't swapBuffers in your draw loop.

you PeekMessage, QUIT or drawScene, swapBuffers, PeekMessage, QUIT or drawScene, SwapBuffers etc etc

Also, make sure #include <windows.h> goes before any GL stuff..

[Edited by - darren_mfuk on March 10, 2007 12:40:53 PM]
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
ok looking at the code again quickly

Shouldn't variables be declared before they are used

Declare variables first ...

//vars
WINDOW win;
float theta;
bool QUIT;
HANDLE thread;
DWORD threadID;

then ...

thread = CreateThread(NULL, 0, StartThreadDraw, (LPVOID)this, NULL, &threadID);

Also your functions are 'bool' but you don't return a result.

Does this actually compile ?
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
It compiles, with 1 warning about passing NULL in the CreateThread() func, but i don't think that would effect it..

This has happened before, it had somehting to do with the rendering context, but i con't remember exactly how i fixed it.

I do draw, look:
             bool go() {                  thread = CreateThread(NULL, 0, StartThreadDraw, (LPVOID)this, NULL, &threadID);                   while (!QUIT) {                      if (PeekMessage(&win.message, NULL, 0, 0, PM_REMOVE)) {                            TranslateMessage(&win.message);                            DispatchMessage(&win.message);                     }                  }             }


that starts a thread to the function that draws:
              static DWORD WINAPI StartThreadDraw(LPVOID pthis) {                     GAME *game = (GAME*)pthis;                                          game->draw();                     //shouldn't get here              }                         //draw           bool draw() {                wglMakeCurrent(win.dc, win.rc);                while (!QUIT) {                    glClearColor (1.0f, 1.0f, 1.0f, 0.0f);                    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                        glPushMatrix ();                    glRotatef (theta, 0.0f, 0.3f, 1.0f);                                        drawCube(0.4);                                        glPopMatrix();                            SwapBuffers(win.dc);                            theta += 1.0f;                    Sleep (1);                }            }
http://furboxes.com/forum
Quote:Original post by Death100
It compiles, with 1 warning about passing NULL in the CreateThread() func, but i don't think that would effect it..

This has happened before, it had somehting to do with the rendering context, but i con't remember exactly how i fixed it.

I do draw, look:
*** Source Snippet Removed ***

that starts a thread to the function that draws:
*** Source Snippet Removed ***

You can only make OpenGL calls from the thread in which the OpenGL context is 'current'. This starts as the thread which creates the display, if you want to send drawing commands from other threads you must first make the context current to that thread (IIRC on windows you can do this with wglMakeCurrent).

From the looks of it you're creating the display in the main thread, but letting the sub thread do the rendering while the context still belongs to the main thread. Either use wglMakeCurrent in the sub thread or do the windows event handling in the sub thread and keep the drawing in the main thread.

IMHO splitting the drawing and events into two different threads gains you nothing but lots of awkward threading bugs. Unless you've got a really good reason it's probably much easier to just do all drawing, update logic and input handling in the same thread.
YAY! I have it working!

What i was doing was using wglMakeCurrent() when i made the window (Which locks the rc to the current thread) and then trying to use wglMakeCurrent() again in a different thread. So i had to remove the first wglMakeCurrent().

to darren_mfuk:
CreateThread() makes a new thread, so the application splits into two (one running StartDrawThread() and one running go())

Ok, I now have another problem, the background changes color, but there is no cube...
http://furboxes.com/forum
hey,

you wanna post the code for drawCube();


----------------------------------------Now just hit that link that says 'Rate This User' [wink]
I've decided to scrap the threaded idea, I thought it would be easier...

drawCube() is up at the top (and i know it doesn't draw a proper cubet's not finished)
http://furboxes.com/forum

This topic is closed to new replies.

Advertisement