Custom RTT Widget in CEGUI with Ogre renderer

For help with anything that CEGUI doesn't offer straight out-of-the-box, e.g.:
- Implementation of new features, such as new Core classes, widgets, WindowRenderers, etc. ...
- Modification of any existing features for specific purposes
- Integration of CEGUI in new engines or frameworks and writing of new plugins (Renderer, Parser, ...) or modules

Moderators: CEGUI MVP, CEGUI Team

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Thu Sep 25, 2014 11:37

Hey there,

I am currently in the process of trying out CEGUI and figuring out if various things we need for our project are possible with it.
It was pretty easy to setup and get it running with Ogre, which we are using as our rendering engine. So thumbs up for that.

We also want to have the possibility to display and manage 3D rendered content using the CEGUI's framwork with layout files.
I already figured out that RTT is probably the way to go for this and I have found posts and code for that as well with this one being the most helpful so far.

However, I got this example running with the current version 0.8, but it does not allow me to declare it that way in a layout xml file. So I started a class which inherits the CEGUI Window to create my own widget. This should simply display the rendered scene a camera can see which is attached to it.

Here is the code I got so far:
Header file:

Code: Select all

class CEGUIViewportWindow : public CEGUI::Window
{
public:
   static const CEGUI::String EventNamespace;            //!< Namespace for global events
    static const CEGUI::String WidgetTypeName;             //!< Window factory name

   CEGUIViewportWindow(const CEGUI::String& type, const CEGUI::String& name);
   virtual ~CEGUIViewportWindow();

   void setCameraToRender(Ogre::Camera& camera);

   void removeCamera(void);

protected:
   void onRenderingStarted(CEGUI::WindowEventArgs& e);
   void onSized(CEGUI::ElementEventArgs& e);

private:
   Ogre::RenderTexture* mRttTexture;
   Ogre::Camera* mCamera;
   Ogre::Viewport* mViewport;

   void __initialiseRTTViewport(CEGUI::RenderingSurface* surface, bool force);
   void __setCamera(Ogre::Camera& camera);
   bool __handleResize(const CEGUI::EventArgs& args);
};


Here the source file:

Code: Select all

const CEGUI::String CEGUIViewportWindow::EventNamespace("ViewportWindow");
const CEGUI::String CEGUIViewportWindow::WidgetTypeName("CEGUI/ViewportWindow");             //!< Window factory name

CEGUIViewportWindow::CEGUIViewportWindow(const CEGUI::String& type, const CEGUI::String& name) :
   CEGUI::Window(type, name)
{
   this->mRttTexture = NULL;
   this->mCamera = NULL;
   this->mViewport = NULL;
}

CEGUIViewportWindow::~CEGUIViewportWindow(void)
{

}

void CEGUIViewportWindow::setCameraToRender(Ogre::Camera& camera)
{
   this->__setCamera(camera);
}

void CEGUIViewportWindow::removeCamera(void)
{
   this->mCamera = NULL;
}

// ------------------------------------------------------------------------------------------------

void CEGUIViewportWindow::__initialiseRTTViewport(CEGUI::RenderingSurface* surface, bool force)
{
    Ogre::RenderTexture* old_rtt = this->mRttTexture;

    // extract the Ogre render target at for the surface
    CEGUI::OgreTextureTarget& textureTarget = dynamic_cast<CEGUI::OgreTextureTarget&>(
            surface->getRenderTarget());
    CEGUI::OgreTexture& ogreTexture = dynamic_cast<CEGUI::OgreTexture&>(textureTarget.getTexture());
    this->mRttTexture = ogreTexture.getOgreTexture()->getBuffer()->getRenderTarget();

    // only do set up if target is changed.
    if (old_rtt != this->mRttTexture || force)
    {
        // tell Ogre not to draw this target automatically (else you get
        // visible flickering).
       this->mRttTexture->setAutoUpdated(false);

        // setup viewport from the same camera as the main scene.
       Ogre::Viewport* viewport = this->mRttTexture->addViewport(mCamera);
       viewport->setOverlaysEnabled(false);
       viewport->setBackgroundColour(Ogre::ColourValue::Black);
    }
}

void CEGUIViewportWindow::__setCamera(Ogre::Camera& camera)
{
   this->mCamera = &camera;

   CEGUI::RenderingSurface* surface = this->getRenderingSurface();
   if (surface != NULL)
      this->__initialiseRTTViewport(surface, true);
}

void CEGUIViewportWindow::onRenderingStarted(CEGUI::WindowEventArgs& e)
{
   if (this->mRttTexture != NULL)
      this->mRttTexture->update();
}

void CEGUIViewportWindow::onSized(CEGUI::ElementEventArgs& e)
{
    // get rendering surface used by FrameWindow.
    CEGUI::RenderingSurface* surface =
          static_cast<CEGUI::Window*>(e.element)->getRenderingSurface();

    // if there's no surface, skip the RTT setup parts!
    if (surface)
        this->__initialiseRTTViewport(surface, false);
}


I also registered the new widget with the WindowFactoryManager like this:

Code: Select all

CEGUI::WindowFactoryManager::getSingleton().addFactory<CEGUI::TplWindowFactory<CEGUIViewportWindow> >();


So I just took the example from this forum I found and tried creating my own widget. I took the already existing widgets from CEGUI as examples. So here is the problem with this:
If I try to create a new window of my own widget type "CEGUI/ViewportWindow", the rendering surface of it is always NULL.
It doesn't matter whether I access it within the class or outside of the class.
I am sure I forgot something, but I wasn't able to figure it out so far. Can somebody give me a hint on this? Or is there a tutorial with an example of a real custom widget based on the Window class?

That's the code section which creates my widget and adds it to the root window:

Code: Select all

CEGUI::Window* fw = wmgr.createWindow("CEGUI/ViewportWindow");
    rootWindow->addChild(fw);
    fw->setSize(CEGUI::USize(CEGUI::UDim(0.5f, 0), CEGUI::UDim(0.5f, 0)));
    ((ogreaddon::cegui::CEGUIViewportWindow*) fw)->setCameraToRender(*camera);

    // this always returns NULL
    CEGUI::RenderingSurface* renderingSurface = fw->getRenderingSurface();


Thanks in advance for any help on this.

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Thu Sep 25, 2014 12:53

First of all this thread is in the wrong section, it doesnt fit into "Advanced Help"... I will move it.

Secondly, have you looked at this: http://cegui.org.uk/wiki/Rendering_to_t ... 9_in_CEGUI ?
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Thu Sep 25, 2014 13:46

Ident wrote:First of all this thread is in the wrong section, it doesnt fit into "Advanced Help"... I will move it.

I am sorry for that. Thought it might be a more advanced topic.

Ident wrote:Secondly, have you looked at this: http://cegui.org.uk/wiki/Rendering_to_t ... 9_in_CEGUI ?

Yes, I have read that as well. But as far as I can tell, this is similar to the example I picked up to start writing the class I posted. If I am mistaken please tell me.

From what I understand, the CEGUI Window serves as a base class for all widgets. I want to create my own widget and add it to the CEGUI framework (and not replacing any existing CEGUI widgets),
so I can use it within layout files as well to create my GUI. That widget should display the contents of an RTT'd texture (like a plain image, but it is updated with new content from the rendered scene of the attached camera).

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Thu Sep 25, 2014 13:52

icetea wrote:From what I understand, the CEGUI Window serves as a base class for all widgets. I want to create my own widget and add it to the CEGUI framework (and not replacing any existing CEGUI widgets),.

There is no "CEGUI framework". We do not use that term anywhere. It is a library.
Anyway, why do you need to create your own widget?



icetea wrote:That widget should display the contents of an RTT'd texture (like a plain image, but it is updated with new content from the rendered scene of the attached camera).

CEGUI/Image can already do that. If you use Generic/Image you can replace the image at any time. RTT is used in the SampleBrowser. The linked wiki article describes what I belive is what you want, in the last section. What do you miss tjere? You can directly use the Texture you render to in Ogre and use it in CEGUI. I m not sure why you need the above code you posted. Could you iterate that more?

Also I only realised after the move that you wanted to create a widget around this. I consider it overkill though and also it couldnt go into our repository because of the other Renderers that all work differently. It could be that i misunderstood the whole issue you brought up here, excuse me if that is the case. Maybe you can explain shortly what you want to do and why you cant do this with the technique described in the wiki.
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Thu Sep 25, 2014 14:50

Ident wrote:Also I only realised after the move that you wanted to create a widget around this. I consider it overkill though and also it couldnt go into our repository because of the other Renderers that all work differently. It could be that i misunderstood the whole issue you brought up here, excuse me if that is the case. Maybe you can explain shortly what you want to do and why you cant do this with the technique described in the wiki.


I am very uncertain if my approach is the right way or if there is already something serving that purpose. That's where I would appreciate it to help me out or at least point me in the right direction.
I will try to explain everything in detail:
I tested the examples provided with CEGUI and saw that it is possible to actually create your whole GUI by using CEGUI with it's layout, scheme, animations etc files, all xml based. Plus having input and event handling lua scripted, I figured this is something we would really like to use to avoid "hardcoding" our complete GUI.
But there are a few custom elements we created and have to use which are not provided by CEGUI and are not possible to build using CEGUI. So in order to still have our complete GUI scripted, we would like to add these elements as widgets to CEGUI. That way we can use them alongside the existing CEGUI widgets like a button, text field etc.
An example for one of our custom widgets is a 3D object which is shaped like a plate. It displays status information on both sides and can thus be turned around by the player on command to view different status information. We would like to have that widget and a few others, which are also 3D objects, as widgets available with CEGUI, so we can use the scripting/xml methods already provided to integrate them.
So I want to say something like this in the layout file and have the element created without having to add any additional code to my current scene I want to display:

Code: Select all

<Window type="MyRTTViewport" name="My3DObjectAsTexture" >
     <!--- ... have properties which identify the camera and other things which are needed to hook up everything -->
</Window>

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Sat Sep 27, 2014 07:00

icetea wrote:An example for one of our custom widgets is a 3D object which is shaped like a plate. It displays status information on both sides and can thus be turned around by the player on command to view different status information. We would like to have that widget and a few others, which are also 3D objects, as widgets available with CEGUI, so we can use the scripting/xml methods already provided to integrate them.
So I want to say something like this in the layout file and have the element created without having to add any additional code to my current scene I want to display:

Code: Select all

<Window type="MyRTTViewport" name="My3DObjectAsTexture" >
     <!--- ... have properties which identify the camera and other things which are needed to hook up everything -->
</Window>


If i understand you right, you do not actually want to render to a texture, you directly want to render the object into a viewport on your display? Correct me if I get you wrong.
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Sat Sep 27, 2014 15:45

Ident wrote:
icetea wrote:An example for one of our custom widgets is a 3D object which is shaped like a plate. It displays status information on both sides and can thus be turned around by the player on command to view different status information. We would like to have that widget and a few others, which are also 3D objects, as widgets available with CEGUI, so we can use the scripting/xml methods already provided to integrate them.
So I want to say something like this in the layout file and have the element created without having to add any additional code to my current scene I want to display:

Code: Select all

<Window type="MyRTTViewport" name="My3DObjectAsTexture" >
     <!--- ... have properties which identify the camera and other things which are needed to hook up everything -->
</Window>


If i understand you right, you do not actually want to render to a texture, you directly want to render the object into a viewport on your display? Correct me if I get you wrong.

I thought that the contents of a window are getting rendered to a texture, so that's the reason that I even used the term RTT at all and thought of that being the way to go. Sorry if I caused any confusion due to that. But to answer your question: yes, the viewport I render to should be the CEGUI widget/window (if that's possible and the right way to say that).

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Sat Sep 27, 2014 17:11

icetea wrote:
Ident wrote:If i understand you right, you do not actually want to render to a texture, you directly want to render the object into a viewport on your display? Correct me if I get you wrong.

I thought that the contents of a window are getting rendered to a texture, so that's the reason that I even used the term RTT at all and thought of that being the way to go. Sorry if I caused any confusion due to that. But to answer your question: yes, the viewport I render to should be the CEGUI widget/window (if that's possible and the right way to say that).

I don't know much about Ogre in that respect, in general i rather use OpenGL and Direct3D directly. Those two major graphics libraries both allow you to do what I said: rendering into a viewport, meaning rendering only into a smaller section of your screen. Since both allow this, it should theoretically be possible to do this in Ogre as well yes. And no, you do not need a RTT for this. Of course, if you would not update this rendering every frame, then a RTT would be better. I will move this back to the advanced section. Sorry for the confusion on my side.

Unfortunately I cannot really help you with non-RTT Ogre rendering. This is an Ogre issue after all and not a CEGUI one. Of course you can tie it into CEGUI, but aside from anything directly CEGUI related I cant help you much there.

In the case you do want to render to a RTT. You can simply use the RTT texture ONLY to do what you want in CEGUI. All you need to do is to have the Ogre Texture reference ready. The wiki article I linked should explain how to create a CEGUI::Image* and set it up for a RTT. From there on, all you need to do is creating the window with the image property set to the right image.
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Sat Sep 27, 2014 18:37

Ident wrote:I don't know much about Ogre in that respect, in general i rather use OpenGL and Direct3D directly. Those two major graphics libraries both allow you to do what I said: rendering into a viewport, meaning rendering only into a smaller section of your screen. Since both allow this, it should theoretically be possible to do this in Ogre as well yes. And no, you do not need a RTT for this. Of course, if you would not update this rendering every frame, then a RTT would be better. I will move this back to the advanced section. Sorry for the confusion on my side.

Unfortunately I cannot really help you with non-RTT Ogre rendering. This is an Ogre issue after all and not a CEGUI one. Of course you can tie it into CEGUI, but aside from anything directly CEGUI related I cant help you much there.

In the case you do want to render to a RTT. You can simply use the RTT texture ONLY to do what you want in CEGUI. All you need to do is to have the Ogre Texture reference ready. The wiki article I linked should explain how to create a CEGUI::Image* and set it up for a RTT. From there on, all you need to do is creating the window with the image property set to the right image.

I know how to use Ogre and how to render to a viewport there. That's not the issue. I also don't mind "breaking" any kind of abstraction using CEGUI for my project, because it relies heavily on Ogre.
I am not sure if I was able to exaplain you my idea properly enough, yet. I get the feeling there are still a few things I couldn't clarify enough.

Though it sounds strange to me, but maybe if I say: "I want to take the Ogre viewport, which displays my entire 3D scene and want be able to use/treat it as a CEGUI widget, also having it available within CEGUI scripts".

Hope this helps you understanding my idea, if you weren't already on that track.
I also appreciate answers of others if someone else can follow my thoughts and has an idea on this.

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Sat Sep 27, 2014 19:29

icetea wrote:Though it sounds strange to me, but maybe if I say: "I want to take the Ogre viewport, which displays my entire 3D scene and want be able to use/treat it as a CEGUI widget, also having it available within CEGUI scripts".


Yea this matches what I understood. Btw., in our default branch we have the work from GSOC2013 available, which was about making custom-rendering and SVG support. This means that in default branch you can for example create 2D objects (lines, circles, rectangles, or just polygons right away) in run-time and let them get rendered by CEGUI. If you want to use 3D this might of course not be optimal but it is helpful for 2D rendering. However, the Ogre Renderer in default branch has not been updated to support this :D. We will probably have to get it running for the 1.0 Release though. Since you want 3D, this isnt recommendable anyways.

Anyways back to topic:
I am not sure what to do regarding the RenderingWindow. If you render to a viewport you do not need an explicit rendersurface for your Window, unless you have the AutoRenderingSurface property set to true (i hope this is the right name). What is the reason that you need this surface to not be 0? Is the RenderingSurface always != 0 for something like a Generic/Image or Generic/Label or a DefaultWindow? I would expect it to be 0 but I actually do not remember how this stuff works.
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Sat Sep 27, 2014 21:33

Ident wrote:I am not sure what to do regarding the RenderingWindow. If you render to a viewport you do not need an explicit rendersurface for your Window, unless you have the AutoRenderingSurface property set to true (i hope this is the right name).

Actually that hint got me to setUsingAutoRenderingSurface from the Window's class. Plus I also replaced

Code: Select all

this->getRenderingSurface();

with

Code: Select all

CEGUI::RenderingContext ctx;
this->getRenderingContext(ctx);
CEGUI::RenderingSurface* surface = ctx.surface;


And it finally works :D
I used a spinning Ogre head to see if the window on the top left is getting updated.
The red part is the scene rendered to a normal viewport (red background) and the black part is another viewport.
The viewport with the black background is the one created in the class CEGUIViewportWindow.

Image

Here is the complete code of the class:

Code: Select all

class CEGUIViewportWindow : public CEGUI::Window
{
public:
   static const CEGUI::String EventNamespace;            //!< Namespace for global events
    static const CEGUI::String WidgetTypeName;             //!< Window factory name

   CEGUIViewportWindow(const CEGUI::String& type, const CEGUI::String& name);
   virtual ~CEGUIViewportWindow();

   void setCameraToRender(Ogre::Camera& camera);

   void removeCamera(void);

protected:
   void onSized(CEGUI::ElementEventArgs& e);

private:
   Ogre::RenderTexture* mRttTexture;
   Ogre::Camera* mCamera;
   Ogre::Viewport* mViewport;

   void __initialiseRTTViewport(CEGUI::RenderingSurface* surface, bool force);
   void __setCamera(Ogre::Camera& camera);
};


Code: Select all

const CEGUI::String CEGUIViewportWindow::EventNamespace("ViewportWindow");
const CEGUI::String CEGUIViewportWindow::WidgetTypeName("CEGUI/ViewportWindow");             //!< Window factory name

CEGUIViewportWindow::CEGUIViewportWindow(const CEGUI::String& type, const CEGUI::String& name) :
   CEGUI::Window(type, name)
{
   this->mRttTexture = NULL;
   this->mCamera = NULL;
   this->mViewport = NULL;
}

CEGUIViewportWindow::~CEGUIViewportWindow(void)
{

}

void CEGUIViewportWindow::setCameraToRender(Ogre::Camera& camera)
{
   this->__setCamera(camera);
}

void CEGUIViewportWindow::removeCamera(void)
{
   this->mCamera = NULL;
}

// ------------------------------------------------------------------------------------------------

void CEGUIViewportWindow::__initialiseRTTViewport(CEGUI::RenderingSurface* surface, bool force)
{
    Ogre::RenderTexture* old_rtt = this->mRttTexture;

    // extract the Ogre render target at for the surface
    CEGUI::OgreTextureTarget& textureTarget = dynamic_cast<CEGUI::OgreTextureTarget&>(
            surface->getRenderTarget());
    CEGUI::OgreTexture& ogreTexture = dynamic_cast<CEGUI::OgreTexture&>(textureTarget.getTexture());
    this->mRttTexture = ogreTexture.getOgreTexture()->getBuffer()->getRenderTarget();

    // only do set up if target is changed.
    if (old_rtt != this->mRttTexture || force)
    {
        // let ogre update the texture
       this->mRttTexture->setAutoUpdated(true);


        // setup viewport from the same camera as the main scene.
       Ogre::Viewport* viewport = this->mRttTexture->addViewport(mCamera);
       viewport->setOverlaysEnabled(false);
       viewport->setBackgroundColour(Ogre::ColourValue::Black);
    }
}

void CEGUIViewportWindow::__setCamera(Ogre::Camera& camera)
{
   this->mCamera = &camera;

   // otherwise surface is not setup
   this->setUsingAutoRenderingSurface(true);

   // important: use render context to get the surface and not
   // //this->getRenderingSurface();
   CEGUI::RenderingContext ctx;
   this->getRenderingContext(ctx);

   CEGUI::RenderingSurface* surface = ctx.surface;
   if (surface != NULL)
      this->__initialiseRTTViewport(surface, true);
}

void CEGUIViewportWindow::onSized(CEGUI::ElementEventArgs& e)
{
    // get rendering surface used by FrameWindow.
    CEGUI::RenderingSurface* surface =
          static_cast<CEGUI::Window*>(e.element)->getRenderingSurface();

    // if there's no surface, skip the RTT setup parts!
    if (surface)
        this->__initialiseRTTViewport(surface, false);
}


The code is still a little messy, but at least I got it working.

Ident wrote:What is the reason that you need this surface to not be 0? Is the RenderingSurface always != 0 for something like a Generic/Image or Generic/Label or a DefaultWindow? I would expect it to be 0 but I actually do not remember how this stuff works.

It seems if I don't use setUsingAutoRenderingSurface, there is no surface created at all.

Though it's working now, can you tell if that's a performant/proper way of doing that or are there things to improve? I will dig a little deeper the next days but I got the feeling this is not really the proper way yet.

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Sat Sep 27, 2014 21:57

icetea wrote:Though it's working now, can you tell if that's a performant/proper way of doing that or are there things to improve? I will dig a little deeper the next days but I got the feeling this is not really the proper way yet.

Yea, i suggest not using the rendering surface. You would have to define a viewport according to the position and dimension of the CEGUI window and just render directly there without going through a RTT. Basically that is what I suggested before. It is a bit complexer though then using an RTT. You have to know exactly what you are doing and get the right coordinates from CEGUI (which is all possible).
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Sun Sep 28, 2014 18:26

Ident wrote:Yea, i suggest not using the rendering surface. You would have to define a viewport according to the position and dimension of the CEGUI window and just render directly there without going through a RTT. Basically that is what I suggested before. It is a bit complexer though then using an RTT. You have to know exactly what you are doing and get the right coordinates from CEGUI (which is all possible).

All right. I will look into this and see how far I can get. Thanks a lot for helping me to get this far.

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

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby Ident » Sun Sep 28, 2014 18:56

icetea wrote:All right. I will look into this and see how far I can get. Thanks a lot for helping me to get this far.

Well, I didnt actually do much except hinting you towards the AutoRenderingSurface, the rest was all your own doing ;) I also am not sure if my suggestion is doable without further modifications. From what I know and understand the whole thing should be doable. I hope I am not leading you to a dead end anyway. If things turn out to be a deadend, you still got that RTT option going for you.
Good luck and keep us updated.
CrazyEddie: "I don't like GUIs"

icetea
Just popping in
Just popping in
Posts: 11
Joined: Thu Sep 25, 2014 11:10

Re: Custom RTT Widget in CEGUI with Ogre renderer

Postby icetea » Thu Nov 13, 2014 19:47

As expected, RTT isn't really performing well, so we had to try something else. Our new solution, which works quite well for us, is not RTT related anymore. We thought it's not a bad idea to share it, because there might be someone else, who got the same or a similar issue.
The code provided here is taken straight from our project minus a few cuts here and there to get rid of any dependencies you won't have. It won't work out of the box, but it shouldn't be too hard create a working example out of it.

Code: Select all

class SceneNodeWidget : public CEGUI::Window
{
public:
   static const CEGUI::String EventNamespace;            //!< Namespace for global events
    static const CEGUI::String WidgetTypeName;             //!< Window factory name

    SceneNodeWidget(const CEGUI::String& type, const CEGUI::String& name);
   virtual ~SceneNodeWidget();

   void setSceneNode(Ogre::SceneNode& sceneNode, Ogre::Camera& camera);

   void setDragingEnabled(bool enabled);

   bool isDragingEnabled() const;

protected:
   void onSized(CEGUI::ElementEventArgs& e);

   void onMoved(CEGUI::ElementEventArgs& e);

   void onMouseMove(CEGUI::MouseEventArgs& e);

   void onMouseButtonDown(CEGUI::MouseEventArgs& e);

   void onMouseButtonUp(CEGUI::MouseEventArgs& e);

   void _updatePosition();

private:
   bool mDragingEnabled;
   bool mBeingDraged;
   CEGUI::Vector2f mDragPoint;

   Ogre::SceneNode* mRefSceneNode;
   Ogre::Camera* mRefCamera;
};


Code: Select all

const CEGUI::String SceneNodeWidget::EventNamespace("SceneNode");
const CEGUI::String SceneNodeWidget::WidgetTypeName("SceneNode");             //!< Window factory name

SceneNodeWidget::SceneNodeWidget(const CEGUI::String& type, const CEGUI::String& name) :
   CEGUI::Window(type, name)
{
   this->mDragingEnabled = false;
   this->mBeingDraged = false;

   this->mRefSceneNode = NULL;
   this->mRefCamera = NULL;
}

SceneNodeWidget::~SceneNodeWidget()
{
   this->mRefSceneNode = NULL;
   this->mRefCamera = NULL;
}

void SceneNodeWidget::setSceneNode(Ogre::SceneNode& sceneNode, Ogre::Camera& camera)
{
   this->mRefSceneNode = &sceneNode;
   this->mRefCamera = &camera;

   this->_updatePosition();
}

void SceneNodeWidget::setDragingEnabled(bool enabled)
{
   this->mDragingEnabled = enabled;
}

bool SceneNodeWidget::isDragingEnabled() const
{
   return this->mDragingEnabled;
}

// ------------------------------------------------------------------------------------

void SceneNodeWidget::onSized(CEGUI::ElementEventArgs& e)
{
   this->Window::onSized(e);
   this->_updatePosition();
   ++e.handled;
}

void SceneNodeWidget::onMoved(CEGUI::ElementEventArgs& e)
{
   this->Window::onMoved(e);
   this->_updatePosition();
   ++e.handled;
}

void SceneNodeWidget::onMouseMove(CEGUI::MouseEventArgs& e)
{
   this->Window::onMouseMove(e);

   if (this->mDragingEnabled && this->mBeingDraged)
   {
      CEGUI::Vector2f localMousePos(CEGUI::CoordConverter::screenToWindow(*this, e.position));

      // calculate sizing deltas...
      float   deltaX = localMousePos.d_x - this->mDragPoint.d_x;
      float   deltaY = localMousePos.d_y - this->mDragPoint.d_y;

      CEGUI::UVector2 mouseMoveOffset(cegui_absdim(deltaX), cegui_absdim(deltaY));
      this->setPosition(this->getPosition() + mouseMoveOffset);
   }

   ++e.handled;
}

void SceneNodeWidget::onMouseButtonDown(CEGUI::MouseEventArgs& e)
{
   this->Window::onMouseButtonDown(e);

   if ((e.button == CEGUI::LeftButton) && this->mDragingEnabled)
   {
      // ensure all inputs come to us for now
      if (this->captureInput())
      {
         // get position of mouse as co-ordinates local to this window.
         CEGUI::Vector2f localPos(CEGUI::CoordConverter::screenToWindow(*this, e.position));

         this->mBeingDraged = true;
         this->mDragPoint = localPos;
         ++e.handled;
      }
   }
}

void SceneNodeWidget::onMouseButtonUp(CEGUI::MouseEventArgs& e)
{
   this->Window::onMouseButtonUp(e);

   if (e.button == CEGUI::LeftButton && this->isCapturedByThis() && this->mDragingEnabled)
   {
      // release our capture on the input data
      this->releaseInput();
      this->mBeingDraged = false;
      ++e.handled;
   }
}

void SceneNodeWidget::_updatePosition()
{
   if (this->mRefCamera != NULL &&
      this->mRefSceneNode != NULL)
   {
      CEGUI::Vector2f vecPosCentered = CEGUIUtils::getAbsoluteScreenPosCenterOfWindow(this);

      CEGUI::Sizef rootWindowSize = this->getRootWindow()->getPixelSize();
      Ogre::Vector3 posWorld = OgreUtils::screenPos2DToWorldSpace3D(   (Ogre::Real) vecPosCentered.d_x,
                                                                     (Ogre::Real) vecPosCentered.d_y,
                                                                     this->mRefSceneNode->getPosition().z,
                                                                     (Ogre::Real) rootWindowSize.d_width,
                                                                     (Ogre::Real) rootWindowSize.d_height,
                                                                     *this->mRefCamera);

      this->mRefSceneNode->setPosition(posWorld);
   }
}


Code: Select all

CEGUI::Vector2f CEGUIUtils::getAbsoluteScreenPosTopLeftCornerOfWindow(const CEGUI::Window* window)
{
   CEGUI::Vector2f vec(0.0f, 0.0f);

   do
   {
      const CEGUI::Sizef& pixelSize = window->getPixelSize();
      const CEGUI::UVector2& pixelPos = window->getPosition();

      float halOffset = 0.0f;
      float valOffset = 0.0f;

      if (window->getParent() != NULL)
      {
         // if we got a parent, we have to checkout the alignment to it
         const CEGUI::Sizef& parentPixelSize = window->getParent()->getPixelSize();

         CEGUI::HorizontalAlignment hal = window->getHorizontalAlignment();
         CEGUI::VerticalAlignment val = window->getVerticalAlignment();

         switch (hal)
         {
            case CEGUI::HA_LEFT:
               halOffset = 0.0f; break;
            case CEGUI::HA_CENTRE:
               halOffset = (parentPixelSize.d_width / 2) - (pixelSize.d_width / 2); break;
            case CEGUI::HA_RIGHT:
               halOffset = parentPixelSize.d_width - pixelSize.d_width;
         }

         switch (val)
         {
            case CEGUI::VA_TOP:
               valOffset = 0.0f; break;
            case CEGUI::VA_CENTRE:
               valOffset = (parentPixelSize.d_height / 2) - (pixelSize.d_height / 2); break;
            case CEGUI::VA_BOTTOM:
               valOffset = parentPixelSize.d_height - pixelSize.d_height; break;
         }
      }

      vec.d_x += pixelSize.d_width * pixelPos.d_x.d_scale + pixelPos.d_x.d_offset + halOffset;
      vec.d_y += pixelSize.d_height * pixelPos.d_y.d_scale + pixelPos.d_y.d_offset + valOffset;

      window = window->getParent();
   }
   while (window);

   return vec;
}

CEGUI::Vector2f CEGUIUtils::getAbsoluteScreenPosCenterOfWindow(const CEGUI::Window* window)
{
   CEGUI::Vector2f pos = CEGUIUtils::getAbsoluteScreenPosTopLeftCornerOfWindow(window);
   CEGUI::Sizef pixelSize = window->getPixelSize();
   return CEGUI::Vector2f(pos.d_x + pixelSize.d_width / 2, pos.d_y + pixelSize.d_height / 2);
}



Ogre::Vector3 OgreUtils::screenPos2DToWorldSpace3D(Ogre::Real x, Ogre::Real y, Ogre::Real targetZDepth, Ogre::Real screenSizeX, Ogre::Real screenSizeY, const Ogre::Camera& camera)
{
   return OgreUtils::screenPos2DRelativeToWorldSpace3D(x / screenSizeX, y / screenSizeY, targetZDepth, camera);
}

Ogre::Vector3 OgreUtils::screenPos2DRelativeToWorldSpace3D(Ogre::Real x, Ogre::Real y, Ogre::Real targetZDepth, const Ogre::Camera& camera)
{
    Ogre::Ray ray = camera.getCameraToViewportRay(x, y);
    Ogre::Vector3 pos = ray.getPoint(2.0f * (abs((camera.getPosition().z - targetZDepth)) - camera.getNearClipDistance()));

    pos.z = targetZDepth;

    return pos;
}


So the basic idea is to leave the rendering to Ogre and just convert the screen position (of the mouse for example) to the position in world space of the scene for the object there. It's not a 100% perfect yet, but it's working fine for now...so we can take care of other things first, before we come back at this (and we also got confirmation that CEGUI does what we need it to do :D). The position on screen is not a 100% perfectly transformed to world space yet. We suppose there is still something not perfectly set up with the camera we are using to view the object in the scene. So we still have to look into that more in depth later.
Though any inputs on this is welcome to further improve this.


Return to “Modifications / Integrations / Customisations”

Who is online

Users browsing this forum: No registered users and 7 guests