[Done] Suggestion: get rid of default context

If you found a bug in our library or on our website, please report it in this section. In this forum you can also make concrete suggestions or feature requests.

Moderators: CEGUI MVP, CEGUI Team

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

[Done] Suggestion: get rid of default context

Postby niello » Wed Feb 06, 2019 19:26

Hi all.

I'm not sure why it was added but it rather makes things harder than helps. When creating CEGUI you must already know its properties, and you have to create this context when CEGUI is initialized, not when you need it. For the hypothetical case of using CEGUI for multiple windows (no doubt a pretty rare case but a revealing one) the logic will be like this:

    Init render system
    Create swap chain (viewport)
    Create CEGUI with default context sized as your viewport
    Use this context for your first window
    For each subsequent window create a new target and context

The worst thing here is that this code requires different handling for the first and subsequent windows. Also it requires to initialize CEGUI after the rendering system, but it is usually the case anyway.

I would propose to remove the entire concept of "default context" and create one when you need it. So the logic becomes:

    Init render system, create CEGUI system (in any order)
    Load whatever resources and configs you want
    Then for every window:
    - Create viewport target (which just means an externally set render target) or a CEGUI-created texture target
    - Create context from this target, setup defaults from config inside CEGUI or leave it to the application

So the system becomes more clean, more flexible and more well-designed for multi-context usage at once. I think this is The way to go but I don't want to make any major local changes which will not be the part of main CEGUI.
Last edited by niello on Thu Jul 25, 2019 07:34, edited 1 time in total.

User avatar
Ident
CEGUI Team
Posts: 1998
Joined: Sat Oct 31, 2009 13:57
Location: Austria

Re: Suggestion: get rid of default context

Postby Ident » Wed Feb 06, 2019 20:17

It was added because of render-to-texture capabilities and that's why we can't remove it.
I just realised I misread your intent while skimming your post.

I think you have a good point, but I do not know what the implications of the proposed changes would be.

Do you know how much work it would be so we could see how it looks and fares? Do you wanna make a PR?
CrazyEddie: "I don't like GUIs"

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Thu Feb 07, 2019 07:45

The default context is implemented as d_guiContexts[0]. It is used in Config_xmlHandler.cpp to set default font, tooltip and cursor, which is better done for each context at its creation. It is used as fallback case in Window::getGUIContext() with the comment like "should we return nullptr instead?", and yes we should, at least because explicit is better than implicit.
Otherwise it is not used anywhere and can be safely removed. I will make a PR for a review in a week or two.

User avatar
Ident
CEGUI Team
Posts: 1998
Joined: Sat Oct 31, 2009 13:57
Location: Austria

Re: Suggestion: get rid of default context

Postby Ident » Thu Feb 07, 2019 09:09

niello wrote:The default context is implemented as d_guiContexts[0]. It is used in Config_xmlHandler.cpp to set default font, tooltip and cursor, which is better done for each context at its creation. It is used as fallback case in Window::getGUIContext() with the comment like "should we return nullptr instead?", and yes we should, at least because explicit is better than implicit.
Otherwise it is not used anywhere and can be safely removed. I will make a PR for a review in a week or two.

Ok thanks for the information. This all sounds very reasonable.

niello wrote:because explicit is better than implicit.

I wholeheartedly agree with this way of thinking :D

The implicit stuff just causes confusion, mistakes and prevents people from properly understanding what is going on in case they don't already know exactly what's going on. So yes, I think this should be part of CEGUI default branch. Unfortunately we can't change this in v0-8 because it would break the existing applications of all people who depend on this, right?
CrazyEddie: "I don't like GUIs"

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Thu Feb 07, 2019 13:01

Definitely. I'll try to migrate to default, and if it causes too much pain / time waste, I will make default-based PR for you and patch my local version accordingly until I'm ready to update major version.

User avatar
Ident
CEGUI Team
Posts: 1998
Joined: Sat Oct 31, 2009 13:57
Location: Austria

Re: Suggestion: get rid of default context

Postby Ident » Sun Feb 10, 2019 09:52

Sounds good!
CrazyEddie: "I don't like GUIs"

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Sun Feb 17, 2019 18:14

The main part is done. But the presense of default viewport target still prevents a proper usage of contexts in a multi-window scenario. We need a viewport target per a viewport, not one per application. I am working on a solution, but it may require to change Renderer interface slightly. To be specific, I plan to remove getDefaultRenderTarget() and to allow createViewportTarget() instead.

Upd:
Or maybe I will just add createViewportTarget() without deleting getDefaultRenderTarget(), because it seems too hard for me to build local infrastructure to test all CEGUI renderers.

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Tue Feb 19, 2019 19:12

Migrating to 'default' I noticed that it has no 'drawmode-devel' merged into it. Can you or me merge drawmode-devel? My code relies on it.

User avatar
Ident
CEGUI Team
Posts: 1998
Joined: Sat Oct 31, 2009 13:57
Location: Austria

Re: Suggestion: get rid of default context

Postby Ident » Sun Feb 24, 2019 18:07

I merged it all into default. I hope I did not miss anything, some file histories did not involve a "move" operation due to a change someone once made that is hard to undo, so there is now always a chance of loss, and also there was a bunch to merge now (which shall be a reminder again that i should merge to default immediately after accepting a PR).

Does it work now?
CrazyEddie: "I don't like GUIs"

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Tue Feb 26, 2019 19:37

ScrollablePane.cpp:248 - need to change from container->setMouseCursor(getMouseCursor()); to container->setCursor(getCursor());
Also drawMode was not merged. No trace of it in code. Looks like drawmode-devel became drawmode-devel-v0 and was not merged to v0-8 or v0 yet. So merging v0-8 -> v0 -> default didn't help.

User avatar
Ident
CEGUI Team
Posts: 1998
Joined: Sat Oct 31, 2009 13:57
Location: Austria

Re: Suggestion: get rid of default context

Postby Ident » Sun Mar 03, 2019 20:52

niello wrote:ScrollablePane.cpp:248 - need to change from container->setMouseCursor(getMouseCursor()); to container->setCursor(getCursor());

I fixed it when i ran the samples but forgot to submit. Submitting it now.
niello wrote:Also drawMode was not merged. No trace of it in code. Looks like drawmode-devel became drawmode-devel-v0 and was not merged to v0-8 or v0 yet. So merging v0-8 -> v0 -> default didn't help.

No idea what that means, can you elaborate?
CrazyEddie: "I don't like GUIs"

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Mon Mar 04, 2019 06:21

There is a branch named 'drawmode-devel-v0'. It contains a feature of rendering some parts of GUI separately. For example as opaque, allowing it to write to Z-buffer. It would be nice to merge it into the default branch if possible.

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Fri Mar 29, 2019 13:16

Any news here?

niello
Quite a regular
Quite a regular
Posts: 76
Joined: Tue May 24, 2011 05:54
Contact:

Re: Suggestion: get rid of default context

Postby niello » Mon Apr 29, 2019 12:44

Default context is removed from the 'default' branch.
Please note that using Renderer::getDefaultRenderTarget is now highly discouraged (I would even prefer to say prohibited) in a core CEGUI code. It can be left for convenience and used in user code though.

drwbns
Just popping in
Just popping in
Posts: 18
Joined: Wed May 30, 2012 15:37

Re: [Done] Suggestion: get rid of default context

Postby drwbns » Sun Aug 23, 2020 00:07

Hey guys. I noticed the SDL2 sample broke due to this change from what I can tell. Here is my update to fix it. Hopefully I am using the createGUIcontext correctly.

I also added "#define SDL_MAIN_HANDLED" before including "sdl.h" because this appears to fix a "main" conflict.

This all seems to work fine but may not be suitable if trying to work with multiple GUI contexts:


Code: Select all

/***********************************************************************
created:    Sep 11 2014
author:     Luca Ebach <bitbucket@lucebac.net>
*************************************************************************/
/***************************************************************************
*   Copyright (C) 2004 - 2015 Paul D Turner & The CEGUI Development Team
*
*   Permission is hereby granted, free of charge, to any person obtaining
*   a copy of this software and associated documentation files (the
*   "Software"), to deal in the Software without restriction, including
*   without limitation the rights to use, copy, modify, merge, publish,
*   distribute, sublicense, and/or sell copies of the Software, and to
*   permit persons to whom the Software is furnished to do so, subject to
*   the following conditions:
*
*   The above copyright notice and this permission notice shall be
*   included in all copies or substantial portions of the Software.
*
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/

/**************************************************************************
* The following libs (and corresponding headers) are needed to compile and to link:
* CEGUIBase
* CEGUIOpenGLRenderer
* CEGUICoreWindowRendererSet
* default CEGUI xml parser (and dependencies)
* SDL2main (windows only)
* SDL2
* OpengGL
* glm headers (as part of CEGUIBase)
***************************************************************************/

#include <iostream>

#include <CEGUI/CEGUI.h>
#include <CEGUI/RendererModules/OpenGL/GLRenderer.h>

#define SDL_MAIN_HANDLED

#include <SDL.h>
#include <SDL_opengl.h>

#include "sdl_scancode_to_dinput_mappings.h"

static SDL_Window* window;
static SDL_GLContext context;
static CEGUI::InputAggregator* G_inputAggregator;

static CEGUI::GUIContext *gc;

CEGUI::Key::Scan toCEGUIKey(SDL_Scancode key)
{
    return static_cast<CEGUI::Key::Scan>(scanCodeToKeyNum[static_cast<int>(key)]);
}

void injectUTF8Text(const char* utf8str)
{
    static SDL_iconv_t cd = SDL_iconv_t(-1);

    if (cd == SDL_iconv_t(-1))
    {
        // note: just "UTF-32" doesn't work as toFormat, because then you get BOMs, which we don't want.
        const char* toFormat = "UTF-32LE"; // TODO: what does CEGUI expect on big endian machines?
        cd = SDL_iconv_open(toFormat, "UTF-8");
        if (cd == SDL_iconv_t(-1))
        {
            std::cerr << "Couldn't initialize SDL_iconv for UTF-8 to UTF-32!" << std::endl;
            return;
        }
    }

    // utf8str has at most SDL_TEXTINPUTEVENT_TEXT_SIZE (32) chars,
    // so we won't have have more utf32 chars than that
    Uint32 utf32buf[SDL_TEXTINPUTEVENT_TEXT_SIZE] = {0};

    // we'll convert utf8str to a utf32 string, saved in utf32buf.
    // the utf32 chars will be injected into cegui

    size_t len = strlen(utf8str);

    size_t inbytesleft = len;
    size_t outbytesleft = 4 * SDL_TEXTINPUTEVENT_TEXT_SIZE; // *4 because utf-32 needs 4x as much space as utf-8
    char* outbuf = (char*)utf32buf;
    size_t n = SDL_iconv(cd, &utf8str, &inbytesleft, &outbuf, &outbytesleft);

    if (n == size_t(-1)) // some error occured during iconv
    {
        std::cerr << "Converting UTF-8 string " << utf8str << " from SDL_TEXTINPUT to UTF-32 failed!" << std::endl;
    }

    for (int i = 0; i < SDL_TEXTINPUTEVENT_TEXT_SIZE; ++i)
    {
        if (utf32buf[i] == 0)
            break; // end of string

        G_inputAggregator->injectChar(utf32buf[i]);
    }

    // reset cd so it can be used again
    SDL_iconv(cd, NULL, &inbytesleft, NULL, &outbytesleft);
}

void initSDL()
{
    // init everything from SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
    {
        std::cerr << "SDL could not be initialized!" << std::endl
            << "Error message: " << SDL_GetError() << std::endl;
        exit(1);
    }

    // create opengl window with size of 800x600px
    window = SDL_CreateWindow("CEGUI + SDL2 window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if (!window)
    {
        std::cerr << "Could not create SDL window: " << SDL_GetError() << std::endl;
        SDL_Quit();
        exit(1);
    }

    // disable native mouse cursor
    SDL_ShowCursor(0);

    // setup opengl rendering context
    context = SDL_GL_CreateContext(window);
}

void initCEGUI()
{
    using namespace CEGUI;

    // create renderer and enable extra states
    OpenGLRenderer& cegui_renderer = OpenGLRenderer::create(Sizef(800.f, 600.f));

    // create CEGUI system object
    System::create(cegui_renderer);

   gc = &System::getSingletonPtr()->createGUIContext(cegui_renderer.getDefaultRenderTarget());

    G_inputAggregator = new InputAggregator(gc);
    G_inputAggregator->initialise();

    // setup resource directories
    DefaultResourceProvider* rp = static_cast<DefaultResourceProvider*>(System::getSingleton().getResourceProvider());
    rp->setResourceGroupDirectory("schemes", "datafiles/schemes/");
    rp->setResourceGroupDirectory("imagesets", "datafiles/imagesets/");
    rp->setResourceGroupDirectory("fonts", "datafiles/fonts/");
    rp->setResourceGroupDirectory("layouts", "datafiles/layouts/");
    rp->setResourceGroupDirectory("looknfeels", "datafiles/looknfeel/");
    rp->setResourceGroupDirectory("lua_scripts", "datafiles/lua_scripts/");
    rp->setResourceGroupDirectory("schemas", "datafiles/xml_schemas/");

    // set default resource groups
    ImageManager::setImagesetDefaultResourceGroup("imagesets");
    Font::setDefaultResourceGroup("fonts");
    Scheme::setDefaultResourceGroup("schemes");
    WidgetLookManager::setDefaultResourceGroup("looknfeels");
    WindowManager::setDefaultResourceGroup("layouts");
    ScriptModule::setDefaultResourceGroup("lua_scripts");

    XMLParser* parser = System::getSingleton().getXMLParser();
    if (parser->isPropertyPresent("SchemaDefaultResourceGroup"))
        parser->setProperty("SchemaDefaultResourceGroup", "schemas");

    // load TaharezLook scheme and DejaVuSans-10 font
    SchemeManager::getSingleton().createFromFile("TaharezLook.scheme", "schemes");
    FontManager::getSingleton().createFromFile("DejaVuSans-10.font");

    // set default font and cursor image and tooltip type
    gc->setDefaultFont("DejaVuSans-10");
   gc->getCursor().setDefaultImage("TaharezLook/MouseArrow");
   gc->setDefaultTooltipType("TaharezLook/Tooltip");
}

void initWindows()
{
    using namespace CEGUI;

    /////////////////////////////////////////////////////////////
    // Add your gui initialisation code in here.
    // You can use the following code as an inspiration for
    // creating your own windows.
    // But you should preferably use layout loading because you won't
    // have to recompile everytime you change the layout.
    /////////////////////////////////////////////////////////////

    // load layout
    Window* root = WindowManager::getSingleton().loadLayoutFromFile("application_templates.layout");
   gc->setRootWindow(root);
}

// convert SDL mouse button to CEGUI mouse button
CEGUI::MouseButton SDLtoCEGUIMouseButton(const Uint8& button)
{
    using namespace CEGUI;

    switch (button)
    {
    case SDL_BUTTON_LEFT:
        return MouseButton::Left;
       
    case SDL_BUTTON_MIDDLE:
        return MouseButton::Middle;

    case SDL_BUTTON_RIGHT:
        return MouseButton::Right;

    case SDL_BUTTON_X1:
        return MouseButton::X1;

    case SDL_BUTTON_X2:
        return MouseButton::X2;

    default:
        return MouseButton::Invalid;
    }
}

int main(int /*argc*/, char* /*argv*/[])
{
    using namespace CEGUI;

    // init SDL
    initSDL();

    // init cegui
    initCEGUI();

    // notify system of the window size
    System::getSingleton().notifyDisplaySizeChanged(Sizef(800.f, 600.f));

    // initialise windows and setup layout
    initWindows();

    // set gl clear color
    glClearColor(0, 0, 0, 255);

    bool quit = false;
    SDL_Event event;
    float time = SDL_GetTicks() / 1000.f;

    OpenGLRenderer* renderer = static_cast<OpenGLRenderer*>(System::getSingleton().getRenderer());

    // repeat until a quit is requested
    while (!quit && !SDL_QuitRequested())
    {
        // query and process events
        while (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
            case SDL_QUIT:
                quit = true;
                break;
           
            case SDL_MOUSEMOTION:
                G_inputAggregator->injectMousePosition(static_cast<float>(event.motion.x),
                                                                                         static_cast<float>(event.motion.y));
                break;

            case SDL_MOUSEBUTTONDOWN:
                G_inputAggregator->injectMouseButtonDown(SDLtoCEGUIMouseButton(event.button.button));
                break;

            case SDL_MOUSEBUTTONUP:
                G_inputAggregator->injectMouseButtonUp(SDLtoCEGUIMouseButton(event.button.button));
                break;

            case SDL_MOUSEWHEEL:
                G_inputAggregator->injectMouseWheelChange(static_cast<float>(event.wheel.y));
                break;

            case SDL_KEYDOWN:
                G_inputAggregator->injectKeyDown(toCEGUIKey(event.key.keysym.scancode));
                break;

            case SDL_KEYUP:
                G_inputAggregator->injectKeyUp(toCEGUIKey(event.key.keysym.scancode));
                break;

            case SDL_TEXTINPUT:
                injectUTF8Text(event.text.text);
                break;

            case SDL_WINDOWEVENT:
                if (event.window.event == SDL_WINDOWEVENT_RESIZED)
                {
                    System::getSingleton().notifyDisplaySizeChanged(Sizef(static_cast<float>(event.window.data1),
                                                                          static_cast<float>(event.window.data2)));
                    glViewport(0, 0, event.window.data1, event.window.data2);
                }
                else if (event.window.event == SDL_WINDOWEVENT_LEAVE)
                {
                    G_inputAggregator->injectMouseLeaves();
                }
                break;

            default:
                break;

            }
        }

        glClear(GL_COLOR_BUFFER_BIT);

        // inject time pulses
        const float newtime = SDL_GetTicks() / 1000.f;
        const float time_elapsed = newtime - time;
        System::getSingleton().injectTimePulse(time_elapsed);
        gc->injectTimePulse(time_elapsed);
        time = newtime;

        // render gui
        renderer->beginRendering();
        System::getSingleton().renderAllGUIContexts();
        renderer->endRendering();

        // swap buffers
        SDL_GL_SwapWindow(window);
    }

    delete G_inputAggregator;
   //delete gc;
    G_inputAggregator = 0;
   gc = 0;
    System::destroy();
    OpenGLRenderer::destroy(*renderer);
    renderer = 0;

    // delete SDL GL context
    SDL_GL_DeleteContext(context);

    // destroy SDL window
    SDL_DestroyWindow(window);

    // cleanup SDL
    SDL_Quit();

    return 0;
}


UPDATE:

Looks like the system doesn't like my GUIContext creation when shutting down. I'll look around for the correct way to do this or maybe someone can chime in:

Capture.PNG


UPDATE 2:

I just commented out the "delete gc;" command above and let the system destroy it. All good now! :)


Return to “Bug Reports, Suggestions, Feature Requests”

Who is online

Users browsing this forum: No registered users and 1 guest