Das Leid mit OpenGL und XPlatform



  • Ah ok.

    Scorcher24 schrieb:

    (persönliche Präferenz, kein Flamewar nötig welches besser ist :D).

    Keine Sorge ich find beide doof :p . Für Tools würd ich eher zu sowas wie C# greifen weil man damit viel schneller ans Ziel kommt 😉



  • Ja, nur dann müsste ich wieder die komplette Engine dann später mit CLI C# tauglich machen. Neee danke dot. 😃



  • Nicht wirklich, du müsstest nur eine Schnittstelle für exakt die Funktionalität des Editors anbieten. D.h. die lowlevel Editorlogik (die du sowieso schreiben musst) in C++/CLI mit deiner Engine schreiben und dann ein C# GUI draufsetzen. So hab ich zumindest vor das in Zukunft zu machen. Und meinen Erfahrungen nach erwart ich dass das ziemlich gut funktionieren sollte 😉
    Ich hab zumindest gelernt dass es keine gute Idee ist 1:1 zu wrappen und dann alles in C# zu machen. Wenn schon dann besser nicht einfach nur wrappen sondern gleich auch die Abstraktionsebene erhöhen. Das ist nicht nur evtl. besser für die Performance sondern sorgt eben wie gesagt vor allem dafür dass die Mehrarbeit des Wrapperschreibens wegfällt und sinnvolle Arbeit die sowieso gemacht werden müsste an ihre Stelle tritt.



  • Irrlicht unterstützt Win32, Mac und Linux ohne externe Abhängigkeiten und ist open source. Die Engine kannst du zwar nicht gebrauchen, die erstellt ja auch nur einen OpenGL 1.x Kontext, aber vielleicht kannst du dir da ja mal angucken wie die das machen.



  • cooky451 schrieb:

    Irrlicht unterstützt Win32, Mac und Linux ohne externe Abhängigkeiten und ist open source. Die Engine kannst du zwar nicht gebrauchen, die erstellt ja auch nur einen OpenGL 1.x Kontext, aber vielleicht kannst du dir da ja mal angucken wie die das machen.

    Ich weiss wie man nen Context erstellt. Nur ich wollte es mir ersparen das ganze selbst zu implementieren für versch. Platformen.
    Mir gings aber hauptsächlich darum, dass OpenGL zwar von der spezifikation her XPlatform ist, aber die Erzeugung des Context ist nicht standardisiert und die vorhanden Tools wie GLUT sind nur rein auf C ausgelegt.
    Es nervt einfach. Wie gesagt, ein userpointer würde alles einfacher machen. Vieeel einfacher.



  • Ich meinte ja nur, wo "selber machen" ja schon im Raum stand, es aber deiner Aussage nach am Know-How für Linux und Mac scheitern würde, könnte man sich ja mal angucken wie die das machen. 🙂



  • Du kannst dir doch von SFML einfach nur die Window-Klasse klauen. DIe ist ziemlich minimal. Sind glaub ich nur 2-3 Header und die Sources dazu. Und das gnaze sollte auch ohne Warnings durchlaufen. Im Gegensatz natürlich zu "RenderWindow" was wirklich veraltet Funktionen einsetzt.

    Das anzupassen sollte dir auf jeden Fall weniger Arbeit machen, als da jetzt komplett selber was aus demn Boden zu stampfen.

    //edit seh grad, die ist doch etwas mehr. Trotzdem verwenden.



  • otze schrieb:

    Du kannst dir doch von SFML einfach nur die Window-Klasse klauen. DIe ist ziemlich minimal. Sind glaub ich nur 2-3 Header und die Sources dazu. Und das gnaze sollte auch ohne Warnings durchlaufen. Im Gegensatz natürlich zu "RenderWindow" was wirklich veraltet Funktionen einsetzt.

    Das anzupassen sollte dir auf jeden Fall weniger Arbeit machen, als da jetzt komplett selber was aus demn Boden zu stampfen.

    //edit seh grad, die ist doch etwas mehr. Trotzdem verwenden.

    Naja, ich brauch eben das RenderWindow.
    Ich habs jetzt in Klassen aufgeteilt:

    NLWindowWin32::NLWindowWin32()
    : NLIPlatformWindow(), m_isActive(true)
    {
        m_hInstance = GetModuleHandle(NULL);
    }
    
    NLWindowWin32::~NLWindowWin32()
    {
        // Destroy the Window
        ::DestroyWindow((HWND)m_hwnd); 
    
        // Change Display back
        ::ChangeDisplaySettings(NULL, 0); 
    
        // Unregister
        ::UnregisterClass(getWindowClassName(), m_hInstance); 
    }
    
    bool NLWindowWin32::createWindow( const NLWindowSettings& settings )
    {
        m_settings = settings;
        WNDCLASSEX wc;
        DWORD dwStyle = WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
    
        // Different Style for Fullscreen
        if ( m_settings.fullscreen )
        {
            dwStyle = WS_POPUP;
        }
        if ( m_settings.resizable && !m_settings.fullscreen )
        {
            dwStyle = WS_OVERLAPPEDWINDOW;
        }
    
        // Fill WindowClass Structure with needed options
        wc.cbSize        = sizeof(WNDCLASSEX);
        wc.style         = CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
        wc.lpfnWndProc   = (WNDPROC)NLWindowWin32::sWinProc;
        wc.cbClsExtra    = 0;
        wc.cbWndExtra    = 0;
        wc.hInstance     = m_hInstance;
        wc.hIcon         = ::LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = 0;
        wc.lpszMenuName  = NULL;
        wc.lpszClassName = getWindowClassName();
        wc.hIconSm       = ::LoadIcon(NULL, IDI_APPLICATION);   
    
        // Register it
        if ( !::RegisterClassEx(&wc) )
        {
            ::MessageBox(HWND_DESKTOP, L"RegisterClass() failed!", L"DXWindow", MB_ICONERROR|MB_OK);
            return false;
        }
    
        // Let Windows(TM) calculate the window size so our canvas is as big as we want it to have.
        m_wnd_rect.left = 0;
        m_wnd_rect.right = static_cast<long>(settings.width);
        m_wnd_rect.bottom = static_cast<long>(settings.height);
        m_wnd_rect.top = 0; 
        ::AdjustWindowRectEx(&m_wnd_rect, dwStyle, FALSE, WS_EX_APPWINDOW);
    
        // Create Window
        m_hwnd = ::CreateWindowEx(WS_EX_APPWINDOW, 
                                  getWindowClassName(), 
                                  L"",  
                                  dwStyle|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
                                  50, 50, 
                                  m_wnd_rect.right-m_wnd_rect.left,
                                  m_wnd_rect.bottom-m_wnd_rect.top,	
                                  NULL, 
                                  NULL, 
                                  m_hInstance, 
                                  NULL);
    
        // Window creation failed for some reason. 
        if ( m_hwnd == NULL )
        {
            ::MessageBox(HWND_DESKTOP, L"CreateWindowEx() failed!", L"NightLight2D", MB_ICONERROR|MB_OK);
            ::UnregisterClass(getWindowClassName(), m_hInstance);
            ChangeDisplaySettings(NULL, 0);
            return false;
        }
    
        // Go fullscreen 
        // TODO: This code fails. 
        if ( m_settings.fullscreen )
        {
            DEVMODE dmVideoMode;				
            memset(&dmVideoMode,0,sizeof(dmVideoMode));		
            dmVideoMode.dmSize       = sizeof(dmVideoMode);		
            dmVideoMode.dmPelsWidth	 = static_cast<DWORD>(m_settings.width);
            dmVideoMode.dmPelsHeight = static_cast<DWORD>(m_settings.height);
            dmVideoMode.dmBitsPerPel = m_settings.bpp;
            dmVideoMode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
    
            if (ChangeDisplaySettings(&dmVideoMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL )
            {
                ::MessageBox(HWND_DESKTOP, L"ChangeDisplaySettings() failed!", L"NightLight2D", MB_ICONERROR|MB_OK);
                return false;
            }
        }
    
        // Set the userpointer
        ::SetWindowLongPtr((HWND)m_hwnd, GWL_USERDATA, reinterpret_cast<long>(this));
    
        //Set caption
        ::SetWindowTextA((HWND)m_hwnd, m_settings.caption.c_str());
    
        // Show Window and bring to the foreground, so it is topmost for now.
        ::ShowWindow((HWND)m_hwnd, true);    
        ::SetForegroundWindow((HWND)m_hwnd);
        return true;
    }
    
    //------------------------------------------------------
    // Event Pump
    //------------------------------------------------------
    bool NLWindowWin32::pumpEvents()
    {
        // Main Loop
        MSG msg;
        while ( ::PeekMessage(&msg, 0, 0, 0, PM_REMOVE) )
        {
            if (msg.message == WM_QUIT)
                break;
    
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);        
        } 
        if ( isRunning() )
            return true;
        return false;
    }
    
    //------------------------------------------------------
    // Real WinProc, gets called by sWinProc
    //------------------------------------------------------
    LRESULT NLWindowWin32::WinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
    {
        switch(msg)
        {
        case WM_CLOSE:
            {
                // Leave loop
                m_isRunning = false;
                return 0;
            }
        case WM_KEYDOWN:
            {
                //return 0;
                break;
            }
        case WM_KEYUP:
            {
                //return 0;
                break;
            }
        case WM_MOUSEMOVE:
            {
                //return 0;
                break;
            }
        case WM_ACTIVATE:
            {
                m_isActive = (LOWORD(wParam) == 1);
                break;
               // return 0;
            }
        }
        return ::DefWindowProc(hwnd, msg, wParam, lParam); 
    }
    
    //------------------------------------------------------
    // Static member function which gets the user pointer
    // from the window and calls the correct object 
    //------------------------------------------------------
    LRESULT NLWindowWin32::sWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
    {
        NLWindowWin32* ptr = reinterpret_cast<NLWindowWin32*>(GetWindowLong(hwnd, GWL_USERDATA));
        return ptr->WinProc(hwnd, msg, wParam, lParam);
    }
    
    //------------------------------------------------------
    // Gets size of the desktop and calculates how the 
    // window has to be positioned to be in the center.
    //------------------------------------------------------
    void NLWindowWin32::center()
    {
        u32 screenWidth = GetSystemMetrics(SM_CXSCREEN);
        u32 screenHeight = GetSystemMetrics(SM_CYSCREEN);
        u32 left = (screenWidth  / 2) - static_cast<u32>( m_settings.width  / 2);
        u32 top  = (screenHeight / 2) - static_cast<u32>( m_settings.height / 2);
        MoveWindow((HWND)m_hwnd, left, top, static_cast<int>(m_settings.width), static_cast<int>(m_settings.height), TRUE);
    }
    
    ////////////////////////////////////////////////////////////////
    
    NLContextWin32::NLContextWin32( NLWindowHandle hwnd, NLOpenGLSettings settings )
    : NLIPlatformContext(hwnd, settings)
    {
        int pf = 0;
        PIXELFORMATDESCRIPTOR pfd = {0};
        OSVERSIONINFO osvi = {0};
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    
        // Obtain HDC for this window.
        if (!(m_hdc = GetDC((HWND)m_hwnd))){
            NLError("[NLContextWin32] GetDC() failed.");
            throw NLException("GetDC() failed.", true);
        }
    
        // Create and set a pixel format for the window.
        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 = settings.BPP;
        pfd.cDepthBits = settings.BPP;
        pfd.iLayerType = PFD_MAIN_PLANE;
    
        // Obtain Windows Version
        if (!GetVersionEx(&osvi))
        {        
            NLError("[NLContextWin32] GetVersionEx() failed.");
            throw NLException("GetVersionEx() failed.");
        }
    
        // Get a pixelformat, based on our settings
        pf = ChoosePixelFormat(m_hdc, &pfd);
    
        // Set the pixelformat
        if (!SetPixelFormat(m_hdc, pf, &pfd))
        {
            NLError("[NLContextWin32] GetVersionEx() failed.");
            throw NLException("SetPixelFormat() failed.");
        }
    
        // When running under Windows Vista or later support desktop composition.
        // This doesn't really apply when running in full screen mode.
        if (osvi.dwMajorVersion > 6 || (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion >= 0))
            pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
    
        // Verify that this OpenGL implementation supports the required extensions.
        std::string extensions = wglGetExtensionsStringARB(m_hdc);
        if (extensions.find("WGL_ARB_create_context") == std::string::npos){
            NLError("[NLContextWin32] Required extension WGL_ARB_create_context is not supported.");
            throw NLException("[NLContextWin32] Required extension WGL_ARB_create_context is not supported.");
        }
    
        // Creates an OpenGL forward compatible rendering context.
        int attribList[] =
        {
            WGL_CONTEXT_MAJOR_VERSION_ARB, settings.MAJOR,
            WGL_CONTEXT_MINOR_VERSION_ARB, settings.MINOR,
            WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
            0, 0
        };
    
        // First try creating an OpenGL context.
        if (!(m_hglrc = wglCreateContextAttribsARB(m_hdc, 0, attribList)))
        {
            // Fall back to an OpenGL 3.0 context.
            attribList[3] = 0;
            if (!(m_hglrc = wglCreateContextAttribsARB(m_hdc, 0, attribList))){
                NLError("[NLContextWin32] wglCreateContextAttribsARB() failed for OpenGL 3 context.");
                throw NLException("wglCreateContextAttribsARB() failed for OpenGL 3 context.", true);
            }
        }
    
        if (!wglMakeCurrent(m_hdc, m_hglrc)){
            NLError("[NLContextWin32] wglMakeCurrent() failed for OpenGL 3 context.");
            throw NLException("wglMakeCurrent() failed for OpenGL 3 context.");
        }
    
        // Init gl3w
        if ( gl3wInit() ){
            std::stringstream ss;
            ss << std::string("[NLWindow] gl3wInit failed.");
            NLError(ss.str());
        }
    
        // OpenGL Error Check
        {
            if ( !NLGLCheck(__FILE__, __LINE__) ){
                NLError("[NLWindow] GLerror after gl3wInit() while gl3wInit() returned OK");
            }
        }
    }
    
    NLContextWin32::~NLContextWin32()
    {
        if (m_hdc)
        {
            if (m_hglrc)
            {
                SystemController().getResourceManager().unload();
                wglMakeCurrent(m_hdc, 0);
                wglDeleteContext(m_hglrc);
            }
            ReleaseDC((HWND)m_hwnd, m_hdc);
        }
    }
    
    void NLContextWin32::endRender()
    {
    #ifdef _DEBUG
        NLGLCheck(__FILE__, __LINE__);
    #endif
        ::SwapBuffers(m_hdc);
    }
    
    void NLContextWin32::beginRender()
    {
        wglMakeCurrent(m_hdc, m_hglrc);
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    }
    
    // Basisklasse:
    
    struct NLOpenGLSettings
    {
        NLOpenGLSettings()
            : MAJOR(3), MINOR(0), BPP(24)
        {}
    
        int MAJOR;
        int MINOR;
        int BPP;
    };
    
    class NLIPlatformContext
    {
    public:
        NLIPlatformContext(NLWindowHandle hwnd, NLOpenGLSettings settings)
            : m_settings(settings), m_hwnd(hwnd)
        {}
    
        virtual ~NLIPlatformContext()
        {}
    
        virtual void endRender() = 0;
        virtual void beginRender() = 0;
    
        inline void dumpOpenGLInfos(bool extensions) 
        {
            // OpenGL
            char* gl_ven    = (char*)glGetString(GL_VENDOR);
            char* gl_ver    = (char*)glGetString(GL_VERSION);
            char* gl_render = (char*)glGetString(GL_RENDERER);
            char* gl_glslang= (char*)glGetString(GL_SHADING_LANGUAGE_VERSION);  
    
            if ( gl_ven )		{ NLMessage(std::string("[NLIPlatformContext] OpenGL Vendor String: ") + gl_ven);      }
            if ( gl_ver )		{ NLMessage(std::string("[NLIPlatformContext] OpenGL Version: ") + gl_ver);			 }
            if ( gl_render  )	{ NLMessage(std::string("[NLIPlatformContext] OpenGL Renderer: ") + gl_render);		 }
            if ( gl_glslang )	{ NLMessage(std::string("[NLIPlatformContext] OpenGL Shader Version: ") + gl_glslang); }
    
            if ( extensions )
            {
                // Get all Extensions
                NLStringVector v;
                GLint num_extensions;
                GLubyte* p = NULL;
                glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions);
                for ( int i=0; i < num_extensions; i++ )
                {
                    p = (GLubyte*) glGetStringi (GL_EXTENSIONS, i);
                    if ( p )
                        v.push_back((char*)p);
                }
                SystemController().getLog().printExtensions(v);
            }
        }
    
        // Implemented inline to ensure it is always the same.
        inline void initOpenGL(f32 w, f32 h) 
        {
            // Set Viewport
            glViewport(0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));
    
            // Clear Color
            glClearColor(m_clearcolor.r, m_clearcolor.g, m_clearcolor.b, m_clearcolor.a);
    
            // Misc. Options    
            glEnable(GL_DEPTH_TEST);   
    
            // Blend Func
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        }
    
        inline void setClearColor(const NLColor4f& color) 
        { 
            m_clearcolor = color;
            glClearColor(m_clearcolor.r, m_clearcolor.g, m_clearcolor.b, m_clearcolor.a);
        }
    
        const NLColor4f& getClearColor() const { return m_clearcolor; }
    
    protected:
        NLWindowHandle m_hwnd;
        NLOpenGLSettings m_settings;
        NLColor4f m_clearcolor;
    };
    

    Was jetzt noch fehlt ist das Key-Handling und mit so tieferen WinAPI Dingen wie Systemkeys abfragen, habe ich halt immer a bissl Probleme^^.
    Egal ich krieg das schon hin, ich beiss mich durch :).
    Ändert aber nix an meiner Kritik an GLUT. Dass SFML das nicht anbietet, dafür können die auch nix, die haben ja die Anforderung nicht an sich selbst OGL3 Konform zu sein.
    SDL1.3 hat das, aber die Abhängigkeit zu DirectX macht das ganze zu komplex für evtl. Anwender der Lib.



  • GFWL wird mit Version 3 Userpointer akzeptieren für die Callbacks. So am rande :). Hab das vorhin erfahren. Ist aber noch instabil, daher keine Wahl momentan.



  • Scorcher24 schrieb:

    GLUT ist eigentlich genau das was ich brauche und möchte:
    Es unterstützt ordentlich OpenGL in allen Versionen, es wird aktualisiert und ich brauch keine dreckigen Hacks implementieren um das zu erreichen was ich möchte.

    Du meinst wohl FreeGlut und nicht das Original GLUT.

    GLUT ist nämlich nicht nur total veraltet, sondern es wird seit AFAIK ca. > 10 Jahren nicht mehr weiterentwickelt.


Anmelden zum Antworten