Search code examples
c++winapiopenglcygwineclipse-cdt

OpenGL on a custom made win32 window, using cygwin compiler, doesn't work


I wrote a bit of code, based on NeHe's first tutorial, which creates a window and initializes gl context. this worked exactly as it should in vc++. Then I've tried to replicate the same code in eclipse c++ environment using cygwin compiler and the problems began.

The window compiles without any errors (A number of warnings but no errors), the exe opens a win32 window as it should, all of the functionality that I've coded into the window works too (e.g. full screen mode, change resolution) the only problem is that instead of refreshing the background of the window with red colour as it should I'm getting a black square and that's it.

To me this looks like an opengl initialization problem. Been trying to solve this problem for two days but I can't find any solution I hope somebody can see what I'm doing wrong.

Below are the code extracts.

Initial method

#include <iostream>
#include <windows.h>
#include <gl/glew.h>
#include <string>

#define GLEW_STATIC

using namespace std;

#include <glWindow.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MSG msg;
    GLboolean Exit = FALSE;
    glWindow screen("Dark Light", 640, 480, 16);

    while(!Exit){
        if (screen.LastError() == errNone && screen.WndState() != glExit){
            // Is There A Message Waiting?
            if (PeekMessage(&msg, screen.Handles().Window(), 0, 0, PM_REMOVE)){
                // Have We Received A Quit Message?
                if (msg.message == WM_QUIT){
                    screen.WndState() = glExit;
                }
                // If Not, Deal With Window Messages
                else{
                    TranslateMessage(&msg);             // Translate The Message
                    DispatchMessage(&msg);                  // Dispatch The Message
                }
            }
            // If There Are No Messages
            else{
                if (screen.WndState() == glActive){
                    if (screen.KeysState(VK_ESCAPE)){
                        screen.WndState() = glExit;
                    }
                    else{
                        // Draw The Scene
                        screen.Draw();
                    }
                }

                if (screen.KeysState(VK_F1)){
                    screen.KeysState(VK_F1) = FALSE;
                    screen.ToggleFullscreen();
                }

                if (screen.KeysState(VK_SPACE)){
                    screen.KeysState(VK_SPACE) = FALSE;
                    screen.SetResolution(800, 600);
                }
            }
        }
        else{
            Exit = true;
        }
    }

    // Shutdown
    return 0;
}

glWindow.h

#ifndef GLWINDOW_H
#define GLWINDOW_H

#include <string>

using namespace std;


enum glWndState
{
    glActive = 0, glPaused = 1, glExit = 2
};

enum glWndErrors
{
    errNone = 0, errCreateWC = 1, errCreateWnd = 2, errCreateDC = 3, errMatchPixelFormat = 4,
    errSetPixelFormat = 5, errCreateRC = 6, errActivateRC = 7, errInitGL = 8, errChangeRC = 9,
    errReleaseRC = 10, errReleaseDC = 11, errDestroyWnd = 12, errDestroyWC = 13, errGoToFullscreen = 14,
    errGoToWindowed = 15, errGetInstance = 16
};

class glWndSettings
{
private:
    GLsizei _width;
    GLsizei _height;
    GLboolean _fullscreen;
    GLint _bits;
    PIXELFORMATDESCRIPTOR _pfd;
    DEVMODE _screenSettings;

public:
    glWndSettings(GLsizei width, GLsizei height, GLint bits);
    glWndErrors glSetStyle(HWND hWnd);
    glWndErrors glSetStyle(HWND hWnd, GLboolean fullscreen, GLboolean save = TRUE);
    glWndErrors glSetResolution(HWND hWnd, GLsizei width, GLsizei height);

    GLsizei& Width();
    GLsizei& Height();
    GLboolean& Fullscreen();
    GLint& Bits();
    PIXELFORMATDESCRIPTOR& PixelFormatDescription();
};

class glWndHandles
{
private:
    string _className;
    HINSTANCE _hInstance;
    WNDCLASS _wc;
    HWND _hWnd;
    HDC _hDC;
    HGLRC _hRC;
    GLuint _pixelFormat;

public:
    glWndHandles(HICON icon, string title, WNDPROC wndProc);
    ~glWndHandles();
    glWndErrors glDefWindow(PIXELFORMATDESCRIPTOR pfd);

    HINSTANCE& Instance();
    WNDCLASS& WinClass();
    HWND& Window();
    HDC& DeviceContext();
    HGLRC& RenderContext();
};

class glWndFPS
{
    GLint _framesCounter;
    GLint _fps;
public:
    glWndFPS();

    GLvoid NewFrame();
    GLvoid ResetFrames();
    GLint FPS();
};

class glWindow
{
    glWndHandles _handles;
    glWndSettings _settings;
    glWndFPS _fps;
    glWndErrors _error;
    glWndState _state;
    bool _keys[256];
    string _title;

    static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
public:
    glWindow(string title, int width, int height, int bits);
    ~glWindow();

    int InitGL();
    GLvoid Draw();
    GLvoid DisplayFPS();
    GLvoid SetTitle(string title);
    GLvoid SetResolution(GLsizei width, GLsizei height);
    GLvoid SetFullscreen(GLboolean fullscreen);
    GLvoid ToggleFullscreen();

    glWndHandles& Handles();
    glWndSettings& Settings();
    glWndFPS& fpsInfo();
    glWndErrors& LastError();
    glWndState& WndState();
    bool& KeysState(int key);

    GLvoid ReSizeGLScene(GLsizei width, GLsizei height);
};

#endif /* GLWINDOW_H_ */

glWindow.cpp

#include <stdio.h>
#include <windows.h>
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp>

using namespace std;

#include "glWindow.h"

glWndSettings::glWndSettings(GLsizei width, GLsizei height, GLint bits){
    _fullscreen = FALSE;

    _width = width;
    _height = height;
    _bits = bits;

    _pfd.nSize              =   sizeof(PIXELFORMATDESCRIPTOR);  // Size Of This Pixel Format Descriptor
    _pfd.nVersion           =   1;                              // Version Number
    _pfd.dwFlags            =   PFD_DRAW_TO_WINDOW |            // Format Must Support Window
                                PFD_SUPPORT_OPENGL |            // Format Must Support OpenGL
                                PFD_DOUBLEBUFFER;               // Must Support Double Buffering

    _pfd.iPixelType         =   PFD_TYPE_RGBA;                  // Request An RGBA Format
    _pfd.cColorBits         =   bits;                           // Select Our Color Depth

    _pfd.cRedBits           =   0; _pfd.cRedShift = 0;
    _pfd.cGreenBits         =   0; _pfd.cGreenShift = 0;
    _pfd.cBlueBits          =   0; _pfd.cBlueShift = 0;         // Color Bits Ignored
    _pfd.cAlphaBits         =   0; _pfd.cAlphaShift = 0;            // No Alpha Buffer

    _pfd.cAccumBits         =   0;
    _pfd.cAccumRedBits      =   0;
    _pfd.cAccumGreenBits    =   0;
    _pfd.cAccumBlueBits     =   0;
    _pfd.cAccumAlphaBits    =   0;

    _pfd.cDepthBits         =   16;                             // 16Bit Z-Buffer (Depth Buffer)
    _pfd.cStencilBits       =   0;                              // No Stencil Buffer
    _pfd.cAuxBuffers        =   0;                              // No Auxiliary Buffer
    _pfd.iLayerType         =   PFD_MAIN_PLANE;                 // Main Drawing Layer
    _pfd.bReserved          =   0;                              // Reserved

    _pfd.dwLayerMask        =   0;
    _pfd.dwVisibleMask      =   0;
    _pfd.dwDamageMask       =   0;                              // Layer Masks Ignored
}
glWndErrors glWndSettings::glSetStyle(HWND hWnd){
    GLboolean fullscreen = !_fullscreen;
    return glSetStyle(hWnd, fullscreen);
}
glWndErrors glWndSettings::glSetStyle(HWND hWnd, GLboolean fullscreen,  GLboolean save){
    DWORD dwExStyle = 0;
    DWORD dwStyle = 0;

    if (save)
        _fullscreen = fullscreen;

    if (fullscreen){
        dwExStyle = WS_EX_APPWINDOW;
        dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

        memset(&_screenSettings, 0, sizeof(_screenSettings));   // Makes Sure Memory's Cleared
        _screenSettings.dmSize = sizeof(_screenSettings);       // Size Of The Devmode Structure
        _screenSettings.dmPelsWidth = _width;                   // Selected Screen Width
        _screenSettings.dmPelsHeight = _height;                 // Selected Screen Height
        _screenSettings.dmBitsPerPel = _bits;                   // Selected Bits Per Pixel
        _screenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        // Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
        if (ChangeDisplaySettings(&_screenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){
            return errGoToFullscreen;
        }
        while(ShowCursor(FALSE) >= 0);
    }
    else{
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

        if (ChangeDisplaySettings(NULL, 0) != DISP_CHANGE_SUCCESSFUL){
            return errGoToWindowed;
        }
        while(ShowCursor(TRUE) < 0);
    }

    RECT windowRect;
    windowRect.left=(long)0;                // Set Left Value To 0
    windowRect.right=(long)_width;          // Set Right Value To Requested Width
    windowRect.top=(long)0;                 // Set Top Value To 0
    windowRect.bottom=(long)_height;        // Set Bottom Value To Requested Height

    AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size

    ShowWindow(hWnd, SW_HIDE);
    DWORD oldExStyle = SetWindowLongPtr(hWnd, GWL_EXSTYLE, dwExStyle);
    DWORD oldStyle = SetWindowLongPtr(hWnd, GWL_STYLE, dwStyle);
    SetWindowPos(hWnd, HWND_TOP, 0, 0, windowRect.right, windowRect.bottom, SWP_NOZORDER);
    ShowWindow(hWnd, SW_SHOW);

    return errNone;
}
glWndErrors glWndSettings::glSetResolution(HWND hWnd, GLsizei width, GLsizei height){
    _width = width; _height = height;
    glSetStyle(hWnd, _fullscreen);

    return errNone;
}

GLsizei& glWndSettings::Width(){
    return _width;
}
GLsizei& glWndSettings::Height(){
    return _height;
}
GLboolean& glWndSettings::Fullscreen(){
    return _fullscreen;
}
GLint& glWndSettings::Bits(){
    return _bits;
}
PIXELFORMATDESCRIPTOR& glWndSettings::PixelFormatDescription(){
    return _pfd;
}

glWndHandles::glWndHandles(HICON icon, string title, WNDPROC wndProc){
    _hInstance = NULL;
    _hWnd = NULL;
    _hDC = NULL;
    _hRC = NULL;
    _pixelFormat = NULL;

    _className = title;

    _wc.style               = CS_HREDRAW | CS_VREDRAW |         // Redraw On Size
                              CS_OWNDC;                         // Own DC For Window.
    _wc.lpfnWndProc         = wndProc;                          // WndProc Handles Messages
    _wc.cbClsExtra          = NULL;                             // No Extra Window Data
    _wc.cbWndExtra          = NULL;                             // No Extra Window Data
    _wc.hInstance           = NULL;                             // Set The Instance
    _wc.hIcon               = icon;                             // Load The Default Icon
    _wc.hCursor             = LoadCursor(NULL, IDC_ARROW);      // Load The Arrow Pointer
    _wc.hbrBackground       = NULL;                             // No Background Required For GL
    _wc.lpszMenuName        = NULL;                             // We Don't Want A Menu
    _wc.lpszClassName       = _className.c_str();               // Set The Class Name
}
glWndHandles::~glWndHandles(){
    // Are We Able To Release The DC And RC Contexts?
    if (_hRC){
        if (!wglMakeCurrent(NULL, NULL))
            MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

        // Are We Able To Delete The RC?
        if (!wglDeleteContext(_hRC))
            MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
    }

    // Are We Able To Release The DC
    if (_hDC && !ReleaseDC(_hWnd, _hDC))
        MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

    // Are We Able To Destroy The Window?
    if (_hWnd && !DestroyWindow(_hWnd))
        MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

    // Are We Able To Unregister Class
    if (!UnregisterClass(_className.c_str(), _hInstance))
        MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
glWndErrors glWndHandles::glDefWindow(PIXELFORMATDESCRIPTOR pfd){
    if ((_hInstance = GetModuleHandle(NULL))){
        _wc.hInstance = _hInstance;
    }
    else{
        MessageBox(NULL,  "Failed To Get Window's Instance.",  "ERROR", MB_OK|MB_ICONEXCLAMATION);
        return errGetInstance;
    }

    if (!RegisterClass(&_wc)){
        MessageBox(NULL,  "Failed To Register The Window Class.",  "ERROR", MB_OK|MB_ICONEXCLAMATION);
        return errCreateWC;
    }

    if (!(_hWnd=CreateWindowEx( NULL,                           // Extended Style For The Window
                                _wc.lpszClassName,              // Class Name
                                _className.c_str(),             // Window Title
                                NULL,                           // Style For The Window
                                0, 0, 300, 300,                 // Window's Position and Size
                                NULL,                           // No Parent Window
                                NULL,                           // No Menu
                                _hInstance,                     // Instance
                                NULL))){
        MessageBox(NULL, "Window Creation Error.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return errCreateWnd;
    }

    //Get Window's Device Context
    if (!(_hDC = GetDC(_hWnd))){
        MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return errCreateDC;
    }

    // Did Windows Find A Matching Pixel Format?
    if (!(_pixelFormat = ChoosePixelFormat(_hDC, &pfd))){
        MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return errMatchPixelFormat;
    }

    // Are We Able To Set The Pixel Format?
    if(!SetPixelFormat(_hDC, _pixelFormat, &pfd)){
        MessageBox(NULL, "Can't Set The PixelFormat.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return errSetPixelFormat;
    }

    if (!(_hRC=wglCreateContext(_hDC))){
        MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return errCreateRC;
    }

    if(!wglMakeCurrent(_hDC,_hRC)){
        MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR",MB_OK|MB_ICONEXCLAMATION);
        return errActivateRC;
    }

//  GLenum err = glewInit();
//
//  if (err != GLEW_OK){
//      MessageBox(NULL, (char*)glewGetErrorString(err), "ERROR", MB_OK|MB_ICONEXCLAMATION);
//      return errInitGL;
//  }

    return errNone;
}

HINSTANCE& glWndHandles::Instance(){
    return _hInstance;
}
WNDCLASS& glWndHandles::WinClass(){
    return _wc;
}
HDC& glWndHandles::DeviceContext(){
    return _hDC;
}
HGLRC& glWndHandles::RenderContext(){
    return _hRC;
}
HWND& glWndHandles::Window(){
    return _hWnd;
}

glWndFPS::glWndFPS(){
    _framesCounter = 0; _fps = 0;
}
GLvoid glWndFPS::NewFrame(){
    _framesCounter++;
}
GLvoid glWndFPS::ResetFrames(){
    _fps = _framesCounter; _framesCounter = 0;
}
GLint glWndFPS::FPS(){
    return _fps;
}

glWindow* owner;
LRESULT CALLBACK glWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    // Check For Windows Messages
    switch (uMsg){
        // Watch For Window Activate Message
        case WM_ACTIVATE:{
            // Check Minimization State
            if (!HIWORD(wParam)){
                // Program Is Active
                owner->_state = glActive;
            }
            else{
                // Program Is No Longer Active
                owner->_state = glPaused;
            }

            // Return To The Message Loop
            return 0;
        }
        // Intercept System Commands
        case WM_SYSCOMMAND:{
            // Check System Calls
            switch (wParam){
                // Screensaver Trying To Start?
                case SC_SCREENSAVE:
                // Monitor Trying To Enter Powersave?
                case SC_MONITORPOWER:
                // Prevent From Happening
                return 0;
            }
            break;
        }
        // Did We Receive A Close Message?
        case WM_CLOSE:{
            // Send A Quit Message
            PostQuitMessage(0);
            return 0;
        }
        // Is A Key Being Held Down?
        case WM_KEYDOWN:{
            // If So, Mark It As TRUE
            owner->_keys[wParam] = TRUE;
            return 0;
        }
        // Has A Key Been Released?
        case WM_KEYUP:{
            // If So, Mark It As FALSE
            owner->_keys[wParam] = FALSE;
            return 0;
        }
        // Resize The OpenGL Window
        case WM_SIZE:{
            if (owner->Settings().Fullscreen() && IsWindowVisible(hWnd)){
                if (wParam == SIZE_MINIMIZED)
                    owner->Settings().glSetStyle(hWnd, FALSE, FALSE);
                else if (wParam == SIZE_RESTORED)
                    owner->Settings().glSetStyle(hWnd, TRUE, FALSE);
            }

            // LoWord=Width, HiWord=Height
            owner->ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
            return 0;
        }
        case WM_KILLFOCUS:{
            if (IsWindowVisible(hWnd) && owner->Settings().Fullscreen())
                ShowWindow(hWnd, SW_MINIMIZE);

            return 0;
        }

        case WM_TIMER:{
            if (wParam == 1)
                owner->DisplayFPS();

            return 0;
        }
    }

    // Pass All Unhandled Messages To DefWindowProc
    return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

glWindow::glWindow(string title, int width, int height, int bits)
    :_settings(width, height, bits), _handles(LoadIcon(NULL, IDI_WINLOGO), title, (WNDPROC)WndProc)
{
    for (int i = 0; i < 256; i++){
        _keys[i] = false;
    }
    _error = errNone; _state = glActive; owner = this;
    _title = title;

    if ((_error = _handles.glDefWindow(_settings.PixelFormatDescription())) != errNone){
        return;
    }

    _settings.glSetStyle(_handles.Window(), false);
    SetForegroundWindow(_handles.Window());                     // Slightly Higher Priority
    SetFocus(_handles.Window());                                // Sets Keyboard Focus To The Window

    // Initialize Our Newly Created GL Window
    if (!InitGL()){
        MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK|MB_ICONEXCLAMATION);
        _error = errInitGL;
        return;
    }

    SetTimer(_handles.Window(), 1, 1000, NULL);
}

glWindow::~glWindow(void){
    if (_settings.Fullscreen()){
        ChangeDisplaySettings(NULL,0);          // If So Switch Back To The Desktop
        ShowCursor(TRUE);                       // Show Mouse Pointer
    }
}

int glWindow::InitGL(){
    glShadeModel(GL_SMOOTH);
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);

    glClearDepth(1.0f);                         // Depth Buffer Setup
    glEnable(GL_DEPTH_TEST);                    // Enables Depth Testing
    glDepthFunc(GL_LEQUAL);                     // The Type Of Depth Test To Do

    // Really Nice Perspective Calculations
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    return TRUE;                                // Initialization Went OK
}

GLvoid glWindow::Draw(){
    //Clear The Screen And The Depth Buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();                           // Reset The Current Modelview Matrix

    SwapBuffers(_handles.DeviceContext());

    fpsInfo().NewFrame();
}

glWndErrors& glWindow::LastError(){
    return _error;
}
glWndState& glWindow::WndState(){
    return _state;
}
glWndHandles& glWindow::Handles(){
    return _handles;
}
glWndSettings& glWindow::Settings(){
    return _settings;
}
glWndFPS& glWindow::fpsInfo(){
    return _fps;
}
bool& glWindow::KeysState(int key){
    return _keys[key];
}

GLvoid glWindow::DisplayFPS(){
    fpsInfo().ResetFrames();
    char fps[100];
    sprintf(fps, "%d", fpsInfo().FPS());

    SetTitle(_title + " : ");
    SetTimer(_handles.Window(), 1, 1000, NULL);
}
GLvoid glWindow::SetTitle(string title){
    SetWindowText(_handles.Window(), title.c_str());
}
GLvoid glWindow::SetResolution(GLsizei width, GLsizei height){
    _settings.glSetResolution(_handles.Window(), width, height);
}
GLvoid glWindow::SetFullscreen(GLboolean fullscreen){
    _settings.glSetStyle(_handles.Window(), fullscreen);
}
GLvoid glWindow::ToggleFullscreen(){
    _settings.glSetStyle(_handles.Window());
}

GLvoid glWindow::ReSizeGLScene(GLsizei width, GLsizei height){
    if (height == 0 && width == 0){
        return;
    }

    glViewport(0, 0, width, height);

    glMatrixMode(GL_PROJECTION);                // Select The Projection Matrix
    glLoadIdentity();                           // Reset The Projection Matrix

    // Calculate The Aspect Ratio Of The Window
    glm::perspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);

    glMatrixMode(GL_MODELVIEW);                 // Select The Modelview Matrix
    glLoadIdentity();                           // Reset The Modelview Matrix
}

Compiler output

g++ -ID:/DarkLight/hello/header -ID:/DarkLight/externals/include -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\glWindow.o" "..\\src\\glWindow.cpp"
g++ -ID:/DarkLight/hello/header -ID:/DarkLight/externals/include -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\hello.o" "..\\src\\hello.cpp" 
g++ -mwindows -o hello.exe "src\\hello.o" "src\\glWindow.o" -lgl -lglew32 -lglu32 -lopengl32 -lgdi32 

Solution

  • How did you compile the Cygwin build? Specifically which libraries did you link?

    Cygwin can be compiled for the native GUI system (Win32) or to make use of X11. But OpenGL goes through two very different stacks between the two cases. In case of Win32 it goes through WGL and in case of X11 it goes through GLX. Now if you accidently linked the GLX based OpenGL API (-lGL) then all the OpenGL symbols are there, so things seem to work superficially, but there's no output. You have to link against opengl32.lib, i.e. -lopengl32 so that the WGL based bindings are used.