Quad-Ren 0.5 Released


hessiess

Member
Joined
Apr 26, 2008
Messages
219
Quad-ren is a resolution independent 2D graphics engine which focuses on minimalism and follows the suckless philosophy. The applications created with Quad-ren are always resizeable, either running in a window or full screen, allowing them to work flawlessly with a wide range of screen resolutions as well as with tiling window managers.

Quad-ren version 0.5 has now bean released, this version adds a lot of new features including a scene graph, scene graph variables, the separation of event receivers and animators. Another example program has bean added and the antialiasing bug which caused crashes in the previous version has now bean fixed.

Main website.

res_independance_ex.png
 
Nice sadly I cannot code nor do I have great idea's and I suck at anything artistic. But I do like stuff with a great idea behind it by people who can code or are artistic
 
Is there any one here who has knowledge of the win32 API? Im working on a cross platform layer for Quad-ren, including a native win32 OpenGL interface. Its mainly working except for some problems with event receiving, for example the program wont always close when the `x' button is clicked.
 
Hessiess said:
Is there any one here who has knowledge of the win32 API? Im working on a cross platform layer for Quad-ren, including a native win32 OpenGL interface. Its mainly working except for some problems with event receiving, for example the program wont always close when the `x' button is clicked.
On which level are you writing this stuff? Do you have a manual WndProc function or do you use some kind of framework to do the dirty job for you?
 
Last edited by a moderator:
dflemstr said:
Hessiess said:
Is there any one here who has knowledge of the win32 API? Im working on a cross platform layer for Quad-ren, including a native win32 OpenGL interface. Its mainly working except for some problems with event receiving, for example the program wont always close when the `x' button is clicked.
On which level are you writing this stuff? Do you have a manual WndProc function or do you use some kind of framework to do the dirty job for you?
Have you considered SDL?
http://www.libsdl.org/cgi/docwiki.cgi
It lets you use OpenGL and receive basic window events on any platform without Win32's BS.

But no, I don't know anything Win32-specific. It's probably very nasty, and they want you to use .NET now.
 
Last edited by a moderator:
Its using a WndProc callback, basically just raw win32 api. Yes I have considered using SDL, it is currently the only API supported by Quad-Ren, however I want to add multi-window support which is not available in SDL. Ive bean building a simple wrapper class that wraps around the underlying code, however the design of the win32 API makes it difficult to provide multi window support in this way, where each window should be its own instance of the wrapper class.

Additionally, for some reason the main trunk of quad-ren will compile with visual studio and SDL after some work (removing stdint.h types) but crashes the OS when it runs, though I am running windows in a VM, outher OpenGL applications like Blender, and the native win api test, run without this crash.

The full source code is available in the following directory of the quad-ren SVN repository.

Code:
svn co https://quad-ren.svn.sourceforge.net/svnroot/quad-ren/tests/winelibtest/src src

This has developed mainly using Winelib on Linux, and it does compile and run on windows with visual studio.

The flowing is the windows specific code:

Code:
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <string>
#include <iostream>

#include "qr_common_vectors.h"
#include "qr_events.h"
#include "qr_driver_base.h"
#include "qr_opengl_common.h"
#include "qr_win32_driver.h"

namespace qr
{
    namespace internal
    {
        driver *driver_instance = NULL; //hack to alow access to class instance from windows callback

/*********************************************************************/
        driver::driver(
            vector2d_i viewp_aspr, float project_width, bool fullscreen,
            vector2d_i size_hint, bool vsync, int multisample)
        {
        // store a copy of the aspect ratio
            this->viewp_aspr    = viewp_aspr;
            this->project_width = project_width;
            this->multisample   = multisample;
            this->vsync         = vsync;
            this->fullscreen    = fullscreen;

        // Check if there is already a driver instance
            if(driver_instance == NULL)
                driver_instance=this;
            else
            {
                std::cout<<"A driver already exists\n";
                throw 1;
            }
            
        // Find the current screen resolution
            vector2d_i screen_size = get_screen_res();

        // If alt res is 0 or full screen mode is enabled, set the window resolution to
        // the screen resolution
            if((size_hint.X == 0 && size_hint.Y == 0) || this->fullscreen == true)
                this->window_size = screen_size;
            else
                this->window_size = size_hint;

        // Set up window
            create_window();
        }

/*********************************************************************/
        void driver::create_window()
        {
        // Register window class
            register_class();

            vector2d_i screen_res = this->get_screen_res();

            set_window_size(screen_res);

            if(this->fullscreen)
                enable_fullscreen();

            make_window();

        //create device context
            this->h_dc=GetDC(h_wnd);

        //get device context
            this->h_dc=GetDC(h_wnd);

            set_pix_format();

        // Create and activate GL context
            this->h_rc=wglCreateContext(h_dc);
            wglMakeCurrent(h_dc,h_rc);

        // Make the window visible
            ShowWindow(h_wnd,SW_SHOW); 
            SetForegroundWindow(h_wnd);
            SetFocus(h_wnd);

        // Resize gl viewport
            resize_viewport();

            set_projection();

            init();
        }

/*********************************************************************/
        void driver::destroy_window()
        {
            if (fullscreen)
            {
                ChangeDisplaySettings(NULL,0);  
                ShowCursor(TRUE);              
            }

            if (h_rc)                    
            {
                wglMakeCurrent(NULL,NULL);
                wglDeleteContext(h_rc);   
            }

            if (h_dc)
            {
                ReleaseDC(h_wnd,h_dc);
            }

            if (h_wnd)
            {
                DestroyWindow(h_wnd);
            }

            UnregisterClass("Quad-ren",h_instance);
        }

/*********************************************************************/
        bool driver::get_event(event **nevent)
        {
            MSG     msg;

            *nevent = NULL;

            if (PeekMessage(&msg,h_wnd,0,0,PM_REMOVE))
            {
                std::cout<<"msg"<<msg.message<<" \n";

                if (msg.message == WM_QUIT)
                {
                    std::cout<<"quit\n";
                    return false;
                }
                else if (msg.message == WM_KEYDOWN)
                {
                    std::cout<<"key pressed"<<msg.wParam<<"\n";
                    *(nevent) = new keydown_event(msg.wParam);
                }
                else if (msg.message == WM_KEYUP)
                {
                    std::cout<<"key released"<<msg.wParam<<"\n";
                    *(nevent) = new keyup_event(msg.wParam);
                }
                else
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);   
                }
            }

       //     std::cout<<nevent;
            return true;
        }

/*********************************************************************/
        LRESULT CALLBACK driver::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        {
            switch (uMsg)                                   // Check For Windows Messages
            {
                case WM_SYSCOMMAND:                         // Intercept System Commands
                {
                    switch (wParam)                         // Check System Calls
                    {
                        case SC_SCREENSAVE:                 // Screensaver Trying To Start?
                        case SC_MONITORPOWER:               // Monitor Trying To Enter Powersave?
                        return 0;                           // Prevent From Happening
                    }
                    break;                                  // Exit
                }
                
                case WM_CLOSE:                              // Did We Receive A Close Message?
                {
                    std::cout<<"quit\n";
                    PostQuitMessage(0);                     // Send A Quit Message
                    return 0; 
                }

                case WM_PAINT:                        
                {
                    driver_instance->draw();
                    return 0;  
                }

                case WM_SIZE:                        
                {
                    driver_instance->set_window_size(qr::vector2d_i(LOWORD(lParam), HIWORD(lParam)));
                    driver_instance->resize_viewport();

                    driver_instance->draw();
                    return 0;                         
                }
            }

            return DefWindowProc(hWnd,uMsg,wParam,lParam);
        }

/*********************************************************************/
        void driver::register_class()
        {
        // Set up window class
            this->h_instance = GetModuleHandle(NULL);
            wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
            wc.lpfnWndProc   = (WNDPROC) WndProc;
            wc.cbClsExtra    = 0;
            wc.cbWndExtra    = 0;
            wc.hInstance     = this->h_instance;
            wc.hIcon         = LoadIcon(NULL,   IDI_WINLOGO);
            wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
            wc.hbrBackground = NULL;
            wc.lpszMenuName  = NULL;
            wc.lpszClassName = "Quad-ren";

            if(!RegisterClass(&wc))
            {
                std::cout<<"Failed to register window class\n";
                throw int(1);
            }
        }

/*********************************************************************/
        void driver::make_window()
        {
            int dw_ex_style = 0;
            int dw_style   = 0;

            if (fullscreen)                                             // Are We Still In Fullscreen Mode?
            {
                dw_ex_style = WS_EX_APPWINDOW;                              // Window Extended Style
                dw_style    = WS_POPUP;                                       // Windows Style
                ShowCursor(false);                                      // Hide Mouse Pointer
            }
            else
            {
                dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;           // Window Extended Style
                dw_style    = WS_OVERLAPPEDWINDOW;                            // Windows Style
            }

        // Create window
            if (!(h_wnd=CreateWindowEx(
                dw_ex_style,                          // Extended Style For The Window
                "Quad-ren",                           // Class Name
                "",                                   // Window title
                dw_style |
                WS_CLIPSIBLINGS |                     // Required Window Style
                WS_CLIPCHILDREN,                      // Required Window Style
                0, 0,                                 // Window Position
                this->window_size.X,                  // Calculate Window Width
                this->window_size.Y,                  // Calculate Window Height
                NULL,                                 // No Parent Window
                NULL,                                 // No Menu
                h_instance,                           // Instance
                NULL)))                               // Don't Pass Anything To WM_CREATE
            {
                std::cout<<"Failed to create window\n";
                throw int(1);
            }
        }

/*********************************************************************/
        void driver::set_pix_format()
        {
            static  PIXELFORMATDESCRIPTOR pfd=              // pfd Tells Windows How We Want Things To Be
            {
                sizeof(PIXELFORMATDESCRIPTOR),              // Size Of This Pixel Format Descriptor
                1,                                          // Version Number
                PFD_DRAW_TO_WINDOW |                        // Format Must Support Window
                PFD_SUPPORT_OPENGL |                        // Format Must Support OpenGL
                PFD_DOUBLEBUFFER,                           // Must Support Double Buffering
                PFD_TYPE_RGBA,                              // Request An RGBA Format
                24,                                       // Select Our Color Depth
                0, 0, 0, 0, 0, 0,                           // Color Bits Ignored
                0,                                          // No Alpha Buffer
                0,                                          // Shift Bit Ignored
                0,                                          // No Accumulation Buffer
                0, 0, 0, 0,                                 // Accumulation Bits Ignored
                16,                                         // 16Bit Z-Buffer (Depth Buffer)  
                0,                                          // No Stencil Buffer
                0,                                          // No Auxiliary Buffer
                PFD_MAIN_PLANE,                             // Main Drawing Layer
                0,                                          // Reserved
                0, 0, 0                                     // Layer Masks Ignored
            };

            unsigned int PixelFormat = ChoosePixelFormat(h_dc,&pfd);

            SetPixelFormat(h_dc, PixelFormat,&pfd);
        }

/*********************************************************************/
        void driver::enable_fullscreen()
        {
            if (fullscreen)
            {
                vector2d_i screen_res = this->get_screen_res();

                DEVMODE dmScreenSettings;                               // Device Mode
                memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
                dmScreenSettings.dmSize=sizeof(dmScreenSettings);       // Size Of The Devmode Structure
                dmScreenSettings.dmPelsWidth    = screen_res.X;                // Selected Screen Width
                dmScreenSettings.dmPelsHeight   = screen_res.Y;               // Selected Screen Height
                dmScreenSettings.dmBitsPerPel   = 32;                   // Selected Bits Per Pixel
                dmScreenSettings.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(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
                {
                    // If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
                    if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
                    {
                        fullscreen=FALSE;       // Windowed Mode Selected.  Fullscreen = FALSE
                    }
                    else
                    {
                        // Pop Up A Message Box Letting User Know The Program Is Closing.
                        MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
                        throw 1;
                        //return FALSE;                                   // Return FALSE
                    }
                }
            }
        }

/*********************************************************************/
        void driver::set_window_size(vector2d_i new_window_size)
        {
            RECT        window_rect;
            window_rect.left   = 0;
            window_rect.right  = new_window_size.X;
            window_rect.top    = 0;
            window_rect.bottom = new_window_size.Y;

       // Adjust window size to account for borders.
            AdjustWindowRectEx(&window_rect, WS_OVERLAPPEDWINDOW, false, WS_EX_APPWINDOW);

            this->window_size.X = window_rect.right  - window_rect.left;
            this->window_size.Y = window_rect.bottom - window_rect.top;
        }
    }
}




int main()
{
    qr::internal::driver *drv = new qr::internal::driver(qr::vector2d_i(16,9), 10);

    qr::event *nevent;

    while(drv->get_event(&nevent))
    {
        if(nevent != NULL && nevent->get_type() == qr::EV_KEYDOWN)
        {
            qr::keydown_event *devent = (qr::keydown_event*) nevent;

            if(devent->get_keysym() == VK_SPACE)
                drv->toggle_fullscreen();
        }

        drv->draw();
    }
}
 
OK, my spontaneous comments:
  • This seems to be unnecessary to do twice:
    Code:
            //create device context
                this->h_dc=GetDC(h_wnd);
    
            //get device context
                this->h_dc=GetDC(h_wnd);
  • You test for WM_CLOSE but not WM_DESTROY. Also, you should call PostQuitMessage in the WM_DESTROY handler, not WM_CLOSE. CLOSE happens when the close button is pressed, DESTROY happens when the window is to be destroyed. You should only need to handle WM_CLOSE if you want to prevent the window from closing when the X button is pressed for some reason.
    Code:
                    case WM_CLOSE:                              // Did We Receive A Close Message?
                    {
                        std::cout<<"quit\n";
                        PostQuitMessage(0);                     // Send A Quit Message
                        return 0; 
                    }
  • There might be issues with threading later on if you want to draw to multiple windows simultaneously but that might not be important right now.

Looks pretty OK otherwise...
 
dflemstr said:
OK, my spontaneous comments:
  • This seems to be unnecessary to do twice:
    Code:
            //create device context
                this->h_dc=GetDC(h_wnd);
    
            //get device context
                this->h_dc=GetDC(h_wnd);
Slaps self.

  • You test for WM_CLOSE but not WM_DESTROY. Also, you should call PostQuitMessage in the WM_DESTROY handler, not WM_CLOSE. CLOSE happens when the close button is pressed, DESTROY happens when the window is to be destroyed. You should only need to handle WM_CLOSE if you want to prevent the window from closing when the X button is pressed for some reason.


    Code:
                    case WM_CLOSE:                              // Did We Receive A Close Message?
                    {
                        std::cout<<"quit\n";
                        PostQuitMessage(0);                     // Send A Quit Message
                        return 0; 
                    }
  • There might be issues with threading later on if you want to draw to multiple windows simultaneously but that might not be important right now.

Looks pretty OK otherwise...

About WM_CLOSE, this code is based on the NeHe windows opengl set-up code here which handles WM_CLOSE but not WM_DESTROY as is done here. Considering that my event problems are related to the window not always closing properly, this may be the cause. Though for some reason the original example code that this is based on works without problems.
edit: yes, that fixed the problem

What problems would occur in a multithreaded environment? `make quad-ren thread safe' is one of the things on my to do list, though I currently know little about concurrency and how to achieve thread safety without platform dependence.

Thanks for your help.
 
Last edited by a moderator:
Back
Top