[SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
User avatar
Jayray
Greenskin
Posts: 115
Joined: Sun Sep 09, 2012 5:29 pm
Location: Strasbourg, France
x 9

[SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by Jayray »

Hi all,

I was using the MovableText snippet on OGRE 1.8 and really liked it, so I am trying to port it to OGRE 2.0.
I have managed to make it compile and to create a MovableText object, but it is not displayed in my scene and I cannot figure out why.

As I am not very familiar with the MovableObject class, maybe someone can tell me what I am missing...

So far, the things I had to change to make it "work":

1. Classes derived from MovableObject cannot be created manually any longer, so I had to create a MovableTextFactory and to register it using this code:

Code: Select all

mMovableTextFactory = OGRE_NEW Ogre::MovableTextFactory();
mRoot->addMovableObjectFactory(mMovableTextFactory);
I also had to write a new constructor for the MovableText class and to create my object by this way:

Code: Select all

Ogre::NameValuePairList params;
params["name"] = "TXT_" + mAssociatedObject->getObjectId();
Ogre::MovableText* movableText = static_cast<Ogre::MovableText*>(sceneManager->createMovableObject(Ogre::MovableTextFactory::FACTORY_TYPE_NAME,
																						&sceneManager->_getEntityMemoryManager(Ogre::SCENE_DYNAMIC), &params));
2. The FontManager is now part of the Overlay component, so I had to include the Overlay library and headers and to initialize the OverlaySystem before the resources are loaded using:

Code: Select all

mOverlaySystem = new Ogre::OverlaySystem();
3. It seems that the _notifyCurrentCamera function does not exist any longer, but the camera is now passed as a parameter of the _updateRenderQueue function.


When doing all these things, I can see that my MovableText object is well created and the functions _updateRenderQueue and getWorldTransforms are well called cyclically.
However, nothing appears on screen.
I have also tried implementing the getWorldAabb, getWorldAabbUpdated, getWorldRadius and getWorldRadiusUpdated functions, but none of them is called.

I have attached my current MovableText source files to this post. If someone wants to help me make the MovableText work, it would be greatly appreciated :)
And of course, I would be glad to post an updated version on the Wiki once I get it working (and after some cleaning of the source file ^^).
Attachments
MovableText.zip
(6.17 KiB) Downloaded 165 times
Last edited by Jayray on Thu Mar 26, 2015 8:56 pm, edited 2 times in total.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Porting MovableText to OGRE 2.0

Post by dark_sylinc »

I have also tried implementing the getWorldAabb, getWorldAabbUpdated, getWorldRadius and getWorldRadiusUpdated functions, but none of them is called
These are not virtual so it's futile to implement them.
You must set mLocalAabb and mLocalRadius, otherwise they will always get frustum culled.

This is from Entity's initialization.

Code: Select all

Aabb aabb( mMesh->getBounds().getCenter(), mMesh->getBounds().getHalfSize() );
mObjectData.mLocalAabb->setFromAabb( aabb, mObjectData.mIndex );
mObjectData.mWorldAabb->setFromAabb( aabb, mObjectData.mIndex );
mObjectData.mLocalRadius[mObjectData.mIndex] = aabb.getRadius();
mObjectData.mWorldRadius[mObjectData.mIndex] = aabb.getRadius();
Note that WorldAabb and WorldRadius are updated automatically every frame. The local variations need to be filled in by you.
User avatar
Jayray
Greenskin
Posts: 115
Joined: Sun Sep 09, 2012 5:29 pm
Location: Strasbourg, France
x 9

Re: Porting MovableText to OGRE 2.0

Post by Jayray »

Thanks for your answer!
Unfortunately, I still cannot get the MovableText to draw :(

I have replaced the following lines:

Code: Select all

mAABB = Ogre::AxisAlignedBox(min, max);
mRadius = Ogre::Math::Sqrt(maxSquaredRadius);
By this code:

Code: Select all

Ogre::Aabb aabb = Ogre::Aabb::newFromExtents(min, max);
float radius = Ogre::Math::Sqrt(maxSquaredRadius);
mObjectData.mLocalAabb->setFromAabb(aabb, mObjectData.mIndex);
mObjectData.mWorldAabb->setFromAabb(aabb, mObjectData.mIndex);
mObjectData.mLocalRadius[mObjectData.mIndex] = radius;
mObjectData.mWorldRadius[mObjectData.mIndex] = radius;
To sum up, the steps to draw a custom movable object are:
1. Instanciate the object using a factory
2. Attach it to a scene node (obviously)
3. Define the local AABB and radius once the geometry is set
4. Implement the _updateRenderQueue to add a renderable to the queue
5. Implement the getWorldTransforms function to compute the xform

Is that it?
User avatar
Jayray
Greenskin
Posts: 115
Joined: Sun Sep 09, 2012 5:29 pm
Location: Strasbourg, France
x 9

Re: Porting MovableText to OGRE 2.0

Post by Jayray »

I have done some other tests, and now the local AABB seems correct, but still, nothing appears on screen where the movable texts should be... :cry:

Could anyone give me a hint on how to debug this?
Maybe some points to check that could help me find the issue?

Sorry for my noob questions, but I really do not know where to investigate since I am not familiar with the internal rendering mechanisms... :(
User avatar
Jayray
Greenskin
Posts: 115
Joined: Sun Sep 09, 2012 5:29 pm
Location: Strasbourg, France
x 9

Re: Porting MovableText to OGRE 2.0

Post by Jayray »

I tried porting MovableText to Ogre 2.1 and to use HLMS and... it's working \o/

There is just one thing that is not working: in HLMS Unlit, MovableObject::_getParentNodeFullTransform() is called to retrieve the world matrix instead of Renderdable::getWorldTransforms().
This means that the Renderable cannot override this function to pass a custom world matrix, which is needed in my case to make it face the camera :(

However, I have seen that HLMS Unlit Mobile uses the Renderdable::getWorldTransforms():

Code: Select all

       //const Matrix4 &worldMat = queuedRenderable.movableObject->_getParentNodeFullTransform();
        Matrix4 worldMat;
        assert( queuedRenderable.renderable->getNumWorldTransforms() == 1 );
        queuedRenderable.renderable->getWorldTransforms( &worldMat );
Will MovableObject::_getParentNodeFullTransform() also be replaced by Renderdable::getWorldTransforms() in the HLMS Unlit component?
Or is there a reason why HLMS Unlit has to use MovableObject::_getParentNodeFullTransform()?

Thanks!

PS: I still haven't figured out why MovableText is not working on Ogre 2.0, but now it is almost working on Ogre 2.1 :roll:
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: Porting MovableText to OGRE 2.0

Post by dark_sylinc »

Hi!

I knew some day this question would be raised.

Renderdable::getWorldTransforms is being deprecated. It's still used in v1 legacy rendering mode to avoid breaking code that relied on this behavior.

There are two issues with Renderdable::getWorldTransforms:
  • It's a virtual function being called per object (that also requires another virtual call per object to be called: getNumWorldTransforms). It's only used by PBS Hlms to render v1 skeleton animated objects, because it's the only way to do it (and the cost of the virtual call is amortized by the higher cost of the number of bone matrices & skinning itself)
  • It's not thread safe. In the future the Hlms will be updating all objects from within multiple threads. Thus getWorldTransforms can introduce race conditions depending on what the derived function is doing.
The Mobile versions are a bit old and haven't caught up with the desktop versions (plus the Mobile versions are much more "legacy friendly" at the moment). That's why you see the mobile implementations do rely on Renderable::getWorldTransforms

So, the answer is no, there is no plan to add a user-definable implementation similar to what Renderdable::getWorldTransforms did.

If you want to solve the problem, you can either:
  • Use a workspace listener to update all the MovableText to update their world matrices to face the camera on every pass. There's the problem though that you may end up doing this for MovableText objects that will not rendered in a particular pass.
  • Use a custom Hlms implementation that will calculate the custom world matrix.
  • Wait (no ETA) for user-defined blocks pieces so that you can insert your custom shader code and send a pass-wide rotation matrix that you can use to make each vertex rotate to face the camera.
User avatar
Jayray
Greenskin
Posts: 115
Joined: Sun Sep 09, 2012 5:29 pm
Location: Strasbourg, France
x 9

Re: Porting MovableText to OGRE 2.0

Post by Jayray »

Hi!

Thanks for the explanation!
I will try your solutions and post the update MovableText snippet once I have a working version :)
User avatar
Jayray
Greenskin
Posts: 115
Joined: Sun Sep 09, 2012 5:29 pm
Location: Strasbourg, France
x 9

Re: Porting MovableText to OGRE 2.0 / 2.1

Post by Jayray »

Hi!

Here is the MovableText snippet ported to OGRE 2.1 :D
Unfortunately the snippet is not backwards compatible, but this allowed me to remove all the unused code.
To use it, please have a look at the first post of this topic.

I will try to upload it to the Wiki as well with some instructions if I can.
Attachments
MovableText_Ogre2.1.zip
(6.29 KiB) Downloaded 216 times
User avatar
Kohedlo
Orc
Posts: 435
Joined: Fri Nov 27, 2009 3:34 pm
Location: Ukraine, Sumy
x 32
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by Kohedlo »

ок. i update ogre 2.1 to december 12 bitbucket commit. AFTER ADDING movable text on scene- occour shader compilation- with negative results and lead to crash.

Code: Select all

17:43:54: GLSL compiled: 537067520PixelShader_ps
17:43:54: OpenGL:error(high) 1281: GL_INVALID_VALUE error generated. <index> exceeds the maximum number of vertex attributes.
17:43:54: Vertex Shader: 537067520VertexShader_vs
Fragment Shader: 537067520PixelShader_ps
 GLSL link result : 
17:43:54: Vertex Shader: 537067520VertexShader_vs
Fragment Shader: 537067520PixelShader_ps
 GLSL validation result : 
17:43:54: OpenGL:performance(medium) 131218: Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches.
17:43:54: OpenGL:performance(medium) 131218: Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches.
17:43:54: OpenGL:performance(medium) 131218: Program/shader state performance warning: Fragment Shader is going to be recompiled because the shader key based on GL state mismatches.
17:43:59: GLSL compile log: 1610612736VertexShader_vs
0(6) : error C7566: out blocks require #version 150 or later
0(6) : error C0000: ... or #extension GL_ARB_gpu_shader5 : enable
0(8) : error C0000: syntax error, unexpected '(', expecting "::" at token "("
0(18) : error C7532: global type uint requires "#version 130" or later
0(18) : error C0000: ... or #extension GL_EXT_gpu_shader4 : enable
0(26) : error C0000: syntax error, unexpected '}' at token "}"
0(41) : error C1004: in and out only apply to formal parameters "main"
(0) : error C0000: syntax error, unexpected $end at token "<EOF>"
17:43:59: OGRE EXCEPTION(3:RenderingAPIException): Vertex Program 1610612736VertexShader_vs failed to compile. See compile log above for details. in GLSLShader::compile at ..\..\..\RenderSystems\GL3Plus\src\GLSL\OgreGLSLShader.cpp (line 297)
c++ game developer.
current project: Imperial Game Engine 2.5
Image
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by dark_sylinc »

Could you upload the generated 1610612736VertexShader_vs ?
User avatar
Kohedlo
Orc
Posts: 435
Joined: Fri Nov 27, 2009 3:34 pm
Location: Ukraine, Sumy
x 32
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by Kohedlo »

Could you upload the generated 1610612736VertexShader_vs ?
that is files: https://drive.google.com/file/d/0B-mxhq ... sp=sharing
c++ game developer.
current project: Imperial Game Engine 2.5
Image
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by dark_sylinc »

Ahh, you didn't include the Common datafolder of the Hlms files correctly.

The files are in Samples/Media/Hlms/Common.
You can see GraphicsSystem.cpp includes it:

Code: Select all

Ogre::Archive *archiveLibrary = Ogre::ArchiveManager::getSingletonPtr()->load(
				dataFolder + "Hlms/Common/" + shaderSyntax,
				"FileSystem", true );
Ogre::ArchiveVec library;
library.push_back( archiveLibrary );
Ogre::Archive *archiveUnlit = Ogre::ArchiveManager::getSingletonPtr()->load(
				dataFolder + "Hlms/Unlit/" + shaderSyntax,
				"FileSystem", true );
Ogre::HlmsUnlit *hlmsUnlit = OGRE_NEW Ogre::HlmsUnlit( archiveUnlit, &library );
User avatar
Kohedlo
Orc
Posts: 435
Joined: Fri Nov 27, 2009 3:34 pm
Location: Ukraine, Sumy
x 32
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by Kohedlo »

works,. I simple not see next in deep leavel of logics.
new Ogre::HlmsPbs(archive1 [ pbs folder],&library [ common folder and also]);
c++ game developer.
current project: Imperial Game Engine 2.5
Image
User avatar
Kohedlo
Orc
Posts: 435
Joined: Fri Nov 27, 2009 3:34 pm
Location: Ukraine, Sumy
x 32
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by Kohedlo »

But text backgrount not transparent...

Image
Large
c++ game developer.
current project: Imperial Game Engine 2.5
Image
User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 51
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by SolarPortal »

Hey Guys,
(Note: I am using 2.1 source base)

i was upgrading the MovableText in our engine with the code found on this page and it seems to work quite well apart from a screen edge glitch which i haven't found yet.
Anyway, i found that the Ogre::Font class has an potential bug with the Pixel Format which makes the the colours very strange on the hlms datablock and haven't found a way to remove without modifying source.

To see if it was a change to 2.1, I checked the 1.9 src and noticed a change from "PF_BYTE_LA" to "PF_RGB".

In file: OgreFont.cpp of the Overlay component, i changed:

line 485 from:

Code: Select all

img.loadRawData( memStream, finalWidth, finalHeight, PF_RG8 );
back to:

Code: Select all

img.loadRawData( memStream, finalWidth, finalHeight, PF_BYTE_LA );
and it all works as planned again.

Second) When you go to change color on the movabletext and have gamma correction enabled, remember the color you choose will not be the colour you see.
I got around the problem without modifying source by:

Code: Select all

movableText->setColor(textColor*textColor); // Multiply by itself for a rough match
Thanks and i hope this helps someone :)

Edit: Changed code block as it referenced an incorrect pixel format.
Last edited by SolarPortal on Tue Feb 23, 2016 10:58 pm, edited 1 time in total.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by dark_sylinc »

SolarPortal wrote:Anyway, i found that the Ogre::Font class has an potential bug with the Pixel Format which makes the the colours very strange on the hlms datablock and haven't found a way to remove without modifying source.

To see if it was a change to 2.1, I checked the 1.9 src and noticed a change from "PF_BYTE_LA" to "PF_RGB".

In file: OgreFont.cpp of the Overlay component, i changed:

line 485 from:

Code: Select all

img.loadRawData( memStream, finalWidth, finalHeight, PF_RGB );
back to:

Code: Select all

img.loadRawData( memStream, finalWidth, finalHeight, PF_BYTE_LA );
I remember this issue very well.

It says "PF_RG8", not PF_RGB, at least on my source and the repo's. The problem is that PF_BYTE_LA doesn't really exist in D3D11 so it's a very poor choice of format for that RenderSystem (because we have to emulate it via an RGBA texture, which can also screw your C++ code if you assume it's a 16bpp as the emulated version will be 32bpp). It also didn't work well on old GL drivers from Intel.

If you need the behavior that Red = RGB and Green = Alpha (basically behave like PF_BYTE_LA did in D3D9); use PF_RG8 and then on the Unlit datablock:

Code: Select all

unlitDatablock->setTextureSwizzle( texUnit, R_MASK, R_MASK, R_MASK, G_MASK );
Where texUnit is the texture unit # where the Font texture was set.
User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 51
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by SolarPortal »

sorry my bad, it was PF_RG8 to begin with not PF_RGB ( :oops: ) and the texture swizzle was already in place in code as you say but it turns out like the image in kolhedo's post.
I will have a look into this again :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by dark_sylinc »

SolarPortal wrote:sorry my bad, it was PF_RG8 to begin with not PF_RGB ( :oops: ) and the texture swizzle was already in place in code as you say but it turns out like the image in kolhedo's post.
I will have a look into this again :)
Are you sure the swizzle was correctly applied? Because I now remember: Without the swizzle it looks exactly like in Kohedlo's screenshots (Orange text, red background, no transparency).
Best way to check is to only render the text, and check the dumped shaders. The sampling should look like "texture( tex, uv ).xxxy" (GLSL) or "texture.Load( sampler, uv ).xxxy" (HLSL)
User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 51
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by SolarPortal »

yes, i couldn't find out how to render the text alone as i thought it was due to the red being part of the image colour that does not blend with the scene not an overlay as the red should be transparent;
As for the shaders, of what i did find referenced was:

Edit: lol, render it alone in the scene.. dropping the ball today :P

Edit: I removed all the generated shaders and then created the movable text and in the few generated files i found:

Code: Select all

//Load base image
	outColour = texture( textureMaps[0], inPs.uv0.xy ).xyzw;
It seems the swizzle is not being applied.

Edit: I am also using OpenGL. Will try it in DX11. Same Results
Edit: Also tried with Forward3D on/off
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5296
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1278
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by dark_sylinc »

Well... things that could be happening:
  • The swizzle is being reset. Place a data breakpoint on HlmsUnlitDatablock::mTextureSwizzles[1] (not at mTextureSwizzles[0] because it always be kept as R_MASK so it doesn't change)
  • A different datablock is later being applied which doesn't have the swizzle. Place a breakpoint at Renderable::setDatablock. Or a data breakpoint at Renderable::mHlmsDatablock
  • For some reason this code from OgreHlmsUnlit.cpp is not executing:

    Code: Select all

    for( size_t j=0; j<4; ++j )
    {
    	const size_t swizzleMask = (datablock->mTextureSwizzles[i] >> (6u - j*2u)) & 0x03u;
    	if( swizzleMask == HlmsUnlitDatablock::R_MASK )
    		texSwizzle += "x";
    	else if( swizzleMask == HlmsUnlitDatablock::G_MASK )
    		texSwizzle += "y";
    	else if( swizzleMask == HlmsUnlitDatablock::B_MASK )
    		texSwizzle += "z";
    	else if( swizzleMask == HlmsUnlitDatablock::A_MASK )
    		texSwizzle += "w";
    }
Edit:
I think I know what's going on.

Just like v1::Billboards, v1::Overlays have this design issue where the geometry is created lazily when it's needed. This is a problem because the Hlms needs to analyze the geometry to know what kind of shader we need to generate. This means setDatablock with a pointer will crash if the geometry wasn't generated yet. Therefore you need to set them via name instead and Ogre will later apply it when the geometry has been generated.
You'll see a snippet like this in Ogre's code:

Code: Select all

if( mInitialised && (!mHlmsDatablock || mHlmsDatablock->getName() != mMaterialName) )
{
	HlmsManager *hlmsManager = Root::getSingleton().getHlmsManager();
	Hlms *hlms = hlmsManager->getHlms( HLMS_UNLIT );
	HlmsDatablock *datablock = hlms->getDatablock( mMaterialName );
	this->setDatablock( datablock );
}
In other words, you may be calling setDatablock by pointer, for some reason it didn't crash; but you never called setMaterialName to set mMaterialName to the name of the Unlit datablock. Thus it overrides your datablock. Solution is to use setMaterialName. This is a nasty heritage from Ogre 1.x that can bite you in the ass the first time until you get used to that one.
User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 51
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by SolarPortal »

thanks for that information. I will check on it tomorrow and get back to you :)

Edit: Just thought to have one last go and Solved!
I had to apply the swizzle inside the MovableText.cpp where the datablock was being created.
I believe as you said it is being overwritten.

Here is the new setFontName function of the MovableText.cpp

Code: Select all

 
void MovableText::setFontName(const String &fontName)
{
    String hlmsDatablockName = mName + "Datablock";
	
	HlmsDatablock* currentDatablock = Root::getSingletonPtr()->getHlmsManager()->getDatablockNoDefault(hlmsDatablockName);
	if(currentDatablock != NULL) 
    { 
		currentDatablock->getCreator()->destroyDatablock(currentDatablock->getName());
    }
 
    if (mFontName != fontName || mpHlmsDatablock == NULL || !mpFont)
    {
        mFontName = fontName;
 
        mpFont = (Font *)FontManager::getSingleton().getByName(mFontName).getPointer();
        if (!mpFont)
            throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + fontName, "MovableText::setFontName");
 
        mpFont->load();
        if (mpHlmsDatablock != NULL)
        {
			mpHlmsDatablock->getCreator()->destroyDatablock(mpHlmsDatablock->getName());
            mpHlmsDatablock = NULL;
        }
 
		// Get font HLMS datablock
		HlmsDatablock* fontDatablock = mpFont->getHlmsDatablock();

		// Create a datablock for the MovableText
        const HlmsBlendblock* hlmsBlendblock = Root::getSingleton().getHlmsManager()->getBlendblock(*fontDatablock->getBlendblock());

		mpHlmsDatablock = fontDatablock->getCreator()->createDatablock(hlmsDatablockName,
																		hlmsDatablockName,
																		HlmsMacroblock(),
																		*hlmsBlendblock,
																		HlmsParamVec(),
																		false);

		reinterpret_cast<HlmsUnlitDatablock*>(mpHlmsDatablock)->setTexture(0, 0, reinterpret_cast<HlmsUnlitDatablock*>(fontDatablock)->getTexture(0));
		
		//Need to reset swizzle here or it will be broken colouring.
		reinterpret_cast<HlmsUnlitDatablock*>(mpHlmsDatablock)->setTextureSwizzle(0, HlmsUnlitDatablock::R_MASK, HlmsUnlitDatablock::R_MASK,
			HlmsUnlitDatablock::R_MASK, HlmsUnlitDatablock::G_MASK);

		_updateHlmsMacroblock();
							
        mNeedUpdate = true;
    }
}
Thanks again :D
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk
User avatar
Kohedlo
Orc
Posts: 435
Joined: Fri Nov 27, 2009 3:34 pm
Location: Ukraine, Sumy
x 32
Contact:

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by Kohedlo »

there is no transparent background as on screen. how to slowe,?
c++ game developer.
current project: Imperial Game Engine 2.5
Image
gabbsson
Halfling
Posts: 65
Joined: Wed Aug 08, 2018 9:03 am
x 13

Re: [SOLVED] Porting MovableText to OGRE 2.0 / 2.1

Post by gabbsson »

Hello!

I've been using the MovableText created in this thread and it works great!

As a challenge (and perhaps future proofing?) I wanted to update it to not rely on any v1 objects.
Currently it uses the v1::RenderOperation to generate planes for each letter and so on and I would like to swap that out for the Vao method, as in the DynamicMesh sample.

I've swapped out the code in the SetupGeometry function but I'm getting a segfault in the addRenderableVX functions.
I say X because by default it ends up in the V1 renderqueue, I can't seem to find what decides this?
When I set the renderqueuegroup in the constructor to a V2 queue it ends up in addRenderableV2 but still segfaults.
I tested just returning immediately in the setupGeometry function (in other words not mess with any buffers and so on) but it still segfaults.
The callstack simply ends in addRenderableV2 (or addRenderableV1) which I find odd since they just call addRenderable in turn.

I've used Ogre::Item and Ogre::SubItem as examples (since it's almost the same anyway). It still inherits Ogre::MovableObject and Ogre::Renderable.
Adds itself to its mRenderables and adds the generated vao to mVaoPerLod for shadow and normal, like SubItem does with the mesh.

I'm not really sure what I need to post here to diagnose this. Is there some checklist of things I need to fulfill to create a custom V2 MovableObject?

I realize its been three years but thanks a ton for the updated MovableText! If my attempt is in vain I'll just keep using the one posted here.

Here's the updated setupGeometry (note it is not cleaned up at all, I'm sure it can still be improved greatly):

Code: Select all

void MovableText::setupGeometry()
{
    assert(ogreFont_);
    assert(ogreHlmsDatablock_);

    mVaoPerLod[Ogre::VpNormal].clear();
    mVaoPerLod[Ogre::VpShadow].clear();

    Ogre::RenderSystem* renderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem();
    Ogre::VaoManager* vaoManager = renderSystem->getVaoManager();
    Ogre::OperationType opType = Ogre::OT_TRIANGLE_LIST;

    if (vertices_ != nullptr)
    {
        OGRE_FREE_SIMD(vertices_, Ogre::MEMCATEGORY_GEOMETRY);
        vertices_ = nullptr;
    }
    if (indices_ != nullptr)
    {
        OGRE_FREE_SIMD(indices_, Ogre::MEMCATEGORY_GEOMETRY);
        indices_ = nullptr;
    }
    if (vao_ != nullptr)
    {
        vaoManager->destroyVertexArrayObject(vao_);
        vao_ = nullptr;
    }
    if (vertexBuffer_ != nullptr)
    {
        vaoManager->destroyVertexBuffer(vertexBuffer_);
        vertexBuffer_  = nullptr;
    }

    if (indexBuffer_ != nullptr)
    {
        vaoManager->destroyIndexBuffer(indexBuffer_);
        indexBuffer_ = nullptr;
    }

    //Vertex declaration
    Ogre::VertexElement2Vec vertexElements;
    vertexElements.push_back(Ogre::VertexElement2(Ogre::VET_FLOAT3, Ogre::VES_POSITION));
    vertexElements.push_back(Ogre::VertexElement2(Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES));


    std::vector<SimpleVertex> verticesVector;

    float largestWidth = 0;
    float left = UV_MIN;
    float top = UV_MAX * normalizedFontSize_;

    Ogre::Real spaceWidth = spaceWidth_;

    // Derive space width from a capital A
    if (spaceWidth <= 0) spaceWidth = ogreFont_->getGlyphAspectRatio('A')*normalizedFontSize_*1.0f;

    // for calculation of AABB
    Ogre::Vector3 min = Ogre::Vector3(0,0,0);
    Ogre::Vector3 max = Ogre::Vector3(1,1,1);
    Ogre::Vector3 currPos;
    float maxSquaredRadius = 0.0f;
    bool first = true;

    // Use iterator
    Ogre::String::iterator i, iend;
    iend = caption_.end();
    bool newLine = true;
    Ogre::Real len = 0.0f;

    Ogre::Real verticalOffset = 0;
    switch (verticalAlignment_)
    {
    case VerticalAlignment::ABOVE:
        verticalOffset = -(1.0f/5.0f) * normalizedFontSize_;
        break;
    case VerticalAlignment::CENTER:
        verticalOffset = -(1.0f/2.0f) * normalizedFontSize_;
        break;
    case VerticalAlignment::BELOW:
        verticalOffset = -(4.0f/5.0f) * normalizedFontSize_;
        break;
    }
    // Raise the first line of the caption
    top += verticalOffset;
    for (i = caption_.begin(); i != iend; ++i)
    {
        if (*i == '\n') top += verticalOffset*UV_RANGE;
    }

    for (i = caption_.begin(); i != iend; ++i)
    {
        if (newLine)
        {
            len = 0.0f;
            for (Ogre::String::iterator j = i; j != iend && *j != '\n'; j++)
            {
                if (*j == ' ') len += spaceWidth;
                else len += ogreFont_->getGlyphAspectRatio(static_cast<unsigned char>(*j))*normalizedFontSize_*UV_RANGE;
            }
            newLine = false;
        }

        if (*i == '\n')
        {
            left = UV_MIN;
            top -= normalizedFontSize_*UV_RANGE;
            newLine = true;
            continue;
        }

        if (*i == ' ')
        {
            // Just leave a gap, no tris
            left += spaceWidth;
            continue;
        }

        Ogre::Real horiz_height = ogreFont_->getGlyphAspectRatio(static_cast<unsigned char>(*i));
        Ogre::Real u1, u2, v1, v2;
        Ogre::Font::UVRect utmp;
        utmp = ogreFont_->getGlyphTexCoords(static_cast<unsigned char>(*i));
        u1 = utmp.left;
        u2 = utmp.right;
        v1 = utmp.top;
        v2 = utmp.bottom;

        // each vert is (x, y, z, u, v)
        //-------------------------------------------------------------------------------------
        // First tri
        //
        // Upper left
        float shiftedLeft = 0;
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) shiftedLeft = left;
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) shiftedLeft = left - len;
        else shiftedLeft = left - len/2;

        verticesVector.push_back(SimpleVertex(shiftedLeft, top, 0, u1, v1));

        // Deal with bounds
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) currPos = Ogre::Vector3(left, top, UV_MIN);
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) currPos = Ogre::Vector3(left - len, top, UV_MIN);
        else currPos = Ogre::Vector3(left - len/2, top, UV_MIN);
        if (first)
        {
            min = max = currPos;
            maxSquaredRadius = currPos.squaredLength();
            first = false;
        }
        else
        {
            min.makeFloor(currPos);
            max.makeCeil(currPos);
            maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
        }

        top -= normalizedFontSize_*UV_RANGE;

        // Bottom left
        shiftedLeft = 0;
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) shiftedLeft = left;
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) shiftedLeft = left - len;
        else shiftedLeft = left - (len / 2);
        verticesVector.push_back(SimpleVertex(shiftedLeft, top, 0, u1, v2));

        // Deal with bounds
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) currPos = Ogre::Vector3(left, top, UV_MIN);
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) currPos = Ogre::Vector3(left - len, top, UV_MIN);
        else currPos = Ogre::Vector3(left - (len/2), top, UV_MIN);
        min.makeFloor(currPos);
        max.makeCeil(currPos);
        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());

        top += normalizedFontSize_*UV_RANGE;
        left += horiz_height * normalizedFontSize_*UV_RANGE;

        // Top right
        shiftedLeft = 0;
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) shiftedLeft = left;
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) shiftedLeft = left - len;
        else shiftedLeft = left - (len / 2);
        verticesVector.push_back(SimpleVertex(shiftedLeft, top, 0, u2, v1));
        //-------------------------------------------------------------------------------------

        // Deal with bounds
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) currPos = Ogre::Vector3(left, top, UV_MIN);
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) currPos = Ogre::Vector3(left - len, top, UV_MIN);
        else currPos = Ogre::Vector3(left - (len/2), top, UV_MIN);
        min.makeFloor(currPos);
        max.makeCeil(currPos);
        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());

        //-------------------------------------------------------------------------------------
        // Second tri
        //
        // Top right (again)

        shiftedLeft = 0;
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) shiftedLeft = left;
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) shiftedLeft = left - len;
        else shiftedLeft = left - (len / 2);
        verticesVector.push_back(SimpleVertex(shiftedLeft, top, 0, u2, v1));

        currPos = Ogre::Vector3(left, top, UV_MIN);
        min.makeFloor(currPos);
        max.makeCeil(currPos);
        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());

        top -= normalizedFontSize_*UV_RANGE;
        left -= horiz_height * normalizedFontSize_*UV_RANGE;

        shiftedLeft = 0;
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) shiftedLeft = left;
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) shiftedLeft = left - len;
        else shiftedLeft = left - (len / 2);
        verticesVector.push_back(SimpleVertex(shiftedLeft, top, 0, u1, v2));

        currPos = Ogre::Vector3(left, top, UV_MIN);
        min.makeFloor(currPos);
        max.makeCeil(currPos);
        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());

        left += horiz_height  * normalizedFontSize_*UV_RANGE;

        // Bottom right
        shiftedLeft = 0;
        if(horizontalAlignment_ == HorizontalAlignment::LEFT) shiftedLeft = left;
        else if(horizontalAlignment_ == HorizontalAlignment::RIGHT) shiftedLeft = left - len;
        else shiftedLeft = left - (len / 2);
        verticesVector.push_back(SimpleVertex(shiftedLeft, top, 0, u2, v2));
        //-------------------------------------------------------------------------------------

        currPos = Ogre::Vector3(left, top, UV_MIN);
        min.makeFloor(currPos);
        max.makeCeil(currPos);
        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());

        // Go back up with top
        top += normalizedFontSize_*UV_RANGE;

        float currentWidth = (left + UV_MAX)/UV_RANGE;
        if (currentWidth > largestWidth) largestWidth = currentWidth;
    }

    if (verticesVector.size() == 0) return;

    size_t vertexCount = static_cast<unsigned int>(verticesVector.size());
    vertices_ = reinterpret_cast<SimpleVertex*>(OGRE_MALLOC_SIMD(sizeof(SimpleVertex)*vertexCount, Ogre::MEMCATEGORY_GEOMETRY));
    std::copy(verticesVector.begin(), verticesVector.end(), vertices_);

    // Create the index and vertex buffers
    try
    {
        //Create the actual vertex buffer.
        vertexBuffer_ = vaoManager->createVertexBuffer(vertexElements,
                                                      vertexCount,
                                                      Ogre::BT_IMMUTABLE,
                                                      vertices_,
                                                      true);
    }
    catch(Ogre::Exception &e)
    {
        OGRE_FREE_SIMD(vertexBuffer_, Ogre::MEMCATEGORY_GEOMETRY);
        vertexBuffer_ = nullptr;
        throw e;
    }

    //Now the Vao. We'll just use one vertex buffer source (multi-source not working yet)
    Ogre::VertexBufferPackedVec vertexBuffers;
    vertexBuffers.push_back(vertexBuffer_);

    Ogre::uint16 indexCount = vertexCount;
    indices_ = reinterpret_cast<Ogre::uint16*>(OGRE_MALLOC_SIMD(sizeof(Ogre::uint16)*indexCount, Ogre::MEMCATEGORY_GEOMETRY));
    for (size_t i = 0; i < indexCount; i++)
    {
        *indices_++ = i*3 + 0;
        *indices_++ = i*3 + 1;
        *indices_++ = i*3 + 2;
    }
    try
    {
        indexBuffer_ = vaoManager->createIndexBuffer(Ogre::IndexBufferPacked::IT_16BIT,
                                                    indexCount,
                                                    Ogre::BT_IMMUTABLE,
                                                    indices_,
                                                    true);
    }
    catch( Ogre::Exception &e )
    {
        // When keepAsShadow = true, the memory will be freed when the index buffer is destroyed.
        // However if for some weird reason there is an exception raised, the memory will
        // not be freed, so it is up to us to do so.
        // The reasons for exceptions are very rare. But we're doing this for correctness.
        OGRE_FREE_SIMD(indexBuffer_, Ogre::MEMCATEGORY_GEOMETRY);
        indexBuffer_ = nullptr;
        throw e;
    }

    vao_ = vaoManager->createVertexArrayObject(vertexBuffers, indexBuffer_, opType);

    // update AABB/Sphere radius
    Ogre::Aabb aabb = Ogre::Aabb::newFromExtents(min, max);
    float radius = Ogre::Math::Sqrt(maxSquaredRadius);
    mObjectData.mLocalAabb->setFromAabb(aabb, mObjectData.mIndex);
    mObjectData.mWorldAabb->setFromAabb(aabb, mObjectData.mIndex);
    mObjectData.mLocalRadius[mObjectData.mIndex] = radius;
    mObjectData.mWorldRadius[mObjectData.mIndex] = radius;

    //Each Vao pushed to the vector refers to an LOD level.
    //Must be in sync with mesh->mLodValues & mesh->mNumLods if you use more than one level
    mVaoPerLod[Ogre::VpNormal].push_back(vao_);

    //Use the same geometry for shadow casting.
    mVaoPerLod[Ogre::VpShadow].push_back(vao_);

    if (updateColors_) this->updateColors();

    needUpdate_ = false;

    this->setDatablock(ogreHlmsDatablock_);
}
EDIT:

I'm dumb, the renderqueueId was being sent in the MovableObject constructor using a default value. I'm pretty sure the problem still remains but at least that answers my question of how the default renderqueue is set.

EDIT2:

Further investigation seems to show that removing "mRenderables.push_back(this)" prevents the segfault.
So is it a terrible idea to use a single class that inherits borth renderable and movable object?
I tried creating two separate objects like Item and SubItem but it still segfaults... It's probably something really simple (just me being bad at C++) but for now I'm a bit stuck.
Post Reply