The documentation confused me quite a bit and I scratched everything up until that point.
My findings so far, cause I don't want to make the next guy wonder about things like I have wondered so many times.
I am currently embedding images into widgets, at runtime, using C++ code, and the OpenGL3 Renderer of CEGUI 8.7 the following way:
First, create a singular, empty "CEGUI::BasicImage", which acts as a Texture Atlas entry (a region of a big Texture) to a separate CEGUI Texture.
Code: Select all
CEGUI::BasicImage * reserveImage(std::string name)
{
// The ImageManager must be given the type of Image to create, in this case, it is "Basic Image", which is important.
// The second argument is the name CEGUI will use to identify the item.
// If loaded via an imageset, the name would be "TaharezLook/name" for example, it is not needed to add something like 'TaharezLook/'
// in front of the name, as long as the image has a unique name, it will be usable, of course adding a little 'namespace' can help with that.
CEGUI::BasicImage * out = static_cast<CEGUI::BasicImage*>(&CEGUI::ImageManager::getSingleton().create("BasicImage", name));
//To check if the empty Image, lacking any information about UVs or texture dimensions has been created, use the ImageManager
if(!CEGUI::ImageManager::getSingleton().isDefined(name))
{
/* do your error handling code here */
}
return out;
}
Next, an empty CEGUI::OpenGLTexture, which will merely act as a bridge between your own OpenGL texture from your application/game and the CEGUI renderer.
Code: Select all
CEGUI::OpenGLTexture * reserveGlTexture(std::string name, CEGUI::OpenGL3Renderer * renderer)
{
CEGUI::OpenGLTexture * out;
// once again, the texture needs a name, which the CEGUI internals will use as a handle
out = static_cast<CEGUI::OpenGLTexture*>(&renderer->createTexture(name));
return out;
}
These two components, the empty BasicImage and the OpenGLTexture are the key to getting any rectangular region of an already existing, non CEGUI OpenGl Texture into a CEGUI widget.
This is how it is done, in an out of context code, don't just copy and paste it:
Code: Select all
// Put something like this where you are creating and initializing all your Widgets, like your textboxes and whatnot.
CEGUI::BasicImage * myOwnIconImage = reserveImage("myOwnIconImage);
CEGUI::OpenGLTexture * myOwnIconTexture = reserveGlTexture("myOwnIconTexture", m_yourCeguiOgl3Renderer);
//Add the texture to the image, but both are still empty and dumb and useless at this point.
myOwnIconImage->setTexture(myOwnIconTexture);
Now your Image/Texture combo is ready to be filled ingame/application.
Let's say you want to render a tile from your tileset into a StaticText window, this is how you could do it.
Again, don't blindly copy and paste.
Code: Select all
void makeCeguiTextureUseMyOwnGLTexture(std::string nameOfCeguiTexture,Gluint myOwnOGlTextureHandle, CEGUI::Sizef myOwnTextureWidthAndHeight,CEGUI::OpenGL3Renderer * renderer )
{
if(renderer->isTextureDefined(nameOfCeguiTexture))
{
CEGUI::OpenGLTexture * ceguiTexture;
ceguiTexture = static_cast<CEGUI::OpenGLTexture*>(&renderer->getTexture(nameOfCeguiTexture));
ceguiTexture->setOpenGLTexture((GLuint)myOwnOGlTextureHandle,myOwnTextureWidthAndHeight);
}
}
void myGameRenderFunction()
{
//let's say the Tileset Texture Atlas is 800 x 600
//stick it in the GameGl to CEGUI Texture bridge
makeCeguiTextureUseMyOwnGLTexture("myOwnIconTexture",myTilesetOGlTexture,CEGUI::Sizef(800,600),m_yourCeguiOgl3Renderer );
//Now that the CEGUI OpenGLTexture has the handle to the same texture handle you use when you're rendering your tileset with your own logic,
//We will now use the CEGUI::BasicImage to tell CEGUI which region of this texture it should render when we use the BasicImage as an Asset for a CEGUI widget
//Note: This method uses actual pixel dimensions, and not UV ranges from 0 to 1, etc
//We want to render the first image of the Atlas, it's at 0,0 and is 32 pixels wide and high.
myOwnIconImage->setArea(CEGUI::Rectf(0,0,32,32));
//Now let's stringstream it into a static Text widget
//Which we have created elsewhere, if you need an example, TaharezLook has a TaharezLook/StaticText widget, which you can create and cast into a CEGUI::Window*
//We must use the name of "myOwnIconImage", which, in this case is "myOwnIconImage"
std::stringstream ss;
ss << "The current tile is: [image='myOwnIconImage'] \n";
m_yourStaticTextBox->setText(ss.str());
m_yourCeguiOgl3Renderer->beginRendering();
m_yourGuiContextWithTheTextBox->draw();
m_yourCeguiOgl3Renderer->endRendering();
}
I hope this helps a little bit.
The BasicImage and GLTexture, combined, are the star of the show, at least for the OpenGL3 renderer and CEGUI 8.7.
Caveat:
This only works for me for static text boxes, so far. Adding the image as a Button state or the background of a window seems to turn things upside down,but I don't want to think about that right now, I don't want to go to that place again...that dark place.
It seems that inserting your image into a widget via "text tags" ([image='myOwnIconImage]) corrects the "internal BasicImage Area" (aka the texture atlas region it represents) on its own.
(Probably by checking if the height is smaller than the Y position of the region, or something)
Just so anyone reading this knows.
The other ways, by setting them via properties had the textures flipped, so in that case you have to also flip the Basic image area, like in this example, instead of
Code: Select all
myOwnIconImage->setArea(CEGUI::Rectf(0,0,32,32));
You go
Code: Select all
myOwnIconImage->setArea(CEGUI::Rectf(0,32,32,0));
It will then work for, so far, all methods of inserting a picture into a widget..
Blindsided me at first, though, since the stringstreamed version I had was rightside up from the get go, and the other two test windows were upside down, after flipping the area, I expected the strinstreamed version to then be upside down and the others right side up, but, no...all were right side up.
Caveat:
Even if you give CEGUI your own texture by putting the OpenGL handle into an empty CEGUI texture, if you change OpenGL texture handles for the CEGUI texture, the CEGUI texture WILL DELETE THE PREVIOUS OF YOUR OWN OPEN GL TEXTURE THROUGH THE HANDLE YOU GAVE IT BEFORE CHANGING TO THE NEW HANDLE.
So, think ahead and make as many CEGUI textures as you have different own GL textures you plan to hand over to CEGUI through handles.
(Aka, the most resource friendly way since it recycles your own texture by using it directly)
This also confused me for a moment because suddenly everything using the first texture went black, and I had to lay down for a bit to not get a lethal stroke.
I don't know if the new dev version has fixed it, but, 8.7 users ...keep this in mind.
You will have to write your own wrapper/hacky thing around, if you don't want to write an entirely new renderer or texture class just for this single issue.
I went with a class that inherits the CEGUI Gl texture and makes it not clobber the user given GL texture handle, it's very messy and a monkey on theback, but better than having to ship the program with a custom cegui lib...
Although I might go for that in the end.