Load BillboardTextSceneNode from *.irr file

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
Dragonazul
Posts: 24
Joined: Sun Sep 23, 2007 9:45 pm
Location: Spain

Load BillboardTextSceneNode from *.irr file

Post by Dragonazul »

Hi All,

There is any easy way to load a BillboardTextSceneNode from an ".irr" file?

The node is save as:

Code: Select all

<node type="text">

			<attributes>
				<string name="Name" value="" />
				<int name="Id" value="-1" />
				<vector3d name="Position" value="0.000000, 0.000000, 0.000000" />
				<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
				<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
				<bool name="Visible" value="true" />
				<enum name="AutomaticCulling" value="box" />
				<int name="DebugDataVisible" value="0" />
				<bool name="IsDebugObject" value="false" />
			</attributes>

			<materials>
				<attributes>
					<enum name="Type" value="trans_alphach_ref" />
					<color name="Ambient" value="ffffffff" />
					<color name="Diffuse" value="ffffffff" />
					<color name="Emissive" value="00000000" />
					<color name="Specular" value="ffffffff" />
					<float name="Shininess" value="0.000000" />
					<float name="Param1" value="0.500000" />
					<float name="Param2" value="0.000000" />
					<texture name="Texture1" value="fontlucida.png" />
					<texture name="Texture2" value="" />
					<texture name="Texture3" value="" />
					<texture name="Texture4" value="" />
					<bool name="Wireframe" value="false" />
					<bool name="GouraudShading" value="true" />
					<bool name="Lighting" value="false" />
					<bool name="ZWriteEnable" value="false" />
					<int name="ZBuffer" value="0" />
					<bool name="BackfaceCulling" value="false" />
					<bool name="FogEnable" value="false" />
					<bool name="NormalizeNormals" value="false" />
					<bool name="BilinearFilter1" value="true" />
					<bool name="BilinearFilter2" value="true" />
					<bool name="BilinearFilter3" value="true" />
					<bool name="BilinearFilter4" value="true" />
					<bool name="TrilinearFilter1" value="false" />
					<bool name="TrilinearFilter2" value="false" />
					<bool name="TrilinearFilter3" value="false" />
					<bool name="TrilinearFilter4" value="false" />
					<bool name="AnisotropicFilter1" value="false" />
					<bool name="AnisotropicFilter2" value="false" />
					<bool name="AnisotropicFilter3" value="false" />
					<bool name="AnisotropicFilter4" value="false" />
					<enum name="TextureWrap1" value="texture_clamp_repeat" />
					<enum name="TextureWrap2" value="texture_clamp_repeat" />
					<enum name="TextureWrap3" value="texture_clamp_repeat" />
					<enum name="TextureWrap4" value="texture_clamp_repeat" />
				</attributes>
			</materials>

But when it is loaded the loadScene give an error:
Could not create scene node of unknown type: text

Thanks
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

Yeah i don't think there's a factory for text scene nodes unfortunately so the scene manage doesn't know how to load them from .irr files... god knows why when it's a standard irrlicht node!
Image Image Image
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I'm looking at the 1.4.2 sources, and there appears to be some support for the "text" scene node type, but it creates a regular CTextSceneNode, not a CBillboardTextSceneNode. It really looks like someone just forgot to write/test the code to serialize and create either of the scene node types. There is no serializeAttributes() for either type, but there are members that need to be serialized (i.e., Text, Color and Font).

Travis
Last edited by vitek on Sat Dec 27, 2008 7:24 pm, edited 1 time in total.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

The reason you don't get back any scene node is that the IGUIFont* that is being passed to addTextSceneNode() is NULL. A small tweak to CSceneManager::addTextSceneNode() or CDefaultSceneNodeFactory::addSceneNode() could be used to set a default font, but that isn't really the right way to fix it. Something needs to be added to Irrlicht to allow for the font to be serialized. This is something the Irrlicht dev guys will need to decide how to handle.

In the meantime, I have a workaround, provided that you only need to use one font for all of your billboard text scene nodes.

First, to get the scene nodes to serialize their attributes properly, you would need to add code to and recompile the library, but that is easy enough...

Code: Select all

// add the serizeAttributes() and deserializeAttributes() declarations to the types in CTextSceneNode.h

class CTextSceneNode : public ITextSceneNode
{
public:

    //... 

    //! Writes attributes of the scene node.
    virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;

    //! Reads attributes of the scene node.
    virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);

    //... 

};

class CBillboardTextSceneNode : public ITextSceneNode
{
public:

    //... 

    //! Writes attributes of the scene node.
    virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;

    //! Reads attributes of the scene node.
    virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);

    //... 

};

Code: Select all

// add the serizeAttributes() and deserializeAttributes() definitions to CTextSceneNode.cpp

//! Writes attributes of the scene node.
void CTextSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
    ITextSceneNode::serializeAttributes(out, options);

    out->addString("Text", Text.c_str());
    out->addColor ("Color", Color );

    // we have no way to serialize the font at this time
}


//! Reads attributes of the scene node.
void CTextSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
    ITextSceneNode::deserializeAttributes(in, options);

    Text  = in->getAttributeAsStringW( "Text" );
    Color = in->getAttributeAsColor  ( "Color" );

    // we have no way to deserialize the font at this time
}


//! Writes attributes of the scene node.
void CBillboardTextSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
    ITextSceneNode::serializeAttributes(out, options);

    out->addString("Text", Text.c_str());
    out->addColor ("Color", Color );

    out->addColor ("Shade_top", Shade_top);
    out->addColor ("Shade_bottom", Shade_bottom);

    out->addFloat("Width", Size.Width);
    out->addFloat("Height", Size.Height);

    // we have no way to serialize the font at this time
}


//! Reads attributes of the scene node.
void CBillboardTextSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
    ITextSceneNode::deserializeAttributes(in, options);

    Text  = in->getAttributeAsStringW( "Text" );
    Color = in->getAttributeAsColor  ( "Color" );

    Shade_top = in->getAttributeAsColor ( "Shade_top" );
    Shade_bottom = in->getAttributeAsColor ("Shade_bottom" );

    Size.Width = in->getAttributeAsFloat("Width");
    Size.Height = in->getAttributeAsFloat("Height");

    setSize(Size);
    setText(Text.c_str());

    // we have no way to deserialize the font correctly at this time
}
Then rebuild the library. Once you've done that, you just need to write your own scene node factory that can be used to create scene nodes of the appropriate type with the appropriate font.

Code: Select all

class MySceneNodeFactory : public scene::ISceneNodeFactory
{
public:

    MySceneNodeFactory(scene::ISceneManager* mgr, gui::IGUIFont* font)
        : Manager(mgr), Font(font)
    {
        if (Font)
            Font->grab();
    }

    virtual ~MySceneNodeFactory()
    {
        if (Font)
            Font->drop();
    }

    void setDefaultFont(gui::IGUIFont* font)
    {
        if (Font != font) {

            if (Font != 0)
                Font->drop();

            Font = font;

            if (Font != 0)
                Font->grab();
        }
    }

    gui::IGUIFont* getDefaultFont() const
    {
        return Font;
    }

    //! adds a scene node to the scene graph based on its type id
    virtual scene::ISceneNode* addSceneNode(scene::ESCENE_NODE_TYPE type, scene::ISceneNode* parent = 0)
    {
        if (scene::ESNT_TEXT == type) {
            return Manager->addBillboardTextSceneNode(Font, L"", parent);
        }

        return 0;
    }

    //! adds a scene node to the scene graph based on its type name
    virtual scene::ISceneNode* addSceneNode(const c8* typeName, scene::ISceneNode* parent = 0)
    {
        if (!strcmp (typeName, "text")) {
            return Manager->addBillboardTextSceneNode(Font, L"", parent);
        }

        return 0;
    }

    //! returns amount of scene node types this factory is able to create
    virtual u32 getCreatableSceneNodeTypeCount() const
    {
        return 1;
    }

    //! returns type name of a createable scene node type by index
    virtual const c8* getCreateableSceneNodeTypeName(u32 idx) const
    {
        _IRR_DEBUG_BREAK_IF(idx != 0)
        return "text";
    }

    //! returns type of a createable scene node type
    virtual scene::ESCENE_NODE_TYPE getCreateableSceneNodeType(u32 idx) const
    {
        _IRR_DEBUG_BREAK_IF(idx != 0)
        return scene::ESNT_TEXT;
    }

    //! returns type name of a createable scene node type 
    virtual const c8* getCreateableSceneNodeTypeName(scene::ESCENE_NODE_TYPE type) const
    {
        if (scene::ESNT_TEXT == type)
            return "text";

        return 0;
    }

private:

    scene::ISceneManager* Manager;
    gui::IGUIFont* Font;
};
Now just create an instance of the factory, and register it with the scene manager...

Code: Select all

MySceneNodeFactory factory(smgr, gui->getBuiltInFont());
smgr->registerSceneNodeFactory(&factory);
Now you should be able to serialize the billboard text scene nodes without any trouble.

Travis
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

It actually looks like there should be a seperate type for the billboard text scene node. That way the serialization code in the scene manager can know which type of node it needs to create.

The above workaround should work fine until someone decides to fix the text scene node serialization. When that happens you should be able to remove the factory stuff and just rely on Irrlicht to do the right thing. At that point, you may need to modify your serialized .irr files so that the node type string matches what that version of Irrlicht expects them to be.

Travis
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

Moving to bug reports, thanks :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Post Reply