Results 1 to 4 of 4

Thread: Entity Layouts via XML!!!

  1. #1
    Lesser Wizard
    Join Date
    Nov 2010
    Location
    Los Angeles, California, United States, United States
    Posts
    126

    Default Entity Layouts via XML!!!

    Hello fellow Proton-ites! I'm sharing with you a development I hope you'll find very useful...

    Entity Layouts via XML!!!

    I have modified the RTSimpleApp example to load everything via XML.
    Click here to get the files

    As an example, here is what the MainMenu looks like:
    Code:
    <Entity name="MainMenu">
    
        <!-- AddFocusIfNeeded()-->
        <EntityComponent class="FocusUpdateComponent">
        <EntityComponent class="FocusRenderComponent"> 
        <EntityComponent class="FocusInputComponent">
        <EntityComponent class="CustomInputComponent" keycode="(uint32)500000">
    
        <Entity name="ParticleTest" pos2d="(vec2f)50,40">
            <EntityComponent class="TextRenderComponent" text="Particle Test">
            <EntityComponent class="TouchHandlerComponent">
            <EntityComponent class="Button2DComponent">
        </Entity>
    
        <Entity name="InputTest" pos2d="(vec2f)50,85">
            <EntityComponent class="TextRenderComponent" text="Text Input Test">
            <EntityComponent class="TouchHandlerComponent">
            <EntityComponent class="Button2DComponent">
        </Entity>
    
        <Entity name="TouchTest" pos2d="(vec2f)50,130">
            <EntityComponent class="TextRenderComponent" text="Multitouch Input Test">
            <EntityComponent class="TouchHandlerComponent">
            <EntityComponent class="Button2DComponent">
        </Entity>
    
        <Entity name="Debug" pos2d="(vec2f)50,175">
            <EntityComponent class="TextRenderComponent" text="Debug and music test">
            <EntityComponent class="TouchHandlerComponent">
            <EntityComponent class="Button2DComponent">
        </Entity>
                
        <Entity name="About" pos2d="(vec2f)50,220">
            <EntityComponent class="TextRenderComponent" text="About (scroll bar test)">
            <EntityComponent class="TouchHandlerComponent">
            <EntityComponent class="Button2DComponent">
        </Entity>
    
    </Entity>
    It is loaded like this:
    Code:
    Entity * MainMenuCreate(Entity *pParentEnt)
    {
        CreateXMLLayoutEntity(pParentEnt, GetBaseAppPath() + "interface/MainMenuLayout.xml");
        
        Entity* pBG = pParentEnt->GetEntityByName("MainMenu");
    
    	EntityComponent *pComp = pBG->GetComponentByName("CustomInput");
        pComp->GetFunction("OnActivated")->sig_function.connect(1, boost::bind(&App::OnExitApp, GetApp(), _1));
    
        Entity* pButtonEntity;
        
        pButtonEntity = pBG->GetEntityByName("ParticleTest");
    	pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect);
    
        pButtonEntity = pBG->GetEntityByName("InputTest");
    	pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect);
    
        pButtonEntity = pBG->GetEntityByName("TouchTest");
    	pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect);
    
        pButtonEntity = pBG->GetEntityByName("Debug");
    	pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect);
    
        pButtonEntity = pBG->GetEntityByName("About");
    	pButtonEntity->GetShared()->GetFunction("OnButtonSelected")->sig_function.connect(&MainMenuOnSelect);
    
    	SlideScreen(pBG, true);
    	return pBG;
    }
    I added these functions to EntityUtils.cpp:

    Code:
    //
    //  XML Layout functions
    //
    
    //
    //  Create a specific EntityComponent instance from class name string
    //
    EntityComponent* CreateEntityComponent( string strClassName, EntityComponent* (*CustomComponentClassFunction)(string) )
    {
        if( strClassName == "ArcadeInputComponent" ) return new ArcadeInputComponent();
        else if( strClassName == "Button2DComponent" ) return new Button2DComponent();
        else if( strClassName == "CustomInputComponent" ) return new CustomInputComponent();
        else if( strClassName == "DPadComponent" ) return new DPadComponent();
        else if( strClassName == "EmitVirtualKeyComponent" ) return new EmitVirtualKeyComponent();
        else if( strClassName == "FilterComponent" ) return new FilterComponent();
        else if( strClassName == "FilterInputComponent" ) return new FilterInputComponent();
        else if( strClassName == "FocusInputComponent" ) return new FocusInputComponent();
        else if( strClassName == "FocusRenderComponent" ) return new FocusRenderComponent();
        else if( strClassName == "FocusUpdateComponent" ) return new FocusUpdateComponent();
        else if( strClassName == "HTTPComponent" ) return new HTTPComponent();
        else if( strClassName == "InputTextRenderComponent" ) return new InputTextRenderComponent();
        else if( strClassName == "InterpolateComponent" ) return new InterpolateComponent();
        else if( strClassName == "LogDisplayComponent" ) return new LogDisplayComponent();
        else if( strClassName == "OverlayRenderComponent" ) return new OverlayRenderComponent();
        else if( strClassName == "ProgressBarComponent" ) return new ProgressBarComponent();
        else if( strClassName == "RectRenderComponent" ) return new RectRenderComponent();
        else if( strClassName == "RenderClipComponent" ) return new RenderClipComponent();
        else if( strClassName == "ScrollBarRenderComponent" ) return new ScrollBarRenderComponent();
        else if( strClassName == "ScrollComponent" ) return new ScrollComponent();
        else if( strClassName == "SelectButtonWithCustomInputComponent" ) return new SelectButtonWithCustomInputComponent();
        else if( strClassName == "SliderComponent" ) return new SliderComponent();
        else if( strClassName == "TapSequenceDetectComponent" ) return new TapSequenceDetectComponent();
        else if( strClassName == "TextBoxRenderComponent" ) return new TextBoxRenderComponent();
        else if( strClassName == "TextRenderComponent" ) return new TextRenderComponent();
        else if( strClassName == "TouchDragComponent" ) return new TouchDragComponent();
        else if( strClassName == "TouchHandlerComponent" ) return new TouchHandlerComponent();
        else if( strClassName == "TouchStripComponent" ) return new TouchStripComponent();
        else if( strClassName == "TrailRenderComponent" ) return new TrailRenderComponent();
        else if( strClassName == "TyperComponent" ) return new TyperComponent();
        else if( strClassName == "UnderlineRenderComponent" ) return new UnderlineRenderComponent();
        else if( CustomComponentClassFunction != NULL )
        {
            return CustomComponentClassFunction(strClassName);
        }
        else
            return NULL;
    }
    
    //
    //  parses custom string formats for defining Variant values
    //
    //enum eType
    //{
    //    TYPE_UNUSED,  
    //    TYPE_FLOAT,       = "(float)23.45"
    //    TYPE_STRING,      = "This is a string"
    //    TYPE_VECTOR2,     = "(vec2f)34.5, 23.4444"
    //    TYPE_VECTOR3,     = "(vec3f)3.4, 5.4, 2"
    //    TYPE_UINT32,      = "(uint32)3"
    //    TYPE_ENTITY,      = UNSUPPORTED
    //    TYPE_COMPONENT,   = UNSUPPORTED
    //    TYPE_RECT,        = "(rec2f)3.4, 4.5, 5.4, 3"
    //    TYPE_INT32        = "(int32)234"
    //    
    //};
    void SetVariantFromFormattedString(Variant* pVar, string strVariant)
    {
        //    TYPE_FLOAT,       = "(float)23.45"    
        if( strVariant.substr(0, 7) == "(float)" )
        {
            string strValue = strVariant.substr(7, strVariant.size());
            
            float f = atof(strValue.c_str());
            
            pVar->Set(f);
        }
        //    TYPE_VECTOR2,     = "(vec2f)34.5, 23.4444"
        else if( strVariant.substr(0, 7) == "(vec2f)" )
        {
            string strValues = strVariant.substr(7, strVariant.size());
            
            vector<string> v = StringTokenize(strValues, ",");
            
            string strX = (string)v[0];
            string strY = (string)v[1];
            
            float f1 = atof(strX.c_str());
            float f2 = atof(strY.c_str());
            
            pVar->Set(f1, f2);
        }
        //    TYPE_VECTOR3,     = "(vec3f)3.4, 5.4, 2"
        else if( strVariant.substr(0, 7) == "(vec3f)" )
        {
            string strValues = strVariant.substr(7, strVariant.size());
            
            vector<string> v = StringTokenize(strValues, ",");
            
            string strX = (string)v[0];
            string strY = (string)v[1];
            string strZ = (string)v[3];
            
            float f1 = atof(strX.c_str());
            float f2 = atof(strY.c_str());
            float f3 = atof(strZ.c_str());
            
            pVar->Set(f1, f2, f3);        
        }
        //    TYPE_UINT32,      = "(uint32)3"
        else if( strVariant.substr(0, 8) == "(uint32)" )
        {
            string strValue = strVariant.substr(8, strVariant.size());
            
            uint32 n = atoi(strValue.c_str());
            
            pVar->Set(n);
        }
        //    TYPE_RECT,        = "(rec2f)3.4, 4.5, 5.4, 3"
        else if( strVariant.substr(0, 7) == "(rec2f)" )
        {
            string strValues = strVariant.substr(7, strVariant.size());
            
            vector<string> v = StringTokenize(strValues, ",");
            
            float f1 = atof(((string)v[0]).c_str());
            float f2 = atof(((string)v[1]).c_str());
            float f3 = atof(((string)v[2]).c_str());
            float f4 = atof(((string)v[3]).c_str());
            
            pVar->Set(CL_Rectf(f1, f2, f3, f4));        
        }
        //    TYPE_INT32        = "(int32)234"
        else if( strVariant.substr(0, 7) == "(int32)" )
        {
            string strValue = strVariant.substr(8, strVariant.size());
            
            int32 n = atoi(strValue.c_str());
            
            pVar->Set(n);    
        }
        // it is a string
        else
        {
            pVar->Set(strVariant);
        }
        
        LogMsg("Set Variant %s", pVar->GetString().c_str());
        
    }
    
    //
    //  Recursive function for parsing an Entity or EntityComponent
    //
    void ReadLayoutXML( Entity* pParentEnt, IrrXMLReader* xml, EntityComponent* (*CustomComponentClassFunction)(string))
    {
        while(xml && xml->read())
        {
            switch(xml->getNodeType())
            {
                case EXN_ELEMENT:
                {
                    string strName = xml->getNodeName();
                    
                    if( strName == "Entity" )
                    {
                        //ReadEntityXML(pParentEnt, xml);
                        Entity* pEnt = pParentEnt->AddEntity(new Entity());
                        
                        for( int i=0; i<xml->getAttributeCount(); i++ )
                        {
                            string strName = xml->getAttributeName(i);
                            string strValue = xml->getAttributeValue(i);                        
                            LogMsg("Adding Entity Attribute: %s=%s", strName.c_str(), strValue.c_str());
                            
                            if( strName == "name" )
                            {
                                // special case for name field which isn't actually in the variant db
                                pEnt->SetName(strValue);
                            }
                            else
                            {
                                // sets the variant based on how the value is cast as a string
                                SetVariantFromFormattedString(pEnt->GetVar(strName), strValue);                        
                            }
                        }
                        
                        if( xml->read() )
                        {
                            ReadLayoutXML(pEnt, xml, CustomComponentClassFunction);
                        }
                    }
                    else if( strName == "EntityComponent" )
                    {
                        string strClass = xml->getAttributeValue("class");
                        EntityComponent* pComp = CreateEntityComponent(strClass, CustomComponentClassFunction);
                        
                        pParentEnt->AddComponent(pComp);
                        
                        if( pComp != NULL )
                        {                                   
                            //ReadEntityComponentXML(pParentEnt, xml);  
                            for( int i=0; i<xml->getAttributeCount(); i++ )
                            {
                                string strName = xml->getAttributeName(i);
                                string strValue = xml->getAttributeValue(i);   
                                
                                /*if( strName == "fileName" )
                                {
                                    if( strValue.substr(0, 1) == "./" )
                                        strValue = GetBaseAppPath() + strValue.substr(2, strValue.size());
                                    else
                                        strValue = GetBaseAppPath() + strValue;
                                }*/
                                
                                LogMsg("Adding EntityComponent Attribute: %s=%s", strName.c_str(), strValue.c_str());
                                
                                SetVariantFromFormattedString(pComp->GetVar(strName), strValue);                        
                            }                        
                        }
                    }
                    else
                    {
                        LogError("Unknown Element type: %s", strName.c_str());
                    }
                    
                    break;
                }
                case EXN_CDATA:
                {
                    break;
                }
                case EXN_ELEMENT_END:
                {
                    //break;
                    return;
                }
                case EXN_NONE:
                case EXN_TEXT:
                case EXN_COMMENT:
                case EXN_UNKNOWN:
                {
                    break;
                }
            }
        }
    }
    
    //
    //  Starts parsing XML lauyout file and creates Entities and Entity components within the parent
    //
    void CreateXMLLayoutEntity(Entity* pParentEnt, string strFile, EntityComponent* (*CustomComponentClassFunction)(string))
    {
        // create the reader using one of the factory functions
        //std::string strFile = GetBaseAppPath() + "interface/layout.xml";
        LogMsg("XML FILE: %s", strFile.c_str());                    
        IrrXMLReader* xml = createIrrXMLReader(strFile.c_str());
        
        ReadLayoutXML(pParentEnt, xml, CustomComponentClassFunction);
        
        // delete the xml parser after usage
        delete xml;
    }

  2. #2
    Lesser Wizard
    Join Date
    Nov 2010
    Location
    Los Angeles, California, United States, United States
    Posts
    126

    Default

    BTW, I would love to contribute more of this directly to a dev branch if you're willing to open this up. Let's go open source!

    ideas for updates:
    * setting forced resolutions from any Entity
    * percent values for sizes and positions (i.e. size2d="(vec2f)80%,70%")
    * better support for existing enum values
    * a GUI layout tool written in Proton!!!
    * HTML5 converter
    * basic scripting, source code generators

  3. #3
    Administrator Seth's Avatar
    Join Date
    Jul 2002
    Location
    Japan
    Posts
    5,340

    Default

    Nice work BigB,

    Sure, I can give you write access to the svn, but only one serious rule.. a requirement is that any changes that break existing builds must be talked about first - otherwise all examples on all platforms must be tweaked and tested (plus my 10 or so private projects) and that's best avoided when at all possible!!

    Your changes use Irrlicht's XML right? I don't want that to be a requirement for the other examples, so what if we remove your functions from EntityUtils.* and create a .. XMLLayoutUtils.h instead?

    Then apps that need it can include it and the irrlicht xml stuff only if needed. The shared code could go in shared/addons/XMLLayout, and the example could go in /addons/XMLLayout. I've been using this addon dir already for some new iPhone joystick-addon code.

    Do you IRC at all? I hang out all day so it might be nice to chat about stuff when needed.. can find me in #clanlib on irc.freenode.net as SethR.
    Seth A. Robinson
    Robinson Technologies

  4. #4
    Lesser Wizard
    Join Date
    Nov 2010
    Location
    Los Angeles, California, United States, United States
    Posts
    126

    Default

    I'll find you on IRC (just joined as BigBMan.) I agree with your conditions , but I think setting up a dev branch might be our best bet.

    ... and what about setting this up on GitHub or Google code?

Similar Threads

  1. Creating Entity on different map
    By kehran in forum Novashell Game Creation System
    Replies: 2
    Last Post: 07-19-2011, 02:04 AM
  2. SetFont() method for Entity text
    By garcia in forum Novashell Game Creation System
    Replies: 3
    Last Post: 12-08-2010, 05:51 AM
  3. What I would need to do to implement a new entity type or something?
    By speeder in forum Novashell Game Creation System
    Replies: 1
    Last Post: 08-18-2010, 05:10 AM
  4. How do I make an entity face a certain direction?
    By Jeral in forum Novashell Game Creation System
    Replies: 2
    Last Post: 12-14-2008, 07:44 PM
  5. Problem with turorial 'convert to entity'
    By hellbound007 in forum Novashell Game Creation System
    Replies: 2
    Last Post: 05-30-2008, 12:58 PM

Bookmarks

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •