Skip to main content
History: Ogre overlays using Qt
View published page
Source of version: 1
(current)
__How to draw Ogre overlays using Qt framework 2D drawing functionality__ __The background:__ If you'd like to display 2D graphics over the top of the Ogre rendered 3D output the overlay functionality works nicely. If the overlays are dynamic that introduces the requirement for a 2D drawing library to create the overlays on the fly. In my application I was already using the Qt framework for the user interface. Qt also includes the ability to draw 2D graphics and text using the QPainter class. I found a simple solution to use the Qt framework with Ogre overlays. In my project (the Landefall MMO) I need a "Heads Up Display". I decided to create a single Ogre overlay panel the same size as the render window. I haven't tested it but I believe a single large overlay panel will be faster to render than a number of smaller panels. The panel will have a material with a single texture containing an image of the HUD. The majority of the texture will be transparent so the 3D render window can actually be seen (that's always good). __The solution:__ The Qt framework provides the QPainter class to render on any of a variety of backing stores. If you use a backing store that's an in memory bitmap then you can use QPainter to draw the HUD then paste it into the Ogre overlay panel texture. __Making it smaller and faster:__ This works very well but I wanted to reduce the overhead as much as possible. The QImage documentation reveals that it's possible to draw on an already allocated memory buffer. I found there's an image storage format that's the same in both the Qt QImage and the Ogre pixel buffer code. I locate the pixel buffer already create by Ogre and pass this to QImage as its buffer to store the image. This eliminates the need to convert the image from one format to another and copy the image from the QImage buffer to the Ogre pixel buffer. It uses less memory, less code, and should be faster. __Example code:__ {BOX(title="Setup")}Ogre::Overlay* overlay; Ogre::TexturePtr HudTexture; QImage ImageHudSpeed; // get template image to use used later from the App resource area ImageHudSpeed = QImage( ":images/Hud-Speed.png" );{BOX} {BOX(title="Programmatically create the overlay material:")}// Create the texture HudTexture = Ogre::TextureManager::getSingleton().createManual( "HUDTexture", // name Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, // type width(), height(), // width & height of the render window 0, // number of mipmaps Ogre::PF_A8R8G8B8, // pixel format chosen to match a format Qt can use Ogre::TU_DEFAULT // usage ); // Create a material using the texture Ogre::MaterialPtr HudMaterial = Ogre::MaterialManager::getSingleton().create( "HUDMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); HudMaterial->getTechnique( 0 )->getPass( 0 )->createTextureUnitState( "HUDTexture" ); HudMaterial->getTechnique( 0 )->getPass( 0 )->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );{BOX} {BOX(title="Programmatically create the overlay panel:")}// Create an overlay Ogre::OverlayManager& overlayManager = Ogre::OverlayManager::getSingleton(); overlay = overlayManager.create( "OverlayName" ); // Create a panel Ogre::OverlayContainer* panel = static_cast<Ogre::OverlayContainer*>( overlayManager.createOverlayElement( "Panel", "PanelName" ) ); panel->setPosition( 0.0, 0.0 ); panel->setDimensions( 1.0, 1.0 ); // cover the entire window panel->setMaterialName( "HUDMaterial" ); // Add the panel to the overlay overlay->add2D( panel ); // Show the overlay overlay->show();{BOX} {BOX(title="Update the HUD texture image:")}// Get the pixel buffer Ogre::HardwarePixelBufferSharedPtr pixelBuffer = HudTexture->getBuffer(); // Lock the pixel buffer and get a pixel box pixelBuffer->lock( Ogre::HardwareBuffer::HBL_NORMAL ); // for best performance use HBL_DISCARD! const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); Ogre::uint8* pDest = static_cast<Ogre::uint8*> ( pixelBox.data ); // construct HUD image directly in the texture buffer { // fill to get 100% transparent image // the buffer content is the colors R,G,B,A. Filling with zeros gets a 100% transparent image memset( pDest, 0, HudTexture->getWidth() * HudTexture->getHeight() ); // tell QImage to use OUR buffer and a compatible image buffer format QImage Hud( pDest, HudTexture->getWidth(), HudTexture->getHeight(), QImage::Format_ARGB32 ); // paste in HUD speedometer. I resize the image and offset it by 8 pixels from // the bottom left edge of the render window QPainter painter( &Hud ); uint8_t Offset = 8; uint16_t w = ImageHudSpeed.width() / 2; uint16_t h = ImageHudSpeed.height() / 2; painter.drawImage( QRect( Offset, HudTexture->getHeight() - h - Offset, w, h ), ImageHudSpeed, QRect( 0, 0, ImageHudSpeed.width(), ImageHudSpeed.height() ) ); // do any other drawing you would like here using painter // done painter.end(); } // note the QImage is destroyed. Bad things will happen if you reuse the QImage! // Unlock the pixel buffer pixelBuffer->unlock();{BOX} That's it. Here's an example of my output {img fileId="2131" thumb="y" rel="box[g]"}
Search by Tags
Search Wiki by Freetags
Latest Changes
Compiled API Reference
Overlay Editor
Introduction - JaJDoo Shader Guide - Basics
RT Shader System
RapidXML Dotscene Loader
One Function Ogre
One Function Ogre
...more
Search
Find
Online Users
155 online users
OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username
Password
CapsLock is on.
Remember me (for 1 year)
Log in