Bläddra i källkod

Merge remote-tracking branch 'refs/remotes/origin/development' into pr/1153

Anis A. Hireche 9 år sedan
förälder
incheckning
10cb6ab9c4
100 ändrade filer med 8583 tillägg och 471 borttagningar
  1. 2 0
      CMakeLists.txt
  2. 1 1
      Engine/lib/collada/src/dae/daeStringTable.cpp
  3. 5 1
      Engine/lib/convexDecomp/NvRemoveTjunctions.cpp
  4. 4 4
      Engine/lib/convexDecomp/NvSimpleTypes.h
  5. 1 1
      Engine/lib/libvorbis/lib/codebook.c
  6. 9 0
      Engine/lib/opcode/OPC_HybridModel.cpp
  7. 9 0
      Engine/lib/opcode/OPC_SweepAndPrune.cpp
  8. 38 13
      Engine/lib/tinyxml/tinyxml.h
  9. 0 23
      Engine/lib/tinyxml/tinyxmlparser.cpp
  10. 111 19
      Engine/source/T3D/aiPlayer.cpp
  11. 11 1
      Engine/source/T3D/aiPlayer.h
  12. 127 0
      Engine/source/T3D/assets/ExampleAsset.cpp
  13. 37 36
      Engine/source/T3D/assets/ExampleAsset.h
  14. 157 0
      Engine/source/T3D/assets/ShapeAsset.cpp
  15. 86 0
      Engine/source/T3D/assets/ShapeAsset.h
  16. 53 0
      Engine/source/T3D/camera.cpp
  17. 3 0
      Engine/source/T3D/camera.h
  18. 1 1
      Engine/source/T3D/convexShape.cpp
  19. 1 0
      Engine/source/T3D/decal/decalData.cpp
  20. 38 8
      Engine/source/T3D/decal/decalManager.cpp
  21. 1 1
      Engine/source/T3D/examples/renderMeshExample.cpp
  22. 8 5
      Engine/source/T3D/fps/guiClockHud.cpp
  23. 7 5
      Engine/source/T3D/fps/guiHealthTextHud.cpp
  24. 11 6
      Engine/source/T3D/fps/guiShapeNameHud.cpp
  25. 0 7
      Engine/source/T3D/fx/explosion.cpp
  26. 0 5
      Engine/source/T3D/fx/explosion.h
  27. 2 2
      Engine/source/T3D/fx/fxFoliageReplicator.cpp
  28. 2 2
      Engine/source/T3D/fx/fxFoliageReplicator.h
  29. 1 1
      Engine/source/T3D/fx/groundCover.cpp
  30. 1 0
      Engine/source/T3D/fx/lightning.cpp
  31. 1 1
      Engine/source/T3D/fx/precipitation.cpp
  32. 4 0
      Engine/source/T3D/gameBase/gameBase.h
  33. 40 5
      Engine/source/T3D/gameBase/gameConnection.cpp
  34. 6 2
      Engine/source/T3D/gameBase/gameConnection.h
  35. 2 1
      Engine/source/T3D/gameBase/gameConnectionEvents.cpp
  36. 37 12
      Engine/source/T3D/gameFunctions.cpp
  37. 0 8
      Engine/source/T3D/gameTSCtrl.cpp
  38. 0 10
      Engine/source/T3D/gameTSCtrl.h
  39. 2 2
      Engine/source/T3D/item.cpp
  40. 1 1
      Engine/source/T3D/item.h
  41. 3 2
      Engine/source/T3D/lightAnimData.cpp
  42. 9 1
      Engine/source/T3D/lightBase.cpp
  43. 2 1
      Engine/source/T3D/lightBase.h
  44. 10 0
      Engine/source/T3D/lightDescription.cpp
  45. 2 0
      Engine/source/T3D/lightDescription.h
  46. 2 2
      Engine/source/T3D/pathCamera.cpp
  47. 1 1
      Engine/source/T3D/pathCamera.h
  48. 5 1
      Engine/source/T3D/physics/bullet/bt.h
  49. 7 6
      Engine/source/T3D/physics/bullet/btPlayer.cpp
  50. 56 3
      Engine/source/T3D/player.cpp
  51. 2 0
      Engine/source/T3D/player.h
  52. 2 0
      Engine/source/T3D/pointLight.cpp
  53. 1 1
      Engine/source/T3D/projectile.cpp
  54. 2 2
      Engine/source/T3D/rigid.cpp
  55. 2 2
      Engine/source/T3D/rigidShape.cpp
  56. 1 1
      Engine/source/T3D/rigidShape.h
  57. 111 44
      Engine/source/T3D/shapeBase.cpp
  58. 11 4
      Engine/source/T3D/shapeBase.h
  59. 2 0
      Engine/source/T3D/spotLight.cpp
  60. 1 1
      Engine/source/T3D/trigger.cpp
  61. 5 5
      Engine/source/T3D/trigger.h
  62. 67 5
      Engine/source/T3D/tsStatic.cpp
  63. 9 0
      Engine/source/T3D/tsStatic.h
  64. 9 10
      Engine/source/T3D/turret/turretShape.cpp
  65. 3 0
      Engine/source/T3D/vehicles/wheeledVehicle.cpp
  66. 2 1
      Engine/source/app/badWordFilter.cpp
  67. 25 15
      Engine/source/app/mainLoop.cpp
  68. 3 8
      Engine/source/app/net/serverQuery.cpp
  69. 86 1
      Engine/source/app/net/tcpObject.cpp
  70. 11 1
      Engine/source/app/net/tcpObject.h
  71. 1 19
      Engine/source/app/version.cpp
  72. 352 0
      Engine/source/assets/assetBase.cpp
  73. 145 0
      Engine/source/assets/assetBase.h
  74. 41 0
      Engine/source/assets/assetBase_ScriptBinding.h
  75. 102 0
      Engine/source/assets/assetDefinition.h
  76. 114 0
      Engine/source/assets/assetFieldTypes.cpp
  77. 56 0
      Engine/source/assets/assetFieldTypes.h
  78. 3017 0
      Engine/source/assets/assetManager.cpp
  79. 395 0
      Engine/source/assets/assetManager.h
  80. 811 0
      Engine/source/assets/assetManager_ScriptBinding.h
  81. 184 0
      Engine/source/assets/assetPtr.h
  82. 121 0
      Engine/source/assets/assetQuery.cpp
  83. 90 0
      Engine/source/assets/assetQuery.h
  84. 85 0
      Engine/source/assets/assetQuery_ScriptBinding.h
  85. 564 0
      Engine/source/assets/assetTagsManifest.cpp
  86. 148 0
      Engine/source/assets/assetTagsManifest.h
  87. 151 0
      Engine/source/assets/assetTagsManifest_ScriptBinding.h
  88. 12 0
      Engine/source/assets/core.h
  89. 45 0
      Engine/source/assets/declaredAssets.cpp
  90. 73 0
      Engine/source/assets/declaredAssets.h
  91. 45 0
      Engine/source/assets/referencedAssets.cpp
  92. 73 0
      Engine/source/assets/referencedAssets.h
  93. 132 0
      Engine/source/assets/tamlAssetDeclaredUpdateVisitor.h
  94. 189 0
      Engine/source/assets/tamlAssetDeclaredVisitor.h
  95. 127 0
      Engine/source/assets/tamlAssetReferencedUpdateVisitor.h
  96. 96 0
      Engine/source/assets/tamlAssetReferencedVisitor.h
  97. 3 2
      Engine/source/cinterface/c_scripting.cpp
  98. 1 1
      Engine/source/collision/boxConvex.cpp
  99. 136 146
      Engine/source/console/CMDscan.cpp
  100. 2 1
      Engine/source/console/CMDscan.l

+ 2 - 0
CMakeLists.txt

@@ -2,6 +2,8 @@ cmake_minimum_required (VERSION 2.8.12)
 
 set(TORQUE_APP_NAME "" CACHE STRING "the app name")
 
+set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/temp" CACHE PATH "default install path" FORCE )
+
 if("${TORQUE_APP_NAME}" STREQUAL "")
 	message(FATAL_ERROR "Please set TORQUE_APP_NAME first")
 endif()

+ 1 - 1
Engine/lib/collada/src/dae/daeStringTable.cpp

@@ -58,7 +58,7 @@ void daeStringTable::clear()
 {
 	unsigned int i;
 	for (i=0;i<_stringBuffersList.getCount();i++)
-#if _MSC_VER <= 1200
+#if defined(_MSC_VER) && (_MSC_VER <= 1200)
 		delete [] (char *) _stringBuffersList[i];
 #else
 		delete [] _stringBuffersList[i];

+ 5 - 1
Engine/lib/convexDecomp/NvRemoveTjunctions.cpp

@@ -60,8 +60,12 @@ NvRemoveTjunctions.cpp : A code snippet to remove tjunctions from a triangle mes
 #include <vector>
 #ifdef __APPLE__
    #include <ext/hash_map>
-#else
+#elif LINUX
    #include <hash_map>
+#elif _MSC_VER < 1500
+   #include <hash_map>
+#elif _MSC_VER > 1800
+   #include <unordered_map>
 #endif
 #include "NvUserMemAlloc.h"
 #include "NvHashMap.h"

+ 4 - 4
Engine/lib/convexDecomp/NvSimpleTypes.h

@@ -87,7 +87,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 		
-#elif LINUX
+#elif defined(LINUX)
 	typedef long long			NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;
@@ -101,7 +101,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 
-#elif __APPLE__
+#elif defined(__APPLE__)
 	typedef long long			NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;
@@ -115,7 +115,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 
-#elif __CELLOS_LV2__
+#elif defined(__CELLOS_LV2__)
 	typedef long long			NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;
@@ -129,7 +129,7 @@ NvSimpleTypes.h : Defines basic data types for integers and floats.
 	typedef float				NxF32;
 	typedef double				NxF64;
 
-#elif _XBOX
+#elif defined(_XBOX)
 	typedef __int64				NxI64;
 	typedef signed int			NxI32;
 	typedef signed short		NxI16;

+ 1 - 1
Engine/lib/libvorbis/lib/codebook.c

@@ -450,7 +450,7 @@ long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){
       }
     }
   }else{
-    int i,j;
+    int i;
 
     for(i=0;i<n;){
       a[i++]=0.f;

+ 9 - 0
Engine/lib/opcode/OPC_HybridModel.cpp

@@ -82,7 +82,16 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 #include "Opcode.h"
+
+#if (defined _MSC_VER) && (_MSC_VER <= 1500)
+#ifdef _WIN64 // [
+typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+#else
 #include <stdint.h>
+#endif
 
 using namespace Opcode;
 

+ 9 - 0
Engine/lib/opcode/OPC_SweepAndPrune.cpp

@@ -17,7 +17,16 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 #include "Opcode.h"
+
+#if (defined _MSC_VER) && (_MSC_VER <= 1500)
+#ifdef _WIN64 // [
+typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+#else
 #include <stdint.h>
+#endif
 
 using namespace Opcode;
 

+ 38 - 13
Engine/lib/tinyxml/tinyxml.h

@@ -283,10 +283,9 @@ public:
 		TIXML_ERROR_STRING_COUNT
 	};
 
-protected:
-
 	static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
 
+protected:
 	inline static bool IsWhiteSpace( char c )		
 	{ 
 		return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); 
@@ -360,6 +359,7 @@ protected:
 		}
 	}
 
+public:
 	// Return true if the next characters in the stream are any of the endTag sequences.
 	// Ignore case only works for english, and should only be relied on when comparing
 	// to English words: StringEqual( p, "version", true ) is fine.
@@ -368,6 +368,7 @@ protected:
 								bool ignoreCase,
 								TiXmlEncoding encoding );
 
+protected:
 	static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
 
 	TiXmlCursor location;
@@ -375,10 +376,13 @@ protected:
     /// Field containing a generic user pointer
 	void*			userData;
 	
+public:
 	// None of these methods are reliable for any language except English.
 	// Good for approximation, not great for accuracy.
 	static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
 	static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+
+protected:
 	inline static int ToLower( int v, TiXmlEncoding encoding )
 	{
 		if ( encoding == TIXML_ENCODING_UTF8 )
@@ -750,9 +754,10 @@ protected:
 	#endif
 
 	// Figure out what is at *p, and parse it. Returns null if it is not an xml node.
-	TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
-
+	virtual TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+public:
 	TiXmlNode*		parent;
+protected:
 	NodeType		type;
 
 	TiXmlNode*		firstChild;
@@ -1047,7 +1052,7 @@ public:
 	/** Sets an attribute of name to a given value. The attribute
 		will be created if it does not exist, or changed if it does.
 	*/
-	void SetAttribute( const char* name, const char * _value );
+	virtual void SetAttribute( const char* name, const char * _value );
 
     #ifdef TIXML_USE_STL
 	const std::string* Attribute( const std::string& name ) const;
@@ -1067,7 +1072,7 @@ public:
 	/** Sets an attribute of name to a given value. The attribute
 		will be created if it does not exist, or changed if it does.
 	*/
-	void SetAttribute( const char * name, int value );
+	virtual void SetAttribute( const char * name, int value );
 
 	/** Sets an attribute of name to a given value. The attribute
 		will be created if it does not exist, or changed if it does.
@@ -1152,7 +1157,6 @@ protected:
 	*/
 	const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
 
-private:
 	TiXmlAttributeSet attributeSet;
 };
 
@@ -1264,7 +1268,6 @@ protected :
 	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
 	#endif
 
-private:
 	bool cdata;			// true if this should be input and output as a CDATA style text element
 };
 
@@ -1336,8 +1339,6 @@ protected:
 	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
 	#endif
 
-private:
-
 	TIXML_STRING version;
 	TIXML_STRING encoding;
 	TIXML_STRING standalone;
@@ -1416,9 +1417,9 @@ public:
 	/// Save a file using the current document value. Returns true if successful.
 	bool SaveFile() const;
 	/// Load a file using the given filename. Returns true if successful.
-	bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	virtual bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
 	/// Save a file using the given filename. Returns true if successful.
-	bool SaveFile( const char * filename ) const;
+	virtual bool SaveFile( const char * filename ) const;
 	/** Load a file using the given FILE*. Returns true if successful. Note that this method
 		doesn't stream - the entire object pointed at by the FILE*
 		will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
@@ -1543,14 +1544,15 @@ protected :
 	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
 	#endif
 
-private:
 	void CopyTo( TiXmlDocument* target ) const;
 
+private:
 	bool error;
 	int  errorId;
 	TIXML_STRING errorDesc;
 	int tabsize;
 	TiXmlCursor errorLocation;
+protected:
 	bool useMicrosoftBOM;		// the UTF-8 BOM were found when read. Note this, and try to write.
 };
 
@@ -1797,6 +1799,29 @@ private:
 	TIXML_STRING lineBreak;
 };
 
+class TiXmlParsingData
+{
+	friend class TiXmlDocument;
+  public:
+	void Stamp( const char* now, TiXmlEncoding encoding );
+
+	const TiXmlCursor& Cursor() const	{ return cursor; }
+
+  private:
+	// Only used by the document!
+	TiXmlParsingData( const char* start, int _tabsize, int row, int col )
+	{
+		assert( start );
+		stamp = start;
+		tabsize = _tabsize;
+		cursor.row = row;
+		cursor.col = col;
+	}
+
+	TiXmlCursor		cursor;
+	const char*		stamp;
+	int				tabsize;
+};
 
 #ifdef _MSC_VER
 #pragma warning( pop )

+ 0 - 23
Engine/lib/tinyxml/tinyxmlparser.cpp

@@ -168,29 +168,6 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng
 }
 
 
-class TiXmlParsingData
-{
-	friend class TiXmlDocument;
-  public:
-	void Stamp( const char* now, TiXmlEncoding encoding );
-
-	const TiXmlCursor& Cursor() const	{ return cursor; }
-
-  private:
-	// Only used by the document!
-	TiXmlParsingData( const char* start, int _tabsize, int row, int col )
-	{
-		assert( start );
-		stamp = start;
-		tabsize = _tabsize;
-		cursor.row = row;
-		cursor.col = col;
-	}
-
-	TiXmlCursor		cursor;
-	const char*		stamp;
-	int				tabsize;
-};
 
 
 void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )

+ 111 - 19
Engine/source/T3D/aiPlayer.cpp

@@ -28,6 +28,8 @@
 #include "T3D/gameBase/moveManager.h"
 #include "console/engineAPI.h"
 
+#include <cfloat>
+
 static U32 sAIPlayerLoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
 
 IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
@@ -107,6 +109,9 @@ AIPlayer::AIPlayer()
 #endif
 
    mIsAiControlled = true;
+
+   for( S32 i = 0; i < MaxTriggerKeys; i ++ )
+      mMoveTriggers[ i ] = false;
 }
 
 /**
@@ -254,7 +259,7 @@ void AIPlayer::setAimObject( GameBase *targetObject )
  * @param targetObject The object to target
  * @param offset       The offest from the target location to aim at
  */
-void AIPlayer::setAimObject( GameBase *targetObject, Point3F offset )
+void AIPlayer::setAimObject(GameBase *targetObject, const Point3F& offset)
 {
    mAimObject = targetObject;
    mTargetInLOS = false;
@@ -285,6 +290,53 @@ void AIPlayer::clearAim()
    mAimOffset = Point3F(0.0f, 0.0f, 0.0f);
 }
 
+/**
+ * Set the state of a movement trigger.
+ *
+ * @param slot The trigger slot to set
+ * @param isSet set/unset the trigger
+ */
+void AIPlayer::setMoveTrigger( U32 slot, const bool isSet )
+{
+   if(slot >= MaxTriggerKeys)
+   {
+      Con::errorf("Attempting to set an invalid trigger slot (%i)", slot);
+   }
+   else
+   {
+      mMoveTriggers[ slot ] = isSet;   // set the trigger
+      setMaskBits(NoWarpMask);         // force the client to updateMove
+   }
+}
+
+/**
+ * Get the state of a movement trigger.
+ *
+ * @param slot The trigger slot to query
+ * @return True if the trigger is set, false if it is not set
+ */
+bool AIPlayer::getMoveTrigger( U32 slot ) const
+{
+   if(slot >= MaxTriggerKeys)
+   {
+      Con::errorf("Attempting to get an invalid trigger slot (%i)", slot);
+      return false;
+   }
+   else
+   {
+      return mMoveTriggers[ slot ];
+   }
+}
+
+/**
+ * Clear the trigger state for all movement triggers.
+ */
+void AIPlayer::clearMoveTriggers()
+{
+   for( U32 i = 0; i < MaxTriggerKeys; i ++ )
+      setMoveTrigger( i, false );
+}
+
 /**
  * This method calculates the moves for the AI player
  *
@@ -513,8 +565,8 @@ bool AIPlayer::getAIMove(Move *movePtr)
 
    // Replicate the trigger state into the move so that
    // triggers can be controlled from scripts.
-   for( int i = 0; i < MaxTriggerKeys; i++ )
-      movePtr->trigger[i] = getImageTriggerState(i);
+   for( U32 i = 0; i < MaxTriggerKeys; i++ )
+      movePtr->trigger[ i ] = mMoveTriggers[ i ];
 
 #ifdef TORQUE_NAVIGATION_ENABLED
    if(mJump == Now)
@@ -673,24 +725,20 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
 
    // Create a new path.
    NavPath *path = new NavPath();
-   if(path)
+
+   path->mMesh = getNavMesh();
+   path->mFrom = getPosition();
+   path->mTo = pos;
+   path->mFromSet = path->mToSet = true;
+   path->mAlwaysRender = true;
+   path->mLinkTypes = mLinkTypes;
+   path->mXray = true;
+   // Paths plan automatically upon being registered.
+   if(!path->registerObject())
    {
-      path->mMesh = getNavMesh();
-      path->mFrom = getPosition();
-      path->mTo = pos;
-      path->mFromSet = path->mToSet = true;
-      path->mAlwaysRender = true;
-      path->mLinkTypes = mLinkTypes;
-      path->mXray = true;
-      // Paths plan automatically upon being registered.
-      if(!path->registerObject())
-      {
-         delete path;
-         return false;
-      }
-   }
-   else
+      delete path;
       return false;
+   }
 
    if(path->success())
    {
@@ -779,11 +827,15 @@ void AIPlayer::followObject(SceneObject *obj, F32 radius)
    if(!isServerObject())
       return;
 
+   if ((mFollowData.lastPos - obj->getPosition()).len()<mMoveTolerance)
+      return;
+
    if(setPathDestination(obj->getPosition()))
    {
       clearCover();
       mFollowData.object = obj;
       mFollowData.radius = radius;
+      mFollowData.lastPos = obj->getPosition();
    }
 }
 
@@ -1256,3 +1308,43 @@ DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool ch
 {
    return object->checkInFoV(obj, fov, checkEnabled);
 }
+
+DefineEngineMethod( AIPlayer, setMoveTrigger, void, ( U32 slot ),,
+   "@brief Sets a movement trigger on an AI object.\n\n"
+   "@param slot The trigger slot to set.\n"
+   "@see getMoveTrigger()\n"
+   "@see clearMoveTrigger()\n"
+   "@see clearMoveTriggers()\n")
+{
+   object->setMoveTrigger( slot, true );
+}
+
+DefineEngineMethod( AIPlayer, clearMoveTrigger, void, ( U32 slot ),,
+   "@brief Clears a movement trigger on an AI object.\n\n"
+   "@param slot The trigger slot to set.\n"
+   "@see setMoveTrigger()\n"
+   "@see getMoveTrigger()\n"
+   "@see clearMoveTriggers()\n")
+{
+   object->setMoveTrigger( slot, false );
+}
+
+DefineEngineMethod( AIPlayer, getMoveTrigger, bool, ( U32 slot ),,
+   "@brief Tests if a movement trigger on an AI object is set.\n\n"
+   "@param slot The trigger slot to check.\n"
+   "@return a boolean indicating if the trigger is set/unset.\n"
+   "@see setMoveTrigger()\n"
+   "@see clearMoveTrigger()\n"
+   "@see clearMoveTriggers()\n")
+{
+   return object->getMoveTrigger( slot );
+}
+
+DefineEngineMethod( AIPlayer, clearMoveTriggers, void, ( ),,
+   "@brief Clear ALL movement triggers on an AI object.\n"
+   "@see setMoveTrigger()\n"
+   "@see getMoveTrigger()\n"
+   "@see clearMoveTrigger()\n")
+{
+   object->clearMoveTriggers();
+}

+ 11 - 1
Engine/source/T3D/aiPlayer.h

@@ -63,6 +63,9 @@ private:
 
    Point3F mAimOffset;
 
+   // move triggers
+   bool mMoveTriggers[MaxTriggerKeys];
+
    // Utility Methods
    void throwCallback( const char *name );
 
@@ -119,10 +122,12 @@ private:
       SimObjectPtr<SceneObject> object;
       /// Distance at whcih to follow.
       F32 radius;
+      Point3F lastPos;
       /// Default constructor.
       FollowData() : object(NULL)
       {
          radius = 5.0f;
+         lastPos = Point3F::Zero;
       }
    };
 
@@ -158,7 +163,7 @@ public:
 
    // Targeting and aiming sets/gets
    void setAimObject( GameBase *targetObject );
-   void setAimObject( GameBase *targetObject, Point3F offset );
+   void setAimObject(GameBase *targetObject, const Point3F& offset);
    GameBase* getAimObject() const  { return mAimObject; }
    void setAimLocation( const Point3F &location );
    Point3F getAimLocation() const { return mAimLocation; }
@@ -175,6 +180,11 @@ public:
    Point3F getMoveDestination() const { return mMoveDestination; }
    void stopMove();
 
+   // Trigger sets/gets
+   void setMoveTrigger( U32 slot, const bool isSet = true );
+   bool getMoveTrigger( U32 slot ) const;
+   void clearMoveTriggers();
+
 #ifdef TORQUE_NAVIGATION_ENABLED
    /// @name Pathfinding
    /// @{

+ 127 - 0
Engine/source/T3D/assets/ExampleAsset.cpp

@@ -0,0 +1,127 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _EXAMPLE_ASSET_H_
+#include "ExampleAsset.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assets/assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _TAML_
+#include "persistence/taml/taml.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(ExampleAsset);
+
+ConsoleType(ExampleAssetPtr, TypeExampleAssetPtr, ExampleAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeExampleAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ExampleAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeExampleAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ExampleAsset>* pAssetPtr = dynamic_cast<AssetPtr<ExampleAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ExampleAsset::ExampleAsset() :
+mAcquireReferenceCount(0),
+mpOwningAssetManager(NULL),
+mAssetInitialized(false)
+{
+   // Generate an asset definition.
+   mpAssetDefinition = new AssetDefinition();
+}
+
+//-----------------------------------------------------------------------------
+
+ExampleAsset::~ExampleAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ExampleAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+}
+
+//------------------------------------------------------------------------------
+
+void ExampleAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}

+ 37 - 36
Engine/source/platform/input/oculusVR/barrelDistortionPostEffect.h → Engine/source/T3D/assets/ExampleAsset.h

@@ -1,5 +1,5 @@
 //-----------------------------------------------------------------------------
-// Copyright (c) 2012 GarageGames, LLC
+// 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
@@ -19,51 +19,52 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
+#ifndef _EXAMPLE_ASSET_H_
+#define _EXAMPLE_ASSET_H_
 
-#ifndef _BARRELDISTORTIONPOSTEFFECT_H_
-#define _BARRELDISTORTIONPOSTEFFECT_H_
+#ifndef _ASSET_BASE_H_
+#include "assets/assetBase.h"
+#endif
 
-#include "postFx/postEffect.h"
+#ifndef _ASSET_DEFINITION_H_
+#include "assets/assetDefinition.h"
+#endif
 
-class BarrelDistortionPostEffect : public PostEffect
-{
-   typedef PostEffect Parent;
-
-protected:
-   GFXShaderConstHandle *mHmdWarpParamSC;
-   GFXShaderConstHandle *mHmdChromaAbSC;
-   GFXShaderConstHandle *mScaleSC;
-   GFXShaderConstHandle *mScaleInSC;
-   GFXShaderConstHandle *mLensCenterSC;
-   GFXShaderConstHandle *mScreenCenterSC;
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
 
-   // Oculus VR HMD index to reference
-   S32 mHMDIndex;
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
 
-   // Oculus VR sensor index to reference
-   S32 mSensorIndex;
-
-   // Used to increase the size of the window into the world at the
-   // expense of apparent resolution.
-   F32 mScaleOutput;
+//-----------------------------------------------------------------------------
+class ExampleAsset : public AssetBase
+{
+   typedef AssetBase Parent;
 
-protected:
-   virtual void _setupConstants( const SceneRenderState *state );
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
 
 public:
-   BarrelDistortionPostEffect();
-   virtual ~BarrelDistortionPostEffect();
-
-   DECLARE_CONOBJECT(BarrelDistortionPostEffect);
+   ExampleAsset();
+   virtual ~ExampleAsset();
 
-   // SimObject
-   virtual bool onAdd();
-   virtual void onRemove();
+   /// Engine.
    static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ExampleAsset);
 
-   virtual void process(   const SceneRenderState *state, 
-                           GFXTexHandle &inOutTex,
-                           const RectI *inTexViewport = NULL );
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
 };
 
-#endif   // _BARRELDISTORTIONPOSTEFFECT_H_
+DefineConsoleType(TypeExampleAssetPtr, ExampleAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 157 - 0
Engine/source/T3D/assets/ShapeAsset.cpp

@@ -0,0 +1,157 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _SHAPE_ASSET_H_
+#include "ShapeAsset.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assets/assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _TAML_
+#include "persistence/taml/taml.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+#include "core/resourceManager.h"
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+static U32 execDepth = 0;
+static U32 journalDepth = 1;
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(ShapeAsset);
+
+ConsoleType(TestAssetPtr, TypeShapeAssetPtr, ShapeAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeShapeAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ShapeAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeShapeAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ShapeAsset>* pAssetPtr = dynamic_cast<AssetPtr<ShapeAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ShapeAsset::ShapeAsset() :
+mAcquireReferenceCount(0),
+mpOwningAssetManager(NULL),
+mAssetInitialized(false)
+{
+   // Generate an asset definition.
+   mpAssetDefinition = new AssetDefinition();
+}
+
+//-----------------------------------------------------------------------------
+
+ShapeAsset::~ShapeAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ShapeAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("fileName", TypeFilename, Offset(mFileName, ShapeAsset), "Path to the script file we want to execute");
+}
+
+void ShapeAsset::initializeAsset()
+{
+   // Call parent.
+   Parent::initializeAsset();
+
+   if (dStrcmp(mFileName, "") == 0)
+      return;
+
+   loadShape();
+}
+
+bool ShapeAsset::loadShape()
+{
+   mShape = ResourceManager::get().load(mFileName);
+
+   if (!mShape)
+   {
+      Con::errorf("StaticMesh::updateShape : failed to load shape file!");
+      return false; //if it failed to load, bail out
+   }
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+
+void ShapeAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}

+ 86 - 0
Engine/source/T3D/assets/ShapeAsset.h

@@ -0,0 +1,86 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+#ifndef _SHAPE_ASSET_H_
+#define _SHAPE_ASSET_H_
+
+#ifndef _ASSET_BASE_H_
+#include "assets/assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assets/assetDefinition.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+#ifndef _TSSHAPE_H_
+#include "ts/tsShape.h"
+#endif
+#ifndef __RESOURCE_H__
+#include "core/resource.h"
+#endif
+
+//-----------------------------------------------------------------------------
+class ShapeAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
+
+protected:
+   StringTableEntry   mFileName;
+   Resource<TSShape>	 mShape;
+
+public:
+   ShapeAsset();
+   virtual ~ShapeAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   virtual void initializeAsset();
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ShapeAsset);
+
+   bool loadShape();
+
+   TSShape* getShape() { return mShape; }
+
+protected:
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypeShapeAssetPtr, ShapeAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 53 - 0
Engine/source/T3D/camera.cpp

@@ -279,6 +279,7 @@ Camera::Camera()
 
    mLastAbsoluteYaw = 0.0f;
    mLastAbsolutePitch = 0.0f;
+   mLastAbsoluteRoll = 0.0f;
 
    // For NewtonFlyMode
    mNewtonRotation = false;
@@ -379,6 +380,57 @@ void Camera::getCameraTransform(F32* pos, MatrixF* mat)
    mat->mul( gCamFXMgr.getTrans() );
 }
 
+void Camera::getEyeCameraTransform(IDisplayDevice *displayDevice, U32 eyeId, MatrixF *outMat)
+{
+   // The camera doesn't support a third person mode,
+   // so we want to override the default ShapeBase behavior.
+   ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
+   if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
+      obj->getEyeCameraTransform(displayDevice, eyeId, outMat);
+   else
+   {
+      Parent::getEyeCameraTransform(displayDevice, eyeId, outMat);
+   }
+}
+
+DisplayPose Camera::calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose)
+{
+   // NOTE: this is intended to be similar to updateMove
+   DisplayPose outPose;
+   outPose.orientation = EulerF(0,0,0);
+   outPose.position = inPose.position;
+
+   // Pitch
+   outPose.orientation.x = (inPose.orientation.x - mLastAbsolutePitch);
+
+   // Constrain the range of mRot.x
+   while (outPose.orientation.x  < -M_PI_F) 
+      outPose.orientation.x += M_2PI_F;
+   while (outPose.orientation.x  > M_PI_F) 
+      outPose.orientation.x -= M_2PI_F;
+
+   // Yaw
+   outPose.orientation.z = (inPose.orientation.z - mLastAbsoluteYaw);
+
+   // Constrain the range of mRot.z
+   while (outPose.orientation.z < -M_PI_F) 
+      outPose.orientation.z += M_2PI_F;
+   while (outPose.orientation.z > M_PI_F) 
+      outPose.orientation.z -= M_2PI_F;
+
+   // Bank
+   if (mDataBlock->cameraCanBank)
+   {
+      outPose.orientation.y = (inPose.orientation.y - mLastAbsoluteRoll);
+   }
+
+   // Constrain the range of mRot.y
+   while (outPose.orientation.y > M_PI_F) 
+      outPose.orientation.y -= M_2PI_F;
+
+   return outPose;
+}
+
 //----------------------------------------------------------------------------
 
 F32 Camera::getCameraFov()
@@ -547,6 +599,7 @@ void Camera::processTick(const Move* move)
 
                mLastAbsoluteYaw = emove->rotZ[emoveIndex];
                mLastAbsolutePitch = emove->rotX[emoveIndex];
+               mLastAbsoluteRoll = emove->rotY[emoveIndex];
 
                // Bank
                mRot.y = emove->rotY[emoveIndex];

+ 3 - 0
Engine/source/T3D/camera.h

@@ -113,6 +113,7 @@ class Camera: public ShapeBase
 
       F32 mLastAbsoluteYaw;            ///< Stores that last absolute yaw value as passed in by ExtendedMove
       F32 mLastAbsolutePitch;          ///< Stores that last absolute pitch value as passed in by ExtendedMove
+      F32 mLastAbsoluteRoll;           ///< Stores that last absolute roll value as passed in by ExtendedMove
 
       /// @name NewtonFlyMode
       /// @{
@@ -235,6 +236,8 @@ class Camera: public ShapeBase
       virtual void processTick( const Move* move );
       virtual void interpolateTick( F32 delta);
       virtual void getCameraTransform( F32* pos,MatrixF* mat );
+      virtual void getEyeCameraTransform( IDisplayDevice *display, U32 eyeId, MatrixF *outMat );
+      virtual DisplayPose calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose);
 
       virtual void writePacketData( GameConnection* conn, BitStream* stream );
       virtual void readPacketData( GameConnection* conn, BitStream* stream );

+ 1 - 1
Engine/source/T3D/convexShape.cpp

@@ -502,7 +502,7 @@ void ConvexShape::prepRenderImage( SceneRenderState *state )
    }
    */
 
-   if ( mVertexBuffer.isNull() )
+   if ( mVertexBuffer.isNull() || !state)
       return;
 
    // If we don't have a material instance after the override then 

+ 1 - 0
Engine/source/T3D/decal/decalData.cpp

@@ -284,6 +284,7 @@ void DecalData::unpackData( BitStream *stream )
    Parent::unpackData( stream );
 
    stream->read( &lookupName );
+   assignName(lookupName);
    stream->read( &size );  
    stream->read( &materialName );
    _updateMaterial();

+ 38 - 8
Engine/source/T3D/decal/decalManager.cpp

@@ -1235,8 +1235,30 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
          currentBatch = &batches.last();
          currentBatch->startDecal = i;
          currentBatch->decalCount = 1;
-         currentBatch->iCount = decal->mIndxCount;
-         currentBatch->vCount = decal->mVertCount;
+
+         // Shrink and warning: preventing a potential crash.
+         currentBatch->iCount =
+             (decal->mIndxCount > smMaxIndices) ? smMaxIndices : decal->mIndxCount;
+         currentBatch->vCount =
+             (decal->mVertCount > smMaxVerts) ? smMaxVerts : decal->mVertCount;
+#ifdef TORQUE_DEBUG
+         // we didn't mean send a spam to the console
+         static U32 countMsgIndx = 0;
+         if ( (decal->mIndxCount > smMaxIndices) && ((countMsgIndx++ % 1024) == 0) ) {
+            Con::warnf(
+               "DecalManager::prepRenderImage() - Shrinked indices of decal."
+               " Lost %u.",  (decal->mIndxCount - smMaxIndices)
+            );
+         }
+         static U32 countMsgVert = 0;
+         if ( (decal->mVertCount > smMaxVerts) && ((countMsgVert++ % 1024) == 0) ) {
+            Con::warnf(
+               "DecalManager::prepRenderImage() - Shrinked vertices of decal."
+               " Lost %u.",  (decal->mVertCount - smMaxVerts)
+            );
+         }
+#endif
+
          currentBatch->mat = mat;
          currentBatch->matInst = decal->mDataBlock->getMaterialInstance();
          currentBatch->priority = decal->getRenderPriority();         
@@ -1299,15 +1321,21 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
       {
          DecalInstance *dinst = mDecalQueue[j];
 
-         for ( U32 k = 0; k < dinst->mIndxCount; k++ )
+         const U32 indxCount =
+             (dinst->mIndxCount > currentBatch.iCount) ?
+             currentBatch.iCount : dinst->mIndxCount;
+         for ( U32 k = 0; k < indxCount; k++ )
          {
             *( pbPtr + ioffset + k ) = dinst->mIndices[k] + voffset;            
          }
 
-         ioffset += dinst->mIndxCount;
+         ioffset += indxCount;
 
-         dMemcpy( vpPtr + voffset, dinst->mVerts, sizeof( DecalVertex ) * dinst->mVertCount );
-         voffset += dinst->mVertCount;
+         const U32 vertCount =
+             (dinst->mVertCount > currentBatch.vCount) ?
+             currentBatch.vCount : dinst->mVertCount;
+         dMemcpy( vpPtr + voffset, dinst->mVerts, sizeof( DecalVertex ) * vertCount );
+         voffset += vertCount;
 
          // Ugly hack for ProjectedShadow!
          if ( (dinst->mFlags & CustomDecal) && dinst->mCustomTex != NULL )
@@ -1357,8 +1385,10 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
       pb->lock( &pbPtr );
 
       // Memcpy from system to video memory.
-      dMemcpy( vpPtr, vertData, sizeof( DecalVertex ) * currentBatch.vCount );
-      dMemcpy( pbPtr, indexData, sizeof( U16 ) * currentBatch.iCount );
+      const U32 vpCount = sizeof( DecalVertex ) * currentBatch.vCount;
+      dMemcpy( vpPtr, vertData, vpCount );
+      const U32 pbCount = sizeof( U16 ) * currentBatch.iCount;
+      dMemcpy( pbPtr, indexData, pbCount );
 
       pb->unlock();
       vb->unlock();

+ 1 - 1
Engine/source/T3D/examples/renderMeshExample.cpp

@@ -269,7 +269,7 @@ void RenderMeshExample::prepRenderImage( SceneRenderState *state )
       createGeometry();
 
    // If we have no material then skip out.
-   if ( !mMaterialInst )
+   if ( !mMaterialInst || !state)
       return;
 
    // If we don't have a material instance after the override then 

+ 8 - 5
Engine/source/T3D/fps/guiClockHud.cpp

@@ -87,6 +87,7 @@ ConsoleDocClass( GuiClockHud,
 GuiClockHud::GuiClockHud()
 {
    mShowFrame = mShowFill = true;
+   mTimeReversed = false;
    mFillColor.set(0, 0, 0, 0.5);
    mFrameColor.set(0, 1, 0, 1);
    mTextColor.set( 0, 1, 0, 1 );
@@ -112,9 +113,11 @@ void GuiClockHud::initPersistFields()
 
 void GuiClockHud::onRender(Point2I offset, const RectI &updateRect)
 {
+   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
+
    // Background first
    if (mShowFill)
-      GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor);
+      drawUtil->drawRectFill(updateRect, mFillColor);
 
    // Convert ms time into hours, minutes and seconds.
    S32 time = S32(getTime());
@@ -128,13 +131,13 @@ void GuiClockHud::onRender(Point2I offset, const RectI &updateRect)
    // Center the text
    offset.x += (getWidth() - mProfile->mFont->getStrWidth((const UTF8 *)buf)) / 2;
    offset.y += (getHeight() - mProfile->mFont->getHeight()) / 2;
-   GFX->getDrawUtil()->setBitmapModulation(mTextColor);
-   GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
-   GFX->getDrawUtil()->clearBitmapModulation();
+   drawUtil->setBitmapModulation(mTextColor);
+   drawUtil->drawText(mProfile->mFont, offset, buf);
+   drawUtil->clearBitmapModulation();
 
    // Border last
    if (mShowFrame)
-      GFX->getDrawUtil()->drawRect(updateRect, mFrameColor);
+      drawUtil->drawRect(updateRect, mFrameColor);
 }
 
 

+ 7 - 5
Engine/source/T3D/fps/guiHealthTextHud.cpp

@@ -162,10 +162,12 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect)
       else  
          mValue = 100 - (100 * control->getDamageValue());    
    }  
+
+   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
   
    // If enabled draw background first  
    if (mShowFill)  
-      GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor);  
+      drawUtil->drawRectFill(updateRect, mFillColor);  
   
    // Prepare text and center it  
    S32 val = (S32)mValue;    
@@ -190,11 +192,11 @@ void GuiHealthTextHud::onRender(Point2I offset, const RectI &updateRect)
       }  
    }  
   
-   GFX->getDrawUtil()->setBitmapModulation(tColor);    
-   GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);    
-   GFX->getDrawUtil()->clearBitmapModulation();    
+   drawUtil->setBitmapModulation(tColor);    
+   drawUtil->drawText(mProfile->mFont, offset, buf);    
+   drawUtil->clearBitmapModulation();    
   
    // If enabled draw the border last  
    if (mShowFrame)  
-      GFX->getDrawUtil()->drawRect(updateRect, mFrameColor);  
+      drawUtil->drawRect(updateRect, mFrameColor);  
 }  

+ 11 - 6
Engine/source/T3D/fps/guiShapeNameHud.cpp

@@ -117,8 +117,11 @@ GuiShapeNameHud::GuiShapeNameHud()
 {
    mFillColor.set( 0.25f, 0.25f, 0.25f, 0.25f );
    mFrameColor.set( 0, 1, 0, 1 );
+   mLabelFillColor.set( 0.25f, 0.25f, 0.25f, 0.25f );
+   mLabelFrameColor.set( 0, 1, 0, 1 );
    mTextColor.set( 0, 1, 0, 1 );
    mShowFrame = mShowFill = true;
+   mShowLabelFrame = mShowLabelFill = false;
    mVerticalOffset = 0.5f;
    mDistanceFade = 0.1f;
    mLabelPadding.set(0, 0);
@@ -193,7 +196,7 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect)
 
    // Collision info. We're going to be running LOS tests and we
    // don't want to collide with the control object.
-   static U32 losMask = TerrainObjectType | ShapeBaseObjectType;
+   static U32 losMask = TerrainObjectType | ShapeBaseObjectType | StaticObjectType;
    control->disableCollision();
 
    // All ghosted objects are added to the server connection group,
@@ -298,18 +301,20 @@ void GuiShapeNameHud::drawName(Point2I offset, const char *name, F32 opacity)
    offset.x -= width / 2;
    offset.y -= height / 2;
 
+   GFXDrawUtil* drawUtil = GFX->getDrawUtil();
+
    // Background fill first
    if (mShowLabelFill)
-      GFX->getDrawUtil()->drawRectFill(RectI(offset, extent), mLabelFillColor);
+      drawUtil->drawRectFill(RectI(offset, extent), mLabelFillColor);
 
    // Deal with opacity and draw.
    mTextColor.alpha = opacity;
-   GFX->getDrawUtil()->setBitmapModulation(mTextColor);
-   GFX->getDrawUtil()->drawText(mProfile->mFont, offset + mLabelPadding, name);
-   GFX->getDrawUtil()->clearBitmapModulation();
+   drawUtil->setBitmapModulation(mTextColor);
+   drawUtil->drawText(mProfile->mFont, offset + mLabelPadding, name);
+   drawUtil->clearBitmapModulation();
 
    // Border last
    if (mShowLabelFrame)
-      GFX->getDrawUtil()->drawRect(RectI(offset, extent), mLabelFrameColor);
+      drawUtil->drawRect(RectI(offset, extent), mLabelFrameColor);
 }
 

+ 0 - 7
Engine/source/T3D/fx/explosion.cpp

@@ -254,10 +254,6 @@ ExplosionData::ExplosionData()
    lifetimeVariance = 0;
    offset = 0.0f;
 
-   shockwave = NULL;
-   shockwaveID = 0;
-   shockwaveOnTerrain = false;
-
    shakeCamera = false;
    camShakeFreq.set( 10.0f, 10.0f, 10.0f );
    camShakeAmp.set( 1.0f, 1.0f, 1.0f );
@@ -321,9 +317,6 @@ void ExplosionData::initPersistFields()
       "explosion.\n\n"
       "@see particleEmitter" );
 
-//   addField( "shockwave", TypeShockwaveDataPtr, Offset(shockwave, ExplosionData) );
-//   addField( "shockwaveOnTerrain", TypeBool, Offset(shockwaveOnTerrain, ExplosionData) );
-
    addField( "debris", TYPEID< DebrisData >(), Offset(debrisList, ExplosionData), EC_NUM_DEBRIS_TYPES,
       "List of DebrisData objects to spawn with this explosion." );
    addField( "debrisThetaMin", TypeF32, Offset(debrisThetaMin, ExplosionData),

+ 0 - 5
Engine/source/T3D/fx/explosion.h

@@ -41,7 +41,6 @@ class ParticleEmitterData;
 class TSThread;
 class SFXTrack;
 struct DebrisData;
-class ShockwaveData;
 
 //--------------------------------------------------------------------------
 class ExplosionData : public GameBaseData {
@@ -77,10 +76,6 @@ class ExplosionData : public GameBaseData {
    ParticleEmitterData*    emitterList[EC_NUM_EMITTERS];
    S32                     emitterIDList[EC_NUM_EMITTERS];
 
-   ShockwaveData *         shockwave;
-   S32                     shockwaveID;
-   bool                    shockwaveOnTerrain;
-
    DebrisData *   debrisList[EC_NUM_DEBRIS_TYPES];
    S32            debrisIDList[EC_NUM_DEBRIS_TYPES];
 

+ 2 - 2
Engine/source/T3D/fx/fxFoliageReplicator.cpp

@@ -248,7 +248,7 @@ fxFoliageCulledList::fxFoliageCulledList(Box3F SearchBox, fxFoliageCulledList* I
 
 //------------------------------------------------------------------------------
 
-void fxFoliageCulledList::FindCandidates(Box3F SearchBox, fxFoliageCulledList* InVec)
+void fxFoliageCulledList::FindCandidates(const Box3F& SearchBox, fxFoliageCulledList* InVec)
 {
    // Search the Culled List.
    for (U32 i = 0; i < InVec->GetListCount(); i++)
@@ -1028,7 +1028,7 @@ void fxFoliageReplicator::SetupBuffers()
 
 //------------------------------------------------------------------------------
 
-Box3F fxFoliageReplicator::FetchQuadrant(Box3F Box, U32 Quadrant)
+Box3F fxFoliageReplicator::FetchQuadrant(const Box3F& Box, U32 Quadrant)
 {
    Box3F QuadrantBox;
 

+ 2 - 2
Engine/source/T3D/fx/fxFoliageReplicator.h

@@ -86,7 +86,7 @@ public:
    fxFoliageCulledList(Box3F SearchBox, fxFoliageCulledList* InVec);
    ~fxFoliageCulledList() {};
 
-   void FindCandidates(Box3F SearchBox, fxFoliageCulledList* InVec);
+   void FindCandidates(const Box3F& SearchBox, fxFoliageCulledList* InVec);
 
    U32 GetListCount(void) { return mCulledObjectSet.size(); };
    fxFoliageItem* GetElement(U32 index) { return mCulledObjectSet[index]; };
@@ -157,7 +157,7 @@ protected:
 
    void SyncFoliageReplicators(void);
 
-   Box3F FetchQuadrant(Box3F Box, U32 Quadrant);
+   Box3F FetchQuadrant(const Box3F& Box, U32 Quadrant);
    void ProcessQuadrant(fxFoliageQuadrantNode* pParentNode, fxFoliageCulledList* pCullList, U32 Quadrant);
    void ProcessNodeChildren(fxFoliageQuadrantNode* pParentNode, fxFoliageCulledList* pCullList);
 

+ 1 - 1
Engine/source/T3D/fx/groundCover.cpp

@@ -148,7 +148,7 @@ protected:
 
 public:
 
-   GroundCoverCell() {}
+   GroundCoverCell() : mDirty(false) {}
 
    ~GroundCoverCell() 
    {

+ 1 - 0
Engine/source/T3D/fx/lightning.cpp

@@ -156,6 +156,7 @@ LightningStrikeEvent::LightningStrikeEvent()
 {
    mLightning = NULL;
    mTarget = NULL;
+   mClientId = 0;
 }
 
 LightningStrikeEvent::~LightningStrikeEvent()

+ 1 - 1
Engine/source/T3D/fx/precipitation.cpp

@@ -1293,7 +1293,7 @@ void Precipitation::interpolateTick(F32 delta)
 void Precipitation::processTick(const Move *)
 {
    //nothing to do on the server
-   if (isServerObject() || mDataBlock == NULL)
+   if (isServerObject() || mDataBlock == NULL || isHidden())
       return;
 
    const U32 currTime = Platform::getVirtualMilliseconds();

+ 4 - 0
Engine/source/T3D/gameBase/gameBase.h

@@ -39,6 +39,9 @@
 #include "scene/sceneManager.h"    
 #define __SCENEMANAGER_H__  
 #endif
+#ifndef _IDISPLAYDEVICE_H_
+#include "platform/output/IDisplayDevice.h"
+#endif
 
 class NetConnection;
 class ProcessList;
@@ -418,6 +421,7 @@ public:
    
    // Not implemented here, but should return the Camera to world transformation matrix
    virtual void getCameraTransform (F32 *pos, MatrixF *mat ) { *mat = MatrixF::Identity; }
+   virtual void getEyeCameraTransform ( IDisplayDevice *device, U32 eyeId, MatrixF *mat ) { *mat = MatrixF::Identity; }
 
    /// Returns the water object we are colliding with, it is up to derived
    /// classes to actually set this object.

+ 40 - 5
Engine/source/T3D/gameBase/gameConnection.cpp

@@ -235,6 +235,7 @@ GameConnection::GameConnection()
 
 GameConnection::~GameConnection()
 {
+   setDisplayDevice(NULL);
    delete mAuthInfo;
    for(U32 i = 0; i < mConnectArgc; i++)
       dFree(mConnectArgv[i]);
@@ -459,6 +460,14 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
       return false;
    }
    ConsoleValueRef connectArgv[MaxConnectArgs + 3];
+   ConsoleValue connectArgvValue[MaxConnectArgs + 3];
+
+   for(U32 i = 0; i < mConnectArgc+3; i++)
+   {
+	   connectArgv[i].value = &connectArgvValue[i];
+	   connectArgvValue[i].init();
+   }
+
    for(U32 i = 0; i < mConnectArgc; i++)
    {
       char argString[256];
@@ -466,11 +475,11 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
       mConnectArgv[i] = dStrdup(argString);
       connectArgv[i + 3] = mConnectArgv[i];
    }
-   connectArgv[0] = "onConnectRequest";
-   connectArgv[1] = 0;
+   connectArgvValue[0].setStackStringValue("onConnectRequest");
+   connectArgvValue[1].setIntValue(0);
    char buffer[256];
    Net::addressToString(getNetAddress(), buffer);
-   connectArgv[2] = buffer;
+   connectArgvValue[2].setStackStringValue(buffer);
 
    // NOTE: Cannot convert over to IMPLEMENT_CALLBACK as it has variable args.
    const char *ret = Con::execute(this, mConnectArgc + 3, connectArgv);
@@ -665,6 +674,30 @@ bool GameConnection::getControlCameraTransform(F32 dt, MatrixF* mat)
    return true;
 }
 
+bool GameConnection::getControlCameraEyeTransforms(IDisplayDevice *display, MatrixF *transforms)
+{
+   GameBase* obj = getCameraObject();
+   if(!obj)
+      return false;
+
+   GameBase* cObj = obj;
+   while((cObj = cObj->getControlObject()) != 0)
+   {
+      if(cObj->useObjsEyePoint())
+         obj = cObj;
+   }
+
+   // Perform operation on left & right eyes. For each we need to calculate the world space 
+   // of the rotated eye offset and add that onto the camera world space.
+   for (U32 i=0; i<2; i++)
+   {
+      obj->getEyeCameraTransform(display, i, &transforms[i]);
+   }
+
+   return true;
+}
+
+
 bool GameConnection::getControlCameraDefaultFov(F32 * fov)
 {
    //find the last control object in the chain (client->player->turret->whatever...)
@@ -991,8 +1024,10 @@ bool GameConnection::readDemoStartBlock(BitStream *stream)
 
 void GameConnection::demoPlaybackComplete()
 {
-   static ConsoleValueRef demoPlaybackArgv[1] = { "demoPlaybackComplete" };
-   Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(1, demoPlaybackArgv, false));
+   static const char* demoPlaybackArgv[1] = { "demoPlaybackComplete" };
+   static StringStackConsoleWrapper demoPlaybackCmd(1, demoPlaybackArgv);
+
+   Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(demoPlaybackCmd.argc, demoPlaybackCmd.argv, false));
    Parent::demoPlaybackComplete();
 }
 

+ 6 - 2
Engine/source/T3D/gameBase/gameConnection.h

@@ -269,6 +269,10 @@ public:
    bool getControlCameraTransform(F32 dt,MatrixF* mat);
    bool getControlCameraVelocity(Point3F *vel);
 
+   /// Returns the eye transforms for the control object, using supplemental information 
+   /// from the provided IDisplayDevice.
+   bool getControlCameraEyeTransforms(IDisplayDevice *display, MatrixF *transforms);
+   
    bool getControlCameraDefaultFov(F32 *fov);
    bool getControlCameraFov(F32 *fov);
    bool setControlCameraFov(F32 fov);
@@ -280,8 +284,8 @@ public:
    void setFirstPerson(bool firstPerson);
    
    bool hasDisplayDevice() const { return mDisplayDevice != NULL; }
-   const IDisplayDevice* getDisplayDevice() const { return mDisplayDevice; }
-   void setDisplayDevice(IDisplayDevice* display) { mDisplayDevice = display; }
+   IDisplayDevice* getDisplayDevice() const { return mDisplayDevice; }
+   void setDisplayDevice(IDisplayDevice* display) { if (mDisplayDevice) mDisplayDevice->setDrawCanvas(NULL); mDisplayDevice = display; }
    void clearDisplayDevice() { mDisplayDevice = NULL; }
 
    void setControlSchemeParameters(bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot);

+ 2 - 1
Engine/source/T3D/gameBase/gameConnectionEvents.cpp

@@ -32,6 +32,7 @@
 #include "app/game.h"
 #include "T3D/gameBase/gameConnection.h"
 #include "T3D/gameBase/gameConnectionEvents.h"
+#include "console/engineAPI.h"
 
 #define DebugChecksum 0xF00DBAAD
 
@@ -234,7 +235,7 @@ void SimDataBlockEvent::process(NetConnection *cptr)
    if(mProcess)
    {
       //call the console function to set the number of blocks to be sent
-      Con::executef("onDataBlockObjectReceived", Con::getIntArg(mIndex), Con::getIntArg(mTotal));
+      Con::executef("onDataBlockObjectReceived", mIndex, mTotal);
 
       String &errorBuffer = NetConnection::getErrorBuffer();
                      

+ 37 - 12
Engine/source/T3D/gameFunctions.cpp

@@ -349,8 +349,13 @@ bool GameProcessCameraQuery(CameraQuery *query)
 
       // Provide some default values
       query->projectionOffset = Point2F::Zero;
-      query->eyeOffset = Point3F::Zero;
-
+      query->stereoTargets[0] = 0;
+      query->stereoTargets[1] = 0;
+      query->eyeOffset[0] = Point3F::Zero;
+      query->eyeOffset[1] = Point3F::Zero;
+      query->hasFovPort = false;
+      query->hasStereoTargets = false;
+      
       F32 cameraFov = 0.0f;
       bool fovSet = false;
 
@@ -358,14 +363,14 @@ bool GameProcessCameraQuery(CameraQuery *query)
       // is not open
       if(!gEditingMission && connection->hasDisplayDevice())
       {
-         const IDisplayDevice* display = connection->getDisplayDevice();
+         IDisplayDevice* display = connection->getDisplayDevice();
+         // Note: all eye values are invalid until this is called
+         display->setDrawCanvas(query->drawCanvas);
 
-         // The connection's display device may want to set the FOV
-         if(display->providesYFOV())
-         {
-            cameraFov = mRadToDeg(display->getYFOV());
-            fovSet = true;
-         }
+         display->setCurrentConnection(connection);
+
+         // Display may activate AFTER so we need to call this again just in case
+         display->onStartFrame();
 
          // The connection's display device may want to set the projection offset
          if(display->providesProjectionOffset())
@@ -374,14 +379,34 @@ bool GameProcessCameraQuery(CameraQuery *query)
          }
 
          // The connection's display device may want to set the eye offset
-         if(display->providesEyeOffset())
+         if(display->providesEyeOffsets())
          {
-            query->eyeOffset = display->getEyeOffset();
+            display->getEyeOffsets(query->eyeOffset);
          }
+
+         // Grab field of view for both eyes
+         if (display->providesFovPorts())
+         {
+            display->getFovPorts(query->fovPort);
+            fovSet = true;
+            query->hasFovPort = true;
+         }
+         
+         // Grab the latest overriding render view transforms
+         connection->getControlCameraEyeTransforms(display, query->eyeTransforms);
+
+         display->getStereoViewports(query->stereoViewports);
+         display->getStereoTargets(query->stereoTargets);
+         query->hasStereoTargets = true;
+      }
+      else
+      {
+         query->eyeTransforms[0] = query->cameraMatrix;
+         query->eyeTransforms[1] = query->cameraMatrix;
       }
 
       // Use the connection's FOV settings if requried
-      if(!fovSet && !connection->getControlCameraFov(&cameraFov))
+      if(!connection->getControlCameraFov(&cameraFov))
       {
          return false;
       }

+ 0 - 8
Engine/source/T3D/gameTSCtrl.cpp

@@ -55,10 +55,6 @@ bool GameTSCtrl::onAdd()
    if ( !Parent::onAdd() )
       return false;
 
-#ifdef TORQUE_DEMO_WATERMARK
-   mWatermark.init();
-#endif
-
    return true;
 }
 
@@ -172,10 +168,6 @@ void GameTSCtrl::onRender(Point2I offset, const RectI &updateRect)
 
    if(!skipRender || true)
       Parent::onRender(offset, updateRect);
-
-#ifdef TORQUE_DEMO_WATERMARK
-   mWatermark.render(getExtent());
-#endif
 }
 
 //--------------------------------------------------------------------------

+ 0 - 10
Engine/source/T3D/gameTSCtrl.h

@@ -30,12 +30,6 @@
 #include "gui/3d/guiTSControl.h"
 #endif
 
-#ifdef TORQUE_DEMO_WATERMARK
-#ifndef _WATERMARK_H_
-#include "demo/watermark/watermark.h"
-#endif
-#endif
-
 class ProjectileData;
 class GameBase;
 
@@ -45,10 +39,6 @@ class GameTSCtrl : public GuiTSCtrl
 private:
    typedef GuiTSCtrl Parent;
 
-#ifdef TORQUE_DEMO_WATERMARK
-   Watermark mWatermark;
-#endif
-
    void makeScriptCall(const char *func, const GuiEvent &evt) const;
 
 public:

+ 2 - 2
Engine/source/T3D/item.cpp

@@ -292,7 +292,7 @@ IMPLEMENT_CALLBACK( Item, onStickyCollision, void, ( const char* objID ),( objID
    "@see Item, ItemData\n"
 );
 
-IMPLEMENT_CALLBACK( Item, onEnterLiquid, void, ( const char* objID, const char* waterCoverage, const char* liquidType ),( objID, waterCoverage, liquidType ),
+IMPLEMENT_CALLBACK( Item, onEnterLiquid, void, ( const char* objID, F32 waterCoverage, const char* liquidType ),( objID, waterCoverage, liquidType ),
    "Informs an Item object that it has entered liquid, along with information about the liquid type.\n"
    "@param objID Object ID for this Item object.\n"
    "@param waterCoverage How much coverage of water this Item object has.\n"
@@ -1005,7 +1005,7 @@ void Item::updatePos(const U32 /*mask*/, const F32 dt)
       {
          if(!mInLiquid && mWaterCoverage != 0.0f)
          {
-			onEnterLiquid_callback( getIdString(), Con::getFloatArg(mWaterCoverage), mLiquidType.c_str() );
+			onEnterLiquid_callback( getIdString(), mWaterCoverage, mLiquidType.c_str() );
             mInLiquid = true;
          }
          else if(mInLiquid && mWaterCoverage == 0.0f)

+ 1 - 1
Engine/source/T3D/item.h

@@ -114,7 +114,7 @@ class Item: public ShapeBase
 
   protected:
 	DECLARE_CALLBACK( void, onStickyCollision, ( const char* objID ));
-	DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objID, const char* waterCoverage, const char* liquidType ));
+	DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objID, F32 waterCoverage, const char* liquidType ));
 	DECLARE_CALLBACK( void, onLeaveLiquid, ( const char* objID, const char* liquidType ));
 
   public:

+ 3 - 2
Engine/source/T3D/lightAnimData.cpp

@@ -195,6 +195,7 @@ bool LightAnimData::AnimValue<COUNT>::animate( F32 time, F32 *output )
    F32 scaledTime, lerpFactor, valueRange, keyFrameLerp;
    U32 posFrom, posTo;
    S32 keyFrameFrom, keyFrameTo;
+   F32 initialValue = *output;
    
    bool wasAnimated = false;
 
@@ -215,13 +216,13 @@ bool LightAnimData::AnimValue<COUNT>::animate( F32 time, F32 *output )
 	   valueRange = ( value2[i] - value1[i] ) / 25.0f;
 
       if ( !smooth[i] )
-   	   output[i] = value1[i] + ( keyFrameFrom * valueRange );
+         output[i] = (value1[i] + (keyFrameFrom * valueRange)) * initialValue;
       else
       {
          lerpFactor = scaledTime - posFrom;
    	   keyFrameLerp = ( keyFrameTo - keyFrameFrom ) * lerpFactor;
 
-         output[i] = value1[i] + ( ( keyFrameFrom + keyFrameLerp ) * valueRange );
+         output[i] = (value1[i] + ((keyFrameFrom + keyFrameLerp) * valueRange)) * initialValue;
       }
    }
 

+ 9 - 1
Engine/source/T3D/lightBase.cpp

@@ -60,6 +60,8 @@ LightBase::LightBase()
       mColor( ColorF::WHITE ),
       mBrightness( 1.0f ),
       mCastShadows( false ),
+      mStaticRefreshFreq( 250 ),
+      mDynamicRefreshFreq( 8 ),
       mPriority( 1.0f ),
       mAnimationData( NULL ),      
       mFlareData( NULL ),
@@ -90,6 +92,8 @@ void LightBase::initPersistFields()
       addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
       addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );      
       addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
+      addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
+      addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)" );
       addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
 		  "Priority determines if a light has a stronger effect than, those with a lower value" );
 
@@ -277,6 +281,8 @@ U32 LightBase::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
       stream->write( mBrightness );
 
       stream->writeFlag( mCastShadows );
+      stream->write(mStaticRefreshFreq);
+      stream->write(mDynamicRefreshFreq);
 
       stream->write( mPriority );      
 
@@ -322,6 +328,8 @@ void LightBase::unpackUpdate( NetConnection *conn, BitStream *stream )
       stream->read( &mColor );
       stream->read( &mBrightness );      
       mCastShadows = stream->readFlag();
+      stream->read(&mStaticRefreshFreq);
+      stream->read(&mDynamicRefreshFreq);
 
       stream->read( &mPriority );      
       
@@ -431,7 +439,7 @@ DefineConsoleMethod( LightBase, playAnimation, void, (const char * anim), (""),
    "existing one is played."
    "@hide")
 {
-	if ( dStrIsEmpty(anim) )
+	if ( String::isEmpty(anim) )
     {
         object->playAnimation();
         return;

+ 2 - 1
Engine/source/T3D/lightBase.h

@@ -56,7 +56,8 @@ protected:
    F32 mBrightness;
 
    bool mCastShadows;
-
+   S32 mStaticRefreshFreq;
+   S32 mDynamicRefreshFreq;
    F32 mPriority;
 
    LightInfo *mLight;

+ 10 - 0
Engine/source/T3D/lightDescription.cpp

@@ -36,6 +36,8 @@ LightDescription::LightDescription()
    brightness( 1.0f ),
    range( 5.0f ),
    castShadows( false ),
+   mStaticRefreshFreq( 250 ),
+   mDynamicRefreshFreq( 8 ),
    animationData( NULL ),
    animationDataId( 0 ),
    animationPeriod( 1.0f ),
@@ -94,6 +96,8 @@ void LightDescription::initPersistFields()
       addField( "brightness", TypeF32, Offset( brightness, LightDescription ), "Adjusts the lights power, 0 being off completely." );      
       addField( "range", TypeF32, Offset( range, LightDescription ), "Controls the size (radius) of the light" );
       addField( "castShadows", TypeBool, Offset( castShadows, LightDescription ), "Enables/disabled shadow casts by this light." );
+      addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightDescription ), "static shadow refresh rate (milliseconds)" );
+      addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightDescription ), "dynamic shadow refresh rate (milliseconds)" );
 
    endGroup( "Light" );
 
@@ -153,6 +157,8 @@ void LightDescription::packData( BitStream *stream )
    stream->write( brightness );
    stream->write( range );
    stream->writeFlag( castShadows );
+   stream->write(mStaticRefreshFreq);
+   stream->write(mDynamicRefreshFreq);
 
    stream->write( animationPeriod );
    stream->write( animationPhase );
@@ -181,6 +187,8 @@ void LightDescription::unpackData( BitStream *stream )
    stream->read( &brightness );     
    stream->read( &range );
    castShadows = stream->readFlag();
+   stream->read(&mStaticRefreshFreq);
+   stream->read(&mDynamicRefreshFreq);
 
    stream->read( &animationPeriod );
    stream->read( &animationPhase );
@@ -200,6 +208,8 @@ void LightDescription::submitLight( LightState *state, const MatrixF &xfm, Light
    li->setRange( range );
    li->setColor( color );
    li->setCastShadows( castShadows );
+   li->setStaticRefreshFreq(mStaticRefreshFreq);
+   li->setDynamicRefreshFreq(mDynamicRefreshFreq);
    li->setTransform( xfm );
 
    if ( animationData )

+ 2 - 0
Engine/source/T3D/lightDescription.h

@@ -101,6 +101,8 @@ public:
    F32 brightness;
    F32 range;
    bool castShadows;
+   S32 mStaticRefreshFreq;
+   S32 mDynamicRefreshFreq;
 
    LightAnimData *animationData;   
    S32 animationDataId;

+ 2 - 2
Engine/source/T3D/pathCamera.cpp

@@ -104,7 +104,7 @@ ConsoleDocClass( PathCamera,
    "@ingroup PathCameras\n"
 );
 
-IMPLEMENT_CALLBACK( PathCamera, onNode, void, (const char* node), (node),
+IMPLEMENT_CALLBACK( PathCamera, onNode, void, (S32 node), (node),
 					"A script callback that indicates the path camera has arrived at a specific node in its path.  Server side only.\n"
 					"@param Node Unique ID assigned to this node.\n");
 
@@ -408,7 +408,7 @@ void PathCamera::popFront()
 void PathCamera::onNode(S32 node)
 {
    if (!isGhost())
-		onNode_callback(Con::getIntArg(node));
+		onNode_callback(node);
    
 }
 

+ 1 - 1
Engine/source/T3D/pathCamera.h

@@ -93,7 +93,7 @@ private:
 public:
    DECLARE_CONOBJECT(PathCamera);
    
-   DECLARE_CALLBACK( void, onNode, (const char* node));
+   DECLARE_CALLBACK( void, onNode, (S32 node));
 
    PathCamera();
    ~PathCamera();

+ 5 - 1
Engine/source/T3D/physics/bullet/bt.h

@@ -24,10 +24,14 @@
 #define _BULLET_H_
 
 // NOTE: We set these defines which bullet needs here.
-#ifdef TORQUE_OS_WIN
+#if defined TORQUE_OS_WIN && !defined(WIN32)
 #define WIN32
 #endif
 
+#ifdef TORQUE_CPU_X86
+#define __BT_SKIP_UINT64_H
+#endif
+
 // NOTE: All the Bullet includes we use should be here and
 // nowhere else.... beware!
 

+ 7 - 6
Engine/source/T3D/physics/bullet/btPlayer.cpp

@@ -290,8 +290,9 @@ bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, Collision
    BtPlayerSweepCallback callback( mGhostObject, disp.normalized() );
 	callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
 	callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
-	
-	mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
+
+   if (disp.length()>0.0001)
+      mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
 
 	inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
    if ( callback.hasHit() )
@@ -340,7 +341,8 @@ void BtPlayer::_stepForward( btVector3 *inOutCurrPos, const btVector3 &displacem
 		callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
 		callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
-		mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
+      if (disp.length()>0.0001)
+         mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
 
       // Subtract from the travel fraction.
       fraction -= callback.m_closestHitFraction;
@@ -434,9 +436,8 @@ void BtPlayer::findContact(   SceneObject **contactObject,
       if ( other == mGhostObject )
          other = (btCollisionObject*)pair.m_pProxy1->m_clientObject;
 
-      AssertFatal( !outOverlapObjects->contains( PhysicsUserData::getObject( other->getUserPointer() ) ),
-         "Got multiple pairs of the same object!" );
-      outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
+      if (!outOverlapObjects->contains(PhysicsUserData::getObject(other->getUserPointer())))
+         outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
 
       if ( other->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
          continue;

+ 56 - 3
Engine/source/T3D/player.cpp

@@ -1650,6 +1650,7 @@ Player::Player()
 
    mLastAbsoluteYaw = 0.0f;
    mLastAbsolutePitch = 0.0f;
+   mLastAbsoluteRoll = 0.0f;
 }
 
 Player::~Player()
@@ -2608,6 +2609,7 @@ void Player::updateMove(const Move* move)
             }
             mLastAbsoluteYaw = emove->rotZ[emoveIndex];
             mLastAbsolutePitch = emove->rotX[emoveIndex];
+            mLastAbsoluteRoll = emove->rotY[emoveIndex];
 
             // Head bank
             mHead.y = emove->rotY[emoveIndex];
@@ -4657,9 +4659,9 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
       }
       Point3F distance = end - start;
 
-      if (mFabs(distance.x) < mObjBox.len_x() &&
-          mFabs(distance.y) < mObjBox.len_y() &&
-          mFabs(distance.z) < mObjBox.len_z())
+      if (mFabs(distance.x) < mScaledBox.len_x() &&
+          mFabs(distance.y) < mScaledBox.len_y() &&
+          mFabs(distance.z) < mScaledBox.len_z())
       {
          // We can potentially early out of this.  If there are no polys in the clipped polylist at our
          //  end position, then we can bail, and just set start = end;
@@ -5584,6 +5586,57 @@ void Player::getMuzzleTransform(U32 imageSlot,MatrixF* mat)
    *mat = nmat;
 }
 
+DisplayPose Player::calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose)
+{
+   // NOTE: this is intended to be similar to updateMove
+   DisplayPose outPose;
+   outPose.orientation = getRenderTransform().toEuler();
+   outPose.position = inPose.position;
+
+   if (con && con->getControlSchemeAbsoluteRotation())
+   {
+      // Pitch
+      outPose.orientation.x = (inPose.orientation.x - mLastAbsolutePitch);
+
+      // Constrain the range of mRot.x
+      while (outPose.orientation.x  < -M_PI_F) 
+         outPose.orientation.x += M_2PI_F;
+      while (outPose.orientation.x  > M_PI_F) 
+         outPose.orientation.x -= M_2PI_F;
+
+      // Yaw
+
+      // Rotate (heading) head or body?
+      if ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson()))
+      {
+         // Rotate head
+         outPose.orientation.z = (inPose.orientation.z - mLastAbsoluteYaw);
+      }
+      else
+      {
+         // Rotate body
+         outPose.orientation.z = (inPose.orientation.z - mLastAbsoluteYaw);
+      }
+
+      // Constrain the range of mRot.z
+      while (outPose.orientation.z < 0.0f)
+         outPose.orientation.z += M_2PI_F;
+      while (outPose.orientation.z > M_2PI_F)
+         outPose.orientation.z -= M_2PI_F;
+
+      // Bank
+      if (mDataBlock->cameraCanBank)
+      {
+         outPose.orientation.y = (inPose.orientation.y - mLastAbsoluteRoll);
+      }
+
+      // Constrain the range of mRot.y
+      while (outPose.orientation.y > M_PI_F) 
+         outPose.orientation.y -= M_2PI_F;
+   }
+
+   return outPose;
+}
 
 void Player::getRenderMuzzleTransform(U32 imageSlot,MatrixF* mat)
 {

+ 2 - 0
Engine/source/T3D/player.h

@@ -439,6 +439,7 @@ protected:
 
    F32 mLastAbsoluteYaw;            ///< Stores that last absolute yaw value as passed in by ExtendedMove
    F32 mLastAbsolutePitch;          ///< Stores that last absolute pitch value as passed in by ExtendedMove
+   F32 mLastAbsoluteRoll;           ///< Stores that last absolute roll value as passed in by ExtendedMove
 
    S32 mMountPending;               ///< mMountPending suppresses tickDelay countdown so players will sit until
                                     ///< their mount, or another animation, comes through (or 13 seconds elapses).
@@ -683,6 +684,7 @@ public:
    void getEyeBaseTransform(MatrixF* mat, bool includeBank);
    void getRenderEyeTransform(MatrixF* mat);
    void getRenderEyeBaseTransform(MatrixF* mat, bool includeBank);
+   virtual DisplayPose calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose);
    void getCameraParameters(F32 *min, F32 *max, Point3F *offset, MatrixF *rot);
    void getMuzzleTransform(U32 imageSlot,MatrixF* mat);
    void getRenderMuzzleTransform(U32 imageSlot,MatrixF* mat);   

+ 2 - 0
Engine/source/T3D/pointLight.cpp

@@ -116,6 +116,8 @@ void PointLight::_conformLights()
 
    mLight->setBrightness( mBrightness );
    mLight->setCastShadows( mCastShadows );
+   mLight->setStaticRefreshFreq(mStaticRefreshFreq);
+   mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
    mLight->setPriority( mPriority );
 
    // Update the bounds and scale to fit our light.

+ 1 - 1
Engine/source/T3D/projectile.cpp

@@ -1018,7 +1018,7 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
 
       // Client (impact) decal.
       if ( mDataBlock->decal )     
-         gDecalManager->addDecal(p, n, mRandF(0.0f, M_2PI_F), mDataBlock->decal);
+         gDecalManager->addDecal(p, n, 0.0f, mDataBlock->decal);
 
       // Client object
       updateSound();

+ 2 - 2
Engine/source/T3D/rigid.cpp

@@ -156,7 +156,7 @@ bool Rigid::resolveCollision(const Point3F& p, const Point3F &normal, Rigid* rig
       return false;
 
    // Compute impulse
-   F32 d, n = -nv * (1.0f + restitution * rigid->restitution);
+   F32 d, n = -nv * (2.0f + restitution * rigid->restitution);
    Point3F a1,b1,c1;
    mCross(r1,normal,&a1);
    invWorldInertia.mulV(a1,&b1);
@@ -173,7 +173,7 @@ bool Rigid::resolveCollision(const Point3F& p, const Point3F &normal, Rigid* rig
 
    applyImpulse(r1,impulse);
    impulse.neg();
-   applyImpulse(r2,impulse);
+   rigid->applyImpulse(r2, impulse);
    return true;
 }
 

+ 2 - 2
Engine/source/T3D/rigidShape.cpp

@@ -153,7 +153,7 @@ ConsoleDocClass( RigidShape,
 );
 
 
-IMPLEMENT_CALLBACK( RigidShape, onEnterLiquid, void, ( const char* objId, const char* waterCoverage, const char* liquidType ),
+IMPLEMENT_CALLBACK( RigidShape, onEnterLiquid, void, ( const char* objId, F32 waterCoverage, const char* liquidType ),
 													 ( objId, waterCoverage, liquidType ),
    "@brief Called whenever this RigidShape object enters liquid.\n\n"
    "@param objId The ID of the rigidShape object.\n"
@@ -1088,7 +1088,7 @@ void RigidShape::updatePos(F32 dt)
       // Water script callbacks      
       if (!inLiquid && mWaterCoverage != 0.0f) 
       {
-         onEnterLiquid_callback(getIdString(), Con::getFloatArg(mWaterCoverage), mLiquidType.c_str() );
+         onEnterLiquid_callback(getIdString(), mWaterCoverage, mLiquidType.c_str() );
          inLiquid = true;
       }
       else if (inLiquid && mWaterCoverage == 0.0f) 

+ 1 - 1
Engine/source/T3D/rigidShape.h

@@ -296,7 +296,7 @@ public:
    void unpackUpdate(NetConnection *conn,           BitStream *stream);
 
    DECLARE_CONOBJECT(RigidShape);
-   DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objId, const char* waterCoverage, const char* liquidType ));
+   DECLARE_CALLBACK( void, onEnterLiquid, ( const char* objId, F32 waterCoverage, const char* liquidType ));
    DECLARE_CALLBACK( void, onLeaveLiquid, ( const char* objId, const char* liquidType ));
 };
 

+ 111 - 44
Engine/source/T3D/shapeBase.cpp

@@ -40,7 +40,6 @@
 #include "scene/sceneRenderState.h"
 #include "scene/sceneObjectLightingPlugin.h"
 #include "T3D/fx/explosion.h"
-#include "T3D/fx/particleEmitter.h"
 #include "T3D/fx/cameraFXMgr.h"
 #include "environment/waterBlock.h"
 #include "T3D/debris.h"
@@ -154,19 +153,26 @@ ShapeBaseData::ShapeBaseData()
    shadowSphereAdjust( 1.0f ),
    shapeName( StringTable->insert("") ),
    cloakTexName( StringTable->insert("") ),
+   cubeDescId( 0 ),
+   reflectorDesc( NULL ),
+   debris( NULL ),
+   debrisID( 0 ),
+   debrisShapeName( StringTable->insert("") ),
+   explosion( NULL ),
+   explosionID( 0 ),
+   underwaterExplosion( NULL ),
+   underwaterExplosionID( 0 ),
    mass( 1.0f ),
    drag( 0.0f ),
    density( 1.0f ),
    maxEnergy( 0.0f ),
    maxDamage( 1.0f ),
-   disabledLevel( 1.0f ),
    destroyedLevel( 1.0f ),
+   disabledLevel( 1.0f ),
    repairRate( 0.0033f ),
    eyeNode( -1 ),
    earNode( -1 ),
    cameraNode( -1 ),
-   damageSequence( -1 ),
-   hulkSequence( -1 ),
    cameraMaxDist( 0.0f ),
    cameraMinDist( 0.2f ),
    cameraDefaultFov( 75.0f ),
@@ -174,24 +180,17 @@ ShapeBaseData::ShapeBaseData()
    cameraMaxFov( 120.f ),
    cameraCanBank( false ),
    mountedImagesBank( false ),
-   isInvincible( false ),
-   renderWhenDestroyed( true ),
-   debris( NULL ),
-   debrisID( 0 ),
-   debrisShapeName( StringTable->insert("") ),
-   explosion( NULL ),
-   explosionID( 0 ),
-   underwaterExplosion( NULL ),
-   underwaterExplosionID( 0 ),
+   debrisDetail( -1 ),
+   damageSequence( -1 ),
+   hulkSequence( -1 ),
+   observeThroughObject( false ),
    firstPersonOnly( false ),
    useEyePoint( false ),
-   cubeDescId( 0 ),
-   reflectorDesc( NULL ),
-   observeThroughObject( false ),
+   isInvincible( false ),
+   renderWhenDestroyed( true ),
    computeCRC( false ),
    inheritEnergyFromMount( false ),
-   mCRC( 0 ),
-   debrisDetail( -1 )
+   mCRC( 0 )
 {      
    dMemset( mountPointNode, -1, sizeof( S32 ) * SceneObject::NumMountPoints );
 }
@@ -878,46 +877,46 @@ IMPLEMENT_CALLBACK( ShapeBase, validateCameraFov, F32, (F32 fov), (fov),
    "@see ShapeBaseData\n\n");
 
 ShapeBase::ShapeBase()
- : mDrag( 0.0f ),
-   mBuoyancy( 0.0f ),
-   mWaterCoverage( 0.0f ),
-   mLiquidHeight( 0.0f ),
+ : mDataBlock( NULL ),
+   mIsAiControlled( false ),
    mControllingObject( NULL ),
-   mGravityMod( 1.0f ),
-   mAppliedForce( Point3F::Zero ),
-   mTimeoutList( NULL ),
-   mDataBlock( NULL ),
+   mMoveMotion( false ),
+   mShapeBaseMount( NULL ),
    mShapeInstance( NULL ),
+   mConvexList( new Convex ),
    mEnergy( 0.0f ),
    mRechargeRate( 0.0f ),
+   mMass( 1.0f ),
+   mOneOverMass( 1.0f ),
+   mDrag( 0.0f ),
+   mBuoyancy( 0.0f ),
+   mLiquidHeight( 0.0f ),
+   mWaterCoverage( 0.0f ),
+   mAppliedForce( Point3F::Zero ),
+   mGravityMod( 1.0f ),
+   mDamageFlash( 0.0f ),
+   mWhiteOut( 0.0f ),
+   mFlipFadeVal( false ),
+   mTimeoutList( NULL ),
    mDamage( 0.0f ),
    mRepairRate( 0.0f ),
    mRepairReserve( 0.0f ),
    mDamageState( Enabled ),
    mDamageThread( NULL ),
    mHulkThread( NULL ),
-   mLastRenderFrame( 0 ),
-   mLastRenderDistance( 0.0f ),
+   damageDir( 0.0f, 0.0f, 1.0f ),
    mCloaked( false ),
    mCloakLevel( 0.0f ),
-   mDamageFlash( 0.0f ),
-   mWhiteOut( 0.0f ),
-   mIsControlled( false ),
-   mConvexList( new Convex ),
-   mCameraFov( 90.0f ),
    mFadeOut( true ),
    mFading( false ),
    mFadeVal( 1.0f ),
-   mFadeTime( 1.0f ),
    mFadeElapsedTime( 0.0f ),
+   mFadeTime( 1.0f ),
    mFadeDelay( 0.0f ),
-   mFlipFadeVal( false ),
-   damageDir( 0.0f, 0.0f, 1.0f ),
-   mShapeBaseMount( NULL ),
-   mMass( 1.0f ),
-   mOneOverMass( 1.0f ),
-   mMoveMotion( false ),
-   mIsAiControlled( false )
+   mCameraFov( 90.0f ),
+   mIsControlled( false ),
+   mLastRenderFrame( 0 ),
+   mLastRenderDistance( 0.0f )
 {
    mTypeMask |= ShapeBaseObjectType | LightObjectType;   
 
@@ -1192,13 +1191,13 @@ void ShapeBase::onDeleteNotify( SimObject *obj )
    Parent::onDeleteNotify( obj );      
 }
 
-void ShapeBase::onImpact(SceneObject* obj, VectorF vec)
+void ShapeBase::onImpact(SceneObject* obj, const VectorF& vec)
 {
    if (!isGhost())
       mDataBlock->onImpact_callback( this, obj, vec, vec.len() );
 }
 
-void ShapeBase::onImpact(VectorF vec)
+void ShapeBase::onImpact(const VectorF& vec)
 {
    if (!isGhost())
       mDataBlock->onImpact_callback( this, NULL, vec, vec.len() );
@@ -1969,6 +1968,75 @@ void ShapeBase::getCameraTransform(F32* pos,MatrixF* mat)
    mat->mul( gCamFXMgr.getTrans() );
 }
 
+void ShapeBase::getEyeCameraTransform(IDisplayDevice *displayDevice, U32 eyeId, MatrixF *outMat)
+{
+   MatrixF temp(1);
+   Point3F eyePos;
+   Point3F rotEyePos;
+
+   DisplayPose inPose;
+   displayDevice->getFrameEyePose(&inPose, eyeId);
+   DisplayPose newPose = calcCameraDeltaPose(displayDevice->getCurrentConnection(), inPose);
+
+   // Ok, basically we just need to add on newPose to the camera transform
+   // NOTE: currently we dont support third-person camera in this mode
+   MatrixF cameraTransform(1);
+   F32 fakePos = 0;
+   getCameraTransform(&fakePos, &cameraTransform);
+
+   QuatF baserot = cameraTransform;
+   QuatF qrot = QuatF(newPose.orientation);
+   QuatF concatRot;
+   concatRot.mul(baserot, qrot);
+   concatRot.setMatrix(&temp);
+   temp.setPosition(cameraTransform.getPosition() + concatRot.mulP(newPose.position, &rotEyePos));
+
+   *outMat = temp;
+}
+
+DisplayPose ShapeBase::calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose)
+{
+   // NOTE: this is intended to be similar to updateMove
+   // WARNING: does not take into account any move values
+
+   DisplayPose outPose;
+   outPose.orientation = getRenderTransform().toEuler();
+   outPose.position = inPose.position;
+
+   if (con && con->getControlSchemeAbsoluteRotation())
+   {
+      // Pitch
+      outPose.orientation.x = inPose.orientation.x;
+
+      // Constrain the range of mRot.x
+      while (outPose.orientation.x < -M_PI_F) 
+         outPose.orientation.x += M_2PI_F;
+      while (outPose.orientation.x > M_PI_F) 
+         outPose.orientation.x -= M_2PI_F;
+
+      // Yaw
+      outPose.orientation.z = inPose.orientation.z;
+
+      // Constrain the range of mRot.z
+      while (outPose.orientation.z < -M_PI_F) 
+         outPose.orientation.z += M_2PI_F;
+      while (outPose.orientation.z > M_PI_F) 
+         outPose.orientation.z -= M_2PI_F;
+
+      // Bank
+      if (mDataBlock->cameraCanBank)
+      {
+         outPose.orientation.y = inPose.orientation.y;
+      }
+
+      // Constrain the range of mRot.y
+      while (outPose.orientation.y > M_PI_F) 
+         outPose.orientation.y -= M_2PI_F;
+   }
+
+   return outPose;
+}
+
 void ShapeBase::getCameraParameters(F32 *min,F32* max,Point3F* off,MatrixF* rot)
 {
    *min = mDataBlock->cameraMinDist;
@@ -1977,7 +2045,6 @@ void ShapeBase::getCameraParameters(F32 *min,F32* max,Point3F* off,MatrixF* rot)
    rot->identity();
 }
 
-
 //----------------------------------------------------------------------------
 F32 ShapeBase::getDamageFlash() const
 {

+ 11 - 4
Engine/source/T3D/shapeBase.h

@@ -63,6 +63,8 @@
    #include "console/dynamicTypes.h"
 #endif
 
+// Need full definition visible for SimObjectPtr<ParticleEmitter>
+#include "T3D/fx/particleEmitter.h"
 
 class GFXCubemap;
 class TSShapeInstance;
@@ -70,8 +72,6 @@ class SceneRenderState;
 class TSThread;
 class GameConnection;
 struct CameraScopeQuery;
-class ParticleEmitter;
-class ParticleEmitterData;
 class ProjectileData;
 class ExplosionData;
 struct DebrisData;
@@ -1104,8 +1104,8 @@ protected:
    virtual void shakeCamera( U32 imageSlot );
    virtual void updateDamageLevel();
    virtual void updateDamageState();
-   virtual void onImpact(SceneObject* obj, VectorF vec);
-   virtual void onImpact(VectorF vec);
+   virtual void onImpact(SceneObject* obj, const VectorF& vec);
+   virtual void onImpact(const VectorF& vec);
    /// @}
 
    /// The inner prep render function that does the 
@@ -1583,6 +1583,13 @@ public:
    /// @param   mat   Camera transform (out)
    virtual void getCameraTransform(F32* pos,MatrixF* mat);
 
+   /// Gets the view transform for a particular eye, taking into account the current absolute 
+   /// orient and position values of the display device.
+   virtual void getEyeCameraTransform( IDisplayDevice *display, U32 eyeId, MatrixF *outMat );
+
+   /// Calculates a delta camera angle and view position based on inPose
+   virtual DisplayPose calcCameraDeltaPose(GameConnection *con, const DisplayPose& inPose);
+
    /// Gets the index of a node inside a mounted image given the name
    /// @param   imageSlot   Image slot
    /// @param   nodeName    Node name

+ 2 - 0
Engine/source/T3D/spotLight.cpp

@@ -122,6 +122,8 @@ void SpotLight::_conformLights()
    mLight->setColor( mColor );
    mLight->setBrightness( mBrightness );
    mLight->setCastShadows( mCastShadows );
+   mLight->setStaticRefreshFreq(mStaticRefreshFreq);
+   mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
    mLight->setPriority( mPriority );
 
    mOuterConeAngle = getMax( 0.01f, mOuterConeAngle );

+ 1 - 1
Engine/source/T3D/trigger.cpp

@@ -236,7 +236,7 @@ DECLARE_STRUCT( Polyhedron );
 IMPLEMENT_STRUCT( Polyhedron, Polyhedron,,
    "" )
 END_IMPLEMENT_STRUCT;
-ConsoleType( floatList, TypeTriggerPolyhedron, Polyhedron )
+ConsoleType(floatList, TypeTriggerPolyhedron, Polyhedron, "")
 
 
 ConsoleGetType( TypeTriggerPolyhedron )

+ 5 - 5
Engine/source/T3D/trigger.h

@@ -87,6 +87,10 @@ class Trigger : public GameBase
    String            mLeaveCommand;
    String            mTickCommand;
 
+   static const U32 CMD_SIZE = 1024;
+
+  protected:
+   
    enum TriggerUpdateBits
    {
       TransformMask = Parent::NextFreeMask << 0,
@@ -97,10 +101,6 @@ class Trigger : public GameBase
       NextFreeMask  = Parent::NextFreeMask << 5,
    };
 
-   static const U32 CMD_SIZE = 1024;
-
-  protected:
-
    static bool smRenderTriggers;
    bool testObject(GameBase* enter);
    void processTick(const Move *move);
@@ -142,7 +142,7 @@ class Trigger : public GameBase
    // Trigger
    void setTriggerPolyhedron(const Polyhedron&);
 
-   void      potentialEnterObject(GameBase*);
+   virtual void potentialEnterObject(GameBase*);
    U32       getNumTriggeringObjects() const;
    GameBase* getObject(const U32);   
    const Vector<GameBase*>& getObjects() const { return mObjects; }

+ 67 - 5
Engine/source/T3D/tsStatic.cpp

@@ -91,6 +91,9 @@ ConsoleDocClass( TSStatic,
 );
 
 TSStatic::TSStatic()
+:
+   cubeDescId( 0 ),
+   reflectorDesc( NULL )
 {
    mNetFlags.set(Ghostable | ScopeAlways);
 
@@ -102,7 +105,7 @@ TSStatic::TSStatic()
    mPlayAmbient      = true;
    mAmbientThread    = NULL;
 
-   mAllowPlayerStep = true;
+   mAllowPlayerStep = false;
 
    mConvexList = new Convex;
 
@@ -186,6 +189,11 @@ void TSStatic::initPersistFields()
 
    endGroup("Rendering");
 
+   addGroup( "Reflection" );
+      addField( "cubeReflectorDesc", TypeRealString, Offset( cubeDescName, TSStatic ), 
+         "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
+   endGroup( "Reflection" );
+
    addGroup("Collision");
 
       addField( "collisionType",    TypeTSMeshType,   Offset( mCollisionType,   TSStatic ),
@@ -292,6 +300,14 @@ bool TSStatic::onAdd()
 
    addToScene();
 
+   if ( isClientObject() )
+   {      
+      mCubeReflector.unregisterReflector();
+
+      if ( reflectorDesc )
+         mCubeReflector.registerReflector( this, reflectorDesc );      
+   }
+
    _updateShouldTick();
 
    // Accumulation
@@ -357,6 +373,16 @@ bool TSStatic::_createShape()
    if ( mAmbientThread )
       mShapeInstance->setSequence( mAmbientThread, ambientSeq, 0);
 
+   // Resolve CubeReflectorDesc.
+   if ( cubeDescName.isNotEmpty() )
+   {
+      Sim::findObject( cubeDescName, reflectorDesc );
+   }
+   else if( cubeDescId > 0 )
+   {
+      Sim::findObject( cubeDescId, reflectorDesc );
+   }
+
    return true;
 }
 
@@ -429,6 +455,8 @@ void TSStatic::onRemove()
    mShapeInstance = NULL;
 
    mAmbientThread = NULL;
+   if ( isClientObject() )
+       mCubeReflector.unregisterReflector();
 
    Parent::onRemove();
 }
@@ -561,6 +589,12 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
 
    F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));   
 
+   // If we're currently rendering our own reflection we
+   // don't want to render ourselves into it.
+   if ( mCubeReflector.isRendering() )
+      return;
+
+
    if ( mForceDetail == -1 )
       mShapeInstance->setDetailFromDistance( state, dist * invScale );
    else
@@ -577,6 +611,9 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    rdata.setFadeOverride( 1.0f );
    rdata.setOriginSort( mUseOriginSort );
 
+   if ( mCubeReflector.isEnabled() )
+      rdata.setCubemap( mCubeReflector.getCubemap() );
+
    // Acculumation
    rdata.setAccuTex(mAccuTex);
 
@@ -604,6 +641,20 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    mat.scale( mObjScale );
    GFX->setWorldMatrix( mat );
 
+   if ( state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery() )
+   {
+       RenderPassManager *pass = state->getRenderPass();
+       OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>();  
+       
+       ri->type = RenderPassManager::RIT_Occluder;
+       ri->query = mCubeReflector.getOcclusionQuery();
+       mObjToWorld.mulP( mObjBox.getCenter(), &ri->position );
+       ri->scale.set( mObjBox.getExtents() );
+       ri->orientation = pass->allocUniqueXform( mObjToWorld ); 
+       ri->isSphere = false;
+       state->getRenderPass()->addInst( ri );
+   }
+
    mShapeInstance->animate();
    if(mShapeInstance)
    {
@@ -715,6 +766,10 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
    if ( mLightPlugin )
       retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
 
+   if( stream->writeFlag( reflectorDesc != NULL ) )
+   {
+      stream->writeRangedU32( reflectorDesc->getId(), DataBlockObjectIdFirst,  DataBlockObjectIdLast );
+   }
    return retMask;
 }
 
@@ -782,6 +837,11 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
       mLightPlugin->unpackUpdate(this, con, stream);
    }
 
+   if( stream->readFlag() )
+   {
+      cubeDescId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
+   }
+
    if ( isProperlyAdded() )
       _updateShouldTick();
 }
@@ -1171,8 +1231,10 @@ DefineEngineMethod( TSStatic, changeMaterial, void, ( const char* mapTo, Materia
       return;
    }
 
+   TSMaterialList* shapeMaterialList = object->getShape()->materialList;
+
    // Check the mapTo name exists for this shape
-   S32 matIndex = object->getShape()->materialList->getMaterialNameList().find_next(String(mapTo));
+   S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo));
    if (matIndex < 0)
    {
       Con::errorf("TSShape::changeMaterial failed: Invalid mapTo name '%s'", mapTo);
@@ -1190,13 +1252,13 @@ DefineEngineMethod( TSStatic, changeMaterial, void, ( const char* mapTo, Materia
 
    // Replace instances with the new material being traded in. Lets make sure that we only
    // target the specific targets per inst, this is actually doing more than we thought
-   delete object->getShape()->materialList->mMatInstList[matIndex];
-   object->getShape()->materialList->mMatInstList[matIndex] = newMat->createMatInstance();
+   delete shapeMaterialList->mMatInstList[matIndex];
+   shapeMaterialList->mMatInstList[matIndex] = newMat->createMatInstance();
 
    // Finish up preparing the material instances for rendering
    const GFXVertexFormat *flags = getGFXVertexFormat<GFXVertexPNTTB>();
    FeatureSet features = MATMGR->getDefaultFeatures();
-   object->getShape()->materialList->getMaterialInst(matIndex)->init( features, flags );
+   shapeMaterialList->getMaterialInst(matIndex)->init(features, flags);
 }
 
 DefineEngineMethod( TSStatic, getModelFile, const char *, (),,

+ 9 - 0
Engine/source/T3D/tsStatic.h

@@ -39,6 +39,10 @@
 #include "ts/tsShape.h"
 #endif
 
+#ifndef _REFLECTOR_H_
+   #include "scene/reflector.h"
+#endif
+
 class TSShapeInstance;
 class TSThread;
 class TSStatic;
@@ -147,6 +151,11 @@ protected:
    /// Start or stop processing ticks depending on our state.
    void _updateShouldTick();
 
+   String cubeDescName;
+   U32 cubeDescId;
+   ReflectorDesc *reflectorDesc;
+   CubeReflector mCubeReflector;
+
 protected:
 
    Convex *mConvexList;

+ 9 - 10
Engine/source/T3D/turret/turretShape.cpp

@@ -1059,9 +1059,9 @@ void TurretShape::writePacketData(GameConnection *connection, BitStream *stream)
 {
    // Update client regardless of status flags.
    Parent::writePacketData(connection, stream);
-
-   stream->write(mRot.x);
-   stream->write(mRot.z);
+   
+   stream->writeSignedFloat(mRot.x / M_2PI_F, 7);
+   stream->writeSignedFloat(mRot.z / M_2PI_F, 7);
 }
 
 void TurretShape::readPacketData(GameConnection *connection, BitStream *stream)
@@ -1069,9 +1069,8 @@ void TurretShape::readPacketData(GameConnection *connection, BitStream *stream)
    Parent::readPacketData(connection, stream);
 
    Point3F rot(0.0f, 0.0f, 0.0f);
-   stream->read(&rot.x);
-   stream->read(&rot.z);
-
+   rot.x = stream->readSignedFloat(7) * M_2PI_F;
+   rot.z = stream->readSignedFloat(7) * M_2PI_F;
    _setRotation(rot);
 
    mTurretDelta.rot = rot;
@@ -1100,8 +1099,8 @@ U32 TurretShape::packUpdate(NetConnection *connection, U32 mask, BitStream *stre
 
    if (stream->writeFlag(mask & TurretUpdateMask))
    {
-      stream->write(mRot.x);
-      stream->write(mRot.z);
+      stream->writeSignedFloat(mRot.x / M_2PI_F, 7);
+      stream->writeSignedFloat(mRot.z / M_2PI_F, 7);
       stream->write(allowManualRotation);
       stream->write(allowManualFire);
    }
@@ -1137,8 +1136,8 @@ void TurretShape::unpackUpdate(NetConnection *connection, BitStream *stream)
    if (stream->readFlag())
    {
       Point3F rot(0.0f, 0.0f, 0.0f);
-      stream->read(&rot.x);
-      stream->read(&rot.z);
+      rot.x = stream->readSignedFloat(7) * M_2PI_F;
+      rot.z = stream->readSignedFloat(7) * M_2PI_F;
       _setRotation(rot);
 
       // New delta for client side interpolation

+ 3 - 0
Engine/source/T3D/vehicles/wheeledVehicle.cpp

@@ -1086,6 +1086,9 @@ void WheeledVehicle::updateForces(F32 dt)
    if (mJetting)
       mRigid.force += by * mDataBlock->jetForce;
 
+   // Add in force from physical zones...
+   mRigid.force += mAppliedForce;
+
    // Container drag & buoyancy
    mRigid.force  += Point3F(0, 0, -mBuoyancy * sWheeledVehicleGravity * mRigid.mass);
    mRigid.force  -= mRigid.linVelocity * mDrag;

+ 2 - 1
Engine/source/app/badWordFilter.cpp

@@ -23,9 +23,10 @@
 #include "core/strings/stringFunctions.h"
 
 #include "console/consoleTypes.h"
+#include "console/simBase.h"
+#include "console/engineAPI.h"
 #include "app/badWordFilter.h"
 #include "core/module.h"
-#include "console/engineAPI.h"
 
 MODULE_BEGIN( BadWordFilter )
 

+ 25 - 15
Engine/source/app/mainLoop.cpp

@@ -61,14 +61,18 @@
 // For the TickMs define... fix this for T2D...
 #include "T3D/gameBase/processList.h"
 
-#ifdef TORQUE_DEMO_PURCHASE
-#include "demo/pestTimer/pestTimer.h"
-#endif
-
 #ifdef TORQUE_ENABLE_VFS
 #include "platform/platformVFS.h"
 #endif
 
+#ifndef _MODULE_MANAGER_H
+#include "module/moduleManager.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assets/assetManager.h"
+#endif
+
 DITTS( F32, gTimeScale, 1.0 );
 DITTS( U32, gTimeAdvance, 0 );
 DITTS( U32, gFrameSkip, 0 );
@@ -261,7 +265,7 @@ void StandardMainLoop::init()
 
    // Initialize modules.
    
-   ModuleManager::initializeSystem();
+   EngineModuleManager::initializeSystem();
          
    // Initialise ITickable.
 #ifdef TORQUE_TGB_ONLY
@@ -292,6 +296,15 @@ void StandardMainLoop::init()
 	Con::addVariable("MiniDump::Params", TypeString, &gMiniDumpParams);
 	Con::addVariable("MiniDump::ExecDir", TypeString, &gMiniDumpExecDir);
 #endif
+
+   // Register the module manager.
+   ModuleDatabase.registerObject("ModuleDatabase");
+
+   // Register the asset database.
+   AssetDatabase.registerObject("AssetDatabase");
+
+   // Register the asset database as a module listener.
+   ModuleDatabase.addListener(&AssetDatabase);
    
    ActionMap* globalMap = new ActionMap;
    globalMap->registerObject("GlobalActionMap");
@@ -309,10 +322,6 @@ void StandardMainLoop::init()
    // Hook in for UDP notification
    Net::smPacketReceive.notify(GNet, &NetInterface::processPacketReceiveEvent);
 
-   #ifdef TORQUE_DEMO_PURCHASE
-   PestTimerinit();
-   #endif
-
    #ifdef TORQUE_DEBUG_GUARD
       Memory::flagCurrentAllocs( Memory::FLAG_Static );
    #endif
@@ -325,10 +334,16 @@ void StandardMainLoop::shutdown()
 
    delete tm;
    preShutdown();
+
+   // Unregister the module database.
+   ModuleDatabase.unregisterObject();
+
+   // Unregister the asset database.
+   AssetDatabase.unregisterObject();
    
    // Shut down modules.
    
-   ModuleManager::shutdownSystem();
+   EngineModuleManager::shutdownSystem();
    
    ThreadPool::GlobalThreadPool::deleteSingleton();
 
@@ -613,11 +628,6 @@ bool StandardMainLoop::doMainLoop()
       ThreadPool::processMainThreadWorkItems();
       Sampler::endFrame();
       PROFILE_END_NAMED(MainLoop);
-
-	  #ifdef TORQUE_DEMO_PURCHASE
-	  CheckTimer();
-	  CheckBlocker();
-	  #endif
    }
    
    return keepRunning;

+ 3 - 8
Engine/source/app/net/serverQuery.cpp

@@ -240,6 +240,7 @@ struct ServerFilter
 
    ServerFilter()
    {
+      type = Normal;
       queryFlags = 0;
       gameType = NULL;
       missionType = NULL;
@@ -433,8 +434,6 @@ DefineConsoleFunction( queryAllServers
 
    queryLanServers(lanPort, flags, gameType, missionType, minPlayers, maxPlayers, maxBots,
       regionMask, maxPing, minCPU, filterFlags);
-   dFree(gameType);
-   dFree(missionType);
 
 }
 
@@ -541,8 +540,7 @@ void queryMasterServer(U8 flags, const char* gameType, const char* missionType,
 }
 
 DefineConsoleFunction( queryMasterServer
-                     , void, ( U32 lanPort
-                             , U32 flags
+                     , void, (  U32 flags
                              , const char * gameType
                              , const char * missionType
                              , U32 minPlayers
@@ -559,9 +557,6 @@ DefineConsoleFunction( queryMasterServer
    clearServerList();
    queryMasterServer(flags,gameType,missionType,minPlayers,maxPlayers,
       maxBots,regionMask,maxPing,minCPU,filterFlags,0,&buddyList);
-
-   dFree(gameType);
-   dFree(missionType);
 }
 
 //-----------------------------------------------------------------------------
@@ -1342,7 +1337,7 @@ static void processPingsAndQueries( U32 session, bool schedule )
       else
          dSprintf( msg, sizeof( msg ), "%d servers found.", foundCount );
 
-      Con::executef( "onServerQueryStatus", "done", msg, "1");
+      Con::executef( "onServerQueryStatus", "done", (const char*)msg, "1");
    }
 }
 

+ 86 - 1
Engine/source/app/net/tcpObject.cpp

@@ -27,6 +27,7 @@
 #include "console/consoleInternal.h"
 #include "core/strings/stringUnit.h"
 #include "console/engineAPI.h"
+#include "core/stream/fileStream.h"
 
 TCPObject *TCPObject::table[TCPObject::TableSize] = {0, };
 
@@ -138,6 +139,15 @@ IMPLEMENT_CALLBACK(TCPObject, onLine, void, (const char* line), (line),
    "@param line Data sent from the server.\n"
    );
 
+IMPLEMENT_CALLBACK(TCPObject, onPacket, bool, (const char* data), (data),
+   "@brief Called when we get a packet with no newlines or nulls (probably websocket).\n\n"
+   "@param data Data sent from the server.\n"
+   "@return true if script handled the packet.\n"
+   );
+IMPLEMENT_CALLBACK(TCPObject, onEndReceive, void, (), (),
+   "@brief Called when we are done reading all lines.\n\n"
+   );
+
 IMPLEMENT_CALLBACK(TCPObject, onDNSResolved, void, (),(),
    "Called whenever the DNS has been resolved.\n"
    );
@@ -355,7 +365,7 @@ void TCPObject::onConnectFailed()
    onConnectFailed_callback();
 }
 
-void TCPObject::finishLastLine()
+bool TCPObject::finishLastLine()
 {
    if(mBufferSize)
    {
@@ -364,6 +374,25 @@ void TCPObject::finishLastLine()
       dFree(mBuffer);
       mBuffer = 0;
       mBufferSize = 0;
+
+      return true;
+   }
+
+   return false;
+}
+
+bool TCPObject::isBufferEmpty()
+{
+   return (mBufferSize <= 0);
+}
+
+void TCPObject::emptyBuffer()
+{
+   if(mBufferSize)
+   {
+      dFree(mBuffer);
+      mBuffer = 0;
+      mBufferSize = 0;
    }
 }
 
@@ -400,6 +429,25 @@ void TCPObject::send(const U8 *buffer, U32 len)
    Net::sendtoSocket(mTag, buffer, S32(len));
 }
 
+bool TCPObject::sendFile(const char* fileName)
+{
+   //Open the file for reading
+   FileStream readFile;
+   if(!readFile.open(fileName, Torque::FS::File::Read))
+   {
+      return false;
+   }
+
+   //Read each byte into our buffer
+   Vector<U8> buffer(readFile.getStreamSize());
+   readFile.read(buffer.size(), &buffer);
+
+   //Send the buffer
+   send(buffer.address(), buffer.size());
+
+   	return true;
+}
+
 DefineEngineMethod(TCPObject, send, void, (const char *data),, 
    "@brief Transmits the data string to the connected computer.\n\n"
 
@@ -421,6 +469,20 @@ DefineEngineMethod(TCPObject, send, void, (const char *data),,
    object->send( (const U8*)data, dStrlen(data) );
 }
 
+DefineEngineMethod(TCPObject, sendFile, bool, (const char *fileName),, 
+   "@brief Transmits the file in binary to the connected computer.\n\n"
+
+   "@param fileName The filename of the file to transfer.\n")
+{
+   return object->sendFile(fileName);
+}
+
+DefineEngineMethod(TCPObject, finishLastLine, void, (),, 
+   "@brief Eat the rest of the lines.\n")
+{
+   object->finishLastLine();
+}
+
 DefineEngineMethod(TCPObject, listen, void, (U32 port),, 
    "@brief Start listening on the specified port for connections.\n\n"
 
@@ -499,6 +561,29 @@ void processConnectedReceiveEvent(NetSocket sock, RawData incomingData)
       size -= ret;
       buffer += ret;
    }
+
+   //If our buffer now has something in it then it's probably a web socket packet and lets handle it
+   if(!tcpo->isBufferEmpty())
+   {
+      //Copy all the data into a string (may be a quicker way of doing this)
+      U8 *data = (U8*)incomingData.data;
+      String temp;
+      for(S32 i = 0; i < incomingData.size; i++)
+      {
+         temp += data[i];
+      }
+
+      //Send the packet to script
+      bool handled = tcpo->onPacket_callback(temp);
+
+      //If the script did something with it, clear the buffer
+      if(handled)
+      {
+         tcpo->emptyBuffer();
+      }
+   }
+
+   tcpo->onEndReceive_callback();
 }
 
 void processConnectedAcceptEvent(NetSocket listeningPort, NetSocket newConnection, NetAddress originatingAddress)

+ 11 - 1
Engine/source/app/net/tcpObject.h

@@ -36,6 +36,8 @@ public:
 
 	DECLARE_CALLBACK(void, onConnectionRequest, (const char* address, const char* ID));
 	DECLARE_CALLBACK(void, onLine, (const char* line));
+	DECLARE_CALLBACK(bool, onPacket, (const char* data));
+	DECLARE_CALLBACK(void, onEndReceive, ());
 	DECLARE_CALLBACK(void, onDNSResolved,());
 	DECLARE_CALLBACK(void, onDNSFailed, ());
 	DECLARE_CALLBACK(void, onConnected, ());
@@ -60,7 +62,9 @@ public:
    virtual ~TCPObject();
 
    void parseLine(U8 *buffer, U32 *start, U32 bufferLen);
-   void finishLastLine();
+   bool finishLastLine();
+   bool isBufferEmpty();
+   void emptyBuffer();
 
    static TCPObject *find(NetSocket tag);
 
@@ -81,6 +85,12 @@ public:
 
    bool processArguments(S32 argc, ConsoleValueRef *argv);
    void send(const U8 *buffer, U32 bufferLen);
+
+   ///Send an entire file over tcp
+   ///@arg fileName Full path to file you want to send
+   ///@return true if file was sent, false if not (file doesn't exist)
+   bool sendFile(const char* fileName);
+
    void addToTable(NetSocket newTag);
    void removeFromTable();
 

+ 1 - 19
Engine/source/app/version.cpp

@@ -139,22 +139,4 @@ DefineConsoleFunction( getBuildString, const char*, (), , "Get the type of build
 #endif
 }
 
-ConsoleFunctionGroupEnd( CompileInformation );
-
-DefineConsoleFunction( isDemo, bool, (), , "")
-{
-#ifdef TORQUE_DEMO
-   return true;
-#else
-   return false;
-#endif
-}
-
-DefineConsoleFunction( isWebDemo, bool, (), , "")
-{
-#ifdef TORQUE_DEMO
-   return Platform::getWebDeployment();
-#else
-   return false;
-#endif
-}
+ConsoleFunctionGroupEnd( CompileInformation );

+ 352 - 0
Engine/source/assets/assetBase.cpp

@@ -0,0 +1,352 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+// Script bindings.
+#include "assetBase_ScriptBinding.h"
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(AssetBase);
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry assetNameField = StringTable->insert("AssetName");
+StringTableEntry assetDescriptionField = StringTable->insert("AssetDescription");
+StringTableEntry assetCategoryField = StringTable->insert("AssetCategory");
+StringTableEntry assetAutoUnloadField = StringTable->insert("AssetAutoUnload");
+StringTableEntry assetInternalField = StringTable->insert("AssetInternal");
+StringTableEntry assetPrivateField = StringTable->insert("AssetPrivate");
+
+//-----------------------------------------------------------------------------
+
+AssetBase::AssetBase() :
+mAcquireReferenceCount(0),
+mpOwningAssetManager(NULL),
+mAssetInitialized(false)
+{
+   // Generate an asset definition.
+   mpAssetDefinition = new AssetDefinition();
+}
+
+//-----------------------------------------------------------------------------
+
+AssetBase::~AssetBase()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   // Asset configuration.
+   addProtectedField(assetNameField, TypeString, 0, &setAssetName, &getAssetName, &writeAssetName, "The name of the asset.  The is not a unique identification like an asset Id.");
+   addProtectedField(assetDescriptionField, TypeString, 0, &setAssetDescription, &getAssetDescription, &writeAssetDescription, "The simple description of the asset contents.");
+   addProtectedField(assetCategoryField, TypeString, 0, &setAssetCategory, &getAssetCategory, &writeAssetCategory, "An arbitrary category that can be used to categorized assets.");
+   addProtectedField(assetAutoUnloadField, TypeBool, 0, &setAssetAutoUnload, &getAssetAutoUnload, &writeAssetAutoUnload, "Whether the asset is automatically unloaded when an asset is released and has no other acquisitions or not.");
+   addProtectedField(assetInternalField, TypeBool, 0, &setAssetInternal, &getAssetInternal, &writeAssetInternal, "Whether the asset is used internally only or not.");
+   addProtectedField(assetPrivateField, TypeBool, 0, &defaultProtectedNotSetFn, &getAssetPrivate, &defaultProtectedNotWriteFn, "Whether the asset is private or not.");
+}
+
+//------------------------------------------------------------------------------
+
+void AssetBase::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+
+   // Cast to asset.
+   AssetBase* pAsset = static_cast<AssetBase*>(object);
+
+   // Sanity!
+   AssertFatal(pAsset != NULL, "AssetBase::copyTo() - Object is not the correct type.");
+
+   // Copy state.
+   pAsset->setAssetName(getAssetName());
+   pAsset->setAssetDescription(getAssetDescription());
+   pAsset->setAssetCategory(getAssetCategory());
+   pAsset->setAssetAutoUnload(getAssetAutoUnload());
+   pAsset->setAssetInternal(getAssetInternal());
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetDescription(const char* pAssetDescription)
+{
+   // Fetch asset description.
+   StringTableEntry assetDescription = StringTable->insert(pAssetDescription);
+
+   // Ignore no change.
+   if (mpAssetDefinition->mAssetDescription == assetDescription)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetDescription = assetDescription;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetCategory(const char* pAssetCategory)
+{
+   // Fetch asset category.
+   StringTableEntry assetCategory = StringTable->insert(pAssetCategory);
+
+   // Ignore no change.
+   if (mpAssetDefinition->mAssetCategory == assetCategory)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetCategory = assetCategory;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetAutoUnload(const bool autoUnload)
+{
+   // Ignore no change.
+   if (mpAssetDefinition->mAssetAutoUnload == autoUnload)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetAutoUnload = autoUnload;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setAssetInternal(const bool assetInternal)
+{
+   // Ignore no change,
+   if (mpAssetDefinition->mAssetInternal == assetInternal)
+      return;
+
+   // Update.
+   mpAssetDefinition->mAssetInternal = assetInternal;
+
+   // Refresh the asset.
+   refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetBase::expandAssetFilePath(const char* pAssetFilePath) const
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_ExpandAssetFilePath);
+
+   // Sanity!
+   AssertFatal(pAssetFilePath != NULL, "Cannot expand a NULL asset path.");
+
+   // Fetch asset file-path length.
+   const U32 assetFilePathLength = dStrlen(pAssetFilePath);
+
+   // Are there any characters in the path?
+   if (assetFilePathLength == 0)
+   {
+      // No, so return empty.
+      return StringTable->EmptyString();
+   }
+
+   // Fetch the asset base-path hint.
+   StringTableEntry assetBasePathHint;
+   if (getOwned() && !getAssetPrivate())
+   {
+      assetBasePathHint = mpOwningAssetManager->getAssetPath(getAssetId());
+   }
+   else
+   {
+      assetBasePathHint = NULL;
+   }
+
+   // Expand the path with the asset base-path hint.
+   char assetFilePathBuffer[1024];
+   Con::expandPath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath, assetBasePathHint);
+   return StringTable->insert(assetFilePathBuffer);
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetBase::collapseAssetFilePath(const char* pAssetFilePath) const
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_CollapseAssetFilePath);
+
+   // Sanity!
+   AssertFatal(pAssetFilePath != NULL, "Cannot collapse a NULL asset path.");
+
+   // Fetch asset file-path length.
+   const U32 assetFilePathLength = dStrlen(pAssetFilePath);
+
+   // Are there any characters in the path?
+   if (assetFilePathLength == 0)
+   {
+      // No, so return empty.
+      return StringTable->EmptyString();
+   }
+
+   char assetFilePathBuffer[1024];
+
+   // Is the asset not owned or private?
+   if (!getOwned() || getAssetPrivate())
+   {
+      // Yes, so we can only collapse the path using the platform layer.
+      Con::collapsePath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath);
+      return StringTable->insert(assetFilePathBuffer);
+   }
+
+   // Fetch asset base-path.
+   StringTableEntry assetBasePath = mpOwningAssetManager->getAssetPath(getAssetId());
+
+   // Is the asset file-path location within the asset base-path?
+   if (Con::isBasePath(pAssetFilePath, assetBasePath))
+   {
+      // Yes, so fetch path relative to the asset base-path.
+      StringTableEntry relativePath = Platform::makeRelativePathName(pAssetFilePath, assetBasePath);
+
+      // Format the collapsed path.
+      dSprintf(assetFilePathBuffer, sizeof(assetFilePathBuffer), "%s", relativePath);
+   }
+   else
+   {
+      // No, so we can collapse the path using the platform layer.
+      Con::collapsePath(assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath);
+   }
+
+   return StringTable->insert(assetFilePathBuffer);
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::refreshAsset(void)
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_RefreshAsset);
+
+   // Finish if asset is not owned or is not initialized.
+   if (mpOwningAssetManager == NULL || !mAssetInitialized)
+      return;
+
+   // Yes, so refresh the asset via the asset manager.
+   mpOwningAssetManager->refreshAsset(getAssetId());
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::acquireAssetReference(void)
+{
+   // Acquired the acquired reference count.
+   if (mpOwningAssetManager != NULL)
+      mpOwningAssetManager->acquireAcquiredReferenceCount();
+
+   mAcquireReferenceCount++;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetBase::releaseAssetReference(void)
+{
+   // Are there any acquisition references?
+   if (mAcquireReferenceCount == 0)
+   {
+      // Return "unload" unless auto unload is off.
+      return mpAssetDefinition->mAssetAutoUnload;
+   }
+
+   // Release the acquired reference count.
+   if (mpOwningAssetManager != NULL)
+      mpOwningAssetManager->releaseAcquiredReferenceCount();
+
+   // Release reference.
+   mAcquireReferenceCount--;
+
+   // Are there any acquisition references?
+   if (mAcquireReferenceCount == 0)
+   {
+      // No, so return "unload" unless auto unload is off.
+      return mpAssetDefinition->mAssetAutoUnload;
+   }
+
+   // Return "don't unload".
+   return false;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetBase::setOwned(AssetManager* pAssetManager, AssetDefinition* pAssetDefinition)
+{
+   // Debug Profiling.
+   PROFILE_SCOPE(AssetBase_setOwned);
+
+   // Sanity!
+   AssertFatal(pAssetManager != NULL, "Cannot set asset ownership with NULL asset manager.");
+   AssertFatal(mpOwningAssetManager == NULL, "Cannot set asset ownership if it is already owned.");
+   AssertFatal(pAssetDefinition != NULL, "Cannot set asset ownership with a NULL asset definition.");
+   AssertFatal(mpAssetDefinition != NULL, "Asset ownership assigned but has a NULL asset definition.");
+   AssertFatal(mpAssetDefinition->mAssetName == pAssetDefinition->mAssetName, "Asset ownership differs by asset name.");
+   AssertFatal(mpAssetDefinition->mAssetDescription == pAssetDefinition->mAssetDescription, "Asset ownership differs by asset description.");
+   AssertFatal(mpAssetDefinition->mAssetCategory == pAssetDefinition->mAssetCategory, "Asset ownership differs by asset category.");
+   AssertFatal(mpAssetDefinition->mAssetAutoUnload == pAssetDefinition->mAssetAutoUnload, "Asset ownership differs by asset auto-unload flag.");
+   AssertFatal(mpAssetDefinition->mAssetInternal == pAssetDefinition->mAssetInternal, "Asset ownership differs by asset internal flag.");
+
+   // Transfer asset definition ownership state.
+   delete mpAssetDefinition;
+   mpAssetDefinition = pAssetDefinition;
+
+   // Flag as owned.
+   // NOTE: This must be done prior to initializing the asset so any initialization can assume ownership.
+   mpOwningAssetManager = pAssetManager;
+
+   // Initialize the asset.
+   initializeAsset();
+
+   // Flag asset as initialized.
+   mAssetInitialized = true;
+}

+ 145 - 0
Engine/source/assets/assetBase.h

@@ -0,0 +1,145 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+#ifndef _ASSET_BASE_H_
+#define _ASSET_BASE_H_
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assetDefinition.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class AssetManager;
+
+//-----------------------------------------------------------------------------
+
+extern StringTableEntry assetNameField;
+extern StringTableEntry assetDescriptionField;
+extern StringTableEntry assetCategoryField;
+extern StringTableEntry assetInternalField;
+extern StringTableEntry assetPrivateField;
+extern StringTableEntry assetAutoUnloadField;
+
+//#define ASSET_BASE_ASSETNAME_FIELD         "AssetName"
+//#define ASSET_BASE_ASSETDESCRIPTION_FIELD  "AssetDescription"
+//#define ASSET_BASE_ASSETCATEGORY_FIELD     "AssetCategory"
+//#define ASSET_BASE_ASSETINTERNAL_FIELD     "AssetInternal"
+//#define ASSET_BASE_ASSETPRIVATE_FIELD      "AssetPrivate"
+//#define ASSET_BASE_AUTOUNLOAD_FIELD        "AssetAutoUnload"
+
+//-----------------------------------------------------------------------------
+
+class AssetBase : public SimObject
+{
+   friend class AssetManager;
+
+   typedef SimObject Parent;
+
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
+
+public:
+   AssetBase();
+   virtual ~AssetBase();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Asset configuration.
+   inline void             setAssetName(const char* pAssetName)              { if (mpOwningAssetManager == NULL) mpAssetDefinition->mAssetName = StringTable->insert(pAssetName); }
+   inline StringTableEntry getAssetName(void) const                          { return mpAssetDefinition->mAssetName; }
+   void                    setAssetDescription(const char* pAssetDescription);
+   inline StringTableEntry getAssetDescription(void) const                   { return mpAssetDefinition->mAssetDescription; }
+   void                    setAssetCategory(const char* pAssetCategory);
+   inline StringTableEntry getAssetCategory(void) const                      { return mpAssetDefinition->mAssetCategory; }
+   void                    setAssetAutoUnload(const bool autoUnload);
+   inline bool             getAssetAutoUnload(void) const                    { return mpAssetDefinition->mAssetAutoUnload; }
+   void                    setAssetInternal(const bool assetInternal);
+   inline bool             getAssetInternal(void) const                      { return mpAssetDefinition->mAssetInternal; }
+   inline bool             getAssetPrivate(void) const                       { return mpAssetDefinition->mAssetPrivate; }
+   inline StringTableEntry getAssetType(void) const                          { return mpAssetDefinition->mAssetType; }
+
+   inline S32              getAcquiredReferenceCount(void) const             { return mAcquireReferenceCount; }
+   inline bool             getOwned(void) const                              { return mpOwningAssetManager != NULL; }
+
+   // Asset Id is only available once registered with the asset manager.
+   inline StringTableEntry getAssetId(void) const                            { return mpAssetDefinition->mAssetId; }
+
+   /// Expanding/Collapsing asset paths is only available once registered with the asset manager.
+   StringTableEntry        expandAssetFilePath(const char* pAssetFilePath) const;
+   StringTableEntry        collapseAssetFilePath(const char* pAssetFilePath) const;
+
+   virtual bool            isAssetValid(void) const                          { return true; }
+
+   void                    refreshAsset(void);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(AssetBase);
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+
+protected:
+   static bool             setAssetName(void *obj, const char *array, const char *data)           { static_cast<AssetBase*>(obj)->setAssetName(data); return false; }
+   static const char*      getAssetName(void* obj, const char* data)           { return static_cast<AssetBase*>(obj)->getAssetName(); }
+   static bool             writeAssetName(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetName() != StringTable->EmptyString(); }
+
+   static bool             setAssetDescription(void *obj, const char *array, const char *data)    { static_cast<AssetBase*>(obj)->setAssetDescription(data); return false; }
+   static const char*      getAssetDescription(void* obj, const char* data)    { return static_cast<AssetBase*>(obj)->getAssetDescription(); }
+   static bool             writeAssetDescription(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetDescription() != StringTable->EmptyString(); }
+
+   static bool             setAssetCategory(void *obj, const char *array, const char *data)       { static_cast<AssetBase*>(obj)->setAssetCategory(data); return false; }
+   static const char*      getAssetCategory(void* obj, const char* data)       { return static_cast<AssetBase*>(obj)->getAssetCategory(); }
+   static bool             writeAssetCategory(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetCategory() != StringTable->EmptyString(); }
+
+   static bool             setAssetAutoUnload(void *obj, const char *array, const char *data)     { static_cast<AssetBase*>(obj)->setAssetAutoUnload(dAtob(data)); return false; }
+   static const char*      getAssetAutoUnload(void* obj, const char* data)     { return Con::getBoolArg(static_cast<AssetBase*>(obj)->getAssetAutoUnload()); }
+   static bool             writeAssetAutoUnload(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetAutoUnload() == false; }
+
+   static bool             setAssetInternal(void *obj, const char *array, const char *data)       { static_cast<AssetBase*>(obj)->setAssetInternal(dAtob(data)); return false; }
+   static const char*      getAssetInternal(void* obj, const char* data)       { return Con::getBoolArg(static_cast<AssetBase*>(obj)->getAssetInternal()); }
+   static bool             writeAssetInternal(void* obj, StringTableEntry pFieldName) { return static_cast<AssetBase*>(obj)->getAssetInternal() == true; }
+
+   static const char*      getAssetPrivate(void* obj, const char* data)        { return Con::getBoolArg(static_cast<AssetBase*>(obj)->getAssetPrivate()); }
+
+private:
+   void                    acquireAssetReference(void);
+   bool                    releaseAssetReference(void);
+
+   /// Set asset manager ownership.
+   void                    setOwned(AssetManager* pAssetManager, AssetDefinition* pAssetDefinition);
+};
+
+#endif // _ASSET_BASE_H_
+

+ 41 - 0
Engine/source/assets/assetBase_ScriptBinding.h

@@ -0,0 +1,41 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+#include "console/engineAPI.h"
+#include "assetBase.h"
+#include "assetManager.h"
+
+
+DefineEngineMethod(AssetBase, refreshAsset, void, (), ,
+   "Refresh the asset.\n"
+   "@return No return value.\n")
+{
+    object->refreshAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetBase, getAssetId, String, (), ,
+   "Gets the assets' Asset Id.  This is only available if the asset was acquired from the asset manager.\n"
+   "@return The assets' Asset Id.\n")
+{
+    return object->getAssetId();
+}

+ 102 - 0
Engine/source/assets/assetDefinition.h

@@ -0,0 +1,102 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_DEFINITION_H_
+#define _ASSET_DEFINITION_H_
+
+#ifndef _STRINGTABLE_H_
+#include "core/stringTable.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "core/strings/stringUnit.h"
+#endif
+
+#ifndef _SIM_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _SIMOBJECT_H_
+#include "console/simObject.h"
+#endif
+
+#ifndef _CONSOLEOBJECT_H_
+#include "console/consoleObject.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class AssetBase;
+class ModuleDefinition;
+
+//-----------------------------------------------------------------------------
+
+struct AssetDefinition
+{
+public:
+    AssetDefinition() { reset(); }
+    virtual ~AssetDefinition() {}
+
+    virtual void reset( void )
+    {
+        mAssetLoading = false;
+        mpModuleDefinition = NULL;
+        mpAssetBase = NULL;
+        mAssetBaseFilePath = StringTable->EmptyString();
+        mAssetId = StringTable->EmptyString();
+        mAssetLoadedCount = 0;
+        mAssetUnloadedCount = 0;
+        mAssetRefreshEnable = true;
+        mAssetLooseFiles.clear();
+
+        // Reset persisted state.
+        mAssetName = StringTable->EmptyString();
+        mAssetDescription = StringTable->EmptyString();
+        mAssetAutoUnload = true;
+        mAssetInternal = false;
+        mAssetPrivate = false;
+        mAssetType = StringTable->EmptyString();
+        mAssetCategory = StringTable->EmptyString();
+    }
+
+    ModuleDefinition*           mpModuleDefinition;
+    AssetBase*                  mpAssetBase;
+    StringTableEntry            mAssetBaseFilePath;
+    StringTableEntry            mAssetId;
+    U32                         mAssetLoadedCount;
+    U32                         mAssetUnloadedCount;
+    bool                        mAssetRefreshEnable;
+    Vector<StringTableEntry>    mAssetLooseFiles;
+
+    /// Persisted state.
+    StringTableEntry            mAssetName;
+    StringTableEntry            mAssetDescription;
+    bool                        mAssetAutoUnload;
+    bool                        mAssetInternal; 
+    bool                        mAssetPrivate;
+    bool                        mAssetLoading;
+    StringTableEntry            mAssetType;
+    StringTableEntry            mAssetCategory;
+};
+
+#endif // _ASSET_DEFINITION_H_
+

+ 114 - 0
Engine/source/assets/assetFieldTypes.cpp

@@ -0,0 +1,114 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assetFieldTypes.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assetPtr.h"
+#endif
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+/*#ifndef _AUDIO_ASSET_H_
+#include "audio/AudioAsset.h"
+#endif*/
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry assetLooseIdSignature = StringTable->insert( ASSET_ID_SIGNATURE );
+StringTableEntry assetLooseFileSignature = StringTable->insert( ASSET_LOOSEFILE_SIGNATURE );
+
+//-----------------------------------------------------------------------------
+
+ConsoleType( assetLooseFilePath, TypeAssetLooseFilePath, String, ASSET_LOOSE_FILE_FIELD_PREFIX )
+ConsoleType(assetIdString, TypeAssetId, String, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType( TypeAssetLooseFilePath )
+{
+    // Fetch asset loose file-path.
+    return *((StringTableEntry*)dptr);
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType( TypeAssetLooseFilePath )
+{
+    // Was a single argument specified?
+    if( argc == 1 )
+    {
+        // Yes, so fetch field value.
+        const char* pFieldValue = argv[0];
+
+        // Fetch asset loose file-path.
+        StringTableEntry* assetLooseFilePath = (StringTableEntry*)(dptr);
+
+        // Update asset loose file-path value.
+        *assetLooseFilePath = StringTable->insert(pFieldValue);
+
+        return;
+    }
+
+    // Warn.
+    Con::warnf( "(TypeAssetLooseFilePath) - Cannot set multiple args to a single asset loose-file." );
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType( TypeAssetId )
+{
+    // Fetch asset Id.
+    return *((StringTableEntry*)dptr);
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType( TypeAssetId )
+{
+    // Was a single argument specified?
+    if( argc == 1 )
+    {
+        // Yes, so fetch field value.
+        const char* pFieldValue = argv[0];
+
+        // Fetch asset Id.
+        StringTableEntry* assetId = (StringTableEntry*)(dptr);
+
+        // Update asset value.
+        *assetId = StringTable->insert(pFieldValue);
+
+        return;
+    }
+
+    // Warn.
+    Con::warnf( "(TypeAssetId) - Cannot set multiple args to a single asset." );
+}
+

+ 56 - 0
Engine/source/assets/assetFieldTypes.h

@@ -0,0 +1,56 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#define _ASSET_FIELD_TYPES_H_
+
+#ifndef _CONSOLE_BASE_TYPE_H_
+#include "console/consoleTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleType( TypeAssetId, S32 )
+DefineConsoleType( TypeAssetLooseFilePath, String )
+
+//-----------------------------------------------------------------------------
+
+/// Asset scope.
+#define ASSET_SCOPE_TOKEN				":"
+
+/// Asset assignment.
+#define ASSET_ASSIGNMENT_TOKEN			"="
+
+/// Asset Id.
+#define ASSET_ID_SIGNATURE              "@asset"
+#define ASSET_ID_FIELD_PREFIX           "@asset="
+
+/// Asset loose file.
+#define ASSET_LOOSEFILE_SIGNATURE       "@assetFile"
+#define ASSET_LOOSE_FILE_FIELD_PREFIX   "@assetFile="
+
+//-----------------------------------------------------------------------------
+
+extern StringTableEntry assetLooseIdSignature;
+extern StringTableEntry assetLooseFileSignature;
+
+#endif // _ASSET_FIELD_TYPES_H_

+ 3017 - 0
Engine/source/assets/assetManager.cpp

@@ -0,0 +1,3017 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#include "assetManager.h"
+
+#ifndef _ASSET_PTR_H_
+#include "assetPtr.h"
+#endif
+
+#ifndef _REFERENCED_ASSETS_H_
+#include "assets/referencedAssets.h"
+#endif
+
+#ifndef _DECLARED_ASSETS_H_
+#include "assets/declaredAssets.h"
+#endif
+
+#ifndef _TAML_ASSET_REFERENCED_VISITOR_H_
+#include "tamlAssetReferencedVisitor.h"
+#endif
+
+#ifndef _TAML_ASSET_DECLARED_VISITOR_H_
+#include "tamlAssetDeclaredVisitor.h"
+#endif
+
+#ifndef _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
+#include "tamlAssetDeclaredUpdateVisitor.h"
+#endif
+
+#ifndef _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
+#include "tamlAssetReferencedUpdateVisitor.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+// Script bindings.
+#include "assetManager_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( AssetManager );
+
+//-----------------------------------------------------------------------------
+
+AssetManager AssetDatabase;
+
+//-----------------------------------------------------------------------------
+
+AssetManager::AssetManager() :
+    mLoadedInternalAssetsCount( 0 ),
+    mLoadedExternalAssetsCount( 0 ),
+    mLoadedPrivateAssetsCount( 0 ),
+    mMaxLoadedInternalAssetsCount( 0 ),
+    mMaxLoadedExternalAssetsCount( 0 ),
+    mMaxLoadedPrivateAssetsCount( 0 ),
+    mAcquiredReferenceCount( 0 ),
+    mEchoInfo( false ),
+    mIgnoreAutoUnload( false )
+{
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::onAdd()
+{
+    // Call parent.
+    if ( !Parent::onAdd() )
+        return false;
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onRemove()
+{
+    // Do we have an asset tags manifest?
+    if ( !mAssetTagsManifest.isNull() )
+    {
+        // Yes, so remove it.
+        mAssetTagsManifest->deleteObject();
+    }
+
+    // Call parent.
+    Parent::onRemove();
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::initPersistFields()
+{
+    // Call parent.
+    Parent::initPersistFields();
+
+    addField( "EchoInfo", TypeBool, Offset(mEchoInfo, AssetManager), "Whether the asset manager echos extra information to the console or not." );
+    addField( "IgnoreAutoUnload", TypeBool, Offset(mIgnoreAutoUnload, AssetManager), "Whether the asset manager should ignore unloading of auto-unload assets or not." );
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::compileReferencedAssets( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_CompileReferencedAsset);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot add declared assets using a NULL module definition" );
+
+    // Clear referenced assets.
+    mReferencedAssets.clear();
+
+    // Iterate the module definition children.
+    for( SimSet::iterator itr = pModuleDefinition->begin(); itr != pModuleDefinition->end(); ++itr )
+    {
+        // Fetch the referenced assets.
+        ReferencedAssets* pReferencedAssets = dynamic_cast<ReferencedAssets*>( *itr );
+
+        // Skip if it's not a referenced assets location.
+        if ( pReferencedAssets == NULL )
+            continue;
+
+        // Expand asset manifest location.
+        char filePathBuffer[1024];
+        dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pReferencedAssets->getPath() );
+
+        // Scan referenced assets at location.
+        if ( !scanReferencedAssets( filePathBuffer, pReferencedAssets->getExtension(), pReferencedAssets->getRecurse() ) )
+        {
+            // Warn.
+            Con::warnf( "AssetManager::compileReferencedAssets() - Could not scan for referenced assets at location '%s' with extension '%s'.", filePathBuffer, pReferencedAssets->getExtension() );
+        }
+    }  
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddDeclaredAssets);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot add declared assets using a NULL module definition" );
+
+    // Does the module have any assets associated with it?
+    if ( pModuleDefinition->getModuleAssets().size() > 0 )
+    {
+        // Yes, so warn.
+        Con::warnf( "Asset Manager: Cannot add declared assets to module '%s' as it already has existing assets.", pModuleDefinition->getSignature() );
+        return false;
+    }
+
+    // Iterate the module definition children.
+    for( SimSet::iterator itr = pModuleDefinition->begin(); itr != pModuleDefinition->end(); ++itr )
+    {
+        // Fetch the declared assets.
+        DeclaredAssets* pDeclaredAssets = dynamic_cast<DeclaredAssets*>( *itr );
+
+        // Skip if it's not a declared assets location.
+        if ( pDeclaredAssets == NULL )
+            continue;
+
+        // Expand asset manifest location.
+        char filePathBuffer[1024];
+        String mdldfpth = pModuleDefinition->getModulePath();
+        String astfpth = pDeclaredAssets->getPath();
+
+        //dSprintf( filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pDeclaredAssets->getPath() );
+        dSprintf(filePathBuffer, sizeof(filePathBuffer), "%s/%s", pModuleDefinition->getModulePath(), pDeclaredAssets->getPath());
+
+        // Scan declared assets at location.
+        if ( !scanDeclaredAssets( filePathBuffer, pDeclaredAssets->getExtension(), pDeclaredAssets->getRecurse(), pModuleDefinition ) )
+        {
+            // Warn.
+            Con::warnf( "AssetManager::addModuleDeclaredAssets() - Could not scan for declared assets at location '%s' with extension '%s'.", filePathBuffer, pDeclaredAssets->getExtension() );
+        }
+    }  
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddSingleDeclaredAsset);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot add single declared asset using a NULL module definition" );
+    AssertFatal( pAssetFilePath != NULL, "Cannot add single declared asset using a NULL asset file-path." );
+
+    // Expand asset file-path.
+    char assetFilePathBuffer[1024];
+    Con::expandPath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath );
+
+    // Find the final slash which should be just before the file.
+    char* pFileStart = dStrrchr( assetFilePathBuffer, '/' );
+
+    // Did we find the final slash?
+    if ( pFileStart == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not add single declared asset file '%s' as file-path '%s' is not valid.",
+            assetFilePathBuffer,
+            pModuleDefinition->getModulePath() );
+        return false;
+    }
+
+    // Terminate path at slash.
+    *pFileStart = 0;
+
+    // Move to next character which should be the file start.
+    pFileStart++;
+
+    // Scan declared assets at location.
+    if ( !scanDeclaredAssets( assetFilePathBuffer, pFileStart, false, pModuleDefinition ) )
+    {
+        // Warn.
+        Con::warnf( "AssetManager::addDeclaredAsset() - Could not scan declared assets at location '%s' with extension '%s'.", assetFilePathBuffer, pFileStart );
+        return false;
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::addPrivateAsset( AssetBase* pAssetBase )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddPrivateAsset);
+
+    // Sanity!
+    AssertFatal( pAssetBase != NULL, "Cannot add a NULL private asset." );
+
+    // Is the asset already added?
+    if (pAssetBase->mpAssetDefinition->mAssetId != StringTable->EmptyString())
+    {
+        // Yes, so warn.
+        Con::warnf( "Cannot add private asset '%d' as it has already been assigned.", pAssetBase->mpAssetDefinition->mAssetId );
+        return StringTable->EmptyString();
+    }
+
+    static U32 masterPrivateAssetId = 1;
+
+    // Create asset definition.
+    AssetDefinition* pAssetDefinition = new AssetDefinition();
+
+    // Fetch source asset definition.
+    AssetDefinition* pSourceAssetDefinition = pAssetBase->mpAssetDefinition;
+
+    // Configure asset.
+    pAssetDefinition->mpAssetBase = pAssetBase;
+    pAssetDefinition->mAssetDescription = pSourceAssetDefinition->mAssetDescription;
+    pAssetDefinition->mAssetCategory = pSourceAssetDefinition->mAssetCategory;
+    pAssetDefinition->mAssetAutoUnload = true;
+    pAssetDefinition->mAssetRefreshEnable = false;
+    pAssetDefinition->mAssetType = StringTable->insert( pAssetBase->getClassName() );
+    pAssetDefinition->mAssetLoadedCount = 0;
+    pAssetDefinition->mAssetInternal = false;
+    pAssetDefinition->mAssetPrivate = true;
+
+    // Format asset name.
+    char assetNameBuffer[256];
+    dSprintf(assetNameBuffer, sizeof(assetNameBuffer), "%s_%d", pAssetDefinition->mAssetType, masterPrivateAssetId++ );    
+
+    // Set asset identity.
+    pAssetDefinition->mAssetName = StringTable->insert( assetNameBuffer );
+    pAssetDefinition->mAssetId = pAssetDefinition->mAssetName;
+
+    // Ensure that the source asset is fully synchronized with the new asset definition.
+    pSourceAssetDefinition->mAssetName = pAssetDefinition->mAssetName;
+    pSourceAssetDefinition->mAssetAutoUnload = pAssetDefinition->mAssetAutoUnload;
+    pSourceAssetDefinition->mAssetInternal = pAssetDefinition->mAssetInternal;
+
+    // Set ownership by asset manager.
+    pAssetDefinition->mpAssetBase->setOwned( this, pAssetDefinition );
+
+    // Store in declared assets.
+    mDeclaredAssets.insert( pAssetDefinition->mAssetId, pAssetDefinition );
+
+    // Increase the private loaded asset count.
+    if ( ++mLoadedPrivateAssetsCount > mMaxLoadedPrivateAssetsCount )
+        mMaxLoadedPrivateAssetsCount = mLoadedPrivateAssetsCount;
+
+    return pAssetDefinition->mAssetId;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemoveDeclaredAssets);
+
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot remove declared assets using a NULL module definition" );
+
+    // Fetch module assets.
+    ModuleDefinition::typeModuleAssetsVector& moduleAssets = pModuleDefinition->getModuleAssets();
+
+    // Remove all module assets.
+    while ( moduleAssets.size() > 0 )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = *moduleAssets.begin();
+
+        // Remove this asset.
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
+    }
+
+    // Info.
+    if ( mEchoInfo )
+        Con::printSeparator();
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::removeDeclaredAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemoveSingleDeclaredAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot remove single declared asset using NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Find declared asset.
+    typeDeclaredAssetsHash::iterator declaredAssetItr = mDeclaredAssets.find( assetId );
+
+    // Did we find the declared asset?
+    if ( declaredAssetItr == mDeclaredAssets.end() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot remove single asset Id '%s' it could not be found.", assetId );
+        return false;
+    }
+
+    // Fetch asset definition.
+    AssetDefinition* pAssetDefinition = declaredAssetItr->value;
+
+    // Is the asset private?
+    if ( !pAssetDefinition->mAssetPrivate )
+    {
+        // No, so fetch module assets.
+        ModuleDefinition::typeModuleAssetsVector& moduleAssets = pAssetDefinition->mpModuleDefinition->getModuleAssets();
+
+        // Remove module asset.
+        for ( ModuleDefinition::typeModuleAssetsVector::iterator moduleAssetItr = moduleAssets.begin(); moduleAssetItr != moduleAssets.end(); ++moduleAssetItr )
+        {
+            if ( *moduleAssetItr == pAssetDefinition )
+            {
+                moduleAssets.erase( moduleAssetItr );
+                break;
+            }
+        }
+
+        // Remove asset dependencies.
+        removeAssetDependencies( pAssetId );
+    }
+
+    // Do we have an asset loaded?
+    if ( pAssetDefinition->mpAssetBase != NULL )
+    {
+        // Yes, so delete it.
+        // NOTE: If anything is using this then this'll cause a crash.  Objects should always use safe reference methods however.
+        pAssetDefinition->mpAssetBase->deleteObject();
+    }
+
+    // Remove from declared assets.
+    mDeclaredAssets.erase( declaredAssetItr );
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: Removing Asset Id '%s' of type '%s' in asset file '%s'.",
+            pAssetDefinition->mAssetId,
+            pAssetDefinition->mAssetType,
+            pAssetDefinition->mAssetBaseFilePath );
+    }
+
+    // Destroy asset definition.
+    delete pAssetDefinition;
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetName( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetName;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetDescription( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetDescription;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetCategory( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetCategory;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetType( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mAssetType;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetFilePath( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return StringTable->EmptyString();
+    }
+
+    return pAssetDefinition->mAssetBaseFilePath;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetManager::getAssetPath( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_GetAssetPath);
+
+    // Fetch asset file-path.
+    StringTableEntry assetFilePath = getAssetFilePath( pAssetId );
+
+    // Finish if no file-path.
+    if ( assetFilePath == StringTable->EmptyString()  )
+        return assetFilePath;
+
+    // Find the final slash which should be just before the file.
+    const char* pFinalSlash = dStrrchr( assetFilePath, '/' );
+
+    // Sanity!
+    AssertFatal( pFinalSlash != NULL, "Should always be able to find final slash in the asset file-path." );
+
+    // Fetch asset path.
+    return StringTable->insertn( assetFilePath, (U32)(pFinalSlash - assetFilePath) );
+}
+
+//-----------------------------------------------------------------------------
+
+ModuleDefinition* AssetManager::getAssetModuleDefinition( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return NULL;
+    }
+
+    return pAssetDefinition->mpModuleDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetInternal( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mAssetInternal;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetPrivate( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mAssetPrivate;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetAutoUnload( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mAssetAutoUnload;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetLoaded( const char* pAssetId )
+{
+    // Find asset definition.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find asset Id '%s'.", pAssetId );
+        return false;
+    }
+
+    return pAssetDefinition->mpAssetBase != NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isDeclaredAsset( const char* pAssetId )
+{
+    return findAsset( pAssetId ) != NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::doesAssetDependOn( const char* pAssetId, const char* pDependsOnAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_DoesAssetDependOn);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+    AssertFatal( pDependsOnAssetId != NULL, "Cannot use NULL depends-on asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Fetch depends-on asset Id.
+    StringTableEntry dependsOnAssetId = StringTable->insert( pDependsOnAssetId );
+
+    // Find depends-on entry.
+    typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find( assetId );
+
+    // Iterate all dependencies.
+    while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == assetId )
+    {
+        // Finish if a depends on.
+        if ( dependsOnItr->value == dependsOnAssetId )
+            return true;
+
+        // Next dependency.
+        dependsOnItr++;
+    }
+
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isAssetDependedOn( const char* pAssetId, const char* pDependedOnByAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_IsAssetDependedOn);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+    AssertFatal( pDependedOnByAssetId != NULL, "Cannot use NULL depended-on-by asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Fetch depended-on-by asset Id.
+    StringTableEntry dependedOnByAssetId = StringTable->insert( pDependedOnByAssetId );
+
+    // Find depended-on-by entry.
+    typeAssetDependsOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find(assetId);
+
+    // Iterate all dependencies.
+    while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
+    {
+        // Finish if depended-on.
+        if ( dependedOnItr->value == dependedOnByAssetId )
+            return true;
+
+        // Next dependency.
+        dependedOnItr++;
+    }
+
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::isReferencedAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_IsReferencedAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot check if NULL asset Id is referenced." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Is asset Id the correct format?
+    if ( StringUnit::getUnitCount( assetId, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot check if asset Id '%s' is referenced as it is not the correct format.", assetId );
+        return false;
+    }
+
+    return mReferencedAssets.count( assetId ) > 0;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameDeclaredAsset);
+
+    // Sanity!
+    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
+    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
+
+    // Fetch asset Ids.
+    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
+    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
+
+    // Is asset Id from the correct format?
+    if ( StringUnit::getUnitCount( assetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as source asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Is asset Id to the correct format?
+    if ( StringUnit::getUnitCount( assetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as target asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Does the asset Id from exist?
+    if ( !mDeclaredAssets.contains( assetIdFrom ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as source asset Id is not declared.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Does the asset Id to exist?
+    if ( mDeclaredAssets.contains( assetIdTo ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as target asset Id is already declared.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Split module Ids from asset Ids.
+    StringTableEntry moduleIdFrom = StringTable->insert( StringUnit::getUnit( assetIdFrom, 0, ASSET_SCOPE_TOKEN ) );
+    StringTableEntry moduleIdTo   = StringTable->insert( StringUnit::getUnit( assetIdTo, 0, ASSET_SCOPE_TOKEN ) );
+
+    // Are the module Ids the same?
+    if ( moduleIdFrom != moduleIdTo )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the module Id cannot be changed.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Find asset definition.
+    typeDeclaredAssetsHash::iterator assetDefinitionItr =  mDeclaredAssets.find( assetIdFrom );
+
+    // Sanity!
+    AssertFatal( assetDefinitionItr != mDeclaredAssets.end(), "Asset Manager: Failed to find asset." );
+
+    // Fetch asset definition.
+    AssetDefinition* pAssetDefinition = assetDefinitionItr->value;
+
+    // Is this a private asset?
+    if ( pAssetDefinition->mAssetPrivate )
+    {
+        // Yes, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the source asset is private.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Setup declared update visitor.
+    TamlAssetDeclaredUpdateVisitor assetDeclaredUpdateVisitor;
+    assetDeclaredUpdateVisitor.setAssetIdFrom( assetIdFrom );
+    assetDeclaredUpdateVisitor.setAssetIdTo( assetIdTo );
+
+    // Update asset file declaration.
+    if ( !mTaml.parse( pAssetDefinition->mAssetBaseFilePath, assetDeclaredUpdateVisitor ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename declared asset Id '%s' to asset Id '%s' as the declared asset file could not be parsed: %s",
+            assetIdFrom, assetIdTo, pAssetDefinition->mAssetBaseFilePath );
+        return false;
+    }
+
+    // Update asset definition.
+    pAssetDefinition->mAssetId = assetIdTo;
+    pAssetDefinition->mAssetName = StringTable->insert( StringUnit::getUnit( assetIdTo, 1, ASSET_SCOPE_TOKEN ) );
+
+    // Reinsert declared asset.
+    mDeclaredAssets.erase( assetIdFrom );
+    mDeclaredAssets.insert( assetIdTo, pAssetDefinition );
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: Renaming declared Asset Id '%s' to Asset Id '%s'.", assetIdFrom, assetIdTo );
+        Con::printSeparator();
+    }
+
+    // Rename asset dependencies.
+    renameAssetDependencies( assetIdFrom, assetIdTo );
+
+    // Do we have an asset tags manifest?
+    if ( !mAssetTagsManifest.isNull() )
+    {
+        // Yes, so rename any assets.
+        mAssetTagsManifest->renameAssetId( pAssetIdFrom, pAssetIdTo );
+
+        // Save the asset tags.
+        saveAssetTags();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameReferencedAsset);
+
+    // Sanity!
+    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
+    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
+
+    // Fetch asset Ids.
+    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
+    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
+
+    // Is asset Id from the correct format?
+    if ( StringUnit::getUnitCount( assetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as source asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Is asset Id to the correct format?
+    if ( StringUnit::getUnitCount( assetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as target asset Id is not the correct format.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Does the asset Id to exist?
+    if ( !mDeclaredAssets.contains( assetIdTo ) )
+    {
+        // No, so warn.
+        Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as target asset Id is not declared.", assetIdFrom, assetIdTo );
+        return false;
+    }
+
+    // Rename asset references.
+    renameAssetReferences( assetIdFrom, assetIdTo );
+
+    // Info.
+    if ( mEchoInfo )
+        Con::printSeparator();
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::releaseAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_ReleaseAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot release NULL asset Id." );
+
+    // Find asset.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to release asset Id '%s' as it does not exist.", pAssetId );
+        return false;
+    }
+
+    // Is the asset loaded?
+    if ( pAssetDefinition->mpAssetBase == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to release asset Id '%s' as it is not acquired.", pAssetId );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started releasing Asset Id '%s'...", pAssetId );
+    }
+
+    // Release asset reference.
+    if ( pAssetDefinition->mpAssetBase->releaseAssetReference() )
+    {
+        // Are we ignoring auto-unloaded assets?
+        if ( mIgnoreAutoUnload )
+        {
+            // Yes, so info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Releasing to idle state." );
+            }
+        }
+        else
+        {
+            // No, so info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Unload the asset from memory." );
+            }
+
+            // Unload the asset.
+            unloadAsset( pAssetDefinition );
+        }
+    }
+    // Info.
+    else if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: > Reference count now '%d'.", pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() );
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: > Finished releasing Asset Id '%s'.", pAssetId );
+        Con::printSeparator();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::purgeAssets( void )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_PurgeAssets);
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: Started purging assets..." );
+    }
+
+    // Iterate asset definitions.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = assetItr->value;
+
+        // Skip asset if private, not loaded or referenced.
+        if (    pAssetDefinition->mAssetPrivate ||
+                pAssetDefinition->mpAssetBase == NULL ||
+                pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() > 0 )
+            continue;
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: Purging asset Id '%s'...", pAssetDefinition->mAssetId );
+        }
+
+        // Unload the asset.
+        unloadAsset( pAssetDefinition );
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: ... Finished purging assets." );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_DeleteAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot delete NULL asset Id." );
+
+    // Find asset.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to delete asset Id '%s' as it does not exist.", pAssetId );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started deleting Asset Id '%s'...", pAssetId );
+    }  
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Are we deleting dependencies?
+    if ( deleteDependencies )
+    {
+        Vector<typeAssetId> dependantAssets;
+
+        // Yes, so find depended-on-by entry.
+        typeAssetDependsOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find( assetId );
+
+        // Iterate all dependencies.
+        while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
+        {
+            // Store asset Id.
+            dependantAssets.push_back( dependedOnItr->value );
+
+            // Next dependency.
+            dependedOnItr++;
+        }
+
+        // Do we have any dependants?
+        if ( dependantAssets.size() > 0 )
+        {
+            // Yes, so iterate dependants.
+            for( Vector<typeAssetId>::const_iterator assetItr = dependantAssets.begin(); assetItr !=  dependantAssets.end(); ++assetItr )
+            {
+                StringTableEntry dependentAssetId = *assetItr;
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printSeparator();
+                    Con::printf( "Asset Manager: Deleting Asset Id '%s' dependant of '%s.'", pAssetId, dependentAssetId );
+                }
+
+                // Delete dependant.
+                deleteAsset( dependentAssetId, deleteLooseFiles, deleteDependencies );
+            }
+        }
+    }
+
+    // Remove asset references.
+    removeAssetReferences( assetId );
+
+    // Are we deleting loose files?
+    if ( deleteLooseFiles )
+    {
+        // Yes, so remove loose files.
+        Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
+        for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
+        {
+            // Fetch loose file.
+            StringTableEntry looseFile = *looseFileItr;
+
+            // Delete the loose file.
+            if ( !dFileDelete( looseFile ) )
+            {
+                // Failed so warn.
+                Con::warnf( "Asset Manager: Failed to delete the loose file '%s' while deleting asset Id '%s'.", looseFile, pAssetId );
+            }
+        }
+    }
+
+    // Fetch asset definition file.
+    StringTableEntry assetDefinitionFile = pAssetDefinition->mAssetBaseFilePath;
+
+    // Remove reference here as we're about to remove the declared asset.
+    pAssetDefinition = NULL;
+
+    // Remove asset.
+    removeDeclaredAsset( pAssetId );
+
+    // Delete the asset definition file.
+    if ( !dFileDelete( assetDefinitionFile ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to delete the asset definition file '%s' while deleting asset Id '%s'.", assetDefinitionFile, pAssetId );
+    }       
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Finished deleting Asset Id '%s'.", pAssetId );
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::refreshAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RefreshAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot refresh NULL asset Id." );
+
+    // Find asset.
+    AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+    // Did we find the asset?
+    if ( pAssetDefinition == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to refresh asset Id '%s' as it does not exist.", pAssetId );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started refreshing Asset Id '%s'...", pAssetId );
+    }    
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Is the asset private?
+    if ( pAssetDefinition->mAssetPrivate )
+    {
+        // Yes, so notify asset of asset refresh only.
+        pAssetDefinition->mpAssetBase->onAssetRefresh();
+
+        // Asset refresh notifications.
+        for( typeAssetPtrRefreshHash::iterator refreshNotifyItr = mAssetPtrRefreshNotifications.begin(); refreshNotifyItr != mAssetPtrRefreshNotifications.end(); ++refreshNotifyItr )
+        {
+            // Fetch pointed asset.
+            StringTableEntry pointedAsset = refreshNotifyItr->key->getAssetId();
+
+            // Ignore if the pointed asset is not the asset or a dependency.
+            if ( pointedAsset == StringTable->EmptyString() || ( pointedAsset != assetId && !doesAssetDependOn( pointedAsset, assetId ) ) )
+                continue;
+
+            // Perform refresh notification callback.
+            refreshNotifyItr->value->onAssetRefreshed( refreshNotifyItr->key );
+        }
+    }
+    // Is the asset definition allowed to refresh?
+    else if ( pAssetDefinition->mAssetRefreshEnable )
+    {
+        // Yes, so fetch the asset.
+        AssetBase* pAssetBase = pAssetDefinition->mpAssetBase;
+
+        // Is the asset loaded?
+        if ( pAssetBase != NULL )
+        {
+            // Yes, so notify asset of asset refresh.
+            pAssetBase->onAssetRefresh();
+
+            // Save asset.
+            mTaml.write( pAssetBase, pAssetDefinition->mAssetBaseFilePath );
+        
+            // Remove asset dependencies.
+            removeAssetDependencies( pAssetId );
+
+            // Find any new dependencies.
+            TamlAssetDeclaredVisitor assetDeclaredVisitor;
+
+            // Parse the filename.
+            if ( !mTaml.parse( pAssetDefinition->mAssetBaseFilePath, assetDeclaredVisitor ) )
+            {
+                // Warn.
+                Con::warnf( "Asset Manager: Failed to parse file containing asset declaration: '%s'.\nDependencies are now incorrect!", pAssetDefinition->mAssetBaseFilePath );
+                return false;
+            }
+
+            // Fetch asset dependencies.
+            TamlAssetDeclaredVisitor::typeAssetIdVector& assetDependencies = assetDeclaredVisitor.getAssetDependencies();
+
+            // Are there any asset dependences?
+            if ( assetDependencies.size() > 0 )
+            {
+                // Yes, so iterate dependencies.
+                for( TamlAssetDeclaredVisitor::typeAssetIdVector::iterator assetDependencyItr = assetDependencies.begin(); assetDependencyItr != assetDependencies.end(); ++assetDependencyItr )
+                {
+                    // Fetch dependency asset Id.
+                    StringTableEntry dependencyAssetId = *assetDependencyItr;
+
+                    // Insert depends-on.
+                    mAssetDependsOn.insertEqual( assetId, dependencyAssetId );
+
+                    // Insert is-depended-on.
+                    mAssetIsDependedOn.insertEqual( dependencyAssetId, assetId );
+                }
+            }
+
+            // Fetch asset loose files.
+            TamlAssetDeclaredVisitor::typeLooseFileVector& assetLooseFiles = assetDeclaredVisitor.getAssetLooseFiles();
+
+            // Clear any existing loose files.
+            pAssetDefinition->mAssetLooseFiles.clear();
+
+            // Are there any loose files?
+            if ( assetLooseFiles.size() > 0 )
+            {
+                // Yes, so iterate loose files.
+                for( TamlAssetDeclaredVisitor::typeLooseFileVector::iterator assetLooseFileItr = assetLooseFiles.begin(); assetLooseFileItr != assetLooseFiles.end(); ++assetLooseFileItr )
+                {
+                    // Store loose file.
+                    pAssetDefinition->mAssetLooseFiles.push_back( *assetLooseFileItr );
+                }
+            }
+
+            // Asset refresh notifications.
+            for( typeAssetPtrRefreshHash::iterator refreshNotifyItr = mAssetPtrRefreshNotifications.begin(); refreshNotifyItr != mAssetPtrRefreshNotifications.end(); ++refreshNotifyItr )
+            {
+                // Fetch pointed asset.
+                StringTableEntry pointedAsset = refreshNotifyItr->key->getAssetId();
+
+                // Ignore if the pointed asset is not the asset or a dependency.
+                if ( pointedAsset == StringTable->EmptyString() || ( pointedAsset != assetId && !doesAssetDependOn( pointedAsset, assetId ) ) )
+                    continue;
+
+                // Perform refresh notification callback.
+                refreshNotifyItr->value->onAssetRefreshed( refreshNotifyItr->key );
+            }
+
+            // Find is-depends-on entry.
+            typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find( assetId );
+
+            // Is asset depended on?
+            if ( isDependedOnItr != mAssetIsDependedOn.end() )
+            {
+                // Yes, so compiled them.
+                Vector<typeAssetId> dependedOn;
+
+                // Iterate all dependencies.
+                while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == assetId )
+                {
+                    dependedOn.push_back( isDependedOnItr->value );
+
+                    // Next dependency.
+                    isDependedOnItr++;
+                }
+
+                // Refresh depended-on assets.
+                for ( Vector<typeAssetId>::iterator isDependedOnItr = dependedOn.begin(); isDependedOnItr != dependedOn.end(); ++isDependedOnItr )
+                {
+                    // Refresh dependency asset.
+                    refreshAsset( *isDependedOnItr );
+                }
+            }
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Finished refreshing Asset Id '%s'.", pAssetId );
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::refreshAllAssets( const bool includeUnloaded )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RefreshAllAssets);
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Started refreshing ALL assets." );
+    }
+
+    Vector<typeAssetId> assetsToRelease;
+
+    // Are we including unloaded assets?
+    if ( includeUnloaded )
+    {
+        // Yes, so prepare a list of assets to release and load them.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset Id.
+            typeAssetId assetId = assetItr->key;
+
+            // Skip if asset is loaded.
+            if ( assetItr->value->mpAssetBase != NULL )
+                continue;
+
+            // Note asset as needing a release.
+            assetsToRelease.push_back( assetId );
+
+            // Acquire the asset.
+            acquireAsset<AssetBase>( assetId );
+        }
+    }
+
+    // Refresh the current loaded assets.
+    // NOTE: This will result in some assets being refreshed more than once due to asset dependencies.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Skip private assets.
+        if ( assetItr->value->mAssetPrivate )
+            continue;
+
+        // Refresh asset if it's loaded.
+        refreshAsset( assetItr->key );
+    }
+
+    // Are we including unloaded assets?
+    if ( includeUnloaded )
+    {
+        // Yes, so release the assets we loaded.
+        for( Vector<typeAssetId>::iterator assetItr = assetsToRelease.begin(); assetItr != assetsToRelease.end(); ++assetItr )
+        {
+            releaseAsset( *assetItr );
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Finished refreshing ALL assets." );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::registerAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase, AssetPtrCallback* pCallback )
+{
+    // Find an existing notification iterator.
+    typeAssetPtrRefreshHash::iterator notificationItr = mAssetPtrRefreshNotifications.find( pAssetPtrBase );
+
+    // Do we have one?
+    if ( notificationItr != mAssetPtrRefreshNotifications.end() )
+    {
+        // Yes, so update the callback.
+        notificationItr->value = pCallback;
+        return;
+    }
+
+    // No, so add one.
+    mAssetPtrRefreshNotifications.insert( pAssetPtrBase, pCallback );
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::unregisterAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase )
+{
+    mAssetPtrRefreshNotifications.erase( pAssetPtrBase );
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::loadAssetTags( ModuleDefinition* pModuleDefinition )
+{
+    // Sanity!
+    AssertFatal( pModuleDefinition != NULL, "Cannot load asset tags manifest using a NULL module definition" );
+
+    // Expand manifest location.
+    char assetTagsManifestFilePathBuffer[1024];
+    Con::expandPath( assetTagsManifestFilePathBuffer, sizeof(assetTagsManifestFilePathBuffer), pModuleDefinition->getAssetTagsManifest() );
+
+    // Do we already have a manifest?
+    if ( !mAssetTagsManifest.isNull() )
+    {
+        // Yes, so warn.
+        Con::warnf( "Asset Manager: Cannot load asset tags manifest from module '%s' as one is already loaded.", pModuleDefinition->getSignature() );
+        return false;
+    }
+
+    // Is the specified file valid?
+    if ( Platform::isFile( assetTagsManifestFilePathBuffer ) )
+    {
+        // Yes, so read asset tags manifest.
+        mAssetTagsManifest = mTaml.read<AssetTagsManifest>( assetTagsManifestFilePathBuffer );
+
+        // Did we read the manifest?
+        if ( mAssetTagsManifest.isNull() )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: Failed to load asset tags manifest '%s' from module '%s'.", assetTagsManifestFilePathBuffer, pModuleDefinition->getSignature() );
+            return false;
+        }
+
+        // Set asset tags module definition.
+        mAssetTagsModuleDefinition = pModuleDefinition;
+    }
+    else
+    {
+        // No, so generate a new asset tags manifest.
+        mAssetTagsManifest = new AssetTagsManifest();
+        mAssetTagsManifest->registerObject();
+
+        // Set asset tags module definition.
+        mAssetTagsModuleDefinition = pModuleDefinition;
+
+        // Save the asset tags.
+        saveAssetTags();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::saveAssetTags( void )
+{
+    // Do we have an asset tags manifest?
+    if ( mAssetTagsManifest.isNull() || mAssetTagsModuleDefinition.isNull() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Failed to save asset tags manifest as one is not loaded." );
+        return false;
+    }
+
+    // Expand manifest location.
+    char assetTagsManifestFilePathBuffer[1024];
+    Con::expandPath( assetTagsManifestFilePathBuffer, sizeof(assetTagsManifestFilePathBuffer), mAssetTagsModuleDefinition->getAssetTagsManifest() );
+
+    // Save asset tags manifest.
+    if ( !mTaml.write( mAssetTagsManifest, assetTagsManifestFilePathBuffer ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to save asset tags manifest '%s' from module '%s'.", assetTagsManifestFilePathBuffer, mAssetTagsModuleDefinition->getSignature() );
+        return false;
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::restoreAssetTags( void )
+{
+    // Do we already have a manifest?
+    if ( mAssetTagsManifest.isNull() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot restore asset tags manifest as one is not already loaded." );
+        return false;
+    }
+
+    // Sanity!
+    AssertFatal( mAssetTagsModuleDefinition != NULL, "Cannot restore asset tags manifest as module definition is NULL." );
+
+    // Delete existing asset tags manifest.
+    mAssetTagsManifest->deleteObject();
+
+    // Reload asset tags manifest.
+    return loadAssetTags( mAssetTagsModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+S32 QSORT_CALLBACK descendingAssetDefinitionLoadCount(const void* a, const void* b)
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_DescendingAssetDefinitionLoadCount);
+
+    // Fetch asset definitions.
+    const AssetDefinition* pAssetDefinitionA  = *(AssetDefinition**)a;
+    const AssetDefinition* pAssetDefinitionB  = *(AssetDefinition**)b;
+
+    // Sort.
+    return pAssetDefinitionB->mAssetLoadedCount - pAssetDefinitionA->mAssetLoadedCount;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::dumpDeclaredAssets( void ) const
+{
+    Vector<const AssetDefinition*> assetDefinitions;
+
+    // Iterate asset definitions.
+    for( typeDeclaredAssetsHash::const_iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        assetDefinitions.push_back( assetItr->value );
+    }
+
+    // Sort asset definitions.
+    dQsort( assetDefinitions.address(), assetDefinitions.size(), sizeof(const AssetDefinition*), descendingAssetDefinitionLoadCount );
+
+    // Info.
+    Con::printSeparator();
+    Con::printf( "Asset Manager: %d declared asset(s) dump as follows:", mDeclaredAssets.size() );
+    Con::printBlankLine();
+
+    // Iterate sorted asset definitions.
+    for ( Vector<const AssetDefinition*>::iterator assetItr = assetDefinitions.begin(); assetItr != assetDefinitions.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        const AssetDefinition* pAssetDefinition = *assetItr;
+
+        // Info.
+        Con::printf( "AssetId:'%s', RefCount:%d, LoadCount:%d, UnloadCount:%d, AutoUnload:%d, Loaded:%d, Internal:%d, Private: %d, Type:'%s', Module/Version:'%s'/'%d', File:'%s'",
+            pAssetDefinition->mAssetId,
+            pAssetDefinition->mpAssetBase == NULL ? 0 : pAssetDefinition->mpAssetBase->getAcquiredReferenceCount(),
+            pAssetDefinition->mAssetLoadedCount,
+            pAssetDefinition->mAssetUnloadedCount,
+            pAssetDefinition->mAssetAutoUnload,
+            pAssetDefinition->mpAssetBase != NULL,
+            pAssetDefinition->mAssetInternal,
+            pAssetDefinition->mAssetPrivate,
+            pAssetDefinition->mAssetType,
+            pAssetDefinition->mpModuleDefinition->getModuleId(),
+            pAssetDefinition->mpModuleDefinition->getVersionId(),
+            pAssetDefinition->mAssetBaseFilePath );
+    }
+
+    // Info.
+    Con::printSeparator();
+    Con::printBlankLine();
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAllAssets( AssetQuery* pAssetQuery, const bool ignoreInternal, const bool ignorePrivate )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAllAssets);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Iterate declared assets.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = assetItr->value;
+
+        // Skip if internal and we're ignoring them.
+        if ( ignoreInternal && pAssetDefinition->mAssetInternal )
+            continue;
+
+        // Skip if private and we're ignoring them.
+        if ( ignorePrivate && pAssetDefinition->mAssetPrivate )
+            continue;
+
+        // Store as result.
+        pAssetQuery->mAssetList.push_back( pAssetDefinition->mAssetId );
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetName( AssetQuery* pAssetQuery, const char* pAssetName, const bool partialName )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetName);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetName != NULL, "Cannot use NULL asset name." );
+
+    // Reset asset name.
+    StringTableEntry assetName = NULL;
+    S32 partialAssetNameLength = 0;
+        
+    // Are we doing partial name search?
+    if ( partialName ) 
+    {
+        // Yes, so fetch length of partial name.
+        partialAssetNameLength = dStrlen( pAssetName );
+    }
+    else
+    {
+        // No, so fetch asset name.
+        assetName = StringTable->insert( pAssetName );
+    }
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Iterate declared assets.
+    for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+    {
+        // Fetch asset definition.
+        AssetDefinition* pAssetDefinition = assetItr->value;
+
+        // Are we doing partial name search?
+        if ( partialName ) 
+        {
+            // Yes, so fetch the length of this asset name.
+            const S32 currentAssetNameLength = dStrlen( pAssetDefinition->mAssetName );
+
+            // Skip if the query asset name is longer than the current asset name.
+            if ( partialAssetNameLength > currentAssetNameLength )
+                continue;
+            
+            // Skip if this is not the asset we want.
+            if ( dStrnicmp( pAssetDefinition->mAssetName, pAssetName, partialAssetNameLength ) != 0 )
+                continue;
+        }
+        else
+        {
+            // No, so skip if this is not the asset we want.
+            if ( assetName != pAssetDefinition->mAssetName )
+                continue;
+        }
+
+        // Store as result.
+        pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+    
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetCategory( AssetQuery* pAssetQuery, const char* pAssetCategory, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetCategory);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetCategory != NULL, "Cannot use NULL asset category." );
+
+    // Fetch asset category.
+    StringTableEntry assetCategory = StringTable->insert( pAssetCategory );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetCategory != assetCategory )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetCategory != pAssetDefinition->mAssetCategory )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+S32 AssetManager::findAssetAutoUnload( AssetQuery* pAssetQuery, const bool assetAutoUnload, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetAutoUnload);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetAutoUnload != assetAutoUnload )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetAutoUnload != pAssetDefinition->mAssetAutoUnload )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetInternal( AssetQuery* pAssetQuery, const bool assetInternal, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetInternal);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetInternal != assetInternal )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetInternal != pAssetDefinition->mAssetInternal )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetPrivate( AssetQuery* pAssetQuery, const bool assetPrivate, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetPrivate);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetPrivate != assetPrivate )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetPrivate != pAssetDefinition->mAssetPrivate )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetType( AssetQuery* pAssetQuery, const char* pAssetType, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetType);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetType != NULL, "Cannot use NULL asset type." );
+
+    // Fetch asset type.
+    StringTableEntry assetType = StringTable->insert( pAssetType );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Skip if this is not the asset we want.
+            if (    pAssetDefinition == NULL ||
+                    pAssetDefinition->mAssetType != assetType )
+                        continue;
+
+            // Store as result.
+            filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Skip if this is not the asset we want.
+            if ( assetType != pAssetDefinition->mAssetType )
+                continue;
+
+            // Store as result.
+            pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+            // Increase result count.
+            resultCount++;
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetDependsOn( AssetQuery* pAssetQuery, const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetDependsOn);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Find depends-on entry.
+    typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find( assetId );
+
+    // Iterate all dependencies.
+    while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == assetId )
+    {
+        // Store as result.
+       pAssetQuery->mAssetList.push_back(dependsOnItr->value);
+
+        // Next dependency.
+        dependsOnItr++;
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetIsDependedOn( AssetQuery* pAssetQuery, const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetIsDependedOn);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetId != NULL, "Cannot use NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Find depended-on entry.
+    typeAssetIsDependedOnHash::Iterator dependedOnItr = mAssetIsDependedOn.find( assetId );
+
+    // Iterate all dependencies.
+    while( dependedOnItr != mAssetIsDependedOn.end() && dependedOnItr->key == assetId )
+    {
+        // Store as result.
+       pAssetQuery->mAssetList.push_back(dependedOnItr->value);
+
+        // Next dependency.
+        dependedOnItr++;
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findInvalidAssetReferences( AssetQuery* pAssetQuery )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindInvalidAssetReferences);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Iterate referenced assets.
+    for( typeReferencedAssetsHash::Iterator assetItr = mReferencedAssets.begin(); assetItr != mReferencedAssets.end(); ++assetItr )
+    {
+        // Find asset definition.
+        AssetDefinition* pAssetDefinition = findAsset( assetItr->key );
+
+        // Skip if the asset definition was found.
+        if ( pAssetDefinition != NULL )
+            continue;
+
+        // Store as result.
+        pAssetQuery->mAssetList.push_back(assetItr->key);
+
+        // Increase result count.
+        resultCount++;
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findTaggedAssets( AssetQuery* pAssetQuery, const char* pAssetTagNames, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindTaggedAssets);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pAssetTagNames != NULL, "Cannot use NULL asset tag name(s)." );
+
+    // Do we have an asset tag manifest?
+    if ( mAssetTagsManifest.isNull() )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Cannot find tagged assets as no asset tag manifest is present." );
+        return 0;
+    }
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    const char* pTagSeparators = " ,\t\n";
+
+    // Fetch tag count.
+    U32 assetTagCount = StringUnit::getUnitCount( pAssetTagNames, pTagSeparators );
+
+    // Fetch asset tags.
+    Vector<AssetTagsManifest::AssetTag*> assetTags;
+    for( U32 tagIndex = 0; tagIndex < assetTagCount; ++tagIndex )
+    {
+        // Fetch asset tag name.
+        const char* pTagName = StringUnit::getUnit( pAssetTagNames, tagIndex, pTagSeparators );
+
+        // Fetch asset tag.
+        AssetTagsManifest::AssetTag* pAssetTag = mAssetTagsManifest->findAssetTag( pTagName );
+
+        // Did we find the asset tag?
+        if ( pAssetTag == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest: Asset Manager: Cannot find tagged assets of '%s' as it does not exist.  Ignoring tag.", pTagName );
+            continue;
+        }
+
+        assetTags.push_back( pAssetTag );
+    }
+
+    // Fetch found asset tag count.
+    assetTagCount = assetTags.size();
+
+    // Did we find any tags?
+    if ( assetTagCount == 0 )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest: Asset Manager: No specified tagged assets found in '%s'.", pAssetTagNames );
+        return 0;
+    } 
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset Id.
+            StringTableEntry assetId = *assetItr;
+
+            // Skip if asset is not valid.
+            if ( !isDeclaredAsset( assetId ) )
+                continue;
+
+            // Reset matched flag.
+            bool assetTagMatched = false;
+
+            // Iterate asset tags.
+            for ( Vector<AssetTagsManifest::AssetTag*>::iterator assetTagItr = assetTags.begin(); assetTagItr != assetTags.end(); ++assetTagItr )
+            {
+                // Fetch asset tag.
+                AssetTagsManifest::AssetTag* pAssetTag = *assetTagItr;
+
+                // Skip if asset is not tagged.
+                if ( !pAssetTag->containsAsset( assetId ) )
+                    continue;
+                
+                // Flag as matched.
+                assetTagMatched = true;
+                break;
+            }
+
+            // Did we find a match?
+            if ( assetTagMatched )
+            {
+                // Yes, so is asset already present?
+                if ( !filteredAssets.containsAsset( assetId ) )
+                {
+                    // No, so store as result.
+                   filteredAssets.mAssetList.push_back(assetId);
+
+                    // Increase result count.
+                    resultCount++;
+                }
+            }
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // Iterate asset tags.
+        for ( Vector<AssetTagsManifest::AssetTag*>::iterator assetTagItr = assetTags.begin(); assetTagItr != assetTags.end(); ++assetTagItr )
+        {
+            // Fetch asset tag.
+            AssetTagsManifest::AssetTag* pAssetTag = *assetTagItr;
+
+            // Iterate tagged assets.
+            for ( Vector<typeAssetId>::iterator assetItr = pAssetTag->mAssets.begin(); assetItr != pAssetTag->mAssets.end(); ++assetItr )
+            {
+                // Fetch asset Id.
+                StringTableEntry assetId = *assetItr;
+
+                // Skip if asset Id is already present.
+                if ( pAssetQuery->containsAsset( assetId ) )
+                    continue;
+
+                // Store as result.
+                pAssetQuery->mAssetList.push_back(assetId);
+
+                // Increase result count.
+                resultCount++;
+            }
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+S32 AssetManager::findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLooseFile, const bool assetQueryAsSource )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAssetLooseFile);
+
+    // Sanity!
+    AssertFatal( pAssetQuery != NULL, "Cannot use NULL asset query." );
+    AssertFatal( pLooseFile != NULL, "Cannot use NULL loose file." );
+
+    // Expand loose file.
+    char looseFileBuffer[1024];
+    Con::expandPath(looseFileBuffer, sizeof(looseFileBuffer), pLooseFile, NULL, false );
+
+    // Fetch asset loose file.
+    StringTableEntry looseFile = StringTable->insert( looseFileBuffer );
+
+    // Reset result count.
+    S32 resultCount = 0;
+
+    // Use asset-query as the source?
+    if ( assetQueryAsSource )
+    {
+        AssetQuery filteredAssets;
+
+        // Yes, so iterate asset query.
+        for (Vector<StringTableEntry>::iterator assetItr = pAssetQuery->mAssetList.begin(); assetItr != pAssetQuery->mAssetList.end(); ++assetItr)
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = findAsset( *assetItr );
+
+            // Fetch loose files.
+            Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
+
+            // Skip if this asset has no loose files.
+            if ( assetLooseFiles.size() == 0 )
+                continue;
+
+            // Search the assets loose files.
+            for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
+            {
+                // Is this the loose file we are searching for?
+                if ( *looseFileItr != looseFile )
+                    continue;
+
+                // Store as result.
+                filteredAssets.mAssetList.push_back(pAssetDefinition->mAssetId);
+
+                // Increase result count.
+                resultCount++;
+
+                break;
+            }
+        }
+
+        // Set asset query.
+        pAssetQuery->set( filteredAssets );
+    }
+    else
+    {
+        // No, so iterate declared assets.
+        for( typeDeclaredAssetsHash::iterator assetItr = mDeclaredAssets.begin(); assetItr != mDeclaredAssets.end(); ++assetItr )
+        {
+            // Fetch asset definition.
+            AssetDefinition* pAssetDefinition = assetItr->value;
+
+            // Fetch loose files.
+            Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
+
+            // Skip if this asset has no loose files.
+            if ( assetLooseFiles.size() == 0 )
+                continue;
+
+            // Search the assets loose files.
+            for( Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr )
+            {
+                // Is this the loose file we are searching for?
+                if ( *looseFileItr != looseFile )
+                    continue;
+
+                // Store as result.
+                pAssetQuery->mAssetList.push_back(pAssetDefinition->mAssetId);
+
+                // Increase result count.
+                resultCount++;
+
+                break;
+            }
+        }
+    }
+
+    return resultCount;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::scanDeclaredAssets( const char* pPath, const char* pExtension, const bool recurse, ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_ScanDeclaredAssets);
+
+    // Sanity!
+    AssertFatal( pPath != NULL, "Cannot scan declared assets with NULL path." );
+    AssertFatal( pExtension != NULL, "Cannot scan declared assets with NULL extension." );
+
+    // Expand path location.
+    char pathBuffer[1024];
+    Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath );
+
+    // Find files.
+    Vector<Platform::FileInfo> files;
+    if ( !Platform::dumpPath( pathBuffer, files, recurse ? -1 : 0 ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to scan declared assets in directory '%s'.", pathBuffer );
+        return false;
+    }
+
+    // Is the asset file-path located within the specified module?
+    if ( !Con::isBasePath( pathBuffer, pModuleDefinition->getModulePath() ) )
+    {
+        // No, so warn.
+        Con::warnf( "Asset Manager: Could not add declared asset file '%s' as file does not exist with module path '%s'",
+            pathBuffer,
+            pModuleDefinition->getModulePath() );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Scanning for declared assets in path '%s' for files with extension '%s'...", pathBuffer, pExtension );
+    }
+
+    // Fetch extension length.
+    const U32 extensionLength = dStrlen( pExtension );
+
+    // Fetch module assets.
+    ModuleDefinition::typeModuleAssetsVector& moduleAssets = pModuleDefinition->getModuleAssets();
+
+    TamlAssetDeclaredVisitor assetDeclaredVisitor;
+
+    // Iterate files.
+    for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr )
+    {
+        // Fetch file info.
+        Platform::FileInfo& fileInfo = *fileItr;
+
+        // Fetch filename.
+        const char* pFilename = fileInfo.pFileName;
+
+        // Find filename length.
+        const U32 filenameLength = dStrlen( pFilename );
+
+        // Skip if extension is longer than filename.
+        if ( extensionLength > filenameLength )
+            continue;
+
+        // Skip if extension not found.
+        if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 )
+            continue;
+
+        // Clear declared assets.
+        assetDeclaredVisitor.clear();
+
+        // Format full file-path.
+        char assetFileBuffer[1024];
+        dSprintf( assetFileBuffer, sizeof(assetFileBuffer), "%s/%s", fileInfo.pFullPath, fileInfo.pFileName );
+
+        // Parse the filename.
+        if ( !mTaml.parse( assetFileBuffer, assetDeclaredVisitor ) )
+        {
+            // Warn.
+            Con::warnf( "Asset Manager: Failed to parse file containing asset declaration: '%s'.", assetFileBuffer );
+            continue;
+        }
+
+        // Fetch asset definition.
+        AssetDefinition& foundAssetDefinition = assetDeclaredVisitor.getAssetDefinition();
+
+        // Did we get an asset name?
+        if ( foundAssetDefinition.mAssetName == StringTable->EmptyString() )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: Parsed file '%s' but did not encounter an asset.", assetFileBuffer );
+            continue;
+        }
+
+        // Set module definition.
+        foundAssetDefinition.mpModuleDefinition = pModuleDefinition;
+
+        // Format asset Id.
+        char assetIdBuffer[1024];
+        dSprintf(assetIdBuffer, sizeof(assetIdBuffer), "%s%s%s",
+            pModuleDefinition->getModuleId(),
+            ASSET_SCOPE_TOKEN,
+            foundAssetDefinition.mAssetName );
+
+        // Set asset Id.
+        foundAssetDefinition.mAssetId = StringTable->insert( assetIdBuffer );
+
+        // Does this asset already exist?
+        if ( mDeclaredAssets.contains( foundAssetDefinition.mAssetId ) )
+        {
+            // Yes, so warn.
+            Con::warnf( "Asset Manager: Encountered asset Id '%s' in asset file '%s' but it conflicts with existing asset Id in asset file '%s'.",
+                foundAssetDefinition.mAssetId,
+                foundAssetDefinition.mAssetBaseFilePath,
+                mDeclaredAssets.find( foundAssetDefinition.mAssetId )->value->mAssetBaseFilePath );
+
+            continue;
+        }
+
+        // Create new asset definition.
+        AssetDefinition* pAssetDefinition = new AssetDefinition( foundAssetDefinition );
+
+        // Store in declared assets.
+        mDeclaredAssets.insert( pAssetDefinition->mAssetId, pAssetDefinition );
+
+        // Store in module assets.
+        moduleAssets.push_back( pAssetDefinition );
+        
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printSeparator();
+            Con::printf( "Asset Manager: Adding Asset Id '%s' of type '%s' in asset file '%s'.",
+                pAssetDefinition->mAssetId,
+                pAssetDefinition->mAssetType,
+                pAssetDefinition->mAssetBaseFilePath );
+        }
+
+        // Fetch asset Id.
+        StringTableEntry assetId = pAssetDefinition->mAssetId;
+
+        // Fetch asset dependencies.
+        TamlAssetDeclaredVisitor::typeAssetIdVector& assetDependencies = assetDeclaredVisitor.getAssetDependencies();
+
+        // Are there any asset dependencies?
+        if ( assetDependencies.size() > 0 )
+        {
+            // Yes, so iterate dependencies.
+            for( TamlAssetDeclaredVisitor::typeAssetIdVector::iterator assetDependencyItr = assetDependencies.begin(); assetDependencyItr != assetDependencies.end(); ++assetDependencyItr )
+            {
+                // Fetch asset Ids.
+                StringTableEntry dependencyAssetId = *assetDependencyItr;
+
+                // Insert depends-on.
+                mAssetDependsOn.insertEqual( assetId, dependencyAssetId );
+
+                // Insert is-depended-on.
+                mAssetIsDependedOn.insertEqual( dependencyAssetId, assetId );
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printf( "Asset Manager: Asset Id '%s' has dependency of Asset Id '%s'", assetId, dependencyAssetId );
+                }
+            }
+        }
+
+        // Fetch asset loose files.
+        TamlAssetDeclaredVisitor::typeLooseFileVector& assetLooseFiles = assetDeclaredVisitor.getAssetLooseFiles();
+
+        // Are there any loose files?
+        if ( assetLooseFiles.size() > 0 )
+        {
+            // Yes, so iterate loose files.
+            for( TamlAssetDeclaredVisitor::typeLooseFileVector::iterator assetLooseFileItr = assetLooseFiles.begin(); assetLooseFileItr != assetLooseFiles.end(); ++assetLooseFileItr )
+            {
+                // Fetch loose file.
+                StringTableEntry looseFile = *assetLooseFileItr;
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printf( "Asset Manager: Asset Id '%s' has loose file '%s'.", assetId, looseFile );
+                }
+
+                // Store loose file.
+                pAssetDefinition->mAssetLooseFiles.push_back( looseFile );
+            }
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: ... Finished scanning for declared assets in path '%s' for files with extension '%s'.", pathBuffer, pExtension );
+        Con::printSeparator();
+        Con::printBlankLine();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetManager::scanReferencedAssets( const char* pPath, const char* pExtension, const bool recurse )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_ScanReferencedAssets);
+
+    // Sanity!
+    AssertFatal( pPath != NULL, "Cannot scan referenced assets with NULL path." );
+    AssertFatal( pExtension != NULL, "Cannot scan referenced assets with NULL extension." );
+
+    // Expand path location.
+    char pathBuffer[1024];
+    Con::expandPath( pathBuffer, sizeof(pathBuffer), pPath );
+
+    // Find files.
+    Vector<Platform::FileInfo> files;
+    if ( !Platform::dumpPath( pathBuffer, files, recurse ? -1 : 0 ) )
+    {
+        // Failed so warn.
+        Con::warnf( "Asset Manager: Failed to scan referenced assets in directory '%s'.", pathBuffer );
+        return false;
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printSeparator();
+        Con::printf( "Asset Manager: Scanning for referenced assets in path '%s' for files with extension '%s'...", pathBuffer, pExtension );
+    }
+
+    // Fetch extension length.
+    const U32 extensionLength = dStrlen( pExtension );
+
+    TamlAssetReferencedVisitor assetReferencedVisitor;
+
+    // Iterate files.
+    for ( Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr )
+    {
+        // Fetch file info.
+        Platform::FileInfo& fileInfo = *fileItr;
+
+        // Fetch filename.
+        const char* pFilename = fileInfo.pFileName;
+
+        // Find filename length.
+        const U32 filenameLength = dStrlen( pFilename );
+
+        // Skip if extension is longer than filename.
+        if ( extensionLength > filenameLength )
+            continue;
+
+        // Skip if extension not found.
+        if ( dStricmp( pFilename + filenameLength - extensionLength, pExtension ) != 0 )
+            continue;
+
+        // Clear referenced assets.
+        assetReferencedVisitor.clear();
+
+        // Format full file-path.
+        char assetFileBuffer[1024];
+        dSprintf( assetFileBuffer, sizeof(assetFileBuffer), "%s/%s", fileInfo.pFullPath, fileInfo.pFileName );
+
+        // Format reference file-path.
+        typeReferenceFilePath referenceFilePath = StringTable->insert( assetFileBuffer );
+
+        // Parse the filename.
+        if ( !mTaml.parse( referenceFilePath, assetReferencedVisitor ) )
+        {
+            // Warn.
+            Con::warnf( "Asset Manager: Failed to parse file containing asset references: '%s'.", referenceFilePath );
+            continue;
+        }
+
+        // Fetch usage map.
+        const TamlAssetReferencedVisitor::typeAssetReferencedHash& assetReferencedMap = assetReferencedVisitor.getAssetReferencedMap();
+
+        // Do we have any asset references?
+        if ( assetReferencedMap.size() > 0 )
+        {
+            // Info.
+            if ( mEchoInfo )
+            {
+                Con::printSeparator();
+            }
+
+            // Iterate usage.
+            for( TamlAssetReferencedVisitor::typeAssetReferencedHash::const_iterator usageItr = assetReferencedMap.begin(); usageItr != assetReferencedMap.end(); ++usageItr )
+            {
+                // Fetch asset name.
+                typeAssetId assetId = usageItr->key;
+
+                // Info.
+                if ( mEchoInfo )
+                {
+                    Con::printf( "Asset Manager: Found referenced Asset Id '%s' in file '%s'.", assetId, referenceFilePath );
+                }
+
+                // Add referenced asset.
+                addReferencedAsset( assetId, referenceFilePath );
+            }
+        }
+    }
+
+    // Info.
+    if ( mEchoInfo )
+    {
+        Con::printf( "Asset Manager: ... Finished scanning for referenced assets in path '%s' for files with extension '%s'.", pathBuffer, pExtension );
+        Con::printSeparator();
+        Con::printBlankLine();
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+AssetDefinition* AssetManager::findAsset( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_FindAsset);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot find NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Find declared asset.
+    typeDeclaredAssetsHash::iterator declaredAssetItr = mDeclaredAssets.find( assetId );
+
+    // Find if we didn't find a declared asset Id.
+    if ( declaredAssetItr == mDeclaredAssets.end() )
+        return NULL;
+
+    return declaredAssetItr->value;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::addReferencedAsset( StringTableEntry assetId, StringTableEntry referenceFilePath )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_AddReferencedAsset);
+
+    // Sanity!
+    AssertFatal( assetId != NULL, "Cannot add referenced asset with NULL asset Id." );
+    AssertFatal( referenceFilePath != NULL, "Cannot add referenced asset with NULL reference file-path." );
+
+    // Find referenced asset.
+    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find( assetId );
+
+    // Did we find the asset?
+    if ( referencedAssetItr == mReferencedAssets.end() )
+    {
+        // No, so add asset Id.
+        mReferencedAssets.insertEqual( assetId, referenceFilePath );
+    }
+    else
+    {
+        // Yes, so add asset Id with a unique file.
+        while( true )
+        {
+            // Finish if this file is already present.
+            if ( referencedAssetItr->value == referenceFilePath )
+                return;
+
+            // Move to next asset Id.
+            referencedAssetItr++;
+
+            // Is this the end of referenced assets or a different asset Id?
+            if ( referencedAssetItr == mReferencedAssets.end() ||
+                referencedAssetItr->key != assetId )
+            {
+                // Yes, so add asset reference.
+                mReferencedAssets.insertEqual( assetId, referenceFilePath );
+                return;
+            }
+        };
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::renameAssetReferences( StringTableEntry assetIdFrom, StringTableEntry assetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameAssetReferences);
+
+    // Sanity!
+    AssertFatal( assetIdFrom != NULL, "Cannot rename asset references using NULL asset Id from." );
+    AssertFatal( assetIdTo != NULL, "Cannot rename asset references using NULL asset Id to." );
+
+    // Finish if the asset is not referenced.
+    if ( !mReferencedAssets.count( assetIdFrom ) )
+        return;
+
+    // Setup referenced update visitor.
+    TamlAssetReferencedUpdateVisitor assetReferencedUpdateVisitor;
+    assetReferencedUpdateVisitor.setAssetIdFrom( assetIdFrom );
+    assetReferencedUpdateVisitor.setAssetIdTo( assetIdTo );
+
+    // Find first referenced asset Id.
+    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find( assetIdFrom );
+
+    // Iterate references.
+    while( true )
+    {
+        // Finish if end of references.
+        if ( referencedAssetItr == mReferencedAssets.end() || referencedAssetItr->key != assetIdFrom )
+            return;
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: Renaming declared Asset Id '%s' to Asset Id '%s'.  Updating referenced file '%s'",
+                assetIdFrom,
+                assetIdTo,
+                referencedAssetItr->value );
+        }
+
+        // Update asset file declaration.
+        if ( !mTaml.parse( referencedAssetItr->value, assetReferencedUpdateVisitor ) )
+        {
+            // No, so warn.
+            Con::warnf("Asset Manager: Cannot rename referenced asset Id '%s' to asset Id '%s' as the referenced asset file could not be parsed: %s",
+                assetIdFrom, assetIdTo, referencedAssetItr->value );
+        }
+
+        // Move to next reference.
+        referencedAssetItr++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::removeAssetReferences( StringTableEntry assetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemoveAssetReferences);
+
+    // Sanity!
+    AssertFatal( assetId != NULL, "Cannot rename asset references using NULL asset Id." );
+
+    // Finish if the asset is not referenced.
+    if ( !mReferencedAssets.count( assetId ) )
+        return;
+
+    // Setup referenced update visitor.
+    TamlAssetReferencedUpdateVisitor assetReferencedUpdateVisitor;
+    assetReferencedUpdateVisitor.setAssetIdFrom( assetId );
+    assetReferencedUpdateVisitor.setAssetIdTo( StringTable->EmptyString() );
+
+    // Find first referenced asset Id.
+    typeReferencedAssetsHash::Iterator referencedAssetItr = mReferencedAssets.find(assetId);
+
+    // Iterate references.
+    while( true )
+    {
+        // Finish if end of references.
+        if ( referencedAssetItr == mReferencedAssets.end() || referencedAssetItr->key != assetId )
+            break;
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: Removing Asset Id '%s' references from file '%s'",
+                assetId,
+                referencedAssetItr->value );
+        }
+
+        // Update asset file declaration.
+        if ( !mTaml.parse( referencedAssetItr->value, assetReferencedUpdateVisitor ) )
+        {
+            // No, so warn.
+            Con::warnf("Asset Manager: Cannot remove referenced asset Id '%s' as the referenced asset file could not be parsed: %s",
+                assetId,
+                referencedAssetItr->value );
+        }
+
+        // Move to next reference.
+        referencedAssetItr++;
+    }
+
+    // Remove asset references.
+    mReferencedAssets.erase( assetId );
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::renameAssetDependencies( StringTableEntry assetIdFrom, StringTableEntry assetIdTo )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RenameAssetDependencies);
+
+    // Sanity!
+    AssertFatal( assetIdFrom != NULL, "Cannot rename asset dependencies using NULL asset Id from." );
+    AssertFatal( assetIdTo != NULL, "Cannot rename asset dependencies using NULL asset Id to." );
+
+    // Rename via depends-on...
+    while( mAssetDependsOn.count( assetIdFrom ) > 0 )
+    {
+        // Find depends-on.
+       typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(assetIdFrom);
+
+        // Fetch dependency asset Id.
+        StringTableEntry dependencyAssetId = dependsOnItr->value;
+
+        // Find is-depends-on entry.
+        typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find(dependencyAssetId);
+
+        // Sanity!
+        AssertFatal( isDependedOnItr != mAssetIsDependedOn.end(), "Asset dependencies are corrupt!" );
+
+        while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value != assetIdFrom )
+        {
+            isDependedOnItr++;
+        }
+
+        // Sanity!
+        AssertFatal( isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value == assetIdFrom, "Asset dependencies are corrupt!" );
+        
+        // Remove is-depended-on.        
+        mAssetIsDependedOn.erase( isDependedOnItr );
+
+        // Remove depends-on.
+        mAssetDependsOn.erase( dependsOnItr );
+
+        // Insert depends-on.
+        mAssetDependsOn.insertEqual( assetIdTo, dependencyAssetId );
+
+        // Insert is-depended-on.
+        mAssetIsDependedOn.insertEqual( dependencyAssetId, assetIdTo );
+    }
+
+    // Rename via is-depended-on...
+    while( mAssetIsDependedOn.count( assetIdFrom ) > 0 )
+    {
+        // Find is-depended-on.
+       typeAssetIsDependedOnHash::Iterator isdependedOnItr = mAssetIsDependedOn.find(assetIdFrom);
+
+        // Fetch dependency asset Id.
+        StringTableEntry dependencyAssetId = isdependedOnItr->value;
+
+        // Find depends-on entry.
+        typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(dependencyAssetId);
+
+        // Sanity!
+        AssertFatal( dependsOnItr != mAssetDependsOn.end(), "Asset dependencies are corrupt!" );
+
+        while( dependsOnItr != mAssetDependsOn.end() && dependsOnItr->key == dependencyAssetId && dependsOnItr->value != assetIdFrom )
+        {
+            dependsOnItr++;
+        }
+
+        // Sanity!
+        AssertFatal( dependsOnItr->key == dependencyAssetId && dependsOnItr->value == assetIdFrom, "Asset dependencies are corrupt!" );
+        
+        // Remove is-depended-on.        
+        mAssetIsDependedOn.erase( isdependedOnItr );
+
+        // Remove depends-on.
+        mAssetDependsOn.erase( dependsOnItr );
+
+        // Insert depends-on.
+        mAssetDependsOn.insertEqual( dependencyAssetId, assetIdTo );
+
+        // Insert is-depended-on.
+        mAssetIsDependedOn.insertEqual( assetIdTo, dependencyAssetId );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::removeAssetDependencies( const char* pAssetId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_RemvoeAsetDependencies);
+
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot remove asset dependencies using NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Remove from depends-on assets.
+    while( mAssetDependsOn.count( assetId ) > 0 )
+    {
+        // Find depends-on.
+       typeAssetDependsOnHash::Iterator dependsOnItr = mAssetDependsOn.find(assetId);
+
+        // Fetch dependency asset Id.
+        StringTableEntry dependencyAssetId = dependsOnItr->value;
+
+        // Find is-depends-on entry.
+        typeAssetIsDependedOnHash::Iterator isDependedOnItr = mAssetIsDependedOn.find(dependencyAssetId);
+
+        // Sanity!
+        AssertFatal( isDependedOnItr != mAssetIsDependedOn.end(), "Asset dependencies are corrupt!" );
+
+        while( isDependedOnItr != mAssetIsDependedOn.end() && isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value != assetId )
+        {
+            isDependedOnItr++;
+        }
+
+        // Sanity!
+        AssertFatal( isDependedOnItr->key == dependencyAssetId && isDependedOnItr->value == assetId, "Asset dependencies are corrupt!" );
+
+        // Remove is-depended-on.        
+        mAssetIsDependedOn.erase( isDependedOnItr );
+
+        // Remove depends-on.
+        mAssetDependsOn.erase( dependsOnItr );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::unloadAsset( AssetDefinition* pAssetDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_UnloadAsset);
+
+    // Destroy the asset.
+    pAssetDefinition->mpAssetBase->deleteObject();
+
+    // Increase unloaded count.
+    pAssetDefinition->mAssetUnloadedCount++;
+
+    // Is the asset internal?
+    if ( pAssetDefinition->mAssetInternal )
+    {
+        // Yes, so decrease internal loaded asset count.
+        mLoadedInternalAssetsCount--;
+    }
+    else
+    {
+        // No, so decrease external loaded assets count.
+        mLoadedExternalAssetsCount--;
+    }
+
+    // Is the asset private?
+    if ( pAssetDefinition->mAssetPrivate )
+    {
+        // Yes, so decrease private loaded asset count.
+        mLoadedPrivateAssetsCount--;
+
+        // Remove it completely.
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onModulePreLoad( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_OnModulePreLoad);
+
+    // Add module declared assets.
+    addModuleDeclaredAssets( pModuleDefinition );
+
+    // Is an asset tags manifest specified?
+    if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString() )
+    {
+        // Yes, so load the asset tags manifest.
+        loadAssetTags( pModuleDefinition );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onModulePreUnload( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_OnModulePreUnload);
+
+    // Is an asset tags manifest specified?
+    if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString() )
+    {
+        // Yes, so save the asset tags manifest.
+        saveAssetTags();
+
+        // Do we have an asset tags manifest?
+        if ( !mAssetTagsManifest.isNull() )
+        {
+            // Yes, so remove it.
+            mAssetTagsManifest->deleteObject();
+            mAssetTagsModuleDefinition = NULL;
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetManager::onModulePostUnload( ModuleDefinition* pModuleDefinition )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AssetManager_OnModulePostUnload);
+
+    // Remove declared assets.
+    removeDeclaredAssets( pModuleDefinition );
+}

+ 395 - 0
Engine/source/assets/assetManager.h

@@ -0,0 +1,395 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_MANAGER_H_
+#define _ASSET_MANAGER_H_
+
+#ifndef _SIMBASE_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _TAML_H_
+#include "persistence/taml/taml.h"
+#endif
+
+#ifndef _MODULE_DEFINITION_H
+#include "module/moduleDefinition.h"
+#endif
+
+#ifndef _MODULE_CALLBACKS_H_
+#include "module/moduleCallbacks.h"
+#endif
+
+#ifndef _ASSET_BASE_H_
+#include "assets/assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assets/assetDefinition.h"
+#endif
+
+#ifndef _ASSET_TAGS_MANIFEST_H_
+#include "assets/assetTagsManifest.h"
+#endif
+
+#ifndef _ASSET_QUERY_H_
+#include "assets/assetQuery.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class AssetPtrCallback;
+class AssetPtrBase;
+
+//-----------------------------------------------------------------------------
+
+class AssetManager : public SimObject, public ModuleCallbacks
+{
+private:
+    typedef SimObject Parent;
+    typedef StringTableEntry typeAssetId;
+    typedef StringTableEntry typeAssetName;
+    typedef StringTableEntry typeReferenceFilePath;
+    typedef HashMap<typeAssetId, AssetDefinition*> typeDeclaredAssetsHash;
+    typedef HashTable<typeAssetId, typeReferenceFilePath> typeReferencedAssetsHash;
+    typedef HashTable<typeAssetId, typeAssetId> typeAssetDependsOnHash;
+    typedef HashTable<typeAssetId, typeAssetId> typeAssetIsDependedOnHash;
+    typedef HashMap<AssetPtrBase*, AssetPtrCallback*> typeAssetPtrRefreshHash;
+
+    /// Declared assets.
+    typeDeclaredAssetsHash              mDeclaredAssets;
+
+    /// Referenced assets.
+    typeReferencedAssetsHash            mReferencedAssets;
+
+    /// Asset dependencies.
+    typeAssetDependsOnHash              mAssetDependsOn;
+    typeAssetIsDependedOnHash           mAssetIsDependedOn;
+
+    /// Asset tags.
+    SimObjectPtr<AssetTagsManifest>     mAssetTagsManifest;
+    SimObjectPtr<ModuleDefinition>      mAssetTagsModuleDefinition;
+
+    /// Asset pointer refresh notifications.
+    typeAssetPtrRefreshHash             mAssetPtrRefreshNotifications;
+
+    /// Miscellaneous.
+    bool                                mEchoInfo;
+    bool                                mIgnoreAutoUnload;
+    U32                                 mLoadedInternalAssetsCount;
+    U32                                 mLoadedExternalAssetsCount;
+    U32                                 mLoadedPrivateAssetsCount;
+    U32                                 mAcquiredReferenceCount;
+    U32                                 mMaxLoadedInternalAssetsCount;
+    U32                                 mMaxLoadedExternalAssetsCount;
+    U32                                 mMaxLoadedPrivateAssetsCount;
+    Taml                                mTaml;
+
+public:
+    AssetManager();
+    virtual ~AssetManager() {}
+
+    /// SimObject overrides
+    virtual bool onAdd();
+    virtual void onRemove();
+    static void initPersistFields();
+
+    /// Declared assets.
+    bool addModuleDeclaredAssets( ModuleDefinition* pModuleDefinition );
+    bool addDeclaredAsset( ModuleDefinition* pModuleDefinition, const char* pAssetFilePath );
+    StringTableEntry addPrivateAsset( AssetBase* pAssetBase );
+    bool removeDeclaredAssets( ModuleDefinition* pModuleDefinition );
+    bool removeDeclaredAsset( const char* pAssetId );
+    bool renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
+    StringTableEntry getAssetName( const char* pAssetId );
+    StringTableEntry getAssetDescription( const char* pAssetId );
+    StringTableEntry getAssetCategory( const char* pAssetId );
+    StringTableEntry getAssetType( const char* pAssetId );
+    StringTableEntry getAssetFilePath( const char* pAssetId );
+    StringTableEntry getAssetPath( const char* pAssetId );
+    ModuleDefinition* getAssetModuleDefinition( const char* pAssetId );
+    bool isAssetInternal( const char* pAssetId );
+    bool isAssetPrivate( const char* pAssetId );
+    bool isAssetAutoUnload( const char* pAssetId );
+    bool isAssetLoaded( const char* pAssetId );
+    bool isDeclaredAsset( const char* pAssetId );
+    bool doesAssetDependOn( const char* pAssetId, const char* pDependsOnAssetId );
+    bool isAssetDependedOn( const char* pAssetId, const char* pDependedOnByAssetId );
+
+    /// Referenced assets.
+    bool compileReferencedAssets( ModuleDefinition* pModuleDefinition );
+    bool isReferencedAsset( const char* pAssetId );
+    bool renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
+
+    /// Public asset acquisition.
+    template<typename T> T* acquireAsset( const char* pAssetId )
+    {
+        // Sanity!
+        AssertFatal( pAssetId != NULL, "Cannot acquire NULL asset Id." );
+
+        // Is this an empty asset Id?
+        if ( *pAssetId == 0 )
+        {
+            // Yes, so return nothing.
+            return NULL;
+        }
+
+        // Find asset.
+        AssetDefinition* pAssetDefinition = findAsset( pAssetId );
+
+        // Did we find the asset?
+        if ( pAssetDefinition == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: Failed to acquire asset Id '%s' as it does not exist.", pAssetId );
+            return NULL;
+        }
+
+        // Is asset loading?
+        if ( pAssetDefinition->mAssetLoading == true )
+        {
+            // Yes, so we've got a circular loop which we cannot resolve!
+            Con::warnf( "Asset Manager: Failed to acquire asset Id '%s' as loading it involves a cyclic dependency on itself which cannot be resolved.", pAssetId );
+            return NULL;
+        }
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printSeparator();
+            Con::printf( "Asset Manager: Started acquiring Asset Id '%s'...", pAssetId );
+        }
+
+        // Is the asset already loaded?
+        if ( pAssetDefinition->mpAssetBase == NULL )
+        {
+            // No, so info
+            if ( mEchoInfo )
+            {
+                // Fetch asset Id.
+                StringTableEntry assetId = StringTable->insert( pAssetId );
+
+                // Find any asset dependencies.
+                typeAssetDependsOnHash::Iterator assetDependenciesItr = mAssetDependsOn.find( assetId );
+
+                // Does the asset have any dependencies?
+                if ( assetDependenciesItr != mAssetDependsOn.end() )
+                {
+                    // Yes, so show all dependency assets.
+                    Con::printf( "Asset Manager: > Found dependencies:" );
+
+                    // Iterate all dependencies.
+                    while( assetDependenciesItr != mAssetDependsOn.end() && assetDependenciesItr->key == assetId )
+                    {
+                        // Info.
+                        Con::printf( "Asset Manager: > Asset Id '%s'", assetDependenciesItr->value );
+
+                        // Next dependency.
+                        assetDependenciesItr++;
+                    }
+                }
+            }
+
+            // Flag asset as loading.
+            pAssetDefinition->mAssetLoading = true;
+
+            // Generate primary asset.
+            pAssetDefinition->mpAssetBase = mTaml.read<T>( pAssetDefinition->mAssetBaseFilePath );
+
+            // Flag asset as finished loading.
+            pAssetDefinition->mAssetLoading = false;
+
+            // Did we generate the asset?
+            if ( pAssetDefinition->mpAssetBase == NULL )
+            {
+                // No, so warn.
+                Con::warnf( "Asset Manager: > Failed to acquire asset Id '%s' as loading the asset file failed to return the asset or the correct asset type: '%s'.",
+                    pAssetId, pAssetDefinition->mAssetBaseFilePath );
+                return NULL;
+            }
+
+            // Increase loaded count.
+            pAssetDefinition->mAssetLoadedCount++;
+
+            // Info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Loading asset into memory as object Id '%d' from file '%s'.",
+                    pAssetDefinition->mpAssetBase->getId(), pAssetDefinition->mAssetBaseFilePath );
+            }
+
+            // Set ownership by asset manager.
+            pAssetDefinition->mpAssetBase->setOwned( this, pAssetDefinition );
+
+            // Is the asset internal?
+            if ( pAssetDefinition->mAssetInternal )
+            {
+                // Yes, so increase internal loaded asset count.
+                if ( ++mLoadedInternalAssetsCount > mMaxLoadedInternalAssetsCount )
+                    mMaxLoadedInternalAssetsCount = mLoadedInternalAssetsCount;
+            }
+            else
+            {
+                // No, so increase external loaded assets count.
+                if ( ++mLoadedExternalAssetsCount > mMaxLoadedExternalAssetsCount )
+                    mMaxLoadedExternalAssetsCount = mLoadedExternalAssetsCount;
+            }
+        }
+        else if ( pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() == 0 )
+        {
+            // Info.
+            if ( mEchoInfo )
+            {
+                Con::printf( "Asset Manager: > Acquiring from idle state." );
+            }
+        }
+
+        // Set acquired asset.
+        T* pAcquiredAsset = dynamic_cast<T*>( (AssetBase*)pAssetDefinition->mpAssetBase );
+
+        // Is asset the correct type?
+        if ( pAcquiredAsset == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "Asset Manager: > Failed to acquire asset Id '%s' as it was not the required asset type: '%s'.", pAssetId, pAssetDefinition->mAssetBaseFilePath );
+            return NULL;
+        }
+
+        // Acquire asset reference.
+        pAcquiredAsset->acquireAssetReference();
+
+        // Info.
+        if ( mEchoInfo )
+        {
+            Con::printf( "Asset Manager: > Finished acquiring asset.  Reference count now '%d'.", pAssetDefinition->mpAssetBase->getAcquiredReferenceCount() );
+            Con::printSeparator();
+        }
+
+        return pAcquiredAsset;
+    }
+
+    /// Private asset acquisition.
+    template<typename T> T* acquireAsPrivateAsset( const char* pAssetId )
+    {
+        // Acquire the asset normally.
+        T* pAsset = acquireAsset<T>( pAssetId );
+
+        // Finish if the asset was not acquired.
+        if ( pAsset == NULL )
+            return NULL;
+
+        // Clone the asset.
+        T* pAssetClone = dynamic_cast<T*>( pAsset->clone() );
+
+        // Sanity!
+        AssertFatal( pAssetClone != NULL, "acquireAsPrivateAsset() - Failed to clone asset type." );
+
+        // Release the public asset.
+        releaseAsset( pAssetId );
+
+        // Add as a private asset.
+        addPrivateAsset( pAssetClone );
+
+        return pAssetClone;
+    }
+
+    bool releaseAsset( const char* pAssetId );
+    void purgeAssets( void );
+
+    /// Asset deletion.
+    bool deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies );
+
+    // Asset refresh notification.
+    bool refreshAsset( const char* pAssetId );
+    void refreshAllAssets( const bool includeUnloaded = false );
+    void registerAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase, AssetPtrCallback* pCallback );
+    void unregisterAssetPtrRefreshNotify( AssetPtrBase* pAssetPtrBase );
+
+    /// Asset tags.
+    bool loadAssetTags( ModuleDefinition* pModuleDefinition );
+    bool saveAssetTags( void );
+    bool restoreAssetTags( void );
+    inline AssetTagsManifest* getAssetTags( void ) const { return mAssetTagsManifest; }
+
+    /// Info.
+    inline U32 getDeclaredAssetCount( void ) const { return (U32)mDeclaredAssets.size(); }
+    inline U32 getReferencedAssetCount( void ) const { return (U32)mReferencedAssets.size(); }
+    inline U32 getLoadedInternalAssetCount( void ) const { return mLoadedInternalAssetsCount; }
+    inline U32 getLoadedExternalAssetCount( void ) const { return mLoadedExternalAssetsCount; }
+    inline U32 getLoadedPrivateAssetCount( void ) const { return mLoadedPrivateAssetsCount; }
+    inline U32 getMaxLoadedInternalAssetCount( void ) const { return mMaxLoadedInternalAssetsCount; }
+    inline U32 getMaxLoadedExternalAssetCount( void ) const { return mMaxLoadedExternalAssetsCount; }
+    inline U32 getMaxLoadedPrivateAssetCount( void ) const { return mMaxLoadedPrivateAssetsCount; }
+    void dumpDeclaredAssets( void ) const;
+
+    /// Total acquired asset references.
+    inline void acquireAcquiredReferenceCount( void ) { mAcquiredReferenceCount++; }
+    inline void releaseAcquiredReferenceCount( void ) { AssertFatal( mAcquiredReferenceCount != 0, "AssetManager: Invalid acquired reference count." ); mAcquiredReferenceCount--; }
+    inline U32 getAcquiredReferenceCount( void ) const { return mAcquiredReferenceCount; }
+
+    /// Asset queries.
+    S32 findAllAssets( AssetQuery* pAssetQuery, const bool ignoreInternal = true, const bool ignorePrivate = true );
+    S32 findAssetName( AssetQuery* pAssetQuery, const char* pAssetName, const bool partialName = false );
+    S32 findAssetCategory( AssetQuery* pAssetQuery, const char* pAssetCategory, const bool assetQueryAsSource = false );
+    S32 findAssetAutoUnload( AssetQuery* pAssetQuery, const bool assetAutoUnload, const bool assetQueryAsSource = false );
+    S32 findAssetInternal( AssetQuery* pAssetQuery, const bool assetInternal, const bool assetQueryAsSource = false );
+    S32 findAssetPrivate( AssetQuery* pAssetQuery, const bool assetPrivate, const bool assetQueryAsSource = false );
+    S32 findAssetType( AssetQuery* pAssetQuery, const char* pAssetType, const bool assetQueryAsSource = false );
+    S32 findAssetDependsOn( AssetQuery* pAssetQuery, const char* pAssetId );
+    S32 findAssetIsDependedOn( AssetQuery* pAssetQuery, const char* pAssetId );
+    S32 findInvalidAssetReferences( AssetQuery* pAssetQuery );
+    S32 findTaggedAssets( AssetQuery* pAssetQuery, const char* pAssetTagNames, const bool assetQueryAsSource = false );
+    S32 findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLooseFile, const bool assetQueryAsSource = false );
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( AssetManager );
+
+private:
+    bool scanDeclaredAssets( const char* pPath, const char* pExtension, const bool recurse, ModuleDefinition* pModuleDefinition );
+    bool scanReferencedAssets( const char* pPath, const char* pExtension, const bool recurse );
+    AssetDefinition* findAsset( const char* pAssetId );
+    void addReferencedAsset( StringTableEntry assetId, StringTableEntry referenceFilePath );
+    void renameAssetReferences( StringTableEntry assetIdFrom, StringTableEntry assetIdTo );
+    void removeAssetReferences( StringTableEntry assetId );
+    void renameAssetDependencies( StringTableEntry assetIdFrom, StringTableEntry assetIdTo );
+    void removeAssetDependencies( const char* pAssetId );
+    void removeAssetLooseFiles( const char* pAssetId );
+    void unloadAsset( AssetDefinition* pAssetDefinition );
+
+    /// Module callbacks.
+    virtual void onModulePreLoad( ModuleDefinition* pModuleDefinition );
+    virtual void onModulePreUnload( ModuleDefinition* pModuleDefinition );
+    virtual void onModulePostUnload( ModuleDefinition* pModuleDefinition );
+};
+
+//-----------------------------------------------------------------------------
+
+extern AssetManager AssetDatabase;
+
+#endif // _ASSET_MANAGER_H_

+ 811 - 0
Engine/source/assets/assetManager_ScriptBinding.h

@@ -0,0 +1,811 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+#include "console/engineAPI.h"
+#include "assetBase.h"
+#include "assetManager.h"
+#include "module/moduleDefinition.h"
+#include "console/sim.h"
+
+DefineEngineMethod(AssetManager, compileReferencedAssets, bool, (const char* moduleDefinition), (""),
+   "Compile the referenced assets determined by the specified module definition.\n"
+   "@param moduleDefinition The module definition specifies the asset manifest.\n"
+   "@return Whether the compilation was successful or not.\n")
+{
+    // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::compileReferencedAssets() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Compile referenced assets.
+    return object->compileReferencedAssets( pModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, addModuleDeclaredAssets, bool, (const char* moduleDefinition), (""),
+   "Add any the declared assets specified by the module definition.\n"
+   "@param moduleDefinition The module definition specifies the asset manifest.\n"
+   "@return Whether adding declared assets was successful or not.\n")
+{
+   // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::addDeclaredAssets() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Add module declared assets.
+    return object->addModuleDeclaredAssets( pModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, addDeclaredAsset, bool, (const char* moduleDefinition, const char* assetFilePath), ("", ""),
+   "Add the specified asset against the specified module definition.\n"
+   "@param moduleDefinition The module definition that may contain declared assets.\n"
+   "@return Whether adding declared assets was successful or not.\n")
+{
+   // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::addDeclaredAsset() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Fetch asset file-path.
+    const char* pAssetFilePath = assetFilePath;
+
+    // Add declared asset.
+    return object->addDeclaredAsset( pModuleDefinition, pAssetFilePath );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, addPrivateAsset, String, (const char* assetObject), (""),
+   "Adds a private asset object.\n"
+   "@param assetObject The asset object to add as a private asset.\n"
+   "@return The allocated private asset Id.\n")
+{
+    // Fetch asset.
+   AssetBase* pAssetBase;
+   Sim::findObject(assetObject, pAssetBase);
+
+    // Did we find the asset?
+    if ( pAssetBase == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::addPrivateAsset() - Could not find the asset '%s'.", assetObject);
+        return StringTable->EmptyString();
+    }
+
+    // Add private asset.
+    return object->addPrivateAsset( pAssetBase );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, removeDeclaredAssets, bool, (const char* moduleDefinition), (""),
+   "Remove any the declared assets specified by the module definition.\n"
+   "@param moduleDefinition The module definition that may contain declared assets.\n"
+   "@return Whether removing declared assets was successful or not.\n")
+{
+    // Fetch module definition.
+   ModuleDefinition* pModuleDefinition;
+   Sim::findObject(moduleDefinition, pModuleDefinition);
+
+    // Did we find the module definition?
+    if ( pModuleDefinition == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::removeDeclaredAssets() - Could not find the module definition '%s'.", moduleDefinition);
+        return false;
+    }
+
+    // Remove declared assets.
+    return object->removeDeclaredAssets( pModuleDefinition );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, removeDeclaredAsset, bool, (const char* assetId), (""),
+   "Remove the specified declared asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether removing the declared asset was successful or not.\n")
+{
+    // Remove the declared asset Id.
+   return object->removeDeclaredAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetName, String, (const char* assetId), (""),
+   "Gets the asset name from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset name from the specified asset Id.\n")
+{
+   return object->getAssetName(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetDescription, String, (const char* assetId), (""),
+   "Gets the asset description from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset description from the specified asset Id.\n")
+{
+   return object->getAssetDescription(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetCategory, String, (const char* assetId), (""),
+   "Gets the asset category from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset category from the specified asset Id.\n")
+{
+   return object->getAssetCategory(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetType, String, (const char* assetId), (""),
+   "Gets the asset type from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset type from the specified asset Id.\n")
+{
+   return object->getAssetType(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetFilePath, String, (const char* assetId), (""),
+   "Gets the asset file-path from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset file - path from the specified asset Id.\n")
+{
+   return object->getAssetFilePath(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetPath, String, (const char* assetId), (""),
+   "Gets the asset path (not including the asset file) from the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The asset path(not including the asset file) from the specified asset Id.\n")
+{
+   return object->getAssetPath(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetModule, String, (const char* assetId), (""),
+   "Gets the module definition where the the specified asset Id is located.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return The module definition where the the specified asset Id is located.\n")
+{
+    // Fetch module definition.
+   ModuleDefinition* pModuleDefinition = object->getAssetModuleDefinition(assetId);
+
+    return pModuleDefinition == NULL ? StringTable->EmptyString() : pModuleDefinition->getIdString();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetInternal, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is internal or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is internal or not.\n")
+{
+   return object->isAssetInternal(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetPrivate, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is private or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is private or not.\n")
+{
+   return object->isAssetPrivate(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetAutoUnload, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is auto - unload or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is auto-unload or not.\n")
+{
+   return object->isAssetAutoUnload(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isAssetLoaded, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is loaded or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is loaded or not.\n")
+{
+   return object->isAssetLoaded(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isDeclaredAsset, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is declared or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is declared or not.\n")
+{
+   return object->isDeclaredAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, isReferencedAsset, bool, (const char* assetId), (""),
+   "Check whether the specified asset Id is referenced or not.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the specified asset Id is referenced or not.\n")
+{
+   return object->isReferencedAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, renameDeclaredAsset, bool, (const char* assetIdFrom, const char* assetIdTo), ("", ""),
+   "Rename declared asset Id.\n"
+   "@param assetIdFrom The selected asset Id to rename from.\n"
+   "@param assetIdFrom The selected asset Id to rename to.\n"
+   "@return Whether the rename was successful or not.\n")
+{
+   return object->renameDeclaredAsset(assetIdFrom, assetIdTo);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, renameReferencedAsset, bool, (const char* assetIdFrom, const char* assetIdTo), ("", ""),
+   "Rename referenced asset Id. \n"
+   "@param assetIdFrom The selected asset Id to rename from.\n"
+   "@param assetIdFrom The selected asset Id to rename to.\n"
+   "@return Whether the rename was successful or not.\n")
+{
+   return object->renameReferencedAsset(assetIdFrom, assetIdTo);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, acquireAsset, String, (const char* assetId, bool asPrivate), ("", false),
+   "Acquire the specified asset Id.\n"
+   "You must release the asset once you're finish with it using 'releaseAsset'.\n"
+   "@param assetId The selected asset Id.\n"
+   "@param asPrivate Whether to acquire the asset Id as a private asset.\n"
+   "@return The acquired asset or NULL if not acquired.\n")
+{
+    // Fetch asset Id.
+   const char* pAssetId = assetId;
+
+    // Reset asset reference.
+    AssetBase* pAssetBase = NULL;
+
+    // Acquire private asset?
+    if ( asPrivate )
+    {
+        // Acquire private asset.
+        pAssetBase = object->acquireAsPrivateAsset<AssetBase>( pAssetId );
+    }
+    else
+    {
+        // Acquire public asset.
+        pAssetBase = object->acquireAsset<AssetBase>( pAssetId );
+    }
+
+    return pAssetBase != NULL ? pAssetBase->getIdString() : StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, releaseAsset, bool, (const char* assetId), (""),
+   "Release the specified asset Id.\n"
+   "The asset should have been acquired using 'acquireAsset'.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return Whether the asset was released or not.\n")
+{
+    // Release asset.
+   return object->releaseAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, purgeAssets, void, (),,
+   "Purge all assets that are not referenced even if they are set to not auto-unload.\n"
+   "Assets can be in this state because they are either set to not auto-unload or the asset manager has/is disabling auto-unload.\n"
+   "@return No return value.\n")
+{
+    // Purge assets.
+    object->purgeAssets();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, deleteAsset, bool, (const char* assetId, bool deleteLooseFiles, bool deleteDependencies), ("", false, false),
+   "Deletes the specified asset Id and optionally its loose files and asset dependencies.\n"
+   "@param assetId The selected asset Id.\n"
+   "@param deleteLooseFiles Whether to delete an assets loose files or not.\n"
+   "@param deleteDependencies Whether to delete assets that depend on this asset or not.\n"
+   "@return Whether the asset deletion was successful or not.  A failure only indicates that the specified asset was not deleted but dependent assets and their loose files may have being deleted.\n")
+{
+    // Fetch asset Id.
+   const char* pAssetId = assetId;
+
+    // Delete asset.
+    return object->deleteAsset( pAssetId, deleteLooseFiles, deleteDependencies );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, refreshAsset, void, (const char* assetId), (""),
+   "Refresh the specified asset Id.\n"
+   "@param assetId The selected asset Id.\n"
+   "@return No return value.\n")
+{
+   object->refreshAsset(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, refreshAllAssets, void, (bool includeUnloaded), (false),
+   "Refresh all declared assets.\n"
+   "@param Whether to include currently unloaded assets in the refresh or not.  Optional: Defaults to false.\n"
+   "Refreshing all assets can be an expensive (time-consuming) operation to perform.\n"
+   "@return No return value.\n")
+{
+    // Refresh assets
+    object->refreshAllAssets(includeUnloaded);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, saveAssetTags, bool, (),,
+   "Save the currently loaded asset tags manifest.\n"
+   "@return Whether the save was successful or not.\n")
+{
+    // Save asset tags.
+    return object->saveAssetTags();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, restoreAssetTags, bool, (),,
+   "Restore the currently loaded asset tags manifest from disk (replace anything in memory).\n"
+   "@return Whether the restore was successful or not.\n")
+{
+    // Restore asset tags.
+    return object->restoreAssetTags();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getAssetTags, S32, (), ,
+   "Gets the currently loaded asset tags manifest.\n"
+   "@return The currently loaded asset tags manifest or zero if not loaded.\n")
+{
+    // Fetch the asset tags manifest.
+    AssetTagsManifest* pAssetTagsManifest = object->getAssetTags();
+
+    return pAssetTagsManifest == NULL ? 0 : pAssetTagsManifest->getId();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAllAssets, S32, (const char* assetQuery, bool ignoreInternal, bool ignorePrivate), ("", true, true),
+   "Performs an asset query searching for all assets optionally ignoring internal assets.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param ignoreInternal Whether to ignore internal assets or not.  Optional: Defaults to true.\n"
+   "@param ignorePrivate Whether to ignore private assets or not.  Optional: Defaults to true.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAllAssets() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAllAssets( pAssetQuery, ignoreInternal, ignorePrivate );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetName, S32, (const char* assetQuery, const char* assetName, bool partialName), ("", "", false),
+   "Performs an asset query searching for the specified asset name.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetName The asset name to search for.  This may be a partial name if 'partialName' is true.\n"
+   "@param partialName Whether the asset name is to be used as a partial name or not.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetName() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset name.
+    const char* pAssetName = assetName;
+
+    // Perform query.
+    return object->findAssetName( pAssetQuery, pAssetName, partialName );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetCategory, S32, (const char* assetQuery, const char* assetCategory, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified asset category.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetCategory The asset category to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetCategory() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset category.
+    const char* pAssetCategory = assetCategory;
+
+    // Perform query.
+    return object->findAssetCategory( pAssetQuery, pAssetCategory, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetAutoUnload, S32, (const char* assetQuery, bool assetAutoUnload, bool assetQueryAsSource), ("", false, false),
+   "Performs an asset query searching for the specified asset auto-unload flag.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetInternal The asset internal flag to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetAutoUnload() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAssetAutoUnload( pAssetQuery, assetAutoUnload, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetInternal, S32, (const char* assetQuery, bool assetInternal, bool assetQueryAsSource), ("", false, false),
+   "Performs an asset query searching for the specified asset internal flag.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetInternal The asset internal flag to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetInternal() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAssetInternal( pAssetQuery, assetInternal, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetPrivate, S32, (const char* assetQuery, bool assetPrivate, bool assetQueryAsSource), ("", false, false),
+   "Performs an asset query searching for the specified asset private flag.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetPrivate The asset private flag to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetPrivate() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findAssetInternal( pAssetQuery, assetPrivate, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetType, S32, (const char* assetQuery, const char* assetType, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified asset type.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetType The asset type to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetType() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset type.
+    const char* pAssetType = assetType;
+
+    // Perform query.
+    return object->findAssetType( pAssetQuery, pAssetType, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetDependsOn, S32, (const char* assetQuery, const char* assetId), ("", ""),
+   "Performs an asset query searching for asset Ids that the specified asset Id depends on.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetId The asset Id to query for any asset Ids that it depends on.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetDependsOn() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset Id.
+    const char* pAssetId = assetId;
+
+    // Perform query.
+    return object->findAssetDependsOn( pAssetQuery, pAssetId );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetIsDependedOn, S32, (const char* assetQuery, const char* assetId), ("", ""),
+   "Performs an asset query searching for asset Ids that depend on the specified asset Id.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetId The asset Id to query for any asset Ids that may depend on it.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetIsDependedOn() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset Id.
+    const char* pAssetId = assetId;
+
+    // Perform query.
+    return object->findAssetIsDependedOn( pAssetQuery, pAssetId );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findInvalidAssetReferences, S32, (const char* assetQuery), (""),
+   "Performs an asset query searching for invalid asset references.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@return The number of asset Ids found that are invalid or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findInvalidAssetReferences() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Perform query.
+    return object->findInvalidAssetReferences( pAssetQuery );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findTaggedAssets, S32, (const char* assetQuery, const char* assetTagNames, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified asset tag name(s).\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetTagNames The asset tag name or names to search for.  Multiple names can be specified using comma, space, tab or newline separation.  Tags use an OR operation i.e. only assets tagged with ANY of the specified tags will be returned.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findTaggedAssets() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset tag name(s).
+    const char* pAssetTagNames = assetTagNames;
+
+    // Perform query.
+    return object->findTaggedAssets( pAssetQuery, pAssetTagNames, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, findAssetLooseFile, S32, (const char* assetQuery, const char* assetLooseFile, bool assetQueryAsSource), ("", "", false),
+   "Performs an asset query searching for the specified loose file.\n"
+   "@param assetQuery The asset query object that will be populated with the results.\n"
+   "@param assetLooseFile The loose-file used by the asset to search for.\n"
+   "@param assetQueryAsSource Whether to use the asset query as the data-source rather than the asset managers database or not.  Doing this effectively filters the asset query.  Optional: Defaults to false.\n"
+   "@return The number of asset Ids found or (-1) if an error occurred.\n")
+{
+   // Fetch asset query.
+   AssetQuery* pAssetQuery;
+   Sim::findObject(assetQuery, pAssetQuery);
+
+    // Did we find the asset query?
+    if ( pAssetQuery == NULL )
+    {
+        // No, so warn.
+       Con::warnf("AssetManager::findAssetLooseFile() - Could not find the asset query object '%s'.", assetQuery);
+        return -1;
+    }
+
+    // Fetch asset loose file.
+    const char* pAssetLooseFile = assetLooseFile;
+
+    // Perform query.
+    return object->findAssetLooseFile( pAssetQuery, pAssetLooseFile, assetQueryAsSource );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getDeclaredAssetCount, bool, (),,
+   "Gets the number of declared assets.\n"
+   "@return Returns the number of declared assets.\n")
+{
+    return object->getDeclaredAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getReferencedAssetCount, bool, (), ,
+   "Gets the number of asset referenced.\n"
+   "@return Returns the number of asset references.\n")
+{
+    return object->getReferencedAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getLoadedInternalAssetCount, bool, (), ,
+   "Gets the number of loaded internal assets.\n"
+   "@return Returns the number of loaded internal assets.\n")
+{
+    return object->getLoadedInternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getMaxLoadedInternalAssetCount, bool, (), ,
+   "Gets the maximum number of loaded internal assets.\n"
+   "@return Returns the maximum number of loaded internal assets.\n")
+{
+    return object->getMaxLoadedInternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getLoadedExternalAssetCount, bool, (), ,
+   "Gets the number of loaded external assets.\n"
+   "@return Returns the number of loaded external assets.\n")
+{
+    return object->getLoadedExternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, getMaxLoadedExternalAssetCount, bool, (), ,
+   "Gets the maximum number of loaded external assets.\n"
+   "@return Returns the maximum number of loaded external assets.\n")
+{
+    return object->getMaxLoadedExternalAssetCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetManager, dumpDeclaredAssets, void, (), ,
+   "Dumps a breakdown of all declared assets.\n"
+   "@return No return value.\n")
+{
+    return object->dumpDeclaredAssets();
+}

+ 184 - 0
Engine/source/assets/assetPtr.h

@@ -0,0 +1,184 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_PTR_H_
+#define _ASSET_PTR_H_
+
+#ifndef _ASSET_MANAGER_H_
+#include "assetManager.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class AssetPtrCallback
+{
+    friend class AssetManager;
+
+protected:
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase ) = 0;    
+};
+
+//-----------------------------------------------------------------------------
+
+class AssetPtrBase
+{
+public:
+    AssetPtrBase() {};
+    virtual ~AssetPtrBase()
+    {
+        // Un-register any notifications.
+        unregisterRefreshNotify();
+    };
+
+    /// Referencing.
+    virtual void clear( void ) = 0;
+    virtual void setAssetId( const char* pAssetId ) = 0;
+    virtual StringTableEntry getAssetId( void ) const = 0;
+    virtual StringTableEntry getAssetType( void ) const = 0;
+    virtual bool isAssetId( const char* pAssetId ) const = 0;
+
+    /// Validity.
+    virtual bool isNull( void ) const = 0;
+    virtual bool notNull( void ) const = 0;
+
+    /// Notification.
+    inline void registerRefreshNotify( AssetPtrCallback* pCallback )
+    {
+        // Sanity!
+        AssertFatal( AssetDatabase.isProperlyAdded(), "AssetPtrBase::registerRefreshNotify() - Cannot register an asset pointer with the asset system." );
+
+        // register refresh notify.
+        AssetDatabase.registerAssetPtrRefreshNotify( this, pCallback );
+    }
+
+    void unregisterRefreshNotify( void )
+    {
+        // Un-register the refresh notify if the asset system is available.
+        if ( AssetDatabase.isProperlyAdded() )
+            AssetDatabase.unregisterAssetPtrRefreshNotify( this );
+    }
+};
+
+//-----------------------------------------------------------------------------
+
+template<typename T> class AssetPtr : public AssetPtrBase
+{
+private:
+    SimObjectPtr<T> mpAsset;
+
+public:
+    AssetPtr() {}
+    AssetPtr( const char* pAssetId )
+    {
+        // Finish if this is an invalid asset Id.
+        if ( pAssetId == NULL || *pAssetId == 0 )
+            return;
+
+        // Acquire asset.
+        mpAsset = AssetDatabase.acquireAsset<T>( pAssetId );
+    }
+    AssetPtr( const AssetPtr<T>& assetPtr )
+    {
+        // Does the asset pointer have an asset?
+        if ( assetPtr.notNull() )
+        {
+            // Yes, so acquire the asset.
+            mpAsset = AssetDatabase.acquireAsset<T>( assetPtr->getAssetId() );
+        }
+    }
+    virtual ~AssetPtr()
+    {
+        // Do we have an asset?
+        if ( notNull() )
+        {
+            // Yes, so release it.
+            AssetDatabase.releaseAsset( mpAsset->getAssetId() );
+        }
+    }
+
+    /// Assignment.
+    AssetPtr<T>& operator=( const char* pAssetId )
+    {
+        // Do we have an asset?
+        if ( notNull() )
+        {
+            // Yes, so finish if the asset Id is already assigned.
+            if ( isAssetId( pAssetId ) )
+                return *this;
+
+            // No, so release it.
+            AssetDatabase.releaseAsset( mpAsset->getAssetId() );
+        }
+
+        // Is the asset Id at least okay to attempt to acquire the asset?
+        if ( pAssetId != NULL && *pAssetId != 0 )
+        {
+            // Yes, so acquire the asset.
+            mpAsset = AssetDatabase.acquireAsset<T>( pAssetId );
+        }
+        else
+        {
+            // No, so remove reference.
+            mpAsset = NULL;
+        }
+
+        // Return Reference.
+        return *this;
+    }
+
+    AssetPtr<T>& operator=( const AssetPtr<T>& assetPtr )
+    {
+        // Set asset pointer.
+        *this = assetPtr->getAssetId();
+
+        // Return Reference.
+        return *this;
+    }
+
+    /// Referencing.
+    virtual void clear( void )
+    {
+        // Do we have an asset?
+        if ( notNull() )
+        {
+            // Yes, so release it.
+            AssetDatabase.releaseAsset( mpAsset->getAssetId() );
+        }
+
+        // Reset the asset reference.
+        mpAsset = NULL;
+    }
+
+    T* operator->( void ) const { return mpAsset; }
+    T& operator*( void ) const { return *mpAsset; }
+    operator T*( void ) const { return mpAsset; }
+    virtual void setAssetId( const char* pAssetId ) { *this = pAssetId; }
+    virtual StringTableEntry getAssetId( void ) const { return isNull() ? StringTable->EmptyString() : mpAsset->getAssetId(); }
+    virtual StringTableEntry getAssetType(void) const { return isNull() ? StringTable->EmptyString() : mpAsset->getClassName(); }
+    virtual bool isAssetId( const char* pAssetId ) const { return pAssetId == NULL ? isNull() : getAssetId() == StringTable->insert(pAssetId); }
+
+    /// Validity.
+    virtual bool isNull( void ) const { return mpAsset.isNull(); }
+    virtual bool notNull( void ) const { return !mpAsset.isNull(); }
+};
+
+#endif // _ASSET_PTR_H_

+ 121 - 0
Engine/source/assets/assetQuery.cpp

@@ -0,0 +1,121 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_QUERY_H_
+#include "assetQuery.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _TAML_CUSTOM_H_
+#include "persistence/taml/tamlCustom.h"
+#endif
+
+// Script bindings.
+#include "assetQuery_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( AssetQuery );
+
+//-----------------------------------------------------------------------------
+
+void AssetQuery::initPersistFields()
+{
+    // Call parent.
+    Parent::initPersistFields();
+
+    addProtectedField("Count", TypeS32, 0, &defaultProtectedSetFn, &getCount, &writeCount, "Gets the number of results in the asset query.");
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetQuery::onTamlCustomWrite( TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomWrite( customNodes );
+
+    // Add node.
+    TamlCustomNode* pCustomNode = customNodes.addNode( ASSETQUERY_RESULTS_NODE_NAME );
+
+    // Finish if no assets.
+    if (mAssetList.size() == 0)
+        return;
+
+    // Iterate asset.
+    for (Vector<StringTableEntry>::iterator assetItr = mAssetList.begin(); assetItr != mAssetList.end(); ++assetItr)
+    {
+        // Add asset node.
+        TamlCustomNode* pAssetNode = pCustomNode->addNode( ASSETQUERY_ASSETNODE_NAME );
+
+        // Add field.
+        pAssetNode->addField( ASSETQUERY_ASSETID_FIELD_NAME, *assetItr );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetQuery::onTamlCustomRead( const TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomRead( customNodes );
+
+    // Find custom node name.
+    const TamlCustomNode* pResultsNode = customNodes.findNode( ASSETQUERY_RESULTS_NODE_NAME );
+
+    // Finish if we don't have a results name.
+    if ( pResultsNode == NULL )
+        return;
+
+    // Fetch node name.
+    StringTableEntry assetNodeName = StringTable->insert( ASSETQUERY_ASSETNODE_NAME );
+
+    // Fetch children asset nodes.
+    const TamlCustomNodeVector& assetNodes = pResultsNode->getChildren();
+
+    // Iterate asset nodes.
+    for( TamlCustomNodeVector::const_iterator assetNodeItr = assetNodes.begin(); assetNodeItr != assetNodes.end(); ++assetNodeItr )
+    {
+        // Fetch asset node.
+        const TamlCustomNode* pAssetNode = *assetNodeItr;
+
+        // Skip if an unknown node name.
+        if ( pAssetNode->getNodeName() != assetNodeName )
+            continue;
+
+        // Fetch field.
+        const TamlCustomField* pField = pAssetNode->findField( ASSETQUERY_ASSETID_FIELD_NAME );
+
+        // Do we find the field?
+        if ( pField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetQuery::onTamlCustomRead() - Could not find '%s' field.", ASSETQUERY_ASSETID_FIELD_NAME );
+            continue;
+        }
+
+        // Store asset.
+        mAssetList.push_back(pField->getFieldValue());
+    }
+}

+ 90 - 0
Engine/source/assets/assetQuery.h

@@ -0,0 +1,90 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_QUERY_H_
+#define _ASSET_QUERY_H_
+
+#ifndef _SIMBASE_H_
+#include "console/simBase.h"
+#endif
+
+#ifndef _TVECTOR_H_
+#include "core/util/tVector.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "core/strings/stringUnit.h"
+#endif
+
+#ifndef _TAML_CUSTOM_H_
+#include "persistence/taml/tamlCustom.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+#define ASSETQUERY_RESULTS_NODE_NAME     "Results"
+#define ASSETQUERY_ASSETNODE_NAME        "Asset"
+#define ASSETQUERY_ASSETID_FIELD_NAME   "AssetId"
+
+//-----------------------------------------------------------------------------
+
+class AssetQuery : public SimObject 
+{
+private:
+    typedef SimObject Parent;
+
+protected:
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
+
+    static const char* getCount(void* obj, const char* data) { return Con::getIntArg(static_cast<AssetQuery*>(obj)->mAssetList.size()); }
+    static bool writeCount( void* obj, StringTableEntry pFieldName ) { return false; }
+
+public:
+    AssetQuery() {}
+    virtual ~AssetQuery() {}
+
+    /// SimObject overrides
+    static void initPersistFields();
+
+    Vector<StringTableEntry> mAssetList;
+
+    /// Whether asset is contained or not.
+    inline bool containsAsset( StringTableEntry assetId )
+    {
+       for (Vector<StringTableEntry>::const_iterator assetItr = mAssetList.begin(); assetItr != mAssetList.end(); ++assetItr)
+        {
+            if ( *assetItr == assetId )
+                return true;
+        }
+        return false;
+    }
+
+    /// Set assets.
+    inline void set( const AssetQuery& assetQuery ) { this->mAssetList = assetQuery.mAssetList; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( AssetQuery );
+};
+
+#endif // _ASSET_QUERY_H_
+

+ 85 - 0
Engine/source/assets/assetQuery_ScriptBinding.h

@@ -0,0 +1,85 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_QUERY_H_
+#include "assets/assetQuery.h"
+#endif
+
+#include "console/engineAPI.h"
+
+DefineConsoleMethod(AssetQuery, clear, void, (),,"Clears all asset Id results."
+   "Clears all asset Id results.\n"
+   "@return () No return value.\n")
+{
+   object->mAssetList.clear();
+}
+
+//-----------------------------------------------------------------------------
+
+
+DefineConsoleMethod(AssetQuery, set, bool, (S32 queryId), ,
+   "Sets the asset query to a copy of the specified asset query.\n"
+   "@param assetQuery The asset query to copy.\n"
+   "@return Whether the operation succeeded or not.\n")
+{
+    // Find asset query.
+    AssetQuery* pAssetQuery;
+
+    if (!Sim::findObject(queryId, pAssetQuery))
+    {
+       // No, so warn.
+       Con::warnf("AssetQuery::set() - Could not find asset query '%i'.", queryId);
+       return false;
+    }
+
+    // Set asset query.
+    object->set( *pAssetQuery );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleMethod(AssetQuery, getCount, S32, (), , 
+   "Gets the count of asset Id results.\n"
+   "@return (int)The count of asset Id results.\n")
+{
+   return object->mAssetList.size();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleMethod(AssetQuery, getAsset, const char*, (S32 resultIndex), (-1), 
+   "Gets the asset Id at the specified query result index.\n"
+   "@param resultIndex The query result index to use.\n"
+   "@return (assetId)The asset Id at the specified index or NULL if not valid.\n")
+{
+    // Is index within bounds?
+   if (resultIndex >= object->mAssetList.size())
+    {
+        // No, so warn.
+        Con::warnf("AssetQuery::getAsset() - Result index '%s' is out of bounds.", resultIndex);
+        return StringTable->EmptyString();
+    }
+
+    return object->mAssetList[resultIndex];
+}

+ 564 - 0
Engine/source/assets/assetTagsManifest.cpp

@@ -0,0 +1,564 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_TAGS_MANIFEST_H_
+#include "assetTagsManifest.h"
+#endif
+
+#ifndef _ASSET_MANAGER_H_
+#include "assetManager.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+// Script binding.
+#include "assetTagsManifest_ScriptBinding.h"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( AssetTagsManifest );
+
+//-----------------------------------------------------------------------------
+
+AssetTagsManifest::AssetTagsManifest()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+AssetTagsManifest::~AssetTagsManifest()
+{
+    // Iterate tags.
+    for( typeTagNameHash::iterator tagNameItr = mTagNameDatabase.begin(); tagNameItr != mTagNameDatabase.end(); ++tagNameItr )
+    {
+        // Delete asset tag.
+        delete tagNameItr->value;
+    }
+
+    // Clear database.
+    mTagNameDatabase.clear();
+    mAssetToTagDatabase.clear();
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetTagsManifest::fetchTagName( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    return StringTable->insert( pTagName, true );
+}
+
+//-----------------------------------------------------------------------------
+
+AssetTagsManifest::AssetTag* AssetTagsManifest::findAssetTag( const char* pTagName )
+{
+    // Fetch tag name.
+    StringTableEntry tagName = fetchTagName( pTagName );
+
+    // Finish if the tag already exists.
+    typeTagNameHash::iterator tagNameItr = mTagNameDatabase.find( tagName );
+
+    return tagNameItr == mTagNameDatabase.end() ? NULL : tagNameItr->value;
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetTagsManifest::renameAssetId( const char* pAssetIdFrom, const char* pAssetIdTo )
+{
+    // Sanity!
+    AssertFatal( pAssetIdFrom != NULL, "Cannot rename from NULL asset Id." );
+    AssertFatal( pAssetIdTo != NULL, "Cannot rename to NULL asset Id." );
+
+    // Fetch asset Ids.
+    StringTableEntry assetIdFrom = StringTable->insert( pAssetIdFrom );
+    StringTableEntry assetIdTo   = StringTable->insert( pAssetIdTo );
+
+    while( true )
+    {
+        // Find asset Id.
+        typeAssetToTagHash::Iterator assetIdItr = mAssetToTagDatabase.find( assetIdFrom );
+
+        // Finish if no asset Id to rename.
+        if ( assetIdItr == mAssetToTagDatabase.end() )
+            return;
+
+        // Fetch asset tag.
+        AssetTag* pAssetTag = assetIdItr->value;
+
+        // Untag old asset Id.
+        untag( assetIdFrom, pAssetTag->mTagName );
+
+        // Tag new asset Id.
+        tag( assetIdTo, pAssetTag->mTagName );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetTagsManifest::onTamlCustomWrite( TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomWrite( customNodes );
+
+    // Finish if no tags.
+    if ( mTagNameDatabase.size() == 0 )
+        return;
+
+    // Add node.
+    TamlCustomNode* pTagsNode = customNodes.addNode( ASSETTAGS_TAGS_NODE_NAME );
+
+    // Iterate tags.
+    for( typeTagNameHash::iterator tagItr = mTagNameDatabase.begin(); tagItr != mTagNameDatabase.end(); ++tagItr )
+    {
+        // Add tag node.
+        TamlCustomNode* pTagNode = pTagsNode->addNode( ASSETTAGS_TAGS_TYPE_NAME );
+
+        // Add fields.
+        pTagNode->addField( ASSETTAGS_TAGS_NAME_FIELD, tagItr->key );
+    }
+
+    // Add node.
+    TamlCustomNode* pAssetTagsNode = customNodes.addNode( ASSETTAGS_ASSETS_NODE_NAME );
+
+    // Iterate asset locations.
+    for( typeAssetToTagHash::Iterator assetTagItr = mAssetToTagDatabase.begin(); assetTagItr != mAssetToTagDatabase.end(); ++assetTagItr )
+    {
+        // Add asset tag node.
+        TamlCustomNode* pAssetNode = pAssetTagsNode->addNode( ASSETTAGS_ASSETS_TYPE_NAME );
+
+        // Add fields.
+        pAssetNode->addField( ASSETTAGS_ASSETS_ASSETID_FIELD, assetTagItr->key );
+        pAssetNode->addField( ASSETTAGS_ASSETS_TAG_FIELD, assetTagItr->value->mTagName );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void AssetTagsManifest::onTamlCustomRead( const TamlCustomNodes& customNodes )
+{
+    // Call parent.
+    Parent::onTamlCustomRead( customNodes );
+
+    // Find tags nodes.
+    const TamlCustomNode* pTagProperty = customNodes.findNode( ASSETTAGS_TAGS_NODE_NAME );
+
+    // Finish if we don't have a tags node name.
+    if ( pTagProperty == NULL )
+        return;
+
+    // Fetch node name.
+    StringTableEntry tagNodeName = StringTable->insert( ASSETTAGS_TAGS_TYPE_NAME );
+
+    // Fetch children asset nodes.
+    const TamlCustomNodeVector& tagNodes = pTagProperty->getChildren();
+
+    // Iterate tag nodes.
+    for( TamlCustomNodeVector::const_iterator tagNodeItr = tagNodes.begin(); tagNodeItr != tagNodes.end(); ++tagNodeItr )
+    {
+        // Fetch tag node.
+        const TamlCustomNode* pTagNode = *tagNodeItr;
+
+        // Skip if an unknown node name.
+        if ( pTagNode->getNodeName() != tagNodeName )
+            continue;
+
+        // Fetch "Name" field.
+        const TamlCustomField* pTagNameField = pTagNode->findField( ASSETTAGS_TAGS_NAME_FIELD );
+
+        // Do we find the field?
+        if ( pTagNameField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Could not find '%s' field.", ASSETTAGS_TAGS_NAME_FIELD );
+            continue;
+        }
+
+        // Create the tag.
+        createTag( pTagNameField->getFieldValue() );
+    }
+
+    // Find asset tags node.
+    const TamlCustomNode* pAssetTagProperty = customNodes.findNode( ASSETTAGS_ASSETS_NODE_NAME );
+
+    // Finish if we don't have an asset tags node name.
+    if ( pAssetTagProperty == NULL )
+        return;
+
+    // Fetch node name.
+    StringTableEntry assetTagNodeName = StringTable->insert( ASSETTAGS_ASSETS_TYPE_NAME );
+
+    // Fetch children asset tag nodes.
+    const TamlCustomNodeVector& assetTagNodes = pAssetTagProperty->getChildren();
+
+    // Iterate property alias.
+    for( TamlCustomNodeVector::const_iterator assetTagNodeItr = assetTagNodes.begin(); assetTagNodeItr != assetTagNodes.end(); ++assetTagNodeItr )
+    {
+        // Fetch asset node.
+        const TamlCustomNode* pAssetTagNode = *assetTagNodeItr;
+
+        // Skip if an unknown node name.
+        if ( pAssetTagNode->getNodeName() != assetTagNodeName )
+            continue;
+
+        // Fetch "AssetId" field.
+        const TamlCustomField* pAssetIdField = pAssetTagNode->findField( ASSETTAGS_ASSETS_ASSETID_FIELD );
+
+        // Do we find the field?
+        if ( pAssetIdField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Could not find '%s' field.", ASSETTAGS_ASSETS_ASSETID_FIELD );
+            continue;
+        }
+
+        // Fetch "Tag" field.
+        const TamlCustomField* pTagField = pAssetTagNode->findField( ASSETTAGS_ASSETS_TAG_FIELD );
+
+        // Do we find the field?
+        if ( pTagField == NULL )
+        {
+            // No, so warn.
+            Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Could not find '%s' field.", ASSETTAGS_ASSETS_TAG_FIELD );
+            continue;
+        }
+
+        // Tag the asset.
+        tag( pAssetIdField->getFieldValue(), pTagField->getFieldValue() );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+const AssetTagsManifest::AssetTag* AssetTagsManifest::createTag( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Finish if the tag already exists.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Return asset tag if already created.
+    if ( pAssetTag != NULL )
+        return pAssetTag;
+
+    // Fetch tag name.
+    StringTableEntry tagName = fetchTagName( pTagName );
+
+    // Generate the asset tag.
+    pAssetTag = new AssetTag( tagName );
+
+    // Add the tag.
+    mTagNameDatabase.insert( tagName, pAssetTag );
+
+    return pAssetTag;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::renameTag( const char* pOldTagName, const char* pNewTagName )
+{
+    // Sanity!
+    AssertFatal( pOldTagName != NULL, "Cannot use a NULL tag name." );
+    AssertFatal( pNewTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find old asset tags.
+    AssetTag* pOldAssetTag = findAssetTag( pOldTagName );
+
+    // Did we find the asset tag?
+    if ( pOldAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest: Cannot rename tag '%s' as it does not exist.", pOldTagName );
+        return false;
+    }
+
+    // Are the old and new tags the same?
+    if ( pOldAssetTag->mTagName == fetchTagName( pNewTagName ) )
+    {
+        // Yes, so warn.
+        Con::warnf( "AssetTagsManifest: Cannot rename tag '%s' to tag '%s' as they are the same.", pOldTagName, pNewTagName );
+        return false;
+    }
+
+    // Create new tag.
+    AssetTag* pNewAssetTag = const_cast<AssetTag*>( createTag( pNewTagName ) );
+
+    // Transfer asset tags.
+    for ( Vector<typeAssetId>::iterator assetIdItr = pOldAssetTag->mAssets.begin(); assetIdItr != pOldAssetTag->mAssets.end(); ++assetIdItr )
+    {
+        pNewAssetTag->mAssets.push_back( *assetIdItr );
+    }
+
+    // Delete old tag.
+    deleteTag( pOldTagName );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::deleteTag( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Did we find the asset tag?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest: Cannot delete tag '%s' as it does not exist.", pTagName );
+        return false;
+    }
+
+    // Remove the tag.
+    mTagNameDatabase.erase( pAssetTag->mTagName );
+
+    // Remove the asset tags.
+    for ( Vector<typeAssetId>::iterator assetIdItr = pAssetTag->mAssets.begin(); assetIdItr != pAssetTag->mAssets.end(); ++assetIdItr )
+    {
+        // Find asset Id tag.
+        typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find( *assetIdItr );
+
+        // Iterate asset Id tags.
+        while( assetItr != mAssetToTagDatabase.end() && assetItr->key == *assetIdItr )
+        {
+            // Is this the asset tag?
+            if ( assetItr->value == pAssetTag )
+            {
+                // Yes, so erase it.
+                mAssetToTagDatabase.erase( assetItr );
+                break;
+            }
+
+            // Next entry.
+            assetItr++;
+        }
+    }
+
+    // Delete the asset tag.
+    delete pAssetTag;
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::isTag( const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Check whether tag exists or not.
+    return findAssetTag( pTagName ) != NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetTagsManifest::getTag( const U32 tagIndex )
+{
+    // Finish if invalid tag count.
+    AssertFatal( tagIndex < getTagCount(), "Tag index is out of bounds." );
+
+    // Fetch tag iterator.
+    typeTagNameHash::iterator tagItr = mTagNameDatabase.begin();
+
+    // Find asset tag by index.
+    // NOTE: Unfortunately this is slow as it's not the natural access method.
+    for( U32 index = 0; index  < tagIndex; ++index, ++tagItr ) {};
+
+    // Return tag name.
+    return tagItr->value->mTagName;
+}
+
+//-----------------------------------------------------------------------------
+
+U32 AssetTagsManifest::getAssetTagCount( const char* pAssetId )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    return (U32)mAssetToTagDatabase.count( assetId );
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry AssetTagsManifest::getAssetTag( const char* pAssetId, const U32 tagIndex )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+
+    // Fetch asset Id.
+    StringTableEntry assetId = StringTable->insert( pAssetId );
+
+    // Sanity!
+    AssertFatal( tagIndex < (U32)mAssetToTagDatabase.count( assetId ), "Asset tag index is out of bounds." );
+
+    // Find asset tag.
+    typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find( assetId );
+
+    // Find asset tag by index.
+    // NOTE: Unfortunately this is slow as it's not the natural access method.
+    for( U32 index = 0; index  < tagIndex; ++index, ++assetItr ) {};
+
+    // Return tag name.
+    return assetItr->value->mTagName;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::tag( const char* pAssetId, const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Does the tag exist?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot tag asset Id '%s' with tag name '%s' as tag name does not exist.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Is the asset Id valid?
+    if ( !AssetDatabase.isDeclaredAsset( pAssetId ) )
+    {
+        // No, so warn.
+        Con::warnf( "AssetTagsManifest::onTamlCustomRead() - Ignoring asset Id '%s' mapped to tag name '%s' as it is not a declared asset Id.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Fetch asset Id.
+    typeAssetId assetId = StringTable->insert( pAssetId );
+
+    // Find asset Id tag.
+    typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find(assetId);
+
+    // Iterate asset Id tags.
+    while( assetItr != mAssetToTagDatabase.end() && assetItr->key == assetId )
+    {
+        // Is the asset already tagged appropriately?
+        if ( assetItr->value == pAssetTag )
+            return true;
+
+        // Next entry.
+        assetItr++;
+    }
+
+    // No, so add tag.
+    mAssetToTagDatabase.insertEqual( assetId, pAssetTag );    
+
+    // Add to asset tag.
+    pAssetTag->mAssets.push_back( assetId );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::untag( const char* pAssetId, const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Does the tag exist?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot untag asset Id '%s' from tag name '%s' as tag name does not exist.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Fetch asset Id.
+    typeAssetId assetId = StringTable->insert( pAssetId );
+
+    // Is the asset tagged?
+    if ( !pAssetTag->containsAsset( assetId ) )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot untag asset Id '%s' from tag name '%s' as the asset is not tagged with the tag name.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Remove asset from assert tag.
+    pAssetTag->removeAsset( assetId );
+
+    // Find asset Id tag.
+    typeAssetToTagHash::Iterator assetItr = mAssetToTagDatabase.find(assetId);
+
+    // Iterate asset Id tags.
+    while( assetItr != mAssetToTagDatabase.end() && assetItr->key == assetId )
+    {
+        // Is this the asset tag?
+        if ( assetItr->value == pAssetTag )
+        {
+            // Yes, so remove it.
+            mAssetToTagDatabase.erase( assetItr );
+            break;
+        }
+
+        // Next entry.
+        assetItr++;
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AssetTagsManifest::hasTag( const char* pAssetId, const char* pTagName )
+{
+    // Sanity!
+    AssertFatal( pAssetId != NULL, "Cannot use a NULL asset Id." );
+    AssertFatal( pTagName != NULL, "Cannot use a NULL tag name." );
+
+    // Find asset tag.
+    AssetTag* pAssetTag = findAssetTag( pTagName );
+
+    // Does the tag exist?
+    if ( pAssetTag == NULL )
+    {
+        // No, so warn.
+        Con::warnf("AssetTagsManifest: Cannot check if asset Id '%s' has tag name '%s' as tag name does not exist.", pAssetId, pTagName );
+        return false;
+    }
+
+    // Return whether asset Id is tagged.
+    return pAssetTag->containsAsset( StringTable->insert( pAssetId ) );
+}

+ 148 - 0
Engine/source/assets/assetTagsManifest.h

@@ -0,0 +1,148 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _ASSET_TAGS_MANIFEST_H_
+#define _ASSET_TAGS_MANIFEST_H_
+
+#ifndef _SIMBASE_H_
+#include "console/simBase.h"
+#endif
+
+#ifndef _TDICTIONARY_H_
+#include "core/util/tDictionary.h"
+#endif
+
+#ifndef _TVECTOR_H_
+#include "core/util/tvector.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "core/strings/stringUnit.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+#define ASSETTAGS_TAGS_NODE_NAME                "Tags"
+#define ASSETTAGS_TAGS_TYPE_NAME                "Tag"
+#define ASSETTAGS_TAGS_NAME_FIELD               "Name"
+
+#define ASSETTAGS_ASSETS_NODE_NAME              "Assets"
+#define ASSETTAGS_ASSETS_TYPE_NAME              "Tag"
+#define ASSETTAGS_ASSETS_ASSETID_FIELD          "AssetId"
+#define ASSETTAGS_ASSETS_TAG_FIELD              "Name"
+
+//-----------------------------------------------------------------------------
+
+class AssetManager;
+
+//-----------------------------------------------------------------------------
+
+class AssetTagsManifest : public SimObject
+{
+    friend class AssetManager;
+
+private:
+    typedef SimObject Parent;
+    typedef StringTableEntry typeAssetId;
+    typedef StringTableEntry typeAssetTagName;
+
+public:
+    /// Asset location.
+    class AssetTag
+    {
+    public:
+        AssetTag( StringTableEntry tagName )
+        {
+            // Sanity!
+            AssertFatal( tagName != NULL, "Cannot use a NULL tag name." );
+
+            // Case sensitive tag name.
+            mTagName = tagName;
+        }
+
+        bool containsAsset( typeAssetId assetId )
+        {
+            for ( Vector<typeAssetId>::iterator assetIdItr = mAssets.begin(); assetIdItr != mAssets.end(); ++assetIdItr )
+            {
+                if ( *assetIdItr == assetId )
+                    return true;
+            }
+
+            return false;
+        }
+
+        void removeAsset( typeAssetId assetId )
+        {
+            for ( Vector<typeAssetId>::iterator assetIdItr = mAssets.begin(); assetIdItr != mAssets.end(); ++assetIdItr )
+            {
+                if ( *assetIdItr == assetId )
+                {
+                    mAssets.erase( assetIdItr );
+                    return;
+                }
+            }
+        }
+
+        typeAssetTagName mTagName;
+        Vector<typeAssetId> mAssets;
+    };
+
+    /// Asset/Tag database.
+    typedef HashMap<typeAssetTagName, AssetTag*> typeTagNameHash;
+    typedef HashTable<typeAssetId, AssetTag*> typeAssetToTagHash;
+
+private:
+    typeTagNameHash mTagNameDatabase;
+    typeAssetToTagHash mAssetToTagDatabase;
+
+private:
+    StringTableEntry fetchTagName( const char* pTagName );
+    AssetTag* findAssetTag( const char* pTagName );
+    void renameAssetId( const char* pAssetIdFrom, const char* pAssetIdTo );
+
+protected:
+    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
+    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
+
+public:
+    AssetTagsManifest();
+    virtual ~AssetTagsManifest();
+
+    /// Tagging.
+    const AssetTag* createTag( const char* pTagName );
+    bool renameTag( const char* pOldTagName, const char* pNewTagName );
+    bool deleteTag( const char* pTagName );
+    bool isTag( const char* pTagName );
+    inline U32 getTagCount( void ) const { return (U32)mTagNameDatabase.size(); }
+    StringTableEntry getTag( const U32 tagIndex );
+    U32 getAssetTagCount( const char* pAssetId );
+    StringTableEntry getAssetTag( const char* pAssetId, const U32 tagIndex );
+    bool tag( const char* pAssetId, const char* pTagName );
+    bool untag( const char* pAssetId, const char* pTagName );
+    bool hasTag( const char* pAssetId, const char* pTagName );
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( AssetTagsManifest );
+};
+
+#endif // _ASSET_TAGS_MANIFEST_H_
+

+ 151 - 0
Engine/source/assets/assetTagsManifest_ScriptBinding.h

@@ -0,0 +1,151 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+#include "console/engineAPI.h"
+#include "assetTagsManifest.h"
+
+DefineEngineMethod(AssetTagsManifest, createTag, void, (const char* tagName), (""),
+   "Creates an asset tag.\n"
+   "@param tagName The tag name to create.\n"
+   "@return No return value.\n")
+{
+   object->createTag(tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, renameTag, bool, (const char* oldTagName, const char* newTagName),,
+   "Renames an existing asset tag.\n"
+   "@param tagName The tag name to rename.\n"
+   "@param newTagName The new tag name to assign.\n"
+   "@return Whether the asset tag was renamed or not.\n")
+{
+   return object->renameTag(oldTagName, newTagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, deleteTag, bool, (const char* tagName),,
+   "Deletes an asset tag.\n"
+   "@param tagName The tag name to delete.\n"
+   "@return Whether the asset tag was deleted or not.\n")
+{
+   return object->deleteTag(tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, isTag, bool, (const char* tagName),,
+   "Checks whether the specified asset tag exists or not.\n"
+   "@param tagName The tag name to check.\n"
+   "@return Whether the specified asset tag exists or not.\n")
+{
+   return object->isTag(tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getTagCount, S32, (),,
+   "Gets the total asset tag count.\n"
+   "@return The total asset tag count.\n")
+{
+    return object->getTagCount();
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getTag, const char*, (S32 tagIndex),,
+   "Gets the asset tag at the specified index.\n"
+   "@param tagIndex The asset tag index.This must be 0 to the asset tag count less one.\n"
+   "@return The asset tag at the specified index or NULL if invalid.\n")
+{
+    // Is the tag index out-of-bounds?
+    if ( tagIndex >= object->getTagCount() )
+    {
+        // Yes, so warn.
+        Con::warnf( "AssetTagsManifest: Asset tag index '%d' is out of bounds.  Asset tag count is '%d'", tagIndex, object->getTagCount() );
+        return StringTable->EmptyString();
+    }
+
+    return object->getTag( tagIndex );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getAssetTagCount, S32, (const char* assetId),,
+   "Gets the asset tag count on the specified asset Id.\n"
+   "@param assetId The asset Id to count tags on.\n"
+   "@return The asset tag count on the specified asset Id.\n")
+{
+   return object->getAssetTagCount(assetId);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, getAssetTag, const char*, (const char* assetId, S32 tagIndex), ,
+   "Gets the asset tag on the specified asset Id at the specified index.\n"
+   "@param assetId The asset Id to count tags on.\n"
+   "@param tagIndex The asset tag index.This must be 0 to the asset tag count less one.\n"
+   "@return The asset tag on the specified asset Id at the specified index or NULL if invalid.\n")
+{
+   // Is the tag index out-of-bounds?
+   if (tagIndex >= object->getAssetTagCount(assetId))
+   {
+      // Yes, so warn.
+      Con::warnf("AssetTagsManifest: Asset tag index '%d' is out of bounds.  Asset tag count is '%d'", tagIndex, object->getAssetTagCount(assetId));
+      return StringTable->EmptyString();
+   }
+
+   return object->getAssetTag(assetId, tagIndex);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, tag, bool, (const char* assetId, const char* tagName),,
+   "Tags the asset Id with the specified asset tag.\n"
+   "@param assetId The asset Id to tag.\n"
+   "@param tagName The tag name to assign.\n"
+   "@return Whether the tag operation was successful or not.\n")
+{
+   return object->tag(assetId, tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, untag, bool, (const char* assetId, const char* tagName),,
+   "Un-tags the asset Id from the specified asset tag.\n"
+   "@param assetId The asset Id to un - tag.\n"
+   "@param tagName The tag name to un - assign.\n"
+   "@return Whether the un - tag operation was successful or not.\n")
+{
+   return object->untag(assetId, tagName);
+}
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(AssetTagsManifest, hasTag, bool, (const char* assetId, const char* tagName), ,
+   "Checks whether the asset Id is tagged with the specified asset tag.\n"
+   "@param assetId The asset Id to check.\n"
+   "@param tagName The tag name to check.\n"
+   "@return Whether the asset Id is tagged with the specified asset tag or not.\n")
+{
+   return object->hasTag(assetId, tagName);
+}

+ 12 - 0
Engine/source/assets/core.h

@@ -0,0 +1,12 @@
+#ifndef _ASSET_CORE_H_
+#define _ASSET_CORE_H_
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assetDefinition.h"
+#endif
+
+#endif

+ 45 - 0
Engine/source/assets/declaredAssets.cpp

@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _DECLARED_ASSETS_H_
+#include "assets/declaredAssets.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( DeclaredAssets );
+
+//-----------------------------------------------------------------------------
+
+void DeclaredAssets::initPersistFields()
+{
+    // Call Parent.
+    Parent::initPersistFields();
+        
+    addField("Path", TypeString, Offset(mPath, DeclaredAssets), "" );
+    addField("Extension", TypeString, Offset(mExtension, DeclaredAssets), "" );
+    addField("Recurse", TypeBool, Offset(mRecurse, DeclaredAssets), "" );
+}

+ 73 - 0
Engine/source/assets/declaredAssets.h

@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _DECLARED_ASSETS_H_
+#define _DECLARED_ASSETS_H_
+
+#ifndef _SIM_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _SIMOBJECT_H_
+#include "console/simObject.h"
+#endif
+
+#ifndef _CONSOLEOBJECT_H_
+#include "console/consoleObject.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class DeclaredAssets : public SimObject
+{
+    friend class AssetManager;
+
+private:
+    typedef SimObject Parent;
+
+    StringTableEntry    mPath;
+    StringTableEntry    mExtension;
+    bool                mRecurse;
+
+public:
+    DeclaredAssets() :
+        mPath( StringTable->EmptyString() ),
+        mExtension(StringTable->EmptyString()),
+        mRecurse( false )
+        {}
+    virtual ~DeclaredAssets() {}
+
+    static void initPersistFields();
+
+    inline void setPath( const char* pPath )            { mPath = StringTable->insert( pPath ); }
+    inline StringTableEntry getPath( void ) const       { return mPath; }
+    inline void setExtension( const char* pPath )       { mExtension = StringTable->insert( pPath ); }
+    inline StringTableEntry getExtension( void ) const  { return mExtension; }
+    inline void setRecurse( const bool recurse )        { mRecurse = recurse; }
+    inline bool getRecurse( void ) const                { return mRecurse; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( DeclaredAssets );
+};
+
+#endif // _DECLARED_ASSETS_H_
+

+ 45 - 0
Engine/source/assets/referencedAssets.cpp

@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _REFERENCED_ASSETS_H_
+#include "assets/referencedAssets.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT( ReferencedAssets );
+
+//-----------------------------------------------------------------------------
+
+void ReferencedAssets::initPersistFields()
+{
+    // Call Parent.
+    Parent::initPersistFields();
+        
+    addField("Path", TypeString, Offset(mPath, ReferencedAssets), "" );
+    addField("Extension", TypeString, Offset(mExtension, ReferencedAssets), "" );
+    addField("Recurse", TypeBool, Offset(mRecurse, ReferencedAssets), "" );
+}

+ 73 - 0
Engine/source/assets/referencedAssets.h

@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _REFERENCED_ASSETS_H_
+#define _REFERENCED_ASSETS_H_
+
+#ifndef _SIM_H_
+#include "console/sim.h"
+#endif
+
+#ifndef _SIMOBJECT_H_
+#include "console/simObject.h"
+#endif
+
+#ifndef _CONSOLEOBJECT_H_
+#include "console/consoleObject.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+class ReferencedAssets : public SimObject
+{
+    friend class AssetManager;
+
+private:
+    typedef SimObject Parent;
+
+    StringTableEntry    mPath;
+    StringTableEntry    mExtension;
+    bool                mRecurse;
+
+public:
+    ReferencedAssets() :
+        mPath( StringTable->EmptyString() ),
+        mExtension(StringTable->EmptyString()),
+        mRecurse( false )
+        {}
+    virtual ~ReferencedAssets() {}
+
+    static void initPersistFields();
+
+    inline void setPath( const char* pPath )            { mPath = StringTable->insert( pPath ); }
+    inline StringTableEntry getPath( void ) const       { return mPath; }
+    inline void setExtension( const char* pPath )       { mExtension = StringTable->insert( pPath ); }
+    inline StringTableEntry getExtension( void ) const  { return mExtension; }
+    inline void setRecurse( const bool recurse )        { mRecurse = recurse; }
+    inline bool getRecurse( void ) const                { return mRecurse; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( ReferencedAssets );
+};
+
+#endif // _REFERENCED_ASSETS_H_
+

+ 132 - 0
Engine/source/assets/tamlAssetDeclaredUpdateVisitor.h

@@ -0,0 +1,132 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
+#define _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence\/taml/tamlParser.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetDeclaredUpdateVisitor : public TamlVisitor
+{
+private:    
+    StringTableEntry mAssetIdFrom;
+    StringTableEntry mAssetIdTo;
+    StringTableEntry mAssetNameFrom;
+    StringTableEntry mAssetNameTo;
+
+public:
+    TamlAssetDeclaredUpdateVisitor() {}
+    virtual ~TamlAssetDeclaredUpdateVisitor() {}
+
+    void setAssetIdFrom( const char* pAssetIdFrom )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdFrom != NULL, "Asset Id from cannot be NULL." );
+
+        // Reset asset Id.
+        mAssetIdFrom = StringTable->EmptyString();
+        mAssetNameFrom = StringTable->EmptyString();
+
+        // Is asset Id the correct format?
+        if ( StringUnit::getUnitCount( pAssetIdFrom, ASSET_SCOPE_TOKEN ) != 2 )
+        {
+            // No, so warn.
+            Con::warnf( "TamlAssetDeclaredUpdateVisitor::setAssetIdFrom() - Cannot use asset Id '%s' as it is not the correct format.", pAssetIdFrom );
+            return;
+        }
+
+        // Set asset Id.
+        mAssetIdFrom = StringTable->insert( pAssetIdFrom );
+        mAssetNameFrom = StringTable->insert( StringUnit::getUnit( pAssetIdFrom, 1, ASSET_SCOPE_TOKEN ) );
+    }
+    StringTableEntry getAssetIdFrom( void ) const { return mAssetIdFrom; }
+
+    void setAssetIdTo( const char* pAssetIdTo )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdTo != NULL, "Asset Id to cannot be NULL." );
+
+        // Reset asset Id.
+        mAssetIdTo = StringTable->EmptyString();
+        mAssetNameTo = StringTable->EmptyString();
+
+        // Is asset Id the correct format?
+        if ( StringUnit::getUnitCount( pAssetIdTo, ASSET_SCOPE_TOKEN ) != 2 )
+        {
+            // No, so warn.
+            Con::warnf( "TamlAssetDeclaredUpdateVisitor::setAssetIdTo() - Cannot use asset Id '%s' as it is not the correct format.", pAssetIdTo );
+            return;
+        }
+
+        // Set asset Id.
+        mAssetIdTo = StringTable->insert( pAssetIdTo );
+        mAssetNameTo = StringTable->insert( StringUnit::getUnit( pAssetIdTo, 1, ASSET_SCOPE_TOKEN ) );
+    }
+    const char* getAssetIdTo( void ) const { return mAssetIdTo; }
+
+    virtual bool wantsPropertyChanges( void ) { return true; }
+    virtual bool wantsRootOnly( void ) { return true; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetDeclaredUpdateVisitor_Visit);
+
+        // Finish if not the asset name field.
+        if ( propertyState.getPropertyName() != assetNameField )
+            return true;
+
+        // Is this the asset Id we're looking for?
+        if ( dStricmp( propertyState.getPropertyValue(), mAssetNameFrom ) != 0 )
+        {
+            // No, so warn.
+            Con::warnf("Cannot rename asset Name '%s' to asset Name '%s' as the declared asset Name was %s",
+                mAssetNameFrom, mAssetNameTo, propertyState.getPropertyValue() );
+
+            // Stop processing!
+            return false;
+        }
+
+        // Assign new value.
+        propertyState.updatePropertyValue( mAssetNameTo );
+
+        // Stop processing!
+        return false;
+    }
+};
+
+#endif // _TAML_ASSET_DECLARED_UPDATE_VISITOR_H_

+ 189 - 0
Engine/source/assets/tamlAssetDeclaredVisitor.h

@@ -0,0 +1,189 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_DECLARED_VISITOR_H_
+#define _TAML_ASSET_DECLARED_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence\/taml/tamlParser.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+#ifndef _ASSET_DEFINITION_H_
+#include "assetDefinition.h"
+#endif
+
+#ifndef _ASSET_BASE_H_
+#include "assetBase.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetDeclaredVisitor : public TamlVisitor
+{
+public:
+    typedef StringTableEntry typeAssetId;
+    typedef Vector<typeAssetId> typeAssetIdVector;
+    typedef Vector<StringTableEntry> typeLooseFileVector;
+
+private:
+    AssetDefinition         mAssetDefinition;
+    typeAssetIdVector       mAssetDependencies;
+    typeLooseFileVector     mAssetLooseFiles;
+
+public:
+    TamlAssetDeclaredVisitor() { mAssetDefinition.reset(); }
+    virtual ~TamlAssetDeclaredVisitor() {}
+
+
+    inline AssetDefinition& getAssetDefinition( void ) { return mAssetDefinition; }
+    inline typeAssetIdVector& getAssetDependencies( void ) { return mAssetDependencies; }
+    inline typeLooseFileVector& getAssetLooseFiles( void ) { return mAssetLooseFiles; }
+
+    void clear( void ) { mAssetDefinition.reset(); mAssetDependencies.clear(); mAssetLooseFiles.clear(); }
+
+    virtual bool wantsPropertyChanges( void ) { return false; }
+    virtual bool wantsRootOnly( void ) { return false; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {    
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetDeclaredVisitor_Visit);
+
+        // Fetch property name and value.
+        StringTableEntry propertyName = propertyState.getPropertyName();
+        const char* pPropertyValue = propertyState.getPropertyValue();
+
+        // Is this the root object?
+        if ( propertyState.isRootObject() )
+        {
+            // Yes, so is the asset type set yet?
+            if ( mAssetDefinition.mAssetType == StringTable->EmptyString() )
+            {
+                // No, set set asset type and base file-path.
+                mAssetDefinition.mAssetType = propertyState.getObjectName();
+                mAssetDefinition.mAssetBaseFilePath = parser.getParsingFilename();
+            }
+
+            // Asset name?
+            if ( propertyName == assetNameField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetName = StringTable->insert( pPropertyValue );
+                return true;
+            }
+            // Asset description?
+            else if ( propertyName == assetDescriptionField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetDescription = StringTable->insert( pPropertyValue );
+                return true;
+            }
+            // Asset description?
+            else if ( propertyName == assetCategoryField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetCategory = StringTable->insert( pPropertyValue );
+                return true;
+            }
+            // Asset auto-unload?
+            else if ( propertyName == assetAutoUnloadField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetAutoUnload = dAtob( pPropertyValue );
+                return true;
+            }
+            // Asset internal?
+            else if ( propertyName == assetInternalField )
+            {
+                // Yes, so assign it.
+                mAssetDefinition.mAssetInternal = dAtob( pPropertyValue );
+                return true;
+            }
+        }
+
+        // Fetch property word count.
+        const U32 propertyWordCount = StringUnit::getUnitCount( pPropertyValue, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if there's not two words.
+        if ( propertyWordCount != 2 )
+            return true;
+
+        // Fetch the asset signature.
+        StringTableEntry assetSignature = StringTable->insert( StringUnit::getUnit( pPropertyValue, 0, ASSET_ASSIGNMENT_TOKEN ) );
+
+        // Is this an asset Id signature?
+        if ( assetSignature == assetLooseIdSignature )
+        {
+            // Yes, so get asset Id.
+            typeAssetId assetId = StringTable->insert( StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN ) );
+
+            // Finish if the dependency is itself!
+            if ( mAssetDefinition.mAssetId == assetId )
+                return true;
+
+            // Iterate existing dependencies.
+            for( typeAssetIdVector::iterator dependencyItr = mAssetDependencies.begin(); dependencyItr != mAssetDependencies.end(); ++dependencyItr )
+            {
+                // Finish if asset Id is already a dependency.
+                if ( *dependencyItr == assetId )
+                    return true;
+            }
+
+            // Insert asset reference.
+            mAssetDependencies.push_back( assetId );
+        }
+        // Is this a loose-file signature?
+        else if ( assetSignature == assetLooseFileSignature )
+        {
+            // Yes, so get loose-file reference.
+            const char* pAssetLooseFile = StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN );
+
+            // Fetch asset path only.
+            char assetBasePathBuffer[1024];
+            dSprintf( assetBasePathBuffer, sizeof(assetBasePathBuffer), "%s", mAssetDefinition.mAssetBaseFilePath );
+            char* pFinalSlash = dStrrchr( assetBasePathBuffer, '/' );
+            if ( pFinalSlash != NULL ) *pFinalSlash = 0;
+
+            // Expand the path in the usual way.
+            char assetFilePathBuffer[1024];
+            Con::expandPath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetLooseFile, assetBasePathBuffer );
+
+            // Insert asset loose-file.
+            mAssetLooseFiles.push_back( StringTable->insert( assetFilePathBuffer ) );
+        }
+
+        return true;
+    }
+};
+
+#endif // _TAML_ASSET_DECLARED_VISITOR_H_

+ 127 - 0
Engine/source/assets/tamlAssetReferencedUpdateVisitor.h

@@ -0,0 +1,127 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
+#define _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence\/taml/tamlParser.h"
+#endif
+
+#ifndef _STRINGUNIT_H_
+#include "string/stringUnit.h"
+#endif
+
+#ifndef _STRINGTABLE_H_
+#include "string/stringTable.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetReferencedUpdateVisitor : public TamlVisitor
+{
+private:    
+    StringTableEntry mAssetIdFrom;
+    StringTableEntry mAssetIdTo;
+
+public:
+    TamlAssetReferencedUpdateVisitor() {}
+    virtual ~TamlAssetReferencedUpdateVisitor() {}
+
+    void setAssetIdFrom( const char* pAssetIdFrom )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdFrom != NULL, "Asset Id from cannot be NULL." );
+
+        mAssetIdFrom = StringTable->insert( pAssetIdFrom );
+    }
+    StringTableEntry getAssetIdFrom( void ) const { return mAssetIdFrom; }
+
+    void setAssetIdTo( const char* pAssetIdTo )
+    {
+        // Sanity!
+        AssertFatal( pAssetIdTo != NULL, "Asset Id to cannot be NULL." );
+
+        mAssetIdTo = StringTable->insert( pAssetIdTo );
+    }
+    const char* getAssetIdTo( void ) const { return mAssetIdTo; }
+
+    virtual bool wantsPropertyChanges( void ) { return true; }
+    virtual bool wantsRootOnly( void ) { return false; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetReferencedUpdateVisitor_Visit);
+
+        // Fetch the property value.
+        const char* pPropertyValue = propertyState.getPropertyValue();
+
+        // Fetch property value word count.
+        const U32 valueWordCount = StringUnit::getUnitCount( pPropertyValue, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if not two words.
+        if ( valueWordCount != 2 )
+            return true;
+
+        // Finish if this is not an asset signature.
+        if ( dStricmp( StringUnit::getUnit( pPropertyValue, 0, ASSET_ASSIGNMENT_TOKEN), assetLooseIdSignature ) != 0 )
+            return true;
+
+        // Get the asset value.
+        const char* pAssetValue = StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if not the asset Id we're looking for.
+        if ( dStricmp( pAssetValue, mAssetIdFrom ) != 0 )
+            return true;
+
+        // Is the target asset empty?
+        if ( mAssetIdTo == StringTable->EmptyString() )
+        {
+            // Yes, so update the property as empty.
+           propertyState.updatePropertyValue(StringTable->EmptyString());
+            return true;
+        }
+
+        // Format asset.
+        char assetBuffer[1024];
+        dSprintf( assetBuffer, sizeof(assetBuffer), "%s%s%s", assetLooseIdSignature, ASSET_ASSIGNMENT_TOKEN, mAssetIdTo );
+
+        // Assign new value.
+        propertyState.updatePropertyValue( assetBuffer );
+
+        return true;
+    }
+};
+
+#endif // _TAML_ASSET_REFERENCED_UPDATE_VISITOR_H_

+ 96 - 0
Engine/source/assets/tamlAssetReferencedVisitor.h

@@ -0,0 +1,96 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#ifndef _TAML_ASSET_REFERENCED_VISITOR_H_
+#define _TAML_ASSET_REFERENCED_VISITOR_H_
+
+#ifndef _TAML_VISITOR_H_
+#include "persistence/taml/tamlVisitor.h"
+#endif
+
+#ifndef _TAML_PARSER_H_
+#include "persistence/taml/tamlParser.h"
+#endif
+
+#ifndef _ASSET_FIELD_TYPES_H_
+#include "assets/assetFieldTypes.h"
+#endif
+
+// Debug Profiling.
+#include "platform/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+class TamlAssetReferencedVisitor : public TamlVisitor
+{
+public:
+    typedef StringTableEntry typeAssetId;
+    typedef HashMap<typeAssetId, StringTableEntry> typeAssetReferencedHash;
+
+private:
+    typeAssetReferencedHash mAssetReferenced;
+
+public:
+    TamlAssetReferencedVisitor() {}
+    virtual ~TamlAssetReferencedVisitor() {}
+
+    const typeAssetReferencedHash& getAssetReferencedMap( void ) const { return mAssetReferenced; }
+
+    void clear( void ) { mAssetReferenced.clear(); }
+
+    virtual bool wantsPropertyChanges( void ) { return false; }
+    virtual bool wantsRootOnly( void ) { return false; }
+
+    virtual bool visit( const TamlParser& parser, TamlVisitor::PropertyState& propertyState )
+    {    
+        // Debug Profiling.
+        PROFILE_SCOPE(TamlAssetReferencedVisitor_Visit);
+
+        // Fetch property value.
+        const char* pPropertyValue = propertyState.getPropertyValue();
+
+        // Fetch property word count.
+        const U32 propertyWordCount = StringUnit::getUnitCount( pPropertyValue, ASSET_ASSIGNMENT_TOKEN );
+
+        // Finish if there's not two words.
+        if ( propertyWordCount != 2 )
+            return true;
+
+        // Finish if the first word is not an asset signature.
+        if ( StringTable->insert( StringUnit::getUnit( pPropertyValue, 0, ASSET_ASSIGNMENT_TOKEN ) ) != assetLooseIdSignature )
+            return true;
+
+        // Get asset Id.
+        typeAssetId assetId = StringTable->insert( StringUnit::getUnit( pPropertyValue, 1, ASSET_ASSIGNMENT_TOKEN ) );
+
+        // Finish if we already have this asset Id.
+        if ( mAssetReferenced.contains( assetId ) )
+            return true;
+
+        // Insert asset reference.
+        mAssetReferenced.insert( assetId, StringTable->EmptyString() );
+
+        return true;
+    }
+};
+
+#endif // _TAML_ASSET_REFERENCED_VISITOR_H_

+ 3 - 2
Engine/source/cinterface/c_scripting.cpp

@@ -76,9 +76,10 @@ extern "C" {
       if (!entry)
          return "";
 
-      ConsoleValueRef argv[] = {"consoleExportXML"};
+      static const char* exportArgv[1] = { "consoleExportXML" };
+      static StringStackConsoleWrapper exportCmd(1, exportArgv);
 
-      return entry->cb.mStringCallbackFunc(NULL, 1, argv);      
+      return entry->cb.mStringCallbackFunc(NULL, exportCmd.argc, exportCmd.argv);      
    }
 
    MarshalNativeEntry* script_get_namespace_entry(const char* nameSpace, const char* name)

+ 1 - 1
Engine/source/collision/boxConvex.cpp

@@ -76,7 +76,7 @@ Point3F BoxConvex::getVertex(S32 v)
    return p;
 }
 
-inline bool isOnPlane(Point3F p,PlaneF& plane)
+inline bool isOnPlane(const Point3F& p,PlaneF& plane)
 {
    F32 dist = mDot(plane,p) + plane.d;
    return dist < 0.1 && dist > -0.1;

+ 136 - 146
Engine/source/console/CMDscan.cpp

@@ -302,7 +302,7 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
 
 #define YY_NUM_RULES 94
 #define YY_END_OF_BUFFER 95
-static yyconst short int yy_accept[233] =
+static yyconst short int yy_accept[224] =
     {   0,
         0,    0,   95,   93,    1,    5,    4,   51,   93,   93,
        58,   57,   93,   41,   42,   45,   43,   56,   44,   50,
@@ -320,16 +320,15 @@ static yyconst short int yy_accept[233] =
        92,   87,    0,   32,    3,    3,   91,    0,   91,   89,
        29,   30,   35,   34,   88,   88,   88,   88,   88,   88,
        88,   88,   73,   88,   88,   76,   88,   88,   88,   88,
-       88,   88,   92,    0,    2,    2,   88,   88,   79,   88,
+       88,   88,   92,    0,    3,    2,   88,   88,   79,   88,
        88,   88,   66,   88,   88,   88,   88,   88,   88,   88,
-       88,   85,   88,    2,    2,    2,    2,    2,   88,   64,
-       88,   88,   88,   86,   88,   88,   88,   88,   88,   88,
-       88,   68,    0,    2,    2,   67,   88,   88,   88,   88,
-
-       88,   88,   88,   65,   88,   81,    0,    2,    2,   88,
-       88,   82,   72,   88,   88,   83,   88,   80,    0,    2,
-        2,    2,   74,   88,   71,   75,   88,   88,   78,   84,
-       77,    0
+       88,   85,   88,    3,    0,   88,   64,   88,   88,   88,
+       86,   88,   88,   88,   88,   88,   88,   88,   68,    0,
+       67,   88,   88,   88,   88,   88,   88,   88,   65,   88,
+
+       81,    0,   88,   88,   82,   72,   88,   88,   83,   88,
+       80,    0,   74,   88,   71,   75,   88,   88,    0,   78,
+       84,   77,    0
     } ;
 
 static yyconst int yy_ec[256] =
@@ -375,69 +374,67 @@ static yyconst int yy_meta[68] =
         7,    7,    7,    1,    1,    1,    1
     } ;
 
-static yyconst short int yy_base[248] =
+static yyconst short int yy_base[237] =
     {   0,
-        0,    0,  380,  381,  377,  381,  381,   61,   63,   51,
-       53,   65,   66,  381,  381,  354,   64,  381,   66,   60,
-       68,   76,   80,  356,  381,   60,  352,   77,  381,  381,
-        0,  341,  338,  345,  381,  381,  348,  311,  311,   54,
-       61,  315,   59,   38,   62,  309,  323,  318,   62,  306,
-      313,  381,   89,  381,  381,  361,  338,  381,  111,  381,
-      357,  100,  381,  339,  381,  381,  381,  112,  381,  355,
-      381,  381,  381,  333,  381,  381,  107,  381,  339,  381,
-      110,  114,  121,    0,  381,  332,  381,  381,  381,  331,
-        0,    0,  324,  324,  381,  292,  303,  290,  293,  287,
-
-      298,    0,  286,  291,  285,  287,    0,    0,  287,  278,
-        0,  294,  278,  282,  285,  274,  283,  381,  381,  381,
-      313,  312,  311,  381,    0,  139,  119,  125,  128,    0,
-      381,  381,    0,    0,  283,  286,  281,  267,  283,  282,
-      277,  264,  275,  276,  273,    0,  267,  257,  268,  256,
-      268,  261,  293,  292,  146,  152,  253,  258,    0,  258,
-      264,  246,    0,  259,  262,  244,  244,  259,  243,  247,
-      254,    0,  251,  155,  157,  162,  165,  168,  237,    0,
-      241,  242,  241,    0,  248,  241,  230,  199,  185,  190,
-      183,    0,  215,  173,  175,    0,  168,  172,  161,  167,
-
-      154,  164,  159,    0,  145,  198,  185,  178,  181,  153,
-      154,    0,  191,  141,  146,    0,  117,  381,    0,  184,
-      186,  191,    0,  110,  381,    0,   88,   76,    0,    0,
-        0,  381,  209,  213,  220,  224,  228,  232,  239,  119,
-      243,  250,  257,  264,  271,  278,  285
+        0,    0,  337,  338,  334,  338,  338,   61,   63,   51,
+       53,   65,   66,  338,  338,  311,   64,  338,   66,   60,
+       68,   76,   80,  313,  338,   60,  309,   77,  338,  338,
+        0,  298,  295,  302,  338,  338,  305,  268,  268,   54,
+       61,  272,   59,   38,   62,  266,  280,  275,   62,  263,
+      270,  338,   89,  338,  338,  318,  295,  338,  111,  338,
+      314,  100,  338,  296,  338,  338,  338,  112,  338,  312,
+      338,  338,  338,  290,  338,  338,  107,  338,  296,  338,
+      110,  114,  121,    0,  338,  289,  338,  338,  338,  288,
+        0,    0,  281,  281,  338,  249,  260,  247,  250,  244,
+
+      255,    0,  243,  248,  242,  244,    0,    0,  244,  235,
+        0,  251,  235,  239,  242,  231,  240,  338,  338,  338,
+      270,  269,  268,  338,    0,  139,  119,  125,  128,    0,
+      338,  338,    0,    0,  240,  243,  238,  224,  240,  239,
+      234,  221,  232,  233,  230,    0,  224,  214,  225,  213,
+      225,  218,  250,  249,  146,  152,  210,  215,    0,  215,
+      221,  203,    0,  216,  219,  201,  201,  216,  200,  204,
+      211,    0,  208,  155,  237,  193,    0,  197,  198,  197,
+        0,  204,  197,  190,  197,  190,  197,  193,    0,  225,
+        0,  180,  184,  179,  177,  153,  158,  151,    0,  134,
+
+      187,  157,  143,  144,    0,  176,  123,  126,    0,  112,
+      338,  160,    0,  115,  338,    0,   88,   76,  162,    0,
+        0,    0,  338,  170,  174,  181,  185,  189,  193,  200,
+      119,  204,  211,  218,  225,  232
     } ;
 
-static yyconst short int yy_def[248] =
+static yyconst short int yy_def[237] =
     {   0,
-      232,    1,  232,  232,  232,  232,  232,  232,  233,  234,
-      234,  232,  235,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      236,  236,  236,  236,  232,  232,  232,  236,  236,  236,
-      236,  236,  236,  236,  236,  236,  236,  236,  236,  236,
-      236,  232,  232,  232,  232,  232,  232,  232,  233,  232,
-      233,  237,  232,  238,  232,  232,  232,  235,  232,  235,
-      232,  232,  232,  232,  232,  232,  232,  232,  239,  232,
-      232,  232,  232,  240,  232,  232,  232,  232,  232,  232,
-      236,  236,  236,  236,  232,  236,  236,  236,  236,  236,
-
-      236,  236,  236,  236,  236,  236,  236,  236,  236,  236,
-      236,  236,  236,  236,  236,  236,  236,  232,  232,  232,
-      241,  238,  238,  232,  239,  242,  232,  232,  232,  240,
-      232,  232,  236,  236,  236,  236,  236,  236,  236,  236,
-      236,  236,  236,  236,  236,  236,  236,  236,  236,  236,
-      236,  236,  241,  241,  243,  244,  236,  236,  236,  236,
-      236,  236,  236,  236,  236,  236,  236,  236,  236,  236,
-      236,  236,  236,  243,  232,  243,  244,  244,  236,  236,
-      236,  236,  236,  236,  236,  236,  236,  236,  236,  236,
-      236,  236,  232,  243,  244,  236,  236,  236,  236,  236,
-
-      236,  236,  236,  236,  236,  236,  232,  245,  246,  236,
-      236,  236,  236,  236,  236,  236,  236,  232,  247,  243,
-      244,  244,  236,  236,  232,  236,  236,  236,  236,  236,
-      236,    0,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232
+      223,    1,  223,  223,  223,  223,  223,  223,  224,  225,
+      225,  223,  226,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      227,  227,  227,  227,  223,  223,  223,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  223,  223,  223,  223,  223,  223,  223,  224,  223,
+      224,  228,  223,  229,  223,  223,  223,  226,  223,  226,
+      223,  223,  223,  223,  223,  223,  223,  223,  230,  223,
+      223,  223,  223,  231,  223,  223,  223,  223,  223,  223,
+      227,  227,  227,  227,  223,  227,  227,  227,  227,  227,
+
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  223,  223,  223,
+      232,  229,  229,  223,  230,  233,  223,  223,  223,  231,
+      223,  223,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  232,  232,  234,  223,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+      227,  227,  227,  234,  223,  227,  227,  227,  227,  227,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  223,
+      227,  227,  227,  227,  227,  227,  227,  227,  227,  227,
+
+      227,  235,  227,  227,  227,  227,  227,  227,  227,  227,
+      223,  236,  227,  227,  223,  227,  227,  227,  236,  227,
+      227,  227,    0,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223
     } ;
 
-static yyconst short int yy_nxt[449] =
+static yyconst short int yy_nxt[406] =
     {   0,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
        14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
@@ -453,44 +450,40 @@ static yyconst short int yy_nxt[449] =
        89,   90,  104,   61,  100,  109,   70,   83,  101,  110,
        99,   83,  118,  114,   84,  105,   60,  102,   62,   62,
       106,   69,  130,   83,  115,   77,   77,   83,  127,  127,
-       81,  231,   82,   82,  128,  230,  128,  127,  127,  129,
-      129,  156,  156,  129,  129,   83,  129,  129,  175,  175,
-       83,   61,   70,  119,  175,  175,  125,  175,  175,  175,
-      175,   83,  229,  176,  175,  175,   83,  175,  175,  178,
-      175,  175,  176,  228,  193,  175,  175,  175,  175,  194,
-      221,  221,  178,  221,  221,  195,  175,  175,  175,  175,
-      208,  227,  209,  175,  175,  208,  226,  225,  209,  224,
-
-      223,  176,  219,  178,  218,  217,  216,  215,  178,   59,
-      214,   59,   59,   59,   59,   59,   64,  213,   64,   64,
-       68,  212,   68,   68,   68,   68,   68,   91,  211,  210,
-       91,  121,  207,  206,  121,  122,  122,  205,  122,  125,
-      204,  125,  125,  125,  125,  125,  153,  153,  203,  153,
-      155,  155,  155,  155,  155,  155,  155,  174,  174,  174,
-      174,  174,  174,  174,  177,  177,  177,  177,  177,  177,
-      177,  220,  220,  220,  220,  220,  220,  220,  222,  222,
-      222,  222,  222,  222,  222,  156,  156,  202,  156,  156,
-      156,  156,  201,  200,  199,  198,  197,  196,  192,  191,
-
-      190,  189,  188,  187,  186,  185,  184,  183,  182,  181,
-      180,  179,  154,  154,  173,  172,  171,  170,  169,  168,
-      167,  166,  165,  164,  163,  162,  161,  160,  159,  158,
-      157,  123,  123,  154,  152,  151,  150,  149,  148,  147,
-      146,  145,  144,  143,  142,  141,  140,  139,  138,  137,
-      136,  135,  134,  133,  132,  131,  126,  124,   68,  123,
-       59,  120,   56,  117,  116,  113,  112,  111,  103,   97,
-       96,   95,   94,   93,   92,   88,   85,   71,   56,  232,
-        3,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232
+       81,  222,   82,   82,  128,  221,  128,  127,  127,  129,
+      129,  156,  156,  129,  129,   83,  129,  129,  156,  156,
+       83,   61,   70,  119,  156,  156,  125,  156,  156,  156,
+      156,   83,  156,  156,  156,  156,   83,  220,  218,  175,
+       59,  217,   59,   59,   59,   59,   59,   64,  216,   64,
+       64,   68,  215,   68,   68,   68,   68,   68,   91,  214,
+      213,   91,  121,  211,  210,  121,  122,  122,  209,  122,
+
+      125,  208,  125,  125,  125,  125,  125,  153,  153,  207,
+      153,  155,  155,  155,  155,  155,  155,  155,  174,  174,
+      174,  174,  174,  174,  174,  212,  212,  206,  212,  212,
+      212,  212,  219,  219,  219,  219,  219,  219,  219,  205,
+      204,  203,  202,  201,  200,  199,  198,  197,  196,  195,
+      194,  193,  192,  191,  190,  189,  188,  187,  186,  185,
+      184,  183,  182,  181,  180,  179,  178,  177,  176,  154,
+      154,  173,  172,  171,  170,  169,  168,  167,  166,  165,
+      164,  163,  162,  161,  160,  159,  158,  157,  123,  123,
+      154,  152,  151,  150,  149,  148,  147,  146,  145,  144,
+
+      143,  142,  141,  140,  139,  138,  137,  136,  135,  134,
+      133,  132,  131,  126,  124,   68,  123,   59,  120,   56,
+      117,  116,  113,  112,  111,  103,   97,   96,   95,   94,
+       93,   92,   88,   85,   71,   56,  223,    3,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+
+      223,  223,  223,  223,  223
     } ;
 
-static yyconst short int yy_chk[449] =
+static yyconst short int yy_chk[406] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -505,42 +498,38 @@ static yyconst short int yy_chk[449] =
 
        28,   28,   43,    9,   41,   45,   13,   22,   41,   45,
        40,   23,   53,   49,   22,   43,   59,   41,   62,   62,
-       43,   68,  240,   22,   49,   77,   77,   23,   81,   81,
-       82,  228,   82,   82,   83,  227,   83,  127,  127,   83,
+       43,   68,  231,   22,   49,   77,   77,   23,   81,   81,
+       82,  218,   82,   82,   83,  217,   83,  127,  127,   83,
        83,  126,  126,  128,  128,   82,  129,  129,  155,  155,
-      127,   59,   68,   53,  156,  156,  126,  174,  174,  175,
-      175,   82,  224,  155,  176,  176,  127,  177,  177,  156,
-      178,  178,  174,  217,  175,  194,  194,  195,  195,  176,
-      208,  208,  177,  209,  209,  178,  220,  220,  221,  221,
-      194,  215,  195,  222,  222,  208,  214,  213,  209,  211,
-
-      210,  220,  207,  221,  206,  205,  203,  202,  222,  233,
-      201,  233,  233,  233,  233,  233,  234,  200,  234,  234,
-      235,  199,  235,  235,  235,  235,  235,  236,  198,  197,
-      236,  237,  193,  191,  237,  238,  238,  190,  238,  239,
-      189,  239,  239,  239,  239,  239,  241,  241,  188,  241,
-      242,  242,  242,  242,  242,  242,  242,  243,  243,  243,
-      243,  243,  243,  243,  244,  244,  244,  244,  244,  244,
-      244,  245,  245,  245,  245,  245,  245,  245,  246,  246,
-      246,  246,  246,  246,  246,  247,  247,  187,  247,  247,
-      247,  247,  186,  185,  183,  182,  181,  179,  173,  171,
-
-      170,  169,  168,  167,  166,  165,  164,  162,  161,  160,
-      158,  157,  154,  153,  152,  151,  150,  149,  148,  147,
-      145,  144,  143,  142,  141,  140,  139,  138,  137,  136,
-      135,  123,  122,  121,  117,  116,  115,  114,  113,  112,
-      110,  109,  106,  105,  104,  103,  101,  100,   99,   98,
-       97,   96,   94,   93,   90,   86,   79,   74,   70,   64,
-       61,   57,   56,   51,   50,   48,   47,   46,   42,   39,
-       38,   37,   34,   33,   32,   27,   24,   16,    5,    3,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232,  232,  232,
-      232,  232,  232,  232,  232,  232,  232,  232
+      127,   59,   68,   53,  156,  156,  126,  174,  174,  202,
+      202,   82,  212,  212,  219,  219,  127,  214,  210,  156,
+      224,  208,  224,  224,  224,  224,  224,  225,  207,  225,
+      225,  226,  206,  226,  226,  226,  226,  226,  227,  204,
+      203,  227,  228,  201,  200,  228,  229,  229,  198,  229,
+
+      230,  197,  230,  230,  230,  230,  230,  232,  232,  196,
+      232,  233,  233,  233,  233,  233,  233,  233,  234,  234,
+      234,  234,  234,  234,  234,  235,  235,  195,  235,  235,
+      235,  235,  236,  236,  236,  236,  236,  236,  236,  194,
+      193,  192,  190,  188,  187,  186,  185,  184,  183,  182,
+      180,  179,  178,  176,  175,  173,  171,  170,  169,  168,
+      167,  166,  165,  164,  162,  161,  160,  158,  157,  154,
+      153,  152,  151,  150,  149,  148,  147,  145,  144,  143,
+      142,  141,  140,  139,  138,  137,  136,  135,  123,  122,
+      121,  117,  116,  115,  114,  113,  112,  110,  109,  106,
+
+      105,  104,  103,  101,  100,   99,   98,   97,   96,   94,
+       93,   90,   86,   79,   74,   70,   64,   61,   57,   56,
+       51,   50,   48,   47,   46,   42,   39,   38,   37,   34,
+       33,   32,   27,   24,   16,    5,    3,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+
+      223,  223,  223,  223,  223
     } ;
 
 static yy_state_type yy_last_accepting_state;
@@ -642,7 +631,7 @@ void CMDerror(char * s, ...);
 // Reset the parser.
 void CMDrestart(FILE *in);
 
-#line 646 "CMDscan.cpp"
+#line 635 "CMDscan.cpp"
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -792,7 +781,7 @@ YY_DECL
 #line 105 "CMDscan.l"
 
          ;
-#line 796 "CMDscan.cpp"
+#line 785 "CMDscan.cpp"
 
 	if ( yy_init )
 		{
@@ -843,13 +832,13 @@ yy_match:
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 233 )
+				if ( yy_current_state >= 224 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			++yy_cp;
 			}
-		while ( yy_base[yy_current_state] != 381 );
+		while ( yy_base[yy_current_state] != 338 );
 
 yy_find_action:
 		yy_act = yy_accept[yy_current_state];
@@ -1298,7 +1287,7 @@ YY_RULE_SETUP
 #line 222 "CMDscan.l"
 ECHO;
 	YY_BREAK
-#line 1302 "CMDscan.cpp"
+#line 1291 "CMDscan.cpp"
 case YY_STATE_EOF(INITIAL):
 	yyterminate();
 
@@ -1587,7 +1576,7 @@ static yy_state_type yy_get_previous_state()
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 233 )
+			if ( yy_current_state >= 224 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1622,11 +1611,11 @@ yy_state_type yy_current_state;
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 233 )
+		if ( yy_current_state >= 224 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 232);
+	yy_is_jam = (yy_current_state == 223);
 
 	return yy_is_jam ? 0 : yy_current_state;
 	}
@@ -2190,6 +2179,7 @@ void CMDerror(char *format, ...)
 #else
    vsnprintf( tempBuf, BUFMAX, format, args );
 #endif
+    va_end(args);
 
    if(fileName)
    {

+ 2 - 1
Engine/source/console/CMDscan.l

@@ -105,7 +105,7 @@ HEXDIGIT [a-fA-F0-9]
 %%
          ;
 {SPACE}+ { }
-("///"[^/][^\n\r]*[\n\r]*)+ { return(Sc_ScanDocBlock()); }
+("///"([^/\n\r][^\n\r]*)?[\n\r]+)+ { return(Sc_ScanDocBlock()); }
 "//"[^\n\r]*   ;
 [\r]        ;
 [\n]        {lineIndex++;}
@@ -250,6 +250,7 @@ void CMDerror(char *format, ...)
 #else
    vsnprintf( tempBuf, BUFMAX, format, args );
 #endif
+    va_end(args);
 
    if(fileName)
    {

Vissa filer visades inte eftersom för många filer har ändrats