Patch [#26799] 2.5x blenderplayer (BGE) anti-aliasing & embedding by Sebastian Korcza...
authorDalai Felinto <dfelinto@gmail.com>
Wed, 4 May 2011 01:50:17 +0000 (01:50 +0000)
committerDalai Felinto <dfelinto@gmail.com>
Wed, 4 May 2011 01:50:17 +0000 (01:50 +0000)
The patch can also be found in http://codereview.appspot.com/4431072/

##############
This patch fix anti-aliasing (multisampling) implementation for win32 platform. It also gives opportunity to embed blenderplayer inside parent window.

Usage:
blenderplayer.exe -i 123456 -m 16 file.blend

where:
123456 - parent window handler (integer, default: 0)
16 - multisample level (integer, default: 0, max: 16. Put there maximum level you want. If not supported, player will automatically try 15,14,13,...,3,2,1)
##############

This patch was originally created as part of the Burster (aka webplugin) project but benefit any one embedding the bge in a custom OpenGL context. By the way, to embed the BGE in a .Net application is really straightforward now =)
The Multisampling work for blenderplayer as a whole.

Missing functionalities:
- to expose the multisampling to the ui (so far it only works in console)
- window focus and keyboard messages for embedded blenderplayer (supported in their previous patch for 2.49, yet to be ported over)
- handle resizing (to be investigated, indeed the changes in getState() in GHOST_WindowWin32.cpp are going to get in the way of that if I'm not mistaken. To be addressed together.

Doxygen documentation to be added whenever I sort out how to do so. Sorry Nathan too many stuff to deal with at the same time. The sooner this patch gets in, the sooner the missing functionalities can be patched on top of that.

intern/ghost/intern/GHOST_Debug.h
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_WindowWin32.cpp
intern/ghost/intern/GHOST_WindowWin32.h
source/gameengine/GamePlayer/ghost/GPG_Application.cpp
source/gameengine/GamePlayer/ghost/GPG_Application.h
source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp

index 602f52a6435c3998c3da9a8bbfdfb1b3212713b1..e77f3b9c46106681678e61b18ff61fef019647b1 100644 (file)
 
 #ifdef GHOST_DEBUG
        #define GHOST_PRINT(x) { std::cout << x; }
-       //#define GHOST_PRINTF(x) { printf(x); }
+       #define GHOST_PRINTF(x, ...) { printf(x, __VA_ARGS__); }
 #else  // GHOST_DEBUG
        #define GHOST_PRINT(x)
-       //#define GHOST_PRINTF(x)
+       #define GHOST_PRINTF(x, ...)
 #endif // GHOST_DEBUG
 
 
index ffc090ba0588b2b2fce5a3e23f25b68667462043..2fdddda835dadfdcb3d1077ecb62eb1b819e44b6 100644 (file)
@@ -238,7 +238,7 @@ GHOST_IWindow* GHOST_SystemWin32::createWindow(
        bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow )
 {
        GHOST_Window* window = 0;
-       window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples);
+       window = new GHOST_WindowWin32 (this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples, parentWindow);
        if (window) {
                if (window->getValid()) {
                        // Store the pointer to the window
@@ -247,6 +247,14 @@ GHOST_IWindow* GHOST_SystemWin32::createWindow(
 //                     }
                }
                else {
+
+                       // Invalid parent window hwnd
+                       if (((GHOST_WindowWin32*)window)->getNextWindow() == NULL) {
+                               delete window;
+                               window = 0;
+                               return window;
+                       }
+
                        // An invalid window could be one that was used to test for AA
                        window = ((GHOST_WindowWin32*)window)->getNextWindow();
                        
index 5d21edb758de89184313b04b92aa5880aebefe64..a89b2608bb45c1136ab323dc79037d584d532a69 100644 (file)
@@ -132,6 +132,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(
        GHOST_TDrawingContextType type,
        const bool stereoVisual,
        const GHOST_TUns16 numOfAASamples,
+       GHOST_TEmbedderWindowID parentwindowhwnd,
        GHOST_TSuccess msEnabled,
        int msPixelFormat)
 :
@@ -149,6 +150,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(
        m_tablet(0),
        m_maxPressure(0),
        m_multisample(numOfAASamples),
+       m_parentWindowHwnd(parentwindowhwnd),
        m_multisampleEnabled(msEnabled),
        m_msPixelFormat(msPixelFormat),
        //For recreation
@@ -223,15 +225,26 @@ GHOST_WindowWin32::GHOST_WindowWin32(
                else if(top < monitor.rcWork.top)
                        top = monitor.rcWork.top;
 
+               int wintype = WS_OVERLAPPEDWINDOW;
+               if (m_parentWindowHwnd != 0)
+               {
+                       wintype = WS_CHILD;
+                       GetWindowRect((HWND)m_parentWindowHwnd, &rect);
+                       left = 0;
+                       top = 0;
+                       width = rect.right - rect.left;
+                       height = rect.bottom - rect.top;
+               }
+               
                m_hWnd = ::CreateWindow(
                        s_windowClassName,                      // pointer to registered class name
                        title,                                          // pointer to window name
-                       WS_OVERLAPPEDWINDOW,            // window style
+                       wintype,                                        // window style
                        left,                                   // horizontal position of window
                        top,                                    // vertical position of window
                        width,                                          // window width
                        height,                                         // window height
-                       HWND_DESKTOP,                           // handle to parent or owner window
+                       (HWND) m_parentWindowHwnd,      // handle to parent or owner window
                        0,                                                      // handle to menu or child-window identifier
                        ::GetModuleHandle(0),           // handle to application instance
                        0);                                                     // pointer to window-creation data
@@ -452,6 +465,11 @@ void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
                        bounds.m_l = rect.left + sm_cysizeframe;
                        bounds.m_r = rect.right - sm_cysizeframe;
                        bounds.m_t = rect.top;
+               } else if (state == GHOST_kWindowStateEmbedded) {
+                       bounds.m_b = rect.bottom;
+                       bounds.m_l = rect.left;
+                       bounds.m_r = rect.right;
+                       bounds.m_t = rect.top;
                } else {
                        bounds.m_b = rect.bottom-GetSystemMetrics(SM_CYCAPTION)-sm_cysizeframe*2;
                        bounds.m_l = rect.left;
@@ -459,7 +477,6 @@ void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
                        bounds.m_t = rect.top;
                }
        } else {
-               ::GetWindowRect(m_hWnd, &rect);
                bounds.m_b = rect.bottom;
                bounds.m_l = rect.left;
                bounds.m_r = rect.right;
@@ -528,6 +545,15 @@ GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32
 GHOST_TWindowState GHOST_WindowWin32::getState() const
 {
        GHOST_TWindowState state;
+
+       // XXX 27.04.2011
+       // we need to find a way to combine parented windows + resizing if we simply set the
+       // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
+       // It's also strange that in Windows is the only platform we need to make this separation.
+       if (m_parentWindowHwnd != 0) {
+               state = GHOST_kWindowStateEmbedded;
+               return state;
+       }
        if (::IsIconic(m_hWnd)) {
                state = GHOST_kWindowStateMinimized;
        }
@@ -589,6 +615,9 @@ GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
                wp.ptMaxPosition.y = 0;
                SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
                break;
+       case GHOST_kWindowStateEmbedded:
+               SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
+               break;
        case GHOST_kWindowStateNormal:
        default:
                ShowWindow(m_hWnd, SW_HIDE);
@@ -651,10 +680,11 @@ GHOST_TSuccess GHOST_WindowWin32::invalidate()
 GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd)
 {
        int pixelFormat;
-       bool success;
+       bool success = FALSE;
        UINT numFormats;
        HDC hDC = GetDC(getHWND());
        float fAttributes[] = {0, 0};
+       UINT nMaxFormats = 1;
 
        // The attributes to look for
        int iAttributes[] = {
@@ -679,36 +709,24 @@ GHOST_TSuccess GHOST_WindowWin32::initMultisample(PIXELFORMATDESCRIPTOR pfd)
                return GHOST_kFailure;
        }
 
-       // See if the format is valid
-       success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
-
-       if (success && numFormats >= 1)
-       {
-               m_multisampleEnabled = GHOST_kSuccess;
-               m_msPixelFormat = pixelFormat;
-               return GHOST_kSuccess;
-       }
-       else
-       {
-               // See if any formats are supported
-               while (!success && iAttributes[19] != 0)
-               {
-                       iAttributes[19] /= 2;
-
-                       success = wglChoosePixelFormatARB(m_hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
-
-                       if (success && numFormats >= 1)
-                       {
-                               m_multisampleEnabled = GHOST_kSuccess;
-                               m_msPixelFormat = pixelFormat;
-                               return GHOST_kSuccess;
-                       }
+       // iAttributes[17] is the initial multisample. If not valid try to use the closest valid value under it.
+       while (iAttributes[17] > 0) {
+               // See if the format is valid
+               success = wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, nMaxFormats, &pixelFormat, &numFormats);
+               GHOST_PRINTF("WGL_SAMPLES_ARB = %i --> success = %i, %i formats\n", iAttributes[17], success, numFormats);
 
-                       success = GHOST_kFailure;
+               if (success && numFormats >= 1 && m_multisampleEnabled == GHOST_kFailure) {
+                       GHOST_PRINTF("valid pixel format with %i multisamples\n", iAttributes[17]);
+                       m_multisampleEnabled = GHOST_kSuccess;
+                       m_msPixelFormat = pixelFormat;
                }
+               iAttributes[17] -= 1;
+               success = GHOST_kFailure;
        }
-
-       // No available pixel format...
+       if (m_multisampleEnabled == GHOST_kSuccess)     {
+               return GHOST_kSuccess;
+       }
+       GHOST_PRINT("no available pixel format\n");
        return GHOST_kFailure;
 }
 
@@ -856,12 +874,17 @@ GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextTyp
                                                                                                        type,
                                                                                                        m_stereo,
                                                                                                        m_multisample,
+                                                                                                       m_parentWindowHwnd,
                                                                                                        m_multisampleEnabled,
                                                                                                        m_msPixelFormat);
 
                                        // Return failure so we can trash this window.
                                        success = GHOST_kFailure;
                                        break;
+                               } else {
+                                       m_multisampleEnabled = GHOST_kSuccess;
+                                       printf("Multisample failed to initialized\n");
+                                       success = GHOST_kSuccess;
                                }
                        }
                }
index 20212bbc2afd6d45f86dcbbe2981929ababcc5bc..4055c3acf56ed1e4e99a38ac836bfec982e12d56 100644 (file)
@@ -100,6 +100,7 @@ public:
                GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
                const bool stereoVisual = false,
                const GHOST_TUns16 numOfAASamples = 0,
+               GHOST_TEmbedderWindowID parentWindowHwnd=0,
                GHOST_TSuccess msEnabled = GHOST_kFailure,
                int msPixelFormat = 0
        );
@@ -391,6 +392,9 @@ protected:
 
        /** The GHOST_System passes this to wm if this window is being replaced */
        GHOST_Window *m_nextWindow;
+
+       /** Hwnd to parent window */
+       GHOST_TEmbedderWindowID m_parentWindowHwnd;
 };
 
 #endif // _GHOST_WINDOW_WIN32_H_
index e00a890a1fb90ed29391e83fc21c7db11ca8dbe3..6ea98e0e8cc114ae4980229c29fa8e26fd8a98f5 100644 (file)
@@ -233,7 +233,8 @@ static HWND findGhostWindowHWND(GHOST_IWindow* window)
 bool GPG_Application::startScreenSaverPreview(
        HWND parentWindow,
        const bool stereoVisual,
-       const int stereoMode)
+       const int stereoMode,
+       const GHOST_TUns16 samples)
 {
        bool success = false;
 
@@ -245,7 +246,7 @@ bool GPG_Application::startScreenSaverPreview(
                STR_String title = "";
                                                        
                m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized,
-                       GHOST_kDrawingContextTypeOpenGL, stereoVisual);
+                       GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples);
                if (!m_mainWindow) {
                        printf("error: could not create main window\n");
                        exit(-1);
@@ -287,9 +288,10 @@ bool GPG_Application::startScreenSaverFullScreen(
                int height,
                int bpp,int frequency,
                const bool stereoVisual,
-               const int stereoMode)
+               const int stereoMode,
+               const GHOST_TUns16 samples)
 {
-       bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode);
+       bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, samples);
        if (ret)
        {
                HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
@@ -311,13 +313,14 @@ bool GPG_Application::startWindow(STR_String& title,
        int windowWidth,
        int windowHeight,
        const bool stereoVisual,
-       const int stereoMode)
+       const int stereoMode,
+       const GHOST_TUns16 samples)
 {
        bool success;
        // Create the main window
        //STR_String title ("Blender Player - GHOST");
        m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
-               GHOST_kDrawingContextTypeOpenGL, stereoVisual);
+               GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples);
        if (!m_mainWindow) {
                printf("error: could not create main window\n");
                exit(-1);
@@ -339,10 +342,13 @@ bool GPG_Application::startWindow(STR_String& title,
 bool GPG_Application::startEmbeddedWindow(STR_String& title,
        const GHOST_TEmbedderWindowID parentWindow, 
        const bool stereoVisual, 
-       const int stereoMode) {
-
-       m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, GHOST_kWindowStateNormal,
-               GHOST_kDrawingContextTypeOpenGL, stereoVisual, parentWindow);
+       const int stereoMode,
+       const GHOST_TUns16 samples) {
+       GHOST_TWindowState state = GHOST_kWindowStateNormal;
+       if (parentWindow != 0)
+               state = GHOST_kWindowStateEmbedded;
+       m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, state,
+               GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples, parentWindow);
 
        if (!m_mainWindow) {
                printf("error: could not create main window\n");
@@ -363,7 +369,8 @@ bool GPG_Application::startFullScreen(
                int height,
                int bpp,int frequency,
                const bool stereoVisual,
-               const int stereoMode)
+               const int stereoMode,
+               const GHOST_TUns16 samples)
 {
        bool success;
        // Create the main window
index 850b34d5b692536261b3765845845425a4bdd983..c06385176577b0eb36122216610770d12b3b6b1c 100644 (file)
@@ -63,12 +63,12 @@ public:
 
                        bool SetGameEngineData(struct Main* maggie, struct Scene* scene, int argc, char** argv);
                        bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight,
-                       const bool stereoVisual, const int stereoMode);
-                       bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode);
-                       bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window, const bool stereoVisual, const int stereoMode);
+                       const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+                       bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+                       bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
 #ifdef WIN32
-                       bool startScreenSaverFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode);
-                       bool startScreenSaverPreview(HWND parentWindow, const bool stereoVisual, const int stereoMode);
+                       bool startScreenSaverFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+                       bool startScreenSaverPreview(HWND parentWindow, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
 #endif
 
        virtual bool processEvent(GHOST_IEvent* event);
index 968d6caeb1c0e1581e85b19964949ae647909b2e..0ab6da240ce43f2d91b49e8745f9c13abeeff6a3 100644 (file)
@@ -199,7 +199,7 @@ void usage(const char* program, bool isBlenderPlayer)
        }
        
        printf("usage:   %s [-w [w h l t]] [-f [fw fh fb ff]] %s[-g gamengineoptions] "
-               "[-s stereomode] %s\n", program, consoleoption, filename);
+               "[-s stereomode] [-m aasamples] %s\n", program, consoleoption, filename);
        printf("  -h: Prints this command summary\n\n");
        printf("  -w: display in a window\n");
        printf("       --Optional parameters--\n"); 
@@ -235,9 +235,8 @@ void usage(const char* program, bool isBlenderPlayer)
        printf("             cubemap                (Cube Map)\n");
        printf("             sphericalpanoramic     (Spherical Panoramic)\n");
        printf("                             depending on the type of dome you are using\n\n");
-#ifndef _WIN32
+       printf("  -m: maximum anti-aliasing (eg. 2,4,8,16)\n\n");
        printf("  -i: parent windows ID \n\n");
-#endif
 #ifdef _WIN32
        printf("  -c: keep console window open\n\n");
 #endif
@@ -257,6 +256,7 @@ void usage(const char* program, bool isBlenderPlayer)
        printf("\n");
        printf("example: %s -w 320 200 10 10 -g noaudio%s%s\n", program, pathname, filename);
        printf("example: %s -g show_framerate = 0 %s%s\n", program, pathname, filename);
+       printf("example: %s -i 232421 -m 16 %s%s\n\n", program, pathname, filename);
 }
 
 static void get_filename(int argc, char **argv, char *filename)
@@ -367,6 +367,7 @@ int main(int argc, char** argv)
        GHOST_TEmbedderWindowID parentWindow = 0;
        bool isBlenderPlayer = false;
        int validArguments=0;
+       GHOST_TUns16 aasamples = 0;
        
 #ifdef __linux__
 #ifdef __alpha__
@@ -553,7 +554,6 @@ int main(int argc, char** argv)
                                usage(argv[0], isBlenderPlayer);
                                return 0;
                                break;
-#ifndef _WIN32
                        case 'i':
                                i++;
                                if ( (i + 1) <= validArguments )
@@ -562,12 +562,15 @@ int main(int argc, char** argv)
                                        error = true;
                                        printf("error: too few options for parent window argument.\n");
                                }
-
 #if defined(DEBUG)
                                printf("XWindows ID = %d\n", parentWindow);
 #endif // defined(DEBUG)
-
-#endif  // _WIN32                      
+                               break;
+                       case 'm':
+                               i++;
+                               if ((i+1) <= validArguments )
+                               aasamples = atoi(argv[i++]);
+                               break;
                        case 'c':
                                i++;
                                closeConsole = false;
@@ -857,13 +860,13 @@ int main(int argc, char** argv)
                                                                if (scr_saver_mode == SCREEN_SAVER_MODE_SAVER)
                                                                {
                                                                        app.startScreenSaverFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
-                                                                               stereoWindow, stereomode);
+                                                                               stereoWindow, stereomode, aasamples);
                                                                }
                                                                else
 #endif
                                                                {
                                                                        app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency,
-                                                                               stereoWindow, stereomode);
+                                                                               stereoWindow, stereomode, aasamples);
                                                                }
                                                        }
                                                        else
@@ -903,16 +906,16 @@ int main(int argc, char** argv)
 #ifdef WIN32
                                                                if (scr_saver_mode == SCREEN_SAVER_MODE_PREVIEW)
                                                                {
-                                                                       app.startScreenSaverPreview(scr_saver_hwnd, stereoWindow, stereomode);
+                                                                       app.startScreenSaverPreview(scr_saver_hwnd, stereoWindow, stereomode, aasamples);
                                                                }
                                                                else
 #endif
                                                                {
                                                                                                                                                                                                                if (parentWindow != 0)
-                                                                               app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode);
+                                                                               app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples);
                                                                        else
                                                                                app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
-                                                                               stereoWindow, stereomode);
+                                                                               stereoWindow, stereomode, aasamples);
                                                                }
                                                        }
                                                }
index 0c47b0d01bfcb5164227c699ccb072af346390ca..23e0a50ed6f01c538429f0ba93124690ca251c1d 100644 (file)
@@ -303,6 +303,8 @@ bool RAS_OpenGLRasterizer::BeginFrame(int drawingmode, double time)
 
        glShadeModel(GL_SMOOTH);
 
+       glEnable(GL_MULTISAMPLE_ARB);
+
        m_2DCanvas->BeginFrame();
        
        return true;
@@ -387,6 +389,9 @@ void RAS_OpenGLRasterizer::EndFrame()
        FlushDebugLines();
 
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+       glDisable(GL_MULTISAMPLE_ARB);
+
        m_2DCanvas->EndFrame();
 }