New Urho3D Editor [update from 2017-11-03]

In worst case scenario, if every view needs it’s own Urho3D instance, that still seems ok to me. Urho is pretty light weight, and for most of the views, a reduced Urho build could be used.

How much is the delay? It’s not a matter of urho’s inactive fps?

I’m not sure those issues are big enough to change path.

@1vanK Note that both exmples use non-native UI. Blender use it everywhere, Unity is probably keep native toolbar and menu,

I am too.

Yes, I pay attention that they updates not with 60 fps, but only when it is need (ui not required ofter redrawing)

Only one 3D view for single Urho3D instance. Some small preview windows like in Resource Browser or Material Editor will now require launcing sepearte Urho3D Application.

Why do you want to use Urho3D for a Resource Browser? Isn’t that just a view of files easier done in Qt anyway?
A Material Editor using Urho3D to display the result would be neat, indeed. But outside of displaying the result, I’m not sure such an editor wouldn’t be better done in Qt.

Either way, as others have pointed out, it is normal in editors to have multiple views/windows each running an instance of some kind of 3D display.
No real way around it, I think. And I agree that it wouldn’t be too much of a performance issue. After all, most of them will be inactive most of the time (aka not updating).

I my Urho Qt Widget I managed key events in this way :

     //------------------------------------------------------------------------------------------------------
    // key utilities to convert Qt key to SDL key
    //------------------------------------------------------------------------------------------------------
    static QMap<Qt::Key, SDL_Keycode> __keymap;
    static void __initKeyMap();
    static Uint16 __convertQtKeyModifierToSDL(Qt::KeyboardModifiers qtKeyModifiers);
    static SDL_Keycode __convertQtKeyToSDL(Qt::Key qtKey);

    //------------------------------------------------------------------------------------------------------
    // map keys Qt/SDL
    //------------------------------------------------------------------------------------------------------
    void __initKeyMap()
    {
        __keymap[Qt::Key_unknown]     = SDLK_UNKNOWN;
        __keymap[Qt::Key_Escape]      = SDLK_ESCAPE;
        __keymap[Qt::Key_Tab]         = SDLK_TAB;
        __keymap[Qt::Key_Backspace]   = SDLK_BACKSPACE;
        __keymap[Qt::Key_Return]      = SDLK_RETURN;
        __keymap[Qt::Key_Enter]       = SDLK_KP_ENTER;
        __keymap[Qt::Key_Insert]      = SDLK_INSERT;
        __keymap[Qt::Key_Delete]      = SDLK_DELETE;
        __keymap[Qt::Key_Pause]       = SDLK_PAUSE;
        __keymap[Qt::Key_Print]       = SDLK_PRINTSCREEN;
        __keymap[Qt::Key_SysReq]      = SDLK_SYSREQ;
        __keymap[Qt::Key_Home]        = SDLK_HOME;
        __keymap[Qt::Key_End]         = SDLK_END;
        __keymap[Qt::Key_Left]        = SDLK_LEFT;
        __keymap[Qt::Key_Right]       = SDLK_RIGHT;
        __keymap[Qt::Key_Up]          = SDLK_UP;
        __keymap[Qt::Key_Down]        = SDLK_DOWN;
        __keymap[Qt::Key_PageUp]      = SDLK_PAGEUP;
        __keymap[Qt::Key_PageDown]    = SDLK_PAGEDOWN;
        __keymap[Qt::Key_Shift]       = SDLK_LSHIFT;
        __keymap[Qt::Key_Control]     = SDLK_LCTRL;
        __keymap[Qt::Key_Alt]         = SDLK_LALT;
        __keymap[Qt::Key_CapsLock]    = SDLK_CAPSLOCK;
        __keymap[Qt::Key_NumLock]     = SDLK_NUMLOCKCLEAR;
        __keymap[Qt::Key_ScrollLock]  = SDLK_SCROLLLOCK;
        __keymap[Qt::Key_F1]          = SDLK_F1;
        __keymap[Qt::Key_F2]          = SDLK_F2;
        __keymap[Qt::Key_F3]          = SDLK_F3;
        __keymap[Qt::Key_F4]          = SDLK_F4;
        __keymap[Qt::Key_F5]          = SDLK_F5;
        __keymap[Qt::Key_F6]          = SDLK_F6;
        __keymap[Qt::Key_F7]          = SDLK_F7;
        __keymap[Qt::Key_F8]          = SDLK_F8;
        __keymap[Qt::Key_F9]          = SDLK_F9;
        __keymap[Qt::Key_F10]         = SDLK_F10;
        __keymap[Qt::Key_F11]         = SDLK_F11;
        __keymap[Qt::Key_F12]         = SDLK_F12;
        __keymap[Qt::Key_F13]         = SDLK_F13;
        __keymap[Qt::Key_F14]         = SDLK_F14;
        __keymap[Qt::Key_F15]         = SDLK_F15;
        __keymap[Qt::Key_Menu]        = SDLK_MENU;
        __keymap[Qt::Key_Help]        = SDLK_HELP;

        // A-Z
        for(int key='A'; key<='Z'; key++)
            __keymap[Qt::Key(key)] = key + 32;

        // 0-9
        for(int key='0'; key<='9'; key++)
            __keymap[Qt::Key(key)] = key;
    }

    //------------------------------------------------------------------------------------------------------
    // get SDL key from Qt key
    //------------------------------------------------------------------------------------------------------
    SDL_Keycode __convertQtKeyToSDL(Qt::Key qtKey)
    {
        SDL_Keycode sldKey = __keymap.value(Qt::Key(qtKey));

        if(sldKey == 0)
            ePRINT("Warning: Key %d not mapped", qtKey);

        return sldKey;
    }

    //------------------------------------------------------------------------------------------------------
    // get SDL key modifier from Qt key modifier
    //------------------------------------------------------------------------------------------------------
    Uint16 __convertQtKeyModifierToSDL(Qt::KeyboardModifiers qtKeyModifiers)
    {
        Uint16 sdlModifiers = KMOD_NONE;

        if(qtKeyModifiers.testFlag(Qt::ShiftModifier))
            sdlModifiers |= KMOD_LSHIFT | KMOD_RSHIFT;
        if(qtKeyModifiers.testFlag(Qt::ControlModifier))
            sdlModifiers |= KMOD_LCTRL | KMOD_RCTRL;
        if(qtKeyModifiers.testFlag(Qt::AltModifier))
            sdlModifiers |= KMOD_LALT | KMOD_RALT;

        return sdlModifiers;
    }

void eRenderView::keyReleaseEvent(QKeyEvent *ke)
{
    QWidget::keyReleaseEvent(ke);      

    // Transmit key release event to SDL
    SDL_Event sdlEvent;
    sdlEvent.type = SDL_KEYUP;
    sdlEvent.key.keysym.sym = __convertQtKeyToSDL( Qt::Key(ke->key()) );
    sdlEvent.key.keysym.mod = __convertQtKeyModifierToSDL(ke->modifiers());
    SDL_PushEvent(&sdlEvent);
}

void eRenderView::keyPressEvent(QKeyEvent *ke)
{
    QWidget::keyPressEvent(ke);     

    // Transmit key press event to SDL
    SDL_Event sdlEvent;
    sdlEvent.type = SDL_KEYDOWN;
    sdlEvent.key.keysym.sym = __convertQtKeyToSDL( Qt::Key(ke->key()) );
    sdlEvent.key.keysym.mod = __convertQtKeyModifierToSDL(ke->modifiers());
    SDL_PushEvent(&sdlEvent);
}

Great! I didn’t know about such cool thing! Thanx!

RB in old Urho3D editor was able to preview materials and models. I need Urho systems to achieve this.

It’s not about rendering performace. Seperate Urho instances mean duplicate resources in memory and redundant disk ops.

I’ll probably end up with small preview window in main Urho widget.

Couldn’t you make the single Urho3D instance overlay the entire window with a viewport for every 3D view?

Then what’s the point of using native framework like Qt if I will have to implement all windows, docks and menus on my own?

I meant graphically overlayed, with the Qt part showing underneath. Or would that bring up other unresolvable issues?

I spent some time recently about UI integration on game engines…
As a background, I come from cocos2dx, which has a UI system of its own, mostly reusing a single Sprite class itself and getting ui widgets out of it, very cocoa-like…
Something like QT is not really viable. At a monstre 15gb download on my mac, it’s as big as the Microsoft virtual machine for development, fully packed up with windows os. So really, no. It’s not just an editor; it’s an ecosystem. Of course, it has all the widgets you may want…
Here’s a list with some lighter ui tools i found which can be used more flexibly, and possibly be mobile friendly.

All these projects looks recent and mantained. The one i’ve tried:

Imgui - is light and works very well. It’s fast and is widely used on gaming projects. You can see it in action in bgfx https://github.com/floooh/fips-bgfx for istance together with nanovg https://github.com/memononen/nanovg (a fast svg direct command library for drawing) in example 20. Anyway, imgui is a immediate gui mode, that’s good for an editor, not-so-good in-game.
Cegui - Gorgeous, skinnable, rich graphics. Well known. Anyway, it’s heavy.
Turbobadger - wasn’t able to make it work correctly on my mac, so i don’t know. Probably not-retina.
Librocket - seems to be already integrated with urho. didn’t tried it yet.
MyGui, Gamegui, Guisan, same as librocket - not yet tried.
Does someone else have experience with these?

I could not disagree more.
The task of this is not to create a game UI (which Qt would be completely wrong for, indeed, but for other reasons).

The task is to create an editor, akin to Maya, Blender, Max, Unity…
This is a completely different thing.

And you can completely forget about doing any of that with any of the libs you listed if you do not want to spend weeks after weeks of implementing basic windowing, widget and misc functionality, which you’d all get for free.
And that doesn’t even cover that editor applications are expected to follow a certain OS-like style in their layouts (note how Eugene’s screens so far make it look somewhat similar to a dark Visual Studio).
Or they will simply end up looking amateurish (as the current Urho editor does). And will be very hard and unintuitive to use.
Good luck designing that with CEGUI :smiley:

I tried working with most of the libs you mentioned. They are horrible for anything more than very basic layout needs. And most of them come with no kind of layout designer (or pretty bad ones).
IMO the only viable GUI library for games which will not cost your sanity is do-it-yourself with libcef3 (as that offers all that can be done in a browser) or the commercial alternative that already did the integration (forgot the name to be honest…).

At a monstre 15gb download on my mac, it’s as big as the Microsoft virtual machine for development, fully packed up with windows os.

I cannot believe that we still get this in 2017. 15gb is nothing. Get over it.
And besides, the actual distribution size of a Qt app is way, way smaller than that - an application I am developing that is using a lot of Qt functionality comes at a size of 200mb, of which Qt is not even 100mb.

1 Like

Do you have any ideas how to merge these two images?
As far as I know, any GAPI widget like DX or GL view always overdraw entire rect area.

Yes, I dislike Qt heaviness too. However, is there any UI framework with such layouts, docks, styles, resource system and hierarchy view?

I’ll check suggested frameworks, anyway.

I just imagined a transparent background. But you seem to imply this wouldn’t work.

[quote=“Eugene, post:59, topic:2407, full:true”]

Do you have any ideas how to merge these two images?
As far as I know, any GAPI widget like DX or GL view always overdraw entire rect area.[/quote]
I think what he meant (correct me if wrong) was to show windows containing Urho3D views on top of the Qt application.
Like… little windows that are hovering over the normal application.
Did I get that right?

If so, this can definitely be done with Qt.
Even the other way around can be done: Displaying Qt elements on top of a Urho3D scene (including transparency).

I don’t think that is a Qt problem but an Urho issue because it doesn’t support multiple windows.

You can however try to play with SDL_GL_MakeCurrent

[quote=“TheSHEEEP, post:61, topic:2407”]Like… little windows that are hovering over the normal application.Did I get that right?
[/quote]
Nope

That might be a better way to do it then. Window-filling 3D-accellerated background with viewports that rescale along with their associated transparent QWidgets.

It may be hard to achieve on GAPI side.

Huh.
Movement looks luggy when I accumulate position attribute change this way:

// Somewhere in Mouse Move event
const QPoint delta = event->globalPos() - prevPosition_;
QCursor::setPos(prevPosition_);

And it looks much better if I write

const QPoint delta = event->globalPos() - prevPosition_;
prevPosition_ = event->globalPos();

It seems that such a crap is caused by setPos.
It seems that this call loses some sub-pixel stuff that end up in unsmooth deltas.

For my widget and to control camera on viewport I don’t use mouseMoveEvent.

Somewher in constructor : setMouseTracking(true);

and :

void eRenderView::mousePressEvent(QMouseEvent *me)
{
    QWidget::mousePressEvent(me);

    m_lastMousePos = me->pos();
    m_mouseDownPos = me->pos();

    if (me->buttons() & Qt::RightButton)
        setContextMenuPolicy(Qt::PreventContextMenu);


    SDL_Event sdlEvent;
    sdlEvent.type = SDL_MOUSEBUTTONDOWN;
    sdlEvent.button.state = SDL_PRESSED;
    if(me->buttons() & Qt::LeftButton)
        sdlEvent.button.button = SDL_BUTTON_LMASK;
    if(me->buttons() & Qt::RightButton)
        sdlEvent.button.button = SDL_BUTTON_RMASK;
    if(me->buttons() & Qt::MiddleButton)
        sdlEvent.button.button = SDL_BUTTON_LMASK;
    QPoint position = me->pos();
    sdlEvent.button.x = position.x();
    sdlEvent.button.y = position.y();
    SDL_PushEvent(&sdlEvent);


    const eBool leftBtn = (me->buttons() & Qt::LeftButton);
    if(leftBtn)
    {
        QPoint glob = mapToGlobal(QPoint(width()/2,height()/2));
        QCursor::setPos(glob);
        SDL_SetRelativeMouseMode(SDL_TRUE);
    }
}

void eRenderView::mouseReleaseEvent(QMouseEvent *me)
{
    QWidget::mouseReleaseEvent(me);

    if (me->button() == Qt::RightButton)
    {
        QContextMenuEvent ce(QContextMenuEvent::Mouse, me->pos());
        setContextMenuPolicy(Qt::DefaultContextMenu);
        contextMenuEvent(&ce);
    }

    SDL_Event sdlEvent;
    sdlEvent.type = SDL_MOUSEBUTTONUP;
    sdlEvent.button.state = SDL_RELEASED;
    if(me->buttons() & Qt::LeftButton)
        sdlEvent.button.button = SDL_BUTTON_LMASK;
    if(me->buttons() & Qt::RightButton)
        sdlEvent.button.button = SDL_BUTTON_RMASK;
    if(me->buttons() & Qt::MiddleButton)
        sdlEvent.button.button = SDL_BUTTON_LMASK;
    QPoint position = me->pos();
    sdlEvent.button.x = position.x();
    sdlEvent.button.y = position.y();
    SDL_PushEvent(&sdlEvent);


    if(SDL_GetRelativeMouseMode())
    {
        SDL_SetRelativeMouseMode(SDL_FALSE);
        QPoint glob = mapToGlobal(QPoint(width()/2,height()/2));
        QCursor::setPos(glob);
    }
}