Commit 709697ea authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Better way to determine supported OpenGL version and extensions.

parent 9a6a3c8b
Loading
Loading
Loading
Loading
+113 −59
Original line number Diff line number Diff line
@@ -36,46 +36,29 @@
#endif /* __WXDEBUG__ */

#include <limits>
#include <boost/bind.hpp>

using namespace KIGFX;

// Prototypes
void InitTesselatorCallbacks( GLUtesselator* aTesselator );

static void InitTesselatorCallbacks( GLUtesselator* aTesselator );
const int glAttributes[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0 };

wxGLContext* OPENGL_GAL::glContext = NULL;

OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
                        wxEvtHandler* aPaintListener, const wxString& aName ) :
    wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
                wxEXPAND, aName ),
    parentWindow( aParent ),
    mouseListener( aMouseListener ),
    paintListener( aPaintListener ),
    cachedManager( true ),
    nonCachedManager( false ),
    overlayManager( false )
{
    // Create the OpenGL-Context
    if( glContext == NULL )
        glContext = new wxGLContext( this );

    aParent->Show();   // wxWidgets require the window to be visible to set its GL context

    // Initialize GLEW, FBOs & VBOs
    SetCurrent( *glContext );
    initGlew();

    // Prepare shaders
    if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) )
        throw std::runtime_error( "Cannot compile vertex shader!" );

    if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) )
        throw std::runtime_error( "Cannot compile fragment shader!" );

    if( !shader.Link() )
        throw std::runtime_error( "Cannot link the shaders!" );
    // Check if OpenGL requirements are met
    runTest();

    // Make VBOs use shaders
    cachedManager.SetShader( shader );
@@ -145,7 +128,8 @@ void OPENGL_GAL::BeginDrawing()
    glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );

    // Create the screen transformation
    glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y, -depthRange.x, -depthRange.y );
    glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y,
             -depthRange.x, -depthRange.y );

    if( !isFramebufferInitialized )
    {
@@ -914,37 +898,6 @@ void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
}


void OPENGL_GAL::initGlew()
{
    // Initialize GLEW library
    GLenum err = glewInit();

    if( GLEW_OK != err )
    {
        throw std::runtime_error( (const char*) glewGetErrorString( err ) );
    }
    else
    {
        wxLogDebug( wxString( wxT( "Status: Using GLEW " ) ) +
                    FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
    }

    // Check the OpenGL version (minimum 2.1 is required)
    if( GLEW_VERSION_2_1 )
        wxLogInfo( wxT( "OpenGL 2.1 supported." ) );
    else
        throw std::runtime_error( "OpenGL 2.1 or higher is required!" );

    // Framebuffers have to be supported
    if( !GLEW_EXT_framebuffer_object )
        throw std::runtime_error( "Framebuffer objects are not supported!" );

    // Vertex buffer has to be supported
    if( !GLEW_ARB_vertex_buffer_object )
        throw std::runtime_error( "Vertex buffer objects are not supported!" );
}


void OPENGL_GAL::blitCursor()
{
    if( !isCursorEnabled )
@@ -984,11 +937,112 @@ unsigned int OPENGL_GAL::getNewGroupNumber()
}


// -------------------------------------
// Callback functions for the tesselator
// -------------------------------------
bool OPENGL_GAL::runTest()
{
    wxDialog* dialog = new wxDialog( GetParent(), -1, wxT( "opengl test" ),
                                     wxPoint( 50, 50 ), wxSize( 50, 50 ) );
    OPENGL_TEST* test = new OPENGL_TEST( dialog, this );

    dialog->ShowModal();
    bool result = test->IsOk();

    if( !result )
        throw std::runtime_error( test->GetError() );

    return result;
}


OPENGL_GAL::OPENGL_TEST::OPENGL_TEST( wxDialog* aParent, OPENGL_GAL* aGal ) :
    wxGLCanvas( aParent, wxID_ANY, glAttributes, wxDefaultPosition,
                wxDefaultSize, 0, wxT( "GLCanvas" ) ),
    m_parent( aParent ), m_gal( aGal ), m_tested( false ), m_result( false )
{
    Connect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::OPENGL_TEST::Render ) );
}


void OPENGL_GAL::OPENGL_TEST::Render( wxPaintEvent& WXUNUSED( aEvent ) )
{
    if( !m_tested )
    {
        m_result = true;    // Assume everything is fine, until proven otherwise

        // One test is enough - close the testing dialog when the test is finished
        Disconnect( wxEVT_PAINT, wxPaintEventHandler( OPENGL_GAL::OPENGL_TEST::Render ) );
        CallAfter( boost::bind( &wxDialog::EndModal, m_parent, wxID_NONE ) );

        SetCurrent( *OPENGL_GAL::glContext );
        GLenum err = glewInit();

        if( GLEW_OK != err )
        {
            error( (const char*) glewGetErrorString( err ) );
            return;
        }
        else
        {
            wxLogDebug( wxString( wxT( "Status: Using GLEW " ) ) +
                        FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
        }

        // Check the OpenGL version (minimum 2.1 is required)
        if( GLEW_VERSION_2_1 )
        {
            wxLogInfo( wxT( "OpenGL 2.1 supported." ) );
        }
        else
        {
            error( "OpenGL 2.1 or higher is required!" );
            return;
        }

        // Framebuffers have to be supported
        if( !GLEW_EXT_framebuffer_object )
        {
            error( "Framebuffer objects are not supported!" );
            return;
        }

        // Vertex buffer has to be supported
        if( !GLEW_ARB_vertex_buffer_object )
        {
            error( "Vertex buffer objects are not supported!" );
            return;
        }

        // Prepare shaders
        if( !m_gal->shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) )
        {
            error( "Cannot compile vertex shader!" );
            return;
        }

        if( !m_gal->shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) )
        {
            error( "Cannot compile fragment shader!" );
            return;
        }

        if( !m_gal->shader.Link() )
        {
            error( "Cannot link the shaders!" );
            return;
        }

        m_tested = true;
    }
}


void OPENGL_GAL::OPENGL_TEST::error(const std::string& aError )
{
    m_result = false;
    m_tested = true;
    m_error = aError;
}

// Compare Redbook Chapter 11
// ------------------------------------- // Callback functions for the tesselator // ------------------------------------- // Compare Redbook Chapter 11
void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{
    GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
@@ -1029,7 +1083,7 @@ void CALLBACK ErrorCallback( GLenum aErrorCode )
}


void InitTesselatorCallbacks( GLUtesselator* aTesselator )
static void InitTesselatorCallbacks( GLUtesselator* aTesselator )
{
    gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA,  ( void (CALLBACK*)() )VertexCallback );
    gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
+30 −6
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 *
 * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
 * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
 * Copyright (C) 2013 CERN
 * Copyright (C) 2013-2015 CERN
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * Graphics Abstraction Layer (GAL) for OpenGL
@@ -55,7 +55,7 @@ class SHADER;
 * @brief Class OpenGL_GAL is the OpenGL implementation of the Graphics Abstraction Layer.
 *
 * This is a direct OpenGL-implementation and uses low-level graphics primitives like triangles
 * and quads. The purpuse is to provide a fast graphics interface, that takes advantage of modern
 * and quads. The purpose is to provide a fast graphics interface, that takes advantage of modern
 * graphics card GPUs. All methods here benefit thus from the hardware acceleration.
 */
class OPENGL_GAL : public GAL, public wxGLCanvas
@@ -254,7 +254,6 @@ private:

    wxClientDC*             clientDC;               ///< Drawing context
    static wxGLContext*     glContext;              ///< OpenGL context of wxWidgets
    wxWindow*               parentWindow;           ///< Parent window
    wxEvtHandler*           mouseListener;
    wxEvtHandler*           paintListener;

@@ -340,9 +339,6 @@ private:
     */
    void skipMouseEvent( wxMouseEvent& aEvent );

    /// Initialize GLEW
    void initGlew();

    /**
     * @brief Blits cursor into the current screen.
     */
@@ -354,6 +350,34 @@ private:
     * @return An unique group number that is not used by any other group.
     */
    unsigned int getNewGroupNumber();

    /**
     * @brief Checks if the required OpenGL version and extensions are supported.
     * @return true in case of success.
     */
    bool runTest();

    // Helper class to determine OpenGL capabilities
    class OPENGL_TEST: public wxGLCanvas
    {
    public:
        OPENGL_TEST( wxDialog* aParent, OPENGL_GAL* aGal );
        void Render( wxPaintEvent& aEvent );
        inline bool IsTested() const { return m_tested; }
        inline bool IsOk() const { return m_result && m_tested; }
        inline std::string GetError() const { return m_error; }

    private:
        void error( const std::string& aError );

        wxDialog* m_parent;
        OPENGL_GAL* m_gal;
        bool m_tested;
        bool m_result;
        std::string m_error;
    };

    friend class OPENGL_TEST;
};
} // namespace KIGFX