How to create rotateable gui text?

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Xeverous
Posts: 11
Joined: Tue Jan 24, 2017 7:25 pm

How to create rotateable gui text?

Post by Xeverous »

As in title. I searched forum, found few threads mentioning iTextSceneNode (will this work for 2d?) and others rendering IGUIStaticText to Texture.
I have also searched IrrExt classes and their's text has no rotation functionality either.

I don't reall know which one to choose and how to do it.

What I want is:
- possible coloring
- rotating
- ability to receive events (by ID I suppose)
- how to connect it to another element (eg be a child node on scene / gui)

I would appreciate any advice and code examples - especially if it should be done by rendering to texture
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to create rotateable gui text?

Post by CuteAlien »

Irrlicht UI does not support that so far. Allowing custom 2d transformation matrix has been on wish-list for a while but always too low priority (sorry). My workaround in a project is to render to a plane (with rendertotexture) and then rotate that plane. I can give you the rough code... (can't give you all as it's part of some more code and structures etc... littly tricky to separate that right now, if there's still strange variables left I probably forgot to modify them right now when copying that stuff).

Code: Select all

 
// irr::scene::SMeshBuffer MeshBuffer; // having that in some header to save the mesh for the plane I'm using
 
// create a simple plane (with uv's going from 0,0 to 1,1)
const irr::f32 eps = irr::core::ROUNDING_ERROR_f32; // epsilon because using uv's 0 and 1 messes up the rendering for unknown reasons
irr::scene::SMeshBuffer* buffer = MeshBuffer;
irr::video::SColor vertCol(255,255,255,255); 
buffer->Vertices.push_back(irr::video::S3DVertex(-0.5f, 0.f, -0.5f, 0.f, 1.f, 0.f, vertCol, eps, 1.f-eps));
buffer->Vertices.push_back(irr::video::S3DVertex(0.5f, 0.f, -0.5f, 0.f, 1.f, 0.f, vertCol, 1.f-eps, 1.f-eps));
buffer->Vertices.push_back(irr::video::S3DVertex(-0.5f, 0.f, 0.5f, 0.f, 1.f, 0.f, vertCol, eps, eps));
buffer->Vertices.push_back(irr::video::S3DVertex(0.5f, 0.f, 0.5f, 0.f, 1.f, 0.f, vertCol, 1.f-eps,  eps));
buffer->Indices.push_back(0);
buffer->Indices.push_back(1);
buffer->Indices.push_back(2);
buffer->Indices.push_back(2);
buffer->Indices.push_back(1);
buffer->Indices.push_back(3);
buffer->recalculateBoundingBox();
 
// Material that allows drawing fonts with transparency
irr::video::SMaterial& material = buffer->getMaterial();
material.MaterialType = irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.BlendOperation = irr::video::EBO_ADD;
material.Lighting = false;
material.BackfaceCulling = false;
 
// your_text is some wchar_t* variable
// Font some IGUIFont*
irr::core::dimension2d<irr::u32> Dimension; // pixels needed for drawing
Dimension = Font->getDimension(your_text);
Dimension.Width += 2;   // otherwise we get black lines from texture-repeat at the sides
Dimension.Height += 2;
 
// draw into rtt's
irr::video::ITexture * rtTex = videoDriver->addRenderTargetTexture(texdim, "rtTxt", irr::video::ECF_A8R8G8B8);
videoDriver->setRenderTarget(rtTex, irr::video::ECBF_COLOR|irr::video::ECBF_DEPTH, irr::video::SColor(0,0,0,0));
 
videoDriver->beginScene(0);
irr::video::SColor fontCol(255, 127, 127, 127);
irr::s32 startX = 1; // don't remember why 1 and not 0... probably should try 0...
irr::s32 startY = 1;
Font->draw(your_text, irr::core::rect<irr::s32>(startX, startY, Dimension.Width, Dimension.Height), fontCol);
videoDriver->endScene();
 
// reset rt
videoDriver->setRenderTarget((irr::video::ITexture *)nullptr, 0);
 
// can't use rt directly as rtt's are reset on resize (if you have no resize of rendertarget in your program you can use rtt's directly I guess)
// But however - idea here is to set your font-text as texture to your plane-mesh
irr::video::IImage * img = videoDriver->createImage (rtTex, irr::core::position2di(0,0), rtTex->getSize());
videoDriver->removeTexture(rtTex);
material.setTexture(0, videoDriver->addTexture("txt", img));
img->drop();
 
// Doesn't help much, but fonts slightly more readable when resizing the plane (todo: real solution needs to scale fonts instead of bitmaps)
material.TextureLayer[0].AnisotropicFilter = true;
material.TextureLayer[0].BilinearFilter = false;
material.TextureLayer[0].TrilinearFilter = false;
 
// You have to do all the above only when text changes
// Rendering then on each frame the usualway for meshes
 
// Transformation obviously depend on where you need the text...so just rough idea...
irr::core::matrix4 trans(some_base_transformation_from_a_scene_node_or_so);
 
irr::core::matrix4 transMat; // relative position to that node
transMat.setTranslation(some_position);
trans *= transMat;
 
irr::core::matrix4 rotMat; // rotation certainly depends on view-angle stuff, here just around y
rotMat.setRotationDegrees(irr::core::vector3df(0.f, RotationAngle, 0.f)); 
trans *= rotMat;
 
irr::f32 nodeScale = 1.f/getScale().X; // play with scale factors, not sure what you need
irr::core::matrix4 scaleMat;    // todo: scale should probably also depend on resolution
scaleMat.setScale(irr::core::vector3df((irr::f32)Dimension.Width*some_scale*nodeScale, 1.f, (irr::f32)Dimension.Height*some_scale*nodeScale));
trans *= scaleMat;
 
// draw it 
trans.setTranslation( trans );
videoDriver->setTransform(irr::video::ETS_WORLD, trans);
videoDriver->setMaterial(MeshBuffer.getMaterial());
videoDriver->drawMeshBuffer(&MeshBuffer);
 
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Xeverous
Posts: 11
Joined: Tue Jan 24, 2017 7:25 pm

Re: How to create rotateable gui text?

Post by Xeverous »

This line

Code: Select all

    // reset rt
    videoDriver->setRenderTarget((irr::video::ITexture *)nullptr, 0);
Is pretty strange for me. While I understand your intent,
why are you trying to convert nullptr (even with old C-like syntax)? This keyword was created
to be implicitly convertibe to any pointer type with a value of 0. There is no point in casting it.

And why do you put 0 when expected type is bool? It's confusing



I'm currently trying to embed your code into mine.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to create rotateable gui text?

Post by CuteAlien »

That line is no longer necessary. I use svn trunk version of Irrlicht when working. And a while ago when we changed the interface for rendertargets we had 2 setRenderTarget functions for a while which both started with pointers (but of different types). So to get the compiler to use the correct one in this case where I have no type (for 0) I had to add a cast (doesn't matter if old-style or other style cast here). But that was a little bit annoying, so we renamed the other function by now to setRenderTargetEx which will be the name for the other function now in Irrlicht 1.9. So that cast can be removed - I just didn't remember I still had it in code. Nice find :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Xeverous
Posts: 11
Joined: Tue Jan 24, 2017 7:25 pm

Re: How to create rotateable gui text?

Post by Xeverous »

I'm having few problems:

1. How should I instantiate MeshBuffer? Just

Code: Select all

irr::scene::SMeshBuffer MeshBuffer
which triggers default ctor?

2.

Code: Select all

irr::core::matrix4 trans(some_base_transformation_from_a_scene_node_or_so);
. How to I get it?
Should I get transformation from my parent-to-be object? Can I construct transformation defaultly?

3.

Code: Select all

irr::core::matrix4 transMat; // relative position to that node
transMat.setTranslation(some_position);
trans *= transMat;
This is a position relative to the parent object, am I right?

4.

Code: Select all

irr::f32 nodeScale = 1.f/getScale().X; // play with scale factors, not sure what you need
irr::core::matrix4 scaleMat;    // todo: scale should probably also depend on resolution
scaleMat.setScale(irr::core::vector3df((irr::f32)Dimension.Width*some_scale*nodeScale, 1.f, (irr::f32)Dimension.Height*some_scale*nodeScale));
trans *= scaleMat;
What is getScale()? My own, RotateableText variable?


Can you provide me minimal, compileable example? My program (with your code) compiles, but I still have black screen
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to create rotateable gui text?

Post by CuteAlien »

Hm, sorry, I just tried copying the parts needed for this. I have this as part of a SceneNode which does a lot more. Wish I could help more, but I dont really have the time to create an extra node & test it right now.

It's probably best to keep SMeshBuffer as pointer not as object (it kinda works when one is careful, but is bad style usually as it's derived from a reference-counted object, I should change that in my code as well).

Tranformations ... in my case I start with the transformation of my node as I use it to put text on top of a certain node.
Basically you have a 3d mesh - so you need a 3d position in the end. For a start don't care too much about text-output - just make sure you get some plane displayed (give it a solid material with some ambient color to make sure you see it). Also a single transformation is sufficient to start with - and maybe some scaling to have it bigger. Maybe take a look at the implementation of CBillboardSceneNode (or CBillboardTextSceneNode) in Irrlicht - they do nearly the same stuff.

Or maybe someone else here can help some more...
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Xeverous
Posts: 11
Joined: Tue Jan 24, 2017 7:25 pm

Re: How to create rotateable gui text?

Post by Xeverous »

t's probably best to keep SMeshBuffer as pointer not as object (it kinda works when one is careful, but is bad style usually as it's derived from a reference-counted object, I should change that in my code as well).
No, it's not. Setting lifetime of variables by scope is the default way. Almost every object should be instantiable by value or created by static method that returns a smart pointer. The problem is that Irrlicht is full of old, deprecated things like inheriting from IReferenceCounted, own string (instead of std::string/wstring), own randomizer (instead of std::default_random_engine), own timer (instead of std::steady_clock), own containers...
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to create rotateable gui text?

Post by CuteAlien »

Somewhat different topic.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: How to create rotateable gui text?

Post by chronologicaldot »

To specifically answer the question: You could create a plane mesh with a texture of the text characters themselves. I forget, but I think the characters are turned into ITexture. Then you rotate the viewport and render it when you render the GUI element it is on.
Post Reply