Browse Source

Resolved Conflicts:
engine/source/2d/scene/Scene.cc

capnlove 12 years ago
parent
commit
cf538f0

+ 21 - 12
engine/source/2d/core/SpriteBatch.cc

@@ -34,6 +34,10 @@
 
 //------------------------------------------------------------------------------
 
+static StringTableEntry spritesNodeName = StringTable->insert( "Sprites" );
+
+//------------------------------------------------------------------------------
+
 SpriteBatch::SpriteBatch() :
     mMasterBatchId( 0 ),
     mSelectedSprite( NULL ),
@@ -1232,34 +1236,39 @@ void SpriteBatch::destroySpriteBatchQuery( void )
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::onTamlCustomWrite( TamlCustomNode* pSpritesNode )
+void SpriteBatch::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomWrite);
 
-    // Fetch property names.
-    StringTableEntry spriteItemTypeName = StringTable->insert( "Sprite" );
+    // Finish if no sprites.
+    if ( getSpriteCount() == 0 )
+        return;
+
+    // Add sprites node.
+    TamlCustomNode* pSpritesNode = customNodes.addNode( spritesNodeName );
 
     // Write all sprites.
     for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
-    {
-        // Add sprite node.
-        TamlCustomNode* pNode = pSpritesNode->addNode( spriteItemTypeName );
-        
+    {      
         // Write type with sprite item.
-        spriteItr->value->onTamlCustomWrite( pNode );
+        spriteItr->value->onTamlCustomWrite( pSpritesNode );
     }
 }
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
+void SpriteBatch::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomRead);
 
-    // Fetch node name.
-    StringTableEntry spriteItemNodeName = StringTable->insert( "Sprite" );
+    // Find sprites custom node.
+    const TamlCustomNode* pSpritesNode = customNodes.findNode( spritesNodeName );
+
+    // Finish if we don't have the node.
+    if ( pSpritesNode == NULL )
+        return;
 
     // Fetch children nodes.
     const TamlCustomNodeVector& spriteNodes = pSpritesNode->getChildren();
@@ -1274,7 +1283,7 @@ void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
         StringTableEntry nodeName = pNode->getNodeName();
 
         // Is this a known node name?
-        if ( nodeName != spriteItemNodeName )
+        if ( nodeName != spritesItemTypeName )
         {
             // No, so warn.
             Con::warnf( "SpriteBatch - Unknown custom type '%s'.", nodeName );

+ 2 - 2
engine/source/2d/core/SpriteBatch.h

@@ -193,8 +193,8 @@ protected:
     void createSpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );
 
-    void onTamlCustomWrite( TamlCustomNode* pSpritesNode );
-    void onTamlCustomRead( const TamlCustomNode* pSpritesNode );
+    void onTamlCustomWrite( TamlCustomNodes& customNodes  );
+    void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 private:
     bool destroySprite( const U32 batchId );

+ 6 - 1
engine/source/2d/core/SpriteBatchItem.cc

@@ -34,6 +34,8 @@
 
 //-----------------------------------------------------------------------------
 
+StringTableEntry spritesItemTypeName                = StringTable->insert( "Sprite" );
+
 static StringTableEntry spriteNameName              = StringTable->insert("Name");
 static StringTableEntry spriteLogicalPositionName   = StringTable->insert("LogicalPosition");
 static StringTableEntry spriteVisibleName           = StringTable->insert("Visible");
@@ -301,8 +303,11 @@ void SpriteBatchItem::updateWorldTransform( const U32 batchTransformId )
 
 //------------------------------------------------------------------------------
 
-void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
+void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pParentNode )
 {
+    // Add sprite node.
+    TamlCustomNode* pSpriteNode = pParentNode->addNode( spritesItemTypeName );
+
     // Write name.
     if ( getName() != StringTable->EmptyString )
         pSpriteNode->addField( spriteNameName, getName() );

+ 5 - 1
engine/source/2d/core/SpriteBatchItem.h

@@ -34,6 +34,10 @@ class SceneRenderRequest;
 
 //------------------------------------------------------------------------------  
 
+extern StringTableEntry spritesItemTypeName;
+
+//------------------------------------------------------------------------------  
+
 class SpriteBatchItem : public ImageFrameProvider
 {
     friend class SpriteBatch;
@@ -297,7 +301,7 @@ protected:
     void updateLocalTransform( void );
     void updateWorldTransform( const U32 batchTransformId );
 
-    void onTamlCustomWrite( TamlCustomNode* pSpriteNode );
+    void onTamlCustomWrite( TamlCustomNode* pParentNode );
     void onTamlCustomRead( const TamlCustomNode* pSpriteNode );
 };
 

+ 102 - 6
engine/source/2d/scene/Scene.cc

@@ -68,6 +68,10 @@ SimObjectPtr<Scene> Scene::LoadingScene = NULL;
 
 //------------------------------------------------------------------------------
 
+IMPLEMENT_CONOBJECT_CHILDREN(Scene);
+
+//------------------------------------------------------------------------------
+
 static ContactFilter mContactFilter;
 
 // Scene counter.
@@ -97,6 +101,7 @@ static StringTableEntry jointRevoluteMotorMaxTorqueName   = StringTable->insert(
 static StringTableEntry jointWeldNodeName                 = StringTable->insert( "Weld" );
 static StringTableEntry jointWeldFrequencyName            = jointDistanceFrequencyName;
 static StringTableEntry jointWeldDampingRatioName         = jointDistanceDampingRatioName;
+static StringTableEntry jointRevoluteMotorMaxTorqueName;
 
 static StringTableEntry jointWheelNodeName                = StringTable->insert( "Wheel" );
 static StringTableEntry jointWheelWorldAxisName           = StringTable->insert( "WorldAxis" );
@@ -108,6 +113,7 @@ static StringTableEntry jointWheelDampingRatioName        = jointDistanceDamping
 static StringTableEntry jointFrictionNodeName             = StringTable->insert( "Friction" );
 static StringTableEntry jointFrictionMaxForceName         = StringTable->insert( "MaxForce" );
 static StringTableEntry jointFrictionMaxTorqueName        = jointRevoluteMotorMaxTorqueName;
+static StringTableEntry jointWheelDampingRatioName;
 
 static StringTableEntry jointPrismaticNodeName            = StringTable->insert( "Prismatic" );
 static StringTableEntry jointPrismaticWorldAxisName       = jointWheelWorldAxisName;
@@ -132,6 +138,7 @@ static StringTableEntry jointTargetDampingRatioName       = jointDistanceDamping
 static StringTableEntry jointMotorNodeName                = StringTable->insert( "Motor" );
 static StringTableEntry jointMotorLinearOffsetName        = StringTable->insert( "LinearOffset" );
 static StringTableEntry jointMotorAngularOffsetName       = StringTable->insert( "AngularOffset" );
+static StringTableEntry jointTargetNodeName;
 static StringTableEntry jointMotorMaxForceName            = jointFrictionMaxForceName;
 static StringTableEntry jointMotorMaxTorqueName           = jointRevoluteMotorMaxTorqueName;
 static StringTableEntry jointMotorCorrectionFactorName    = StringTable->insert( "CorrectionFactor" );
@@ -172,6 +179,79 @@ Scene::Scene() :
     mRenderCallback(false),
     mSceneIndex(0)
 {
+    // Initialize Taml property names.
+    if ( !tamlPropertiesInitialized )
+    {
+        jointCustomNodeName               = StringTable->insert( "Joints" );
+        jointCollideConnectedName         = StringTable->insert( "CollideConnected" );
+        jointLocalAnchorAName             = StringTable->insert( "LocalAnchorA" );
+        jointLocalAnchorBName             = StringTable->insert( "LocalAnchorB" );
+
+        jointDistanceNodeName             = StringTable->insert( "Distance" );
+        jointDistanceLengthName           = StringTable->insert( "Length" );
+        jointDistanceFrequencyName        = StringTable->insert( "Frequency" );
+        jointDistanceDampingRatioName     = StringTable->insert( "DampingRatio" );
+
+        jointRopeNodeName                 = StringTable->insert( "Rope" );
+        jointRopeMaxLengthName            = StringTable->insert( "MaxLength" );
+
+        jointRevoluteNodeName             = StringTable->insert( "Revolute" );
+        jointRevoluteLimitLowerAngleName  = StringTable->insert( "LowerAngle" );
+        jointRevoluteLimitUpperAngleName  = StringTable->insert( "UpperAngle" );
+        jointRevoluteMotorSpeedName       = StringTable->insert( "MotorSpeed" );
+        jointRevoluteMotorMaxTorqueName   = StringTable->insert( "MaxTorque" );
+
+        jointWeldNodeName                 = StringTable->insert( "Weld" );
+        jointWeldFrequencyName            = jointDistanceFrequencyName;
+        jointWeldDampingRatioName         = jointDistanceDampingRatioName;
+
+        jointWheelNodeName                = StringTable->insert( "Wheel" );
+        jointWheelWorldAxisName           = StringTable->insert( "WorldAxis" );
+        jointWheelMotorSpeedName          = StringTable->insert( "MotorSpeed" );
+        jointWheelMotorMaxTorqueName      = jointRevoluteMotorMaxTorqueName;
+        jointWheelFrequencyName           = jointDistanceFrequencyName;
+        jointWheelDampingRatioName        = jointDistanceDampingRatioName;
+
+        jointFrictionNodeName             = StringTable->insert( "Friction" );
+        jointFrictionMaxForceName         = StringTable->insert( "MaxForce" );
+        jointFrictionMaxTorqueName        = jointRevoluteMotorMaxTorqueName;
+
+        jointPrismaticNodeName            = StringTable->insert( "Prismatic" );
+        jointPrismaticWorldAxisName       = jointWheelWorldAxisName;
+        jointPrismaticLimitLowerTransName = StringTable->insert( "LowerTranslation" );
+        jointPrismaticLimitUpperTransName = StringTable->insert( "UpperTranslation" );
+        jointPrismaticMotorSpeedName      = jointRevoluteMotorSpeedName;
+        jointPrismaticMotorMaxForceName   = jointFrictionMaxForceName;
+
+        jointPulleyNodeName               = StringTable->insert( "Pulley" );
+        jointPulleyGroundAnchorAName      = StringTable->insert( "GroundAnchorA" );
+        jointPulleyGroundAnchorBName      = StringTable->insert( "GroundAnchorB" );
+        jointPulleyLengthAName            = StringTable->insert( "LengthA" );
+        jointPulleyLengthBName            = StringTable->insert( "LengthB" );
+        jointPulleyRatioName              = StringTable->insert( "Ratio" );
+
+        jointTargetNodeName               = StringTable->insert( "Target" );
+        jointTargetWorldTargetName        = StringTable->insert( "WorldTarget" );
+        jointTargetMaxForceName           = StringTable->insert( jointFrictionMaxForceName );
+        jointTargetFrequencyName          = jointDistanceFrequencyName;
+        jointTargetDampingRatioName       = jointDistanceDampingRatioName;
+
+        jointMotorNodeName                = StringTable->insert( "Motor" );
+        jointMotorLinearOffsetName        = StringTable->insert( "LinearOffset" );
+        jointMotorAngularOffsetName       = StringTable->insert( "AngularOffset" );
+        jointMotorMaxForceName            = jointFrictionMaxForceName;
+        jointMotorMaxTorqueName           = jointRevoluteMotorMaxTorqueName;
+        jointMotorCorrectionFactorName    = StringTable->insert( "CorrectionFactor" );
+
+        controllerCustomNodeName	      = StringTable->insert( "Controllers" );
+
+        assetPreloadNodeName              = StringTable->insert( "AssetPreloads" );
+        assetNodeName                     = StringTable->insert( "Asset" );
+
+        // Flag as initialized.
+        tamlPropertiesInitialized = true;
+    }
+
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mSceneObjects );
     VECTOR_SET_ASSOCIATION( mDeleteRequests );
@@ -497,16 +577,16 @@ void Scene::dispatchBeginContactCallbacks( void )
         const F32 tangentImpulse2 = tickContact.mTangentImpulses[1];
 
         // Format objects.
-        char sceneObjectABuffer[16];
-        char sceneObjectBBuffer[16];
-        dSprintf( sceneObjectABuffer, sizeof(sceneObjectABuffer), "%d", pSceneObjectA->getId() );
-        dSprintf( sceneObjectBBuffer, sizeof(sceneObjectBBuffer), "%d", pSceneObjectB->getId() );
+        char* pSceneObjectABuffer = Con::getArgBuffer( 8 );
+        char* pSceneObjectBBuffer = Con::getArgBuffer( 8 );
+        dSprintf( pSceneObjectABuffer, 8, "%d", pSceneObjectA->getId() );
+        dSprintf( pSceneObjectBBuffer, 8, "%d", pSceneObjectB->getId() );
 
         // Format miscellaneous information.
-        char miscInfoBuffer[128];
+        char* pMiscInfoBuffer = Con::getArgBuffer(128);
         if ( pointCount == 2 )
         {
-            dSprintf(miscInfoBuffer, sizeof(miscInfoBuffer),
+            dSprintf(pMiscInfoBuffer, 128,
                 "%d %d %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f",
                 shapeIndexA, shapeIndexB,
                 normal.x, normal.y,
@@ -5352,6 +5432,10 @@ const char* Scene::getPickModeDescription( Scene::PickMode pickMode )
 
 static void WriteJointsCustomTamlScehema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "Taml::WriteJointsCustomTamlScehema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "Taml::WriteJointsCustomTamlScehema() - Parent Element cannot be NULL." );
+
     char buffer[1024];
 
     // Create joints node element.
@@ -5429,6 +5513,10 @@ static void WriteJointsCustomTamlScehema( const AbstractClassRep* pClassRep, TiX
 
 static void WriteControllersCustomTamlScehema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "Taml::WriteControllersCustomTamlScehema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "Taml::WriteControllersCustomTamlScehema() - Parent Element cannot be NULL." );
+
     char buffer[1024];
 
     // Create controllers node element.
@@ -5477,6 +5565,10 @@ static void WriteControllersCustomTamlScehema( const AbstractClassRep* pClassRep
 
 static void WritePreloadsCustomTamlScehema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "Taml::WritePreloadsCustomTamlScehema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "Taml::WritePreloadsCustomTamlScehema() - Parent Element cannot be NULL." );
+
     char buffer[1024];
 
     // Create preloads node element.
@@ -5518,6 +5610,10 @@ static void WritePreloadsCustomTamlScehema( const AbstractClassRep* pClassRep, T
 
 static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "Taml::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "Taml::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
     WriteJointsCustomTamlScehema( pClassRep, pParentElement );
     WriteControllersCustomTamlScehema( pClassRep, pParentElement );
     WritePreloadsCustomTamlScehema( pClassRep, pParentElement );

+ 5 - 0
engine/source/2d/scene/Scene.h

@@ -618,6 +618,11 @@ public:
 
     F32                     getMotorJointMaxTorque( const U32 jointId );
 
+	/// Misc Joint Utilities - 19-03-13 - capnlove
+
+	F32                     getRevoluteJointAngle(const U32 jointID);
+	F32						getRevoluteJointSpeed(const U32 jointID);
+
     /// Debug and metrics.
     inline void             setDebugOn( const U32 debugMask )           { mDebugMask |= debugMask; }
     inline void             setDebugOff( const U32 debugMask )          { mDebugMask &= ~debugMask; }

+ 37 - 0
engine/source/2d/scene/Scene_ScriptBinding.h

@@ -3167,3 +3167,40 @@ ConsoleMethod(Scene, create, const char*, 3, 3, "(type) Creates the specified sc
     return pSceneObject == NULL ? NULL : pSceneObject->getIdString();
 }
 
+ConsoleMethod(Scene, getRevoluteJointAngle, const char*, 3, 3,  "(jointId) Gets the current angle of a revolute joint.\n"
+                                                                        "@param jointId The Id of the joint to use.\n"
+                                                                    "@return Returns the joint angle in degrees (not Rad" )
+{
+    // Fetch joint Id.
+    const S32 jointId = dAtoi(argv[2]);
+
+    // Args.
+    F32 currentAngle;
+
+    // Access joint.
+	currentAngle = object->getRevoluteJointAngle( jointId);
+    
+    // Format output.
+    char* pBuffer = Con::getReturnBuffer(64);
+    dSprintf( pBuffer, 64, "%g", mRadToDeg(currentAngle) );
+    return pBuffer;
+}
+
+ConsoleMethod(Scene, getRevoluteJointSpeed, const char*, 3, 3,  "(jointId) Gets the current speed of a revolute joint.\n"
+                                                                        "@param jointId The Id of the joint to use.\n"
+                                                                    "@return Returns the joint speed as Angular Velocity" )
+{
+    // Fetch joint Id.
+    const S32 jointId = dAtoi(argv[2]);
+
+    // Args.
+    F32 angularVel;
+
+    // Access joint.
+	angularVel = object->getRevoluteJointSpeed( jointId);
+    
+    // Format output.
+    char* pBuffer = Con::getReturnBuffer(64);
+    dSprintf( pBuffer, 64, "%g", angularVel);
+    return pBuffer;
+}

+ 2 - 19
engine/source/2d/sceneobject/CompositeSprite.cc

@@ -409,18 +409,8 @@ void CompositeSprite::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Call parent.
     Parent::onTamlCustomWrite( customNodes );
 
-    // Fetch sprite count.
-    const U32 spriteCount = getSpriteCount();
-
-    // Finish if no sprites.
-    if ( spriteCount == 0 )
-        return;
-
-    // Add sprites node.
-    TamlCustomNode* pSpritesNode = customNodes.addNode( StringTable->insert("Sprites") );
-
     // Write node with sprite batch.
-    SpriteBatch::onTamlCustomWrite( pSpritesNode );
+    SpriteBatch::onTamlCustomWrite( customNodes );
 }
 
 //-----------------------------------------------------------------------------
@@ -430,13 +420,6 @@ void CompositeSprite::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Call parent.
     Parent::onTamlCustomRead( customNodes );
 
-    // Find sprites custom node.
-    const TamlCustomNode* pSpritesNode = customNodes.findNode( StringTable->insert("Sprites") );
-
-    // Finish if we don't have the node.
-    if ( pSpritesNode == NULL )
-        return;
-
     // Read node with sprite batch.
-    SpriteBatch::onTamlCustomRead( pSpritesNode );
+    SpriteBatch::onTamlCustomRead( customNodes );
 }

+ 20 - 0
engine/source/2d/sceneobject/SceneObject.cc

@@ -4101,6 +4101,10 @@ const char* SceneObject::getDstBlendFactorDescription(const GLenum factor)
 
 static void WriteCircleCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteCircleCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCircleCustomTamlSchema() - Parent Element cannot be NULL." );
+
     // Create circle element.
     TiXmlElement* pCircleElement = new TiXmlElement( "xs:element" );
     pCircleElement->SetAttribute( "name", circleTypeName );
@@ -4181,6 +4185,10 @@ static void WriteCircleCustomTamlSchema( const AbstractClassRep* pClassRep, TiXm
 
 static void WritePolygonCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WritePolygonCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WritePolygonCustomTamlSchema() - Parent Element cannot be NULL." );
+
     // Create polygon element.
     TiXmlElement* pPolygonElement = new TiXmlElement( "xs:element" );
     pPolygonElement->SetAttribute( "name", polygonTypeName );
@@ -4252,6 +4260,10 @@ static void WritePolygonCustomTamlSchema( const AbstractClassRep* pClassRep, TiX
 
 static void WriteChainCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteChainCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteChainCustomTamlSchema() - Parent Element cannot be NULL." );
+
     // Create chain element.
     TiXmlElement* pChainElement = new TiXmlElement( "xs:element" );
     pChainElement->SetAttribute( "name", chainTypeName );
@@ -4337,6 +4349,10 @@ static void WriteChainCustomTamlSchema( const AbstractClassRep* pClassRep, TiXml
 
 static void WriteEdgeCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteEdgeCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
     // Create edge element.
     TiXmlElement* pEdgeElement = new TiXmlElement( "xs:element" );
     pEdgeElement->SetAttribute( "name", edgeTypeName );
@@ -4420,6 +4436,10 @@ static void WriteEdgeCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlE
 
 static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
     char buffer[1024];
 
     // Create shapes node element.

+ 1 - 1
engine/source/2d/sceneobject/SceneObject.h

@@ -705,7 +705,7 @@ protected:
     static bool             writeUseInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getUseInputEvents() == true; }
 
     /// Picking.
-    static bool             writePickingAllowed( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getPickingAllowed() == true; }    
+    static bool             writePickingAllowed( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getPickingAllowed() == false; }    
 
     /// Script callbacks.
     static bool             writeUpdateCallback( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getUpdateCallback() == true; }

+ 191 - 173
engine/source/component/behaviors/behaviorComponent.cpp

@@ -35,16 +35,18 @@
 #include "persistence/taml/tamlCustom.h"
 #endif
 
+#ifndef _TAML_H_
+#include "persistence/Taml/taml.h"
+#endif
+
 // Script bindings.
 #include "behaviorComponent_ScriptBinding.h"
 
 //-----------------------------------------------------------------------------
 
-#define BEHAVIOR_FIELDNAME              "Behavior"
-
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT( BehaviorComponent );
+#define BEHAVIOR_ID_FIELD_NAME                  "Id"
+#define BEHAVIOR_NODE_NAME                      "Behaviors"
+#define BEHAVIOR_CONNECTION_TYPE_NAME           "Connection"
 
 //-----------------------------------------------------------------------------
 
@@ -885,6 +887,183 @@ const BehaviorComponent::typePortConnectionVector* BehaviorComponent::getBehavio
 
 //-----------------------------------------------------------------------------
 
+void BehaviorComponent::write( Stream &stream, U32 tabStop, U32 flags /* = 0 */ )
+{
+    // Export selected only?
+    if( ( flags & SelectedOnly ) && !isSelected() )
+    {
+        return;
+    }
+
+    if( mBehaviors.size() == 0 )
+    {
+        Parent::write( stream, tabStop, flags );
+        return;
+    }
+
+    // The work we want to perform here is in the Taml callback.
+    onTamlPreWrite();
+
+    // Write object.
+    Parent::write( stream, tabStop, flags );
+
+    // The work we want to perform here is in the Taml callback.
+    onTamlPostWrite();
+}
+
+//-----------------------------------------------------------------------------
+
+bool BehaviorComponent::handlesConsoleMethod( const char *fname, S32 *routingId )
+{
+
+   // CodeReview [6/25/2007 justind]
+   // If we're deleting the BehaviorComponent, don't forward the call to the
+   // behaviors, the parent onRemove will handle freeing them
+   // This should really be handled better, and is in the Parent implementation
+   // but behaviors are a special case because they always want to be called BEFORE
+   // the parent to act.
+   if( dStricmp( fname, "delete" ) == 0 )
+      return Parent::handlesConsoleMethod( fname, routingId );
+
+   for( SimSet::iterator nItr = mBehaviors.begin(); nItr != mBehaviors.end(); nItr++ )
+   {
+      SimObject *pComponent = dynamic_cast<SimObject *>(*nItr);
+      if( pComponent != NULL && pComponent->isMethod( fname ) )
+      {
+         *routingId = -2; // -2 denotes method on component
+         return true;
+      }
+   }
+
+   // Let parent handle it
+   return Parent::handlesConsoleMethod( fname, routingId );
+}
+
+//-----------------------------------------------------------------------------
+
+// Needed to be able to directly call execute on a Namespace::Entry
+extern ExprEvalState gEvalState;
+
+const char *BehaviorComponent::callOnBehaviors( U32 argc, const char *argv[] )
+{   
+    if( mBehaviors.empty() )   
+        return Parent::callOnBehaviors( argc, argv );
+      
+    // Copy the arguments to avoid weird clobbery situations.
+    FrameTemp<char *> argPtrs (argc);
+   
+    U32 strdupWatermark = FrameAllocator::getWaterMark();
+    for( U32 i = 0; i < argc; i++ )
+    {
+        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
+        dStrcpy( argPtrs[i], argv[i] );
+    }
+
+    // Walk backwards through the list just as with components
+    const char* result = "";
+    bool handled = false;
+    for( SimSet::iterator i = (mBehaviors.end()-1); i >= mBehaviors.begin(); i-- )
+    {
+        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
+        AssertFatal( pBehavior, "BehaviorComponent::callOnBehaviors - Bad behavior instance in list." );
+        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
+
+        // Use the BehaviorInstance's namespace
+        Namespace *pNamespace = pBehavior->getNamespace();
+        if(!pNamespace)
+            continue;
+
+        // Lookup the Callback Namespace entry and then splice callback
+        const char *cbName = StringTable->insert(argv[0]);
+        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
+        if( pNSEntry )
+        {
+            // Set %this to our BehaviorInstance's Object ID
+            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
+
+            // Change the Current Console object, execute, restore Object
+            SimObject *save = gEvalState.thisObject;
+            gEvalState.thisObject = pBehavior;
+
+            result = pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
+
+            gEvalState.thisObject = save;
+            handled = true;
+            break;
+        }
+    }
+
+    // If this wasn't handled by a behavior above then pass along to the parent DynamicConsoleMethodComponent
+    // to deal with it.  If the parent cannot handle the message it will return an error string.
+    if (!handled)
+    {
+        result = Parent::callOnBehaviors( argc, argv );
+    }
+
+    // Clean up.
+    FrameAllocator::setWaterMark( strdupWatermark );
+
+    return result;
+}
+
+//-----------------------------------------------------------------------------
+
+const char *BehaviorComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true  */ )
+{   
+    if( mBehaviors.empty() )   
+        return Parent::_callMethod( argc, argv, callThis );
+     
+    // Copy the arguments to avoid weird clobbery situations.
+    FrameTemp<char *> argPtrs (argc);
+   
+    U32 strdupWatermark = FrameAllocator::getWaterMark();
+    for( U32 i = 0; i < argc; i++ )
+    {
+        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
+        dStrcpy( argPtrs[i], argv[i] );
+    }
+
+    for( SimSet::iterator i = mBehaviors.begin(); i != mBehaviors.end(); i++ )
+    {
+        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
+        AssertFatal( pBehavior, "BehaviorComponent::_callMethod - Bad behavior instance in list." );
+        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
+
+        // Use the BehaviorInstance's namespace
+        Namespace *pNamespace = pBehavior->getNamespace();
+        if(!pNamespace)
+            continue;
+
+        // Lookup the Callback Namespace entry and then splice callback
+        const char *cbName = StringTable->insert(argv[0]);
+        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
+        if( pNSEntry )
+        {
+            // Set %this to our BehaviorInstance's Object ID
+            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
+
+            // Change the Current Console object, execute, restore Object
+            SimObject *save = gEvalState.thisObject;
+            gEvalState.thisObject = pBehavior;
+
+            pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
+
+            gEvalState.thisObject = save;
+        }
+    }
+
+    // Pass this up to the parent since a BehaviorComponent is still a DynamicConsoleMethodComponent
+    // it needs to be able to contain other components and behave properly
+    const char* fnRet = Parent::_callMethod( argc, argv, callThis );
+
+    // Clean up.
+    FrameAllocator::setWaterMark( strdupWatermark );
+
+    return fnRet;
+}
+
+//-----------------------------------------------------------------------------
+
 void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Call parent.
@@ -1224,177 +1403,16 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomNodes& customNodes )
 
 //-----------------------------------------------------------------------------
 
-void BehaviorComponent::write( Stream &stream, U32 tabStop, U32 flags /* = 0 */ )
-{
-    // Export selected only?
-    if( ( flags & SelectedOnly ) && !isSelected() )
-    {
-        return;
-    }
-
-    if( mBehaviors.size() == 0 )
-    {
-        Parent::write( stream, tabStop, flags );
-        return;
-    }
-
-    // The work we want to perform here is in the Taml callback.
-    onTamlPreWrite();
-
-    // Write object.
-    Parent::write( stream, tabStop, flags );
-
-    // The work we want to perform here is in the Taml callback.
-    onTamlPostWrite();
-}
-
-//-----------------------------------------------------------------------------
-
-bool BehaviorComponent::handlesConsoleMethod( const char *fname, S32 *routingId )
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "BehaviorComponent::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "BehaviorComponent::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
 
-   // CodeReview [6/25/2007 justind]
-   // If we're deleting the BehaviorComponent, don't forward the call to the
-   // behaviors, the parent onRemove will handle freeing them
-   // This should really be handled better, and is in the Parent implementation
-   // but behaviors are a special case because they always want to be called BEFORE
-   // the parent to act.
-   if( dStricmp( fname, "delete" ) == 0 )
-      return Parent::handlesConsoleMethod( fname, routingId );
-
-   for( SimSet::iterator nItr = mBehaviors.begin(); nItr != mBehaviors.end(); nItr++ )
-   {
-      SimObject *pComponent = dynamic_cast<SimObject *>(*nItr);
-      if( pComponent != NULL && pComponent->isMethod( fname ) )
-      {
-         *routingId = -2; // -2 denotes method on component
-         return true;
-      }
-   }
-
-   // Let parent handle it
-   return Parent::handlesConsoleMethod( fname, routingId );
-}
-
-//-----------------------------------------------------------------------------
-
-// Needed to be able to directly call execute on a Namespace::Entry
-extern ExprEvalState gEvalState;
-
-const char *BehaviorComponent::callOnBehaviors( U32 argc, const char *argv[] )
-{   
-    if( mBehaviors.empty() )   
-        return Parent::callOnBehaviors( argc, argv );
-      
-    // Copy the arguments to avoid weird clobbery situations.
-    FrameTemp<char *> argPtrs (argc);
-   
-    U32 strdupWatermark = FrameAllocator::getWaterMark();
-    for( U32 i = 0; i < argc; i++ )
-    {
-        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
-        dStrcpy( argPtrs[i], argv[i] );
-    }
-
-    // Walk backwards through the list just as with components
-    const char* result = "";
-    bool handled = false;
-    for( SimSet::iterator i = (mBehaviors.end()-1); i >= mBehaviors.begin(); i-- )
-    {
-        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
-        AssertFatal( pBehavior, "BehaviorComponent::callOnBehaviors - Bad behavior instance in list." );
-        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
-
-        // Use the BehaviorInstance's namespace
-        Namespace *pNamespace = pBehavior->getNamespace();
-        if(!pNamespace)
-            continue;
-
-        // Lookup the Callback Namespace entry and then splice callback
-        const char *cbName = StringTable->insert(argv[0]);
-        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
-        if( pNSEntry )
-        {
-            // Set %this to our BehaviorInstance's Object ID
-            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
-
-            // Change the Current Console object, execute, restore Object
-            SimObject *save = gEvalState.thisObject;
-            gEvalState.thisObject = pBehavior;
-
-            result = pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
-
-            gEvalState.thisObject = save;
-            handled = true;
-            break;
-        }
-    }
-
-    // If this wasn't handled by a behavior above then pass along to the parent DynamicConsoleMethodComponent
-    // to deal with it.  If the parent cannot handle the message it will return an error string.
-    if (!handled)
-    {
-        result = Parent::callOnBehaviors( argc, argv );
-    }
-
-    // Clean up.
-    FrameAllocator::setWaterMark( strdupWatermark );
-
-    return result;
+    // Write an unrestricted custom Taml schema.
+    Taml::WriteUnrestrictedCustomTamlSchema( BEHAVIOR_NODE_NAME, pClassRep, pParentElement );
 }
 
 //-----------------------------------------------------------------------------
 
-const char *BehaviorComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true  */ )
-{   
-    if( mBehaviors.empty() )   
-        return Parent::_callMethod( argc, argv, callThis );
-     
-    // Copy the arguments to avoid weird clobbery situations.
-    FrameTemp<char *> argPtrs (argc);
-   
-    U32 strdupWatermark = FrameAllocator::getWaterMark();
-    for( U32 i = 0; i < argc; i++ )
-    {
-        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
-        dStrcpy( argPtrs[i], argv[i] );
-    }
-
-    for( SimSet::iterator i = mBehaviors.begin(); i != mBehaviors.end(); i++ )
-    {
-        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
-        AssertFatal( pBehavior, "BehaviorComponent::_callMethod - Bad behavior instance in list." );
-        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
-
-        // Use the BehaviorInstance's namespace
-        Namespace *pNamespace = pBehavior->getNamespace();
-        if(!pNamespace)
-            continue;
-
-        // Lookup the Callback Namespace entry and then splice callback
-        const char *cbName = StringTable->insert(argv[0]);
-        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
-        if( pNSEntry )
-        {
-            // Set %this to our BehaviorInstance's Object ID
-            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
-
-            // Change the Current Console object, execute, restore Object
-            SimObject *save = gEvalState.thisObject;
-            gEvalState.thisObject = pBehavior;
-
-            pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
-
-            gEvalState.thisObject = save;
-        }
-    }
-
-    // Pass this up to the parent since a BehaviorComponent is still a DynamicConsoleMethodComponent
-    // it needs to be able to contain other components and behave properly
-    const char* fnRet = Parent::_callMethod( argc, argv, callThis );
-
-    // Clean up.
-    FrameAllocator::setWaterMark( strdupWatermark );
-
-    return fnRet;
-}
+IMPLEMENT_CONOBJECT_SCHEMA( BehaviorComponent, WriteCustomTamlSchema );

+ 0 - 7
engine/source/component/behaviors/behaviorComponent.h

@@ -33,13 +33,6 @@
 
 //-----------------------------------------------------------------------------
 
-#define BEHAVIOR_ID_FIELD_NAME                  "Id"
-#define BEHAVIOR_NODE_NAME                      "Behaviors"
-#define BEHAVIOR_CONNECTION_NODE_NAME           "BehaviorConnections"
-#define BEHAVIOR_CONNECTION_TYPE_NAME           "Connection"
-
-//-----------------------------------------------------------------------------
-
 class BehaviorComponent : public DynamicConsoleMethodComponent
 {
     friend class BehaviorInterface;

+ 30 - 42
engine/source/graphics/color.cc

@@ -48,35 +48,6 @@ static typeColorIToNameHash    mColorIToName;
 
 //-----------------------------------------------------------------------------
 
-class StockColorItem
-{
-private:
-    StockColorItem() {}
-
-public:
-    StockColorItem( const char* pName, const U8 red, const U8 green, const U8 blue, const U8 alpha = 255 )
-    {
-        // Sanity!
-        AssertFatal( pName != NULL, "Stock color name cannot be NULL." );
-
-        // Set stock color.
-        // NOTE:-   We'll use the char pointer here.  We can yet use the string-table unfortunately.
-        mColorName = pName;
-        mColorI.set( red, green, blue, alpha );
-        mColorF = mColorI;
-    }
-
-    inline const char*      getColorName( void ) const { return mColorName; }
-    inline const ColorF&    getColorF( void ) const { return mColorF; }
-    inline const ColorI&    getColorI( void ) const { return mColorI; }
-
-    const char*         mColorName;
-    ColorF              mColorF;
-    ColorI              mColorI;
-};
-
-//-----------------------------------------------------------------------------
-
 StockColorItem StockColorTable[] =
 {
     StockColorItem( "InvisibleBlack", 0, 0, 0, 0 ),
@@ -368,6 +339,32 @@ StringTableEntry StockColor::name( const ColorI& color )
 
 //-----------------------------------------------------------------------------
 
+S32 StockColor::getCount( void )
+{
+    return sizeof(StockColorTable) / sizeof(StockColorItem);
+}
+
+//-----------------------------------------------------------------------------
+
+const StockColorItem* StockColor::getColorItem( const S32 index )
+{
+    // Fetch stock color count.
+    const S32 stockColorCount = StockColor::getCount();
+
+    // Is the stock color index in range?
+    if ( index < 0 || index >= stockColorCount )
+    {
+        // No, so warn.
+        Con::warnf("StockColor::getName() - Specified color index '%d' is out of range.  Range is 0 to %d.", index, stockColorCount-1 );
+        return NULL;
+    }
+
+    // Return color name.
+    return &(StockColorTable[index]);
+}
+
+//-----------------------------------------------------------------------------
+
 ColorF::ColorF( const char* pStockColorName )
 {
     // Set stock color.
@@ -582,7 +579,7 @@ ConsoleSetType( TypeColorI )
 ConsoleFunction( getStockColorCount, S32, 1, 1, "() - Gets a count of available stock colors.\n"
                                                 "@return A count of available stock colors." )
 {
-    return sizeof(StockColorTable) / sizeof(StockColorItem);
+    return StockColor::getCount();
 }
 
 //-----------------------------------------------------------------------------
@@ -594,19 +591,10 @@ ConsoleFunction( getStockColorName, const char*, 2, 2,  "(stockColorIndex) - Get
     // Fetch stock color index.
     const S32 stockColorIndex = dAtoi(argv[1]);
 
-    // Fetch stock color count.
-    const S32 stockColorCount = sizeof(StockColorTable) / sizeof(StockColorItem);
+    // Fetch the color item.
+    const StockColorItem* pColorItem = StockColor::getColorItem( stockColorIndex );
 
-    // Is the stock color index in range?
-    if ( stockColorIndex < 0 || stockColorIndex >= stockColorCount )
-    {
-        // No, so warn.
-        Con::warnf("getStockColorName() - Specified color index '%d' is out of range.  Range is 0 to %d.", stockColorIndex, stockColorCount-1 );
-        return StringTable->EmptyString;
-    }
-
-    // Return color name.
-    return StockColorTable[stockColorIndex].getColorName();
+    return pColorItem == NULL ? NULL : pColorItem->getColorName();
 }
 
 //-----------------------------------------------------------------------------

+ 34 - 0
engine/source/graphics/color.h

@@ -36,6 +36,7 @@
 DefineConsoleType( TypeColorI )
 DefineConsoleType( TypeColorF )
 
+
 //-----------------------------------------------------------------------------
 
 class ColorI;
@@ -176,6 +177,36 @@ class ColorI
    U16 get4444() const;
 };
 
+
+//-----------------------------------------------------------------------------
+
+class StockColorItem
+{
+private:
+    StockColorItem() {}
+
+public:
+    StockColorItem( const char* pName, const U8 red, const U8 green, const U8 blue, const U8 alpha = 255 )
+    {
+        // Sanity!
+        AssertFatal( pName != NULL, "Stock color name cannot be NULL." );
+
+        // Set stock color.
+        // NOTE:-   We'll use the char pointer here.  We can yet use the string-table unfortunately.
+        mColorName = pName;
+        mColorI.set( red, green, blue, alpha );
+        mColorF = mColorI;
+    }
+
+    inline const char*      getColorName( void ) const { return mColorName; }
+    inline const ColorF&    getColorF( void ) const { return mColorF; }
+    inline const ColorI&    getColorI( void ) const { return mColorI; }
+
+    const char*         mColorName;
+    ColorF              mColorF;
+    ColorI              mColorI;
+};
+
 //-----------------------------------------------------------------------------
 
 class StockColor
@@ -187,6 +218,9 @@ public:
     static StringTableEntry name( const ColorF& color );
     static StringTableEntry name( const ColorI& color );
 
+    static S32 getCount( void );
+    static const StockColorItem* getColorItem( const S32 index );
+
     static void create( void );
     static void destroy( void );
 };

+ 184 - 18
engine/source/persistence/taml/taml.cc

@@ -856,10 +856,32 @@ SimObject* Taml::createType( StringTableEntry typeName, const Taml* pTaml, const
 
 //-----------------------------------------------------------------------------
 
-bool Taml::generateTamlSchema( const char* pFilename )
+bool Taml::generateTamlSchema()
 {
-    // Sanity!
-    AssertFatal( pFilename != NULL, "Taml::generateTamlSchema() - Cannot write a NULL filename." );
+    // Fetch any TAML Schema file reference.
+    const char* pTamlSchemaFile = Con::getVariable( TAML_SCHEMA_VARIABLE );
+
+    // Do we have a schema file reference?
+    if ( pTamlSchemaFile == NULL || *pTamlSchemaFile == 0 )
+    {
+        // No, so warn.
+        Con::warnf( "Taml::generateTamlSchema() - Cannot write a TAML schema as no schema variable is set ('%s').", TAML_SCHEMA_VARIABLE );
+        return false;
+    }
+
+    // Expand the file-name into the file-path buffer.
+    char filePathBuffer[1024];
+    Con::expandPath( filePathBuffer, sizeof(filePathBuffer), pTamlSchemaFile );
+
+    FileStream stream;
+
+    // File opened?
+    if ( !stream.open( filePathBuffer, FileStream::Write ) )
+    {
+        // No, so warn.
+        Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer );
+        return false;
+    }
 
     // Create document.
     TiXmlDocument schemaDocument;
@@ -876,6 +898,11 @@ bool Taml::generateTamlSchema( const char* pFilename )
     // Fetch class-rep root.
     AbstractClassRep* pRootType = AbstractClassRep::getClassList();
 
+    // Fetch SimObject class rep.
+    AbstractClassRep* pSimObjectType = AbstractClassRep::findClassRep( "SimObject" );
+    // Sanity!
+    AssertFatal( pSimObjectType != NULL, "Taml::GenerateTamlSchema() - Could not find SimObject class rep." );
+
     // Reset scratch state.
     char buffer[1024];
     HashMap<AbstractClassRep*, StringTableEntry> childGroups;
@@ -959,7 +986,7 @@ bool Taml::generateTamlSchema( const char* pFilename )
     pRectFElementA->SetAttribute( "base", "xs:string" );
     pRectFTypeElement->LinkEndChild( pRectFElementA );
     TiXmlElement* pRectFElementB = new TiXmlElement( "xs:pattern" );
-    pRectFElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );   
+    pRectFElementB->SetAttribute( "value", "(\\b[-]?(b[0-9]+)?\\.)?[0-9]+\\b" );   
     pRectFElementA->LinkEndChild( pRectFElementB );
 
     // AssetId.
@@ -976,6 +1003,68 @@ bool Taml::generateTamlSchema( const char* pFilename )
     pAssetIdElementB->SetAttribute( "value", buffer );
     pAssetIdElementA->LinkEndChild( pAssetIdElementB );
 
+    // Color Enums.
+    TiXmlComment* pColorEnumsComment = new TiXmlComment( "Color Enums" );
+    pSchemaElement->LinkEndChild( pColorEnumsComment );
+    TiXmlElement* pColorEnumsTypeElement = new TiXmlElement( "xs:simpleType" );
+    pColorEnumsTypeElement->SetAttribute( "name", "Color_Enums" );
+    pSchemaElement->LinkEndChild( pColorEnumsTypeElement );
+    TiXmlElement* pColorEnumsRestrictionElement = new TiXmlElement( "xs:restriction" );
+    pColorEnumsRestrictionElement->SetAttribute( "base", "xs:string" );
+    pColorEnumsTypeElement->LinkEndChild( pColorEnumsRestrictionElement );
+    const S32 ColorEnumsCount = StockColor::getCount();
+    for( S32 index = 0; index < ColorEnumsCount; ++index )
+    {
+        // Add enumeration element.
+        TiXmlElement* pColorEnumsAttributeEnumerationElement = new TiXmlElement( "xs:enumeration" );
+        pColorEnumsAttributeEnumerationElement->SetAttribute( "value", StockColor::getColorItem(index)->getColorName() );
+        pColorEnumsRestrictionElement->LinkEndChild( pColorEnumsAttributeEnumerationElement );
+    }
+
+    // ColorF.
+    TiXmlComment* pColorFValuesComment = new TiXmlComment( "ColorF Values" );
+    pSchemaElement->LinkEndChild( pColorFValuesComment );
+    TiXmlElement* pColorFValuesTypeElement = new TiXmlElement( "xs:simpleType" );
+    pColorFValuesTypeElement->SetAttribute( "name", "ColorF_Values" );
+    pSchemaElement->LinkEndChild( pColorFValuesTypeElement );
+    TiXmlElement* pColorFValuesElementA = new TiXmlElement( "xs:restriction" );
+    pColorFValuesElementA->SetAttribute( "base", "xs:string" );
+    pColorFValuesTypeElement->LinkEndChild( pColorFValuesElementA );
+    TiXmlElement* pColorFValuesElementB = new TiXmlElement( "xs:pattern" );
+    pColorFValuesElementB->SetAttribute( "value", "([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b ([-]?(\\b[0-9]+)?\\.)?[0-9]+\\b" );
+    pColorFValuesElementA->LinkEndChild( pColorFValuesElementB );
+
+    TiXmlComment* pColorFComment = new TiXmlComment( "ColorF Console Type" );
+    pSchemaElement->LinkEndChild( pColorFComment );
+    TiXmlElement* pColorFTypeElement = new TiXmlElement( "xs:simpleType" );
+    pColorFTypeElement->SetAttribute( "name", "ColorF_ConsoleType" );
+    pSchemaElement->LinkEndChild( pColorFTypeElement );
+    TiXmlElement* pColorFUnionElement = new TiXmlElement( "xs:union" );
+    pColorFUnionElement->SetAttribute( "memberTypes", "ColorF_Values Color_Enums" );
+    pColorFTypeElement->LinkEndChild( pColorFUnionElement );
+
+    // ColorI.
+    TiXmlComment* pColorIValuesComment = new TiXmlComment( "ColorI Values" );
+    pSchemaElement->LinkEndChild( pColorIValuesComment );
+    TiXmlElement* pColorIValuesTypeElement = new TiXmlElement( "xs:simpleType" );
+    pColorIValuesTypeElement->SetAttribute( "name", "ColorI_Values" );
+    pSchemaElement->LinkEndChild( pColorIValuesTypeElement );
+    TiXmlElement* pColorIValuesElementA = new TiXmlElement( "xs:restriction" );
+    pColorIValuesElementA->SetAttribute( "base", "xs:string" );
+    pColorIValuesTypeElement->LinkEndChild( pColorIValuesElementA );
+    TiXmlElement* pColorIValuesElementB = new TiXmlElement( "xs:pattern" );
+    pColorIValuesElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*" );
+    pColorIValuesElementA->LinkEndChild( pColorIValuesElementB );
+
+    TiXmlComment* pColorIComment = new TiXmlComment( "ColorI Console Type" );
+    pSchemaElement->LinkEndChild( pColorIComment );
+    TiXmlElement* pColorITypeElement = new TiXmlElement( "xs:simpleType" );
+    pColorITypeElement->SetAttribute( "name", "ColorI_ConsoleType" );
+    pSchemaElement->LinkEndChild( pColorITypeElement );
+    TiXmlElement* pColorIUnionElement = new TiXmlElement( "xs:union" );
+    pColorIUnionElement->SetAttribute( "memberTypes", "ColorI_Values Color_Enums" );
+    pColorITypeElement->LinkEndChild( pColorIUnionElement );
+
     // *************************************************************
     // Generate engine type elements.
     // *************************************************************
@@ -1084,6 +1173,12 @@ bool Taml::generateTamlSchema( const char* pFilename )
             customSchemaFn( pType, pSequenceElement );
         }
 
+        // Generate field attribute group.
+        TiXmlElement* pFieldAttributeGroupElement = new TiXmlElement( "xs:attributeGroup" );
+        dSprintf( buffer, sizeof(buffer), "%s_Fields", pType->getClassName() );
+        pFieldAttributeGroupElement->SetAttribute( "name", buffer );
+        pSchemaElement->LinkEndChild( pFieldAttributeGroupElement );
+
         // Fetch field list.
         const AbstractClassRep::FieldList& fields = pType->mFieldList;
 
@@ -1102,6 +1197,10 @@ bool Taml::generateTamlSchema( const char* pFilename )
                 field.type == AbstractClassRep::EndGroupFieldType )
             continue;
 
+            // Skip if the field root is not this type.
+            if ( pType->findFieldRoot( field.pFieldname ) != pType )
+                continue;
+
             // Add attribute element.
             TiXmlElement* pAttributeElement = new TiXmlElement( "xs:attribute" );
             pAttributeElement->SetAttribute( "name", field.pFieldname );
@@ -1176,6 +1275,14 @@ bool Taml::generateTamlSchema( const char* pFilename )
                 {
                     pFieldTypeDescription = "RectF_ConsoleType";
                 }
+                else if( fieldType == TypeColorF )
+                {
+                    pFieldTypeDescription = "ColorF_ConsoleType";
+                }
+                else if( fieldType == TypeColorI )
+                {
+                    pFieldTypeDescription = "ColorI_ConsoleType";
+                }
                 else if(    fieldType == TypeAssetId ||
                             fieldType == TypeImageAssetPtr ||
                             fieldType == TypeAnimationAssetPtr ||
@@ -1189,7 +1296,40 @@ bool Taml::generateTamlSchema( const char* pFilename )
             }
 
             pAttributeElement->SetAttribute( "use", "optional" );
-            pComplexTypeElement->LinkEndChild( pAttributeElement );
+            pFieldAttributeGroupElement->LinkEndChild( pAttributeElement );
+        }
+
+        // Is this the SimObject Type?
+        if ( pType == pSimObjectType )
+        {
+            // Yes, so add reserved Taml field attributes here...
+
+            // Add Taml "Name" attribute element.
+            TiXmlElement* pNameAttributeElement = new TiXmlElement( "xs:attribute" );
+            pNameAttributeElement->SetAttribute( "name", TAML_OBJECTNAME_ATTRIBUTE_NAME );
+            pNameAttributeElement->SetAttribute( "type", "xs:normalizedString" );
+            pFieldAttributeGroupElement->LinkEndChild( pNameAttributeElement );
+
+            // Add Taml "TamlId" attribute element.
+            TiXmlElement* pTamlIdAttributeElement = new TiXmlElement( "xs:attribute" );
+            pTamlIdAttributeElement->SetAttribute( "name", TAML_ID_ATTRIBUTE_NAME );
+            pTamlIdAttributeElement->SetAttribute( "type", "xs:nonNegativeInteger" );
+            pFieldAttributeGroupElement->LinkEndChild( pTamlIdAttributeElement );
+
+            // Add Taml "TamlRefId" attribute element.
+            TiXmlElement* pTamlRefIdAttributeElement = new TiXmlElement( "xs:attribute" );
+            pTamlRefIdAttributeElement->SetAttribute( "name", TAML_REFID_ATTRIBUTE_NAME );
+            pTamlRefIdAttributeElement->SetAttribute( "type", "xs:nonNegativeInteger" );
+            pFieldAttributeGroupElement->LinkEndChild( pTamlRefIdAttributeElement );
+        }
+
+        // Add attribute group types.
+        for ( AbstractClassRep* pAttributeGroupsType = pType; pAttributeGroupsType != NULL; pAttributeGroupsType = pAttributeGroupsType->getParentClass() )
+        {
+            TiXmlElement* pFieldAttributeGroupRefElement = new TiXmlElement( "xs:attributeGroup" );
+            dSprintf( buffer, sizeof(buffer), "%s_Fields", pAttributeGroupsType->getClassName() );
+            pFieldAttributeGroupRefElement->SetAttribute( "ref", buffer );
+            pComplexTypeElement->LinkEndChild( pFieldAttributeGroupRefElement );
         }
 
         // Add "any" attribute element (dynamic fields).
@@ -1198,19 +1338,6 @@ bool Taml::generateTamlSchema( const char* pFilename )
         pComplexTypeElement->LinkEndChild( pAnyAttributeElement );
     }
 
-    // Expand the file-name into the file-path buffer.
-    char filePathBuffer[1024];
-    Con::expandPath( filePathBuffer, sizeof(filePathBuffer), pFilename );
-
-    FileStream stream;
-
-    // File opened?
-    if ( !stream.open( filePathBuffer, FileStream::Write ) )
-    {
-        // No, so warn.
-        Con::warnf("Taml::GenerateTamlSchema() - Could not open filename '%s' for write.", filePathBuffer );
-        return false;
-    }
     // Write the schema document.
     schemaDocument.SaveFile( stream );
 
@@ -1219,3 +1346,42 @@ bool Taml::generateTamlSchema( const char* pFilename )
 
     return true;
 }
+
+//-----------------------------------------------------------------------------
+
+void Taml::WriteUnrestrictedCustomTamlSchema( const char* pCustomNodeName, const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pCustomNodeName != NULL, "Taml::WriteDefaultCustomTamlSchema() - Node name cannot be NULL." );
+    AssertFatal( pClassRep != NULL,  "Taml::WriteDefaultCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "Taml::WriteDefaultCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Add custom type element.
+    TiXmlElement* pCustomElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), pCustomNodeName  );
+    pCustomElement->SetAttribute( "name", buffer );
+    pCustomElement->SetAttribute( "minOccurs", 0 );
+    pCustomElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pCustomElement );
+
+    // Add complex type element.
+    TiXmlElement* pComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pCustomElement->LinkEndChild( pComplexTypeElement );
+
+    // Add choice element.
+    TiXmlElement* pChoiceElement = new TiXmlElement( "xs:choice" );
+    pChoiceElement->SetAttribute( "minOccurs", 0 );
+    pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pComplexTypeElement->LinkEndChild( pChoiceElement );
+
+    // Add sequence element.
+    TiXmlElement* pSequenceElement = new TiXmlElement( "xs:sequence" );
+    pChoiceElement->LinkEndChild( pSequenceElement );
+
+    // Add "any" element.
+    TiXmlElement* pAnyElement = new TiXmlElement( "xs:any" );
+    pAnyElement->SetAttribute( "processContents", "skip" );
+    pSequenceElement->LinkEndChild( pAnyElement );
+}

+ 8 - 2
engine/source/persistence/taml/taml.h

@@ -56,11 +56,14 @@
 #define TAML_SIGNATURE                  "Taml"
 #define TAML_ID_ATTRIBUTE_NAME          "TamlId"
 #define TAML_REFID_ATTRIBUTE_NAME       "TamlRefId"
-#define TAML_REF_FIELD_NAME             "TamlRefField"
 #define TAML_OBJECTNAME_ATTRIBUTE_NAME  "Name"
 
 //-----------------------------------------------------------------------------
 
+#define TAML_SCHEMA_VARIABLE            "$pref::T2D::TAMLSchema"
+
+//-----------------------------------------------------------------------------
+
 class TamlXmlWriter;
 class TamlXmlReader;
 class TamlBinaryWriter;
@@ -193,7 +196,10 @@ public:
     static const char* getFormatModeDescription( const TamlFormatMode formatMode );
 
     /// Schema generation.
-    static bool generateTamlSchema( const char* pFilename );
+    static bool generateTamlSchema();
+
+    /// Write a unrestricted custom Taml schema.
+    static void WriteUnrestrictedCustomTamlSchema( const char* pCustomNodeName, const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
 
     /// Declare Console Object.
     DECLARE_CONOBJECT( Taml );

+ 0 - 1
engine/source/persistence/taml/tamlXmlReader.h

@@ -45,7 +45,6 @@ public:
     {
         mTamlRefId      = StringTable->insert( TAML_ID_ATTRIBUTE_NAME );
         mTamlRefToId    = StringTable->insert( TAML_REFID_ATTRIBUTE_NAME );
-        mTamlRefField   = StringTable->insert( TAML_REF_FIELD_NAME );
         mTamlObjectName = StringTable->insert( TAML_OBJECTNAME_ATTRIBUTE_NAME );
     }
 

+ 35 - 3
engine/source/persistence/taml/tamlXmlWriter.cc

@@ -35,8 +35,40 @@ bool TamlXmlWriter::write( FileStream& stream, const TamlWriteNode* pTamlWriteNo
     // Create document.
     TiXmlDocument xmlDocument;
 
-    // Compile root element.
-    xmlDocument.LinkEndChild( compileElement( pTamlWriteNode ) );
+    // Compile the root element.
+    TiXmlElement* pRootElement = compileElement( pTamlWriteNode );
+
+    // Fetch any TAML Schema file reference.
+    const char* pTamlSchemaFile = Con::getVariable( TAML_SCHEMA_VARIABLE );
+
+    // Do we have a schema file reference?
+    if ( pTamlSchemaFile != NULL && *pTamlSchemaFile != 0 )
+    {
+        // Yes, so add namespace attribute to root.
+        pRootElement->SetAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
+
+        // Expand the file-path reference.
+        char schemaFilePathBuffer[1024];
+        Con::expandPath( schemaFilePathBuffer, sizeof(schemaFilePathBuffer), pTamlSchemaFile );
+
+        // Fetch the output path for the Taml file.
+        char outputFileBuffer[1024];
+        dSprintf( outputFileBuffer, sizeof(outputFileBuffer), "%s", mpTaml->getFilePathBuffer() );
+        char* pFileStart = dStrrchr( outputFileBuffer, '/' );
+        if ( pFileStart == NULL )
+            *outputFileBuffer = 0;
+        else
+            *pFileStart = 0;
+
+        // Fetch the schema file-path relative to the output file.
+        StringTableEntry relativeSchemaFilePath = Platform::makeRelativePathName( schemaFilePathBuffer, outputFileBuffer );
+
+        // Add schema location attribute to root.
+        pRootElement->SetAttribute( "xsi:noNamespaceSchemaLocation", relativeSchemaFilePath );
+    }
+
+    // Link the root element.
+    xmlDocument.LinkEndChild( pRootElement );
 
     // Save document to stream.
     return xmlDocument.SaveFile( stream );
@@ -44,7 +76,7 @@ bool TamlXmlWriter::write( FileStream& stream, const TamlWriteNode* pTamlWriteNo
 
 //-----------------------------------------------------------------------------
 
-TiXmlNode* TamlXmlWriter::compileElement( const TamlWriteNode* pTamlWriteNode )
+TiXmlElement* TamlXmlWriter::compileElement( const TamlWriteNode* pTamlWriteNode )
 {
     // Debug Profiling.
     PROFILE_SCOPE(TamlXmlWriter_CompileElement);

+ 1 - 1
engine/source/persistence/taml/tamlXmlWriter.h

@@ -50,7 +50,7 @@ private:
     Taml* mpTaml;
 
 private:
-    TiXmlNode* compileElement( const TamlWriteNode* pTamlWriteNode );
+    TiXmlElement* compileElement( const TamlWriteNode* pTamlWriteNode );
     void compileAttributes( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode );
     void compileCustomElements( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode );
     void compileCustomNode( TiXmlElement* pXmlElement, const TamlCustomNode* pCustomNode );

+ 3 - 6
engine/source/persistence/taml/taml_ScriptBinding.h

@@ -294,13 +294,10 @@ ConsoleFunction(TamlRead, const char*, 2, 4,    "(filename, [format]) - Read an
 
 //-----------------------------------------------------------------------------
 
-ConsoleFunction(GenerateTamlSchema, bool, 2, 2, "(filename) - Generate a TAML schema file of all engine types.\n"
-                                                "@param filename The schema file to generate.\n"
+ConsoleFunction(GenerateTamlSchema, bool, 1, 1, "() - Generate a TAML schema file of all engine types.\n"
+                                                "The schema file is specified using the console variable '"TAML_SCHEMA_VARIABLE"'.\n"
                                                 "@return Whether the schema file was writtent or not." )
 {
-    // Fetch the filename.
-    const char* pFilename = argv[1];
-
     // Generate the schema.
-    return Taml::generateTamlSchema( pFilename );
+    return Taml::generateTamlSchema();
 }

+ 1 - 0
modules/AppCore/1/scripts/defaultPreferences.cs

@@ -54,6 +54,7 @@ $pref::T2D::ParticlePlayerTimeScale = 1.0;
 $pref::T2D::warnFileDeprecated = 1;
 $pref::T2D::warnSceneOccupancy = 1;
 $pref::T2D::imageAssetGlobalFilterMode = Bilinear;
+$pref::T2D::TAMLSchema="";
 
 /// Video
 $pref::Video::appliedPref = 0;