Browse Source

Merge remote-tracking branch 'upstream/development' into development

Charlie Patterson 12 years ago
parent
commit
88ee6ca
77 changed files with 3295 additions and 1474 deletions
  1. 202 144
      engine/source/2d/assets/ImageAsset.cc
  2. 17 4
      engine/source/2d/assets/ParticleAsset.cc
  3. 1 0
      engine/source/2d/assets/ParticleAsset.h
  4. 17 4
      engine/source/2d/assets/ParticleAssetEmitter.cc
  5. 92 0
      engine/source/2d/assets/ParticleAssetField.cc
  6. 2 0
      engine/source/2d/assets/ParticleAssetField.h
  7. 35 0
      engine/source/2d/assets/ParticleAssetFieldCollection.cc
  8. 2 0
      engine/source/2d/assets/ParticleAssetFieldCollection.h
  9. 1 1
      engine/source/2d/controllers/BuoyancyController.cc
  10. 1 1
      engine/source/2d/controllers/PointForceController.cc
  11. 110 68
      engine/source/2d/core/SpriteBatch.cc
  12. 4 2
      engine/source/2d/core/SpriteBatch.h
  13. 165 2
      engine/source/2d/core/SpriteBatchItem.cc
  14. 9 1
      engine/source/2d/core/SpriteBatchItem.h
  15. 61 21
      engine/source/2d/core/SpriteBatchQuery.cc
  16. 10 6
      engine/source/2d/core/SpriteBatchQuery.h
  17. 114 39
      engine/source/2d/gui/SceneWindow.cc
  18. 25 29
      engine/source/2d/gui/SceneWindow.h
  19. 46 0
      engine/source/2d/gui/SceneWindow_ScriptBinding.h
  20. 156 41
      engine/source/2d/scene/Scene.cc
  21. 2 1
      engine/source/2d/scene/Scene.h
  22. 270 84
      engine/source/2d/scene/Scene_ScriptBinding.h
  23. 305 57
      engine/source/2d/scene/WorldQuery.cc
  24. 30 15
      engine/source/2d/scene/WorldQuery.h
  25. 21 26
      engine/source/2d/sceneobject/CompositeSprite.cc
  26. 3 1
      engine/source/2d/sceneobject/CompositeSprite.h
  27. 18 7
      engine/source/2d/sceneobject/CompositeSprite_ScriptBinding.h
  28. 77 39
      engine/source/2d/sceneobject/SceneObject.cc
  29. 1 3
      engine/source/2d/sceneobject/SceneObject.h
  30. 15 4
      engine/source/2d/sceneobject/SceneObject_ScriptBinding.h
  31. 10 167
      engine/source/2d/sceneobject/ShapeVector.cc
  32. 16 30
      engine/source/2d/sceneobject/ShapeVector.h
  33. 166 33
      engine/source/2d/sceneobject/ShapeVector_ScriptBinding.h
  34. 191 173
      engine/source/component/behaviors/behaviorComponent.cpp
  35. 0 7
      engine/source/component/behaviors/behaviorComponent.h
  36. 30 42
      engine/source/graphics/color.cc
  37. 40 0
      engine/source/graphics/color.h
  38. 4 4
      engine/source/gui/guiColorPicker.h
  39. 7 7
      engine/source/gui/guiPopUpCtrl.cc
  40. 7 7
      engine/source/gui/guiPopUpCtrlEx.cc
  41. 1 1
      engine/source/gui/guiPopUpCtrlEx.h
  42. 285 32
      engine/source/persistence/taml/taml.cc
  43. 8 2
      engine/source/persistence/taml/taml.h
  44. 0 1
      engine/source/persistence/taml/tamlWriteNode.h
  45. 0 1
      engine/source/persistence/taml/tamlXmlReader.h
  46. 35 3
      engine/source/persistence/taml/tamlXmlWriter.cc
  47. 1 1
      engine/source/persistence/taml/tamlXmlWriter.h
  48. 3 6
      engine/source/persistence/taml/taml_ScriptBinding.h
  49. 1 0
      modules/AppCore/1/scripts/defaultPreferences.cs
  50. 3 15
      modules/CompositeSpriteToy/1/main.cs
  51. 173 0
      modules/CompoundObjectsToy/1/main.cs
  52. 10 0
      modules/CompoundObjectsToy/1/module.taml
  53. 4 39
      modules/DeathBallToy/1/main.cs
  54. 2 18
      modules/MoveToToy/1/main.cs
  55. 221 0
      modules/PickingToy/1/main.cs
  56. 10 0
      modules/PickingToy/1/module.taml
  57. 1 12
      modules/PointForceControllerToy/1/main.cs
  58. 2 18
      modules/RotateToToy/1/main.cs
  59. 0 3
      modules/Sandbox/1/assets/gui/ToolsIconDown.asset.taml
  60. 13 0
      modules/Sandbox/1/gui/guiProfiles.cs
  61. 3 0
      modules/Sandbox/1/main.cs
  62. 199 217
      modules/Sandbox/1/scripts/manipulation.cs
  63. 4 1
      modules/Sandbox/1/scripts/toys.cs
  64. 1 15
      modules/ScrollerToy/1/main.cs
  65. 0 1
      modules/SpriteToy/1/main.cs
  66. 1 1
      modules/ToyAssets/1/assets/animations/Ice_Projectile_1Animation.asset.taml
  67. 1 1
      modules/ToyAssets/1/assets/animations/Ice_Projectile_2Animation.asset.taml
  68. 1 1
      modules/ToyAssets/1/assets/animations/Ice_Projectile_3Animation.asset.taml
  69. BIN
      modules/ToyAssets/1/assets/images/BlankCircle.png
  70. BIN
      modules/ToyAssets/1/assets/images/Ice_Projectile_1.png
  71. 8 0
      modules/ToyAssets/1/assets/images/Ice_Projectile_1Sprite.asset.taml
  72. BIN
      modules/ToyAssets/1/assets/images/Ice_Projectile_2.png
  73. 8 0
      modules/ToyAssets/1/assets/images/Ice_Projectile_2Sprite.asset.taml
  74. BIN
      modules/ToyAssets/1/assets/images/Ice_Projectile_3.png
  75. 8 0
      modules/ToyAssets/1/assets/images/Ice_Projectile_3Sprite.asset.taml
  76. 3 0
      modules/ToyAssets/1/assets/images/blankCircle.asset.taml
  77. 2 15
      modules/TruckToy/1/main.cs

+ 202 - 144
engine/source/2d/assets/ImageAsset.cc

@@ -107,10 +107,6 @@ ConsoleSetType( TypeImageAssetPtr )
 
 //------------------------------------------------------------------------------
 
-IMPLEMENT_CONOBJECT(ImageAsset);
-
-//------------------------------------------------------------------------------
-
 static StringTableEntry cellCustomNodeName          = StringTable->insert( "Cells" );
 static StringTableEntry cellNodeName                = StringTable->insert( "Cell" );
 static StringTableEntry cellOffsetName              = StringTable->insert( "Offset" );
@@ -905,146 +901,6 @@ void ImageAsset::onTamlPostWrite( void )
 
 //------------------------------------------------------------------------------
 
-void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(ImageAsset_OnTamlCustomWrite);
-
-    // Call parent.
-    Parent::onTamlCustomWrite( customNodes );
-
-    // Finish if not in explicit mode.
-    if ( !mExplicitMode )
-        return;
-
-    // Add cell custom node.
-    TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeName );
-
-    // Iterate explicit frames.
-    for( typeExplicitFrameAreaVector::iterator frameItr = mExplicitFrames.begin(); frameItr != mExplicitFrames.end(); ++frameItr )
-    {
-        // Fetch pixel area.
-        const FrameArea::PixelArea& pixelArea = *frameItr;
-
-        // Add cell alias.
-        TamlCustomNode* pCellNode = pCustomCellNodes->addNode( cellNodeName );
-
-        // Add cell properties.
-        pCellNode->addField( cellOffsetName, pixelArea.mPixelOffset );
-        pCellNode->addField( cellWidthName, pixelArea.mPixelWidth );
-        pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
-
-    // Call parent.
-    Parent::onTamlCustomRead( customNodes );
-
-    // Find cell custom node.
-    const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeName );
-
-    // Finish if we don't have explicit cells.
-    if ( pCustomCellNodes == NULL )
-        return;
-
-    // Set explicit mode.
-    mExplicitMode = true;
-
-    // Fetch children cell nodes.
-    const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
-
-    // Iterate cells.
-    for( TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr )
-    {
-        // Fetch cell node.
-        TamlCustomNode* pCellNode = *cellNodeItr;
-
-        // Fetch node name.
-        StringTableEntry nodeName = pCellNode->getNodeName();
-
-        // Is this a valid alias?
-        if ( nodeName != cellNodeName )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, cellNodeName );
-            continue;
-        }
-
-        Point2I cellOffset(-1, -1);
-        S32 cellWidth = 0;
-        S32 cellHeight = 0;
-
-        // Fetch fields.
-        const TamlCustomFieldVector& fields = pCellNode->getFields();
-
-        // Iterate property fields.
-        for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
-        {
-            // Fetch field.
-            const TamlCustomField* pField = *fieldItr;
-
-            // Fetch field name.
-            StringTableEntry fieldName = pField->getFieldName();
-
-            // Check common fields.
-            if ( fieldName == cellOffsetName )
-            {
-                pField->getFieldValue( cellOffset );
-            }
-            else if ( fieldName == cellWidthName )
-            {
-                pField->getFieldValue( cellWidth );
-            }
-            else if ( fieldName == cellHeightName )
-            {
-                pField->getFieldValue( cellHeight );
-            }
-            else
-            {
-                // Unknown name so warn.
-                Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName );
-                continue;
-            }
-        }
-
-        // Is cell offset valid?
-        if ( cellOffset.x < 0 || cellOffset.y < 0 )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell offset of '(%d,%d)' is invalid or was not set.", cellOffset.x, cellOffset.y );
-            continue;
-        }
-
-        // Is cell width valid?
-        if ( cellWidth <= 0 )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell width of '%d' is invalid or was not set.", cellWidth );
-            continue;
-        }
-
-        // Is cell height valid?
-        if ( cellHeight <= 0 )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell height of '%d' is invalid or was not set.", cellHeight );
-            continue;
-        }
-
-        // Add explicit frame.
-        FrameArea::PixelArea pixelArea( cellOffset.x, cellOffset.y, cellWidth, cellHeight );
-        mExplicitFrames.push_back( pixelArea );
-    }
-}
-
-//------------------------------------------------------------------------------
-
 void ImageAsset::calculateImage( void )
 {
     // Debug Profiling.
@@ -1318,3 +1174,205 @@ bool ImageAsset::setFilterMode( void* obj, const char* data )
     static_cast<ImageAsset*>(obj)->setFilterMode(getFilterModeEnum(data));
     return false;
 }
+
+//------------------------------------------------------------------------------
+
+void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(ImageAsset_OnTamlCustomWrite);
+
+    // Call parent.
+    Parent::onTamlCustomWrite( customNodes );
+
+    // Finish if not in explicit mode.
+    if ( !mExplicitMode )
+        return;
+
+    // Add cell custom node.
+    TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeName );
+
+    // Iterate explicit frames.
+    for( typeExplicitFrameAreaVector::iterator frameItr = mExplicitFrames.begin(); frameItr != mExplicitFrames.end(); ++frameItr )
+    {
+        // Fetch pixel area.
+        const FrameArea::PixelArea& pixelArea = *frameItr;
+
+        // Add cell alias.
+        TamlCustomNode* pCellNode = pCustomCellNodes->addNode( cellNodeName );
+
+        // Add cell properties.
+        pCellNode->addField( cellOffsetName, pixelArea.mPixelOffset );
+        pCellNode->addField( cellWidthName, pixelArea.mPixelWidth );
+        pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
+
+    // Call parent.
+    Parent::onTamlCustomRead( customNodes );
+
+    // Find cell custom node.
+    const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeName );
+
+    // Finish if we don't have explicit cells.
+    if ( pCustomCellNodes == NULL )
+        return;
+
+    // Set explicit mode.
+    mExplicitMode = true;
+
+    // Fetch children cell nodes.
+    const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
+
+    // Iterate cells.
+    for( TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr )
+    {
+        // Fetch cell node.
+        TamlCustomNode* pCellNode = *cellNodeItr;
+
+        // Fetch node name.
+        StringTableEntry nodeName = pCellNode->getNodeName();
+
+        // Is this a valid alias?
+        if ( nodeName != cellNodeName )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, cellNodeName );
+            continue;
+        }
+
+        Point2I cellOffset(-1, -1);
+        S32 cellWidth = 0;
+        S32 cellHeight = 0;
+
+        // Fetch fields.
+        const TamlCustomFieldVector& fields = pCellNode->getFields();
+
+        // Iterate property fields.
+        for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
+        {
+            // Fetch field.
+            const TamlCustomField* pField = *fieldItr;
+
+            // Fetch field name.
+            StringTableEntry fieldName = pField->getFieldName();
+
+            // Check common fields.
+            if ( fieldName == cellOffsetName )
+            {
+                pField->getFieldValue( cellOffset );
+            }
+            else if ( fieldName == cellWidthName )
+            {
+                pField->getFieldValue( cellWidth );
+            }
+            else if ( fieldName == cellHeightName )
+            {
+                pField->getFieldValue( cellHeight );
+            }
+            else
+            {
+                // Unknown name so warn.
+                Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName );
+                continue;
+            }
+        }
+
+        // Is cell offset valid?
+        if ( cellOffset.x < 0 || cellOffset.y < 0 )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell offset of '(%d,%d)' is invalid or was not set.", cellOffset.x, cellOffset.y );
+            continue;
+        }
+
+        // Is cell width valid?
+        if ( cellWidth <= 0 )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell width of '%d' is invalid or was not set.", cellWidth );
+            continue;
+        }
+
+        // Is cell height valid?
+        if ( cellHeight <= 0 )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell height of '%d' is invalid or was not set.", cellHeight );
+            continue;
+        }
+
+        // Add explicit frame.
+        FrameArea::PixelArea pixelArea( cellOffset.x, cellOffset.y, cellWidth, cellHeight );
+        mExplicitFrames.push_back( pixelArea );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ImageAsset::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ImageAsset::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Create ImageAsset node element.
+    TiXmlElement* pImageAssetNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), cellCustomNodeName );
+    pImageAssetNodeElement->SetAttribute( "name", buffer );
+    pImageAssetNodeElement->SetAttribute( "minOccurs", 0 );
+    pImageAssetNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pImageAssetNodeElement );
+
+    // Create complex type.
+    TiXmlElement* pImageAssetNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pImageAssetNodeElement->LinkEndChild( pImageAssetNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pImageAssetNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pImageAssetNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pImageAssetNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pImageAssetNodeComplexTypeElement->LinkEndChild( pImageAssetNodeChoiceElement );
+
+    // Create ImageAsset element.
+    TiXmlElement* pImageAssetElement = new TiXmlElement( "xs:element" );
+    pImageAssetElement->SetAttribute( "name", cellNodeName );
+    pImageAssetElement->SetAttribute( "minOccurs", 0 );
+    pImageAssetElement->SetAttribute( "maxOccurs", 1 );
+    pImageAssetNodeChoiceElement->LinkEndChild( pImageAssetElement );
+
+    // Create complex type Element.
+    TiXmlElement* pImageAssetComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pImageAssetElement->LinkEndChild( pImageAssetComplexTypeElement );
+
+    // Create "Offset" attribute.
+    TiXmlElement* pImageAssetOffset = new TiXmlElement( "xs:attribute" );
+    pImageAssetOffset->SetAttribute( "name", cellOffsetName );
+    pImageAssetOffset->SetAttribute( "type", "Point2I_ConsoleType" );
+    pImageAssetComplexTypeElement->LinkEndChild( pImageAssetOffset );
+
+    // Create "Width" attribute.
+    TiXmlElement* pImageAssetWidth = new TiXmlElement( "xs:attribute" );
+    pImageAssetWidth->SetAttribute( "name", cellWidthName );
+    pImageAssetWidth->SetAttribute( "type", "xs:unsignedInt" );
+    pImageAssetComplexTypeElement->LinkEndChild( pImageAssetWidth );
+
+    // Create "Height" attribute.
+    TiXmlElement* pImageAssetHeight = new TiXmlElement( "xs:attribute" );
+    pImageAssetHeight->SetAttribute( "name", cellHeightName );
+    pImageAssetHeight->SetAttribute( "type", "xs:unsignedInt" );
+    pImageAssetComplexTypeElement->LinkEndChild( pImageAssetHeight );
+}
+
+//------------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(ImageAsset, WriteCustomTamlSchema);

+ 17 - 4
engine/source/2d/assets/ParticleAsset.cc

@@ -119,10 +119,6 @@ ConsoleSetType( TypeParticleAssetPtr )
     Con::warnf( "(TypeParticleAssetPtr) - Cannot set multiple args to a single asset." );
 }
 
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(ParticleAsset);
-
 //------------------------------------------------------------------------------
 
 ParticleAsset::ParticleAsset() :
@@ -493,3 +489,20 @@ void ParticleAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Read the fields.
     mParticleFields.onTamlCustomRead( customNodes );
 }
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAsset::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAsset::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Write the particle asset fields.
+    ParticleAsset particleAsset;
+    particleAsset.getParticleFields().WriteCustomTamlSchema( pClassRep, pParentElement );
+}
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA(ParticleAsset, WriteCustomTamlSchema);

+ 1 - 0
engine/source/2d/assets/ParticleAsset.h

@@ -45,6 +45,7 @@ class ParticleAsset : public AssetBase, public TamlChildren
 {
 private:
     typedef AssetBase  Parent;
+    typedef ParticleAssetEmitter Children;
     typedef Vector<ParticleAssetEmitter*> typeEmitterVector;
 
 public:

+ 17 - 4
engine/source/2d/assets/ParticleAssetEmitter.cc

@@ -128,10 +128,6 @@ const char* ParticleAssetEmitter::getOrientationTypeDescription( const ParticleO
 
 //------------------------------------------------------------------------------
 
-IMPLEMENT_CONOBJECT(ParticleAssetEmitter);
-
-//------------------------------------------------------------------------------
-
 ParticleAssetEmitter::ParticleAssetEmitter() :
                             mEmitterName( StringTable->EmptyString ),
                             mOwner( NULL ),
@@ -509,3 +505,20 @@ void ParticleAssetEmitter::onTamlCustomRead( const TamlCustomNodes& customNodes
     mParticleFields.onTamlCustomRead( customNodes );
 }
 
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAssetEmitter::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAssetEmitter::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Write the particle asset emitter fields.
+    ParticleAssetEmitter particleAssetEmitter;
+    particleAssetEmitter.getParticleFields().WriteCustomTamlSchema( pClassRep, pParentElement );
+}
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(ParticleAssetEmitter, WriteCustomTamlSchema);

+ 92 - 0
engine/source/2d/assets/ParticleAssetField.cc

@@ -682,3 +682,95 @@ void ParticleAssetField::onTamlCustomRead( const TamlCustomNode* pCustomNode )
     // Set the data keys.
     mDataKeys = keys;
 }
+
+//-----------------------------------------------------------------------------
+
+void ParticleAssetField::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAssetField::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAssetField::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create Field element.
+    TiXmlElement* pFieldElement = new TiXmlElement( "xs:element" );
+    pFieldElement->SetAttribute( "name", getFieldName() );
+    pFieldElement->SetAttribute( "minOccurs", 0 );
+    pFieldElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pFieldElement );
+
+    // Create complex type Element.
+    TiXmlElement* pFieldComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pFieldElement->LinkEndChild( pFieldComplexTypeElement );
+
+    // Create choice element.
+    TiXmlElement* pFieldChoiceElement = new TiXmlElement( "xs:choice" );
+    pFieldChoiceElement->SetAttribute( "minOccurs", 0 );
+    pFieldChoiceElement->SetAttribute( "maxOccurs", 1 );
+    pFieldComplexTypeElement->LinkEndChild( pFieldChoiceElement );
+
+    // Create key element.
+    TiXmlElement* pKeyElement = new TiXmlElement( "xs:element" );
+    pKeyElement->SetAttribute( "name", particleAssetFieldDataKeyName );
+    pKeyElement->SetAttribute( "minOccurs", 0 );
+    pKeyElement->SetAttribute( "maxOccurs", "unbounded" );
+    pFieldChoiceElement->LinkEndChild( pKeyElement );
+
+    // Create complex type Element.
+    TiXmlElement* pKeyComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pKeyElement->LinkEndChild( pKeyComplexTypeElement );
+
+    // Create "Time" attribute.
+    TiXmlElement* pKeyTimeAttribute = new TiXmlElement( "xs:attribute" );
+    pKeyTimeAttribute->SetAttribute( "name", particleAssetFieldDataKeyTimeName );
+    pKeyComplexTypeElement->LinkEndChild( pKeyTimeAttribute );
+    TiXmlElement* pKeyTimeSimpleType = new TiXmlElement( "xs:simpleType" );
+    pKeyTimeAttribute->LinkEndChild( pKeyTimeSimpleType );
+    TiXmlElement* pKeyTimeRestriction = new TiXmlElement( "xs:restriction" );
+    pKeyTimeRestriction->SetAttribute( "base", "xs:float" );
+    pKeyTimeSimpleType->LinkEndChild( pKeyTimeRestriction );
+    TiXmlElement* pKeyTimeMinRestriction = new TiXmlElement( "xs:minInclusive" );
+    pKeyTimeMinRestriction->SetAttribute( "value", "0" );
+    pKeyTimeRestriction->LinkEndChild( pKeyTimeMinRestriction );
+
+    // Create "Value" attribute.
+    TiXmlElement* pKeyValueAttribute = new TiXmlElement( "xs:attribute" );
+    pKeyValueAttribute->SetAttribute( "name", particleAssetFieldDataKeyValueName );
+    pKeyValueAttribute->SetAttribute( "type", "xs:float" );
+    pKeyComplexTypeElement->LinkEndChild( pKeyValueAttribute );
+
+    // Create "Min Value" attribute.
+    TiXmlElement* pFieldMinValue = new TiXmlElement( "xs:attribute" );
+    pFieldMinValue->SetAttribute( "name", particleAssetFieldMinValueName );
+    pFieldMinValue->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldMinValue );
+
+    // Create "Max Value" attribute.
+    TiXmlElement* pFieldMaxValue = new TiXmlElement( "xs:attribute" );
+    pFieldMaxValue->SetAttribute( "name", particleAssetFieldMaxValueName );
+    pFieldMaxValue->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldMaxValue );
+
+    // Create "Max Time" attribute.
+    TiXmlElement* pFieldMaxTime = new TiXmlElement( "xs:attribute" );
+    pFieldMaxTime->SetAttribute( "name", particleAssetFieldMaxTimeName );
+    pFieldMaxTime->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldMaxTime );
+
+    // Create "Default Value" attribute.
+    TiXmlElement* pFieldDefaultValue = new TiXmlElement( "xs:attribute" );
+    pFieldDefaultValue->SetAttribute( "name", particleAssetFieldDefaultValueName );
+    pFieldDefaultValue->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldDefaultValue );
+
+    // Create "Value Scale" attribute.
+    TiXmlElement* pFieldValueScale = new TiXmlElement( "xs:attribute" );
+    pFieldValueScale->SetAttribute( "name", particleAssetFieldValueScaleName );
+    pFieldValueScale->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldValueScale );
+
+    // Create "Repeat Time" attribute.
+    TiXmlElement* pFieldRepeatTime = new TiXmlElement( "xs:attribute" );
+    pFieldRepeatTime->SetAttribute( "name", particleAssetFieldRepeatTimeName );
+    pFieldRepeatTime->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldRepeatTime );
+}

+ 2 - 0
engine/source/2d/assets/ParticleAssetField.h

@@ -111,6 +111,8 @@ public:
 
     void onTamlCustomWrite( TamlCustomNode* pCustomNode  );
     void onTamlCustomRead( const TamlCustomNode* pCustomNode );
+
+    void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
 };
 
 //-----------------------------------------------------------------------------

+ 35 - 0
engine/source/2d/assets/ParticleAssetFieldCollection.cc

@@ -482,5 +482,40 @@ void ParticleAssetFieldCollection::onTamlCustomRead( const TamlCustomNodes& cust
     }
 }
 
+//-----------------------------------------------------------------------------
+
+void ParticleAssetFieldCollection::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement ) const
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAssetFieldCollection::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAssetFieldCollection::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Create Fields node element.
+    TiXmlElement* pFieldsNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), particleAssetFieldNodeName );
+    pFieldsNodeElement->SetAttribute( "name", buffer );
+    pFieldsNodeElement->SetAttribute( "minOccurs", 0 );
+    pFieldsNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pFieldsNodeElement );
+
+    // Create complex type.
+    TiXmlElement* pFieldsNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pFieldsNodeElement->LinkEndChild( pFieldsNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pFieldsNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pFieldsNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pFieldsNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pFieldsNodeComplexTypeElement->LinkEndChild( pFieldsNodeChoiceElement );
+
+    // Iterate the fields.
+    for( typeFieldHash::const_iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
+    {
+        // Write schema for the field.
+        fieldItr->value->WriteCustomTamlSchema( pClassRep, pFieldsNodeChoiceElement );
+    }
+}
 
 

+ 2 - 0
engine/source/2d/assets/ParticleAssetFieldCollection.h

@@ -83,6 +83,8 @@ public:
 
     void onTamlCustomWrite( TamlCustomNodes& customNodes );
     void onTamlCustomRead( const TamlCustomNodes& customNodes );
+
+    void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement ) const;
 };
 
 #endif // ParticleAssetFieldCollection

+ 1 - 1
engine/source/2d/controllers/BuoyancyController.cc

@@ -107,7 +107,7 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
     WorldQuery* pWorldQuery = prepareQueryFilter( pScene );
 
     // Query for candidate objects.
-    pWorldQuery->anyQueryArea( mFluidArea ); 
+    pWorldQuery->anyQueryAABB( mFluidArea ); 
 
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();

+ 1 - 1
engine/source/2d/controllers/PointForceController.cc

@@ -112,7 +112,7 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
     aabb.upperBound.Set( currentPosition.x + mRadius, currentPosition.y + mRadius );
 
     // Query for candidate objects.
-    pWorldQuery->anyQueryArea( aabb ); 
+    pWorldQuery->anyQueryAABB( aabb ); 
 
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();

+ 110 - 68
engine/source/2d/core/SpriteBatch.cc

@@ -34,6 +34,10 @@
 
 //------------------------------------------------------------------------------
 
+static StringTableEntry spritesNodeName = StringTable->insert( "Sprites" );
+
+//------------------------------------------------------------------------------
+
 SpriteBatch::SpriteBatch() :
     mMasterBatchId( 0 ),
     mSelectedSprite( NULL ),
@@ -105,7 +109,7 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
         SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
 
         // Perform query.
-        pSpriteBatchQuery->renderQueryArea( localAABB );
+        pSpriteBatchQuery->queryArea( localAABB, false );
 
         // Debug Profiling.
         PROFILE_END(); // SpriteBatch_PrepareRenderQuery
@@ -1228,38 +1232,106 @@ void SpriteBatch::destroySpriteBatchQuery( void )
 
     // Finish if sprite clipping 
     delete mpSpriteBatchQuery;
+    mpSpriteBatchQuery = NULL;
+}
+
+//------------------------------------------------------------------------------
+
+bool SpriteBatch::destroySprite( const U32 batchId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(SpriteBatch_DestroySprite);
+
+    // Find sprite.
+    typeSpriteBatchHash::iterator spriteItr = mSprites.find( batchId );
+
+    // Finish if sprite not found.
+    if ( spriteItr == mSprites.end() )
+        return false;
+
+    // Find sprite.    
+    SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
+
+    // Sanity!
+    AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch::destroySprite() - Found sprite but it was NULL." );
+
+    // Cache sprite.
+    SpriteBatchItemFactory.cacheObject( pSpriteBatchItem );
+
+    // Remove from sprites.
+    mSprites.erase( batchId );
+
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+bool SpriteBatch::checkSpriteSelected( void ) const
+{
+    // Finish if a sprite is selected.
+    if ( mSelectedSprite != NULL )
+        return true;
+
+    // No, so warn,
+    Con::warnf( "Cannot perform sprite operation no sprite is selected." );
+
+    return false;
+}
+
+//------------------------------------------------------------------------------
+
+b2AABB SpriteBatch::calculateLocalAABB( const b2AABB& renderAABB )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(SpriteBatch_CalculateLocalAABB);
+
+    // Calculate local OOBB.
+    b2Vec2 localOOBB[4];
+    CoreMath::mAABBtoOOBB( renderAABB, localOOBB );
+    CoreMath::mCalculateInverseOOBB( localOOBB, mBatchTransform, localOOBB );
+
+    // Calculate local AABB.
+    b2AABB localAABB;
+    CoreMath::mOOBBtoAABB( localOOBB, localAABB );
+    
+    return localAABB;
 }
 
 //------------------------------------------------------------------------------
 
-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 +1346,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 );
@@ -1312,62 +1384,32 @@ void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
 
 //------------------------------------------------------------------------------
 
-bool SpriteBatch::destroySprite( const U32 batchId )
+void SpriteBatch::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
-    // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatch_DestroySprite);
-
-    // Find sprite.
-    typeSpriteBatchHash::iterator spriteItr = mSprites.find( batchId );
-
-    // Finish if sprite not found.
-    if ( spriteItr == mSprites.end() )
-        return false;
-
-    // Find sprite.    
-    SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
-
     // Sanity!
-    AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch::destroySprite() - Found sprite but it was NULL." );
-
-    // Cache sprite.
-    SpriteBatchItemFactory.cacheObject( pSpriteBatchItem );
-
-    // Remove from sprites.
-    mSprites.erase( batchId );
-
-    return true;
-}
-
-//------------------------------------------------------------------------------
-
-bool SpriteBatch::checkSpriteSelected( void ) const
-{
-    // Finish if a sprite is selected.
-    if ( mSelectedSprite != NULL )
-        return true;
-
-    // No, so warn,
-    Con::warnf( "Cannot perform sprite operation no sprite is selected." );
-
-    return false;
-}
-
-//------------------------------------------------------------------------------
-
-b2AABB SpriteBatch::calculateLocalAABB( const b2AABB& renderAABB )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatch_CalculateLocalAABB);
-
-    // Calculate local OOBB.
-    b2Vec2 localOOBB[4];
-    CoreMath::mAABBtoOOBB( renderAABB, localOOBB );
-    CoreMath::mCalculateInverseOOBB( localOOBB, mBatchTransform, localOOBB );
-
-    // Calculate local AABB.
-    b2AABB localAABB;
-    CoreMath::mOOBBtoAABB( localOOBB, localAABB );
+    AssertFatal( pClassRep != NULL,  "SpriteBatch::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SpriteBatch::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Create sprite batch node element.
+    TiXmlElement* pBatchNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), spritesNodeName );
+    pBatchNodeElement->SetAttribute( "name", buffer );
+    pBatchNodeElement->SetAttribute( "minOccurs", 0 );
+    pBatchNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pBatchNodeElement );
+
+    // Create complex type.
+    TiXmlElement* pBatchNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pBatchNodeElement->LinkEndChild( pBatchNodeComplexTypeElement );
     
-    return localAABB;
+    // Create choice element.
+    TiXmlElement* pBatchNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pBatchNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pBatchNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pBatchNodeComplexTypeElement->LinkEndChild( pBatchNodeChoiceElement );
+
+    // Write sprite batch item.
+    SpriteBatchItem::WriteCustomTamlSchema( pClassRep, pBatchNodeChoiceElement );
 }

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

@@ -179,6 +179,8 @@ public:
     void setSpriteName( const char* pName );
     StringTableEntry getSpriteName( void ) const;
 
+    static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
+
 protected:
     SpriteBatchItem* createSprite( void );
     SpriteBatchItem* findSpritePosition( const SpriteBatchItem::LogicalPosition& logicalPosition );
@@ -193,8 +195,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 );

+ 165 - 2
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() );
@@ -377,7 +382,7 @@ void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
 
     // Write source blend factor.
     if ( mBlendMode && mSrcBlendFactor != GL_SRC_ALPHA )
-        pSpriteNode->addField( spriteBlendModeName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
+        pSpriteNode->addField( spriteSrcBlendFactorName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
         
     // Write destination blend factor.
     if ( mBlendMode && mDstBlendFactor != GL_ONE_MINUS_SRC_ALPHA )
@@ -551,3 +556,161 @@ void SpriteBatchItem::onTamlCustomRead( const TamlCustomNode* pSpriteNode )
     if ( spriteChildren.size() == 1 )
         setDataObject( spriteChildren[0]->getProxyObject<SimObject>(true) );
 }
+
+//------------------------------------------------------------------------------
+
+void SpriteBatchItem::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SpriteBatchItem::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SpriteBatchItem::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create batch item element.
+    TiXmlElement* pBatchItemElement = new TiXmlElement( "xs:element" );
+    pBatchItemElement->SetAttribute( "name", spritesItemTypeName );
+    pBatchItemElement->SetAttribute( "minOccurs", 0 );
+    pBatchItemElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pBatchItemElement );
+
+    // Create complex type Element.
+    TiXmlElement* pBatchItemComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pBatchItemElement->LinkEndChild( pBatchItemComplexTypeElement );
+
+    // Create "Name" attribute.
+    TiXmlElement* pBatchItemName = new TiXmlElement( "xs:attribute" );
+    pBatchItemName->SetAttribute( "name", spriteNameName );
+    pBatchItemName->SetAttribute( "type", "xs:string" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemName );
+
+    // "Create "Image" attribute.
+    TiXmlElement* pBatchItemImage = new TiXmlElement( "xs:attribute" );
+    pBatchItemImage->SetAttribute( "name", spriteImageName );
+    pBatchItemImage->SetAttribute( "type", "AssetId_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemImage );
+
+    // "Create "Image Frame" attribute.
+    TiXmlElement* pBatchItemImageFrame = new TiXmlElement( "xs:attribute" );
+    pBatchItemImageFrame->SetAttribute( "name", spriteImageFrameName );
+    pBatchItemImageFrame->SetAttribute( "type", "xs:positiveInteger" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemImageFrame );
+
+    // "Create "Animation" attribute.
+    TiXmlElement* pBatchItemAnimation = new TiXmlElement( "xs:attribute" );
+    pBatchItemAnimation->SetAttribute( "name", spriteAnimationName );
+    pBatchItemAnimation->SetAttribute( "type", "AssetId_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemAnimation );
+
+    // Create "Visible" attribute.
+    TiXmlElement* pBatchItemVisible = new TiXmlElement( "xs:attribute" );
+    pBatchItemVisible->SetAttribute( "name", spriteVisibleName );
+    pBatchItemVisible->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemVisible );
+
+    // Create "Local Position" attribute.
+    TiXmlElement* pBatchItemPosition = new TiXmlElement( "xs:attribute" );
+    pBatchItemPosition->SetAttribute( "name", spriteLocalPositionName );
+    pBatchItemPosition->SetAttribute( "type", "Vector2_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemPosition );
+
+    // Create "Size" attribute.
+    TiXmlElement* pBatchItemSize = new TiXmlElement( "xs:attribute" );
+    pBatchItemSize->SetAttribute( "name", spriteSizeName );
+    pBatchItemSize->SetAttribute( "type", "Vector2_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemSize );
+
+    // Create "Local Angle" attribute.
+    TiXmlElement* pBatchItemAngle = new TiXmlElement( "xs:attribute" );
+    pBatchItemAngle->SetAttribute( "name", spriteLocalAngleName );
+    pBatchItemAngle->SetAttribute( "type", "xs:float" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemAngle );
+
+    // Create "Depth" attribute.
+    TiXmlElement* pBatchItemDepth = new TiXmlElement( "xs:attribute" );
+    pBatchItemDepth->SetAttribute( "name", spriteDepthName );
+    pBatchItemDepth->SetAttribute( "type", "xs:float" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemDepth );
+
+    // Create "FlipX" attribute.
+    TiXmlElement* pBatchItemFlipX = new TiXmlElement( "xs:attribute" );
+    pBatchItemFlipX->SetAttribute( "name", spriteFlipXName );
+    pBatchItemFlipX->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemFlipX );
+
+    // Create "FlipY" attribute.
+    TiXmlElement* pBatchItemFlipY = new TiXmlElement( "xs:attribute" );
+    pBatchItemFlipY->SetAttribute( "name", spriteFlipYName );
+    pBatchItemFlipY->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemFlipY );
+
+    // Create "Sort Point" attribute.
+    TiXmlElement* pBatchItemSortPoint = new TiXmlElement( "xs:attribute" );
+    pBatchItemSortPoint->SetAttribute( "name", spriteSortPointName );
+    pBatchItemSortPoint->SetAttribute( "type", "Vector2_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemSortPoint );
+
+    // Create "Render Group" attribute.
+    TiXmlElement* pBatchItemRenderGroup = new TiXmlElement( "xs:attribute" );
+    pBatchItemRenderGroup->SetAttribute( "name", spriteRenderGroupName );
+    pBatchItemRenderGroup->SetAttribute( "type", "xs:string" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemRenderGroup );
+
+    // Create "Blend Mode" attribute.
+    TiXmlElement* pBatchItemBlendMode = new TiXmlElement( "xs:attribute" );
+    pBatchItemBlendMode->SetAttribute( "name", spriteBlendModeName );
+    pBatchItemBlendMode->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemBlendMode );
+
+    // Create "Source Blend Factor" attribute.
+    TiXmlElement* pBatchItemSrcBlendFactor = new TiXmlElement( "xs:attribute" );
+    pBatchItemSrcBlendFactor->SetAttribute( "name", spriteSrcBlendFactorName );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemSrcBlendFactor );
+    TiXmlElement* pBatchItemSrcBlendFactorType = new TiXmlElement( "xs:simpleType" );
+    pBatchItemSrcBlendFactor->LinkEndChild( pBatchItemSrcBlendFactorType );
+    TiXmlElement* pBatchItemSrcBlendFactorTypeRestriction = new TiXmlElement( "xs:restriction" );
+    pBatchItemSrcBlendFactorTypeRestriction->SetAttribute( "base", "xs:string" );
+    pBatchItemSrcBlendFactorType->LinkEndChild( pBatchItemSrcBlendFactorTypeRestriction );
+    const S32 srcBlendFactorEnumsCount = srcBlendFactorTable.size;
+    for( S32 index = 0; index < srcBlendFactorEnumsCount; ++index )
+    {
+        // Add enumeration element.
+        TiXmlElement* pSrcBlendFactorEnumeration = new TiXmlElement( "xs:enumeration" );
+        pSrcBlendFactorEnumeration->SetAttribute( "value", srcBlendFactorTable.table[index].label );
+        pBatchItemSrcBlendFactorTypeRestriction->LinkEndChild( pSrcBlendFactorEnumeration );
+    }
+
+    // Create "Destination Blend Factor" attribute.
+    TiXmlElement* pBatchItemDstBlendFactor = new TiXmlElement( "xs:attribute" );
+    pBatchItemDstBlendFactor->SetAttribute( "name", spriteDstBlendFactorName );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemDstBlendFactor );
+    TiXmlElement* pBatchItemDstBlendFactorType = new TiXmlElement( "xs:simpleType" );
+    pBatchItemDstBlendFactor->LinkEndChild( pBatchItemDstBlendFactorType );
+    TiXmlElement* pBatchItemDstBlendFactorTypeRestriction = new TiXmlElement( "xs:restriction" );
+    pBatchItemDstBlendFactorTypeRestriction->SetAttribute( "base", "xs:string" );
+    pBatchItemDstBlendFactorType->LinkEndChild( pBatchItemDstBlendFactorTypeRestriction );
+    const S32 dstBlendFactorEnumsCount = dstBlendFactorTable.size;
+    for( S32 index = 0; index < dstBlendFactorEnumsCount; ++index )
+    {
+        // Add enumeration element.
+        TiXmlElement* pDstBlendFactorEnumeration = new TiXmlElement( "xs:enumeration" );
+        pDstBlendFactorEnumeration->SetAttribute( "value", dstBlendFactorTable.table[index].label );
+        pBatchItemDstBlendFactorTypeRestriction->LinkEndChild( pDstBlendFactorEnumeration );
+    }
+
+    // Create "Blend Color" attribute.
+    TiXmlElement* pBatchItemBlendColor = new TiXmlElement( "xs:attribute" );
+    pBatchItemBlendColor->SetAttribute( "name", spriteBlendColorName );
+    pBatchItemBlendColor->SetAttribute( "type", "Color_Enums" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemBlendColor );
+
+    // Create "Alpha Test" attribute.
+    TiXmlElement* pBatchItemAlphaTest = new TiXmlElement( "xs:attribute" );
+    pBatchItemAlphaTest->SetAttribute( "name", spriteAlphaTestName );
+    pBatchItemAlphaTest->SetAttribute( "type", "xs:float" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemAlphaTest );
+
+    // Create "Logical Position" attribute.
+    TiXmlElement* pBatchItemLogicalPosition = new TiXmlElement( "xs:attribute" );
+    pBatchItemLogicalPosition->SetAttribute( "name", spriteLogicalPositionName );
+    pBatchItemLogicalPosition->SetAttribute( "type", "xs:string" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemLogicalPosition );
+}

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

@@ -34,6 +34,10 @@ class SceneRenderRequest;
 
 //------------------------------------------------------------------------------  
 
+extern StringTableEntry spritesItemTypeName;
+
+//------------------------------------------------------------------------------  
+
 class SpriteBatchItem : public ImageFrameProvider
 {
     friend class SpriteBatch;
@@ -287,9 +291,13 @@ public:
 
     virtual void copyTo( SpriteBatchItem* pSpriteBatchItem ) const;
 
+    inline const Vector2* getRenderOOBB( void ) const { return mRenderOOBB; }
+
     void prepareRender( SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
     void render( BatchRender* pBatchRenderer, const SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
 
+    static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
+
 protected:
     void setBatchParent( SpriteBatch* pSpriteBatch, const U32 batchId );
     inline void setProxyId( const S32 proxyId ) { mProxyId = proxyId; }
@@ -297,7 +305,7 @@ protected:
     void updateLocalTransform( void );
     void updateWorldTransform( const U32 batchTransformId );
 
-    void onTamlCustomWrite( TamlCustomNode* pSpriteNode );
+    void onTamlCustomWrite( TamlCustomNode* pParentNode );
     void onTamlCustomRead( const TamlCustomNode* pSpriteNode );
 };
 

+ 61 - 21
engine/source/2d/core/SpriteBatchQuery.cc

@@ -39,8 +39,8 @@ SpriteBatchQuery::SpriteBatchQuery( SpriteBatch* pSpriteBatch ) :
         mpSpriteBatch(pSpriteBatch),
         mIsRaycastQueryResult(false),
         mMasterQueryKey(0),
-        mCheckFixturePoint(false),
-        mFixturePoint(0.0f, 0.0f)
+        mCheckPoint(false),
+        mComparePoint(0.0f, 0.0f)
 {
     // Set debug associations.
     VECTOR_SET_ASSOCIATION( mQueryResults );
@@ -81,10 +81,10 @@ bool SpriteBatchQuery::update( SpriteBatchItem* pSpriteBatchItem, const b2AABB&
 
 //-----------------------------------------------------------------------------
 
-U32 SpriteBatchQuery::renderQueryArea( const b2AABB& aabb )
+U32 SpriteBatchQuery::queryArea( const b2AABB& aabb, const bool targetOOBB )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryArea);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryArea);
 
     mMasterQueryKey++;
 
@@ -92,17 +92,26 @@ U32 SpriteBatchQuery::renderQueryArea( const b2AABB& aabb )
     mIsRaycastQueryResult = false;
 
     // Query.
+    b2Vec2 verts[4];
+    verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+    verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+    verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+    verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+    mComparePolygonShape.Set( verts, 4 );
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = targetOOBB;
     Query( this, aabb );
+    mCheckOOBB = false;
 
     return getQueryResultsCount();
 }
 
 //-----------------------------------------------------------------------------
 
-U32 SpriteBatchQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
+U32 SpriteBatchQuery::queryRay( const Vector2& point1, const Vector2& point2, const bool targetOOBB )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryRay);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryRay);
 
     mMasterQueryKey++;
 
@@ -110,23 +119,23 @@ U32 SpriteBatchQuery::renderQueryRay( const Vector2& point1, const Vector2& poin
     mIsRaycastQueryResult = true;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point1;
-    rayInput.p2 = point2;
-
-    rayInput.maxFraction = 1.0f;
-
-    RayCast( this, rayInput );
+    mCompareRay.p1 = point1;
+    mCompareRay.p2 = point2;
+    mCompareRay.maxFraction = 1.0f;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = targetOOBB;
+    RayCast( this, mCompareRay );
+    mCheckOOBB = false;
 
     return getQueryResultsCount();
 }
 
 //-----------------------------------------------------------------------------
 
-U32 SpriteBatchQuery::renderQueryPoint( const Vector2& point )
+U32 SpriteBatchQuery::queryPoint( const Vector2& point, const bool targetOOBB )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryPoint);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryPoint);
 
     mMasterQueryKey++;
 
@@ -134,12 +143,13 @@ U32 SpriteBatchQuery::renderQueryPoint( const Vector2& point )
     mIsRaycastQueryResult = false;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point;
-    rayInput.p2 = b2Vec2( point.x + b2_linearSlop, point.y + b2_linearSlop );
-    rayInput.maxFraction = 1.0f;
-
-    RayCast( this, rayInput );
+    b2AABB aabb;
+    aabb.lowerBound = point;
+    aabb.upperBound = point;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = targetOOBB;
+    Query( this, aabb );
+    mCheckOOBB = false;
 
     return getQueryResultsCount();
 }
@@ -180,6 +190,25 @@ bool SpriteBatchQuery::QueryCallback( S32 proxyId )
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
         return true;
 
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+            // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSpriteBatchItem->getRenderOOBB(), 4);
+
+        if ( mCheckPoint )
+        {
+            if ( !oobb.TestPoint( mCompareTransform, mComparePoint ) )
+                return true;
+        }
+        else
+        {
+            if ( !b2TestOverlap( &mComparePolygonShape, 0, &oobb, 0, mCompareTransform, mCompareTransform ) )
+                return true;
+        }
+    }
+
     // Tag with world query key.
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
 
@@ -203,6 +232,17 @@ F32 SpriteBatchQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
         return 1.0f;
 
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+        // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSpriteBatchItem->getRenderOOBB(), 4);
+        b2RayCastOutput rayOutput;
+        if ( !oobb.RayCast( &rayOutput, mCompareRay, mCompareTransform, 0 ) )
+            return true;
+    }
+
     // Tag with world query key.
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
 

+ 10 - 6
engine/source/2d/core/SpriteBatchQuery.h

@@ -48,10 +48,10 @@ public:
     void            remove( SpriteBatchItem* pSpriteBatchItem );
     bool            update( SpriteBatchItem* pSpriteBatchItem, const b2AABB& aabb, const b2Vec2& displacement );
 
-    //// Render queries.
-    U32             renderQueryArea( const b2AABB& aabb );
-    U32             renderQueryRay( const Vector2& point1, const Vector2& point2 );
-    U32             renderQueryPoint( const Vector2& point );
+    //// Spatial queries.
+    U32             queryArea( const b2AABB& aabb, const bool targetOOBB );
+    U32             queryRay( const Vector2& point1, const Vector2& point2, const bool targetOOBB );
+    U32             queryPoint( const Vector2& point, const bool targetOOBB );
  
     /// Results.
     void            clearQuery( void );
@@ -74,8 +74,12 @@ private:
 
 private:
     SpriteBatch*                mpSpriteBatch;
-    bool                        mCheckFixturePoint;
-    b2Vec2                      mFixturePoint;
+    b2PolygonShape              mComparePolygonShape;
+    b2RayCastInput              mCompareRay;
+    b2Vec2                      mComparePoint;
+    b2Transform                 mCompareTransform;
+    bool                        mCheckOOBB;
+    bool                        mCheckPoint;
     typeSpriteBatchQueryResultVector mQueryResults;
     bool                        mIsRaycastQueryResult;
     typeSceneObjectVector       mAlwaysInScopeSet;

+ 114 - 39
engine/source/2d/gui/SceneWindow.cc

@@ -40,6 +40,28 @@
 // Debug Profiling.
 #include "debug/profiler.h"
 
+// Input event names.
+static StringTableEntry inputEventEnterName            = StringTable->insert("onTouchEnter");
+static StringTableEntry inputEventLeaveName            = StringTable->insert("onTouchLeave");
+static StringTableEntry inputEventDownName             = StringTable->insert("onTouchDown");
+static StringTableEntry inputEventUpName               = StringTable->insert("onTouchUp");
+static StringTableEntry inputEventMovedName            = StringTable->insert("onTouchMoved");
+static StringTableEntry inputEventDraggedName          = StringTable->insert("onTouchDragged");
+
+static StringTableEntry mouseEventMiddleMouseDownName   = StringTable->insert("onMiddleMouseDown");
+static StringTableEntry mouseEventMiddleMouseUpName     = StringTable->insert("onMiddleMouseUp");
+static StringTableEntry mouseEventMiddleMouseDraggedName= StringTable->insert("onMiddleMouseDragged");
+
+static StringTableEntry mouseEventRightMouseDownName   = StringTable->insert("onRightMouseDown");
+static StringTableEntry mouseEventRightMouseUpName     = StringTable->insert("onRightMouseUp");
+static StringTableEntry mouseEventRightMouseDraggedName= StringTable->insert("onRightMouseDragged");
+
+static StringTableEntry mouseEventWheelUpName          = StringTable->insert("onMouseWheelUp");
+static StringTableEntry mouseEventWheelDownName        = StringTable->insert("onMouseWheelDown");
+
+static StringTableEntry mouseEventEnterName            = StringTable->insert("onMouseEnter");
+static StringTableEntry mouseEventLeaveName            = StringTable->insert("onMouseLeave");
+
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_CONOBJECT(SceneWindow);
@@ -99,23 +121,6 @@ SceneWindow::SceneWindow() :    mpScene(NULL),
     VECTOR_SET_ASSOCIATION( mInputEventEntering );
     VECTOR_SET_ASSOCIATION( mInputEventLeaving );    
 
-    // Touch input event names.
-    mInputEventDownName             = StringTable->insert("onTouchDown");
-    mInputEventUpName               = StringTable->insert("onTouchUp");
-    mInputEventMovedName            = StringTable->insert("onTouchMoved");
-    mInputEventDraggedName          = StringTable->insert("onTouchDragged");
-    mInputEventEnterName            = StringTable->insert("onTouchEnter");
-    mInputEventLeaveName            = StringTable->insert("onTouchLeave");
-
-    // Mouse input event names.
-    mMouseEventRightMouseDownName   = StringTable->insert("onRightMouseDown");
-    mMouseEventRightMouseUpName     = StringTable->insert("onRightMouseUp");
-    mMouseEventRightMouseDraggedName= StringTable->insert("onRightMouseDragged");
-    mMouseEventWheelUpName          = StringTable->insert("onMouseWheelUp");
-    mMouseEventWheelDownName        = StringTable->insert("onMouseWheelDown");
-    mMouseEventEnterName            = StringTable->insert("onMouseEnter");
-    mMouseEventLeaveName            = StringTable->insert("onMouseLeave");
-
     // Turn-on Tick Processing.
     setProcessTicks( true );
 }
@@ -130,9 +135,14 @@ SceneWindow::~SceneWindow()
 
 bool SceneWindow::onAdd()
 {
+    // Call parent.
     if(!Parent::onAdd())
         return false;
 
+    // Register input sets.
+    mInputEventWatching.registerObject();
+    mInputListeners.registerObject();
+
     // Reset the camera position.
     setCameraPosition( Vector2::getZero() );
 
@@ -156,6 +166,10 @@ void SceneWindow::onRemove()
     // Reset Scene.
     resetScene();
 
+    // Unregister input sets.
+    mInputEventWatching.unregisterObject();
+    mInputListeners.unregisterObject();
+
     // Call Parent.
     Parent::onRemove();
 }
@@ -820,6 +834,28 @@ void SceneWindow::setObjectInputEventInvisibleFilter( const bool useInvisible )
 
 //-----------------------------------------------------------------------------
 
+void SceneWindow::addInputListener( SimObject* pSimObject )
+{
+    // Sanity!
+    AssertFatal( pSimObject != NULL, "SceneWindow::addInputEventListener() - Cannot add NULL object as input event listener." );
+
+    // Ignore if the object is already a listener.
+    if ( mInputListeners.find( pSimObject ) != mInputListeners.end() )
+        return;
+
+    // Add as listener.
+    mInputListeners.addObject( pSimObject );
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneWindow::removeInputListener( SimObject* pSimObject )
+{
+    mInputListeners.removeObject( pSimObject );
+}
+
+//-----------------------------------------------------------------------------
+
 void SceneWindow::setMousePosition( const Vector2& mousePosition )
 {
     // Fetch Canvas.
@@ -967,6 +1003,13 @@ void SceneWindow::sendWindowInputEvent( StringTableEntry name, const GuiEvent& e
 
     // Call Scripts.
     Con::executef(this, 4, name, argBuffer[0], argBuffer[1], argBuffer[2]);
+
+    // Iterate listeners.
+    for( SimSet::iterator listenerItr = mInputListeners.begin(); listenerItr != mInputListeners.end(); ++listenerItr )
+    {
+        // Call scripts on listener.
+        Con::executef( *listenerItr, 4, name, argBuffer[0], argBuffer[1], argBuffer[2] );
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -980,10 +1023,10 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
     if ( !getScene() ) return;
 
     // Only process appropriate input events.
-    if ( !( name == mInputEventDownName ||
-            name == mInputEventUpName ||
-            name == mInputEventMovedName ||
-            name == mInputEventDraggedName ) )
+    if ( !( name == inputEventDownName ||
+            name == inputEventUpName ||
+            name == inputEventMovedName ||
+            name == inputEventDraggedName ) )
         return;
 
     // Convert Event-Position into scene coordinates.
@@ -1089,7 +1132,7 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
         SceneObject* pSceneObject = mInputEventLeaving[index];
 
         // Emit event.
-        pSceneObject->onInputEvent( mInputEventLeaveName, event, worldMousePoint );
+        pSceneObject->onInputEvent( inputEventLeaveName, event, worldMousePoint );
 
         // Remove scene object.
         mInputEventWatching.removeObject( pSceneObject );
@@ -1102,10 +1145,10 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
         SceneObject* pSceneObject = mInputEventEntering[index];
 
         // Emit event.
-        pSceneObject->onInputEvent( mInputEventEnterName, event, worldMousePoint );
+        pSceneObject->onInputEvent( inputEventEnterName, event, worldMousePoint );
 
         // Process "moved" or "dragged" events.
-        if ( name == mInputEventMovedName || name == mInputEventDraggedName )
+        if ( name == inputEventMovedName || name == inputEventDraggedName )
             pSceneObject->onInputEvent( name, event, worldMousePoint );
 
         // Add scene object.
@@ -1120,6 +1163,22 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
 
 //-----------------------------------------------------------------------------
 
+void SceneWindow::onMouseEnter( const GuiEvent& event )
+{
+    // Dispatch input event.
+    dispatchInputEvent(mouseEventEnterName, event);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneWindow::onMouseLeave( const GuiEvent& event )
+{
+    // Dispatch input event.
+    dispatchInputEvent(mouseEventLeaveName, event);
+}
+
+//-----------------------------------------------------------------------------
+
 void SceneWindow::onMouseDown( const GuiEvent& event )
 {
     // Lock Mouse (if necessary).
@@ -1127,7 +1186,7 @@ void SceneWindow::onMouseDown( const GuiEvent& event )
         mouseLock();
 
     // Dispatch input event.
-    dispatchInputEvent( mInputEventDownName, event);
+    dispatchInputEvent( inputEventDownName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1139,7 +1198,7 @@ void SceneWindow::onMouseUp( const GuiEvent& event )
         mouseUnlock();
 
     // Dispatch input event.
-    dispatchInputEvent(mInputEventUpName, event);
+    dispatchInputEvent(inputEventUpName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1147,7 +1206,7 @@ void SceneWindow::onMouseUp( const GuiEvent& event )
 void SceneWindow::onMouseMove( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mInputEventMovedName, event);
+    dispatchInputEvent(inputEventMovedName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1155,23 +1214,39 @@ void SceneWindow::onMouseMove( const GuiEvent& event )
 void SceneWindow::onMouseDragged( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mInputEventDraggedName, event);
+    dispatchInputEvent(inputEventDraggedName, event);
 }
 
 //-----------------------------------------------------------------------------
 
-void SceneWindow::onMouseEnter( const GuiEvent& event )
+void SceneWindow::onMiddleMouseDown( const GuiEvent& event )
 {
+    // Lock Mouse (if necessary).
+    if(mLockMouse)
+        mouseLock();
+
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventEnterName, event);
+    dispatchInputEvent(mouseEventMiddleMouseDownName, event);
 }
 
 //-----------------------------------------------------------------------------
 
-void SceneWindow::onMouseLeave( const GuiEvent& event )
+void SceneWindow::onMiddleMouseUp( const GuiEvent& event )
+{
+    // Lock Mouse (if necessary).
+    if(mLockMouse)
+        mouseUnlock();
+
+    // Dispatch input event.
+    dispatchInputEvent(mouseEventMiddleMouseUpName, event);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneWindow::onMiddleMouseDragged( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventLeaveName, event);
+    dispatchInputEvent(mouseEventMiddleMouseDraggedName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1183,7 +1258,7 @@ void SceneWindow::onRightMouseDown( const GuiEvent& event )
         mouseLock();
 
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseDownName, event);
+    dispatchInputEvent(mouseEventRightMouseDownName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1195,7 +1270,7 @@ void SceneWindow::onRightMouseUp( const GuiEvent& event )
         mouseUnlock();
 
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseUpName, event);
+    dispatchInputEvent(mouseEventRightMouseUpName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1203,7 +1278,7 @@ void SceneWindow::onRightMouseUp( const GuiEvent& event )
 void SceneWindow::onRightMouseDragged( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseDraggedName, event);
+    dispatchInputEvent(mouseEventRightMouseDraggedName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1214,7 +1289,7 @@ bool SceneWindow::onMouseWheelUp( const GuiEvent& event )
    Parent::onMouseWheelUp( event );
 
    // Dispatch input event.
-   dispatchInputEvent(mMouseEventWheelUpName, event);
+   dispatchInputEvent(mouseEventWheelUpName, event);
 
    // Return Success.
    return true;
@@ -1228,7 +1303,7 @@ bool SceneWindow::onMouseWheelDown( const GuiEvent& event )
    Parent::onMouseWheelDown( event );
 
    // Dispatch input event.
-   dispatchInputEvent(mMouseEventWheelDownName, event);
+   dispatchInputEvent(mouseEventWheelDownName, event);
 
    // Return Success.
    return true;
@@ -1689,7 +1764,7 @@ void SceneWindow::renderMetricsOverlay( Point2I offset, const RectI& updateRect
     glEnable        ( GL_BLEND );
     glBlendFunc     ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
 
-    // Set banner background colour.
+    // Set banner background color.
     const ColorI& fillColor = mProfile->mFillColor;
     const F32 colorScale = 1.0f / 255.0f;
     glColor4f( fillColor.red * colorScale, fillColor.green * colorScale, fillColor.blue * colorScale, fillColor.alpha * colorScale );
@@ -1726,7 +1801,7 @@ void SceneWindow::renderMetricsOverlay( Point2I offset, const RectI& updateRect
     // Disable Banner Blending.
     glDisable       ( GL_BLEND );
         
-    // Set Debug Text Colour.
+    // Set Debug Text color.
     dglSetBitmapModulation( mProfile->mFontColor );
 
     // ****************************************************************

+ 25 - 29
engine/source/2d/gui/SceneWindow.h

@@ -131,27 +131,11 @@ private:
     U32                 mInputEventGroupMaskFilter;
     U32                 mInputEventLayerMaskFilter;
     bool                mInputEventInvisibleFilter;
-    SimSet              mInputEventWatching;
     typeWorldQueryResultVector mInputEventQuery;
     typeSceneObjectVector mInputEventEntering;
     typeSceneObjectVector mInputEventLeaving;
-
-    // Input event names.
-    StringTableEntry    mInputEventDownName;
-    StringTableEntry    mInputEventUpName;
-    StringTableEntry    mInputEventMovedName;
-    StringTableEntry    mInputEventDraggedName;
-    StringTableEntry    mInputEventEnterName;
-    StringTableEntry    mInputEventLeaveName;
-
-    StringTableEntry    mMouseEventRightMouseDownName;
-    StringTableEntry    mMouseEventRightMouseUpName;
-    StringTableEntry    mMouseEventRightMouseDraggedName;
-    StringTableEntry    mMouseEventWheelUpName;
-    StringTableEntry    mMouseEventWheelDownName;
-    StringTableEntry    mMouseEventEnterName;
-    StringTableEntry    mMouseEventLeaveName;
-
+    SimSet              mInputEventWatching;
+    SimSet              mInputListeners;
 
     /// Render Masks.
     U32                 mRenderLayerMask;
@@ -220,6 +204,9 @@ public:
     inline void clearWatchedInputEvents( void ) { mInputEventWatching.clear(); }
     inline void removeFromInputEventPick(SceneObject* pSceneObject ) { mInputEventWatching.removeObject((SimObject*)pSceneObject); }
 
+    void addInputListener( SimObject* pSimObject );
+    void removeInputListener( SimObject* pSimObject );
+
     /// Coordinate Conversion.
     void windowToScenePoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
     void sceneToWindowPoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
@@ -304,18 +291,27 @@ public:
 
     /// GuiControl
     virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
-    void onMouseDown( const GuiEvent& event );
-    void onMouseUp( const GuiEvent& event );
-    void onMouseMove( const GuiEvent& event );
-    void onMouseDragged( const GuiEvent& event );
-    void onMouseEnter( const GuiEvent& event );
-    void onMouseLeave( const GuiEvent& event );
-    void onRightMouseDown( const GuiEvent& event );
-    void onRightMouseUp( const GuiEvent& event );
-    void onRightMouseDragged( const GuiEvent& event );
-    bool onMouseWheelDown( const GuiEvent &event );
-    bool onMouseWheelUp( const GuiEvent &event );
     virtual void onRender( Point2I offset, const RectI& updateRect );
+
+    virtual void onMouseEnter( const GuiEvent& event );
+    virtual void onMouseLeave( const GuiEvent& event );
+
+    virtual void onMouseDown( const GuiEvent& event );
+    virtual void onMouseUp( const GuiEvent& event );
+    virtual void onMouseMove( const GuiEvent& event );
+    virtual void onMouseDragged( const GuiEvent& event );
+
+    virtual void onMiddleMouseDown(const GuiEvent &event);
+    virtual void onMiddleMouseUp(const GuiEvent &event);
+    virtual void onMiddleMouseDragged(const GuiEvent &event);
+
+    virtual void onRightMouseDown( const GuiEvent& event );
+    virtual void onRightMouseUp( const GuiEvent& event );
+    virtual void onRightMouseDragged( const GuiEvent& event );
+
+    virtual bool onMouseWheelDown( const GuiEvent &event );
+    virtual bool onMouseWheelUp( const GuiEvent &event );
+
     void renderMetricsOverlay( Point2I offset, const RectI& updateRect );
 
     static CameraInterpolationMode getInterpolationModeEnum(const char* label);

+ 46 - 0
engine/source/2d/gui/SceneWindow_ScriptBinding.h

@@ -1146,6 +1146,52 @@ ConsoleMethod(SceneWindow, setObjectInputEventInvisibleFilter, void, 3, 3, "(boo
 
 //-----------------------------------------------------------------------------
 
+ConsoleMethod(SceneWindow, addInputListener, bool, 3, 3,    "(inputListener) Adds an object as an input listener.\n"
+                                                            "@param inputListener The object to add as an input listener.\n"
+                                                            "@return Whether the object was added as an input event listener or not.")
+{
+    // Find the SimObject
+    SimObject* pSimObject = Sim::findObject( argv[2] );
+
+    // Did we find the SimObject?
+    if ( pSimObject == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "SceneWindow::addInputListener() - Could not find the object '%s' to add as an input event listener.", argv[2] );
+        return false;
+    }
+
+    // Add input listener.
+    object->addInputListener( pSimObject );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(SceneWindow, removeInputListener, bool, 3, 3, "(inputListener) Removes an object from being an input listener.\n"
+                                                            "@param inputListener The object to remove as an input listener.\n"
+                                                            "@return Whether the object was removed as an input event listener or not.")
+{
+    // Find the SimObject
+    SimObject* pSimObject = Sim::findObject( argv[2] );
+
+    // Did we find the SimObject?
+    if ( pSimObject == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "SceneWindow::removeInputListener() - Could not find the object '%s' to remove from being an input event listener.", argv[2] );
+        return false;
+    }
+
+    // Remove input listener.
+    object->removeInputListener( pSimObject );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
 ConsoleMethod(SceneWindow, setLockMouse, void, 3, 3, "(bool lockSet) Sets the window mouse-lock status."
               "@return No return value.")
 {

+ 156 - 41
engine/source/2d/scene/Scene.cc

@@ -497,16 +497,16 @@ void Scene::dispatchBeginContactCallbacks( void )
         const F32 tangentImpulse2 = tickContact.mTangentImpulses[1];
 
         // Format objects.
-        char* pSceneObjectABuffer = Con::getArgBuffer( 8 );
-        char* pSceneObjectBBuffer = Con::getArgBuffer( 8 );
-        dSprintf( pSceneObjectABuffer, 8, "%d", pSceneObjectA->getId() );
-        dSprintf( pSceneObjectBBuffer, 8, "%d", pSceneObjectB->getId() );
+        char sceneObjectABuffer[16];
+        char sceneObjectBBuffer[16];
+        dSprintf( sceneObjectABuffer, sizeof(sceneObjectABuffer), "%d", pSceneObjectA->getId() );
+        dSprintf( sceneObjectBBuffer, sizeof(sceneObjectBBuffer), "%d", pSceneObjectB->getId() );
 
         // Format miscellaneous information.
-        char* pMiscInfoBuffer = Con::getArgBuffer(128);
+        char miscInfoBuffer[128];
         if ( pointCount == 2 )
         {
-            dSprintf(pMiscInfoBuffer, 128,
+            dSprintf(miscInfoBuffer, sizeof(miscInfoBuffer),
                 "%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,
@@ -519,7 +519,7 @@ void Scene::dispatchBeginContactCallbacks( void )
         }
         else if ( pointCount == 1 )
         {
-            dSprintf(pMiscInfoBuffer, 128,
+            dSprintf(miscInfoBuffer, sizeof(miscInfoBuffer),
                 "%d %d %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f",
                 shapeIndexA, shapeIndexB,
                 normal.x, normal.y,
@@ -529,7 +529,7 @@ void Scene::dispatchBeginContactCallbacks( void )
         }
         else
         {
-            dSprintf(pMiscInfoBuffer, 64,
+            dSprintf(miscInfoBuffer, sizeof(miscInfoBuffer),
                 "%d %d",
                 shapeIndexA, shapeIndexB );
         }
@@ -540,14 +540,14 @@ void Scene::dispatchBeginContactCallbacks( void )
         {
             // Yes, so perform script callback on the Scene.
             Con::executef( this, 4, "onSceneCollision",
-                pSceneObjectABuffer,
-                pSceneObjectBBuffer,
-                pMiscInfoBuffer );
+                sceneObjectABuffer,
+                sceneObjectBBuffer,
+                miscInfoBuffer );
         }
         else
         {
             // No, so call it on its behaviors.
-            const char* args[5] = { "onSceneCollision", getIdString(), pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
+            const char* args[5] = { "onSceneCollision", "", sceneObjectABuffer, sceneObjectBBuffer, miscInfoBuffer };
             callOnBehaviors( 5, args );
         }
 
@@ -560,14 +560,14 @@ void Scene::dispatchBeginContactCallbacks( void )
             {
                 // Yes, so perform the script callback on it.
                 Con::executef( pSceneObjectA, 3, "onCollision",
-                    pSceneObjectBBuffer,
-                    pMiscInfoBuffer );
+                    sceneObjectBBuffer,
+                    miscInfoBuffer );
             }
             else
             {
                 // No, so call it on its behaviors.
-                const char* args[4] = { "onCollision", pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
-                pSceneObjectA->callOnBehaviors( 4, args );
+                const char* args[5] = { "onCollision", "", sceneObjectABuffer, sceneObjectBBuffer, miscInfoBuffer };
+                pSceneObjectA->callOnBehaviors( 5, args );
             }
         }
 
@@ -580,14 +580,14 @@ void Scene::dispatchBeginContactCallbacks( void )
             {
                 // Yes, so perform the script callback on it.
                 Con::executef( pSceneObjectB, 3, "onCollision",
-                    pSceneObjectABuffer,
-                    pMiscInfoBuffer );
+                    sceneObjectABuffer,
+                    miscInfoBuffer );
             }
             else
             {
                 // No, so call it on its behaviors.
-                const char* args[4] = { "onCollision", pSceneObjectBBuffer, pSceneObjectABuffer, pMiscInfoBuffer };
-                pSceneObjectB->callOnBehaviors( 4, args );
+                const char* args[5] = { "onCollision", "", sceneObjectBBuffer, sceneObjectABuffer, miscInfoBuffer };
+                pSceneObjectB->callOnBehaviors( 5, args );
             }
         }
     }
@@ -637,14 +637,14 @@ void Scene::dispatchEndContactCallbacks( void )
         AssertFatal( shapeIndexB >= 0, "Scene::dispatchEndContactCallbacks() - Cannot find shape index reported on physics proxy of a fixture." );
 
         // Format objects.
-        char* pSceneObjectABuffer = Con::getArgBuffer( 8 );
-        char* pSceneObjectBBuffer = Con::getArgBuffer( 8 );
-        dSprintf( pSceneObjectABuffer, 8, "%d", pSceneObjectA->getId() );
-        dSprintf( pSceneObjectBBuffer, 8, "%d", pSceneObjectB->getId() );
+        char sceneObjectABuffer[16];
+        char sceneObjectBBuffer[16];
+        dSprintf( sceneObjectABuffer, sizeof(sceneObjectABuffer), "%d", pSceneObjectA->getId() );
+        dSprintf( sceneObjectBBuffer, sizeof(sceneObjectBBuffer), "%d", pSceneObjectB->getId() );
 
         // Format miscellaneous information.
-        char* pMiscInfoBuffer = Con::getArgBuffer(32);
-        dSprintf(pMiscInfoBuffer, 32, "%d %d", shapeIndexA, shapeIndexB );
+        char miscInfoBuffer[32];
+        dSprintf(miscInfoBuffer, sizeof(miscInfoBuffer), "%d %d", shapeIndexA, shapeIndexB );
 
         // Does the scene handle the collision callback?
         Namespace* pNamespace = getNamespace();
@@ -652,14 +652,14 @@ void Scene::dispatchEndContactCallbacks( void )
         {
             // Yes, so does the scene handle the collision callback?
             Con::executef( this, 4, "onSceneEndCollision",
-                pSceneObjectABuffer,
-                pSceneObjectBBuffer,
-                pMiscInfoBuffer );
+                sceneObjectABuffer,
+                sceneObjectBBuffer,
+                miscInfoBuffer );
         }
         else
         {
             // No, so call it on its behaviors.
-            const char* args[5] = { "onSceneEndCollision", getIdString(), pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
+            const char* args[5] = { "onSceneEndCollision", "", sceneObjectABuffer, sceneObjectBBuffer, miscInfoBuffer };
             callOnBehaviors( 5, args );
         }
 
@@ -672,14 +672,14 @@ void Scene::dispatchEndContactCallbacks( void )
             {
                 // Yes, so perform the script callback on it.
                 Con::executef( pSceneObjectA, 3, "onEndCollision",
-                    pSceneObjectBBuffer,
-                    pMiscInfoBuffer );
+                    sceneObjectBBuffer,
+                    miscInfoBuffer );
             }
             else
             {
                 // No, so call it on its behaviors.
-                const char* args[4] = { "onEndCollision", pSceneObjectABuffer, pSceneObjectBBuffer, pMiscInfoBuffer };
-                pSceneObjectA->callOnBehaviors( 4, args );
+                const char* args[5] = { "onEndCollision", "", sceneObjectABuffer, sceneObjectBBuffer, miscInfoBuffer };
+                pSceneObjectA->callOnBehaviors( 5, args );
             }
         }
 
@@ -692,14 +692,14 @@ void Scene::dispatchEndContactCallbacks( void )
             {
                 // Yes, so perform the script callback on it.
                 Con::executef( pSceneObjectB, 3, "onEndCollision",
-                    pSceneObjectABuffer,
-                    pMiscInfoBuffer );
+                    sceneObjectABuffer,
+                    miscInfoBuffer );
             }
             else
             {
                 // No, so call it on its behaviors.
-                const char* args[4] = { "onEndCollision", pSceneObjectBBuffer, pSceneObjectABuffer, pMiscInfoBuffer };
-                pSceneObjectB->callOnBehaviors( 4, args );
+                const char* args[5] = { "onEndCollision", "", sceneObjectBBuffer, sceneObjectABuffer, miscInfoBuffer };
+                pSceneObjectB->callOnBehaviors( 5, args );
             }
         }
     }
@@ -991,7 +991,7 @@ void Scene::sceneRender( const SceneRenderState* pSceneRenderState )
     mpWorldQuery->setQueryFilter( queryFilter );
 
     // Query render AABB.
-    mpWorldQuery->renderQueryArea( cameraAABB );
+    mpWorldQuery->aabbQueryAABB( cameraAABB );
 
     // Debug Profiling.
     PROFILE_END();  //Scene_RenderSceneVisibleQuery
@@ -5312,7 +5312,8 @@ b2JointType Scene::getJointTypeEnum(const char* label)
 static EnumTable::Enums pickModeLookup[] =
                 {
                 { Scene::PICK_ANY,          "Any" },
-                { Scene::PICK_SIZE,         "Size" },
+                { Scene::PICK_AABB,         "AABB" },
+                { Scene::PICK_OOBB,         "OOBB" },
                 { Scene::PICK_COLLISION,    "Collision" },
                 };
 
@@ -5350,8 +5351,12 @@ const char* Scene::getPickModeDescription( Scene::PickMode pickMode )
 
 //-----------------------------------------------------------------------------
 
-static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+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.
@@ -5425,6 +5430,116 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
     pDistanceJointElementC->LinkEndChild( pDistanceJointElementD );
 }
 
+//-----------------------------------------------------------------------------
+
+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.
+    TiXmlElement* pControllersNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), controllerCustomNodeName );
+    pControllersNodeElement->SetAttribute( "name", buffer );
+    pControllersNodeElement->SetAttribute( "minOccurs", 0 );
+    pControllersNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pControllersNodeElement );
+    
+    // Create complex type.
+    TiXmlElement* pControllersNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pControllersNodeElement->LinkEndChild( pControllersNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pControllersNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pControllersNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pControllersNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pControllersNodeComplexTypeElement->LinkEndChild( pControllersNodeChoiceElement );
+
+    // Fetch the scene controller type.
+    AbstractClassRep* pPickingSceneControllerType = AbstractClassRep::findClassRep( "PickingSceneController" );
+    AbstractClassRep* pGroupedSceneControllerType = AbstractClassRep::findClassRep( "GroupedSceneController" );
+
+    // Sanity!
+    AssertFatal( pPickingSceneControllerType != NULL, "Scene::WriteControllersCustomTamlScehema() - Cannot find the PickingSceneController type." );
+    AssertFatal( pGroupedSceneControllerType != NULL, "Scene::WriteControllersCustomTamlScehema() - Cannot find the GroupedSceneController type." );
+
+    // Add choice members.
+    for ( AbstractClassRep* pChoiceType = AbstractClassRep::getClassList(); pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass() )
+    {
+        // Skip if not derived from either of the scene controllers.
+        if ( !pChoiceType->isClass( pPickingSceneControllerType ) && !pChoiceType->isClass( pGroupedSceneControllerType ) )
+            continue;
+
+        // Add choice member.
+        TiXmlElement* pChoiceMemberElement = new TiXmlElement( "xs:element" );
+        pChoiceMemberElement->SetAttribute( "name", pChoiceType->getClassName() );
+        dSprintf( buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName() );
+        pChoiceMemberElement->SetAttribute( "type", buffer );
+        pControllersNodeChoiceElement->LinkEndChild( pChoiceMemberElement );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+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.
+    TiXmlElement* pPreloadsNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), assetPreloadNodeName );
+    pPreloadsNodeElement->SetAttribute( "name", buffer );
+    pPreloadsNodeElement->SetAttribute( "minOccurs", 0 );
+    pPreloadsNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pPreloadsNodeElement );
+    
+    // Create complex type.
+    TiXmlElement* pPreloadsNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pPreloadsNodeElement->LinkEndChild( pPreloadsNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pPreloadsNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pPreloadsNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pPreloadsNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pPreloadsNodeComplexTypeElement->LinkEndChild( pPreloadsNodeChoiceElement );
+
+    // Add choice member element.
+    TiXmlElement* pChoiceMemberElement = new TiXmlElement( "xs:element" );
+    pChoiceMemberElement->SetAttribute( "name", assetNodeName );
+    pPreloadsNodeChoiceElement->LinkEndChild( pChoiceMemberElement );
+
+    // Add choice member complex type element.
+    TiXmlElement* pChoiceMemberComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pChoiceMemberElement->LinkEndChild( pChoiceMemberComplexTypeElement );
+
+    // Add choice member attribute element.
+    TiXmlElement* pChoiceAttributeElement = new TiXmlElement( "xs:attribute" );
+    pChoiceAttributeElement->SetAttribute( "name", "Id" );
+    dSprintf( buffer, sizeof(buffer), "%s", "AssetId_ConsoleType" );
+    pChoiceAttributeElement->SetAttribute( "type", buffer );
+    pChoiceMemberComplexTypeElement->LinkEndChild( pChoiceAttributeElement );
+}
+
+//-----------------------------------------------------------------------------
+
+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 );
+}
+
 //------------------------------------------------------------------------------
 
 IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA(Scene, WriteCustomTamlSchema);

+ 2 - 1
engine/source/2d/scene/Scene.h

@@ -198,7 +198,8 @@ public:
         PICK_INVALID,
         ///---
         PICK_ANY,
-        PICK_SIZE,
+        PICK_AABB,
+        PICK_OOBB,
         PICK_COLLISION,
     };
 

+ 270 - 84
engine/source/2d/scene/Scene_ScriptBinding.h

@@ -2305,9 +2305,9 @@ ConsoleMethod(Scene, getMotorJointMaxTorque, F32, 3, 3,  "(jointId) Gets the max
 ConsoleMethod(Scene, pickArea, const char*, 4, 9, "(startx/y, endx/y, [sceneGroupMask], [sceneLayerMask], [pickMode] ) Picks objects intersecting the specified area with optional group/layer masks.\n"
               "@param startx/y The coordinates of the start point as either (\"x y\") or (x,y)\n"
               "@param endx/y The coordinates of the end point as either (\"x y\") or (x,y)\n"
-              "@param sceneGroupMask Optional scene group mask.\n"
-              "@param sceneLayerMask Optional scene layer mask.\n"
-              "@param pickMode Optional mode 'any', 'size' or 'collision' (default is 'size').\n"
+              "@param sceneGroupMask Optional scene group mask.  (-1) or empty string selects all groups.\n"
+              "@param sceneLayerMask Optional scene layer mask.  (-1) or empty string selects all layers.\n"
+              "@param pickMode Optional mode 'any', 'aabb', 'oobb' or 'collision' (default is 'oobb').\n"
               "@return Returns list of object IDs.")
 {
     // Upper left and lower right bound.
@@ -2356,15 +2356,21 @@ ConsoleMethod(Scene, pickArea, const char*, 4, 9, "(startx/y, endx/y, [sceneGrou
     // Calculate scene group mask.
     U32 sceneGroupMask = MASK_ALL;
     if ( (U32)argc > firstArg )
-        sceneGroupMask = dAtoi(argv[firstArg]);
+    {
+        if ( *argv[firstArg] != 0 )
+            sceneGroupMask = dAtoi(argv[firstArg]);
+    }
 
     // Calculate scene layer mask.
     U32 sceneLayerMask = MASK_ALL;
     if ( (U32)argc > (firstArg + 1) )
-        sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    {
+        if ( *argv[firstArg + 1] != 0 )
+            sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    }
 
     // Calculate pick mode.
-    Scene::PickMode pickMode = Scene::PICK_SIZE;
+    Scene::PickMode pickMode = Scene::PICK_OOBB;
     if ( (U32)argc > (firstArg + 2))
     {
         pickMode = Scene::getPickModeEnum(argv[firstArg + 2]);
@@ -2372,7 +2378,7 @@ ConsoleMethod(Scene, pickArea, const char*, 4, 9, "(startx/y, endx/y, [sceneGrou
     if ( pickMode == Scene::PICK_INVALID )
     {
         Con::warnf("Scene::pickArea() - Invalid pick mode of %s", argv[firstArg + 2]);
-        pickMode = Scene::PICK_SIZE;
+        pickMode = Scene::PICK_OOBB;
     }
 
 
@@ -2393,15 +2399,19 @@ ConsoleMethod(Scene, pickArea, const char*, 4, 9, "(startx/y, endx/y, [sceneGrou
     // Perform query.
     if ( pickMode == Scene::PICK_ANY )
     {
-        pWorldQuery->anyQueryArea( aabb );    
+        pWorldQuery->anyQueryAABB( aabb );    
     }
-    else if ( pickMode == Scene::PICK_SIZE )
+    else if ( pickMode == Scene::PICK_AABB )
     {
-        pWorldQuery->renderQueryArea( aabb );    
+        pWorldQuery->aabbQueryAABB( aabb );    
+    }
+    else if ( pickMode == Scene::PICK_OOBB )
+    {
+        pWorldQuery->oobbQueryAABB( aabb );    
     }
     else if ( pickMode == Scene::PICK_COLLISION )
     {
-        pWorldQuery->fixtureQueryArea( aabb );    
+        pWorldQuery->collisionQueryAABB( aabb );    
     }
     else
     {
@@ -2454,9 +2464,9 @@ ConsoleMethod(Scene, pickArea, const char*, 4, 9, "(startx/y, endx/y, [sceneGrou
 ConsoleMethod(Scene, pickRay, const char*, 4, 9, "(startx/y, endx/y, [sceneGroupMask], [sceneLayerMask], [pickMode] ) Picks objects intersecting the specified ray with optional group/layer masks.\n"
               "@param startx/y The coordinates of the start point as either (\"x y\") or (x,y)\n"
               "@param endx/y The coordinates of the end point as either (\"x y\") or (x,y)\n"
-              "@param sceneGroupMask Optional scene group mask.\n"
-              "@param sceneLayerMask Optional scene layer mask.\n"
-              "@param pickMode Optional mode 'any', 'size' or 'collision' (default is 'size').\n"
+              "@param sceneGroupMask Optional scene group mask.  (-1) or empty string selects all groups.\n"
+              "@param sceneLayerMask Optional scene layer mask.  (-1) or empty string selects all layers.\n"
+              "@param pickMode Optional mode 'any', 'aabb', 'oobb' or 'collision' (default is 'oobb').\n"
               "@return Returns list of object IDs.")
 {
     // Upper left and lower right bound.
@@ -2505,15 +2515,21 @@ ConsoleMethod(Scene, pickRay, const char*, 4, 9, "(startx/y, endx/y, [sceneGroup
     // Calculate scene group mask.
     U32 sceneGroupMask = MASK_ALL;
     if ( (U32)argc > firstArg )
-        sceneGroupMask = dAtoi(argv[firstArg]);
+    {
+        if ( *argv[firstArg] != 0 )
+            sceneGroupMask = dAtoi(argv[firstArg]);
+    }
 
     // Calculate scene layer mask.
     U32 sceneLayerMask = MASK_ALL;
     if ( (U32)argc > (firstArg + 1) )
-        sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    {
+        if ( *argv[firstArg + 1] != 0 )
+            sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    }
 
     // Calculate pick mode.
-    Scene::PickMode pickMode = Scene::PICK_SIZE;
+    Scene::PickMode pickMode = Scene::PICK_OOBB;
     if ( (U32)argc > (firstArg + 2))
     {
         pickMode = Scene::getPickModeEnum(argv[firstArg + 2]);
@@ -2521,7 +2537,7 @@ ConsoleMethod(Scene, pickRay, const char*, 4, 9, "(startx/y, endx/y, [sceneGroup
     if ( pickMode == Scene::PICK_INVALID )
     {
         Con::warnf("Scene::pickRay() - Invalid pick mode of %s", argv[firstArg + 2]);
-        pickMode = Scene::PICK_SIZE;
+        pickMode = Scene::PICK_OOBB;
     }
 
 
@@ -2537,13 +2553,17 @@ ConsoleMethod(Scene, pickRay, const char*, 4, 9, "(startx/y, endx/y, [sceneGroup
     {
         pWorldQuery->anyQueryRay( v1, v2 );    
     }
-    else if ( pickMode == Scene::PICK_SIZE )
+    else if ( pickMode == Scene::PICK_AABB )
+    {
+        pWorldQuery->aabbQueryRay( v1, v2 );    
+    }
+    else if ( pickMode == Scene::PICK_OOBB )
     {
-        pWorldQuery->renderQueryRay( v1, v2 );    
+        pWorldQuery->oobbQueryRay( v1, v2 );    
     }
     else if ( pickMode == Scene::PICK_COLLISION )
     {
-        pWorldQuery->fixtureQueryRay( v1, v2 );    
+        pWorldQuery->collisionQueryRay( v1, v2 );    
     }
     else
     {
@@ -2599,67 +2619,71 @@ ConsoleMethod(Scene, pickRay, const char*, 4, 9, "(startx/y, endx/y, [sceneGroup
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(Scene, pickRayCollision, const char*, 4, 8, "(startx/y, endx/y, [sceneGroupMask], [sceneLayerMask] ) Picks objects with collision shapes intersecting the specified ray with optional group/layer masks.\n"
-                "Unlike other pick methods, this returns the complete detail for each object encountered, returning the collision point, normal and fraction of the ray intersection.\n"
-                "@param startx/y The coordinates of the start point as either (\"x y\") or (x,y)\n"
-                "@param endx/y The coordinates of the end point as either (\"x y\") or (x,y)\n"
-                "@param sceneGroupMask Optional scene group mask.\n"
-                "@param sceneLayerMask Optional scene layer mask.\n"
-                "@return Returns a list of objects in blocks of detail items where each block represents a single object and its collision detail in the format:"
-                "<ObjectId PointX PointY NormalX NormalY RayFraction ShapeIndex> <ObjectId PointX PointY NormalX NormalY RayFraction ShapeIndex> <ObjectId PointX PointY NormalX NormalY RayFraction ShapeIndex> etc.\n")
+ConsoleMethod(Scene, pickPoint, const char*, 3, 7, "(x / y, [sceneGroupMask], [sceneLayerMask], [pickMode] ) Picks objects intersecting the specified point with optional group/layer masks.\n"
+              "@param x/y The coordinate of the point as either (\"x y\") or (x,y)\n"
+              "@param sceneGroupMask Optional scene group mask.  (-1) or empty string selects all groups.\n"
+              "@param sceneLayerMask Optional scene layer mask.  (-1) or empty string selects all layers.\n"
+              "@param pickMode Optional mode 'any', 'aabb', 'oobb' or 'collision' (default is 'ooabb').\n"
+              "@return Returns list of object IDs.")
 {
-    // Upper left and lower right bound.
-    Vector2 v1, v2;
+    // The point.
+    Vector2 point;
 
     // The index of the first optional parameter.
     U32 firstArg;
 
-    // Grab the number of elements in the first two parameters.
-    U32 elementCount1 = Utility::mGetStringElementCount(argv[2]);
-    U32 elementCount2 = 1;
-    if (argc > 3)
-        elementCount2 = Utility::mGetStringElementCount(argv[3]);
+    // Grab the number of elements in the first parameter.
+    U32 elementCount = Utility::mGetStringElementCount(argv[2]);
 
-    // ("x1 y1 x2 y2")
-    if ((elementCount1 == 4) && (argc < 9))
+    // ("x y")
+    if ((elementCount == 2) && (argc < 8))
     {
-        v1 = Utility::mGetStringElementVector(argv[2]);
-        v2 = Utility::mGetStringElementVector(argv[2], 2);
+        point = Utility::mGetStringElementVector(argv[2]);
         firstArg = 3;
     }
    
-    // ("x1 y1", "x2 y2")
-    else if ((elementCount1 == 2) && (elementCount2 == 2) && (argc > 3) && (argc < 9))
+    // (x, y)
+    else if ((elementCount == 1) && (argc > 3))
     {
-        v1 = Utility::mGetStringElementVector(argv[2]);
-        v2 = Utility::mGetStringElementVector(argv[3]);
+        point = Vector2(dAtof(argv[2]), dAtof(argv[3]));
         firstArg = 4;
     }
    
-    // (x1, y1, x2, y2)
-    else if (argc > 5)
-    {
-        v1 = Vector2(dAtof(argv[2]), dAtof(argv[3]));
-        v2 = Vector2(dAtof(argv[4]), dAtof(argv[5]));
-        firstArg = 6;
-    }
-   
     // Invalid
     else
     {
-        Con::warnf("Scene::pickRayCollision() - Invalid number of parameters!");
+        Con::warnf("Scene::pickPoint() - Invalid number of parameters!");
         return NULL;
     }
 
     // Calculate scene group mask.
     U32 sceneGroupMask = MASK_ALL;
     if ( (U32)argc > firstArg )
-        sceneGroupMask = dAtoi(argv[firstArg]);
+    {
+        if ( *argv[firstArg] != 0 )
+            sceneGroupMask = dAtoi(argv[firstArg]);
+    }
 
     // Calculate scene layer mask.
     U32 sceneLayerMask = MASK_ALL;
     if ( (U32)argc > (firstArg + 1) )
-        sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    {
+        if ( *argv[firstArg + 1] != 0 )
+            sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    }
+
+    // Calculate pick mode.
+    Scene::PickMode pickMode = Scene::PICK_OOBB;
+    if ( (U32)argc > (firstArg + 2 ))
+    {
+        pickMode = Scene::getPickModeEnum(argv[firstArg + 2]);
+    }
+    if ( pickMode == Scene::PICK_INVALID )
+    {
+        Con::warnf("Scene::pickPoint() - Invalid pick mode of %s", argv[firstArg + 2]);
+        pickMode = Scene::PICK_OOBB;
+    }
+
 
     // Fetch world query and clear results.
     WorldQuery* pWorldQuery = object->getWorldQuery( true );
@@ -2669,10 +2693,26 @@ ConsoleMethod(Scene, pickRayCollision, const char*, 4, 8, "(startx/y, endx/y, [s
     pWorldQuery->setQueryFilter( queryFilter );
 
     // Perform query.
-    pWorldQuery->fixtureQueryRay( v1, v2 );    
-
-    // Sanity!
-    AssertFatal( pWorldQuery->getIsRaycastQueryResult(), "Invalid non-ray-cast query result returned." );
+    if ( pickMode == Scene::PICK_ANY )
+    {
+        pWorldQuery->anyQueryPoint( point );    
+    }
+    else if ( pickMode == Scene::PICK_AABB )
+    {
+        pWorldQuery->aabbQueryPoint( point );    
+    }
+    else if ( pickMode == Scene::PICK_OOBB )
+    {
+        pWorldQuery->oobbQueryPoint( point );    
+    }
+    else if ( pickMode == Scene::PICK_COLLISION )
+    {
+        pWorldQuery->collisionQueryPoint( point );    
+    }
+    else
+    {
+        AssertFatal( false, "Unsupported pick mode." );
+    }
 
     // Fetch result count.
     const U32 resultCount = pWorldQuery->getQueryResultsCount();
@@ -2681,9 +2721,6 @@ ConsoleMethod(Scene, pickRayCollision, const char*, 4, 8, "(startx/y, endx/y, [s
     if ( resultCount == 0 )
         return NULL;
 
-    // Sort ray-cast result.
-    pWorldQuery->sortRaycastQueryResult();
-
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
 
@@ -2699,21 +2736,14 @@ ConsoleMethod(Scene, pickRayCollision, const char*, 4, 8, "(startx/y, endx/y, [s
     // Add Picked Objects to List.
     for ( U32 n = 0; n < resultCount; n++ )
     {
-        // Fetch query result.
-        const WorldQueryResult& queryResult = queryResults[n];
-
-        bufferCount += dSprintf( pBuffer + bufferCount, maxBufferSize-bufferCount, "%d %g %g %g %g %g %d ",
-            queryResult.mpSceneObject->getId(),
-            queryResult.mPoint.x, queryResult.mPoint.y,
-            queryResult.mNormal.x, queryResult.mNormal.y,
-            queryResult.mFraction,
-            queryResult.mShapeIndex );
+        // Output Object ID.
+        bufferCount += dSprintf( pBuffer + bufferCount, maxBufferSize-bufferCount, "%d ", queryResults[n].mpSceneObject->getId() );
 
         // Finish early if we run out of buffer space.
         if ( bufferCount >= maxBufferSize )
         {
             // Warn.
-            Con::warnf("Scene::pickRayCollision() - Too many items picked to return to scripts!");
+            Con::warnf("Scene::pickPoint() - Too many items picked to return to scripts!");
             break;
         }
     }
@@ -2727,11 +2757,12 @@ ConsoleMethod(Scene, pickRayCollision, const char*, 4, 8, "(startx/y, endx/y, [s
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(Scene, pickPoint, const char*, 3, 7, "(x / y, [sceneGroupMask], [sceneLayerMask], [pickMode] ) Picks objects intersecting the specified point with optional group/layer masks.\n"
+ConsoleMethod(Scene, pickCircle, const char*, 4, 8, "(x / y, radius, [sceneGroupMask], [sceneLayerMask], [pickMode] ) Picks objects intersecting the specified circle with optional group/layer masks.\n"
               "@param x/y The coordinate of the point as either (\"x y\") or (x,y)\n"
-              "@param sceneGroupMask Optional scene group mask.\n"
-              "@param sceneLayerMask Optional scene layer mask.\n"
-              "@param pickMode Optional mode 'any', 'size' or 'collision' (default is 'size').\n"
+              "@param radius The radius of the circle.\n"
+              "@param sceneGroupMask Optional scene group mask.  (-1) or empty string selects all groups.\n"
+              "@param sceneLayerMask Optional scene layer mask.  (-1) or empty string selects all layers.\n"
+              "@param pickMode Optional mode 'any', 'aabb', 'oobb' or 'collision' (default is 'ooabb').\n"
               "@return Returns list of object IDs.")
 {
     // The point.
@@ -2764,18 +2795,34 @@ ConsoleMethod(Scene, pickPoint, const char*, 3, 7, "(x / y, [sceneGroupMask], [s
         return NULL;
     }
 
+    // Fetch radius.
+    const F32 radius = dAtof(argv[firstArg++]);
+
+    // Check radius.
+    if ( radius <= 0.0f )
+    {
+        Con::warnf( "Scene::pickCircle()  Radius must be greater than zero." );
+        return StringTable->EmptyString;
+    }
+
     // Calculate scene group mask.
     U32 sceneGroupMask = MASK_ALL;
     if ( (U32)argc > firstArg )
-        sceneGroupMask = dAtoi(argv[firstArg]);
+    {
+        if ( *argv[firstArg] != 0 )
+            sceneGroupMask = dAtoi(argv[firstArg]);
+    }
 
     // Calculate scene layer mask.
     U32 sceneLayerMask = MASK_ALL;
     if ( (U32)argc > (firstArg + 1) )
-        sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    {
+        if ( *argv[firstArg + 1] != 0 )
+            sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    }
 
     // Calculate pick mode.
-    Scene::PickMode pickMode = Scene::PICK_SIZE;
+    Scene::PickMode pickMode = Scene::PICK_OOBB;
     if ( (U32)argc > (firstArg + 2 ))
     {
         pickMode = Scene::getPickModeEnum(argv[firstArg + 2]);
@@ -2783,7 +2830,7 @@ ConsoleMethod(Scene, pickPoint, const char*, 3, 7, "(x / y, [sceneGroupMask], [s
     if ( pickMode == Scene::PICK_INVALID )
     {
         Con::warnf("Scene::pickPoint() - Invalid pick mode of %s", argv[firstArg + 2]);
-        pickMode = Scene::PICK_SIZE;
+        pickMode = Scene::PICK_OOBB;
     }
 
 
@@ -2797,15 +2844,19 @@ ConsoleMethod(Scene, pickPoint, const char*, 3, 7, "(x / y, [sceneGroupMask], [s
     // Perform query.
     if ( pickMode == Scene::PICK_ANY )
     {
-        pWorldQuery->anyQueryPoint( point );    
+        pWorldQuery->anyQueryCircle( point, radius );    
     }
-    else if ( pickMode == Scene::PICK_SIZE )
+    else if ( pickMode == Scene::PICK_AABB )
     {
-        pWorldQuery->renderQueryPoint( point );    
+        pWorldQuery->aabbQueryCircle( point, radius );    
+    }
+    else if ( pickMode == Scene::PICK_OOBB )
+    {
+        pWorldQuery->oobbQueryCircle( point, radius );    
     }
     else if ( pickMode == Scene::PICK_COLLISION )
     {
-        pWorldQuery->fixtureQueryPoint( point );    
+        pWorldQuery->collisionQueryCircle( point, radius );    
     }
     else
     {
@@ -2853,6 +2904,141 @@ ConsoleMethod(Scene, pickPoint, const char*, 3, 7, "(x / y, [sceneGroupMask], [s
     return pBuffer;
 }
 
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(Scene, pickRayCollision, const char*, 4, 8, "(startx/y, endx/y, [sceneGroupMask], [sceneLayerMask] ) Picks objects with collision shapes intersecting the specified ray with optional group/layer masks.\n"
+                "Unlike other pick methods, this returns the complete detail for each object encountered, returning the collision point, normal and fraction of the ray intersection.\n"
+                "@param startx/y The coordinates of the start point as either (\"x y\") or (x,y)\n"
+                "@param endx/y The coordinates of the end point as either (\"x y\") or (x,y)\n"
+                "@param sceneGroupMask Optional scene group mask.  (-1) or empty string selects all groups.\n"
+                "@param sceneLayerMask Optional scene layer mask.  (-1) or empty string selects all layers.\n"
+                "@return Returns a list of objects in blocks of detail items where each block represents a single object and its collision detail in the format:"
+                "<ObjectId PointX PointY NormalX NormalY RayFraction ShapeIndex> <ObjectId PointX PointY NormalX NormalY RayFraction ShapeIndex> <ObjectId PointX PointY NormalX NormalY RayFraction ShapeIndex> etc.\n")
+{
+    // Upper left and lower right bound.
+    Vector2 v1, v2;
+
+    // The index of the first optional parameter.
+    U32 firstArg;
+
+    // Grab the number of elements in the first two parameters.
+    U32 elementCount1 = Utility::mGetStringElementCount(argv[2]);
+    U32 elementCount2 = 1;
+    if (argc > 3)
+        elementCount2 = Utility::mGetStringElementCount(argv[3]);
+
+    // ("x1 y1 x2 y2")
+    if ((elementCount1 == 4) && (argc < 9))
+    {
+        v1 = Utility::mGetStringElementVector(argv[2]);
+        v2 = Utility::mGetStringElementVector(argv[2], 2);
+        firstArg = 3;
+    }
+   
+    // ("x1 y1", "x2 y2")
+    else if ((elementCount1 == 2) && (elementCount2 == 2) && (argc > 3) && (argc < 9))
+    {
+        v1 = Utility::mGetStringElementVector(argv[2]);
+        v2 = Utility::mGetStringElementVector(argv[3]);
+        firstArg = 4;
+    }
+   
+    // (x1, y1, x2, y2)
+    else if (argc > 5)
+    {
+        v1 = Vector2(dAtof(argv[2]), dAtof(argv[3]));
+        v2 = Vector2(dAtof(argv[4]), dAtof(argv[5]));
+        firstArg = 6;
+    }
+   
+    // Invalid
+    else
+    {
+        Con::warnf("Scene::pickRayCollision() - Invalid number of parameters!");
+        return NULL;
+    }
+
+    // Calculate scene group mask.
+    U32 sceneGroupMask = MASK_ALL;
+    if ( (U32)argc > firstArg )
+    {
+        if ( *argv[firstArg] != 0 )
+            sceneGroupMask = dAtoi(argv[firstArg]);
+    }
+
+    // Calculate scene layer mask.
+    U32 sceneLayerMask = MASK_ALL;
+    if ( (U32)argc > (firstArg + 1) )
+    {
+        if ( *argv[firstArg + 1] != 0 )
+            sceneLayerMask = dAtoi(argv[firstArg + 1]);
+    }
+
+    // Fetch world query and clear results.
+    WorldQuery* pWorldQuery = object->getWorldQuery( true );
+
+    // Set filter.
+    WorldQueryFilter queryFilter( sceneLayerMask, sceneGroupMask, true, false, true, true );
+    pWorldQuery->setQueryFilter( queryFilter );
+
+    // Perform query.
+    pWorldQuery->collisionQueryRay( v1, v2 );    
+
+    // Sanity!
+    AssertFatal( pWorldQuery->getIsRaycastQueryResult(), "Invalid non-ray-cast query result returned." );
+
+    // Fetch result count.
+    const U32 resultCount = pWorldQuery->getQueryResultsCount();
+
+    // Finish if no results.
+    if ( resultCount == 0 )
+        return NULL;
+
+    // Sort ray-cast result.
+    pWorldQuery->sortRaycastQueryResult();
+
+    // Fetch results.
+    typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
+
+    // Set Max Buffer Size.
+    const U32 maxBufferSize = 4096;
+
+    // Create Returnable Buffer.
+    char* pBuffer = Con::getReturnBuffer(maxBufferSize);
+
+    // Set Buffer Counter.
+    U32 bufferCount = 0;
+
+    // Add Picked Objects to List.
+    for ( U32 n = 0; n < resultCount; n++ )
+    {
+        // Fetch query result.
+        const WorldQueryResult& queryResult = queryResults[n];
+
+        bufferCount += dSprintf( pBuffer + bufferCount, maxBufferSize-bufferCount, "%d %g %g %g %g %g %d ",
+            queryResult.mpSceneObject->getId(),
+            queryResult.mPoint.x, queryResult.mPoint.y,
+            queryResult.mNormal.x, queryResult.mNormal.y,
+            queryResult.mFraction,
+            queryResult.mShapeIndex );
+
+        // Finish early if we run out of buffer space.
+        if ( bufferCount >= maxBufferSize )
+        {
+            // Warn.
+            Con::warnf("Scene::pickRayCollision() - Too many items picked to return to scripts!");
+            break;
+        }
+    }
+
+    // Clear world query.
+    pWorldQuery->clearQuery();
+
+    // Return buffer.
+    return pBuffer;
+}
+
 //-----------------------------------------------------------------------------
 
 ConsoleMethod(Scene, setDebugOn, void, 3, 2 + DEBUG_MODE_COUNT, "(debugOptions) Sets Debug option(s) on.\n"

+ 305 - 57
engine/source/2d/scene/WorldQuery.cc

@@ -39,8 +39,10 @@ WorldQuery::WorldQuery( Scene* pScene ) :
         mpScene(pScene),
         mIsRaycastQueryResult(false),
         mMasterQueryKey(0),
-        mCheckFixturePoint(false),
-        mFixturePoint(0.0f, 0.0f)
+        mCheckPoint(false),
+        mCheckAABB(false),
+        mCheckOOBB(false),
+        mCheckCircle(false)
 {
     // Set debug associations.
     for ( U32 n = 0; n < MAX_LAYERS_SUPPORTED; n++ )
@@ -130,10 +132,10 @@ void WorldQuery::removeAlwaysInScope( SceneObject* pSceneObject )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
+U32 WorldQuery::collisionQueryAABB( const b2AABB& aabb )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryArea);
+    PROFILE_SCOPE(WorldQuery_collisionQueryAABB);
 
     mMasterQueryKey++;
 
@@ -141,7 +143,16 @@ U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
     mIsRaycastQueryResult = false;
 
     // Query.
+    b2Vec2 verts[4];
+    verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+    verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+    verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+    verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+    mComparePolygonShape.Set( verts, 4 );
+    mCompareTransform.SetIdentity();
+    mCheckAABB = true;
     mpScene->getWorld()->QueryAABB( this, aabb );
+    mCheckAABB = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -151,10 +162,10 @@ U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::fixtureQueryRay( const Vector2& point1, const Vector2& point2 )
+U32 WorldQuery::collisionQueryRay( const Vector2& point1, const Vector2& point2 )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryRay);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryRay);
 
     mMasterQueryKey++;
 
@@ -172,10 +183,10 @@ U32 WorldQuery::fixtureQueryRay( const Vector2& point1, const Vector2& point2 )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
+U32 WorldQuery::collisionQueryPoint( const Vector2& point )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryPoint);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryPoint);
 
     mMasterQueryKey++;
 
@@ -186,10 +197,10 @@ U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
     b2AABB aabb;
     aabb.lowerBound = point;
     aabb.upperBound = point;
-    mCheckFixturePoint = true;
-    mFixturePoint = point;
+    mCheckPoint = true;
+    mComparePoint = point;
     mpScene->getWorld()->QueryAABB( this, aabb );
-    mCheckFixturePoint = false;
+    mCheckPoint = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -199,10 +210,38 @@ U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::renderQueryArea( const b2AABB& aabb )
+U32 WorldQuery::collisionQueryCircle( const Vector2& centroid, const F32 radius )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryArea);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryCircle);
+
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2AABB aabb;
+    mCompareTransform.SetIdentity();
+    mCompareCircleShape.m_p = centroid;
+    mCompareCircleShape.m_radius = radius;
+    mCompareCircleShape.ComputeAABB( &aabb, mCompareTransform, 0 );
+    mCheckCircle = true;
+    mpScene->getWorld()->QueryAABB( this, aabb );
+    mCheckCircle = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::aabbQueryAABB( const b2AABB& aabb )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_aabbQueryAABB);
 
     mMasterQueryKey++;
 
@@ -220,10 +259,10 @@ U32 WorldQuery::renderQueryArea( const b2AABB& aabb )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
+U32 WorldQuery::aabbQueryRay( const Vector2& point1, const Vector2& point2 )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryRay);
+    PROFILE_SCOPE(WorldQuery_AABBQueryRay);
 
     mMasterQueryKey++;
 
@@ -231,13 +270,35 @@ U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
     mIsRaycastQueryResult = true;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point1;
-    rayInput.p2 = point2;
+    mCompareRay.p1 = point1;
+    mCompareRay.p2 = point2;
+    mCompareRay.maxFraction = 1.0f;
+    mCompareTransform.SetIdentity();
+    RayCast( this, mCompareRay );
 
-    rayInput.maxFraction = 1.0f;
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::aabbQueryPoint( const Vector2& point )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_AABBQueryPoint);
 
-    RayCast( this, rayInput );
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2AABB aabb;
+    aabb.lowerBound = point;
+    aabb.upperBound = point;
+    Query( this, aabb );
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -247,10 +308,10 @@ U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::renderQueryPoint( const Vector2& point )
+U32 WorldQuery::aabbQueryCircle( const Vector2& centroid, const F32 radius )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryPoint);
+    PROFILE_SCOPE(WorldQuery_AABBQueryCircle);
 
     mMasterQueryKey++;
 
@@ -258,12 +319,46 @@ U32 WorldQuery::renderQueryPoint( const Vector2& point )
     mIsRaycastQueryResult = false;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point;
-    rayInput.p2 = b2Vec2( point.x + b2_linearSlop, point.y + b2_linearSlop );
-    rayInput.maxFraction = 1.0f;
+    b2AABB aabb;
+    mCompareTransform.SetIdentity();
+    mCompareCircleShape.m_p = centroid;
+    mCompareCircleShape.m_radius = radius;
+    mCompareCircleShape.ComputeAABB( &aabb, mCompareTransform, 0 );
+    mCheckCircle = true;
+    Query( this, aabb );
+    mCheckCircle = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
 
-    RayCast( this, rayInput );
+U32 WorldQuery::oobbQueryAABB( const b2AABB& aabb )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_aabbQueryAABB);
+
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2Vec2 verts[4];
+    verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+    verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+    verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+    verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+    mComparePolygonShape.Set( verts, 4 );
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = true;
+    mCheckAABB = true;
+    Query( this, aabb );
+    mCheckAABB = false;
+    mCheckOOBB = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -273,15 +368,54 @@ U32 WorldQuery::renderQueryPoint( const Vector2& point )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::anyQueryArea( const b2AABB& aabb )
+U32 WorldQuery::oobbQueryRay( const Vector2& point1, const Vector2& point2 )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_AnyQueryAreaAABB);
+    PROFILE_SCOPE(WorldQuery_AABBQueryRay);
+
+    mMasterQueryKey++;
+
+    // Flag as a ray-cast query result.
+    mIsRaycastQueryResult = true;
 
     // Query.
-    renderQueryArea( aabb );
-    mMasterQueryKey--;
-    fixtureQueryArea( aabb );
+    mCompareRay.p1 = point1;
+    mCompareRay.p2 = point2;
+    mCompareRay.maxFraction = 1.0f;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = true;
+    RayCast( this, mCompareRay );
+    mCheckOOBB = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::oobbQueryPoint( const Vector2& point )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_AABBQueryPoint);
+
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2AABB aabb;
+    aabb.lowerBound = point;
+    aabb.upperBound = point;
+    mComparePoint = point;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = true;
+    mCheckPoint = true;
+    Query( this, aabb );
+    mCheckPoint = false;
+    mCheckOOBB = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -291,18 +425,50 @@ U32 WorldQuery::anyQueryArea( const b2AABB& aabb )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::anyQueryArea( const Vector2& lowerBound, const Vector2& upperBound )
+U32 WorldQuery::oobbQueryCircle( const Vector2& centroid, const F32 radius )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_AnyQueryAreaBounds);
+    PROFILE_SCOPE(WorldQuery_OOBBQueryCircle);
+
+    mMasterQueryKey++;
 
-    // Calculate AABB.
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
     b2AABB aabb;
-    aabb.lowerBound.Set( getMin( lowerBound.x, upperBound.x ), getMin( lowerBound.x, upperBound.x ) );
-    aabb.upperBound.Set( getMax( lowerBound.x, upperBound.x ), getMax( lowerBound.x, upperBound.x ) );
+    mCompareTransform.SetIdentity();
+    mCompareCircleShape.m_p = centroid;
+    mCompareCircleShape.m_radius = radius;
+    mCompareCircleShape.ComputeAABB( &aabb, mCompareTransform, 0 );
+    mCheckOOBB = true;
+    mCheckCircle = true;
+    Query( this, aabb );
+    mCheckCircle = false;
+    mCheckOOBB = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::anyQueryAABB( const b2AABB& aabb )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_anyQueryAABBAABB);
 
     // Query.
-    return anyQueryArea( aabb );
+    oobbQueryAABB( aabb );
+    mMasterQueryKey--;
+    collisionQueryAABB( aabb );
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
 }
 
 //-----------------------------------------------------------------------------
@@ -313,9 +479,9 @@ U32 WorldQuery::anyQueryRay( const Vector2& point1, const Vector2& point2 )
     PROFILE_SCOPE(WorldQuery_AnyQueryRay);
 
     // Query.
-    renderQueryRay( point1, point2 );
+    oobbQueryRay( point1, point2 );
     mMasterQueryKey--;
-    fixtureQueryRay( point1, point2 );
+    collisionQueryRay( point1, point2 );
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -331,9 +497,27 @@ U32 WorldQuery::anyQueryPoint( const Vector2& point )
     PROFILE_SCOPE(WorldQuery_AnyQueryPoint);
 
     // Query.
-    renderQueryPoint( point );
+    oobbQueryPoint( point );
     mMasterQueryKey--;
-    fixtureQueryPoint( point );
+    collisionQueryPoint( point );
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::anyQueryCircle( const Vector2& centroid, const F32 radius )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_AnyQueryCircle);
+
+    // Query.
+    oobbQueryCircle( centroid, radius );
+    mMasterQueryKey--;
+    collisionQueryCircle( centroid, radius );
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -425,12 +609,19 @@ bool WorldQuery::ReportFixture( b2Fixture* fixture )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return true;
 
-    // Check fixture point.
-    if ( mCheckFixturePoint && !fixture->TestPoint( mFixturePoint ) )
+    // Check collision point.
+    if ( mCheckPoint && !fixture->TestPoint( mComparePoint ) )
         return true;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
+    // Check collision AABB.
+    if ( mCheckAABB )
+        if ( !b2TestOverlap( &mComparePolygonShape, 0, fixture->GetShape(), 0, mCompareTransform, fixture->GetBody()->GetTransform() ) )
+            return true;
+
+    // Check collision circle.
+    if ( mCheckCircle )
+        if ( !b2TestOverlap( &mCompareCircleShape, 0, fixture->GetShape(), 0, mCompareTransform, fixture->GetBody()->GetTransform() ) )
+            return true;
 
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -442,6 +633,9 @@ bool WorldQuery::ReportFixture( b2Fixture* fixture )
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return true;
@@ -478,9 +672,6 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return 1.0f;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
-
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneGroupMask = pSceneObject->getSceneGroupMask();
@@ -489,7 +680,7 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
     const S32 shapeIndex = pSceneObject->getCollisionShapeIndex( fixture );
 
     // Sanity!
-    AssertFatal( shapeIndex >= 0, "2dWorldQuery::ReportFixture() - Cannot find shape index reported on physics proxy of a fixture." );
+    AssertFatal( shapeIndex >= 0, "WorldQuery::ReportFixture() - Cannot find shape index reported on physics proxy of a fixture." );
 
     // Compare masks and report.
     if ( (mQueryFilter.mSceneLayerMask & sceneLayerMask) != 0 && (mQueryFilter.mSceneGroupMask & sceneGroupMask) != 0 )
@@ -497,6 +688,9 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
         WorldQueryResult queryResult( pSceneObject, point, normal, fraction, (U32)shapeIndex );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return 1.0f;
@@ -533,8 +727,48 @@ bool WorldQuery::QueryCallback( S32 proxyId )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return true;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+        // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSceneObject->getRenderOOBB(), 4);
+
+        // Check point.
+        if ( mCheckPoint )
+        {
+            if ( !oobb.TestPoint( mCompareTransform, mComparePoint ) )
+                return true;
+        }
+        // Check AABB.
+        else if ( mCheckAABB )
+        {
+            if ( !b2TestOverlap( &mComparePolygonShape, 0, &oobb, 0, mCompareTransform, mCompareTransform ) )
+                return true;
+        }
+        // Check circle.
+        else if ( mCheckCircle )
+        {
+            if ( !b2TestOverlap( &mCompareCircleShape, 0, &oobb, 0, mCompareTransform, mCompareTransform ) )
+                return true;
+        }
+    }
+    // Check circle.
+    else if ( mCheckCircle )
+    {
+        // Fetch the shapes AABB.
+        b2AABB aabb = pSceneObject->getAABB();
+        b2Vec2 verts[4];
+        verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+        verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+        verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+        verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+        b2PolygonShape shapeAABB;
+        shapeAABB.Set( verts, 4);
+        if ( !b2TestOverlap( &mCompareCircleShape, 0, &shapeAABB, 0, mCompareTransform, mCompareTransform ) )
+            return true;
+    }
+
 
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -546,6 +780,9 @@ bool WorldQuery::QueryCallback( S32 proxyId )
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return true;
@@ -582,8 +819,16 @@ F32 WorldQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return 1.0f;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+        // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSceneObject->getRenderOOBB(), 4);
+        b2RayCastOutput rayOutput;
+        if ( !oobb.RayCast( &rayOutput, mCompareRay, mCompareTransform, 0 ) )
+            return true;
+    }
 
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -595,6 +840,9 @@ F32 WorldQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId )
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return 1.0f;
@@ -621,9 +869,6 @@ void WorldQuery::injectAlwaysInScope( void )
         if ( pSceneObject->getWorldQueryKey() == mMasterQueryKey )
             continue;
 
-        // Tag with world query key.
-        pSceneObject->setWorldQueryKey( mMasterQueryKey );
-
         // Enabled filter.
         if ( mQueryFilter.mEnabledFilter && !pSceneObject->isEnabled() )
             continue;
@@ -646,6 +891,9 @@ void WorldQuery::injectAlwaysInScope( void )
             WorldQueryResult queryResult( pSceneObject );
             mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
             mQueryResults.push_back( queryResult );
+
+            // Tag with world query key.
+            pSceneObject->setWorldQueryKey( mMasterQueryKey );
         }
     }
 }

+ 30 - 15
engine/source/2d/scene/WorldQuery.h

@@ -56,21 +56,29 @@ public:
     void            addAlwaysInScope( SceneObject* pSceneObject );
     void            removeAlwaysInScope( SceneObject* pSceneObject );
 
-    //// World fixture queries.
-    U32             fixtureQueryArea( const b2AABB& aabb );
-    U32             fixtureQueryRay( const Vector2& point1, const Vector2& point2 );
-    U32             fixtureQueryPoint( const Vector2& point );
-
-    //// Render queries.
-    U32             renderQueryArea( const b2AABB& aabb );
-    U32             renderQueryRay( const Vector2& point1, const Vector2& point2 );
-    U32             renderQueryPoint( const Vector2& point );
-
-    /// World fixture & render queries.
-    U32             anyQueryArea( const b2AABB& aabb );
-    U32             anyQueryArea( const Vector2& lowerBound, const Vector2& upperBound );
+    /// World collision-shape queries.
+    U32             collisionQueryAABB( const b2AABB& aabb );
+    U32             collisionQueryRay( const Vector2& point1, const Vector2& point2 );
+    U32             collisionQueryPoint( const Vector2& point );
+    U32             collisionQueryCircle( const Vector2& centroid, const F32 radius );
+
+    /// AABB queries.
+    U32             aabbQueryAABB( const b2AABB& aabb );
+    U32             aabbQueryRay( const Vector2& point1, const Vector2& point2 );
+    U32             aabbQueryPoint( const Vector2& point );
+    U32             aabbQueryCircle( const Vector2& centroid, const F32 radius );
+
+    /// OOBB queries.
+    U32             oobbQueryAABB( const b2AABB& aabb );
+    U32             oobbQueryRay( const Vector2& point1, const Vector2& point2 );
+    U32             oobbQueryPoint( const Vector2& point );
+    U32             oobbQueryCircle( const Vector2& centroid, const F32 radius );
+
+    /// Any queries.
+    U32             anyQueryAABB( const b2AABB& aabb );
     U32             anyQueryRay( const Vector2& point1, const Vector2& point2 );
     U32             anyQueryPoint( const Vector2& point );
+    U32             anyQueryCircle( const Vector2& centroid, const F32 radius );
 
     /// Filtering.
     inline void     setQueryFilter( const WorldQueryFilter& queryFilter ) { mQueryFilter = queryFilter; }
@@ -96,8 +104,15 @@ private:
 private:
     Scene*                      mpScene;
     WorldQueryFilter            mQueryFilter;
-    bool                        mCheckFixturePoint;
-    b2Vec2                      mFixturePoint;
+    b2PolygonShape              mComparePolygonShape;
+    b2CircleShape               mCompareCircleShape;
+    b2RayCastInput              mCompareRay;
+    b2Vec2                      mComparePoint;
+    b2Transform                 mCompareTransform;
+    bool                        mCheckPoint;
+    bool                        mCheckAABB;
+    bool                        mCheckOOBB;
+    bool                        mCheckCircle;
     typeWorldQueryResultVector  mLayeredQueryResults[MAX_LAYERS_SUPPORTED];
     typeWorldQueryResultVector  mQueryResults;
     bool                        mIsRaycastQueryResult;

+ 21 - 26
engine/source/2d/sceneobject/CompositeSprite.cc

@@ -81,10 +81,6 @@ const char* CompositeSprite::getBatchLayoutTypeDescription(const CompositeSprite
     return StringTable->EmptyString;
 }
 
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(CompositeSprite);
-
 //------------------------------------------------------------------------------
 
 CompositeSprite::CompositeSprite() :
@@ -108,8 +104,8 @@ void CompositeSprite::initPersistFields()
     Parent::initPersistFields();
 
     /// Defaults.
-    addProtectedField( "DefaultSpriteStride", TypeVector2, Offset(mDefaultSpriteStride, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
-    addProtectedField( "DefaultSpriteSize", TypeVector2, Offset(mDefaultSpriteSize, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
+    addProtectedField( "DefaultSpriteStride", TypeVector2, Offset(mDefaultSpriteStride, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeDefaultSpriteStride, "");
+    addProtectedField( "DefaultSpriteSize", TypeVector2, Offset(mDefaultSpriteSize, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeDefaultSpriteSize, "");
     addProtectedField( "DefaultSpriteAngle", TypeF32, Offset(mDefaultSpriteSize, CompositeSprite), &setDefaultSpriteAngle, &getDefaultSpriteAngle, &writeDefaultSpriteAngle, "");
     addProtectedField( "BatchLayout", TypeEnum, Offset(mBatchLayoutType, CompositeSprite), &setBatchLayout, &defaultProtectedGetFn, &writeBatchLayout, 1, &batchLayoutTypeTable, "");
     addProtectedField( "BatchCulling", TypeBool, Offset(mBatchCulling, CompositeSprite), &setBatchCulling, &defaultProtectedGetFn, &writeBatchCulling, "");
@@ -271,8 +267,8 @@ SpriteBatchItem* CompositeSprite::createSprite( const SpriteBatchItem::LogicalPo
             return createCustomLayout( logicalPosition );
 
         default:
-            // Sanity!
-            AssertFatal( false, "CompositeSprite::createSprite() - Unknown layout type encountered." );
+            // Warn.
+            Con::warnf( "CompositeSprite::createSprite() - Unknown layout type encountered." );
             return SpriteBatch::createSprite( logicalPosition );
     }
 }
@@ -409,18 +405,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 +416,22 @@ void CompositeSprite::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Call parent.
     Parent::onTamlCustomRead( customNodes );
 
-    // Find sprites custom node.
-    const TamlCustomNode* pSpritesNode = customNodes.findNode( StringTable->insert("Sprites") );
+    // Read node with sprite batch.
+    SpriteBatch::onTamlCustomRead( customNodes );
+}
+
+//-----------------------------------------------------------------------------
 
-    // Finish if we don't have the node.
-    if ( pSpritesNode == NULL )
-        return;
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "CompositeSprite::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "CompositeSprite::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
 
-    // Read node with sprite batch.
-    SpriteBatch::onTamlCustomRead( pSpritesNode );
+    // Write sprite batch.
+    SpriteBatch::WriteCustomTamlSchema( pClassRep, pParentElement );
 }
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(CompositeSprite, WriteCustomTamlSchema);

+ 3 - 1
engine/source/2d/sceneobject/CompositeSprite.h

@@ -92,9 +92,11 @@ protected:
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 protected:
+    static bool         writeDefaultSpriteStride( void* obj, StringTableEntry pFieldName )  { return !STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteStride().isEqual( Vector2::getOne() ); }
+    static bool         writeDefaultSpriteSize( void* obj, StringTableEntry pFieldName )    { return !STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteSize().isEqual( Vector2::getOne() ); }
     static bool         setDefaultSpriteAngle(void* obj, const char* data)                  { STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->setDefaultSpriteAngle(mDegToRad(dAtof(data))); return false; }
     static const char*  getDefaultSpriteAngle(void* obj, const char* data)                  { return Con::getFloatArg( mRadToDeg(STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteAngle()) ); }
-    static bool         writeDefaultSpriteAngle( void* obj, StringTableEntry pFieldName )   { return mNotZero( static_cast<SpriteBatch*>(obj)->getDefaultSpriteAngle() ); }
+    static bool         writeDefaultSpriteAngle( void* obj, StringTableEntry pFieldName )   { return mNotZero( STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteAngle() ); }
     static bool         writeBatchIsolated( void* obj, StringTableEntry pFieldName )        { return static_cast<CompositeSprite*>(obj)->getBatchIsolated(); }
     static bool         writeBatchSortMode( void* obj, StringTableEntry pFieldName )        { return static_cast<CompositeSprite*>(obj)->getBatchSortMode() != SceneRenderQueue::RENDER_SORT_OFF; }
 

+ 18 - 7
engine/source/2d/sceneobject/CompositeSprite_ScriptBinding.h

@@ -768,14 +768,25 @@ ConsoleMethod(CompositeSprite, setSpriteBlendColor, void, 3, 6, "(float red, flo
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(CompositeSprite, getSpriteBlendColor, const char*, 2, 2,  "Gets the sprite blend color\n"
+ConsoleMethod(CompositeSprite, getSpriteBlendColor, const char*, 2, 3,  "(allowColorNames) Gets the sprite blend color\n"
+                                                                        "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
                                                                         "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    // Get Blend Colour.
+    // Get Blend color.
     ColorF blendColor = object->getSpriteBlendColor();
 
-    // Fetch the field value.
-    return Con::getData( TypeColorF, &blendColor, 0 );
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &blendColor, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return blendColor.scriptThis();
 }
 
 //-----------------------------------------------------------------------------
@@ -904,7 +915,7 @@ ConsoleMethod(CompositeSprite, pickPoint, const char*, 3, 4,    "(x / y ) Picks
     point = b2MulT( renderTransform, point );
 
     // Perform query.
-    pSpriteBatchQuery->renderQueryPoint( point );
+    pSpriteBatchQuery->queryPoint( point, true );
 
     // Fetch result count.
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
@@ -1028,7 +1039,7 @@ ConsoleMethod(CompositeSprite, pickArea, const char*, 4, 6, "(startx/y, endx/y )
     CoreMath::mRotateAABB( aabb, -renderTransform.q.GetAngle(), aabb );
 
     // Perform query.
-    pSpriteBatchQuery->renderQueryArea( aabb );
+    pSpriteBatchQuery->queryArea( aabb, true );
 
     // Fetch result count.
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
@@ -1142,7 +1153,7 @@ ConsoleMethod(CompositeSprite, pickRay, const char*, 4, 6,  "(startx/y, endx/y)
     v2 = b2MulT( renderTransform, v2 );
 
     // Perform query.
-    pSpriteBatchQuery->renderQueryRay( v1, v2 );
+    pSpriteBatchQuery->queryRay( v1, v2, true );
 
     // Sanity!
     AssertFatal( pSpriteBatchQuery->getIsRaycastQueryResult(), "Invalid non-ray-cast query result returned." );

+ 77 - 39
engine/source/2d/sceneobject/SceneObject.cc

@@ -2603,14 +2603,14 @@ void SceneObject::setBlendOptions( void )
         // Set Blend Function.
         glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
 
-        // Set Colour.
+        // Set color.
         glColor4f(mBlendColor.red,mBlendColor.green,mBlendColor.blue,mBlendColor.alpha );
     }
     else
     {
         // Disable Blending.
         glDisable( GL_BLEND );
-        // Reset Colour.
+        // Reset color.
         glColor4f(1,1,1,1);
     }
 
@@ -2637,7 +2637,7 @@ void SceneObject::resetBlendOptions( void )
 
     glDisable( GL_ALPHA_TEST);
 
-    // Reset Colour.
+    // Reset color.
     glColor4f(1,1,1,1);
 }
 
@@ -4099,36 +4099,18 @@ const char* SceneObject::getDstBlendFactorDescription(const GLenum factor)
 
 //-----------------------------------------------------------------------------
 
-static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+static void WriteCircleCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
-    char buffer[1024];
-
-    // Create shapes node element.
-    TiXmlElement* pShapesNodeElement = new TiXmlElement( "xs:element" );
-    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), shapeCustomNodeName );
-    pShapesNodeElement->SetAttribute( "name", buffer );
-    pShapesNodeElement->SetAttribute( "minOccurs", 0 );
-    pShapesNodeElement->SetAttribute( "maxOccurs", 1 );
-    pParentElement->LinkEndChild( pShapesNodeElement );
-    
-    // Create complex type.
-    TiXmlElement* pShapesNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
-    pShapesNodeElement->LinkEndChild( pShapesNodeComplexTypeElement );
-    
-    // Create choice element.
-    TiXmlElement* pShapesNodeChoiceElement = new TiXmlElement( "xs:choice" );
-    pShapesNodeChoiceElement->SetAttribute( "minOccurs", 0 );
-    pShapesNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
-    pShapesNodeComplexTypeElement->LinkEndChild( pShapesNodeChoiceElement );
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteCircleCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCircleCustomTamlSchema() - Parent Element cannot be NULL." );
 
-    // ********************************************************************************
-    // Create Circle
-    // ********************************************************************************
+    // Create circle element.
     TiXmlElement* pCircleElement = new TiXmlElement( "xs:element" );
     pCircleElement->SetAttribute( "name", circleTypeName );
     pCircleElement->SetAttribute( "minOccurs", 0 );
     pCircleElement->SetAttribute( "maxOccurs", 1 );
-    pShapesNodeChoiceElement->LinkEndChild( pCircleElement );
+    pParentElement->LinkEndChild( pCircleElement );
 
     // Create complex type Element.
     TiXmlElement* pCircleComplexTypeElement = new TiXmlElement( "xs:complexType" );
@@ -4197,15 +4179,22 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
     pCircleElementD = new TiXmlElement( "xs:minInclusive" );
     pCircleElementD->SetAttribute( "value", "0" );
     pCircleElementC->LinkEndChild( pCircleElementD );
+}
 
-    // ********************************************************************************
-    // Create Polygon
-    // ********************************************************************************
+//-----------------------------------------------------------------------------
+
+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 );
     pPolygonElement->SetAttribute( "minOccurs", 0 );
     pPolygonElement->SetAttribute( "maxOccurs", 1 );
-    pShapesNodeChoiceElement->LinkEndChild( pPolygonElement );
+    pParentElement->LinkEndChild( pPolygonElement );
 
     // Create complex type Element.
     TiXmlElement* pPolygonComplexTypeElement = new TiXmlElement( "xs:complexType" );
@@ -4265,15 +4254,22 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
     pPolygonElementD = new TiXmlElement( "xs:minInclusive" );
     pPolygonElementD->SetAttribute( "value", "0" );
     pPolygonElementC->LinkEndChild( pPolygonElementD );
+}
+
+//-----------------------------------------------------------------------------
 
-    // ********************************************************************************
-    // Create Chain
-    // ********************************************************************************
+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 );
     pChainElement->SetAttribute( "minOccurs", 0 );
     pChainElement->SetAttribute( "maxOccurs", 1 );
-    pShapesNodeChoiceElement->LinkEndChild( pChainElement );
+    pParentElement->LinkEndChild( pChainElement );
 
     // Create complex type Element.
     TiXmlElement* pChainComplexTypeElement = new TiXmlElement( "xs:complexType" );
@@ -4347,15 +4343,22 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
     pChainElementD = new TiXmlElement( "xs:minInclusive" );
     pChainElementD->SetAttribute( "value", "0" );
     pChainElementC->LinkEndChild( pChainElementD );
+}
 
-    // ********************************************************************************
-    // Create Edge
-    // ********************************************************************************
+//-----------------------------------------------------------------------------
+
+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 );
     pEdgeElement->SetAttribute( "minOccurs", 0 );
     pEdgeElement->SetAttribute( "maxOccurs", 1 );
-    pShapesNodeChoiceElement->LinkEndChild( pEdgeElement );
+    pParentElement->LinkEndChild( pEdgeElement );
 
     // Create complex type Element.
     TiXmlElement* pEdgeComplexTypeElement = new TiXmlElement( "xs:complexType" );
@@ -4431,4 +4434,39 @@ static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlEleme
 
 //-----------------------------------------------------------------------------
 
+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.
+    TiXmlElement* pShapesNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), shapeCustomNodeName );
+    pShapesNodeElement->SetAttribute( "name", buffer );
+    pShapesNodeElement->SetAttribute( "minOccurs", 0 );
+    pShapesNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pShapesNodeElement );
+    
+    // Create complex type.
+    TiXmlElement* pShapesNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pShapesNodeElement->LinkEndChild( pShapesNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pShapesNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pShapesNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pShapesNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pShapesNodeComplexTypeElement->LinkEndChild( pShapesNodeChoiceElement );
+
+    // Write collision shapes.
+    WriteCircleCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+    WritePolygonCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+    WriteChainCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+    WriteEdgeCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+}
+
+//-----------------------------------------------------------------------------
+
 IMPLEMENT_CONOBJECT_SCHEMA(SceneObject, WriteCustomTamlSchema);

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

@@ -91,8 +91,6 @@ const S32 INVALID_COLLISION_SHAPE_INDEX = -1;
 extern EnumTable bodyTypeTable;
 extern EnumTable srcBlendFactorTable;
 extern EnumTable dstBlendFactorTable;
-extern EnumTable srcBlendFactorTable;
-extern EnumTable dstBlendFactorTable;
 
 //-----------------------------------------------------------------------------
 
@@ -705,7 +703,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; }

+ 15 - 4
engine/source/2d/sceneobject/SceneObject_ScriptBinding.h

@@ -3315,14 +3315,25 @@ ConsoleMethod(SceneObject, setBlendColor, void, 3, 6,   "(float red, float green
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(SceneObject, getBlendColor, const char*, 2, 2, "Gets the Rendering Blend Colour.\n"
+ConsoleMethod(SceneObject, getBlendColor, const char*, 2, 3,    "(allowColorNames) Gets the Rendering Blend color.\n"
+                                                                "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
                                                                 "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    // Get Blend Colour.
+    // Get Blend color.
     ColorF blendColor = object->getBlendColor();
 
-    // Fetch the field value.
-    return Con::getData( TypeColorF, &blendColor, 0 );
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &blendColor, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return blendColor.scriptThis();
 }
 
 //-----------------------------------------------------------------------------

+ 10 - 167
engine/source/2d/sceneobject/ShapeVector.cc

@@ -63,11 +63,11 @@ ShapeVector::~ShapeVector()
 void ShapeVector::initPersistFields()
 {
    addProtectedField("PolyList", TypePoint2FVector, Offset(mPolygonBasisList, ShapeVector), &setPolyList, &defaultProtectedGetFn, &writePolyList, "");
-   addProtectedField("LineColor", TypeColorF, Offset(mLineColor, ShapeVector), &setLineColor, &defaultProtectedGetFn, &writeLineColor, "");
-   addProtectedField("FillColor", TypeColorF, Offset(mFillColor, ShapeVector), &setFillColor, &defaultProtectedGetFn, &writeFillColor, "");
-   addProtectedField("FillMode", TypeBool, Offset(mFillMode, ShapeVector), &setFillMode, &defaultProtectedGetFn, &writeFillMode, "");
-   addProtectedField("IsCircle", TypeBool, Offset(mIsCircle, ShapeVector), &setIsCircle, &defaultProtectedGetFn, &writeIsCircle, "");
-   addProtectedField("CircleRadius", TypeF32, Offset(mCircleRadius, ShapeVector), &setCircleRadius, &defaultProtectedGetFn, &writeCircleRadius, "");
+   addField("LineColor", TypeColorF, Offset(mLineColor, ShapeVector), &writeLineColor, "");
+   addField("FillColor", TypeColorF, Offset(mFillColor, ShapeVector), &writeFillColor, "");
+   addField("FillMode", TypeBool, Offset(mFillMode, ShapeVector), &writeFillMode, "");
+   addField("IsCircle", TypeBool, Offset(mIsCircle, ShapeVector), &writeIsCircle, "");
+   addField("CircleRadius", TypeF32, Offset(mCircleRadius, ShapeVector), &writeCircleRadius, "");
 
    Parent::initPersistFields();
 }
@@ -151,7 +151,7 @@ void ShapeVector::sceneRender( const SceneRenderState* pSceneRenderState, const
         renderPolygonShape(vertexCount);
     }
 
-    // Restore Colour.
+    // Restore color.
     glColor4f( 1,1,1,1 );
 
     // Restore Matrix.
@@ -220,7 +220,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         // Yes, so set polygon mode to FILL.
         //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 
-        // Set Fill Colour.
+        // Set Fill color.
         glColor4f( (GLfloat)mFillColor.red, (GLfloat)mFillColor.green, (GLfloat)mFillColor.blue, (GLfloat)mFillColor.alpha );
 
         GLfloat vert1[] = {//get first vert and make triangles based off of this one
@@ -253,7 +253,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
  
     }
 
-    // Set Line Colour.
+    // Set Line color.
     glColor4f(mLineColor.red, mLineColor.green, mLineColor.blue, mLineColor.alpha );
     
         for ( U32 n = 1; n <= vertexCount; n++ )
@@ -276,7 +276,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         // Yes, so set polygon mode to FILL.
         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 
-        // Set Fill Colour.
+        // Set Fill color.
         glColor4fv( (GLfloat*)&mFillColor );
 
         // Draw Object.
@@ -288,7 +288,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         glEnd();
     }
 
-    // Set Line Colour.
+    // Set Line color.
     glColor4fv( (GLfloat*)&mLineColor );
 
     // Draw Object.
@@ -586,163 +586,6 @@ void ShapeVector::generateLocalPoly( void )
 
 //----------------------------------------------------------------------------
 
-void ShapeVector::setLineColorString( const char* lineColour )
-{
-    // Calculate Element Count.
-    const U32 elementCount = Utility::mGetStringElementCount( lineColour );
-
-    // Check we've got enough arguments.
-    if ( elementCount < 3 )
-    {
-        Con::warnf("ShapeVector::setLineColourString() - Invalid Number of Elements! (%s)", lineColour);
-        return;
-    }
-
-    // Calculate Red, Green and Blue.
-    const F32 red   = dAtof(Utility::mGetStringElement( lineColour, 0 ));
-    const F32 green = dAtof(Utility::mGetStringElement( lineColour, 1 ));
-    const F32 blue  = dAtof(Utility::mGetStringElement( lineColour, 2 ));
-
-    // Set Alpha (if specified).
-    F32 alpha;
-    if ( elementCount >= 4 )
-        alpha = dAtof(Utility::mGetStringElement( lineColour, 3 ));
-    else alpha = 1.0f;
-
-    // Set Line Colour.
-    setLineColor( ColorF(red, green, blue, alpha) );
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setLineColor( const ColorF& lineColour )
-{
-    // Set Line Colour.
-    mLineColor = lineColour;
-}
-
-//----------------------------------------------------------------------------
-
-const char* ShapeVector::getLineColor()
-{
-    // Get Return Buffer.
-    char* pReturnBuffer = Con::getReturnBuffer( 64 );
-    dSprintf( pReturnBuffer, 64, "%0.5f %0.5f %0.5f %0.5f", mLineColor.red, mLineColor.green,
-                                                            mLineColor.blue, mLineColor.alpha);
-    return pReturnBuffer;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setLineAlpha( const F32 alpha )
-{
-    // Set Line Alpha.
-    mLineColor.alpha = alpha;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillColorString( const char* fillColour )
-{
-    // Calculate Element Count.
-    const U32 elementCount = Utility::mGetStringElementCount( fillColour );
-
-    // Check we've got enough arguments.
-    if ( elementCount < 3 )
-    {
-        Con::warnf("ShapeVector::setFillColourString() - Invalid Number of Elements! (%s)", fillColour);
-        return;
-    }
-
-    // Calculate Red, Green and Blue.
-    const F32 red   = dAtof(Utility::mGetStringElement( fillColour, 0 ));
-    const F32 green = dAtof(Utility::mGetStringElement( fillColour, 1 ));
-    const F32 blue  = dAtof(Utility::mGetStringElement( fillColour, 2 ));
-
-    // Set Alpha (if specified).
-    F32 alpha;
-    if ( elementCount >= 4 )
-        alpha = dAtof(Utility::mGetStringElement( fillColour, 3 ));
-    else alpha = 1.0f;
-
-    // Set Fill Colour.
-    setFillColor( ColorF(red, green, blue, alpha) );
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillColor( const ColorF& fillColour )
-{
-    // Set Fill Colour.
-    mFillColor = fillColour;
-}
-
-//----------------------------------------------------------------------------
-
-const char* ShapeVector::getFillColor()
-{
-    // Get Return Buffer.
-    char* pReturnBuffer = Con::getReturnBuffer( 64 );
-    dSprintf( pReturnBuffer, 64, "%0.5f %0.5f %0.5f %0.5f", mFillColor.red, mFillColor.green,
-                                                            mFillColor.blue, mFillColor.alpha);
-    return pReturnBuffer;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillAlpha( const F32 alpha )
-{
-    // Set Fill Alpha.
-    mFillColor.alpha = alpha;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillMode( const bool fillMode )
-{
-    // Set Fill Mode.
-    mFillMode = fillMode;
-}
-
-//----------------------------------------------------------------------------
-
-bool ShapeVector::getFillMode()
-{
-    return mFillMode;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setIsCircle( const bool isCircle )
-{
-    // Set Fill Mode.
-    mIsCircle = isCircle;
-}
-
-//----------------------------------------------------------------------------
-
-bool ShapeVector::getIsCircle()
-{
-    return mIsCircle;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setCircleRadius( const F32 circleRadius )
-{
-    // Set Fill Mode.
-    mCircleRadius = circleRadius;
-}
-
-//----------------------------------------------------------------------------
-
-F32 ShapeVector::getCircleRadius()
-{
-    return mCircleRadius;
-}
-
-//----------------------------------------------------------------------------
-
 Vector2 ShapeVector::getBoxFromPoints()
 {
     Vector2 box(1.0f, 1.0f);

+ 16 - 30
engine/source/2d/sceneobject/ShapeVector.h

@@ -55,28 +55,24 @@ public:
     void setPolyScale( const Vector2& scale );
     void setPolyPrimitive( const U32 polyVertexCount );
     void setPolyCustom( const U32 polyVertexCount, const char* pCustomPolygon );
-
-    /// Rendering Attributes.
-    void setLineColorString( const char* lineColour );
-    void setLineColor( const ColorF& lineColour );
-    void setLineAlpha( const F32 alpha );
-    void setFillColorString( const char* fillColour );
-    void setFillColor( const ColorF& fillColour );
-    void setFillAlpha( const F32 alpha );
-    void setFillMode( const bool fillMode );
-    void setIsCircle( const bool isCircle );
-    void setCircleRadius( F32 radius );
-
-    /// Retrieval.
     U32 getPolyVertexCount( void ) { return U32(mPolygonBasisList.size()); };
+    inline const Vector2* getPolyBasis( void ) const { return &(mPolygonBasisList[0]); };
     const char* getPoly( void );
     const char* getWorldPoly( void );
-    inline const Vector2* getPolyBasis( void ) const         { return &(mPolygonBasisList[0]); };
-    bool getFillMode( void );
-    const char* getLineColor( void );
-    const char* getFillColor( void );
-    bool getIsCircle( void );
-    F32 getCircleRadius ( void );
+
+    inline void setLineColor( const ColorF& linecolor ) { mLineColor = linecolor; }
+    inline const ColorF& getLineColor( void ) const { return mLineColor; }
+    inline void setLineAlpha( const F32 alpha ) { mLineColor.alpha = alpha; }
+    inline void setFillColor( const ColorF& fillcolor ) { mFillColor = fillcolor; }
+    inline const ColorF& getFillColor( void ) const { return mFillColor; }
+    inline void setFillAlpha( const F32 alpha ) { mFillColor.alpha = alpha; }
+    inline void setFillMode( const bool fillMode ) { mFillMode = fillMode; }
+    inline bool getFillMode( void ) const { return mFillMode; }
+    inline void setIsCircle( const bool isCircle ) { mIsCircle = isCircle; }
+    inline bool getIsCircle( void ) const { return mIsCircle; }
+    inline void setCircleRadius( const F32 circleRadius ) { mCircleRadius = circleRadius; }
+    inline F32 getCircleRadius ( void ) const { return mCircleRadius; }
+
     Vector2 getBoxFromPoints( void );
 
     /// Internal Crunchers.
@@ -112,25 +108,15 @@ public:
 protected:
     static bool setPolyList(void* obj, const char* data)
     {
-       //Vector2 poly[b2_maxPolygonVertices];
-       U32 count = Utility::mGetStringElementCount(data) >> 1;
-       //for (U32 i = 0; i < count; i++)
-       //   poly[i] = Utility::mGetStringElementVector(data, i * 2);
-
+       const U32 count = Utility::mGetStringElementCount(data) >> 1;
        static_cast<ShapeVector*>(obj)->setPolyCustom(count, data);
        return false;
     }
     static bool writePolyList( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mPolygonBasisList.size() > 0; }
-
-    static bool setLineColor(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setLineColorString(data); return false; }
     static bool writeLineColor( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mLineColor != ColorF(1.0f,1.0f,1.0f,1.0f); }
-    static bool setFillColor(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setFillColorString(data); return false; }
     static bool writeFillColor( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mFillColor != ColorF(0.5f,0.5f,0.5f,1.0f); }
-    static bool setFillMode(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setFillMode(dAtob(data)); return false; }
     static bool writeFillMode( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mFillMode == true; }
-    static bool setIsCircle(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setIsCircle(dAtob(data)); return false; }
     static bool writeIsCircle( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mIsCircle == true; }
-    static bool setCircleRadius(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setCircleRadius(dAtof(data)); return false; }
     static bool writeCircleRadius( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mIsCircle != 1; }
 };
 

+ 166 - 33
engine/source/2d/sceneobject/ShapeVector_ScriptBinding.h

@@ -93,30 +93,97 @@ ConsoleMethod(ShapeVector, getWorldPoly, const char*, 2, 2, "() Gets Polygon poi
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, setLineColour, void, 3, 3, "(R / G / B / [A]) Sets the Rendering Line Color (identical to setLineColor).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value.")
+ConsoleMethod(ShapeVector, setLineColor, void, 3, 6,    "(float red, float green, float blue, [float alpha = 1.0]) or ( stockColorName ) - Sets the line color."
+                                                        "@param red The red value.\n"
+                                                        "@param green The green value.\n"
+                                                        "@param blue The blue value.\n"
+                                                        "@param alpha The alpha value.\n"
+                                                        "@return No return Value.")
 {
-    // Set Line Color.
-    object->setLineColorString( argv[2] );
-}
+    // The colors.
+    F32 red;
+    F32 green;
+    F32 blue;
+    F32 alpha = 1.0f;
+
+    // Space separated.
+    if (argc == 3 )
+    {
+        // Grab the element count.
+        const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+        // Has a single argument been specified?
+        if ( elementCount == 1 )
+        {
+            // Set color.
+            Con::setData( TypeColorF, &const_cast<ColorF&>(object->getBlendColor()), 0, 1, &(argv[2]) );
+            return;
+        }
+
+        // ("R G B [A]")
+        if ((elementCount == 3) || (elementCount == 4))
+        {
+            // Extract the color.
+            red   = dAtof(Utility::mGetStringElement(argv[2], 0));
+            green = dAtof(Utility::mGetStringElement(argv[2], 1));
+            blue  = dAtof(Utility::mGetStringElement(argv[2], 2));
+
+            // Grab the alpha if it's there.
+            if (elementCount > 3)
+                alpha = dAtof(Utility::mGetStringElement(argv[2], 3));
+        }
+
+        // Invalid.
+        else
+        {
+            Con::warnf("ShapeVector::setLineColor() - Invalid Number of parameters!");
+            return;
+        }
+    }
 
-//----------------------------------------------------------------------------
+    // (R, G, B)
+    else if (argc >= 5)
+    {
+        red   = dAtof(argv[2]);
+        green = dAtof(argv[3]);
+        blue  = dAtof(argv[4]);
 
-ConsoleMethod(ShapeVector, setLineColor, void, 3, 3, "(R / G / B / [A]) - Sets the Rendering Line Color(identical to setLineColor).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value.")
-{
-    // Set Line Color.
-    object->setLineColorString( argv[2] );
+        // Grab the alpha if it's there.
+        if (argc > 5)
+            alpha = dAtof(argv[5]);
+    }
+
+    // Invalid.
+    else
+    {
+        Con::warnf("ShapeVector::setLineColor() - Invalid Number of parameters!");
+        return;
+    }
+
+    object->setLineColor( ColorF(red, green, blue, alpha) );
 }
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, getLineColor, const char*, 2, 2, "() Gets the Rendering Line Color.\n"
-              "@return Returns the fill color as a string formatted with \"Red Green Blue Alpha\"")
+ConsoleMethod(ShapeVector, getLineColor, const char*, 2, 3,     "(allowColorNames) Gets the fill color.\n"
+                                                                "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
+                                                                "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    return object->getLineColor();
+    // Get line color.
+    ColorF color = object->getLineColor();
+
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &color, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return color.scriptThis();
 }
 
 //----------------------------------------------------------------------------
@@ -131,31 +198,97 @@ ConsoleMethod(ShapeVector, setLineAlpha, void, 3, 3, "(alpha) Sets the Rendering
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, setFillColour, void, 3, 3, "(R / G / B / [A]) Sets the Rendering Fill Color (identical to setFillColor).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value."
-              )
+ConsoleMethod(ShapeVector, setFillColor, void, 3, 3,    "(float red, float green, float blue, [float alpha = 1.0]) or ( stockColorName ) - Sets the fill color."
+                                                        "@param red The red value.\n"
+                                                        "@param green The green value.\n"
+                                                        "@param blue The blue value.\n"
+                                                        "@param alpha The alpha value.\n"
+                                                        "@return No return Value.")
 {
-    // Set Fill Color.
-    object->setLineColorString( argv[2] );
-}
+    // The colors.
+    F32 red;
+    F32 green;
+    F32 blue;
+    F32 alpha = 1.0f;
+
+    // Space separated.
+    if (argc == 3 )
+    {
+        // Grab the element count.
+        const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+        // Has a single argument been specified?
+        if ( elementCount == 1 )
+        {
+            // Set color.
+            Con::setData( TypeColorF, &const_cast<ColorF&>(object->getBlendColor()), 0, 1, &(argv[2]) );
+            return;
+        }
+
+        // ("R G B [A]")
+        if ((elementCount == 3) || (elementCount == 4))
+        {
+            // Extract the color.
+            red   = dAtof(Utility::mGetStringElement(argv[2], 0));
+            green = dAtof(Utility::mGetStringElement(argv[2], 1));
+            blue  = dAtof(Utility::mGetStringElement(argv[2], 2));
+
+            // Grab the alpha if it's there.
+            if (elementCount > 3)
+                alpha = dAtof(Utility::mGetStringElement(argv[2], 3));
+        }
+
+        // Invalid.
+        else
+        {
+            Con::warnf("ShapeVector::setFillColor() - Invalid Number of parameters!");
+            return;
+        }
+    }
 
-//----------------------------------------------------------------------------
+    // (R, G, B)
+    else if (argc >= 5)
+    {
+        red   = dAtof(argv[2]);
+        green = dAtof(argv[3]);
+        blue  = dAtof(argv[4]);
 
-ConsoleMethod(ShapeVector, setFillColor, void, 3, 3, "(R / G / B / [A]) - Sets the Rendering Fill Color (identical to setFillColour).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value.")
-{
-    // Set Fill Color.
-    object->setFillColorString( argv[2] );
+        // Grab the alpha if it's there.
+        if (argc > 5)
+            alpha = dAtof(argv[5]);
+    }
+
+    // Invalid.
+    else
+    {
+        Con::warnf("ShapeVector::setFillColor() - Invalid Number of parameters!");
+        return;
+    }
+
+    object->setFillColor( ColorF(red, green, blue, alpha) );
 }
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, getFillColor, const char*, 2, 2, "() Gets the Rendering Fill Color.\n"
-              "@return Returns the fill color as a string formatted with \"Red Green Blue Alpha\"")
+ConsoleMethod(ShapeVector, getFillColor, const char*, 2, 3,     "(allowColorNames) Gets the fill color.\n"
+                                                                "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
+                                                                "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    return object->getFillColor();
+    // Get line color.
+    ColorF color = object->getFillColor();
+
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &color, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return color.scriptThis();
 }
 
 //----------------------------------------------------------------------------

+ 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();
 }
 
 //-----------------------------------------------------------------------------

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

@@ -36,6 +36,7 @@
 DefineConsoleType( TypeColorI )
 DefineConsoleType( TypeColorF )
 
+
 //-----------------------------------------------------------------------------
 
 class ColorI;
@@ -110,6 +111,9 @@ class ColorF
                                       (blue  >= 0.0f && blue  <= 1.0f) &&
                                       (alpha >= 0.0f && alpha <= 1.0f); }
    void clamp();
+
+   inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%f %f %f %f", red, green, blue, alpha ); return StringTable->insert(buffer); }
+   inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%.5f %.5f %.5f %.5f", red, green, blue, alpha ); return pBuffer; }
 };
 
 //-----------------------------------------------------------------------------
@@ -174,6 +178,39 @@ class ColorI
 
    U16 get565()  const;
    U16 get4444() const;
+
+   inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%d %d %d %d", red, green, blue, alpha ); return StringTable->insert(buffer); }
+   inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%d %d %d %d", red, green, blue, alpha ); return pBuffer; }
+};
+
+
+//-----------------------------------------------------------------------------
+
+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;
 };
 
 //-----------------------------------------------------------------------------
@@ -187,6 +224,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 );
 };

+ 4 - 4
engine/source/gui/guiColorPicker.h

@@ -32,7 +32,7 @@
 /// This control draws a box containing a color specified by mPickColor, 
 /// in a way according to one of the PickMode enum's, stored as mDisplayMode.
 /// 
-/// The color the box represents is stored as mBaseColour (for pPallete, pBlendColorRange), 
+/// The color the box represents is stored as mBasecolor (for pPallete, pBlendColorRange), 
 /// whilst the color chosen by the box is stored as mPickColor.
 ///
 /// Whenever the control is clicked, it will do one of many things :
@@ -43,7 +43,7 @@
 /// -# If its in pHorizAlphaRange or pVertAlphaRange mode, it will also function the same way as 3
 /// -# If its in pDropperBackground mode, nothing will happen
 ///
-/// Colours are drawn in different ways according to mDisplayMode:
+/// colors are drawn in different ways according to mDisplayMode:
 ///
 /// -# With pPallete, a box with a blank color, mBaseColor is drawn.
 /// -# With pHorizColorRange, a horizontal box with colors blending in the range, mColorRange.
@@ -89,7 +89,7 @@ class GuiColorPickerCtrl : public GuiControl
    /// @name Core Variables
    /// @{
    ColorF mPickColor;		///< Color that has been picked from control
-   ColorF mBaseColor;		///< Colour we display (in case of pallet and blend mode)
+   ColorF mBaseColor;		///< color we display (in case of pallet and blend mode)
    PickMode mDisplayMode;	///< Current color display mode of the selector
    
    Point2I mSelectorPos;	///< Current position of the selector
@@ -115,7 +115,7 @@ class GuiColorPickerCtrl : public GuiControl
    /// @{
    /// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful
    void setValue(ColorF &value) {mBaseColor = value;}
-   /// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colours themselves)
+   /// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colors themselves)
    ColorF getValue() {return mDisplayMode == pPallet ? mBaseColor : mPickColor;}
    const char *getScriptValue();
    void setScriptValue(const char *value);

+ 7 - 7
engine/source/gui/guiPopUpCtrl.cc

@@ -23,7 +23,7 @@
 // Revision History:
 // December 31, 2003	David Wyand		Changed a bunch of stuff.  Search for DAW below
 //										and make better notes here and in the changes doc.
-// May 19, 2004			David Wyand		Made changes to allow for a coloured rectangle to be
+// May 19, 2004			David Wyand		Made changes to allow for a colored rectangle to be
 //										displayed to the left of the text in the popup.
 // May 27, 2004			David Wyand		Added a check for mReverseTextList to see if we should
 //										reverse the text list if we must render it above
@@ -193,14 +193,14 @@ void GuiPopupTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selec
    getCellSize(size);
    if(mouseOver)
    {
-      // DAW: Render a background colour for the cell
+      // DAW: Render a background color for the cell
       RectI cellR(offset.x, offset.y, size.x, size.y);
       ColorI color(0,0,0);
       dglDrawRectFill(cellR, color);
 
    } else if(selected)
    {
-      // DAW: Render a background colour for the cell
+      // DAW: Render a background color for the cell
       RectI cellR(offset.x, offset.y, size.x, size.y);
       ColorI color(128,128,128);
       dglDrawRectFill(cellR, color);
@@ -209,7 +209,7 @@ void GuiPopupTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selec
    // DAW: Define the default x offset for the text
    U32 textXOffset = offset.x + mProfile->mTextOffset.x;
 
-   // DAW: Do we also draw a coloured box beside the text?
+   // DAW: Do we also draw a colored box beside the text?
    ColorI boxColor;
    bool drawbox = mPopUpCtrl->getColoredBox( boxColor, mList[cell.y].id);
    if(drawbox)
@@ -647,7 +647,7 @@ void GuiPopUpMenuCtrl::addEntry(const char *buf, S32 id, U32 scheme)
    char * cp = dStrchr(e.buf, '~');
    e.ascii = cp ? cp[1] : 0;
 
-   // DAW: See if there is a colour box defined with the text
+   // DAW: See if there is a color box defined with the text
    char* cb = dStrchr(e.buf, '|');
    if(cb)
    {
@@ -1029,7 +1029,7 @@ void GuiPopUpMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
          break;
       }
 
-      // DAW: Do we first draw a coloured box beside the text?
+      // DAW: Do we first draw a colored box beside the text?
       ColorI boxColor;
       bool drawbox = getColoredBox( boxColor, mSelIndex);
       if(drawbox)
@@ -1422,7 +1422,7 @@ bool GuiPopUpMenuCtrl::getFontColor( ColorI &fontColor, S32 id, bool selected, b
    }
 
    // Default color scheme...
-   fontColor = selected ? mProfile->mFontColorSEL : mouseOver ? mProfile->mFontColorHL : mProfile->mFontColorNA; // DAW: Modified the final colour choice from mProfile->mFontColor to mProfile->mFontColorNA
+   fontColor = selected ? mProfile->mFontColorSEL : mouseOver ? mProfile->mFontColorHL : mProfile->mFontColorNA; // DAW: Modified the final color choice from mProfile->mFontColor to mProfile->mFontColorNA
 
    return( true );
 }

+ 7 - 7
engine/source/gui/guiPopUpCtrlEx.cc

@@ -23,7 +23,7 @@
 // Revision History:
 // December 31, 2003	David Wyand		Changed a bunch of stuff.  Search for DAW below
 //										and make better notes here and in the changes doc.
-// May 19, 2004			David Wyand		Made changes to allow for a coloured rectangle to be
+// May 19, 2004			David Wyand		Made changes to allow for a colored rectangle to be
 //										displayed to the left of the text in the popup.
 // May 27, 2004			David Wyand		Added a check for mReverseTextList to see if we should
 //										reverse the text list if we must render it above
@@ -233,7 +233,7 @@ void GuiPopupTextListCtrlEx::onRenderCell(Point2I offset, Point2I cell, bool sel
    getCellSize(size);
    if(mouseOver && (mList[cell.y].id != -1))
    {
-      // DAW: Render a background colour for the cell
+      // DAW: Render a background color for the cell
       RectI cellR(offset.x, offset.y, size.x, size.y);
 	  ColorI color(0,0,0);
       dglDrawRectFill(cellR, color);
@@ -241,7 +241,7 @@ void GuiPopupTextListCtrlEx::onRenderCell(Point2I offset, Point2I cell, bool sel
    } 
    else if(selected)
    {
-      // DAW: Render a background colour for the cell
+      // DAW: Render a background color for the cell
       RectI cellR(offset.x, offset.y, size.x, size.y);
 	  ColorI color(128,128,128);
       dglDrawRectFill(cellR, color);
@@ -250,7 +250,7 @@ void GuiPopupTextListCtrlEx::onRenderCell(Point2I offset, Point2I cell, bool sel
    // DAW: Define the default x offset for the text
    U32 textXOffset = offset.x + mProfile->mTextOffset.x;
 
-   // DAW: Do we also draw a coloured box beside the text?
+   // DAW: Do we also draw a colored box beside the text?
    ColorI boxColor;
    bool drawbox = mPopUpCtrl->getColoredBox( boxColor, mList[cell.y].id);
    if(drawbox)
@@ -678,7 +678,7 @@ void GuiPopUpMenuCtrlEx::addEntry(const char *buf, S32 id, U32 scheme)
    char * cp = dStrchr(e.buf, '~');
    e.ascii = cp ? cp[1] : 0;
 
-   // DAW: See if there is a colour box defined with the text
+   // DAW: See if there is a color box defined with the text
    char* cb = dStrchr(e.buf, '|');
    if(cb)
    {
@@ -1020,7 +1020,7 @@ void GuiPopUpMenuCtrlEx::onRender(Point2I offset, const RectI &updateRect)
          break;
    }
 
-   // DAW: Do we first draw a coloured box beside the text?
+   // DAW: Do we first draw a colored box beside the text?
    ColorI boxColor;
    bool drawbox = getColoredBox( boxColor, mSelIndex);
    if(drawbox)
@@ -1410,7 +1410,7 @@ bool GuiPopUpMenuCtrlEx::getFontColor( ColorI &fontColor, S32 id, bool selected,
       fontColor = mProfile->mFontColorHL;
    else
    // Default color scheme...
-   fontColor = selected ? mProfile->mFontColorSEL : mouseOver ? mProfile->mFontColorHL : mProfile->mFontColorNA; // DAW: Modified the final colour choice from mProfile->mFontColor to mProfile->mFontColorNA
+   fontColor = selected ? mProfile->mFontColorSEL : mouseOver ? mProfile->mFontColorHL : mProfile->mFontColorNA; // DAW: Modified the final color choice from mProfile->mFontColor to mProfile->mFontColorNA
 
    return( true );
 }

+ 1 - 1
engine/source/gui/guiPopUpCtrlEx.h

@@ -28,7 +28,7 @@
 //										class.
 // May 19, 2004			David Wyand		Added the bool usesColorBox and ColorI colorbox to the
 //										Entry structure of the GuiPopUpMenuCtrl class.  These
-//										are used to draw a coloured rectangle beside the text in
+//										are used to draw a colored rectangle beside the text in
 //										the list.
 // November 16, 2005	David Wyand		Added the method setNoneSelected() to set none of the
 //										items as selected.  Use this over setSelected(-1); when

+ 285 - 32
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,8 +898,14 @@ 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;
 
     // *************************************************************
     // Generate console type elements.
@@ -922,6 +950,45 @@ bool Taml::generateTamlSchema( const char* pFilename )
     pPoint2IElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]*" );   
     pPoint2IElementA->LinkEndChild( pPoint2IElementB );
 
+    // b2AABB.
+    TiXmlComment* pb2AABBComment = new TiXmlComment( "b2AABB Console Type" );
+    pSchemaElement->LinkEndChild( pb2AABBComment );
+    TiXmlElement* pb2AABBTypeElement = new TiXmlElement( "xs:simpleType" );
+    pb2AABBTypeElement->SetAttribute( "name", "b2AABB_ConsoleType" );
+    pSchemaElement->LinkEndChild( pb2AABBTypeElement );
+    TiXmlElement* pb2AABBElementA = new TiXmlElement( "xs:restriction" );
+    pb2AABBElementA->SetAttribute( "base", "xs:string" );
+    pb2AABBTypeElement->LinkEndChild( pb2AABBElementA );
+    TiXmlElement* pb2AABBElementB = new TiXmlElement( "xs:pattern" );
+    pb2AABBElementB->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" );   
+    pb2AABBElementA->LinkEndChild( pb2AABBElementB );   
+
+    // RectI.
+    TiXmlComment* pRectIComment = new TiXmlComment( "RectI Console Type" );
+    pSchemaElement->LinkEndChild( pRectIComment );
+    TiXmlElement* pRectITypeElement = new TiXmlElement( "xs:simpleType" );
+    pRectITypeElement->SetAttribute( "name", "RectI_ConsoleType" );
+    pSchemaElement->LinkEndChild( pRectITypeElement );
+    TiXmlElement* pRectIElementA = new TiXmlElement( "xs:restriction" );
+    pRectIElementA->SetAttribute( "base", "xs:string" );
+    pRectITypeElement->LinkEndChild( pRectIElementA );
+    TiXmlElement* pRectIElementB = new TiXmlElement( "xs:pattern" );
+    pRectIElementB->SetAttribute( "value", "[-]?[0-9]* [-]?[0-9]* [-]?[0-9]* [-]?[0-9]*" );   
+    pRectIElementA->LinkEndChild( pRectIElementB );
+
+    // RectF.
+    TiXmlComment* pRectFComment = new TiXmlComment( "RectF Console Type" );
+    pSchemaElement->LinkEndChild( pRectFComment );
+    TiXmlElement* pRectFTypeElement = new TiXmlElement( "xs:simpleType" );
+    pRectFTypeElement->SetAttribute( "name", "RectF_ConsoleType" );
+    pSchemaElement->LinkEndChild( pRectFTypeElement );
+    TiXmlElement* pRectFElementA = new TiXmlElement( "xs:restriction" );
+    pRectFElementA->SetAttribute( "base", "xs:string" );
+    pRectFTypeElement->LinkEndChild( pRectFElementA );
+    TiXmlElement* pRectFElementB = new TiXmlElement( "xs:pattern" );
+    pRectFElementB->SetAttribute( "value", "(\\b[-]?(b[0-9]+)?\\.)?[0-9]+\\b" );   
+    pRectFElementA->LinkEndChild( pRectFElementB );
+
     // AssetId.
     TiXmlComment* pAssetIdComment = new TiXmlComment( "AssetId Console Type" );
     pSchemaElement->LinkEndChild( pAssetIdComment );
@@ -936,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.
     // *************************************************************
@@ -985,20 +1114,49 @@ bool Taml::generateTamlSchema( const char* pFilename )
             pChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
             pSequenceElement->LinkEndChild( pChoiceElement );
 
-            // Add choice members.
-            for ( AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass() )
+            // Find child group.
+            HashMap<AbstractClassRep*, StringTableEntry>::iterator childGroupItr = childGroups.find( pContainerChildClass );
+
+            // Does the group exist?
+            if ( childGroupItr == childGroups.end() )
             {
-                // Skip if not derived from the container child class.
-                if ( !pChoiceType->isClass( pContainerChildClass ) )
-                    continue;
-
-                // Add choice member.
-                TiXmlElement* pChoiceMemberElement = new TiXmlElement( "xs:element" );
-                pChoiceMemberElement->SetAttribute( "name", pChoiceType->getClassName() );
-                dSprintf( buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName() );
-                pChoiceMemberElement->SetAttribute( "type", buffer );
-                pChoiceElement->LinkEndChild( pChoiceMemberElement );
+                // No, so format group name.
+                dSprintf( buffer, sizeof(buffer), "%s_ChildrenTypes", pContainerChildClass->getClassName() );
+
+                // Insert into child group hash.
+                childGroupItr = childGroups.insert( pContainerChildClass, StringTable->insert( buffer ) );
+
+                // Add the group.
+                TiXmlElement* pChildrenGroupElement = new TiXmlElement( "xs:group" );
+                pChildrenGroupElement->SetAttribute( "name", buffer );
+                pSchemaElement->LinkEndChild( pChildrenGroupElement );
+
+                // Add choice element.
+                TiXmlElement* pChildreGroupChoiceElement = new TiXmlElement( "xs:choice" );
+                pChildrenGroupElement->LinkEndChild( pChildreGroupChoiceElement );
+
+                // Add choice members.
+                for ( AbstractClassRep* pChoiceType = pRootType; pChoiceType != NULL; pChoiceType = pChoiceType->getNextClass() )
+                {
+                    // Skip if not derived from the container child class.
+                    if ( !pChoiceType->isClass( pContainerChildClass ) )
+                        continue;
+
+                    // Add choice member.
+                    TiXmlElement* pChildrenMemberElement = new TiXmlElement( "xs:element" );
+                    pChildrenMemberElement->SetAttribute( "name", pChoiceType->getClassName() );
+                    dSprintf( buffer, sizeof(buffer), "%s_Type", pChoiceType->getClassName() );
+                    pChildrenMemberElement->SetAttribute( "type", buffer );
+                    pChildreGroupChoiceElement->LinkEndChild( pChildrenMemberElement );
+                }
+
             }
+
+            // Reference the child group.
+            TiXmlElement* pChoiceGroupReferenceElement = new TiXmlElement( "xs:group" );
+            pChoiceGroupReferenceElement->SetAttribute( "ref", childGroupItr->value );
+            pChoiceGroupReferenceElement->SetAttribute( "minOccurs", 0 );
+            pChoiceElement->LinkEndChild( pChoiceGroupReferenceElement );
         }
 
         // Generate the custom Taml schema.
@@ -1015,12 +1173,23 @@ bool Taml::generateTamlSchema( const char* pFilename )
             customSchemaFn( pType, pSequenceElement );
         }
 
-        // Iterate static fields.
+        // 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;
-        for( AbstractClassRep::FieldList::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
+
+        // Fetcj field count.
+        const S32 fieldCount = fields.size();
+
+        // Iterate static fields (in reverse as most types are organized from the root-fields up).
+        for( S32 index = fieldCount-1; index > 0; --index )
         {
             // Fetch field.
-            const AbstractClassRep::Field& field = *fieldItr;
+            const AbstractClassRep::Field& field = fields[index];
 
             // Skip if not a data field.
             if( field.type == AbstractClassRep::DepricatedFieldType ||
@@ -1028,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 );
@@ -1081,6 +1254,7 @@ bool Taml::generateTamlSchema( const char* pFilename )
                 {
                     pFieldTypeDescription = "Vector2_ConsoleType";
                 }
+
                 else if( fieldType == TypePoint2F )
                 {
                     pFieldTypeDescription = "Point2F_ConsoleType";
@@ -1089,6 +1263,26 @@ bool Taml::generateTamlSchema( const char* pFilename )
                 {
                     pFieldTypeDescription = "Point2I_ConsoleType";
                 }
+                else if( fieldType == Typeb2AABB )
+                {
+                    pFieldTypeDescription = "b2AABB_ConsoleType";
+                }
+                else if( fieldType == TypeRectI )
+                {
+                    pFieldTypeDescription = "RectI_ConsoleType";
+                }
+                else if( fieldType == TypeRectF )
+                {
+                    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 ||
@@ -1102,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).
@@ -1111,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 );
 
@@ -1132,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/tamlWriteNode.h

@@ -67,7 +67,6 @@ public:
     {
         // NOTE: This MUST be done before the state is reset otherwise we'll be touching uninitialized stuff.
         mRefToNode = NULL;
-        mChildren = NULL;
         mpSimObject = NULL;
         mpTamlCallbacks = NULL;
         mpObjectName = NULL;

+ 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;

+ 3 - 15
modules/CompositeSpriteToy/1/main.cs

@@ -22,9 +22,6 @@
 
 function CompositeSpriteToy::create( %this )
 {
-    // Activate the package.
-    activatePackage( CompositeSpriteToyPackage );
-    
     // Load scripts.
     exec( "./scripts/noLayout.cs" );
     exec( "./scripts/rectLayout.cs" );
@@ -49,7 +46,7 @@ function CompositeSpriteToy::create( %this )
     addNumericOption("Maximum Sprite Count", 10, 1000, 10, "setSpriteCount", CompositeSpriteToy.SpriteCount, true, "Sets the maximum number of sprites to create." );
     addNumericOption("Angular Velocity", -180, 180, 20, "setAngularVelocity", CompositeSpriteToy.AngularVelocity, false, "Sets the rate at which the composite sprite spins." );    
     addFlagOption("Render Isolated", "setRenderIsolated", CompositeSpriteToy.RenderIsolated, true , "Whether the composite renders its sprites isolated from the scene layer it occupies or not.");
-        
+    
     // Reset the toy.
     %this.reset();     
 }
@@ -58,8 +55,6 @@ function CompositeSpriteToy::create( %this )
 
 function CompositeSpriteToy::destroy( %this )
 {
-    // Deactivate the package.
-    deactivatePackage( CompositeSpriteToyPackage );    
 }
 
 //-----------------------------------------------------------------------------
@@ -141,15 +136,10 @@ function CompositeSpriteToy::createBackground(%this)
     SandboxScene.add( %obj );   
 }
 
+//-----------------------------------------------------------------------------
 
-package CompositeSpriteToyPackage
-{
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+function CompositeSpriteToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-    
     // Fetch the composite sprite.
     %compositeSprite = CompositeSpriteToy.CompositeSprite;
     
@@ -176,5 +166,3 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
         %compositeSprite.removeSprite();
     }
 }
-  
-};

+ 173 - 0
modules/CompoundObjectsToy/1/main.cs

@@ -0,0 +1,173 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::create( %this )
+{
+    // Configure the toy.
+    CompoundObjectsToy.BlockSize = 1.5;
+    CompoundObjectsToy.BlockCount = 15;
+    CompoundObjectsToy.GroundWidth = 40;    
+    
+    // Set the camera.
+    SandboxWindow.setCameraSize( 40, 30 );
+    
+    // Se the gravity.
+    SandboxScene.setGravity( 0, -9.8 );
+   
+    // Reset the toy.
+    CompoundObjectsToy.reset();
+}
+
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::destroy( %this )
+{
+}
+
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::reset( %this )
+{
+    // Clear the scene.
+    SandboxScene.clear();
+        
+    // Create a background.
+    %this.createBackground();
+       
+    // Create the ground.
+    %this.createGround();    
+}
+
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::createBackground( %this )
+{    
+    // Create the sprite.
+    %object = new Sprite();
+    
+    // Set the sprite as "static" so it is not affected by gravity.
+    %object.setBodyType( static );
+       
+    // Always try to configure a scene-object prior to adding it to a scene for best performance.
+
+    // Set the size.        
+    %object.Size = CompoundObjectsToy.GroundWidth SPC (CompoundObjectsToy.GroundWidth * 0.75);
+    
+    // Set the position.
+    %object.setPositionY( (%object.getSizeY() * 0.5) - 15 );
+    
+    // Set to the furthest background layer.
+    %object.SceneLayer = 31;
+    
+    // Set an image.
+    %object.Image = "ToyAssets:jungleSky";
+            
+    // Add the sprite to the scene.
+    SandboxScene.add( %object );    
+}
+
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::createGround( %this )
+{
+    // Create the ground
+    %ground = SandboxScene.create( Scroller );
+    %ground.BodyType = static;
+    %ground.Image = "ToyAssets:dirtGround";
+    %ground.SceneGroup = 10;
+    %ground.setPosition(0, -12);
+    %ground.setSize(CompoundObjectsToy.GroundWidth, 6);
+    %ground.setRepeatX(CompoundObjectsToy.GroundWidth / 60);   
+    %ground.createEdgeCollisionShape(CompoundObjectsToy.GroundWidth/-2, 3, CompoundObjectsToy.GroundWidth/2, 3);
+    %ground.createEdgeCollisionShape(CompoundObjectsToy.GroundWidth/-2, 3, CompoundObjectsToy.GroundWidth/-2, 40 );
+    %ground.createEdgeCollisionShape(CompoundObjectsToy.GroundWidth/2, 3, CompoundObjectsToy.GroundWidth/2, 40 );
+    
+    // Create the grass.
+    %grass = SandboxScene.create( Sprite );
+    %grass.BodyType = static;
+    %grass.Image = "ToyAssets:grassForeground";
+    %grass.SetPosition(0, -8.5);
+    %grass.setSize(CompoundObjectsToy.GroundWidth, 2); 
+
+}
+
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::createCompoundObject( %this, %worldPosition )
+{
+    // Configure the compound object.
+    %radius = 2;
+    %angleStride = 15;
+    %blockSize = 1;    
+      
+    // Create the composite.
+    %composite = SandboxScene.create( CompositeSprite );
+    
+    // Turn-off batch culling to save memory as this is a small composite.
+    %composite.BatchCulling = false;
+    
+    // Turn-off batch layout as these sprites will be positioned explicitly.
+    %composite.BatchLayout = "none";
+    
+    // Render everything together, don't sort the sprites with the rest of the scene layer.
+    %composite.BatchIsolated = true;
+    
+    // Set the position.    
+    %composite.Position = %worldPosition;
+    
+    // Set the scene layer (behind the grass).
+    %composite.SceneLayer = 1;
+    
+    // Create compound ring.    
+    for( %angle = 0; %angle < 360; %angle += %angleStride )
+    {
+        %radianAngle = mDegToRad( %angle );
+        %spriteX = mSin( %radianAngle ) * %radius;
+        %spriteY = mCos( %radianAngle ) * %radius;
+        
+        %composite.addSprite();
+        %composite.setSpriteLocalPosition( %spriteX, %spriteY );
+        %composite.setSpriteSize( %blockSize );
+        %composite.setSpriteAngle( -%angle );
+        %composite.setSpriteImage( "ToyAssets:Blocks" );
+        %composite.setSpriteImageFrame( getRandom(0,55) );
+    }
+
+    // Add center sprite.
+    %composite.addSprite();
+    %composite.setSpriteSize( %radius * 2 );
+    %composite.setSpriteAnimation( "ToyAssets:TD_Barbarian_WalkSouth" );
+
+    // Set the collision shape defaults.
+    %composite.setDefaultFriction( 0.25 );
+    %composite.setDefaultRestitution( 0.75 );
+    
+    // Create a collision shape.
+    %composite.createCircleCollisionShape( %radius + (%blockSize * 0.5 ) ); 
+}
+
+//-----------------------------------------------------------------------------
+
+function CompoundObjectsToy::onTouchDown(%this, %touchID, %worldPosition)
+{
+    %this.createCompoundObject( %worldPosition );
+}

+ 10 - 0
modules/CompoundObjectsToy/1/module.taml

@@ -0,0 +1,10 @@
+<ModuleDefinition
+	ModuleId="CompoundObjectsToy"
+	VersionId="1"
+	Description="Demonstrates creating compound objects using the CompositeSprite."
+	Dependencies="ToyAssets=1"
+	Type="toy"
+	ToyCategoryIndex="3"
+	ScriptFile="main.cs"
+	CreateFunction="create"
+	DestroyFunction="destroy"/>

+ 4 - 39
modules/DeathBallToy/1/main.cs

@@ -29,9 +29,6 @@ function DeathBallToy::create( %this )
     exec("./scripts/moveTowardBehavior.cs");
     exec("./scripts/spawnAreaBehavior.cs");
 
-    // Activate the package.
-    activatePackage( DeathBallToyPackage );
-
     // Initialize the toys settings.
     DeathBallToy.WorldTop = 35;
     DeathBallToy.WorldBottom = -110;
@@ -68,9 +65,6 @@ function DeathBallToy::destroy( %this )
 {
     // Cancel any pending events.
     DeathBallToy::cancelPendingEvents();
-
-    // Deactivate the package.
-    deactivatePackage( DeathBallToyPackage );
 }
 
 //-----------------------------------------------------------------------------
@@ -453,14 +447,8 @@ function DeathBallToy::cancelPendingEvents()
 
 //-----------------------------------------------------------------------------
 
-package DeathBallToyPackage
+function DeathBallToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
-{
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-    
     %origin = Deathball.getPosition();
     %angle = -mRadToDeg( mAtan( getWord(%worldPosition,0)-getWord(%origin,0), getWord(%worldPosition,1)-getWord(%origin,1) ) );
 
@@ -477,11 +465,8 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
 
 //-----------------------------------------------------------------------------
 
-function SandboxWindow::onTouchUp(%this, %touchID, %worldPosition)
+function DeathBallToy::onTouchUp(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchUp(%this, %touchID, %worldPosition );
-    
     %origin = Deathball.getPosition();
     %angle = -mRadToDeg( mAtan( getWord(%worldPosition,0)-getWord(%origin,0), getWord(%worldPosition,1)-getWord(%origin,1) ) );
 
@@ -494,11 +479,8 @@ function SandboxWindow::onTouchUp(%this, %touchID, %worldPosition)
 
 //-----------------------------------------------------------------------------
 
-function SandboxWindow::onTouchDragged(%this, %touchID, %worldPosition)
-{
-    // Call parent.
-    Parent::onTouchDragged(%this, %touchID, %worldPosition );
-    
+function DeathBallToy::onTouchDragged(%this, %touchID, %worldPosition)
+{    
     %origin = Deathball.getPosition();
     %angle = -mRadToDeg( mAtan( getWord(%worldPosition,0)-getWord(%origin,0), getWord(%worldPosition,1)-getWord(%origin,1) ) );
 
@@ -512,20 +494,3 @@ function SandboxWindow::onTouchDragged(%this, %touchID, %worldPosition)
 
     Deathball.setLinearVelocity( getWord(%scaledVelocity, 0), getWord(%scaledVelocity, 1) );
 }
-
-
-//-----------------------------------------------------------------------------
-
-/*function SandboxWindow::onMouseWheelUp(%this, %modifier, %mousePoint, %mouseClickCount)
-{
-    // Don't allow zooming
-}
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onMouseWheelDown(%this, %modifier, %mousePoint, %mouseClickCount)
-{
-    // Don't allow zooming
-}         */
-
-};

+ 2 - 18
modules/MoveToToy/1/main.cs

@@ -22,9 +22,6 @@
 
 function MoveToToy::create( %this )
 {
-    // Activate the package.
-    activatePackage( MoveToToyPackage );    
-
     // Initialize the toys settings.
     MoveToToy.moveSpeed = 50;
     MoveToToy.trackMouse = true;
@@ -41,8 +38,6 @@ function MoveToToy::create( %this )
 
 function MoveToToy::destroy( %this )
 {
-    // Deactivate the package.
-    deactivatePackage( MoveToToyPackage );
 }
 
 //-----------------------------------------------------------------------------
@@ -164,14 +159,8 @@ function MoveToToy::setTrackMouse( %this, %value )
 
 //-----------------------------------------------------------------------------
 
-package MoveToToyPackage
-{
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+function MoveToToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-    
     // Set the target to the touched position.
     MoveToToy.TargetObject.Position = %worldPosition;
     
@@ -181,11 +170,8 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
 
 //-----------------------------------------------------------------------------
 
-function SandboxWindow::onTouchMoved(%this, %touchID, %worldPosition)
+function MoveToToy::onTouchMoved(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchMoved(%this, %touchID, %worldPosition );
-    
     // Finish if not tracking the mouse.
     if ( !MoveToToy.trackMouse )
         return;
@@ -196,5 +182,3 @@ function SandboxWindow::onTouchMoved(%this, %touchID, %worldPosition)
     // Move the sight to the touched position.
     MoveToToy.SightObject.MoveTo( %worldPosition, MoveToToy.moveSpeed );     
 }
-    
-};

+ 221 - 0
modules/PickingToy/1/main.cs

@@ -0,0 +1,221 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+function PickingToy::create( %this )
+{
+    // Configure the toy.
+    PickingToy.PickType = Point;
+    PickingToy.PickMode = Any;
+    PickingToy.NotPickedAlpha = 0.2;
+    PickingToy.PickAreaSize = 10;
+    PickingToy.RayStart = "0 30";
+
+    // Add the configuration options.
+    addSelectionOption( "Point,Area,Circle,Ray", "Pick Type", 4, "setPickType", true, "Selects the picking type." );
+    addSelectionOption( "Any,OOBB,AABB,Collision", "Pick Mode", 4, "setPickMode", false, "Selects the picking mode." );
+
+    // Force-on debug options.
+    setAABBOption( true );
+    setOOBBOption( true );
+    setCollisionOption( true );
+    
+    // Reset the toy.
+    PickingToy.reset();
+}
+
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::destroy( %this )
+{
+    // Force-off debug options.
+    setAABBOption( false );
+    setOOBBOption( false );
+    setCollisionOption( false );    
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::reset( %this )
+{
+    // Clear the scene.
+    SandboxScene.clear();
+       
+    // Create background.
+    %this.createBackground();
+       
+    // Create target.
+    %this.createTarget();   
+    
+    // Create pick cursor.
+    %this.createPickCursor();
+    
+    // Create the ray-cast overlay.
+    %this.createRaycastOverlay();    
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::createBackground( %this )
+{    
+    // Create the sprite.
+    %object = SandboxScene.create( Sprite );
+    %object.BodyType = static;
+    %object.Position = "0 0";
+    %object.Size = "100 75";
+    %object.SceneLayer = 31;
+    %object.Image = "ToyAssets:highlightBackground";
+    %object.BlendColor = SlateGray;
+    %object.PickingAllowed = false;
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::createTarget( %this )
+{    
+    // Create the sprite.
+    %object = SandboxScene.create( Sprite );
+    %object.Size = 40;
+    %object.Angle = -30;
+    %object.Image = "ToyAssets:Tiles";
+    %object.Frame = 0;
+    %object.setBlendAlpha( PickingToy.NotPickedAlpha );
+    // Create some collision shapes.    
+    %object.createCircleCollisionShape( 10, "-20 -20" );
+    %object.createPolygonBoxCollisionShape( "20 20", "20 20" );
+    
+    // Set the target object.
+    PickingToy.TargetObject = %object;
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::createPickCursor( %this )
+{    
+    // Create the sprite.
+    %object = SandboxScene.create( Sprite );
+    %object.Size = PickingToy.PickAreaSize;
+    %object.BlendColor = Red;
+    %object.PickingAllowed = false;
+    
+    if ( PickingToy.PickType $= "point" || PickingToy.PickType $= "ray" )
+    {
+        %object.Image = "ToyAssets:CrossHair1";
+    }
+    else if ( PickingToy.PickType $= "area" )
+    {
+        %object.Image = "ToyAssets:Blank";
+    }
+    else if ( PickingToy.PickType $= "circle" )
+    {
+        %object.Image = "ToyAssets:BlankCircle";
+    }
+    
+    // Set the cursor.
+    PickingToy.CursorObject = %object;
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::createRaycastOverlay( %this )
+{    
+    // Finish if not in ray mode.
+    if ( PickingToy.PickType !$= "ray" )
+        return;
+    
+    // Create the sprite.
+    %object = SandboxScene.create( ShapeVector );
+    %object.Size = "1 1";
+    %object.PickingAllowed = false;
+    %object.IsCircle = false;
+    %object.FillMode = false;
+    %object.LineColor = Red;   
+    
+    // Set the ray-cast overlay object.
+    PickingToy.RaycastOverlay = %object;
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::onTouchMoved(%this, %touchID, %worldPosition)
+{
+    // Update cursor position.
+    PickingToy.CursorObject.Position = %worldPosition;
+    
+    // Are we in ray mode?
+    if ( PickingToy.PickType $= "ray" )
+    {
+        // Yes, so update the ray geometry.
+        PickingToy.RaycastOverlay.PolyList = PickingToy.RayStart SPC %worldPosition;
+    }    
+    
+    // Handle picking mode appropriately.
+    switch$( PickingToy.PickType )
+    {
+        case "point":
+            %picked = SandboxScene.pickPoint( %worldPosition, "", "", PickingToy.PickMode );
+        
+        case "area":
+            %halfSize = PickingToy.PickAreaSize * 0.5;
+            %lower = (%worldPosition._0 - %halfSize) SPC(%worldPosition._1 - %halfSize);    
+            %upper = (%worldPosition._0 + %halfSize) SPC(%worldPosition._1 + %halfSize);    
+            %picked = SandboxScene.pickArea( %lower, %upper, "", "", PickingToy.PickMode );
+            
+        case "ray":
+            %picked = SandboxScene.pickRay( PickingToy.RayStart, %worldPosition, "", "", PickingToy.PickMode );
+            
+        case "circle":
+            %halfSize = PickingToy.PickAreaSize * 0.5;
+            %picked = SandboxScene.pickCircle( %worldPosition, %halfSize, "", "", PickingToy.PickMode );
+    }
+        
+    // Fetch pick count.
+    %pickCount = %picked.Count;
+    
+    // See if the target object is amongst those picked.
+    for( %i = 0; %i < %pickCount; %i++ )
+    {
+        // If this is the target object then make it opaque.
+        if ( getWord( %picked, %i ) == PickingToy.TargetObject )
+        {
+            PickingToy.TargetObject.setBlendAlpha( 1.0 );
+            return;
+        }
+    }
+    
+    // Target not picked so make it transparent.
+    PickingToy.TargetObject.setBlendAlpha( 0.25 );
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::setPickMode( %this, %value )
+{
+    PickingToy.PickMode = %value;
+}
+
+//-----------------------------------------------------------------------------
+
+function PickingToy::setPickType( %this, %value )
+{
+    PickingToy.PickType = %value;
+}

+ 10 - 0
modules/PickingToy/1/module.taml

@@ -0,0 +1,10 @@
+<ModuleDefinition
+	ModuleId="PickingToy"
+	VersionId="1"
+	Description="Demonstrates picking."
+	Dependencies="ToyAssets=1"
+	Type="toy"
+	ToyCategoryIndex="3"
+	ScriptFile="main.cs"
+	CreateFunction="create"
+	DestroyFunction="destroy"/>

+ 1 - 12
modules/PointForceControllerToy/1/main.cs

@@ -22,9 +22,6 @@
 
 function PointForceControllerToy::create( %this )
 {
-    // Activate the package.
-    activatePackage( PointForceControllerToyPackage );    
-    
     // Set the sandbox drag mode availability.
     Sandbox.allowManipulation( pull );
     
@@ -322,14 +319,8 @@ function PointForceControllerToy::setAsteroidSpeed( %this, %value )
 
 //-----------------------------------------------------------------------------
 
-package PointForceControllerToyPackage
-{
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+function PointForceControllerToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-
     // Create an asteroid.
     %object = PointForceControllerToy.createAsteroid( %worldPosition );
     
@@ -338,5 +329,3 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
     else
         %object.setLinearVelocity( -PointForceControllerToy.asteroidSpeed, 0 );    
 }
-    
-};

+ 2 - 18
modules/RotateToToy/1/main.cs

@@ -22,9 +22,6 @@
 
 function RotateToToy::create( %this )
 {        
-    // Activate the package.
-    activatePackage( RotateToToyPackage );    
-    
     // Initialize the toys settings.
     RotateToToy.rotateSpeed = 360;
     RotateToToy.trackMouse = true;
@@ -42,8 +39,6 @@ function RotateToToy::create( %this )
 
 function RotateToToy::destroy( %this )
 {
-    // Deactivate the package.
-    deactivatePackage( RotateToToyPackage );
 }
 
 //-----------------------------------------------------------------------------
@@ -128,14 +123,8 @@ function RotateToToy::setTrackMouse( %this, %value )
 
 //-----------------------------------------------------------------------------
 
-package RotateToToyPackage
-{
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+function RotateToToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-    
     // Calculate the angle to the mouse.
     %origin = RotateToToy.TargetObject.getPosition();
     %angle = -mRadToDeg( mAtan( %worldPosition.x-%origin.x, %worldPosition.y-%origin.y ) );
@@ -146,11 +135,8 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
 
 //-----------------------------------------------------------------------------
 
-function SandboxWindow::onTouchMoved(%this, %touchID, %worldPosition)
+function RotateToToy::onTouchMoved(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchMoved(%this, %touchID, %worldPosition );
-    
     // Finish if not tracking the mouse.
     if ( !RotateToToy.trackMouse )
         return;
@@ -162,5 +148,3 @@ function SandboxWindow::onTouchMoved(%this, %touchID, %worldPosition)
     //Rotate to the touched angle.
     RotateToToy.TargetObject.RotateTo( %angle, RotateToToy.rotateSpeed );        
 }
-    
-};

+ 0 - 3
modules/Sandbox/1/assets/gui/ToolsIconDown.asset.taml

@@ -1,3 +0,0 @@
-<ImageAsset
-    AssetName="toolsIconDown"
-    ImageFile="toolsIconDown.png" />

+ 13 - 0
modules/Sandbox/1/gui/guiProfiles.cs

@@ -288,6 +288,19 @@ if(!isObject(GuiScrollProfile)) new GuiControlProfile (GuiScrollProfile)
 
 //-----------------------------------------------------------------------------
 
+if(!isObject(GuiTransparentScrollProfile)) new GuiControlProfile (GuiTransparentScrollProfile)
+{
+   opaque = false;
+   fillColor = "255 255 255";
+   border = false;
+   borderThickness = 2;
+   borderColor = "0 0 0";
+   bitmap = "^Sandbox/gui/images/scrollBar.png";
+   hasBitmapArray = true;
+};
+
+//-----------------------------------------------------------------------------
+
 if(!isObject(ConsoleScrollProfile)) new GuiControlProfile( ConsoleScrollProfile : GuiScrollProfile )
 {
     opaque = true;

+ 3 - 0
modules/Sandbox/1/main.cs

@@ -55,6 +55,9 @@ function Sandbox::create( %this )
     // Initialize the toolbox.    
     initializeToolbox();
     
+    // Initialize the input controller.
+    Sandbox.InputController.initialize();
+    
     // Initialize the "cannot render" proxy.
     new RenderProxy(CannotRenderProxy)
     {

+ 199 - 217
modules/Sandbox/1/scripts/manipulation.cs

@@ -30,9 +30,9 @@ Sandbox.ManipulationMode = "off";
 Sandbox.ManipulationPullMaxForce = 1000;
 
 // Reset the touch events.
-Sandbox.TouchController = new ScriptObject()
+Sandbox.InputController = new ScriptObject()
 {
-    class = SandboxTouchGesture;
+    class = SandboxInputController;
     TouchEventCount = 0;
     TouchEventActive[0] = false;
     TouchEventActive[1] = false;
@@ -45,100 +45,240 @@ Sandbox.TouchController = new ScriptObject()
 
 //-----------------------------------------------------------------------------
 
-function SandboxTouchGesture::onTouchDownEvent( %this, %touchId, %worldPosition )
+function SandboxInputController::initialize( %this )
 {
-    //echo( "SandboxTouchGesture::onTouchDownEvent(" @ %touchId @ "," @ %worldPosition @ ")" );
+    // Add sandbox touch gester as an input listener.
+    SandboxWindow.addInputListener( %this );
+}
+
+//-----------------------------------------------------------------------------
 
+function SandboxInputController::onTouchDown(%this, %touchID, %worldPosition)
+{
+    // Finish if the drag mode is off.
+    if ( Sandbox.ManipulationMode $= "off" )
+        return;
+        
     // Sanity!
     if ( %this.TouchEventActive[%touchId] == true )
     {
-        error( "SandboxTouchGesture::onTouchDownEvent() - Touch Id already active." );
-        return;        
+        error( "SandboxInputController::onTouchDown() - Touch Id already active." );
     }
+    else
+    {
+        // Calculate window position.
+        %windowPosition = SandboxWindow.getWindowPoint( %worldPosition );
 
-    // Calculate window position.
-    %windowPosition = SandboxWindow.getWindowPoint( %worldPosition );
-
-    // Store the new touch position.
-    %this.NewTouchPosition[%touchId] = %windowPosition;
+        // Store the new touch position.
+        %this.NewTouchPosition[%touchId] = %windowPosition;
+            
+        // Set the old touch position as new touch position.
+        %this.OldTouchPosition[%touchId] = %windowPosition;
         
-    // Set the old touch position as new touch position.
-    %this.OldTouchPosition[%touchId] = %windowPosition;
-    
-    // Flag event as active.
-    %this.TouchEventActive[%touchId] = true;
+        // Flag event as active.
+        %this.TouchEventActive[%touchId] = true;
 
-    // Insert the new touch Id.
-    %this.PreviousTouchId = %this.CurrentTouchId;
-    %this.CurrentTouchId = %touchId;
+        // Insert the new touch Id.
+        %this.PreviousTouchId = %this.CurrentTouchId;
+        %this.CurrentTouchId = %touchId;
 
-    // Increase event count.
-    %this.TouchEventCount++;
+        // Increase event count.
+        %this.TouchEventCount++;           
+    }
+                      
+           
+    // Handle "pull" mode.
+    if ( Sandbox.ManipulationMode $= "pull" )
+    {
+        // Reset the pull
+        Sandbox.ManipulationPullObject[%touchID] = "";
+        Sandbox.ManipulationPullJointId[%touchID] = "";
+        
+        // Pick an object.
+        %picked = SandboxScene.pickPoint( %worldPosition );
+        
+        // Finish if nothing picked.
+        if ( %picked $= "" )
+            return;
+        
+        // Fetch the pick count.
+        %pickCount = %picked.Count;
+        
+        for( %n = 0; %n < %pickCount; %n++ )
+        {
+            // Fetch the picked object.
+            %pickedObject = getWord( %picked, %n );
+            
+            // Skip if the object is static.
+            if ( %pickedObject.getBodyType() $= "static" )
+                continue;
+                
+            // Set the pull object.
+            Sandbox.ManipulationPullObject[%touchID] = %pickedObject;
+            Sandbox.ManipulationPullJointId[%touchID] = SandboxScene.createTargetJoint( %pickedObject, %worldPosition, Sandbox.ManipulationPullMaxForce );            
+            return;
+        }
+        
+        return;
+    }    
 }
 
 //-----------------------------------------------------------------------------
 
-function SandboxTouchGesture::onTouchUpEvent( %this, %touchId, %worldPosition )
+function SandboxInputController::onTouchUp(%this, %touchID, %worldPosition)
 {
-    //echo( "SandboxTouchGesture::onTouchUpEvent(" @ %touchId @ "," @ %worldPosition @ ")" );
-
+    // Finish if the drag mode is off.
+    if ( Sandbox.ManipulationMode $= "off" )
+        return;
+        
     // Sanity!
     if ( %this.TouchEventActive[%touchId] == false )
     {
-        error( "SandboxTouchGesture::onTouchUpEvent() - Touch Id not active." );
-        return;        
+        error( "SandboxInputController::onTouchUp() - Touch Id not active." );
     }
+    else
+    {    
+        // Reset previous touch.
+        %this.OldTouchPosition[%touchId] = "";
         
-    // Reset previous touch.
-    %this.OldTouchPosition[%touchId] = "";
-    
-    // Reset current touch.
-    %this.NewTouchPosition[%touchId] = "";
-    
-    // Flag event as inactive.
-    %this.TouchEventActive[%touchId] = false;
+        // Reset current touch.
+        %this.NewTouchPosition[%touchId] = "";
+        
+        // Flag event as inactive.
+        %this.TouchEventActive[%touchId] = false;
 
-    // Remove the touch Id.
-    if ( %this.PreviousTouchId == %touchId )
-    {
-         %this.PreviousTouchId = "";
-    }
-    if ( %this.CurrentTouchId == %touchId )
-    {
-         %this.CurrentTouchId = %this.PreviousTouchId;
-         %this.PreviousTouchId = "";
+        // Remove the touch Id.
+        if ( %this.PreviousTouchId == %touchId )
+        {
+             %this.PreviousTouchId = "";
+        }
+        if ( %this.CurrentTouchId == %touchId )
+        {
+             %this.CurrentTouchId = %this.PreviousTouchId;
+             %this.PreviousTouchId = "";
+        }
+
+        // Decrease event count.
+        %this.TouchEventCount--;
     }
 
-    // Decrease event count.
-    %this.TouchEventCount--;
+    // Handle "pull" mode.
+    if ( Sandbox.ManipulationMode $= "pull" )
+    {       
+        // Finish if nothing is being pulled.
+        if ( !isObject(Sandbox.ManipulationPullObject[%touchID]) )
+            return;
+        
+        // Reset the pull object.
+        Sandbox.ManipulationPullObject[%touchID] = "";
+        
+        // Remove the pull joint.
+        SandboxScene.deleteJoint( Sandbox.ManipulationPullJointId[%touchID] );
+        Sandbox.ManipulationPullJointId[%touchID] = "";        
+        return;
+    }      
 }
 
 //-----------------------------------------------------------------------------
 
-function SandboxTouchGesture::onTouchDraggedEvent( %this, %touchId, %worldPosition )
+function SandboxInputController::onTouchDragged(%this, %touchID, %worldPosition)
 {
-    //echo( "SandboxTouchGesture::onTouchDraggedEvent(" @ %touchId @ "," @ %worldPosition @ ")" );
+    // Finish if the drag mode is off.
+    if ( Sandbox.ManipulationMode $= "off" )
+        return;
 
     // Sanity!
     if ( %this.TouchEventActive[%touchId] == false )
     {
-        error( "SandboxTouchGesture::onTouchDraggedEvent() - Touch Id not active." );
-        return;        
+        error( "SandboxInputController::onTouchDraggedEvent() - Touch Id not active." );
     }
+    else
+    {
+        // Calculate window position.
+        %windowPosition = SandboxWindow.getWindowPoint( %worldPosition );
 
-    // Calculate window position.
-    %windowPosition = SandboxWindow.getWindowPoint( %worldPosition );
+        // Set the current touch as the previous touch.
+        %this.OldTouchPosition[%touchId] = %this.NewTouchPosition[%touchId];
+        
+        // Store the touch event.
+        %this.NewTouchPosition[%touchId] = %windowPosition;
+    }
+        
+    // Handle "pan" mode.
+    if ( Sandbox.ManipulationMode $= "pan" )
+    {
+        // Fetch the touch event count.
+        %touchEventCount = Sandbox.InputController.TouchEventCount;
+        
+        // Do we have a single touch event?
+        if ( %touchEventCount == 1 )
+        {
+            // Yes, so perform pan gesture.
+            Sandbox.InputController.performPanGesture();
+            
+            return;
+        }
+        
+        // Do we have two event counts?
+        if ( %touchEventCount == 2 )
+        {
+            // Yes, so perform zoom gesture.
+            Sandbox.InputController.performZoomGesture();
 
-    // Set the current touch as the previous touch.
-    %this.OldTouchPosition[%touchId] = %this.NewTouchPosition[%touchId];
+            return;
+        }
+    }
     
-    // Store the touch event.
-    %this.NewTouchPosition[%touchId] = %windowPosition;
+    // Handle "pull" mode.
+    if ( Sandbox.ManipulationMode $= "pull" )
+    {
+        // Finish if nothing is being pulled.
+        if ( !isObject(Sandbox.ManipulationPullObject[%touchID]) )
+            return;
+              
+        // Set a new target for the target joint.
+        SandboxScene.setTargetJointTarget( Sandbox.ManipulationPullJointId[%touchID], %worldPosition );
+        
+        return;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+function SandboxInputController::onTouchMoved(%this, %touchID, %worldPosition)
+{
+    // Finish if the drag mode is off.
+    if ( Sandbox.ManipulationMode $= "off" )
+        return;
+}
+
+//-----------------------------------------------------------------------------
+
+function SandboxInputController::onMouseWheelUp(%this, %modifier, %mousePoint, %mouseClickCount)
+{
+    // Finish if the drag mode is not "pan".
+    if ( !Sandbox.ManipulationMode $= "pan" )
+        return;
+        
+    // Increase the zoom.
+    SandboxWindow.setCameraZoom( SandboxWindow.getCameraZoom() + $pref::Sandbox::cameraMouseZoomRate );
 }
 
 //-----------------------------------------------------------------------------
 
-function SandboxTouchGesture::performPanGesture( %this )
+function SandboxInputController::onMouseWheelDown(%this, %modifier, %mousePoint, %mouseClickCount)
+{
+    // Finish if the drag mode is not "pan".
+    if ( !Sandbox.ManipulationMode $= "pan" )
+        return;
+
+    // Increase the zoom.
+    SandboxWindow.setCameraZoom( SandboxWindow.getCameraZoom() - $pref::Sandbox::cameraMouseZoomRate );
+}
+
+//-----------------------------------------------------------------------------
+
+function SandboxInputController::performPanGesture( %this )
 {
     // Finish if we don't have two touch events.
     if ( %this.TouchEventCount != 1 )
@@ -150,7 +290,7 @@ function SandboxTouchGesture::performPanGesture( %this )
     // Sanity!
     if ( %touchId $= "" )
     {
-        error( "SandboxTouchGesture::performPanGesture() - Current touch Id not available." );
+        error( "SandboxInputController::performPanGesture() - Current touch Id not available." );
         return;
     }
 
@@ -169,7 +309,7 @@ function SandboxTouchGesture::performPanGesture( %this )
 
 //-----------------------------------------------------------------------------
 
-function SandboxTouchGesture::performZoomGesture( %this )
+function SandboxInputController::performZoomGesture( %this )
 {
     // Finish if we don't have two touch events.
     if ( %this.TouchEventCount != 2 )
@@ -182,7 +322,7 @@ function SandboxTouchGesture::performZoomGesture( %this )
     // Finish if we don't have touch Ids active.
     if ( !%this.TouchEventActive[%currentTouchId] || !%this.TouchEventActive[%previousTouchId] )
     {
-        error( "SandboxTouchGesture::performZoomGesture() - Current or previous touch events were no active." );
+        error( "SandboxInputController::performZoomGesture() - Current or previous touch events were no active." );
         return;
     }
 
@@ -327,161 +467,3 @@ function cycleManipulation( %make )
         Sandbox.useManipulation("off");
     }          
 }
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
-{
-    // Finish if the drag mode is off.
-    if ( Sandbox.ManipulationMode $= "off" )
-        return;
-        
-    // Set touch event.
-    Sandbox.TouchController.onTouchDownEvent( %touchID, %worldPosition );
-           
-    // Handle "pull" mode.
-    if ( Sandbox.ManipulationMode $= "pull" )
-    {
-        // Reset the pull
-        Sandbox.ManipulationPullObject[%touchID] = "";
-        Sandbox.ManipulationPullJointId[%touchID] = "";
-        
-        // Pick an object.
-        %picked = SandboxScene.pickPoint( %worldPosition );
-        
-        // Finish if nothing picked.
-        if ( %picked $= "" )
-            return;
-        
-        // Fetch the pick count.
-        %pickCount = %picked.Count;
-        
-        for( %n = 0; %n < %pickCount; %n++ )
-        {
-            // Fetch the picked object.
-            %pickedObject = getWord( %picked, %n );
-            
-            // Skip if the object is static.
-            if ( %pickedObject.getBodyType() $= "static" )
-                continue;
-                
-            // Set the pull object.
-            Sandbox.ManipulationPullObject[%touchID] = %pickedObject;
-            Sandbox.ManipulationPullJointId[%touchID] = SandboxScene.createTargetJoint( %pickedObject, %worldPosition, Sandbox.ManipulationPullMaxForce );            
-            return;
-        }
-        
-        return;
-    }    
-}
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onTouchUp(%this, %touchID, %worldPosition)
-{
-    // Finish if the drag mode is off.
-    if ( Sandbox.ManipulationMode $= "off" )
-        return;
-        
-    // Set touch event.
-    Sandbox.TouchController.onTouchUpEvent( %touchID, %worldPosition );
-
-    // Handle "pull" mode.
-    if ( Sandbox.ManipulationMode $= "pull" )
-    {       
-        // Finish if nothing is being pulled.
-        if ( !isObject(Sandbox.ManipulationPullObject[%touchID]) )
-            return;
-        
-        // Reset the pull object.
-        Sandbox.ManipulationPullObject[%touchID] = "";
-        
-        // Remove the pull joint.
-        SandboxScene.deleteJoint( Sandbox.ManipulationPullJointId[%touchID] );
-        Sandbox.ManipulationPullJointId[%touchID] = "";        
-        return;
-    }      
-}
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onTouchMoved(%this, %touchID, %worldPosition)
-{
-    // Finish if the drag mode is off.
-    if ( Sandbox.ManipulationMode $= "off" )
-        return;
-}
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onTouchDragged(%this, %touchID, %worldPosition)
-{
-    // Finish if the drag mode is off.
-    if ( Sandbox.ManipulationMode $= "off" )
-        return;
-
-    // Set touch event.
-    Sandbox.TouchController.onTouchDraggedEvent( %touchID, %worldPosition );
-    
-    // Handle "pan" mode.
-    if ( Sandbox.ManipulationMode $= "pan" )
-    {
-        // Fetch the touch event count.
-        %touchEventCount = Sandbox.TouchController.TouchEventCount;
-        
-        // Do we have a single touch event?
-        if ( %touchEventCount == 1 )
-        {
-            // Yes, so perform pan gesture.
-            Sandbox.TouchController.performPanGesture();
-            
-            return;
-        }
-        
-        // Do we have two event counts?
-        if ( %touchEventCount == 2 )
-        {
-            // Yes, so perform zoom gesture.
-            Sandbox.TouchController.performZoomGesture();
-
-            return;
-        }
-    }
-    
-    // Handle "pull" mode.
-    if ( Sandbox.ManipulationMode $= "pull" )
-    {
-        // Finish if nothing is being pulled.
-        if ( !isObject(Sandbox.ManipulationPullObject[%touchID]) )
-            return;
-              
-        // Set a new target for the target joint.
-        SandboxScene.setTargetJointTarget( Sandbox.ManipulationPullJointId[%touchID], %worldPosition );
-        
-        return;
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onMouseWheelUp(%this, %modifier, %mousePoint, %mouseClickCount)
-{
-    // Finish if the drag mode is not "pan".
-    if ( !Sandbox.ManipulationMode $= "pan" )
-        return;
-        
-    // Increase the zoom.
-    SandboxWindow.setCameraZoom( SandboxWindow.getCameraZoom() + $pref::Sandbox::cameraMouseZoomRate );
-}
-
-//-----------------------------------------------------------------------------
-
-function SandboxWindow::onMouseWheelDown(%this, %modifier, %mousePoint, %mouseClickCount)
-{
-    // Finish if the drag mode is not "pan".
-    if ( !Sandbox.ManipulationMode $= "pan" )
-        return;
-
-    // Increase the zoom.
-    SandboxWindow.setCameraZoom( SandboxWindow.getCameraZoom() - $pref::Sandbox::cameraMouseZoomRate );
-}

+ 4 - 1
modules/Sandbox/1/scripts/toys.cs

@@ -85,7 +85,10 @@ function loadToy( %moduleDefinition )
     }
     
     // Add the scene so it's unloaded when the toy module is.
-    %moduleDefinition.ScopeSet.add( SandboxScene );        
+    %moduleDefinition.ScopeSet.add( SandboxScene );    
+    
+    // Add toy scope-set as a listener.
+    SandboxWindow.addInputListener( %moduleDefinition.ScopeSet );        
 }
 
 //-----------------------------------------------------------------------------

+ 1 - 15
modules/ScrollerToy/1/main.cs

@@ -22,9 +22,6 @@
 
 function ScrollerToy::create( %this )
 {
-    // Activate the package.
-    activatePackage( ScrollerToyPackage );  
-    
     // Reset the toy.
     ScrollerToy.reset();
 }
@@ -33,8 +30,6 @@ function ScrollerToy::create( %this )
 
 function ScrollerToy::destroy( %this )
 {
-    // Deactivate the package.
-    deactivatePackage( ScrollerToyPackage );    
 }
 
 //-----------------------------------------------------------------------------
@@ -151,14 +146,8 @@ function ScrollerToy::createNearScroller( %this )
 
 //-----------------------------------------------------------------------------
 
-package ScrollerToyPackage
-{
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+function ScrollerToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-
     // Set the scrollers speed to be the distance from the farground scrollers origin.
     // Also use the sign to control the direction of scrolling.
     %scrollerSpeed = %worldPosition.x - ScrollerToy.FarScroller.Position.x;
@@ -167,6 +156,3 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
     ScrollerToy.FarScroller.ScrollX = %scrollerSpeed;
     ScrollerToy.NearScroller.ScrollX = %scrollerSpeed * 1.5;
 }
-    
-};
-

+ 0 - 1
modules/SpriteToy/1/main.cs

@@ -32,7 +32,6 @@ function SpriteToy::create( %this )
     SpriteToy.reset();
 }
 
-
 //-----------------------------------------------------------------------------
 
 function SpriteToy::destroy( %this )

+ 1 - 1
modules/ToyAssets/1/assets/animations/Ice_Projectile_1Animation.asset.taml

@@ -1,6 +1,6 @@
 <AnimationAsset
     AssetName="Ice_Projectile_1Animation"
-    Image="@asset=ToyAssets:Ice_Projectile_1Sprite"
+    Image="@asset=ToyAssets:Ice_Projectile_1"
     animationFrames="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
     animationTime="1"
     animationCycle="1"

+ 1 - 1
modules/ToyAssets/1/assets/animations/Ice_Projectile_2Animation.asset.taml

@@ -1,6 +1,6 @@
 <AnimationAsset
     AssetName="Ice_Projectile_2Animation"
-    Image="@asset=ToyAssets:Ice_Projectile_2Sprite"
+    Image="@asset=ToyAssets:Ice_Projectile_2"
     animationFrames="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
     animationTime="1"
     animationCycle="1"

+ 1 - 1
modules/ToyAssets/1/assets/animations/Ice_Projectile_3Animation.asset.taml

@@ -1,6 +1,6 @@
 <AnimationAsset
     AssetName="Ice_Projectile_3Animation"
-    Image="@asset=ToyAssets:Ice_Projectile_3Sprite"
+    Image="@asset=ToyAssets:Ice_Projectile_3"
     animationFrames="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
     animationTime="1"
     animationCycle="1"

BIN
modules/ToyAssets/1/assets/images/BlankCircle.png


BIN
modules/ToyAssets/1/assets/images/Ice_Projectile_1.png


+ 8 - 0
modules/ToyAssets/1/assets/images/Ice_Projectile_1Sprite.asset.taml

@@ -0,0 +1,8 @@
+<ImageAsset
+    AssetName="Ice_Projectile_1"
+    imageFile="Ice_Projectile_1.png"
+    cellCountX="4"
+    cellCountY="4"
+    cellWidth="64"
+    cellHeight="64"
+	AssetCategory="sprites" />

BIN
modules/ToyAssets/1/assets/images/Ice_Projectile_2.png


+ 8 - 0
modules/ToyAssets/1/assets/images/Ice_Projectile_2Sprite.asset.taml

@@ -0,0 +1,8 @@
+<ImageAsset
+    AssetName="Ice_Projectile_2"
+    imageFile="Ice_Projectile_2.png"
+    cellCountX="4"
+    cellCountY="4"
+    cellWidth="64"
+    cellHeight="64"
+	AssetCategory="sprites" />

BIN
modules/ToyAssets/1/assets/images/Ice_Projectile_3.png


+ 8 - 0
modules/ToyAssets/1/assets/images/Ice_Projectile_3Sprite.asset.taml

@@ -0,0 +1,8 @@
+<ImageAsset
+    AssetName="Ice_Projectile_3"
+    imageFile="Ice_Projectile_3.png"
+    cellCountX="4"
+    cellCountY="4"
+    cellWidth="64"
+    cellHeight="64"
+	AssetCategory="sprites" />

+ 3 - 0
modules/ToyAssets/1/assets/images/blankCircle.asset.taml

@@ -0,0 +1,3 @@
+<ImageAsset
+    AssetName="BlankCircle"
+    ImageFile="BlankCircle.png"/>

+ 2 - 15
modules/TruckToy/1/main.cs

@@ -22,9 +22,6 @@
 
 function TruckToy::create( %this )
 {        
-    // Activate the package.
-    activatePackage( TruckToyPackage );
-
     TruckToy.ObstacleFriction = 1.5;
     TruckToy.CameraWidth = 20;
     TruckToy.CameraHeight = 15;
@@ -932,14 +929,8 @@ function TruckToy::setRotateCamera( %this, %value )
 
 //-----------------------------------------------------------------------------
 
-package TruckToyPackage
-{
-
-function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
+function TruckToy::onTouchDown(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchDown(%this, %touchID, %worldPosition );
-    
     // Finish if truck is already moving.
     if ( TruckToy.TruckMoving )
         return;
@@ -957,13 +948,9 @@ function SandboxWindow::onTouchDown(%this, %touchID, %worldPosition)
 
 //-----------------------------------------------------------------------------
 
-function SandboxWindow::onTouchUp(%this, %touchID, %worldPosition)
+function TruckToy::onTouchUp(%this, %touchID, %worldPosition)
 {
-    // Call parent.
-    Parent::onTouchUp(%this, %touchID, %worldPosition );
-    
     // Stop the truck.
     TruckToy.truckStop();
 }
     
-};