Irrlicht 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

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Irrlicht Renderer

Postby CrazyEddie » Thu Jul 15, 2004 08:38

Okay, this is not as bad as it first seems :) The Ogre and D3D8.1 Renderers currently written are using the exact same approach for implementation, but this does not mean that all renderers have to (it was just easier for me to to it that way;))

What you need to do is implement two classes, a renderer and a texture. These classes need to provide definitions for some abstract methods in the base classes. If you look in the files include/CEGUIRenderer.h and include/CEGUITexture.h you can see the interface that you need to provide (look for the pure virtual methods).

Now I'll talk a little about the way the rendering actually proceeds. Each window within the system is asked to render itself, this is done using the Image/Imageset system which in turn calls a Renderer based object to queue quads; that is, at this stage nothing is sent to the screen. Once all the windows have done their drawing operations, the Renderer::doRender method is called, which will sort the queued quads into order (required for alpha blending support), and then finally sends the quads to the underlying API or engibe to be drawn. Now, one of the optimisations the system can offer is that if nothing within the Gui has changed, then there is no need for the windows to re-queue the same information, and as such that whole stage is skipped and the previous quad queue is used again. Which leads us to something else, the renderer needs to be able to disable the queueing and send quads directly to the display (this is done with the mouse cursor - so that simply moving the mouse does not trigger a total redraw).

The texture class needs to supply implementations for methods to create textures from files, memory, and empty textures.

It's worth pointing out that obviously these classes can optionally do other things which relate to the underlying engine, for example the Ogre renderer allows you to switch around where the Gui "layer" will appear in the final output and things such as that - these functions are not part of the Gui system itself, but are offered as some extra power to users of that particular engine (various other things are possible also).

So, where do you start? First of all you need to consider how Irrlicht does its rendering, and whether the Gui system (or more correctly, the client code) will need to initiate the call to 'CEGUI::System::renderGUI' (as what happens under direct3D), or whether the engine will handle this itself (like under Ogre). Depending on how things are structured, you'll need to make this call in line with the design ideals of the target engine (I have no idea atm, I haven't looked at Irrlicht :oops:).

I'll now discuss the Renderer a little, so that you know what is going on (this references the Ogre renderer)...

The constructor (actually constructor_impl) basically does two things; it allocates and does any pre-initialisation of resources required for using the engine (in this case sets up a vertex format and allocates a vertex buffer), and then allocates two buffers; one is an array of structs that hold information about queued quads, and the other is an array of pointers to the objects in the other buffer (which is done for fast sorting - quicker to swap two pointers than two objects). I'll just mention that this QuadInfo structure is not actually part of the Gui system, but is an implementation detail - you can use any method you wish for queueing quads.

The addQuad method will do one of two things. If queuing is enabled, some preliminary work is done onthe input data (which is a desination screen area rectangle, a z co-ord (only really needed for quad sorting), a Texture pointer, a source texture co-ordinate rectangle, and a set of diffuse colour values (as a ColourRect)), and the quad is then stored in the next free QuadInfo in the array, and a pointer to that QuadInfo added to the 'pointer array'. If queuing is disabled, basically the same things happen, except that instead of queuing the quad, it is sent directly to the engine for rendering (which is done in an implementation method called renderQuadDirect).

The doRender method performs the actual rendering. First it sorts the quads (which only does anything if the quad list has changed since last time), then it initialises the required settings within the underlying engine, finally it sends the quads to the engine for rendering.

The other required methods offer methods to clear the render list, enable/disable/and check the state of queuing (on or off), and finally methods that create Texture based objects.

Your derived Texture class does not need to do anything special other than be able to load images / copy data from memory, as well as report basic information about itself (size etc). You also need to offer some means for your Renderer class to discover the 'real' texture, though this is an implementation detail.

I hope that this has given at least a little idea as to how things are supposed to work. If you need any help with specific areas, just let me know :D

CE.

User avatar
zola
Quite a regular
Quite a regular
Posts: 48
Joined: Wed Jan 12, 2005 12:06

Irrlicht Renderer

Postby zola » Tue Jul 20, 2004 16:42

Hi CE

I'm playing around with Your GUI in Irrlicht. So far I managed to draw things receive events from mouse and keyboard etc. runs quiet well :-) two thumbs up!!

I have some trouble with setting the initial mouse position. In the CEGUI::System class I haven't found any method to do that. What would be the right way to init the mouse pos?

Any hints are welcome, thanks

Tom

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Irrlicht Renderer

Postby CrazyEddie » Tue Jul 20, 2004 17:37

You need to access the MouseCursor class for this.

Code: Select all

CEGUI::MouseCursor::getSingleton().setPosition(Point(x,y));

or similar will give you what you want.

User avatar
zola
Quite a regular
Quite a regular
Posts: 48
Joined: Wed Jan 12, 2005 12:06

Irrlicht Renderer

Postby zola » Thu Jul 22, 2004 18:48

Hi

I have finished an IrrlichtRenderer. You can download it at http://www.webtracker.ch/jahia/album/thomas/irr/cegui_irrlicht.zip.

There are two projects 'irrrender' ( the renderer) and 'irrtest' a test app (mostly a copy of the demo4 for ogre :wink:

To use the renderer irrlicht must be tweeked a little bit. Take a look at IrrichtRendererDef.h in the renderer sources for some hints what needs to be done.

To compile just place the zip in the cegui_mk2 root folder, unpack and add the projects to the cegui_mk2 solution.

Irrtest is precompiled (using irr-opengl) and comes with all dlls needed to run / at least I hope so ;)

Cheers
Tom

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Irrlicht Renderer

Postby CrazyEddie » Thu Jul 22, 2004 19:25

:shock:

:D Excellent stuff! :D I'm really happy you did this, because it proves the concept that to use the system on a different engine you can reasonably easily write a couple of classes and away you go. And the end result is brilliant - good job.

Now, the question?! Your files say "do whatever you want", but I still must ask whether it's okay to include the renderer as part of the CEGUI system, and if so, should I LGPL it or leave it as do-what-you-want-ware, and also whether you're willing to maintain / support this module?

Whatever your answers - major kudos to you sir!

CE.

User avatar
zola
Quite a regular
Quite a regular
Posts: 48
Joined: Wed Jan 12, 2005 12:06

Irrlicht Renderer

Postby zola » Thu Jul 22, 2004 22:10

Not at all, You're the one who did the invention. I just implemented a few methods. Many thanks to You CrazyEddie.

If You want to include it to the CEGUI system cool, this would be my first contribution to open source then :D
CEGUI is LGPL as I understand, then I think the CEGUI-IrrlichtRenderer should be LGPL as well.

I intend to use the CEGUI system in my projects so I will certainly do my best to keep the renderer up to date with the newest irrlicht version.
(Though I don't reckon it will be much work)

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Irrlicht Renderer

Postby CrazyEddie » Fri Jul 23, 2004 10:15

Cool. :) I'll get this added in over the weekend.

Thanks again,

CE.

User avatar
zola
Quite a regular
Quite a regular
Posts: 48
Joined: Wed Jan 12, 2005 12:06

Irrlicht Renderer

Postby zola » Tue Jul 27, 2004 09:07

Sorry about the unprecise help for integration with irrlicht.
Just to have a complete history here's the answer I gave to brcolow.

If all goes well the changes will only be needed for Irrlicht version 0.6.
If You are fond of CVS then You can export a patched version of irrlicht 0.6 sources at http://www.irrlichtnx.mmdevel.de/ brcolow will maintain the irrlicht changes there. I don't know when the changes are commited but I'd estimate in 1 or 2 days from now.

=========================

In IVideoDriver.h You define the function like this:

Code: Select all

    // IVideoDriver.h
    /*!
          \brief the part of the texture denoted by sourceRect is used as
             texture for the rectangle denoted by destRect.
             clipRect defines a clipping rectangle against which the destRect is clipped.
             colors is an array of four color values colors[1]
             is the color for the upperleft corner of the destination rectangle.
             the order is counter clock wise.
             useAlphaChannelOfTexture tells the method if rendering
             in opaque mode (false) or blended mode (true) is needed.
          \param texture, the texture used for texturing
          \param destRect, the destination rectangle (screen coordinates)
          \param sourceRect, the source rectangle in texture coordinates ( (0,tex_width), (0, textheight) )
          \param colors, 4 colors of the corners of the destRectangle starting at upperleft, ordered counter clock wise
          \param useAlphaChannelOfTexture, true paint in blend mode, false paint in opaque mode
          */
    virtual void draw2DImage(video::ITexture* texture, const core::rect<s32>& destRect, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0, video::SColor* colors=0, bool useAlphaChannelOfTexture=false) = 0;



Then in CVideoNull.h You do the following

Code: Select all

    // CVideoNull.h
    virtual void draw2DImage(video::ITexture* texture, const core::rect<s32>& destRectt, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0, video::SColor* colors=0, bool useAlphaChannelOfTexture=false){ }



and finally in the real driver (in my case opengl) you implement the method with the inteded behaviour



Headerfile

Code: Select all

    //CVideoOpenGL.h
    virtual void draw2DImage(video::ITexture* texture, const core::rect<s32>& destRect,const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect = 0,video::SColor* colors=0, bool useAlphaChannelOfTexture=false);



Implementation:

Code: Select all

    //CVideoOpenGL.cpp
    void CVideoOpenGL::draw2DImage(video::ITexture* texture, const core::rect<s32>& destRect,const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, video::SColor colors[4], bool useAlphaChannelOfTexture)
    {
       if (!texture)
          return;

       core::rect<s32> trgRect=destRect;
       core::rect<s32> srcRect=sourceRect;

       const core::dimension2d<s32> targetSurfaceSize=ScreenSize;

       const core::dimension2d<s32> ss = texture->getOriginalSize();
       float ssw=1.0f/ss.Width;
       float ssh=1.0f/ss.Height;

       core::rect<f32> tcoords;
       tcoords.UpperLeftCorner.X = (((f32)srcRect.UpperLeftCorner.X)+0.5f) * ssw ;
       tcoords.UpperLeftCorner.Y = (((f32)srcRect.UpperLeftCorner.Y)+0.5f) * ssh;
       tcoords.LowerRightCorner.X = (((f32)srcRect.UpperLeftCorner.X +0.5f + (f32)srcRect.getWidth())) * ssw;
       tcoords.LowerRightCorner.Y = (((f32)srcRect.UpperLeftCorner.Y +0.5f + (f32)srcRect.getHeight())) * ssh;

       s32 xPlus = -(ScreenSize.Width>>1);
       f32 xFact = 1.0f / (ScreenSize.Width>>1);

       s32 yPlus = ScreenSize.Height-(ScreenSize.Height>>1);
       f32 yFact = 1.0f / (ScreenSize.Height>>1);

       core::rect<float> npos;
       npos.UpperLeftCorner.X = (f32)(trgRect.UpperLeftCorner.X+xPlus+0.5f) * xFact;
       npos.UpperLeftCorner.Y = (f32)(yPlus-trgRect.UpperLeftCorner.Y+0.5f) * yFact;
       npos.LowerRightCorner.X = (f32)(trgRect.LowerRightCorner.X+xPlus+0.5f) * xFact;
       npos.LowerRightCorner.Y = (f32)(yPlus-trgRect.LowerRightCorner.Y+0.5f) * yFact;

       setTexture(0, texture);   

       if (useAlphaChannelOfTexture)
       {
          setRenderStates2DMode(false, true, true);
       }
       else
          setRenderStates2DMode(false, true, false);

       bool bTempColors=false;
       if(colors==NULL)
       {
          colors=new SColor[4];
          for(int i=0;i<4;i++)colors[i]=SColor(0,255,255,255);
          bTempColors=true;
       }

       glBegin(GL_QUADS);

       glColor4ub(colors[0].getRed(), colors[0].getGreen(), colors[0].getBlue(), colors[0].getAlpha());
       glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
       glVertex2f(npos.UpperLeftCorner.X, npos.UpperLeftCorner.Y);

       glColor4ub(colors[3].getRed(), colors[3].getGreen(), colors[3].getBlue(), colors[3].getAlpha());
       glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
       glVertex2f(npos.LowerRightCorner.X, npos.UpperLeftCorner.Y);

       glColor4ub(colors[2].getRed(), colors[2].getGreen(), colors[2].getBlue(), colors[2].getAlpha());
       glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
       glVertex2f(npos.LowerRightCorner.X, npos.LowerRightCorner.Y);

       glColor4ub(colors[1].getRed(), colors[1].getGreen(), colors[1].getBlue(), colors[1].getAlpha());
       glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
       glVertex2f(npos.UpperLeftCorner.X, npos.LowerRightCorner.Y);

       glEnd();

       if(bTempColors) delete [] colors;
    }




You must also make sure that the textures get painted with alpha blending enabled

Code: Select all

    // CVideoOpenGL.cpp
    void CVideoOpenGL::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel)
    {
       if (CurrentRenderMode != ERM_2D || Transformation3DChanged)
       {
          glMatrixMode(GL_PROJECTION);
          glLoadIdentity();

          glMatrixMode(GL_MODELVIEW);
          glLoadIdentity();

          Transformation3DChanged = false;

          glDisable(GL_DEPTH_TEST);
          glDisable(GL_FOG);
          glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
          glDisable(GL_LIGHTING);

          if (MultiTextureExtension)
             glActiveTextureARB(GL_TEXTURE0_ARB);

          glDisable(GL_TEXTURE_GEN_S);
          glDisable(GL_TEXTURE_GEN_T);

          ClampTexture = false;
       }

       if (texture)
       {
          //GL_NEAREST
          glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

          if (alphaChannel)
          {
             // GL_MODULATE GL_DECAL
             glEnable(GL_BLEND);
             glDisable(GL_ALPHA_TEST);
             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,  GL_MODULATE);
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
             
             //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
             //glDisable(GL_BLEND);
             //glEnable(GL_ALPHA_TEST);
             //glAlphaFunc(GL_GREATER, 0);   
                   
          }
          else
          {
             if (alpha)
             {
                glDisable(GL_ALPHA_TEST);
                glEnable(GL_BLEND);
             }
             else
             {
                glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                glDisable(GL_ALPHA_TEST);
                glDisable(GL_BLEND);
             }
          }

       }
       else
       {
          if (alpha)
          {
             glEnable(GL_BLEND);
             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
             glDisable(GL_ALPHA_TEST);
          }
          else
          {
             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
             glDisable(GL_BLEND);
             glDisable(GL_ALPHA_TEST);
          }
       }

       CurrentRenderMode = ERM_2D;
    }


Return to “Modifications / Integrations / Customisations”

Who is online

Users browsing this forum: No registered users and 17 guests