Giter VIP home page Giter VIP logo

Comments (12)

mosra avatar mosra commented on May 18, 2024

Hi, thanks for the report!

Interesting, looks like things changed significantly since I last checked on Arch. I got stuck already at CMake not being able to find wxgtk3, I had to convince it by supplying an extra name for wx-config (fix commited in d8f6221). For the assertion, it seems the following patch fixes it (instead of moving SetCurrent() to OnPaint()):

diff --git a/src/MyApplication.cpp b/src/MyApplication.cpp
index 21d1672..05756d3 100644
--- a/src/MyApplication.cpp
+++ b/src/MyApplication.cpp
@@ -61,6 +61,7 @@ MainFrame::MainFrame(int argc, char** argv): wxFrame{nullptr, wxID_ANY, "Magnum
     #endif
 
     _wxGlContext = new wxGLContext{_wxGlCanvas};
+    Show();
     _wxGlCanvas->SetCurrent(*_wxGlContext);
     _glContext.create();
 

The GL::Context: unsupported OpenGL version (0, 0) was just a consequence of the SetCurrent() being moved -- _glContext needs an active OpenGL context in order to query version and setup Magnum's GL wrapper and if it doesn't have it, it usually ends up getting all zeros for everything it queries.

However, I have zero idea what I'm doing here (not a wxWidgets user at all), so I didn't commit the above. Can you confirm that Show() is allowed to be called in the constructor? Or do I need to attach to some wxEVT_SHOW event and do the GL context and Magnum GLContext setup in there instead? @williamjcm, you were the original author of this code, can you advise? Thanks :)

from magnum-bootstrap.

astinus87 avatar astinus87 commented on May 18, 2024

@mosra Thanks for the fix. Calling Show in the constructor as you did fixed it for me.

CMake couldn't find wxWidgets for me too. I fixed it by creating a symlink /usr/bin/wx-config pointing to /usr/bin/wx-config-gtk3 instead of your CMakeLists solution. wxgtk3 package only installs /usr/bin/wx-config-gtk3. I think there should be a wx-config executable on the system because there might be other projects using it.

I am an absolute beginner in wxWidgets and I chose it because it is said to provide native look. I will develop a cross platform app for Windows and Linux. I have used .Net WPF before. I didn't like Qt because it seemed too tied to the Qt Creator. Do you use any GUI framework? I appreciate it if you have any suggestion.

from magnum-bootstrap.

mosra avatar mosra commented on May 18, 2024

I think there should be a wx-config executable on the system

By looking at the FindwxWidgets module, there's about 15 of them already, so I suppose this was only one case that wasn't added there yet. I'd rather have that patched up by the buildsystem than requiring users to create symlinks. Ideally the CMake module would be updated to recognize this name as well, but I'm too busy to open a PR on the cmake repository...

I didn't like Qt because it seemed too tied to the Qt Creator.

I was happily using Qt without QtCreator for several years in the Qt4 days, and didn't really miss any of its features for Qt development. Though I have to admit it "jumped the shark" after that, and version 5 (and now 6) seems rather bloated. (OTOH I'm a happy KDE user and wouldn't trade it for a GTK-based environment ever, the difference in overall polish and flexibility is just too huge between the two.)

Qt is bloated, GTK lacks critical features like fractional DPI scaling, .NET is, well, C#... I don't have a suggestion, sorry, it's all various levels of bad nowadays :( Depending on what you'll be doing, using ImGui might be just fine and flexible enough (and Magnum has integration for it). That one is very feature-rich although I don't personally like the default look, and the only major downside is that it's not suited for "idle" apps because it requires constant redraw in order to function properly.

from magnum-bootstrap.

williamjcm avatar williamjcm commented on May 18, 2024

Sorry for the late answer! I don't check GitHub as often as I used to. ๐Ÿ˜…

Show() is allowed to be called in the constructor? [...] @williamjcm, you were the original author of this code, can you advise? Thanks :)

Yes, it can. In fact, in my wxWidgets/Magnum project, I do all of the context setup in the constructor for the window.

Here's what I have in that project:

_wxGlContext.emplace(_glCanvas, nullptr, &context_attributes);
#ifdef __WXGTK__
Show();
#endif
_wxGlContext->SetCurrent(*_glCanvas);
#ifdef __WXGTK__
Hide();
#endif

Since I only target Windows and Linux, I use #ifdef __WXGTK__, but if it happens on other targets, those lines should be replaced with #ifndef __WXMSW__.

If there are any further questions, I'll try to answer them ASAP.

from magnum-bootstrap.

mosra avatar mosra commented on May 18, 2024

Oh, so you're saying it's backend-dependent? Interesting. Are there any "good practice" docs explaining this in more detail? Like if it's a GTK quirk or something one should expect in general.

from magnum-bootstrap.

williamjcm avatar williamjcm commented on May 18, 2024

Oh, so you're saying it's backend-dependent?

In a way, yeah.

On Windows, wxWidgets will assert in the same way as on GTK when calling wxGLCanvas::SetCurrent() when the window is hidden, but, for some reason, it doesn't when calling wxGLContext::SetCurrent().

Are there any "good practice" docs explaining this in more detail? Like if it's a GTK quirk or something one should expect in general.

The "good practice" on all platforms would be to only set a context as current when the canvas is shown, as the docs for wxGLCanvas::SetCurrent() say.

While the docs also say to not call it in the constructor of the window, it worked fine during my testing of the bootstrap project. And in my main project, I do the initialisation of the context in another class that inherits from the window's class, so the window itself is technically ready by that point.

It's... a bit of a mess, I admit.

from magnum-bootstrap.

asmwarrior avatar asmwarrior commented on May 18, 2024

Hi, I just try the base-wxwidgets project under Code::Blocks (I'm using msys2's prebuild magnum library, and msys2's wx 3.1.5 library)

The pure base-wxwidgets works OK without any issue. See the image show below:
ok

But if I try to add some member variables in the MainFrame class, I got crashed.

Here is the code:

#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/Platform/GLContext.h>


#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/Math/Color.h>
#include <Magnum/Shaders/VertexColor.h>


#include <wx/app.h>
#include <wx/frame.h>
#include <wx/glcanvas.h>
#include <wx/sizer.h>
#include <wx/version.h>

using namespace Magnum;

class MyApplication: public wxApp {
    public:
        bool OnInit();
};

class MainFrame: public wxFrame {
    public:
        explicit MainFrame(int argc, char** argv);
        ~MainFrame();

    private:
        void OnPaint(wxPaintEvent& event);

        wxGLCanvas* _wxGlCanvas;
        wxGLContext* _wxGlContext;
        Platform::GLContext _glContext;

#if 1
        //GL::Mesh _mesh;
        //Shaders::VertexColor2D _shader;
#endif // 0

};

wxIMPLEMENT_APP(MyApplication);

bool MyApplication::OnInit() {
    MainFrame *frame = new MainFrame{argc, argv};
    frame->Show(true);
    return true;
}

MainFrame::MainFrame(int argc, char** argv)
    : wxFrame{nullptr, wxID_ANY, "Magnum wxWidgets Application"},
    _glContext{NoCreate, argc, argv}
{
    wxBoxSizer* bSizer;
    bSizer = new wxBoxSizer{wxVERTICAL};

    #if (wxMAJOR_VERSION == 3) && (wxMINOR_VERSION >= 1)
    wxGLAttributes attributes;
    attributes.PlatformDefaults()
              .BufferSize(24)
              .MinRGBA(8, 8, 8, 0)
              .Depth(24)
              .Stencil(0)
              .DoubleBuffer()
              .EndList();
    _wxGlCanvas = new wxGLCanvas{this, attributes, wxID_ANY, wxDefaultPosition, wxSize{800, 600}};
    #elif (wxMAJOR_VERSION == 3) && (wxMINOR_VERSION == 0)
    int attributes[] = { WX_GL_RGBA,
                         WX_GL_DOUBLEBUFFER,
                         WX_GL_DEPTH_SIZE, 24,
                         WX_GL_STENCIL_SIZE, 0,
                         0 };
    _wxGlCanvas = new wxGLCanvas{this, wxID_ANY, &attributes[0], wxDefaultPosition, wxSize{800, 600}};
    #else
    #error You need wxWidgets version 3.0 or later.
    #endif

    _wxGlContext = new wxGLContext{_wxGlCanvas};
    _wxGlCanvas->SetCurrent(*_wxGlContext);
    _glContext.create();

    bSizer->Add(_wxGlCanvas, 1, wxALL|wxEXPAND, 5);
    SetSizer(bSizer);

    Layout();

    bSizer->Fit(this);

    Centre(wxBOTH);

    _wxGlCanvas->Connect(wxEVT_PAINT, wxPaintEventHandler(MainFrame::OnPaint), nullptr, this);

    /* TODO: Add your initialization code here */

#if 0
    // https://doc.magnum.graphics/magnum/triangle_2TriangleExample_8cpp-example.html
    using namespace Math::Literals;

    struct TriangleVertex {
        Vector2 position;
        Color3 color;
    };
    const TriangleVertex data[]{
        {{-0.5f, -0.5f}, 0xff0000_rgbf},    /* Left vertex, red color */
        {{ 0.5f, -0.5f}, 0x00ff00_rgbf},    /* Right vertex, green color */
        {{ 0.0f,  0.5f}, 0x0000ff_rgbf}     /* Top vertex, blue color */
    };

    GL::Buffer buffer;
    buffer.setData(data);

    _mesh.setCount(3)
         .addVertexBuffer(std::move(buffer), 0,
            Shaders::VertexColor2D::Position{},
            Shaders::VertexColor2D::Color3{});
#endif // 0
}

MainFrame::~MainFrame() {
    _wxGlCanvas->Disconnect(wxEVT_PAINT, wxPaintEventHandler(MainFrame::OnPaint), nullptr, this);
}

void MainFrame::OnPaint(wxPaintEvent& event) {
    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);

    /* TODO: Add your drawing code here */

#if 0
    _shader.draw(_mesh);
#endif // 0
    _wxGlCanvas->SwapBuffers();


}

Note that there are two member variables

        GL::Mesh _mesh;
        Shaders::VertexColor2D _shader;

If you umcomment either one of them, or all of them, I got crash on the construction of the MainFrame.
The crash just open a message below:

crash

Note that I'm using the msys2's prebuild version, which is: mingw64/mingw-w64-x86_64-magnum 2020.06-1
and mingw64/mingw-w64-x86_64-wxmsw3.1 3.1.5-3

Any ideas how to solve this issue? Thanks.

from magnum-bootstrap.

asmwarrior avatar asmwarrior commented on May 18, 2024

Some extra information, if I enable the console window, I see when it crashed, some message was shown in the console, see below image show:

GL::Context::current(): no current context

crash2

So, when the member variable get initialized, they need an active context?

from magnum-bootstrap.

asmwarrior avatar asmwarrior commented on May 18, 2024

By searching the error message, I got this:

Context::current(): no current context ยท Issue #167 ยท mosra/magnum

As the internal context is created by the NoCreate parameter.

_glContext{NoCreate, argc, argv}

How can we create a mesh and shader object if the _glContext is not created yet?

from magnum-bootstrap.

asmwarrior avatar asmwarrior commented on May 18, 2024

I solved this issue by a hack that I just create a function to initialize the _glContext member variable before the other shader and mesh members, see the full code below and screen shot.

#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/Platform/GLContext.h>


#include <Magnum/GL/Buffer.h>
#include <Magnum/GL/DefaultFramebuffer.h>
#include <Magnum/GL/Mesh.h>
#include <Magnum/Math/Color.h>
#include <Magnum/Shaders/VertexColor.h>


#include <wx/app.h>
#include <wx/frame.h>
#include <wx/glcanvas.h>
#include <wx/sizer.h>
#include <wx/version.h>

using namespace Magnum;

class MyApplication: public wxApp {
    public:
        bool OnInit();
};

class MainFrame: public wxFrame {
    public:
        explicit MainFrame(int argc, char** argv);
        ~MainFrame();

    private:
        void OnPaint(wxPaintEvent& event);

       void InitContext();

        wxGLCanvas* _wxGlCanvas;
        wxGLContext* _wxGlContext;
        Platform::GLContext _glContext;

        int m_a;

#if 1
        GL::Mesh _mesh;
        Shaders::VertexColor2D _shader;
#endif // 0

};

wxIMPLEMENT_APP(MyApplication);


void CreateConsole()
{
    if (!AllocConsole()) {
        // Add some error handling here.
        // You can call GetLastError() to get more info about the error.
        return;
    }

    // std::cout, std::clog, std::cerr, std::cin
    FILE* fDummy;
    freopen_s(&fDummy, "CONOUT$", "w", stdout);
    freopen_s(&fDummy, "CONOUT$", "w", stderr);
    freopen_s(&fDummy, "CONIN$", "r", stdin);
    std::cout.clear();
    std::clog.clear();
    std::cerr.clear();
    std::cin.clear();

    // std::wcout, std::wclog, std::wcerr, std::wcin
    HANDLE hConOut = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    HANDLE hConIn = CreateFile(_T("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    SetStdHandle(STD_OUTPUT_HANDLE, hConOut);
    SetStdHandle(STD_ERROR_HANDLE, hConOut);
    SetStdHandle(STD_INPUT_HANDLE, hConIn);
    std::wcout.clear();
    std::wclog.clear();
    std::wcerr.clear();
    std::wcin.clear();
}


bool MyApplication::OnInit() {

    CreateConsole();

    MainFrame *frame = new MainFrame{argc, argv};
    frame->Show(true);
    return true;
}

MainFrame::MainFrame(int argc, char** argv)
    : wxFrame{nullptr, wxID_ANY, "Magnum wxWidgets Application"},
    _glContext{NoCreate, argc,  argv},
    m_a{(InitContext(),0)}
{
    wxBoxSizer* bSizer;
    bSizer = new wxBoxSizer{wxVERTICAL};



    bSizer->Add(_wxGlCanvas, 1, wxALL|wxEXPAND, 5);
    SetSizer(bSizer);

    Layout();

    bSizer->Fit(this);

    Centre(wxBOTH);

    _wxGlCanvas->Connect(wxEVT_PAINT, wxPaintEventHandler(MainFrame::OnPaint), nullptr, this);

    /* TODO: Add your initialization code here */

#if 1
    // https://doc.magnum.graphics/magnum/triangle_2TriangleExample_8cpp-example.html
    using namespace Math::Literals;

    struct TriangleVertex {
        Vector2 position;
        Color3 color;
    };
    const TriangleVertex data[]{
        {{-0.5f, -0.5f}, 0xff0000_rgbf},    /* Left vertex, red color */
        {{ 0.5f, -0.5f}, 0x00ff00_rgbf},    /* Right vertex, green color */
        {{ 0.0f,  0.5f}, 0x0000ff_rgbf}     /* Top vertex, blue color */
    };

    GL::Buffer buffer;
    buffer.setData(data);

    _mesh.setCount(3)
         .addVertexBuffer(std::move(buffer), 0,
            Shaders::VertexColor2D::Position{},
            Shaders::VertexColor2D::Color3{});
#endif // 0
}


void MainFrame::InitContext()
{
    #if (wxMAJOR_VERSION == 3) && (wxMINOR_VERSION >= 1)
    wxGLAttributes attributes;
    attributes.PlatformDefaults()
              .BufferSize(24)
              .MinRGBA(8, 8, 8, 0)
              .Depth(24)
              .Stencil(0)
              .DoubleBuffer()
              .EndList();
    _wxGlCanvas = new wxGLCanvas{this, attributes, wxID_ANY, wxDefaultPosition, wxSize{800, 600}};
    #elif (wxMAJOR_VERSION == 3) && (wxMINOR_VERSION == 0)
    int attributes[] = { WX_GL_RGBA,
                         WX_GL_DOUBLEBUFFER,
                         WX_GL_DEPTH_SIZE, 24,
                         WX_GL_STENCIL_SIZE, 0,
                         0 };
    _wxGlCanvas = new wxGLCanvas{this, wxID_ANY, &attributes[0], wxDefaultPosition, wxSize{800, 600}};
    #else
    #error You need wxWidgets version 3.0 or later.
    #endif

    _wxGlContext = new wxGLContext{_wxGlCanvas};
    _wxGlCanvas->SetCurrent(*_wxGlContext);
    _glContext.create();
}

MainFrame::~MainFrame() {
    _wxGlCanvas->Disconnect(wxEVT_PAINT, wxPaintEventHandler(MainFrame::OnPaint), nullptr, this);
}

void MainFrame::OnPaint(wxPaintEvent& event) {
    GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);

    /* TODO: Add your drawing code here */

#if 1
    _shader.draw(_mesh);
#endif // 0
    _wxGlCanvas->SwapBuffers();


}

ok2

It is dirty, because I have to use the method mentioned here:
constructor - C++ - Run a function before initializing a class member - Stack Overflow

Now, the next step is I just try to see if I can add the mouse event handling, so I can tweak the camera (to rotate, scale the scene)

from magnum-bootstrap.

mosra avatar mosra commented on May 18, 2024

@asmwarrior delayed context creation is a rather common workflow, the solution is using the NoCreate constructors for GL objects as well:

        GL::Mesh _mesh{NoCreate};
        Shaders::VertexColor2D _shader{NoCreate};

and then, once you have the context created, populating them with proper live instances:

_glContext.create();

// Now it's safe to call into GL
_mesh = GL::Mesh{};
_shader = Shaders::VertexColor2D{};

I realized the documentation for this workflow was rather nonexistent (sorry about that), so I mentioned this in the OpenGL wrapper overview and a few other places (mosra/magnum@2bd933d).

from magnum-bootstrap.

asmwarrior avatar asmwarrior commented on May 18, 2024

Hi, @mosra , many thanks!
The document: in the OpenGL wrapper overview is so nice, especially for the beginners.

from magnum-bootstrap.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.