فهرست منبع

Merge pull request #2182 from Areloch/AssetBrowser_Initial

Asset browser initial
Areloch 7 سال پیش
والد
کامیت
963739102c
100فایلهای تغییر یافته به همراه7830 افزوده شده و 437 حذف شده
  1. 24 14
      Engine/source/T3D/assets/ComponentAsset.cpp
  2. 13 8
      Engine/source/T3D/assets/ComponentAsset.h
  3. 3 8
      Engine/source/T3D/assets/ExampleAsset.cpp
  4. 0 5
      Engine/source/T3D/assets/ExampleAsset.h
  5. 222 0
      Engine/source/T3D/assets/GUIAsset.cpp
  6. 89 0
      Engine/source/T3D/assets/GUIAsset.h
  7. 93 9
      Engine/source/T3D/assets/GameObjectAsset.cpp
  8. 23 7
      Engine/source/T3D/assets/GameObjectAsset.h
  9. 161 0
      Engine/source/T3D/assets/ImageAsset.cpp
  10. 90 0
      Engine/source/T3D/assets/ImageAsset.h
  11. 126 0
      Engine/source/T3D/assets/LevelAsset.cpp
  12. 72 0
      Engine/source/T3D/assets/LevelAsset.h
  13. 241 0
      Engine/source/T3D/assets/MaterialAsset.cpp
  14. 101 0
      Engine/source/T3D/assets/MaterialAsset.h
  15. 205 0
      Engine/source/T3D/assets/ParticleAsset.cpp
  16. 89 0
      Engine/source/T3D/assets/ParticleAsset.h
  17. 129 0
      Engine/source/T3D/assets/PostEffectAsset.cpp
  18. 71 0
      Engine/source/T3D/assets/PostEffectAsset.h
  19. 137 0
      Engine/source/T3D/assets/ScriptAsset.cpp
  20. 69 0
      Engine/source/T3D/assets/ScriptAsset.h
  21. 131 0
      Engine/source/T3D/assets/ShapeAnimationAsset.cpp
  22. 102 0
      Engine/source/T3D/assets/ShapeAnimationAsset.h
  23. 212 20
      Engine/source/T3D/assets/ShapeAsset.cpp
  24. 48 6
      Engine/source/T3D/assets/ShapeAsset.h
  25. 141 0
      Engine/source/T3D/assets/SoundAsset.cpp
  26. 75 0
      Engine/source/T3D/assets/SoundAsset.h
  27. 207 0
      Engine/source/T3D/assets/stateMachineAsset.cpp
  28. 89 0
      Engine/source/T3D/assets/stateMachineAsset.h
  29. 37 49
      Engine/source/T3D/components/animation/animationComponent.cpp
  30. 421 0
      Engine/source/T3D/components/audio/SoundComponent.cpp
  31. 129 0
      Engine/source/T3D/components/audio/SoundComponent.h
  32. 8 3
      Engine/source/T3D/components/camera/cameraComponent.cpp
  33. 0 2
      Engine/source/T3D/components/collision/collisionComponent.cpp
  34. 22 15
      Engine/source/T3D/components/component.cpp
  35. 18 3
      Engine/source/T3D/components/component.h
  36. 0 1
      Engine/source/T3D/components/game/stateMachineComponent.cpp
  37. 2 2
      Engine/source/T3D/components/physics/rigidBodyComponent.cpp
  38. 237 134
      Engine/source/T3D/components/render/meshComponent.cpp
  39. 25 16
      Engine/source/T3D/components/render/meshComponent.h
  40. 29 1
      Engine/source/T3D/components/render/meshComponent_ScriptBinding.h
  41. 265 58
      Engine/source/T3D/entity.cpp
  42. 37 6
      Engine/source/T3D/entity.h
  43. 30 0
      Engine/source/T3D/systems/componentSystem.h
  44. 375 0
      Engine/source/T3D/systems/render/meshRenderSystem.cpp
  45. 207 0
      Engine/source/T3D/systems/render/meshRenderSystem.h
  46. 34 0
      Engine/source/T3D/systems/updateSystem.cpp
  47. 16 0
      Engine/source/T3D/systems/updateSystem.h
  48. 1 1
      Engine/source/assets/assetBase.cpp
  49. 1 0
      Engine/source/assets/assetBase.h
  50. 28 0
      Engine/source/assets/assetManager.cpp
  51. 13 8
      Engine/source/assets/assetManager.h
  52. 25 2
      Engine/source/gui/containers/guiDragAndDropCtrl.cpp
  53. 5 1
      Engine/source/gui/containers/guiDragAndDropCtrl.h
  54. 21 0
      Engine/source/gui/controls/guiTreeViewCtrl.cpp
  55. 2 0
      Engine/source/gui/controls/guiTreeViewCtrl.h
  56. 6 2
      Engine/source/gui/editor/guiInspector.cpp
  57. 22 1
      Engine/source/gui/editor/guiMenuBar.cpp
  58. 1 0
      Engine/source/gui/editor/guiMenuBar.h
  59. 13 6
      Engine/source/gui/editor/guiPopupMenuCtrl.cpp
  60. 1 0
      Engine/source/gui/editor/inspector/variableField.h
  61. 3 0
      Engine/source/gui/editor/inspector/variableGroup.cpp
  62. 7 0
      Engine/source/gui/editor/inspector/variableInspector.cpp
  63. 2 0
      Engine/source/module/moduleDefinition.cpp
  64. 103 2
      Engine/source/module/moduleManager.cpp
  65. 7 1
      Engine/source/module/moduleManager.h
  66. 45 0
      Engine/source/module/moduleManager_ScriptBinding.h
  67. 14 3
      Engine/source/platform/nativeDialogs/fileDialog.cpp
  68. 1 0
      Engine/source/platform/nativeDialogs/fileDialog.h
  69. 5 0
      Engine/source/scene/sceneManager.cpp
  70. 0 11
      Engine/source/scene/sceneRenderState.cpp
  71. 10 0
      Templates/BaseGame/game/core/CoreComponents.cs
  72. 3 0
      Templates/BaseGame/game/core/CoreComponents.module
  73. 2 2
      Templates/BaseGame/game/core/components/game/camera.asset.taml
  74. 2 2
      Templates/BaseGame/game/core/components/game/controlObject.asset.taml
  75. 2 2
      Templates/BaseGame/game/core/components/game/itemRotate.asset.taml
  76. 2 2
      Templates/BaseGame/game/core/components/game/playerSpawner.asset.taml
  77. 206 2
      Templates/BaseGame/game/core/helperFunctions.cs
  78. 1 1
      Templates/BaseGame/game/data/clientServer/ClientServer.cs
  79. 11 3
      Templates/BaseGame/game/data/clientServer/scripts/server/server.cs
  80. 50 18
      Templates/BaseGame/game/data/ui/scripts/chooseLevelDlg.cs
  81. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/animationIcon.png
  82. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/clientScriptIcon.png
  83. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/componentIcon.png
  84. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/gameObjectIcon.png
  85. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/guiIcon.png
  86. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/levelIcon.png
  87. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/materialIcon.png
  88. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/postEffectIcon.png
  89. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/scriptIcon.png
  90. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/serverScriptIcon.png
  91. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/soundIcon.png
  92. BIN
      Templates/BaseGame/game/tools/assetBrowser/art/stateMachineIcon.png
  93. 18 0
      Templates/BaseGame/game/tools/assetBrowser/assetImportConfigs.xml
  94. 217 0
      Templates/BaseGame/game/tools/assetBrowser/guis/GameObjectCreator.gui
  95. 142 0
      Templates/BaseGame/game/tools/assetBrowser/guis/addModuleWindow.gui
  96. 142 0
      Templates/BaseGame/game/tools/assetBrowser/guis/addPackageWindow.gui
  97. 934 0
      Templates/BaseGame/game/tools/assetBrowser/guis/assetBrowser.gui
  98. 613 0
      Templates/BaseGame/game/tools/assetBrowser/guis/assetImport.gui
  99. 147 0
      Templates/BaseGame/game/tools/assetBrowser/guis/editAsset.gui
  100. 147 0
      Templates/BaseGame/game/tools/assetBrowser/guis/editModule.gui

+ 24 - 14
Engine/source/T3D/assets/ComponentAsset.cpp

@@ -74,7 +74,7 @@ ConsoleSetType(TypeComponentAssetPtr)
       if (pAssetPtr == NULL)
       {
          // No, so fail.
-         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         //Con::warnf("(TypeComponentAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
          return;
       }
 
@@ -85,24 +85,20 @@ ConsoleSetType(TypeComponentAssetPtr)
    }
 
    // Warn.
-   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+   Con::warnf("(TypeComponentAssetPtr) - Cannot set multiple args to a single asset.");
 }
 
 //-----------------------------------------------------------------------------
 
-ComponentAsset::ComponentAsset() :
-   mpOwningAssetManager(NULL),
-   mAssetInitialized(false),
-   mAcquireReferenceCount(0)
+ComponentAsset::ComponentAsset()
 {
-   // Generate an asset definition.
-   mpAssetDefinition = new AssetDefinition();
-
-   mComponentName = StringTable->lookup("");
-   mComponentClass = StringTable->lookup("");
-   mFriendlyName = StringTable->lookup("");
-   mComponentType = StringTable->lookup("");
-   mDescription = StringTable->lookup("");
+   mComponentName = StringTable->EmptyString();
+   mComponentClass = StringTable->EmptyString();
+   mFriendlyName = StringTable->EmptyString();
+   mComponentType = StringTable->EmptyString();
+   mDescription = StringTable->EmptyString();
+
+   mScriptFile = StringTable->EmptyString();
 }
 
 //-----------------------------------------------------------------------------
@@ -127,6 +123,8 @@ void ComponentAsset::initPersistFields()
    addField("friendlyName", TypeString, Offset(mFriendlyName, ComponentAsset), "The human-readble name for the component.");
    addField("componentType", TypeString, Offset(mComponentType, ComponentAsset), "The category of the component for organizing in the editor.");
    addField("description", TypeString, Offset(mDescription, ComponentAsset), "Simple description of the component.");
+
+   addField("scriptFile", TypeString, Offset(mScriptFile, ComponentAsset), "A script file with additional scripted functionality for this component.");
 }
 
 //------------------------------------------------------------------------------
@@ -135,4 +133,16 @@ void ComponentAsset::copyTo(SimObject* object)
 {
    // Call to parent.
    Parent::copyTo(object);
+}
+
+void ComponentAsset::initializeAsset()
+{
+   if(Platform::isFile(mScriptFile))
+      Con::executeFile(mScriptFile, false, false);
+}
+
+void ComponentAsset::onAssetRefresh()
+{
+   if (Platform::isFile(mScriptFile))
+      Con::executeFile(mScriptFile, false, false);
 }

+ 13 - 8
Engine/source/T3D/assets/ComponentAsset.h

@@ -44,17 +44,14 @@ class ComponentAsset : public AssetBase
 {
    typedef AssetBase Parent;
 
-   AssetManager*           mpOwningAssetManager;
-   bool                    mAssetInitialized;
-   AssetDefinition*        mpAssetDefinition;
-   U32                     mAcquireReferenceCount;
-
    StringTableEntry mComponentName;
    StringTableEntry mComponentClass;
    StringTableEntry mFriendlyName;
    StringTableEntry mComponentType;
    StringTableEntry mDescription;
 
+   StringTableEntry mScriptFile;
+
 public:
    ComponentAsset();
    virtual ~ComponentAsset();
@@ -69,12 +66,20 @@ public:
    StringTableEntry getComponentName() { return mComponentName; }
    StringTableEntry getComponentClass() { return mComponentClass; }
    StringTableEntry getFriendlyName() { return mFriendlyName; }
-   StringTableEntry getFriendlyType() { return mComponentType; }
+   StringTableEntry getComponentType() { return mComponentType; }
    StringTableEntry getDescription() { return mDescription; }
 
+   void setComponentName(StringTableEntry name) { mComponentName = name; }
+   void setComponentClass(StringTableEntry name) { mComponentClass = name; }
+   void setFriendlyName(StringTableEntry name) { mFriendlyName = name; }
+   void setComponentType(StringTableEntry typeName) { mComponentType = typeName; }
+   void setDescription(StringTableEntry description) { mDescription = description; }
+
+   AssetDefinition* getAssetDefinition() { return mpAssetDefinition; }
+
 protected:
-   virtual void            initializeAsset(void) {}
-   virtual void            onAssetRefresh(void) {}
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
 };
 
 DefineConsoleType(TypeComponentAssetPtr, ComponentAsset)

+ 3 - 8
Engine/source/T3D/assets/ExampleAsset.cpp

@@ -74,7 +74,7 @@ ConsoleSetType(TypeExampleAssetPtr)
       if (pAssetPtr == NULL)
       {
          // No, so fail.
-         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         //Con::warnf("(TypeExampleAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
          return;
       }
 
@@ -85,18 +85,13 @@ ConsoleSetType(TypeExampleAssetPtr)
    }
 
    // Warn.
-   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+   Con::warnf("(TypeExampleAssetPtr) - Cannot set multiple args to a single asset.");
 }
 
 //-----------------------------------------------------------------------------
 
-ExampleAsset::ExampleAsset() :
-mpOwningAssetManager(NULL),
-mAssetInitialized(false),
-mAcquireReferenceCount(0)
+ExampleAsset::ExampleAsset()
 {
-   // Generate an asset definition.
-   mpAssetDefinition = new AssetDefinition();
 }
 
 //-----------------------------------------------------------------------------

+ 0 - 5
Engine/source/T3D/assets/ExampleAsset.h

@@ -43,11 +43,6 @@ class ExampleAsset : public AssetBase
 {
    typedef AssetBase Parent;
 
-   AssetManager*           mpOwningAssetManager;
-   bool                    mAssetInitialized;
-   AssetDefinition*        mpAssetDefinition;
-   U32                     mAcquireReferenceCount;
-
 public:
    ExampleAsset();
    virtual ~ExampleAsset();

+ 222 - 0
Engine/source/T3D/assets/GUIAsset.cpp

@@ -0,0 +1,222 @@
+//-----------------------------------------------------------------------------
+// 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 GUI_ASSET_H
+#include "GUIAsset.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(GUIAsset);
+
+ConsoleType(GUIAssetPtr, TypeGUIAssetPtr, GUIAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeGUIAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<GUIAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeGUIAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<GUIAsset>* pAssetPtr = dynamic_cast<AssetPtr<GUIAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeGUIAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeGUIAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+GUIAsset::GUIAsset()
+{
+   mScriptFilePath = StringTable->EmptyString();
+   mGUIFilePath = StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+GUIAsset::~GUIAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void GUIAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("scriptFilePath", TypeString, Offset(mScriptFilePath, GUIAsset), "Path to the script file for the gui");
+   addField("GUIFilePath", TypeString, Offset(mGUIFilePath, GUIAsset), "Path to the gui file");
+}
+
+//------------------------------------------------------------------------------
+
+void GUIAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+void GUIAsset::initializeAsset()
+{
+   if (Platform::isFile(mGUIFilePath))
+      Con::executeFile(mGUIFilePath, false, false);
+
+   if (Platform::isFile(mScriptFilePath))
+      Con::executeFile(mScriptFilePath, false, false);
+}
+
+void GUIAsset::onAssetRefresh()
+{
+   if (Platform::isFile(mGUIFilePath))
+      Con::executeFile(mGUIFilePath, false, false);
+
+   if (Platform::isFile(mScriptFilePath))
+      Con::executeFile(mScriptFilePath, false, false);
+}
+
+//-----------------------------------------------------------------------------
+// GuiInspectorTypeAssetId
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeGUIAssetPtr);
+
+ConsoleDocClass(GuiInspectorTypeGUIAssetPtr,
+   "@brief Inspector field type for GUI Asset Objects\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+);
+
+void GuiInspectorTypeGUIAssetPtr::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeGUIAssetPtr)->setInspectorFieldType("GuiInspectorTypeGUIAssetPtr");
+}
+
+GuiControl* GuiInspectorTypeGUIAssetPtr::constructEditControl()
+{
+   // Create base filename edit controls
+   GuiControl *retCtrl = Parent::constructEditControl();
+   if (retCtrl == NULL)
+      return retCtrl;
+
+   // Change filespec
+   char szBuffer[512];
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"GUIAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
+      mInspector->getComponentGroupTargetId(), mCaption);
+   mBrowseButton->setField("Command", szBuffer);
+
+   // Create "Open in ShapeEditor" button
+   mSMEdButton = new GuiBitmapButtonCtrl();
+
+   dSprintf(szBuffer, sizeof(szBuffer), "echo(\"Game Object Editor not implemented yet!\");", retCtrl->getId());
+   mSMEdButton->setField("Command", szBuffer);
+
+   char bitmapName[512] = "tools/worldEditor/images/toolbar/shape-editor";
+   mSMEdButton->setBitmap(bitmapName);
+
+   mSMEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
+   mSMEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
+   mSMEdButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
+   mSMEdButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this file in the State Machine Editor");
+
+   mSMEdButton->registerObject();
+   addObject(mSMEdButton);
+
+   return retCtrl;
+}
+
+bool GuiInspectorTypeGUIAssetPtr::updateRects()
+{
+   S32 dividerPos, dividerMargin;
+   mInspector->getDivider(dividerPos, dividerMargin);
+   Point2I fieldExtent = getExtent();
+   Point2I fieldPos = getPosition();
+
+   mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
+   mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
+
+   bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
+   if (mBrowseButton != NULL)
+   {
+      mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
+      resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
+   }
+
+   if (mSMEdButton != NULL)
+   {
+      RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
+      resized |= mSMEdButton->resize(shapeEdRect.point, shapeEdRect.extent);
+   }
+
+   return resized;
+}

+ 89 - 0
Engine/source/T3D/assets/GUIAsset.h

@@ -0,0 +1,89 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 GUI_ASSET_H
+#define GUI_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
+
+#include "gui/editor/guiInspectorTypes.h"
+
+//-----------------------------------------------------------------------------
+class GUIAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   StringTableEntry mScriptFilePath;
+   StringTableEntry mGUIFilePath;
+
+public:
+   GUIAsset();
+   virtual ~GUIAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(GUIAsset);
+
+protected:
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
+};
+
+DefineConsoleType(TypeGUIAssetPtr, GUIAsset)
+
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+class GuiInspectorTypeGUIAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mSMEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeGUIAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};
+
+#endif // _ASSET_BASE_H_
+

+ 93 - 9
Engine/source/T3D/assets/GameObjectAsset.cpp

@@ -74,7 +74,7 @@ ConsoleSetType(TypeGameObjectAssetPtr)
       if (pAssetPtr == NULL)
       {
          // No, so fail.
-         //Con::warnf("(TypeTextureAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         //Con::warnf("(TypeGameObjectAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
          return;
       }
 
@@ -85,19 +85,13 @@ ConsoleSetType(TypeGameObjectAssetPtr)
    }
 
    // Warn.
-   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+   Con::warnf("(TypeGameObjectAssetPtr) - Cannot set multiple args to a single asset.");
 }
 
 //-----------------------------------------------------------------------------
 
-GameObjectAsset::GameObjectAsset() :
-   mpOwningAssetManager(NULL),
-   mAssetInitialized(false),
-   mAcquireReferenceCount(0)
+GameObjectAsset::GameObjectAsset()
 {
-   // Generate an asset definition.
-   mpAssetDefinition = new AssetDefinition();
-
    mGameObjectName = StringTable->lookup("");
    mScriptFilePath = StringTable->lookup("");
    mTAMLFilePath = StringTable->lookup("");
@@ -131,4 +125,94 @@ void GameObjectAsset::copyTo(SimObject* object)
 {
    // Call to parent.
    Parent::copyTo(object);
+}
+
+void GameObjectAsset::initializeAsset()
+{
+   if (Platform::isFile(mScriptFilePath))
+      Con::executeFile(mScriptFilePath, false, false);
+}
+
+void GameObjectAsset::onAssetRefresh()
+{
+   if (Platform::isFile(mScriptFilePath))
+      Con::executeFile(mScriptFilePath, false, false);
+}
+
+//-----------------------------------------------------------------------------
+// GuiInspectorTypeAssetId
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeGameObjectAssetPtr);
+
+ConsoleDocClass(GuiInspectorTypeGameObjectAssetPtr,
+   "@brief Inspector field type for Game Objects\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+);
+
+void GuiInspectorTypeGameObjectAssetPtr::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeGameObjectAssetPtr)->setInspectorFieldType("GuiInspectorTypeGameObjectAssetPtr");
+}
+
+GuiControl* GuiInspectorTypeGameObjectAssetPtr::constructEditControl()
+{
+   // Create base filename edit controls
+   GuiControl *retCtrl = Parent::constructEditControl();
+   if (retCtrl == NULL)
+      return retCtrl;
+
+   // Change filespec
+   char szBuffer[512];
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"GameObjectAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
+      mInspector->getComponentGroupTargetId(), mCaption);
+   mBrowseButton->setField("Command", szBuffer);
+
+   // Create "Open in ShapeEditor" button
+   mSMEdButton = new GuiBitmapButtonCtrl();
+
+   dSprintf(szBuffer, sizeof(szBuffer), "echo(\"Game Object Editor not implemented yet!\");", retCtrl->getId());
+   mSMEdButton->setField("Command", szBuffer);
+
+   char bitmapName[512] = "tools/worldEditor/images/toolbar/shape-editor";
+   mSMEdButton->setBitmap(bitmapName);
+
+   mSMEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
+   mSMEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
+   mSMEdButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
+   mSMEdButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this file in the State Machine Editor");
+
+   mSMEdButton->registerObject();
+   addObject(mSMEdButton);
+
+   return retCtrl;
+}
+
+bool GuiInspectorTypeGameObjectAssetPtr::updateRects()
+{
+   S32 dividerPos, dividerMargin;
+   mInspector->getDivider(dividerPos, dividerMargin);
+   Point2I fieldExtent = getExtent();
+   Point2I fieldPos = getPosition();
+
+   mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
+   mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
+
+   bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
+   if (mBrowseButton != NULL)
+   {
+      mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
+      resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
+   }
+
+   if (mSMEdButton != NULL)
+   {
+      RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
+      resized |= mSMEdButton->resize(shapeEdRect.point, shapeEdRect.extent);
+   }
+
+   return resized;
 }

+ 23 - 7
Engine/source/T3D/assets/GameObjectAsset.h

@@ -38,17 +38,15 @@
 #ifndef _ASSET_FIELD_TYPES_H_
 #include "assets/assetFieldTypes.h"
 #endif
+#ifndef _GUI_INSPECTOR_TYPES_H_
+#include "gui/editor/guiInspectorTypes.h"
+#endif
 
 //-----------------------------------------------------------------------------
 class GameObjectAsset : public AssetBase
 {
    typedef AssetBase Parent;
 
-   AssetManager*           mpOwningAssetManager;
-   bool                    mAssetInitialized;
-   AssetDefinition*        mpAssetDefinition;
-   U32                     mAcquireReferenceCount;
-
    StringTableEntry mGameObjectName;
    StringTableEntry mScriptFilePath;
    StringTableEntry mTAMLFilePath;
@@ -65,11 +63,29 @@ public:
    DECLARE_CONOBJECT(GameObjectAsset);
 
 protected:
-   virtual void            initializeAsset(void) {}
-   virtual void            onAssetRefresh(void) {}
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
 };
 
 DefineConsoleType(TypeGameObjectAssetPtr, GameObjectAsset)
 
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+class GuiInspectorTypeGameObjectAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mSMEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeGameObjectAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};
+
 #endif // _ASSET_BASE_H_
 

+ 161 - 0
Engine/source/T3D/assets/ImageAsset.cpp

@@ -0,0 +1,161 @@
+//-----------------------------------------------------------------------------
+// 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 IMAGE_ASSET_H
+#include "ImageAsset.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(ImageAsset);
+
+ConsoleType(ImageAssetPtr, TypeImageAssetPtr, ImageAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeImageAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ImageAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeImageAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ImageAsset>* pAssetPtr = dynamic_cast<AssetPtr<ImageAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeImageAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeImageAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ImageAsset::ImageAsset()
+{
+   mImageFileName = StringTable->EmptyString();
+
+   mImage = NULL;
+   mUseMips = true;
+   mIsHDRImage = false;
+   mIsValidImage = false;
+}
+
+//-----------------------------------------------------------------------------
+
+ImageAsset::~ImageAsset()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("imageFile", TypeString, Offset(mImageFileName, ImageAsset), "Path to the image file.");
+   addField("useMips", TypeBool, Offset(mUseMips, ImageAsset), "Should the image use mips? (Currently unused).");
+   addField("isHDRImage", TypeBool, Offset(mIsHDRImage, ImageAsset), "Is the image in an HDR format? (Currently unused)");
+}
+
+//------------------------------------------------------------------------------
+
+void ImageAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+void ImageAsset::loadImage()
+{
+   SAFE_DELETE(mImage);
+
+   if (mImageFileName)
+   {
+      if (!Platform::isFile(mImageFileName))
+      {
+         Con::errorf("ImageAsset::initializeAsset: Attempted to load file %s but it was not valid!", mImageFileName);
+         return;
+      }
+
+      mImage.set(mImageFileName, &GFXStaticTextureSRGBProfile, avar("%s() - mImage (line %d)", __FUNCTION__, __LINE__));
+
+      if (mImage)
+      {
+         mIsValidImage = true;
+         return;
+      }
+   }
+
+   mIsValidImage = false;
+}
+
+void ImageAsset::initializeAsset()
+{
+   loadImage();
+}
+
+void ImageAsset::onAssetRefresh()
+{
+   loadImage();
+}

+ 90 - 0
Engine/source/T3D/assets/ImageAsset.h

@@ -0,0 +1,90 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 IMAGE_ASSET_H
+#define IMAGE_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
+
+#include "gfx/bitmap/gBitmap.h"
+#include "gfx/gfxTextureHandle.h"
+
+//-----------------------------------------------------------------------------
+class ImageAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   AssetManager*           mpOwningAssetManager;
+   bool                    mAssetInitialized;
+   AssetDefinition*        mpAssetDefinition;
+   U32                     mAcquireReferenceCount;
+
+   StringTableEntry mImageFileName;
+
+   GFXTexHandle mImage;
+
+   bool mIsValidImage;
+   bool mUseMips;
+   bool mIsHDRImage;
+
+public:
+   ImageAsset();
+   virtual ~ImageAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ImageAsset);
+
+   StringTableEntry getImageFileName() { return mImageFileName; }
+
+   bool isValid() { return mIsValidImage; }
+
+   GFXTexHandle* getImage() { return &mImage; }
+
+protected:
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
+
+   void loadImage();
+};
+
+DefineConsoleType(TypeImageAssetPtr, ImageAsset)
+
+#endif
+

+ 126 - 0
Engine/source/T3D/assets/LevelAsset.cpp

@@ -0,0 +1,126 @@
+//-----------------------------------------------------------------------------
+// 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 LEVEL_ASSET_H
+#include "LevelAsset.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(LevelAsset);
+
+ConsoleType(LevelAssetPtr, TypeLevelAssetPtr, LevelAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeLevelAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<LevelAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeLevelAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<LevelAsset>* pAssetPtr = dynamic_cast<AssetPtr<LevelAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeLevelAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeLevelAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+LevelAsset::LevelAsset()
+{
+   mLevelFile = StringTable->EmptyString();
+   mPreviewImage = StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+LevelAsset::~LevelAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void LevelAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("LevelFile", TypeString, Offset(mLevelFile, LevelAsset), "Path to the actual level file.");
+   addField("PreviewImage", TypeString, Offset(mPreviewImage, LevelAsset), "Path to the image used for selection preview.");
+}
+
+//------------------------------------------------------------------------------
+
+void LevelAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}

+ 72 - 0
Engine/source/T3D/assets/LevelAsset.h

@@ -0,0 +1,72 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 LEVEL_ASSET_H
+#define LEVEL_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
+
+//-----------------------------------------------------------------------------
+class LevelAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   StringTableEntry        mLevelFile;
+   StringTableEntry        mPreviewImage;
+
+   bool                    mIsSubLevel;
+   StringTableEntry        mMainLevelAsset;
+
+public:
+   LevelAsset();
+   virtual ~LevelAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(LevelAsset);
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypeLevelAssetPtr, LevelAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 241 - 0
Engine/source/T3D/assets/MaterialAsset.cpp

@@ -0,0 +1,241 @@
+//-----------------------------------------------------------------------------
+// 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 MATERIALASSET_H
+#include "MaterialAsset.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
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(MaterialAsset);
+
+ConsoleType(MaterialAssetPtr, TypeMaterialAssetPtr, MaterialAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeMaterialAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<MaterialAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeMaterialAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<MaterialAsset>* pAssetPtr = dynamic_cast<AssetPtr<MaterialAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeMaterialAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeMaterialAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+MaterialAsset::MaterialAsset()
+{
+   mShaderGraphFile = "";
+   mScriptFile = "";
+   mMatDefinitionName = "";
+}
+
+//-----------------------------------------------------------------------------
+
+MaterialAsset::~MaterialAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void MaterialAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   //addField("shaderGraph", TypeRealString, Offset(mShaderGraphFile, MaterialAsset), "");
+   addField("scriptFile", TypeRealString, Offset(mScriptFile, MaterialAsset), "Path to the file containing the material definition.");
+   addField("materialDefinitionName", TypeRealString, Offset(mMatDefinitionName, MaterialAsset), "Name of the material definition this asset is for.");
+}
+
+void MaterialAsset::initializeAsset()
+{
+   // Call parent.
+   Parent::initializeAsset();
+
+   compileShader();
+
+   if (Platform::isFile(mScriptFile))
+      Con::executeFile(mScriptFile, false, false);
+}
+
+void MaterialAsset::onAssetRefresh()
+{
+   if (Platform::isFile(mScriptFile))
+      Con::executeFile(mScriptFile, false, false);
+
+   if (!mMatDefinitionName.isEmpty())
+   {
+      Material* matDef;
+      if (!Sim::findObject(mMatDefinitionName.c_str(), matDef))
+      {
+         Con::errorf("MaterialAsset: Unable to find the Material %s", mMatDefinitionName.c_str());
+         return;
+      }
+
+      matDef->reload();
+   }
+}
+
+//------------------------------------------------------------------------------
+
+void MaterialAsset::compileShader()
+{
+}
+
+void MaterialAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+ConsoleMethod(MaterialAsset, compileShader, void, 2, 2, "() - Compiles the material's generated shader, if any. Not yet implemented\n")
+{
+   object->compileShader();
+}
+
+//-----------------------------------------------------------------------------
+// GuiInspectorTypeAssetId
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeMaterialAssetPtr);
+
+ConsoleDocClass(GuiInspectorTypeMaterialAssetPtr,
+   "@brief Inspector field type for Material Asset Objects\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+);
+
+void GuiInspectorTypeMaterialAssetPtr::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeMaterialAssetPtr)->setInspectorFieldType("GuiInspectorTypeMaterialAssetPtr");
+}
+
+GuiControl* GuiInspectorTypeMaterialAssetPtr::constructEditControl()
+{
+   // Create base filename edit controls
+   GuiControl *retCtrl = Parent::constructEditControl();
+   if (retCtrl == NULL)
+      return retCtrl;
+
+   // Change filespec
+   char szBuffer[512];
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"MaterialAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
+      mInspector->getComponentGroupTargetId(), mCaption);
+   mBrowseButton->setField("Command", szBuffer);
+
+   // Create "Open in ShapeEditor" button
+   mSMEdButton = new GuiBitmapButtonCtrl();
+
+   dSprintf(szBuffer, sizeof(szBuffer), "echo(\"Game Object Editor not implemented yet!\");", retCtrl->getId());
+   mSMEdButton->setField("Command", szBuffer);
+
+   char bitmapName[512] = "tools/worldEditor/images/toolbar/shape-editor";
+   mSMEdButton->setBitmap(bitmapName);
+
+   mSMEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
+   mSMEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
+   mSMEdButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
+   mSMEdButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this file in the Material Editor");
+
+   mSMEdButton->registerObject();
+   addObject(mSMEdButton);
+
+   return retCtrl;
+}
+
+bool GuiInspectorTypeMaterialAssetPtr::updateRects()
+{
+   S32 dividerPos, dividerMargin;
+   mInspector->getDivider(dividerPos, dividerMargin);
+   Point2I fieldExtent = getExtent();
+   Point2I fieldPos = getPosition();
+
+   mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
+   mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
+
+   bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
+   if (mBrowseButton != NULL)
+   {
+      mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
+      resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
+   }
+
+   if (mSMEdButton != NULL)
+   {
+      RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
+      resized |= mSMEdButton->resize(shapeEdRect.point, shapeEdRect.extent);
+   }
+
+   return resized;
+}

+ 101 - 0
Engine/source/T3D/assets/MaterialAsset.h

@@ -0,0 +1,101 @@
+//-----------------------------------------------------------------------------
+// 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 MATERIALASSET_H
+#define MATERIALASSET_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 _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
+
+#ifndef _GUI_INSPECTOR_TYPES_H_
+#include "gui/editor/guiInspectorTypes.h"
+#endif
+
+#include "materials/matTextureTarget.h"
+#include "materials/materialDefinition.h"
+#include "materials/customMaterialDefinition.h"
+
+//-----------------------------------------------------------------------------
+class MaterialAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   String                  mShaderGraphFile;
+   String                  mScriptFile;
+   String                  mMatDefinitionName;
+
+public:
+   MaterialAsset();
+   virtual ~MaterialAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   virtual void initializeAsset();
+   virtual void onAssetRefresh(void);
+
+   void compileShader();
+
+   String getMaterialDefinitionName() { return mMatDefinitionName; }
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(MaterialAsset);
+};
+
+DefineConsoleType(TypeMaterialAssetPtr, MaterialAsset)
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+class GuiInspectorTypeMaterialAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mSMEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeMaterialAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};
+
+#endif // _ASSET_BASE_H_
+

+ 205 - 0
Engine/source/T3D/assets/ParticleAsset.cpp

@@ -0,0 +1,205 @@
+//-----------------------------------------------------------------------------
+// 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 PARTICLE_ASSET_H
+#include "ParticleAsset.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(ParticleAsset);
+
+ConsoleType(ParticleAssetPtr, TypeParticleAssetPtr, ParticleAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeParticleAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ParticleAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeParticleAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ParticleAsset>* pAssetPtr = dynamic_cast<AssetPtr<ParticleAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeParticleAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeParticleAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ParticleAsset::ParticleAsset()
+{
+   mScriptFilePath = StringTable->EmptyString();
+   mDatablockFilePath = StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+ParticleAsset::~ParticleAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ParticleAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("scriptFilePath", TypeString, Offset(mScriptFilePath, ParticleAsset), "Path to the script file for the particle effect");
+   addField("DatablockFilePath", TypeString, Offset(mDatablockFilePath, ParticleAsset), "Path to the datablock file");
+}
+
+//------------------------------------------------------------------------------
+
+void ParticleAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+
+//-----------------------------------------------------------------------------
+// GuiInspectorTypeAssetId
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeParticleAssetPtr);
+
+ConsoleDocClass(GuiInspectorTypeParticleAssetPtr,
+   "@brief Inspector field type for Partial Asset Objects\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+);
+
+void GuiInspectorTypeParticleAssetPtr::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeParticleAssetPtr)->setInspectorFieldType("GuiInspectorTypeParticleAssetPtr");
+}
+
+GuiControl* GuiInspectorTypeParticleAssetPtr::constructEditControl()
+{
+   // Create base filename edit controls
+   GuiControl *retCtrl = Parent::constructEditControl();
+   if (retCtrl == NULL)
+      return retCtrl;
+
+   // Change filespec
+   char szBuffer[512];
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ParticleAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
+      mInspector->getComponentGroupTargetId(), mCaption);
+   mBrowseButton->setField("Command", szBuffer);
+
+   // Create "Open in ShapeEditor" button
+   mSMEdButton = new GuiBitmapButtonCtrl();
+
+   dSprintf(szBuffer, sizeof(szBuffer), "echo(\"Game Object Editor not implemented yet!\");", retCtrl->getId());
+   mSMEdButton->setField("Command", szBuffer);
+
+   char bitmapName[512] = "tools/worldEditor/images/toolbar/shape-editor";
+   mSMEdButton->setBitmap(bitmapName);
+
+   mSMEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
+   mSMEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
+   mSMEdButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
+   mSMEdButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this file in the State Machine Editor");
+
+   mSMEdButton->registerObject();
+   addObject(mSMEdButton);
+
+   return retCtrl;
+}
+
+bool GuiInspectorTypeParticleAssetPtr::updateRects()
+{
+   S32 dividerPos, dividerMargin;
+   mInspector->getDivider(dividerPos, dividerMargin);
+   Point2I fieldExtent = getExtent();
+   Point2I fieldPos = getPosition();
+
+   mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
+   mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
+
+   bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
+   if (mBrowseButton != NULL)
+   {
+      mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
+      resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
+   }
+
+   if (mSMEdButton != NULL)
+   {
+      RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
+      resized |= mSMEdButton->resize(shapeEdRect.point, shapeEdRect.extent);
+   }
+
+   return resized;
+}

+ 89 - 0
Engine/source/T3D/assets/ParticleAsset.h

@@ -0,0 +1,89 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 PARTICLE_ASSET_H
+#define PARTICLE_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
+
+#include "gui/editor/guiInspectorTypes.h"
+
+//-----------------------------------------------------------------------------
+class ParticleAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   StringTableEntry mScriptFilePath;
+   StringTableEntry mDatablockFilePath;
+
+public:
+   ParticleAsset();
+   virtual ~ParticleAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ParticleAsset);
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypeParticleAssetPtr, ParticleAsset)
+
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+class GuiInspectorTypeParticleAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mSMEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeParticleAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};
+
+#endif // _ASSET_BASE_H_
+

+ 129 - 0
Engine/source/T3D/assets/PostEffectAsset.cpp

@@ -0,0 +1,129 @@
+//-----------------------------------------------------------------------------
+// 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 POSTEFFECT_ASSET_H
+#include "PostEffectAsset.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(PostEffectAsset);
+
+ConsoleType(PostEffectAssetPtr, TypePostEffectAssetPtr, PostEffectAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypePostEffectAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<PostEffectAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypePostEffectAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<PostEffectAsset>* pAssetPtr = dynamic_cast<AssetPtr<PostEffectAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypePostEffectAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypePostEffectAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+PostEffectAsset::PostEffectAsset()
+{
+   mScriptFile = StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+PostEffectAsset::~PostEffectAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void PostEffectAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("scriptFile", TypeString, Offset(mScriptFile, PostEffectAsset), "Path to the script file.");
+}
+
+//------------------------------------------------------------------------------
+
+void PostEffectAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+void PostEffectAsset::initializeAsset()
+{
+   //mPostEffect = new PostEffect();
+}

+ 71 - 0
Engine/source/T3D/assets/PostEffectAsset.h

@@ -0,0 +1,71 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 POSTEFFECT_ASSET_H
+#define POSTEFFECT_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
+
+#include "postFx/postEffect.h"
+
+//-----------------------------------------------------------------------------
+class PostEffectAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   StringTableEntry        mScriptFile;
+   
+public:
+   PostEffectAsset();
+   virtual ~PostEffectAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   virtual void initializeAsset();
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(PostEffectAsset);
+
+protected:
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypePostEffectAssetPtr, PostEffectAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 137 - 0
Engine/source/T3D/assets/ScriptAsset.cpp

@@ -0,0 +1,137 @@
+//-----------------------------------------------------------------------------
+// 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 SCRIPT_ASSET_H
+#include "ScriptAsset.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(ScriptAsset);
+
+ConsoleType(ScriptAssetPtr, TypeScriptAssetPtr, ScriptAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeScriptAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ScriptAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeScriptAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ScriptAsset>* pAssetPtr = dynamic_cast<AssetPtr<ScriptAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeScriptAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeScriptAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ScriptAsset::ScriptAsset()
+{
+   mScriptFilePath = StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+ScriptAsset::~ScriptAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ScriptAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("scriptFilePath", TypeString, Offset(mScriptFilePath, ScriptAsset), "Path to the script file.");
+   addField("isServerSide", TypeBool, Offset(mIsServerSide, ScriptAsset), "Is this script file to be run on the server side?");
+
+}
+
+//------------------------------------------------------------------------------
+
+void ScriptAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+void ScriptAsset::initializeAsset()
+{
+   if (Platform::isFile(mScriptFilePath))
+      Con::executeFile(mScriptFilePath, false, false);
+}
+
+void ScriptAsset::onAssetRefresh()
+{
+   if (Platform::isFile(mScriptFilePath))
+      Con::executeFile(mScriptFilePath, false, false);
+}

+ 69 - 0
Engine/source/T3D/assets/ScriptAsset.h

@@ -0,0 +1,69 @@
+//-----------------------------------------------------------------------------
+// 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 SCRIPT_ASSET_H
+#define SCRIPT_ASSET_H
+#pragma once
+
+#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
+
+//-----------------------------------------------------------------------------
+class ScriptAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   StringTableEntry        mScriptFilePath;
+   bool                    mIsServerSide;
+
+public:
+   ScriptAsset();
+   virtual ~ScriptAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ScriptAsset);
+
+protected:
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
+};
+
+DefineConsoleType(TypeScriptAssetPtr, ScriptAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 131 - 0
Engine/source/T3D/assets/ShapeAnimationAsset.cpp

@@ -0,0 +1,131 @@
+//-----------------------------------------------------------------------------
+// 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_ANIMATION_ASSET_H
+#include "ShapeAnimationAsset.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"
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(ShapeAnimationAsset);
+
+ConsoleType(ShapeAnimationAssetPtr, TypeShapeAnimationAssetPtr, ShapeAnimationAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeShapeAnimationAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<ShapeAnimationAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeShapeAnimationAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<ShapeAnimationAsset>* pAssetPtr = dynamic_cast<AssetPtr<ShapeAnimationAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeShapeAnimationAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeShapeAnimationAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+ShapeAnimationAsset::ShapeAnimationAsset()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+ShapeAnimationAsset::~ShapeAnimationAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void ShapeAnimationAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("animationFile", TypeFilename, Offset(mFileName, ShapeAnimationAsset), "Path to the file name containing the animation");
+   addField("animationName", TypeString, Offset(mAnimationName, ShapeAnimationAsset), "Name of the animation");
+
+   addField("startFrame", TypeS32, Offset(mStartFrame, ShapeAnimationAsset), "What frame does this animation clip start on");
+   addField("endFrame", TypeS32, Offset(mEndFrame, ShapeAnimationAsset), "What fram does this animation clip end on");
+   addField("padRotation", TypeBool, Offset(mPadRotation, ShapeAnimationAsset), "Are the rotation values padded");
+   addField("padTransforms", TypeBool, Offset(mPadTransforms, ShapeAnimationAsset), "Are the transform values padded");
+}
+
+//------------------------------------------------------------------------------
+
+void ShapeAnimationAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}

+ 102 - 0
Engine/source/T3D/assets/ShapeAnimationAsset.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 SHAPE_ANIMATION_ASSET_H
+#define SHAPE_ANIMATION_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
+
+//-----------------------------------------------------------------------------
+class ShapeAnimationAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+protected:
+   StringTableEntry   mFileName;
+
+   //
+   StringTableEntry mAnimationName;
+   S32 mStartFrame;
+   S32 mEndFrame;
+   bool mPadRotation;
+   bool mPadTransforms;
+
+public:
+   ShapeAnimationAsset();
+   virtual ~ShapeAnimationAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(ShapeAnimationAsset);
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+
+public:
+   StringTableEntry getAnimationFilename() { return mFileName; }
+   StringTableEntry getAnimationName() { return mAnimationName; }
+
+   S32 getStartFrame() { return mStartFrame; }
+   S32 getEndFrame() { return mEndFrame; }
+
+   bool getPadRotation() { return mPadRotation; }
+   bool getPadTransforms() { return mPadTransforms; }
+};
+
+DefineConsoleType(TypeShapeAnimationAssetPtr, ShapeAnimationAsset)
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+/*class GuiInspectorTypeShapeAnimationAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mShapeEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeShapeAnimationAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};*/
+
+#endif // _ASSET_BASE_H_
+

+ 212 - 20
Engine/source/T3D/assets/ShapeAsset.cpp

@@ -49,14 +49,14 @@
 
 IMPLEMENT_CONOBJECT(ShapeAsset);
 
-ConsoleType(TestAssetPtr, TypeShapeAssetPtr, ShapeAsset, ASSET_ID_FIELD_PREFIX)
+ConsoleType(assetIdString, TypeShapeAssetPtr, String, ASSET_ID_FIELD_PREFIX)
 
 //-----------------------------------------------------------------------------
 
 ConsoleGetType(TypeShapeAssetPtr)
 {
    // Fetch asset Id.
-   return (*((AssetPtr<ShapeAsset>*)dptr)).getAssetId();
+   return *((StringTableEntry*)dptr);
 }
 
 //-----------------------------------------------------------------------------
@@ -69,33 +69,22 @@ ConsoleSetType(TypeShapeAssetPtr)
       // Yes, so fetch field value.
       const char* pFieldValue = argv[0];
 
-      // Fetch asset pointer.
-      AssetPtr<ShapeAsset>* pAssetPtr = dynamic_cast<AssetPtr<ShapeAsset>*>((AssetPtrBase*)(dptr));
+      // Fetch asset Id.
+      StringTableEntry* assetId = (StringTableEntry*)(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);
+      // Update asset value.
+      *assetId = StringTable->insert(pFieldValue);
 
       return;
    }
 
    // Warn.
-   Con::warnf("(TypeTextureAssetPtr) - Cannot set multiple args to a single asset.");
+   Con::warnf("(TypeAssetId) - Cannot set multiple args to a single asset.");
 }
 
 //-----------------------------------------------------------------------------
 
-ShapeAsset::ShapeAsset() :
-mpOwningAssetManager(NULL),
-mAssetInitialized(false),
-mAcquireReferenceCount(0)
+ShapeAsset::ShapeAsset()
 {
 }
 
@@ -116,7 +105,21 @@ void ShapeAsset::initPersistFields()
    // Call parent.
    Parent::initPersistFields();
 
-   addField("fileName", TypeFilename, Offset(mFileName, ShapeAsset), "Path to the script file we want to execute");
+   addField("fileName", TypeFilename, Offset(mFileName, ShapeAsset), "Path to the shape file we want to render");
+}
+
+void ShapeAsset::setDataField(StringTableEntry slotName, const char *array, const char *value)
+{
+   Parent::setDataField(slotName, array, value);
+
+   //Now, if it's a material slot of some fashion, set it up
+   StringTableEntry matSlotName = StringTable->insert("materialAsset");
+   if (String(slotName).startsWith(matSlotName))
+   {
+      StringTableEntry matId = StringTable->insert(value);
+
+      mMaterialAssetIds.push_back(matId);
+   }
 }
 
 void ShapeAsset::initializeAsset()
@@ -132,6 +135,45 @@ void ShapeAsset::initializeAsset()
 
 bool ShapeAsset::loadShape()
 {
+   mMaterialAssets.clear();
+   mMaterialAssetIds.clear();
+
+   //First, load any material, animation, etc assets we may be referencing in our asset
+   // Find any asset dependencies.
+   AssetManager::typeAssetDependsOnHash::Iterator assetDependenciesItr = mpOwningAssetManager->getDependedOnAssets()->find(mpAssetDefinition->mAssetId);
+
+   // Does the asset have any dependencies?
+   if (assetDependenciesItr != mpOwningAssetManager->getDependedOnAssets()->end())
+   {
+      // Iterate all dependencies.
+      while (assetDependenciesItr != mpOwningAssetManager->getDependedOnAssets()->end() && assetDependenciesItr->key == mpAssetDefinition->mAssetId)
+      {
+         StringTableEntry assetType = mpOwningAssetManager->getAssetType(assetDependenciesItr->value);
+
+         if (assetType == StringTable->insert("MaterialAsset"))
+         {
+            mMaterialAssetIds.push_back(assetDependenciesItr->value);
+
+            //Force the asset to become initialized if it hasn't been already
+            AssetPtr<MaterialAsset> matAsset = assetDependenciesItr->value;
+
+            mMaterialAssets.push_back(matAsset);
+         }
+         else if (assetType == StringTable->insert("ShapeAnimationAsset"))
+         {
+            mAnimationAssetIds.push_back(assetDependenciesItr->value);
+
+            //Force the asset to become initialized if it hasn't been already
+            AssetPtr<ShapeAnimationAsset> animAsset = assetDependenciesItr->value;
+
+            mAnimationAssets.push_back(animAsset);
+         }
+
+         // Next dependency.
+         assetDependenciesItr++;
+      }
+   }
+
    mShape = ResourceManager::get().load(mFileName);
 
    if (!mShape)
@@ -140,6 +182,19 @@ bool ShapeAsset::loadShape()
       return false; //if it failed to load, bail out
    }
 
+   //Now that we've successfully loaded our shape and have any materials and animations loaded
+   //we need to set up the animations we're using on our shape
+   for (U32 i = 0; i < mAnimationAssets.size(); i++)
+   {
+      String srcName;
+      String srcPath(mAnimationAssets[i]->getAnimationFilename());
+      SplitSequencePathAndName(srcPath, srcName);
+
+      if (!mShape->addSequence(srcPath, srcName, mAnimationAssets[i]->getAnimationName(), 
+         mAnimationAssets[i]->getStartFrame(), mAnimationAssets[i]->getEndFrame(), mAnimationAssets[i]->getPadRotation(), mAnimationAssets[i]->getPadTransforms()))
+         return false;
+   }
+
    return true;
 }
 
@@ -153,4 +208,141 @@ void ShapeAsset::copyTo(SimObject* object)
 
 void ShapeAsset::onAssetRefresh(void)
 {
+   if (dStrcmp(mFileName, "") == 0)
+      return;
+
+   loadShape();
+}
+
+void ShapeAsset::SplitSequencePathAndName(String& srcPath, String& srcName)
+{
+   srcName = "";
+
+   // Determine if there is a sequence name at the end of the source string, and
+   // if so, split the filename from the sequence name
+   S32 split = srcPath.find(' ', 0, String::Right);
+   S32 split2 = srcPath.find('\t', 0, String::Right);
+   if ((split == String::NPos) || (split2 > split))
+      split = split2;
+   if (split != String::NPos)
+   {
+      split2 = split + 1;
+      while ((srcPath[split2] != '\0') && dIsspace(srcPath[split2]))
+         split2++;
+
+      // now 'split' is at the end of the path, and 'split2' is at the start of the sequence name
+      srcName = srcPath.substr(split2);
+      srcPath = srcPath.erase(split, srcPath.length() - split);
+   }
+}
+
+ShapeAnimationAsset* ShapeAsset::getAnimation(S32 index)
+{
+   if (index < mAnimationAssets.size())
+   {
+      return mAnimationAssets[index];
+   }
+
+   return nullptr;
+}
+
+DefineEngineMethod(ShapeAsset, getMaterialCount, S32, (), ,
+   "Gets the number of materials for this shape asset.\n"
+   "@return Material count.\n")
+{
+   return object->getMaterialCount();
+}
+
+DefineEngineMethod(ShapeAsset, getAnimationCount, S32, (), ,
+   "Gets the number of animations for this shape asset.\n"
+   "@return Animation count.\n")
+{
+   return object->getAnimationCount();
+}
+
+DefineEngineMethod(ShapeAsset, getAnimation, ShapeAnimationAsset*, (S32 index), (0),
+   "Gets a particular shape animation asset for this shape.\n"
+   "@param animation asset index.\n"
+   "@return Shape Animation Asset.\n")
+{
+   return object->getAnimation(index);
+}
+//-----------------------------------------------------------------------------
+// GuiInspectorTypeAssetId
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeShapeAssetPtr);
+
+ConsoleDocClass(GuiInspectorTypeShapeAssetPtr,
+   "@brief Inspector field type for Shapes\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+   );
+
+void GuiInspectorTypeShapeAssetPtr::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeShapeAssetPtr)->setInspectorFieldType("GuiInspectorTypeShapeAssetPtr");
+}
+
+GuiControl* GuiInspectorTypeShapeAssetPtr::constructEditControl()
+{
+   // Create base filename edit controls
+   GuiControl *retCtrl = Parent::constructEditControl();
+   if (retCtrl == NULL)
+      return retCtrl;
+
+   // Change filespec
+   char szBuffer[512];
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"ShapeAsset\", \"AssetBrowser.changeAsset\", %d, %s);", 
+      mInspector->getComponentGroupTargetId(), mCaption);
+   mBrowseButton->setField("Command", szBuffer);
+
+   setDataField(StringTable->insert("ComponentOwner"), NULL, String::ToString(mInspector->getComponentGroupTargetId()).c_str());
+
+   // Create "Open in ShapeEditor" button
+   mShapeEdButton = new GuiBitmapButtonCtrl();
+
+   dSprintf(szBuffer, sizeof(szBuffer), "ShapeEditorPlugin.openShapeAsset(%d.getText());", retCtrl->getId());
+   mShapeEdButton->setField("Command", szBuffer);
+
+   char bitmapName[512] = "tools/worldEditor/images/toolbar/shape-editor";
+   mShapeEdButton->setBitmap(bitmapName);
+
+   mShapeEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
+   mShapeEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
+   mShapeEdButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
+   mShapeEdButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this file in the Shape Editor");
+
+   mShapeEdButton->registerObject();
+   addObject(mShapeEdButton);
+
+   return retCtrl;
+}
+
+bool GuiInspectorTypeShapeAssetPtr::updateRects()
+{
+   S32 dividerPos, dividerMargin;
+   mInspector->getDivider(dividerPos, dividerMargin);
+   Point2I fieldExtent = getExtent();
+   Point2I fieldPos = getPosition();
+
+   mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
+   mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
+
+   bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
+   if (mBrowseButton != NULL)
+   {
+      mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
+      resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
+   }
+
+   if (mShapeEdButton != NULL)
+   {
+      RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
+      resized |= mShapeEdButton->resize(shapeEdRect.point, shapeEdRect.extent);
+   }
+
+   return resized;
 }

+ 48 - 6
Engine/source/T3D/assets/ShapeAsset.h

@@ -44,21 +44,35 @@
 #ifndef __RESOURCE_H__
 #include "core/resource.h"
 #endif
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif 
+#ifndef MATERIALASSET_H
+#include "MaterialAsset.h"
+#endif
+#ifndef SHAPE_ANIMATION_ASSET_H
+#include "ShapeAnimationAsset.h"
+#endif
+
+#include "gui/editor/guiInspectorTypes.h"
 
 //-----------------------------------------------------------------------------
 class ShapeAsset : public AssetBase
 {
    typedef AssetBase Parent;
 
-   AssetManager*           mpOwningAssetManager;
-   bool                    mAssetInitialized;
-   AssetDefinition*        mpAssetDefinition;
-   U32                     mAcquireReferenceCount;
-
 protected:
    StringTableEntry   mFileName;
    Resource<TSShape>	 mShape;
 
+   //Material assets we're dependent on and use
+   Vector<StringTableEntry> mMaterialAssetIds;
+   Vector<AssetPtr<MaterialAsset>> mMaterialAssets;
+
+   //Animation assets we're dependent on and use
+   Vector<StringTableEntry> mAnimationAssetIds;
+   Vector<AssetPtr<ShapeAnimationAsset>> mAnimationAssets;
+
 public:
    ShapeAsset();
    virtual ~ShapeAsset();
@@ -67,6 +81,8 @@ public:
    static void initPersistFields();
    virtual void copyTo(SimObject* object);
 
+   virtual void setDataField(StringTableEntry slotName, const char *array, const char *value);
+
    virtual void initializeAsset();
 
    /// Declare Console Object.
@@ -78,11 +94,37 @@ public:
 
    Resource<TSShape> getShapeResource() { return mShape; }
 
+   void SplitSequencePathAndName(String& srcPath, String& srcName);
+   String getShapeFilename() { return mFileName; }
+   
+   U32 getShapeFilenameHash() { return _StringTable::hashString(mFileName); }
+
+   S32 getMaterialCount() { return mMaterialAssets.size(); }
+   S32 getAnimationCount() { return mAnimationAssets.size(); }
+   ShapeAnimationAsset* getAnimation(S32 index);
+
 protected:
    virtual void            onAssetRefresh(void);
 };
 
-DefineConsoleType(TypeShapeAssetPtr, ShapeAsset)
+DefineConsoleType(TypeShapeAssetPtr, S32)
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+class GuiInspectorTypeShapeAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mShapeEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeShapeAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};
 
 #endif
 

+ 141 - 0
Engine/source/T3D/assets/SoundAsset.cpp

@@ -0,0 +1,141 @@
+//-----------------------------------------------------------------------------
+// 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 SOUND_ASSET_H
+#include "SoundAsset.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(SoundAsset);
+
+ConsoleType(SoundAssetPtr, TypeSoundAssetPtr, SoundAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeSoundAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<SoundAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeSoundAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<SoundAsset>* pAssetPtr = dynamic_cast<AssetPtr<SoundAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeSoundAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeSoundAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+SoundAsset::SoundAsset()
+{
+   mSoundFilePath = StringTable->EmptyString();
+
+   mPitchAdjust = 0;
+   mVolumeAdjust = 0;
+
+   //mSound = nullptr;
+}
+
+//-----------------------------------------------------------------------------
+
+SoundAsset::~SoundAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void SoundAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("soundFilePath", TypeFilename, Offset(mSoundFilePath, SoundAsset), "Path to the sound file.");
+
+   addField("pitchAdjust", TypeF32, Offset(mPitchAdjust, SoundAsset), "Adjustment of the pitch value");
+   addField("volumeAdjust", TypeF32, Offset(mVolumeAdjust, SoundAsset), "Adjustment to the volume.");
+}
+
+//------------------------------------------------------------------------------
+
+void SoundAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+void SoundAsset::initializeAsset(void)
+{
+}
+
+void SoundAsset::onAssetRefresh(void)
+{
+
+}

+ 75 - 0
Engine/source/T3D/assets/SoundAsset.h

@@ -0,0 +1,75 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 SOUND_ASSET_H
+#define SOUND_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
+
+class SFXTrack;
+
+//-----------------------------------------------------------------------------
+class SoundAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+protected:
+   StringTableEntry        mSoundFilePath;
+   F32                     mPitchAdjust;
+   F32                     mVolumeAdjust;
+
+public:
+   SoundAsset();
+   virtual ~SoundAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(SoundAsset);
+
+   StringTableEntry getSoundFilePath() { return mSoundFilePath; }
+
+protected:
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
+};
+
+DefineConsoleType(TypeSoundAssetPtr, SoundAsset)
+
+#endif // _ASSET_BASE_H_
+

+ 207 - 0
Engine/source/T3D/assets/stateMachineAsset.cpp

@@ -0,0 +1,207 @@
+//-----------------------------------------------------------------------------
+// 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 STATE_MACHINE_ASSET_H
+#include "stateMachineAsset.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(StateMachineAsset);
+
+ConsoleType(StateMachineAssetPtr, TypeStateMachineAssetPtr, StateMachineAsset, ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeStateMachineAssetPtr)
+{
+   // Fetch asset Id.
+   return (*((AssetPtr<StateMachineAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeStateMachineAssetPtr)
+{
+   // Was a single argument specified?
+   if (argc == 1)
+   {
+      // Yes, so fetch field value.
+      const char* pFieldValue = argv[0];
+
+      // Fetch asset pointer.
+      AssetPtr<StateMachineAsset>* pAssetPtr = dynamic_cast<AssetPtr<StateMachineAsset>*>((AssetPtrBase*)(dptr));
+
+      // Is the asset pointer the correct type?
+      if (pAssetPtr == NULL)
+      {
+         // No, so fail.
+         //Con::warnf("(TypeStateMachineAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+         return;
+      }
+
+      // Set asset.
+      pAssetPtr->setAssetId(pFieldValue);
+
+      return;
+   }
+
+   // Warn.
+   Con::warnf("(TypeStateMachineAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+//-----------------------------------------------------------------------------
+
+StateMachineAsset::StateMachineAsset()
+{
+   mStateMachineFileName = StringTable->EmptyString();
+}
+
+//-----------------------------------------------------------------------------
+
+StateMachineAsset::~StateMachineAsset()
+{
+   // If the asset manager does not own the asset then we own the
+   // asset definition so delete it.
+   if (!getOwned())
+      delete mpAssetDefinition;
+}
+
+//-----------------------------------------------------------------------------
+
+void StateMachineAsset::initPersistFields()
+{
+   // Call parent.
+   Parent::initPersistFields();
+
+   addField("stateMachineFile", TypeString, Offset(mStateMachineFileName, StateMachineAsset), "Path to the state machine file.");
+}
+
+//------------------------------------------------------------------------------
+
+void StateMachineAsset::copyTo(SimObject* object)
+{
+   // Call to parent.
+   Parent::copyTo(object);
+}
+
+DefineEngineMethod(StateMachineAsset, notifyAssetChanged, void, (),,"")
+{
+   ResourceManager::get().getChangedSignal().trigger(object->getStateMachineFileName());
+}
+
+//-----------------------------------------------------------------------------
+// GuiInspectorTypeAssetId
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(GuiInspectorTypeStateMachineAssetPtr);
+
+ConsoleDocClass(GuiInspectorTypeStateMachineAssetPtr,
+   "@brief Inspector field type for State Machines\n\n"
+   "Editor use only.\n\n"
+   "@internal"
+);
+
+void GuiInspectorTypeStateMachineAssetPtr::consoleInit()
+{
+   Parent::consoleInit();
+
+   ConsoleBaseType::getType(TypeStateMachineAssetPtr)->setInspectorFieldType("GuiInspectorTypeStateMachineAssetPtr");
+}
+
+GuiControl* GuiInspectorTypeStateMachineAssetPtr::constructEditControl()
+{
+   // Create base filename edit controls
+   GuiControl *retCtrl = Parent::constructEditControl();
+   if (retCtrl == NULL)
+      return retCtrl;
+
+   // Change filespec
+   char szBuffer[512];
+   dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"StateMachineAsset\", \"AssetBrowser.changeAsset\", %d, %s);",
+      mInspector->getComponentGroupTargetId(), mCaption);
+   mBrowseButton->setField("Command", szBuffer);
+
+   // Create "Open in ShapeEditor" button
+   mSMEdButton = new GuiBitmapButtonCtrl();
+
+   dSprintf(szBuffer, sizeof(szBuffer), "StateMachineEditor.loadStateMachineAsset(%d.getText()); Canvas.pushDialog(StateMachineEditor);", retCtrl->getId());
+   mSMEdButton->setField("Command", szBuffer);
+
+   char bitmapName[512] = "tools/worldEditor/images/toolbar/shape-editor";
+   mSMEdButton->setBitmap(bitmapName);
+
+   mSMEdButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
+   mSMEdButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
+   mSMEdButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
+   mSMEdButton->setDataField(StringTable->insert("tooltip"), NULL, "Open this file in the State Machine Editor");
+
+   mSMEdButton->registerObject();
+   addObject(mSMEdButton);
+
+   return retCtrl;
+}
+
+bool GuiInspectorTypeStateMachineAssetPtr::updateRects()
+{
+   S32 dividerPos, dividerMargin;
+   mInspector->getDivider(dividerPos, dividerMargin);
+   Point2I fieldExtent = getExtent();
+   Point2I fieldPos = getPosition();
+
+   mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
+   mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
+
+   bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
+   if (mBrowseButton != NULL)
+   {
+      mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
+      resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
+   }
+
+   if (mSMEdButton != NULL)
+   {
+      RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
+      resized |= mSMEdButton->resize(shapeEdRect.point, shapeEdRect.extent);
+   }
+
+   return resized;
+}

+ 89 - 0
Engine/source/T3D/assets/stateMachineAsset.h

@@ -0,0 +1,89 @@
+#pragma once
+//-----------------------------------------------------------------------------
+// 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 STATE_MACHINE_ASSET_H
+#define STATE_MACHINE_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
+
+#include "gui/editor/guiInspectorTypes.h"
+
+//-----------------------------------------------------------------------------
+class StateMachineAsset : public AssetBase
+{
+   typedef AssetBase Parent;
+
+   StringTableEntry mStateMachineFileName;
+
+public:
+   StateMachineAsset();
+   virtual ~StateMachineAsset();
+
+   /// Engine.
+   static void initPersistFields();
+   virtual void copyTo(SimObject* object);
+
+   /// Declare Console Object.
+   DECLARE_CONOBJECT(StateMachineAsset);
+
+   StringTableEntry getStateMachineFileName() { return mStateMachineFileName; }
+
+protected:
+   virtual void            initializeAsset(void) {}
+   virtual void            onAssetRefresh(void) {}
+};
+
+DefineConsoleType(TypeStateMachineAssetPtr, StateMachineAsset)
+
+//-----------------------------------------------------------------------------
+// TypeAssetId GuiInspectorField Class
+//-----------------------------------------------------------------------------
+class GuiInspectorTypeStateMachineAssetPtr : public GuiInspectorTypeFileName
+{
+   typedef GuiInspectorTypeFileName Parent;
+public:
+
+   GuiBitmapButtonCtrl  *mSMEdButton;
+
+   DECLARE_CONOBJECT(GuiInspectorTypeStateMachineAssetPtr);
+   static void consoleInit();
+
+   virtual GuiControl* constructEditControl();
+   virtual bool updateRects();
+};
+
+#endif
+

+ 37 - 49
Engine/source/T3D/components/animation/animationComponent.cpp

@@ -72,7 +72,6 @@ IMPLEMENT_CALLBACK(AnimationComponent, onAnimationTrigger, void, (Component* obj
 AnimationComponent::AnimationComponent() : Component()
 {
    mNetworked = true;
-   mNetFlags.set(Ghostable | ScopeAlways);
 
    mFriendlyName = "Animation(Component)";
    mComponentType = "Render";
@@ -223,31 +222,19 @@ U32 AnimationComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stre
 {
    U32 retMask = Parent::packUpdate(con, mask, stream);
 
-   //early test if we lack an owner, ghost-wise
-   //no point in trying, just re-queue the mask and go
-   if (!mOwner || con->getGhostIndex(mOwner) == -1)
+   /*for (int i = 0; i < MaxScriptThreads; i++)
    {
-      stream->writeFlag(false);
-      return retMask |= ThreadMask;
-   }
-   else
-   {
-      stream->writeFlag(true);
-
-      for (int i = 0; i < MaxScriptThreads; i++) 
+      Thread& st = mAnimationThreads[i];
+      if (stream->writeFlag((st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i))))
       {
-         Thread& st = mAnimationThreads[i];
-         if (stream->writeFlag( (st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i)) ) ) 
-         {
-            stream->writeInt(st.sequence,ThreadSequenceBits);
-            stream->writeInt(st.state,2);
-            stream->write(st.timescale);
-            stream->write(st.position);
-            stream->writeFlag(st.atEnd);
-            stream->writeFlag(st.transition);
-         }
+         stream->writeInt(st.sequence, ThreadSequenceBits);
+         stream->writeInt(st.state, 2);
+         stream->write(st.timescale);
+         stream->write(st.position);
+         stream->writeFlag(st.atEnd);
+         stream->writeFlag(st.transition);
       }
-   }
+   }*/
 
    return retMask;
 }
@@ -256,29 +243,26 @@ void AnimationComponent::unpackUpdate(NetConnection *con, BitStream *stream)
 {
    Parent::unpackUpdate(con, stream);
 
-   if (stream->readFlag()) 
+   /*for (S32 i = 0; i < MaxScriptThreads; i++) 
    {
-      for (S32 i = 0; i < MaxScriptThreads; i++) 
+      if (stream->readFlag()) 
       {
-         if (stream->readFlag()) 
-         {
-            Thread& st = mAnimationThreads[i];
-            U32 seq = stream->readInt(ThreadSequenceBits);
-            st.state = stream->readInt(2);
-            stream->read( &st.timescale );
-            stream->read( &st.position );
-            st.atEnd = stream->readFlag();
-            bool transition = stream->readFlag();
-
-            if (!st.thread || st.sequence != seq && st.state != Thread::Destroy)
-               setThreadSequence(i, seq, false, transition);
-            else
-               updateThread(st);
-
-         }
+         Thread& st = mAnimationThreads[i];
+         U32 seq = stream->readInt(ThreadSequenceBits);
+         st.state = stream->readInt(2);
+         stream->read( &st.timescale );
+         stream->read( &st.position );
+         st.atEnd = stream->readFlag();
+         bool transition = stream->readFlag();
+
+         if (!st.thread || st.sequence != seq && st.state != Thread::Destroy)
+            setThreadSequence(i, seq, false, transition);
+         else
+            updateThread(st);
       }
-   }
+   }*/
 }
+
 void AnimationComponent::processTick()
 {
    Parent::processTick();
@@ -327,9 +311,6 @@ const char *AnimationComponent::getThreadSequenceName(U32 slot)
 
 bool AnimationComponent::setThreadSequence(U32 slot, S32 seq, bool reset, bool transition, F32 transTime)
 {
-   if (!mOwnerShapeInstance)
-      return false;
-
    Thread& st = mAnimationThreads[slot];
    if (st.thread && st.sequence == seq && st.state == Thread::Play && !reset)
       return true;
@@ -340,7 +321,6 @@ bool AnimationComponent::setThreadSequence(U32 slot, S32 seq, bool reset, bool t
 
    if (seq < MaxSequenceIndex)
    {
-      setMaskBits(-1);
       setMaskBits(ThreadMaskN << slot);
       st.sequence = seq;
       st.transition = transition;
@@ -647,7 +627,7 @@ void AnimationComponent::advanceThreads(F32 dt)
             st.atEnd = true;
             updateThread(st);
 
-            if (!isGhost())
+            if (!isClientObject())
             {
                Con::executef(this, "onAnimationEnd", st.thread->getSequenceName());
             }
@@ -660,7 +640,7 @@ void AnimationComponent::advanceThreads(F32 dt)
             mOwnerShapeInstance->advanceTime(dt, st.thread);
          }
 
-         if (mOwnerShapeInstance && !isGhost())
+         if (mOwnerShapeInstance && !isClientObject())
          {
             for (U32 i = 1; i < 32; i++)
             {
@@ -672,8 +652,16 @@ void AnimationComponent::advanceThreads(F32 dt)
             }
          }
 
-         if (isGhost())
+         if (isClientObject())
+         {
             mOwnerShapeInstance->animate();
+            /*mOwnerShapeInstance->animateGround();
+            MatrixF groundTransform = mOwnerShapeInstance->getGroundTransform();
+            if (groundTransform != MatrixF::Identity)
+            {
+               mOwner->setPosition(groundTransform.getPosition());
+            }*/
+         }
       }
    }
 }

+ 421 - 0
Engine/source/T3D/components/audio/SoundComponent.cpp

@@ -0,0 +1,421 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 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 "T3D/components/audio/SoundComponent.h"
+#include "core/stream/bitStream.h"
+#include "sim/netConnection.h"
+
+#include "sfx/sfxSystem.h"
+#include "sfx/sfxSource.h"
+#include "sfx/sfxTrack.h"
+#include "sfx/sfxDescription.h"
+#include "T3D/sfx/sfx3DWorld.h"
+
+#include "sfx/sfxTrack.h"
+#include "sfx/sfxTypes.h"
+
+#include "renderInstance/renderPassManager.h"
+#include "gfx/gfxDrawUtil.h"
+
+// Timeout for non-looping sounds on a channel
+static SimTime sAudioTimeout = 500;
+
+extern bool gEditingMission;
+
+//////////////////////////////////////////////////////////////////////////
+// Constructor/Destructor
+//////////////////////////////////////////////////////////////////////////
+SoundComponent::SoundComponent() : Component()
+{
+   //These flags inform that, in this particular component, we network down to the client, which enables the pack/unpackData functions to operate
+   mNetworked = true;
+
+   mFriendlyName = "Sound(Component)";
+   mComponentType = "Sound";
+   mDescription = getDescriptionText("Stores up to 4 sounds for playback.");
+
+   for (U32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++) {
+      mSoundThread[slotNum].play = false;
+      mSoundThread[slotNum].profile = 0;
+      mSoundThread[slotNum].sound = 0;
+
+      mSoundFile[slotNum] = NULL;
+      mPreviewSound[slotNum] = false;
+      mPlay[slotNum] = false;
+   }
+}
+
+SoundComponent::~SoundComponent()
+{
+}
+
+IMPLEMENT_CO_NETOBJECT_V1(SoundComponent);
+
+//Standard onAdd function, for when the component is created
+bool SoundComponent::onAdd()
+{
+   if (!Parent::onAdd())
+      return false;
+
+   for (U32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+      mPreviewSound[slotNum] = false;
+
+   return true;
+}
+
+//Standard onRemove function, when the component object is deleted
+void SoundComponent::onRemove()
+{
+   Parent::onRemove();
+}
+
+//This is called when the component has been added to an entity
+void SoundComponent::onComponentAdd()
+{
+   Parent::onComponentAdd();
+
+   Con::printf("We were added to an entity! SoundComponent reporting in for owner entity %i", mOwner->getId());
+}
+
+//This is called when the component has been removed from an entity
+void SoundComponent::onComponentRemove()
+{
+   Con::printf("We were removed from our entity! SoundComponent signing off for owner entity %i", mOwner->getId());
+   Parent::onComponentRemove();
+}
+
+//This is called any time a component is added to an entity. Every component currently owned by the entity is informed of the event. 
+//This allows you to do dependency behavior, like collisions being aware of a mesh component, etc
+void SoundComponent::componentAddedToOwner(Component *comp)
+{
+   for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+   {
+      if (mPlay[slotNum])
+      {
+         playAudio(slotNum, mSoundFile[slotNum]);
+      }
+   }
+   Con::printf("Our owner entity has a new component being added! SoundComponent welcomes component %i of type %s", comp->getId(), comp->getClassRep()->getNameSpace());
+}
+
+//This is called any time a component is removed from an entity. Every component current owned by the entity is informed of the event.
+//This allows cleanup and dependency management.
+void SoundComponent::componentRemovedFromOwner(Component *comp)
+{
+   Con::printf("Our owner entity has a removed a component! SoundComponent waves farewell to component %i of type %s", comp->getId(), comp->getClassRep()->getNameSpace());
+}
+
+//Regular init persist fields function to set up static fields.
+void SoundComponent::initPersistFields()
+{
+   //addArray("Sounds", MaxSoundThreads);
+   addField("mSoundFile", TypeSFXTrackName, Offset(mSoundFile, SoundComponent), MaxSoundThreads, "If the text will not fit in the control, the deniedSound is played.");
+   addProtectedField("mPreviewSound", TypeBool, Offset(mPreviewSound, SoundComponent),
+      &_previewSound, &defaultProtectedGetFn, MaxSoundThreads, "Preview Sound", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
+   addProtectedField("play", TypeBool, Offset(mPlay, SoundComponent),
+      &_autoplay, &defaultProtectedGetFn, MaxSoundThreads, "Whether playback of the emitter's sound should start as soon as the emitter object is added to the level.\n"
+      "If this is true, the emitter will immediately start to play when the level is loaded.");
+   //endArray("Sounds");
+   Parent::initPersistFields();
+}
+
+bool SoundComponent::_previewSound(void *object, const char *index, const char *data)
+{
+   U32 slotNum = (index != NULL) ? dAtoui(index) : 0;
+   SoundComponent* component = reinterpret_cast< SoundComponent* >(object);
+   if (!component->mPreviewSound[slotNum])
+      component->playAudio(slotNum, component->mSoundFile[slotNum]);
+   else
+      component->stopAudio(slotNum);
+   component->mPreviewSound[slotNum] = !component->mPreviewSound[slotNum];
+
+   return false;
+}
+
+bool SoundComponent::_autoplay(void *object, const char *index, const char *data)
+{
+   U32 slotNum = (index != NULL) ? dAtoui(index) : 0;
+   SoundComponent* component = reinterpret_cast< SoundComponent* >(object);
+   component->mPlay[slotNum] = dAtoui(data);
+   if (component->mPlay[slotNum])
+      component->playAudio(slotNum, component->mSoundFile[slotNum]);
+   else
+      component->stopAudio(slotNum);
+
+   return false;
+}
+
+U32 SoundComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
+{
+   U32 retMask = Parent::packUpdate(con, mask, stream);
+
+   if (mask & InitialUpdateMask)
+   {
+      // mask off sounds that aren't playing
+      S32 slotNum;
+      for (slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+         if (!mSoundThread[slotNum].play)
+            mask &= ~(SoundMaskN << slotNum);
+   }
+
+   for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+      stream->writeFlag(mPreviewSound[slotNum]);
+
+   if (stream->writeFlag(mask & SoundMask)) 
+   {
+      for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++) 
+      {
+         Sound& st = mSoundThread[slotNum];
+
+         if (stream->writeFlag(mask & (SoundMaskN << slotNum)))
+         {
+            if (stream->writeFlag(st.play))
+               //stream->writeRangedU32(st.profile->getId(), DataBlockObjectIdFirst,
+               //   DataBlockObjectIdLast);
+               stream->writeString(st.profile->getName());
+
+         }
+      }
+   }
+
+   return retMask;
+}
+
+void SoundComponent::unpackUpdate(NetConnection *con, BitStream *stream)
+{
+   Parent::unpackUpdate(con, stream);
+
+   for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+      mPreviewSound[slotNum] = stream->readFlag();
+
+   if (stream->readFlag())
+   {
+      for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+      {
+         if (stream->readFlag())
+         {
+            Sound& st = mSoundThread[slotNum];
+            st.play = stream->readFlag();
+            if (st.play)
+            {
+               //st.profile = (SFXTrack*)stream->readRangedU32(DataBlockObjectIdFirst,
+               //   DataBlockObjectIdLast);
+               char profileName[255];
+               stream->readString(profileName);
+
+               if (!Sim::findObject(profileName, st.profile))
+                  Con::errorf("Could not find SFXTrack");
+            }
+
+            //if (isProperlyAdded())
+               updateAudioState(st);
+         }
+      }
+   }
+}
+
+//This allows custom behavior in the event the owner is being edited
+void SoundComponent::onInspect()
+{
+}
+
+//This allows cleanup of the custom editor behavior if our owner stopped being edited
+void SoundComponent::onEndInspect()
+{
+}
+
+//Process tick update function, natch
+void SoundComponent::processTick()
+{
+   Parent::processTick();
+}
+
+//Client-side advance function
+void SoundComponent::advanceTime(F32 dt)
+{
+
+}
+
+//Client-side interpolation function
+void SoundComponent::interpolateTick(F32 delta)
+{
+
+}
+
+void SoundComponent::prepRenderImage(SceneRenderState *state)
+{
+   if (!mEnabled || !mOwner || !gEditingMission)
+      return;
+   ObjectRenderInst* ri = state->getRenderPass()->allocInst< ObjectRenderInst >();
+
+   ri->renderDelegate.bind(this, &SoundComponent::_renderObject);
+   ri->type = RenderPassManager::RIT_Editor;
+   ri->defaultKey = 0;
+   ri->defaultKey2 = 0;
+
+   state->getRenderPass()->addInst(ri);
+}
+
+void SoundComponent::_renderObject(ObjectRenderInst *ri,
+   SceneRenderState *state,
+   BaseMatInstance *overrideMat)
+{
+   if (overrideMat)
+      return;
+
+   GFXStateBlockDesc desc;
+   desc.setBlend(true);
+
+   MatrixF camera = GFX->getWorldMatrix();
+   camera.inverse();
+   Point3F pos = mOwner->getPosition();
+
+   for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+   {
+      if (mPreviewSound[slotNum])
+      {
+         Sound& st = mSoundThread[slotNum];
+         if (st.sound && st.sound->getDescription())
+         {
+            F32 minRad = st.sound->getDescription()->mMinDistance;
+            F32 falloffRad = st.sound->getDescription()->mMaxDistance;
+            SphereF sphere(pos, falloffRad);
+            if (sphere.isContained(camera.getPosition()))
+               desc.setCullMode(GFXCullNone);
+
+            GFX->getDrawUtil()->drawSphere(desc, minRad, pos, ColorI(255, 0, 255, 64));
+            GFX->getDrawUtil()->drawSphere(desc, falloffRad, pos, ColorI(128, 0, 128, 64));
+         }
+      }
+   }
+}
+
+void SoundComponent::playAudio(U32 slotNum, SFXTrack* _profile)
+{
+   AssertFatal(slotNum < MaxSoundThreads, "ShapeBase::playAudio() bad slot index");
+   SFXTrack* profile = (_profile != NULL) ? _profile : mSoundFile[slotNum];
+   Sound& st = mSoundThread[slotNum];
+   if (profile && (!st.play || st.profile != profile))
+   {
+      setMaskBits(SoundMaskN << slotNum);
+      st.play = true;
+      st.profile = profile;
+      updateAudioState(st);
+   }
+}
+
+void SoundComponent::stopAudio(U32 slotNum)
+{
+   AssertFatal(slotNum < MaxSoundThreads, "ShapeBase::stopAudio() bad slot index");
+
+   Sound& st = mSoundThread[slotNum];
+   if (st.play)
+   {
+      st.play = false;
+      setMaskBits(SoundMaskN << slotNum);
+      updateAudioState(st);
+   }
+}
+
+void SoundComponent::updateServerAudio()
+{
+   // Timeout non-looping sounds
+   for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++) 
+   {
+      Sound& st = mSoundThread[slotNum];
+      if (st.play && st.timeout && st.timeout < Sim::getCurrentTime()) 
+      {
+         //clearMaskBits(SoundMaskN << slotNum);
+         st.play = false;
+      }
+   }
+}
+
+void SoundComponent::updateAudioState(Sound& st)
+{
+   SFX_DELETE(st.sound);
+
+   if (st.play && st.profile)
+   {
+      if (isClientObject())
+      {
+         //if (Sim::findObject(SimObjectId((uintptr_t)st.profile), st.profile))
+        // {
+            st.sound = SFX->createSource(st.profile, &mOwner->getTransform());
+            if (st.sound)
+               st.sound->play();
+         //}
+         else
+            st.play = false;
+      }
+      else
+      {
+         // Non-looping sounds timeout on the server
+         st.timeout = 0;
+         if (!st.profile->getDescription()->mIsLooping)
+            st.timeout = Sim::getCurrentTime() + sAudioTimeout;
+      }
+   }
+   else
+      st.play = false;
+}
+
+void SoundComponent::updateAudioPos()
+{
+   for (S32 slotNum = 0; slotNum < MaxSoundThreads; slotNum++)
+   {
+      SFXSource* source = mSoundThread[slotNum].sound;
+      if (source)
+         source->setTransform(mOwner->getTransform());
+   }
+}
+
+//----------------------------------------------------------------------------
+DefineEngineMethod(SoundComponent, playAudio, bool, (S32 slot, SFXTrack* track), (0, nullAsType<SFXTrack*>()),
+   "@brief Attach a sound to this shape and start playing it.\n\n"
+
+   "@param slot Audio slot index for the sound (valid range is 0 - 3)\n" // 3 = ShapeBase::MaxSoundThreads-1
+   "@param track SFXTrack to play\n"
+   "@return true if the sound was attached successfully, false if failed\n\n"
+
+   "@see stopAudio()\n")
+{
+   if (track && slot >= 0 && slot < SoundComponent::MaxSoundThreads) {
+      object->playAudio(slot, track);
+      return true;
+   }
+   return false;
+}
+
+DefineEngineMethod(SoundComponent, stopAudio, bool, (S32 slot), ,
+   "@brief Stop a sound started with playAudio.\n\n"
+
+   "@param slot audio slot index (started with playAudio)\n"
+   "@return true if the sound was stopped successfully, false if failed\n\n"
+
+   "@see playAudio()\n")
+{
+   if (slot >= 0 && slot < SoundComponent::MaxSoundThreads) {
+      object->stopAudio(slot);
+      return true;
+   }
+   return false;
+}

+ 129 - 0
Engine/source/T3D/components/audio/SoundComponent.h

@@ -0,0 +1,129 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 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_COMPONENT_H
+#define EXAMPLE_COMPONENT_H
+#pragma once
+
+#ifndef COMPONENT_H
+#include "T3D/components/component.h"
+#endif
+#ifndef RENDER_COMPONENT_INTERFACE_H
+#include "T3D/components/render/renderComponentInterface.h"
+#endif
+
+class SFXSource;
+
+//SoundComponent
+//A basic example of the various functions you can utilize to make your own component!
+//This example doesn't really DO anything, persay, but you can readily copy it as a base
+//and use it as a starting point for your own.
+class SoundComponent : public Component, public RenderComponentInterface, public EditorInspectInterface
+{
+   typedef Component Parent;
+
+public:
+   enum PublicConstants
+   {
+      MaxSoundThreads = 4,            ///< Should be a power of 2
+   };
+
+   /// @name Network state masks
+   /// @{
+
+   ///
+   enum SoundComponentMasks
+   {
+      SoundMaskN = Parent::NextFreeMask << 6,       ///< Extends + MaxSoundThreads bits
+   };
+
+   enum BaseMaskConstants
+   {
+      SoundMask = (SoundMaskN << MaxSoundThreads) - SoundMaskN,
+   };
+   /// @name Scripted Sound
+   /// @{
+   struct Sound {
+      bool play;                    ///< Are we playing this sound?
+      SimTime timeout;              ///< Time until we stop playing this sound.
+      SFXTrack* profile;            ///< Profile on server
+      SFXSource* sound;             ///< Sound on client
+      Sound::Sound()
+      {
+         play = false;
+         timeout = 0;
+         profile = NULL;
+         sound = NULL;
+      }
+   };
+   Sound mSoundThread[MaxSoundThreads];
+   SFXTrack* mSoundFile[MaxSoundThreads];
+   bool mPreviewSound[MaxSoundThreads];
+   bool mPlay[MaxSoundThreads];
+   /// @}
+
+   SoundComponent();
+   virtual ~SoundComponent();
+   DECLARE_CONOBJECT(SoundComponent);
+
+   virtual bool onAdd();
+   virtual void onRemove();
+   static void initPersistFields();
+   static bool _previewSound(void *object, const char *index, const char *data);
+   static bool _autoplay(void *object, const char *index, const char *data);
+
+   virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
+   virtual void unpackUpdate(NetConnection *con, BitStream *stream);
+
+   virtual void onComponentRemove();
+   virtual void onComponentAdd();
+
+   virtual void componentAddedToOwner(Component *comp);
+   virtual void componentRemovedFromOwner(Component *comp);
+
+   virtual void onInspect();
+   virtual void onEndInspect();
+
+   virtual void processTick();
+   virtual void advanceTime(F32 dt);
+   virtual void interpolateTick(F32 delta);
+
+   void prepRenderImage(SceneRenderState* state);
+   void _renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
+
+   virtual void playAudio(U32 slotNum, SFXTrack* profile = NULL);
+   virtual void stopAudio(U32 slot);
+   virtual void updateServerAudio();
+   virtual void updateAudioState(Sound& st);
+   virtual void updateAudioPos();
+
+   //why god why
+   virtual TSShape* getShape() { return NULL; };
+   Signal< void(RenderComponentInterface*) > onShapeChanged;
+   virtual TSShapeInstance* getShapeInstance() { return NULL; };
+   Signal< void(RenderComponentInterface*) > onShapeInstanceChanged;
+   virtual MatrixF getNodeTransform(S32 nodeIdx) { return MatrixF::Identity; };
+   virtual Vector<MatrixF> getNodeTransforms() { return NULL; };
+   virtual void setNodeTransforms(Vector<MatrixF> transforms) {};
+};
+
+#endif

+ 8 - 3
Engine/source/T3D/components/camera/cameraComponent.cpp

@@ -79,6 +79,7 @@ CameraComponent::CameraComponent() : Component()
    mTargetNode = "";
 
    mUseParentTransform = true;
+   mNetworked = true;
 
    mFriendlyName = "Camera(Component)";
 }
@@ -202,7 +203,7 @@ void CameraComponent::setCameraFov(F32 fov)
 void CameraComponent::onCameraScopeQuery(NetConnection *cr, CameraScopeQuery * query)
 {
    // update the camera query
-   query->camera = this;
+   query->camera = mOwner;//this;
 
    if(GameConnection * con = dynamic_cast<GameConnection*>(cr))
    {
@@ -357,7 +358,8 @@ U32 CameraComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
          mTargetNodeIdx = nodeIndex;
       }
 
-      stream->writeInt(mTargetNodeIdx, 32);
+      if(stream->writeFlag(mTargetNodeIdx > -1))
+         stream->writeInt(mTargetNodeIdx, 32);
       //send offsets here
 
       stream->writeCompressedPoint(mPosOffset);
@@ -382,7 +384,10 @@ void CameraComponent::unpackUpdate(NetConnection *con, BitStream *stream)
 
    if(stream->readFlag())
    {
-      mTargetNodeIdx = stream->readInt(32);
+      if (stream->readFlag())
+         mTargetNodeIdx = stream->readInt(32);
+      else
+         mTargetNodeIdx = -1;
 
       stream->readCompressedPoint(&mPosOffset);
 

+ 0 - 2
Engine/source/T3D/components/collision/collisionComponent.cpp

@@ -125,8 +125,6 @@ EndImplementEnumType;
 //
 CollisionComponent::CollisionComponent() : Component()
 {
-   mNetFlags.set(Ghostable | ScopeAlways);
-
    mFriendlyName = "Collision(Component)";
 
    mOwnerRenderInterface = NULL;

+ 22 - 15
Engine/source/T3D/components/component.cpp

@@ -31,6 +31,7 @@
 #include "console/engineAPI.h"
 #include "sim/netConnection.h"
 #include "console/consoleInternal.h"
+#include "T3D/assets/MaterialAsset.h"
 
 #define DECLARE_NATIVE_COMPONENT( ComponentType )                   \
 	 Component* staticComponentTemplate = new ComponentType; \
@@ -52,7 +53,6 @@ Component::Component()
 
    mNetworked = false;
 
-
    // [tom, 1/12/2007] We manage the memory for the description since it
    // could be loaded from a file and thus massive. This is accomplished with
    // protected fields, but since they still call Con::getData() the field
@@ -66,7 +66,7 @@ Component::Component()
 
    mOriginatingAssetId = StringTable->EmptyString();
 
-   mNetFlags.set(Ghostable);
+   mIsServerObject = true;
 }
 
 Component::~Component()
@@ -198,7 +198,6 @@ void Component::onComponentRemove()
    {
       mOwner->onComponentAdded.remove(this, &Component::componentAddedToOwner);
       mOwner->onComponentRemoved.remove(this, &Component::componentRemovedFromOwner);
-      mOwner->onTransformSet.remove(this, &Component::ownerTransformSet);
    }
 
    mOwner = NULL;
@@ -212,7 +211,6 @@ void Component::setOwner(Entity* owner)
    {
       mOwner->onComponentAdded.remove(this, &Component::componentAddedToOwner);
       mOwner->onComponentRemoved.remove(this, &Component::componentRemovedFromOwner);
-      mOwner->onTransformSet.remove(this, &Component::ownerTransformSet);
 
       mOwner->removeComponent(this, false);
    }
@@ -223,11 +221,18 @@ void Component::setOwner(Entity* owner)
    {
       mOwner->onComponentAdded.notify(this, &Component::componentAddedToOwner);
       mOwner->onComponentRemoved.notify(this, &Component::componentRemovedFromOwner);
-      mOwner->onTransformSet.notify(this, &Component::ownerTransformSet);
    }
 
    if (isServerObject())
+   {
       setMaskBits(OwnerMask);
+
+      //if we have any outstanding maskbits, push them along to have the network update happen on the entity
+      if (mDirtyMaskBits != 0 && mOwner)
+      {
+         mOwner->setMaskBits(Entity::ComponentsUpdateMask);
+      }
+   }
 }
 
 void Component::componentAddedToOwner(Component *comp)
@@ -240,16 +245,19 @@ void Component::componentRemovedFromOwner(Component *comp)
    return;
 }
 
-void Component::ownerTransformSet(MatrixF *mat)
+void Component::setMaskBits(U32 orMask)
 {
-   return;
+   AssertFatal(orMask != 0, "Invalid net mask bits set.");
+   
+   if (mOwner)
+      mOwner->setComponentNetMask(this, orMask);
 }
 
 U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
 {
-   U32 retMask = Parent::packUpdate(con, mask, stream);
+   U32 retMask = 0;
 
-   if (mask & OwnerMask)
+   /*if (mask & OwnerMask)
    {
       if (mOwner != NULL)
       {
@@ -274,7 +282,7 @@ U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
       }
    }
    else
-      stream->writeFlag(false);
+      stream->writeFlag(false);*/
 
    if (stream->writeFlag(mask & EnableMask))
    {
@@ -299,9 +307,7 @@ U32 Component::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
 
 void Component::unpackUpdate(NetConnection *con, BitStream *stream)
 {
-   Parent::unpackUpdate(con, stream);
-
-   if (stream->readFlag())
+   /*if (stream->readFlag())
    {
       if (stream->readFlag())
       {
@@ -317,7 +323,7 @@ void Component::unpackUpdate(NetConnection *con, BitStream *stream)
          //it's being nulled out
          setOwner(NULL);
       }
-   }
+   }*/
 
    if (stream->readFlag())
    {
@@ -467,7 +473,7 @@ void Component::addComponentField(const char *fieldName, const char *desc, const
    else if (fieldType == StringTable->insert("vector"))
       fieldTypeMask = TypePoint3F;
    else if (fieldType == StringTable->insert("material"))
-      fieldTypeMask = TypeMaterialName;
+      fieldTypeMask = TypeMaterialAssetPtr;
    else if (fieldType == StringTable->insert("image"))
       fieldTypeMask = TypeImageFilename;
    else if (fieldType == StringTable->insert("shape"))
@@ -488,6 +494,7 @@ void Component::addComponentField(const char *fieldName, const char *desc, const
       fieldTypeMask = TypeGameObjectAssetPtr;
    else
       fieldTypeMask = TypeString;
+   field.mFieldTypeName = fieldType;
 
    field.mFieldType = fieldTypeMask;
 

+ 18 - 3
Engine/source/T3D/components/component.h

@@ -64,9 +64,9 @@ struct ComponentField
 /// 
 /// 
 //////////////////////////////////////////////////////////////////////////
-class Component : public NetObject, public UpdateInterface
+class Component : public SimObject, public UpdateInterface
 {
-   typedef NetObject Parent;
+   typedef SimObject Parent;
 
 protected:
    StringTableEntry mFriendlyName;
@@ -92,6 +92,10 @@ protected:
    StringTableEntry		      mOriginatingAssetId;
    AssetPtr<ComponentAsset>  mOriginatingAsset;
 
+   U32                        mDirtyMaskBits;
+
+   bool                 mIsServerObject;
+
 public:
    Component();
    virtual ~Component();
@@ -113,7 +117,8 @@ public:
    //This is called when a different component is removed from our owner entity
    virtual void componentRemovedFromOwner(Component *comp);  
 
-   virtual void ownerTransformSet(MatrixF *mat);
+   //Overridden by components that actually care
+   virtual void ownerTransformSet(MatrixF *mat) {}
 
    void setOwner(Entity* pOwner);
    inline Entity *getOwner() { return mOwner ? mOwner : NULL; }
@@ -190,6 +195,16 @@ public:
       NextFreeMask = BIT(5)
    };
 
+   virtual void setMaskBits(U32 orMask);
+   virtual void clearMaskBits() {
+      mDirtyMaskBits = 0;
+   }
+
+   bool isServerObject() { return mIsServerObject; }
+   bool isClientObject() { return !mIsServerObject; }
+
+   void setIsServerObject(bool isServerObj) { mIsServerObject = isServerObj; }
+
    virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
    virtual void unpackUpdate(NetConnection *con, BitStream *stream);
    /// @}

+ 0 - 1
Engine/source/T3D/components/game/stateMachineComponent.cpp

@@ -57,7 +57,6 @@ StateMachineComponent::StateMachineComponent() : Component()
 
    //doesn't need to be networked
    mNetworked = false;
-   mNetFlags.clear();
 }
 
 StateMachineComponent::~StateMachineComponent()

+ 2 - 2
Engine/source/T3D/components/physics/rigidBodyComponent.cpp

@@ -288,7 +288,7 @@ void RigidBodyComponent::processTick()
       return;
 
    // SINGLE PLAYER HACK!!!!
-   if (PHYSICSMGR->isSinglePlayer() && isClientObject() && getServerObject())
+   /*if (PHYSICSMGR->isSinglePlayer() && isClientObject() && getServerObject())
    {
       RigidBodyComponent *servObj = (RigidBodyComponent*)getServerObject();
       mOwner->setTransform(servObj->mState.getTransform());
@@ -296,7 +296,7 @@ void RigidBodyComponent::processTick()
       mRenderState[1] = servObj->mRenderState[1];
 
       return;
-   }
+   }*/
 
    // Store the last render state.
    mRenderState[0] = mRenderState[1];

+ 237 - 134
Engine/source/T3D/components/render/meshComponent.cpp

@@ -45,52 +45,49 @@
 #include "core/strings/findMatch.h"
 #include "T3D/components/render/meshComponent_ScriptBinding.h"
 
+ImplementEnumType(BatchingMode,
+   "Type of mesh data available in a shape.\n"
+   "@ingroup gameObjects")
+{
+   MeshComponent::Individual, "Individual", "This mesh is rendered indivudally, wthout batching or instancing."
+},
+   { MeshComponent::StaticBatch, "Static Batching", "Statically batches this mesh together with others to reduce drawcalls." },
+   //{ MeshComponent::DynamicBatch, "Dynamic Batching", "Dynamical batches this mesh together with others to reduce drawcalls each frame." },
+  // { MeshComponent::Instanced, "Instanced", "This mesh is rendered as an instance, reducing draw overhead with others that share the same mesh and material." },
+      EndImplementEnumType;
+
 //////////////////////////////////////////////////////////////////////////
 // Constructor/Destructor
 //////////////////////////////////////////////////////////////////////////
 MeshComponent::MeshComponent() : Component()
 {
-   mShapeName = StringTable->insert("");
-   mShapeAsset = StringTable->insert("");
-   mShapeInstance = NULL;
-
-   mChangingMaterials.clear();
-
-   mMaterials.clear();
-
    mFriendlyName = "Mesh Component";
    mComponentType = "Render";
 
    mDescription = getDescriptionText("Causes the object to render a non-animating 3d shape using the file provided.");
 
    mNetworked = true;
-   mNetFlags.set(Ghostable | ScopeAlways);
-}
 
-MeshComponent::~MeshComponent(){}
+   mShapeName = StringTable->EmptyString();
+   mShapeAsset = StringTable->EmptyString();
 
-IMPLEMENT_CO_NETOBJECT_V1(MeshComponent);
+   mMeshAsset = StringTable->EmptyString();
+   mMeshAssetId = StringTable->EmptyString();
 
-//==========================================================================================
-void MeshComponent::boneObject::addObject(SimObject* object)
-{
-   SceneObject* sc = dynamic_cast<SceneObject*>(object);
-
-   if(sc && mOwner)
-   {
-      if(TSShape* shape = mOwner->getShape())
-      {
-         S32 nodeID = shape->findNode(mBoneName);
+   mInterfaceData = new MeshRenderSystemInterface();
 
-         //we may have a offset on the shape's center
-         //so make sure we accomodate for that when setting up the mount offsets
-         MatrixF mat = mOwner->getNodeTransform(nodeID);
+   mRenderMode = Individual;
+}
 
-         mOwner->getOwner()->mountObject(sc, nodeID, mat);
-      }
-   }
+MeshComponent::~MeshComponent()
+{
+   if (mInterfaceData)
+      SAFE_DELETE(mInterfaceData);
 }
 
+IMPLEMENT_CO_NETOBJECT_V1(MeshComponent);
+
+//==========================================================================================
 bool MeshComponent::onAdd()
 {
    if(! Parent::onAdd())
@@ -106,6 +103,12 @@ void MeshComponent::onComponentAdd()
 {
    Parent::onComponentAdd();
 
+   if (isClientObject())
+      mInterfaceData->mIsClient = true;
+
+  // if (mInterfaceData != nullptr)
+  //   mInterfaceData->mIsClient = isClientObject();
+
    //get the default shape, if any
    updateShape();
 }
@@ -113,10 +116,6 @@ void MeshComponent::onComponentAdd()
 void MeshComponent::onRemove()
 {
    Parent::onRemove();
-
-   mMeshAsset.clear();
-
-   SAFE_DELETE(mShapeInstance);
 }
 
 void MeshComponent::onComponentRemove()
@@ -135,9 +134,14 @@ void MeshComponent::initPersistFields()
 {
    Parent::initPersistFields();
 
+   addGroup("Rendering");
+   addField("BatchingMode", TypeBatchingMode, Offset(mRenderMode, MeshComponent),
+      "The mode of batching this shape should be rendered with.");
+   endGroup("Rendering");
+
    //create a hook to our internal variables
    addGroup("Model");
-   addProtectedField("MeshAsset", TypeAssetId, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn, 
+   addProtectedField("MeshAsset", TypeShapeAssetPtr, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn,
       "The asset Id used for the mesh.", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
    endGroup("Model");
 }
@@ -165,6 +169,9 @@ bool MeshComponent::_setShape( void *object, const char *index, const char *data
 bool MeshComponent::setMeshAsset(const char* assetName)
 {
    // Fetch the asset Id.
+   if (mInterfaceData == nullptr)
+      return false;
+
    mMeshAssetId = StringTable->insert(assetName);
 
    mMeshAsset = mMeshAssetId;
@@ -183,9 +190,129 @@ bool MeshComponent::setMeshAsset(const char* assetName)
    return true;
 }
 
+void MeshComponent::updateShape()
+{
+   if (mInterfaceData == nullptr)
+      return;
+
+   //if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0'))
+   if ((mShapeName && mShapeName[0] != '\0') || (mMeshAssetId && mMeshAssetId[0] != '\0'))
+
+   {
+      if (mMeshAsset == NULL)
+         return;
+
+      mShape = mMeshAsset->getShape();
+
+      if (!mMeshAsset->getShape())
+         return;
+
+      setupShape();
+
+      //Do this on both the server and client
+      S32 materialCount = mMeshAsset->getShape()->materialList->getMaterialNameList().size();
+
+      if (isServerObject())
+      {
+         //we need to update the editor
+         for (U32 i = 0; i < mFields.size(); i++)
+         {
+            //find any with the materialslot title and clear them out
+            if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false))
+            {
+               setDataField(mFields[i].mFieldName, NULL, "");
+               mFields.erase(i);
+               continue;
+            }
+         }
+
+         //next, get a listing of our materials in the shape, and build our field list for them
+         char matFieldName[128];
+
+         if (materialCount > 0)
+            mComponentGroup = StringTable->insert("Materials");
+
+         for (U32 i = 0; i < materialCount; i++)
+         {
+            String materialname = mMeshAsset->getShape()->materialList->getMaterialName(i);
+            if (materialname == String("ShapeBounds"))
+               continue;
+
+            dSprintf(matFieldName, 128, "MaterialSlot%d", i);
+
+            addComponentField(matFieldName, "A material used in the shape file", "Material", materialname, "");
+         }
+
+         if (materialCount > 0)
+            mComponentGroup = "";
+      }
+
+      if (mOwner != NULL)
+      {
+         Point3F min, max, pos;
+         pos = mOwner->getPosition();
+
+         mOwner->getWorldToObj().mulP(pos);
+
+         min = mMeshAsset->getShape()->bounds.minExtents;
+         max = mMeshAsset->getShape()->bounds.maxExtents;
+
+         if (mInterfaceData)
+         {
+            mInterfaceData->mBounds.set(min, max);
+            mInterfaceData->mScale = mOwner->getScale();
+            mInterfaceData->mTransform = mOwner->getRenderTransform();
+         }
+
+         mOwner->setObjectBox(Box3F(min, max));
+
+         mOwner->resetWorldBox();
+
+         if (mOwner->getSceneManager() != NULL)
+            mOwner->getSceneManager()->notifyObjectDirty(mOwner);
+      }
+
+      if (isClientObject() && mInterfaceData)
+      {
+         if (mRenderMode == StaticBatch)
+         {
+            mInterfaceData->mStatic = true;
+
+            OptimizedPolyList geom;
+            MatrixF transform = mInterfaceData->mTransform;
+            mInterfaceData->mGeometry.setTransform(&transform, mInterfaceData->mScale);
+            mInterfaceData->mGeometry.setObject(mOwner);
+
+            mInterfaceData->mShapeInstance->buildPolyList(&mInterfaceData->mGeometry, 0);
+         }
+         else
+         {
+            mInterfaceData->mStatic = false;
+         }
+
+         MeshRenderSystem::rebuildBuffers();
+      }
+
+      //finally, notify that our shape was changed
+      onShapeInstanceChanged.trigger(this);
+   }
+}
+
+void MeshComponent::setupShape()
+{
+   mInterfaceData->mShapeInstance = new TSShapeInstance(mMeshAsset->getShape(), true);
+}
+
 void MeshComponent::_onResourceChanged( const Torque::Path &path )
 {
-   if ( path != Torque::Path( mShapeName ) )
+   if (mInterfaceData == nullptr)
+      return;
+
+   String filePath;
+   if (mMeshAsset)
+      filePath = Torque::Path(mMeshAsset->getShapeFilename());
+
+   if (!mMeshAsset || path != Torque::Path(mMeshAsset->getShapeFilename()) )
       return;
 
    updateShape();
@@ -216,6 +343,8 @@ U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
    if (stream->writeFlag(mask & ShapeMask))
    {
       stream->writeString(mShapeName);
+
+      stream->writeInt(mRenderMode, 8);
    }
 
    if (stream->writeFlag( mask & MaterialMask ))
@@ -226,7 +355,7 @@ U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
       {
          stream->writeInt(mChangingMaterials[i].slot, 16);
 
-         NetStringHandle matNameStr = mChangingMaterials[i].matName.c_str();
+         NetStringHandle matNameStr = mChangingMaterials[i].assetId.c_str();
          con->packNetStringHandleU(stream, matNameStr);
       }
 
@@ -243,6 +372,8 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream)
    if(stream->readFlag())
    {
       mShapeName = stream->readSTString();
+
+      mRenderMode = (RenderMode)stream->readInt(8);
       setMeshAsset(mShapeName);
       updateShape();
    }
@@ -256,7 +387,10 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream)
       {
          matMap newMatMap;
          newMatMap.slot = stream->readInt(16);
-         newMatMap.matName = String(con->unpackNetStringHandleU(stream).getString());
+         newMatMap.assetId = String(con->unpackNetStringHandleU(stream).getString());
+
+         //do the lookup, now
+         newMatMap.matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newMatMap.assetId);
 
          mChangingMaterials.push_back(newMatMap);
       }
@@ -267,7 +401,7 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream)
 
 void MeshComponent::prepRenderImage( SceneRenderState *state )
 {
-   if (!mEnabled || !mOwner || !mShapeInstance)
+   /*if (!mEnabled || !mOwner || !mShapeInstance)
       return;
 
    Point3F cameraOffset;
@@ -300,114 +434,41 @@ void MeshComponent::prepRenderImage( SceneRenderState *state )
    rdata.setLightQuery(&query);
 
    MatrixF mat = mOwner->getRenderTransform();
-   Point3F renderPos = mat.getPosition();
-   EulerF renderRot = mat.toEuler();
-   mat.scale(objScale);
-   GFX->setWorldMatrix(mat);
-
-   mShapeInstance->render(rdata);
-}
-
-void MeshComponent::updateShape()
-{
-   bool isServer = isServerObject();
 
-   if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0'))
+   if (mOwner->isMounted())
    {
-      if (mMeshAsset == NULL)
-         return;
-
-      mShape = mMeshAsset->getShape();
-
-      if (!mShape)
-         return;
-
-      setupShape();
-
-      //Do this on both the server and client
-      S32 materialCount = mShape->materialList->getMaterialNameList().size();
-
-      if(isServerObject())
-      {
-         //we need to update the editor
-         for (U32 i = 0; i < mFields.size(); i++)
-         {
-            //find any with the materialslot title and clear them out
-            if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false))
-            {
-               setDataField(mFields[i].mFieldName, NULL, "");
-               mFields.erase(i);
-               continue;
-            }
-         }
-
-         //next, get a listing of our materials in the shape, and build our field list for them
-         char matFieldName[128];
-
-         if(materialCount > 0)
-            mComponentGroup = StringTable->insert("Materials");
-
-         for(U32 i=0; i < materialCount; i++)
-         {
-            String materialname = mShape->materialList->getMaterialName(i);
-            if(materialname == String("ShapeBounds"))
-               continue;
+      MatrixF wrldPos = mOwner->getWorldTransform();
+      Point3F wrldPosPos = wrldPos.getPosition();
 
-            dSprintf(matFieldName, 128, "MaterialSlot%d", i);
-            
-            addComponentField(matFieldName, "A material used in the shape file", "TypeAssetId", materialname, "");
-         }
-
-         if(materialCount > 0)
-            mComponentGroup = "";
-      }
-
-      if(mOwner != NULL)
-      {
-         Point3F min, max, pos;
-         pos = mOwner->getPosition();
-
-         mOwner->getWorldToObj().mulP(pos);
+      Point3F mntPs = mat.getPosition();
+      EulerF mntRt = RotationF(mat).asEulerF();
 
-         min = mShape->bounds.minExtents;
-         max = mShape->bounds.maxExtents;
-
-         mShapeBounds.set(min, max);
-
-         mOwner->setObjectBox(Box3F(min, max));
-
-         if( mOwner->getSceneManager() != NULL )
-            mOwner->getSceneManager()->notifyObjectDirty( mOwner );
-      }
-
-      //finally, notify that our shape was changed
-      onShapeInstanceChanged.trigger(this);
+      bool tr = true;
    }
-}
 
-void MeshComponent::setupShape()
-{
-   mShapeInstance = new TSShapeInstance(mShape, true);
+   mat.scale(objScale);
+   GFX->setWorldMatrix(mat);
+
+   mShapeInstance->render(rdata);*/
 }
 
 void MeshComponent::updateMaterials()
 {
-   if (mChangingMaterials.empty() || !mShape)
+   if (mChangingMaterials.empty() || !mMeshAsset->getShape())
       return;
 
-   TSMaterialList* pMatList = mShapeInstance->getMaterialList();
+   TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList();
    pMatList->setTextureLookupPath(getShapeResource().getPath().getPath());
 
    const Vector<String> &materialNames = pMatList->getMaterialNameList();
    for ( S32 i = 0; i < materialNames.size(); i++ )
    {
-      const String &pName = materialNames[i];
-
       for(U32 m=0; m < mChangingMaterials.size(); m++)
       {
          if(mChangingMaterials[m].slot == i)
          {
-            pMatList->renameMaterial( i, mChangingMaterials[m].matName );
+            //Fetch the actual material asset
+            pMatList->renameMaterial( i, mChangingMaterials[m].matAsset->getMaterialDefinitionName());
          }
       }
 
@@ -415,22 +476,31 @@ void MeshComponent::updateMaterials()
    }
 
    // Initialize the material instances
-   mShapeInstance->initMaterialList();
+   mInterfaceData->mShapeInstance->initMaterialList();
 }
 
 MatrixF MeshComponent::getNodeTransform(S32 nodeIdx)
 {
-   if (mShape)
+   if (mInterfaceData != nullptr && mMeshAsset->getShape())
    {
       S32 nodeCount = getShape()->nodes.size();
 
       if(nodeIdx >= 0 && nodeIdx < nodeCount)
       {
          //animate();
-         MatrixF mountTransform = mShapeInstance->mNodeTransforms[nodeIdx];
-         mountTransform.mul(mOwner->getRenderTransform());
+         MatrixF nodeTransform = mInterfaceData->mShapeInstance->mNodeTransforms[nodeIdx];
+         const Point3F& scale = mOwner->getScale();
+
+         // The position of the node needs to be scaled.
+         Point3F position = nodeTransform.getPosition();
+         position.convolve(scale);
+         nodeTransform.setPosition(position);
+
+         MatrixF finalTransform = MatrixF::Identity;
+
+         finalTransform.mul(mOwner->getRenderTransform(), nodeTransform);
 
-         return mountTransform;
+         return finalTransform;
       }
    }
 
@@ -439,7 +509,7 @@ MatrixF MeshComponent::getNodeTransform(S32 nodeIdx)
 
 S32 MeshComponent::getNodeByName(String nodeName)
 {
-   if (mShape)
+   if (mMeshAsset->getShape())
    {
       S32 nodeIdx = getShape()->findNode(nodeName);
 
@@ -485,12 +555,18 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue
       if(slot == -1)
          return;
 
+      //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name
+      MaterialAsset* matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newValue);
+      if (!matAsset)
+         return;
+
       bool found = false;
       for(U32 i=0; i < mChangingMaterials.size(); i++)
       {
          if(mChangingMaterials[i].slot == slot)
          {
-            mChangingMaterials[i].matName = String(newValue);
+            mChangingMaterials[i].matAsset = matAsset;
+            mChangingMaterials[i].assetId = newValue;
             found = true;
          }
       }
@@ -499,7 +575,8 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue
       {
          matMap newMatMap;
          newMatMap.slot = slot;
-         newMatMap.matName = String(newValue);
+         newMatMap.matAsset = matAsset;
+         newMatMap.assetId = newValue;
 
          mChangingMaterials.push_back(newMatMap);
       }
@@ -510,14 +587,31 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue
    Parent::onDynamicModified(slotName, newValue);
 }
 
-void MeshComponent::changeMaterial(U32 slot, const char* newMat)
+void MeshComponent::changeMaterial(U32 slot, MaterialAsset* newMat)
 {
    
    char fieldName[512];
 
    //update our respective field
    dSprintf(fieldName, 512, "materialSlot%d", slot);
-   setDataField(fieldName, NULL, newMat);
+   setDataField(fieldName, NULL, newMat->getAssetId());
+}
+
+bool MeshComponent::setMatInstField(U32 slot, const char* field, const char* value)
+{
+   TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList();
+   pMatList->setTextureLookupPath(getShapeResource().getPath().getPath());
+
+   MaterialParameters* params = pMatList->getMaterialInst(slot)->getMaterialParameters();
+
+   if (pMatList->getMaterialInst(slot)->getFeatures().hasFeature(MFT_DiffuseColor))
+   {
+      MaterialParameterHandle* handle = pMatList->getMaterialInst(slot)->getMaterialParameterHandle("DiffuseColor");
+
+      params->set(handle, LinearColorF(0, 0, 0));
+   }
+
+   return true;
 }
 
 void MeshComponent::onInspect()
@@ -526,4 +620,13 @@ void MeshComponent::onInspect()
 
 void MeshComponent::onEndInspect()
 {
+}
+
+void MeshComponent::ownerTransformSet(MatrixF *mat)
+{
+   if (mInterfaceData != nullptr)
+   {
+      MatrixF newTransform = *mat;
+      mInterfaceData->mTransform = newTransform;
+   }
 }

+ 25 - 16
Engine/source/T3D/components/render/meshComponent.h

@@ -60,6 +60,8 @@
 #include "gfx/gfxVertexFormat.h"
 #endif
 
+#include "T3D/systems/render/meshRenderSystem.h"
+
 class TSShapeInstance;
 class SceneRenderState;
 //////////////////////////////////////////////////////////////////////////
@@ -84,37 +86,38 @@ protected:
    StringTableEntry		mShapeName;
    StringTableEntry		mShapeAsset;
    TSShape*		         mShape;
-   Box3F						mShapeBounds;
+   //Box3F						mShapeBounds;
    Point3F					mCenterOffset;
 
+   MeshRenderSystemInterface*  mInterfaceData;
+
    struct matMap
    {
-      String matName;
+      MaterialAsset* matAsset;
+      String assetId;
       U32 slot;
    };
 
    Vector<matMap>  mChangingMaterials;
    Vector<matMap>  mMaterials;
 
-   class boneObject : public SimGroup
+public:
+   enum RenderMode
    {
-      MeshComponent *mOwner;
-   public:
-      boneObject(MeshComponent *owner){ mOwner = owner; }
-
-      StringTableEntry mBoneName;
-      S32 mItemID;
-
-      virtual void addObject(SimObject *obj);
+      Individual = 0,
+      DynamicBatch,
+      StaticBatch,
+      Instanced
    };
 
-   Vector<boneObject*> mNodesList;
+protected:
+   RenderMode           mRenderMode;
 
 public:
    StringTableEntry       mMeshAssetId;
    AssetPtr<ShapeAsset>   mMeshAsset;
 
-   TSShapeInstance*       mShapeInstance;
+   //TSShapeInstance*       mShapeInstance;
 
 public:
    MeshComponent();
@@ -132,7 +135,7 @@ public:
    virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
    virtual void unpackUpdate(NetConnection *con, BitStream *stream);
 
-   Box3F getShapeBounds() { return mShapeBounds; }
+   Box3F getShapeBounds() { return mInterfaceData->mBounds; }
 
    virtual MatrixF getNodeTransform(S32 nodeIdx);
    S32 getNodeByName(String nodeName);
@@ -144,6 +147,8 @@ public:
    virtual void onComponentRemove();
    virtual void onComponentAdd();
 
+   virtual void ownerTransformSet(MatrixF *mat);
+
    static bool _setMesh(void *object, const char *index, const char *data);
    static bool _setShape(void *object, const char *index, const char *data);
    const char* _getShape(void *object, const char *data);
@@ -151,7 +156,7 @@ public:
    bool setMeshAsset(const char* assetName);
 
    virtual TSShape* getShape() { if (mMeshAsset)  return mMeshAsset->getShape(); else return NULL; }
-   virtual TSShapeInstance* getShapeInstance() { return mShapeInstance; }
+   virtual TSShapeInstance* getShapeInstance() { return mInterfaceData->mShapeInstance; }
 
    Resource<TSShape> getShapeResource() { return mMeshAsset->getShapeResource(); }
 
@@ -163,7 +168,8 @@ public:
 
    virtual void onDynamicModified(const char* slotName, const char* newValue);
 
-   void changeMaterial(U32 slot, const char* newMat);
+   void changeMaterial(U32 slot, MaterialAsset* newMat);
+   bool setMatInstField(U32 slot, const char* field, const char* value);
 
    virtual void onInspect();
    virtual void onEndInspect();
@@ -180,4 +186,7 @@ public:
    }
 };
 
+typedef MeshComponent::RenderMode BatchingMode;
+DefineEnumType(BatchingMode);
+
 #endif

+ 29 - 1
Engine/source/T3D/components/render/meshComponent_ScriptBinding.h

@@ -126,6 +126,28 @@ DefineEngineMethod(MeshComponent, getNodePosition, Point3F,
    return Point3F(0, 0, 0);
 }
 
+DefineEngineMethod(MeshComponent, getNodeRotation, EulerF,
+   (S32 node), (-1),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   if (node != -1)
+   {
+      //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen
+      //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity
+      //object->mountObjectToNode( objB, node, /*MatrixF::Identity*/txfm.getMatrix() );
+      RotationF mat = object->getNodeTransform(node);
+
+      return mat.asEulerF(RotationF::Degrees);
+   }
+
+   return EulerF(0, 0, 0);
+}
+
 DefineEngineMethod(MeshComponent, getNodeByName, S32,
    (String nodeName), ,
    "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
@@ -148,8 +170,14 @@ DefineEngineMethod(MeshComponent, getNodeByName, S32,
    return -1;
 }
 
-DefineEngineMethod(MeshComponent, changeMaterial, void, (U32 slot, const char* newMat), (0, ""),
+DefineEngineMethod(MeshComponent, changeMaterial, void, (U32 slot, MaterialAsset* newMat), (0, nullAsType<MaterialAsset*>()),
    "@brief Change one of the materials on the shape.\n\n")
 {
    object->changeMaterial(slot, newMat);
+}
+
+DefineEngineMethod(MeshComponent, setMatInstField, bool, (U32 slot, const char* field, const char* value), (0, "", ""),
+   "@brief Change one of the materials on the shape.\n\n")
+{
+   return object->setMatInstField(slot, field, value);
 }

+ 265 - 58
Engine/source/T3D/entity.cpp

@@ -47,7 +47,9 @@
 #include "T3D/gameBase/std/stdMoveList.h"
 
 #include "T3D/prefab.h"
+#include "T3D/gameBase/gameConnection.h"
 
+#include <thread>
 //
 #include "gfx/sim/debugDraw.h"
 //
@@ -118,6 +120,8 @@ Entity::Entity()
 
    mInitialized = false;
 
+   mLifetimeMS = 0;
+
    mGameObjectAssetId = StringTable->insert("");
 
 }
@@ -147,6 +151,10 @@ void Entity::initPersistFields()
 
    endGroup("Transform");
 
+   addGroup("Misc");
+   addField("LifetimeMS", TypeS32, Offset(mLifetimeMS, Entity), "Object world orientation.");
+   endGroup("Misc");
+
    addGroup("GameObject");
    addProtectedField("gameObjectName", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, Entity), &_setGameObject, &defaultProtectedGetFn,
       "The asset Id used for the game object this entity is based on.");
@@ -231,8 +239,19 @@ bool Entity::onAdd()
    addToScene();
 
    //Make sure we get positioned
-   setMaskBits(TransformMask);
-   setMaskBits(NamespaceMask);
+   if (isServerObject())
+   {
+      setMaskBits(TransformMask);
+      setMaskBits(NamespaceMask);
+   }
+   else
+   {
+      //We can shortcut the initialization here because stuff generally ghosts down in order, and onPostAdd isn't called on ghosts.
+      onPostAdd();
+   }
+
+   if (mLifetimeMS != 0)
+      mStartTimeMS = Platform::getRealMilliseconds();
 
    return true;
 }
@@ -245,6 +264,8 @@ void Entity::onRemove()
 
    onDataSet.removeAll();
 
+   mGameObjectAsset.clear();
+
    Parent::onRemove();
 }
 
@@ -258,6 +279,27 @@ void Entity::onPostAdd()
       mComponents[i]->onComponentAdd();
    }
 
+   //Set up the networked components
+   mNetworkedComponents.clear();
+   for (U32 i = 0; i < mComponents.size(); i++)
+   {
+      if (mComponents[i]->isNetworked())
+      {
+         NetworkedComponent netComp;
+         netComp.componentIndex = i;
+         netComp.updateState = NetworkedComponent::Adding;
+         netComp.updateMaskBits = -1;
+
+         mNetworkedComponents.push_back(netComp);
+      }
+   }
+
+   if (!mNetworkedComponents.empty())
+   {
+      setMaskBits(AddComponentsMask);
+      setMaskBits(ComponentsUpdateMask);
+   }
+
    if (isMethod("onAdd"))
       Con::executef(this, "onAdd");
 }
@@ -396,6 +438,14 @@ void Entity::processTick(const Move* move)
       mDelta.rot[1] = mRot.asQuatF();
 
       setTransform(getPosition(), mRot);
+
+      //Lifetime test
+      if (mLifetimeMS != 0)
+      {
+         S32 currentTime = Platform::getRealMilliseconds();
+         if (currentTime - mStartTimeMS >= mLifetimeMS)
+            deleteObject();
+      }
    }
 }
 
@@ -446,62 +496,107 @@ U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
       mathWrite(*stream, mObjBox);
    }
 
-   //pass our behaviors around
-   if (mask & ComponentsMask || mask & InitialUpdateMask)
+   if (stream->writeFlag(mask & AddComponentsMask))
    {
-      stream->writeFlag(true);
-      //now, we run through a list of our to-be-sent behaviors and begin sending them
-      //if any fail, we keep our list and re-queue the mask
-      S32 componentCount = mToLoadComponents.size();
+      U32 toAddComponentCount = 0;
 
-      //build our 'ready' list
-      //This requires both the instance and the instances' template to be prepped(if the template hasn't been ghosted,
-      //then we know we shouldn't be passing the instance's ghosts around yet)
-      U32 ghostedCompCnt = 0;
-      for (U32 i = 0; i < componentCount; i++)
+      for (U32 i = 0; i < mNetworkedComponents.size(); i++)
       {
-         if (con->getGhostIndex(mToLoadComponents[i]) != -1)
-            ghostedCompCnt++;
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
+         {
+            toAddComponentCount++;
+         }
       }
 
-      if (ghostedCompCnt != 0)
+      //you reaaaaally shouldn't have >255 networked components on a single entity
+      stream->writeInt(toAddComponentCount, 8);
+
+      for (U32 i = 0; i < mNetworkedComponents.size(); i++)
       {
-         stream->writeFlag(true);
+         NetworkedComponent::UpdateState state = mNetworkedComponents[i].updateState;
 
-         stream->writeFlag(mStartComponentUpdate);
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
+         {
+            const char* className = mComponents[mNetworkedComponents[i].componentIndex]->getClassName();
+            stream->writeString(className, strlen(className));
 
-         //if not all the behaviors have been ghosted, we'll need another pass
-         if (ghostedCompCnt != componentCount)
-            retMask |= ComponentsMask;
+            mNetworkedComponents[i].updateState = NetworkedComponent::Updating;
+         }
+      }
+   }
 
-         //write the currently ghosted behavior count
-         stream->writeInt(ghostedCompCnt, 16);
+   if (stream->writeFlag(mask & RemoveComponentsMask))
+   {
+      /*U32 toRemoveComponentCount = 0;
 
-         for (U32 i = 0; i < mToLoadComponents.size(); i++)
+      for (U32 i = 0; i < mNetworkedComponents.size(); i++)
+      {
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
          {
-            //now fetch them and pass the ghost
-            S32 ghostIndex = con->getGhostIndex(mToLoadComponents[i]);
-            if (ghostIndex != -1)
-            {
-               stream->writeInt(ghostIndex, NetConnection::GhostIdBitSize);
-               mToLoadComponents.erase(i);
-               i--;
+            toRemoveComponentCount++;
+         }
+      }
+
+      //you reaaaaally shouldn't have >255 networked components on a single entity
+      stream->writeInt(toRemoveComponentCount, 8);
+
+      for (U32 i = 0; i < mNetworkedComponents.size(); i++)
+      {
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::Removing)
+         {
+            stream->writeInt(i, 16);
+         }
+      }*/
+
+      /*for (U32 i = 0; i < mNetworkedComponents.size(); i++)
+      {
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::UpdateState::Removing)
+         {
+            removeComponent(mComponents[mNetworkedComponents[i].componentIndex], true);
+            mNetworkedComponents.erase(i);
+            i--;
 
-               mStartComponentUpdate = false;
-            }
+         }
+      }*/
+   }
+
+   //Update our components
+   if (stream->writeFlag(mask & ComponentsUpdateMask))
+   {
+      U32 toUpdateComponentCount = 0;
+
+      for (U32 i = 0; i < mNetworkedComponents.size(); i++)
+      {
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating)
+         {
+            toUpdateComponentCount++;
          }
       }
-      else if (componentCount)
+
+      //you reaaaaally shouldn't have >255 networked components on a single entity
+      stream->writeInt(toUpdateComponentCount, 8);
+
+      bool forceUpdate = false;
+
+      for (U32 i = 0; i < mNetworkedComponents.size(); i++)
       {
-         //on the odd chance we have behaviors to ghost, but NONE of them have been yet, just set the flag now
-         stream->writeFlag(false);
-         retMask |= ComponentsMask;
+         if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating)
+         {
+            stream->writeInt(i, 8);
+
+            mNetworkedComponents[i].updateMaskBits = mComponents[mNetworkedComponents[i].componentIndex]->packUpdate(con, mNetworkedComponents[i].updateMaskBits, stream);
+
+            if (mNetworkedComponents[i].updateMaskBits != 0)
+               forceUpdate = true;
+            else
+               mNetworkedComponents[i].updateState = NetworkedComponent::None;
+         }
       }
-      else
-         stream->writeFlag(false);
+
+      //If we have leftover, we need to re-iterate our packing
+      if (forceUpdate)
+         setMaskBits(ComponentsUpdateMask);
    }
-   else
-      stream->writeFlag(false);
 
    /*if (stream->writeFlag(mask & NamespaceMask))
    {
@@ -594,25 +689,52 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream)
       resetWorldBox();
    }
 
+   //AddComponentMask
    if (stream->readFlag())
    {
-      //are we passing any behaviors currently?
-      if (stream->readFlag())
+      U32 addedComponentCount = stream->readInt(8);
+
+      for (U32 i = 0; i < addedComponentCount; i++)
       {
-         //if we've just started the update, clear our behaviors
-         if (stream->readFlag())
-            clearComponents(false);
+         char className[256] = "";
+         stream->readString(className);
+
+         //Change to components, so iterate our list and create any new components
+         // Well, looks like we have to create a new object.
+         const char* componentType = className;
+
+         ConsoleObject *object = ConsoleObject::create(componentType);
 
-         S32 componentCount = stream->readInt(16);
+         // Finally, set currentNewObject to point to the new one.
+         Component* newComponent = dynamic_cast<Component *>(object);
 
-         for (U32 i = 0; i < componentCount; i++)
+         if (newComponent)
          {
-            S32 gIndex = stream->readInt(NetConnection::GhostIdBitSize);
-            addComponent(dynamic_cast<Component*>(con->resolveGhost(gIndex)));
+            addComponent(newComponent);
          }
       }
    }
 
+   //RemoveComponentMask
+   if (stream->readFlag())
+   {
+      
+   }
+
+   //ComponentUpdateMask
+   if (stream->readFlag())
+   {
+      U32 updatingComponents = stream->readInt(8);
+
+      for (U32 i = 0; i < updatingComponents; i++)
+      {
+         U32 updateComponentIndex = stream->readInt(8);
+
+         Component* comp = mComponents[updateComponentIndex];
+         comp->unpackUpdate(con, stream);
+      }
+   }
+
    /*if (stream->readFlag())
    {
       if (stream->readFlag())
@@ -640,6 +762,26 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream)
    }*/
 }
 
+void Entity::setComponentNetMask(Component* comp, U32 mask)
+{
+   setMaskBits(Entity::ComponentsUpdateMask);
+
+   for (U32 i = 0; i < mNetworkedComponents.size(); i++)
+   {
+      U32 netCompId = mComponents[mNetworkedComponents[i].componentIndex]->getId();
+      U32 compId = comp->getId();
+
+      if (netCompId == compId && 
+         (mNetworkedComponents[i].updateState == NetworkedComponent::None || mNetworkedComponents[i].updateState == NetworkedComponent::Updating))
+      {
+         mNetworkedComponents[i].updateState = NetworkedComponent::Updating;
+         mNetworkedComponents[i].updateMaskBits |= mask;
+
+         break;
+      }
+   }
+}
+
 //Manipulation
 void Entity::setTransform(const MatrixF &mat)
 {
@@ -758,7 +900,11 @@ void Entity::setTransform(Point3F position, RotationF rotation)
       // Update the transforms.
       Parent::setTransform(newMat);
 
-      onTransformSet.trigger(&newMat);
+      U32 compCount = mComponents.size();
+      for (U32 i = 0; i < compCount; ++i)
+      {
+         mComponents[i]->ownerTransformSet(&newMat);
+      }
 
       Point3F newPos = newMat.getPosition();
       RotationF newRot = newMat;
@@ -800,7 +946,11 @@ void Entity::setRenderTransform(Point3F position, RotationF rotation)
 
       Parent::setRenderTransform(newMat);
 
-      onTransformSet.trigger(&newMat);
+      U32 compCount = mComponents.size();
+      for (U32 i = 0; i < compCount; ++i)
+      {
+         mComponents[i]->ownerTransformSet(&newMat);
+      }
    }
 }
 
@@ -1155,11 +1305,28 @@ bool Entity::addComponent(Component *comp)
    // Register the component with this owner.
    comp->setOwner(this);
 
+   comp->setIsServerObject(isServerObject());
+
    //if we've already been added and this is being added after the fact(at runtime), 
    //then just go ahead and call it's onComponentAdd so it can get to work
-   if (mInitialized)
+   //if (mInitialized)
+   {
       comp->onComponentAdd();
 
+      if (comp->isNetworked())
+      {
+         NetworkedComponent netComp;
+         netComp.componentIndex = mComponents.size() - 1;
+         netComp.updateState = NetworkedComponent::Adding;
+         netComp.updateMaskBits = -1;
+
+         mNetworkedComponents.push_back(netComp);
+
+         setMaskBits(AddComponentsMask);
+         setMaskBits(ComponentsUpdateMask);
+      }
+   }
+
    onComponentAdded.trigger(comp);
 
    return true;
@@ -1269,7 +1436,7 @@ Component *Entity::getComponent(String componentType)
          Namespace *NS = comp->getNamespace();
 
          //we shouldn't ever go past Component into net object, as we're no longer dealing with component classes
-         while (dStrcmp(NS->getName(), "NetObject"))
+         while (dStrcmp(NS->getName(), "SimObject"))
          {
             String namespaceName = NS->getName();
 
@@ -1497,7 +1664,8 @@ void Entity::notifyComponents(String signalFunction, String argA, String argB, S
 
 void Entity::setComponentsDirty()
 {
-   if (mToLoadComponents.empty())
+   bool tmp = true;
+   /*if (mToLoadComponents.empty())
       mStartComponentUpdate = true;
 
    //we need to build a list of behaviors that need to be pushed across the network
@@ -1522,7 +1690,7 @@ void Entity::setComponentsDirty()
       }
    }
 
-   setMaskBits(ComponentsMask);
+   setMaskBits(ComponentsMask);*/
 }
 
 void Entity::setComponentDirty(Component *comp, bool forceUpdate)
@@ -1654,7 +1822,7 @@ ConsoleMethod(Entity, addComponents, void, 2, 2, "() - Add all fielded behaviors
    object->addComponents();
 }*/
 
-ConsoleMethod(Entity, addComponent, bool, 3, 3, "(Component* bi) - Add a behavior to the object\n"
+ConsoleMethod(Entity, addComponent, bool, 3, 3, "(ComponentInstance bi) - Add a behavior to the object\n"
    "@param bi The behavior instance to add"
    "@return (bool success) Whether or not the behavior was successfully added")
 {
@@ -1679,7 +1847,7 @@ ConsoleMethod(Entity, addComponent, bool, 3, 3, "(Component* bi) - Add a behavio
    return false;
 }
 
-ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(Component* bi, [bool deleteBehavior = true])\n"
+ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(ComponentInstance bi, [bool deleteBehavior = true])\n"
    "@param bi The behavior instance to remove\n"
    "@param deleteBehavior Whether or not to delete the behavior\n"
    "@return (bool success) Whether the behavior was successfully removed")
@@ -1834,4 +2002,43 @@ DefineConsoleMethod(Entity, notify, void, (String signalFunction, String argA, S
       return;
 
    object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);
+}
+
+DefineConsoleFunction(findEntitiesByTag, const char*, (SimGroup* searchingGroup, String tags), (nullAsType<SimGroup*>(), ""),
+"Finds all entities that have the provided tags.\n"
+"@param searchingGroup The SimGroup to search inside. If null, we'll search the entire dictionary(this can be slow!).\n"
+"@param tags Word delimited list of tags to search for. If multiple tags are included, the list is eclusively parsed, requiring all tags provided to be found on an entity for a match.\n"
+"@return A word list of IDs of entities that match the tag search terms.")
+{
+   //if (tags.isEmpty())
+      return "";
+
+   /*if (searchingGroup == nullptr)
+   {
+      searchingGroup = Sim::getRootGroup();
+   }
+
+   StringTableEntry entityStr = StringTable->insert("Entity");
+
+   std::thread threadBob;
+
+   std::thread::id a = threadBob.get_id();
+   std::thread::id b = std::this_thread::get_id().;
+
+   if (a == b)
+   {
+      //do
+   }
+
+   for (SimGroup::iterator itr = searchingGroup->begin(); itr != searchingGroup->end(); itr++)
+   {
+      Entity* ent = dynamic_cast<Entity*>((*itr));
+
+      if (ent != nullptr)
+      {
+         ent->mTags.
+      }
+   }
+
+   object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);*/
 }

+ 37 - 6
Engine/source/T3D/entity.h

@@ -58,7 +58,27 @@ private:
 
    Vector<Component*>         mComponents;
 
-   Vector<Component*>         mToLoadComponents;
+   //Bit of helper data to let us track and manage the adding, removal and updating of networked components
+   struct NetworkedComponent
+   {
+      U32 componentIndex;
+
+      enum UpdateState
+      {
+         None,
+         Adding,
+         Removing,
+         Updating
+      };
+
+      UpdateState updateState;
+
+      U32 updateMaskBits;
+   };
+
+   Vector<NetworkedComponent> mNetworkedComponents;
+
+   U32                        mComponentNetMask;
 
    bool                       mStartComponentUpdate;
 
@@ -69,10 +89,12 @@ private:
 
    bool mInitialized;
 
+   String mTags;
+
    Signal< void(Component*) > onComponentAdded;
    Signal< void(Component*) > onComponentRemoved;
 
-   Signal< void(MatrixF*) > onTransformSet;
+   S32                       mLifetimeMS;
 
 protected:
 
@@ -105,10 +127,12 @@ public:
    {
       TransformMask = Parent::NextFreeMask << 0,
       BoundsMask = Parent::NextFreeMask << 1,
-      ComponentsMask = Parent::NextFreeMask << 2,
-      NoWarpMask = Parent::NextFreeMask << 3,
-      NamespaceMask = Parent::NextFreeMask << 4,
-      NextFreeMask = Parent::NextFreeMask << 5
+      ComponentsUpdateMask = Parent::NextFreeMask << 2,
+      AddComponentsMask = Parent::NextFreeMask << 3,
+      RemoveComponentsMask = Parent::NextFreeMask << 4,
+      NoWarpMask = Parent::NextFreeMask << 5,
+      NamespaceMask = Parent::NextFreeMask << 6,
+      NextFreeMask = Parent::NextFreeMask << 7
    };
 
    StateDelta mDelta;
@@ -116,6 +140,8 @@ public:
 
    Move lastMove;
 
+   S32      mStartTimeMS;
+
    //
    Entity();
    ~Entity();
@@ -163,6 +189,9 @@ public:
    /// @param  client   Client that is now controlling this object
    virtual void setControllingClient(GameConnection *client);
 
+   //
+   //Networking
+   //
    // NetObject
    U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
    void unpackUpdate(NetConnection *conn, BitStream *stream);
@@ -170,6 +199,8 @@ public:
    void setComponentsDirty();
    void setComponentDirty(Component *comp, bool forceUpdate = false);
 
+   void setComponentNetMask(Component* comp, U32 mask);
+
    //Components
    virtual bool deferAddingComponents() const { return true; }
 

+ 30 - 0
Engine/source/T3D/systems/componentSystem.h

@@ -0,0 +1,30 @@
+#pragma once
+#include "console/engineAPI.h"
+
+template<typename T>
+class SystemInterface
+{
+public:
+   bool mIsEnabled;
+   bool mIsServer;
+
+   static Vector<T*> all;
+
+   SystemInterface()
+   {
+      all.push_back((T*)this);
+   }
+
+   virtual ~SystemInterface()
+   {
+      for (U32 i = 0; i < all.size(); i++)
+      {
+         if (all[i] == (T*)this)
+         {
+            all.erase(i);
+            return;
+         }
+      }
+   }
+};
+template<typename T> Vector<T*> SystemInterface<T>::all(0);

+ 375 - 0
Engine/source/T3D/systems/render/meshRenderSystem.cpp

@@ -0,0 +1,375 @@
+#include "T3D/systems/render/meshRenderSystem.h"
+#include "gfx/gfxTransformSaver.h"
+#include "lighting/lightQuery.h"
+
+#include "renderInstance/renderPassManager.h"
+#include "materials/materialManager.h"
+#include "materials/baseMatInstance.h"
+
+Vector<MeshRenderSystem::BufferMaterials> MeshRenderSystem::mBufferMaterials(0);
+Vector<MeshRenderSystem::BufferSet> MeshRenderSystem::mStaticBuffers(0);
+
+void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* state)
+{
+   Frustum viewFrustum = state->getCullingFrustum();
+   MatrixF camTransform = state->getCameraTransform();
+
+   U32 count = MeshRenderSystemInterface::all.size();
+   for (U32 i = 0; i < count; i++)
+   {
+      //Server side items exist for data, but we don't actually render them
+      bool isClient = MeshRenderSystemInterface::all[i]->mIsClient;
+      if (!MeshRenderSystemInterface::all[i]->mIsClient)
+         continue;
+
+      bool isStatic = MeshRenderSystemInterface::all[i]->mStatic;
+      if (MeshRenderSystemInterface::all[i]->mStatic)
+         continue;
+
+      //First, do frustum culling
+      if (viewFrustum.isCulled(MeshRenderSystemInterface::all[i]->mBounds))
+         continue;
+
+      // Set the query box for the container query.  Never
+      // make it larger than the frustum's AABB.  In the editor,
+      // always query the full frustum as that gives objects
+      // the opportunity to render editor visualizations even if
+      // they are otherwise not in view.
+      if (!state->getCullingFrustum().getBounds().isOverlapped(state->getRenderArea()))
+      {
+         // This handles fringe cases like flying backwards into a zone where you
+         // end up pretty much standing on a zone border and looking directly into
+         // its "walls".  In that case the traversal area will be behind the frustum
+         // (remember that the camera isn't where visibility starts, it's the near
+         // distance).
+
+         continue;
+      }
+
+      //We can then sort our objects by range since we have it already, so we can do occlusion culling be rendering front-to-back
+
+      //if we've made it this far, call down to the render function to actually display our stuff
+      renderInterface(i, state);
+   }
+
+   //Static Batch rendering
+   if ( /*!mMaterialInst ||*/ !state)
+      return;
+
+   BaseMatInstance *matInst = MATMGR->getWarningMatInstance();
+
+   // Get a handy pointer to our RenderPassmanager
+   RenderPassManager *renderPass = state->getRenderPass();
+
+   for (U32 i = 0; i < mStaticBuffers.size(); i++)
+   {
+      for (U32 b = 0; b < mStaticBuffers[i].buffers.size(); b++)
+      {
+         if (mStaticBuffers[i].buffers[b].vertData.empty())
+            continue;
+
+         MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
+
+         // Set our RenderInst as a standard mesh render
+         ri->type = RenderPassManager::RIT_Mesh;
+
+         //If our material has transparency set on this will redirect it to proper render bin
+         if (matInst->getMaterial()->isTranslucent())
+         {
+            ri->type = RenderPassManager::RIT_Translucent;
+            ri->translucentSort = true;
+         }
+
+         // Calculate our sorting point
+         if (state)
+         {
+            // Calculate our sort point manually.
+            const Box3F& rBox = Box3F(1000);// getRenderWorldBox();
+            ri->sortDistSq = rBox.getSqDistanceToPoint(state->getCameraPosition());
+         }
+         else
+            ri->sortDistSq = 0.0f;
+
+         // Set up our transforms
+         MatrixF objectToWorld = MatrixF::Identity;//getRenderTransform();
+                                                   //objectToWorld.scale(getScale());
+
+         ri->objectToWorld = renderPass->allocUniqueXform(objectToWorld);
+         ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
+         ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
+
+         // If our material needs lights then fill the RIs 
+         // light vector with the best lights.
+         /*if (matInst->isForwardLit())
+         {
+         LightQuery query;
+         query.init(getWorldSphere());
+         query.getLights(ri->lights, 8);
+         }*/
+
+         // Make sure we have an up-to-date backbuffer in case
+         // our Material would like to make use of it
+         // NOTICE: SFXBB is removed and refraction is disabled!
+         //ri->backBuffTex = GFX->getSfxBackBuffer();
+
+         // Set our Material
+         ri->matInst = matInst;
+
+         // Set up our vertex buffer and primitive buffer
+         ri->vertBuff = &mStaticBuffers[i].buffers[b].vertexBuffer;
+         ri->primBuff = &mStaticBuffers[i].buffers[b].primitiveBuffer;
+
+         ri->prim = renderPass->allocPrim();
+         ri->prim->type = GFXTriangleList;
+         ri->prim->minIndex = 0;
+         ri->prim->startIndex = 0;
+         ri->prim->numPrimitives = mStaticBuffers[i].buffers[b].primData.size();
+         ri->prim->startVertex = 0;
+         ri->prim->numVertices = mStaticBuffers[i].buffers[b].vertData.size();
+
+         // We sort by the material then vertex buffer
+         ri->defaultKey = matInst->getStateHint();
+         ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
+
+                                                    // Submit our RenderInst to the RenderPassManager
+         state->getRenderPass()->addInst(ri);
+      }
+   }
+}
+
+void MeshRenderSystem::renderInterface(U32 interfaceIndex, SceneRenderState* state)
+{
+   //Fetch
+   MeshRenderSystemInterface* interface = MeshRenderSystemInterface::all[interfaceIndex];
+
+   if (interface->mShapeInstance == nullptr)
+      return;
+
+   Point3F cameraOffset;
+   interface->mTransform.getColumn(3, &cameraOffset);
+   cameraOffset -= state->getDiffuseCameraPosition();
+   F32 dist = cameraOffset.len();
+   if (dist < 0.01f)
+      dist = 0.01f;
+
+   Point3F objScale = interface->mScale;
+   F32 invScale = (1.0f / getMax(getMax(objScale.x, objScale.y), objScale.z));
+
+   interface->mShapeInstance->setDetailFromDistance(state, dist * invScale);
+
+   if (interface->mShapeInstance->getCurrentDetail() < 0)
+      return;
+
+   GFXTransformSaver saver;
+
+   // Set up our TS render state.
+   TSRenderState rdata;
+   rdata.setSceneState(state);
+   rdata.setFadeOverride(1.0f);
+   rdata.setOriginSort(false);
+
+   // We might have some forward lit materials
+   // so pass down a query to gather lights.
+   LightQuery query;
+   query.init(interface->mSphere);
+   rdata.setLightQuery(&query);
+
+   MatrixF mat = interface->mTransform;
+
+   mat.scale(objScale);
+   GFX->setWorldMatrix(mat);
+
+   interface->mShapeInstance->render(rdata);
+}
+
+void MeshRenderSystem::rebuildBuffers()
+{
+   U32 BUFFER_SIZE = 65000;
+   Vector<U32> tempIndices;
+   tempIndices.reserve(4);
+
+   Box3F newBounds = Box3F::Zero;
+
+   mStaticBuffers.clear();
+
+   for (U32 i = 0; i < MeshRenderSystemInterface::all.size(); i++)
+   {
+      if (!MeshRenderSystemInterface::all[i]->mIsEnabled)
+         continue;
+
+      if (!MeshRenderSystemInterface::all[i]->mIsClient || !MeshRenderSystemInterface::all[i]->mStatic)
+         continue;
+
+      //TODO: Properly re-implement StaticElements to container owner interfaces and buffer sets
+      for (U32 j = 0; j < MeshRenderSystemInterface::all[i]->mGeometry.mPolyList.size(); j++)
+      {
+         const OptimizedPolyList::Poly& poly = MeshRenderSystemInterface::all[i]->mGeometry.mPolyList[j];
+
+         if (poly.vertexCount < 3)
+            continue;
+
+         tempIndices.setSize(poly.vertexCount);
+         dMemset(tempIndices.address(), 0, poly.vertexCount);
+
+         if (poly.type == OptimizedPolyList::TriangleStrip ||
+            poly.type == OptimizedPolyList::TriangleFan)
+         {
+            tempIndices[0] = 0;
+            U32 idx = 1;
+
+            for (U32 k = 1; k < poly.vertexCount; k += 2)
+               tempIndices[idx++] = k;
+
+            for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
+               tempIndices[idx++] = k;
+         }
+         else if (poly.type == OptimizedPolyList::TriangleList)
+         {
+            for (U32 k = 0; k < poly.vertexCount; k++)
+               tempIndices[k] = k;
+         }
+         else
+            continue;
+
+         //got our data, now insert it into the correct buffer!
+         S32 bufferId = findBufferSetByMaterial(poly.material);
+
+         if (bufferId == -1)
+         {
+            //add a new buffer set if we didn't get a match!
+            BufferSet newSet;
+            newSet.surfaceMaterialId = poly.material;
+
+            mStaticBuffers.push_back(newSet);
+
+            bufferId = mStaticBuffers.size() - 1;
+         }
+
+         //see if this would push us over our buffer size limit, if it is, make a new buffer for this set
+         if (mStaticBuffers[bufferId].buffers.last().vertData.size() + 3 > BUFFER_SIZE
+            || mStaticBuffers[bufferId].buffers.last().primData.size() + 1 > BUFFER_SIZE)
+         {
+            //yep, we'll overstep with this, so spool up a new buffer in this set
+            BufferSet::Buffers newBuffer = BufferSet::Buffers();
+            mStaticBuffers[bufferId].buffers.push_back(newBuffer);
+         }
+
+         const U32& firstIdx = MeshRenderSystemInterface::all[i]->mGeometry.mIndexList[poly.vertexStart];
+         const OptimizedPolyList::VertIndex& firstVertIdx = MeshRenderSystemInterface::all[i]->mGeometry.mVertexList[firstIdx];
+
+         //Vector<Point3F> geomPoints = MeshRenderSystemInterface::all[i]->mGeometry.mPoints;
+         //Vector<Point3F> geomNormals = MeshRenderSystemInterface::all[i]->mGeometry.mNormals;
+         //Vector<Point2F> geoUVs = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s;
+
+         for (U32 k = 1; k < poly.vertexCount - 1; k++)
+         {
+            const U32& secondIdx = MeshRenderSystemInterface::all[i]->mGeometry.mIndexList[poly.vertexStart + tempIndices[k]];
+            const U32& thirdIdx = MeshRenderSystemInterface::all[i]->mGeometry.mIndexList[poly.vertexStart + tempIndices[k + 1]];
+
+            const OptimizedPolyList::VertIndex& secondVertIdx = MeshRenderSystemInterface::all[i]->mGeometry.mVertexList[secondIdx];
+            const OptimizedPolyList::VertIndex& thirdVertIdx = MeshRenderSystemInterface::all[i]->mGeometry.mVertexList[thirdIdx];
+
+            Point3F points[3];
+            points[0] = MeshRenderSystemInterface::all[i]->mGeometry.mPoints[firstVertIdx.vertIdx];
+            points[1] = MeshRenderSystemInterface::all[i]->mGeometry.mPoints[secondVertIdx.vertIdx];
+            points[2] = MeshRenderSystemInterface::all[i]->mGeometry.mPoints[thirdVertIdx.vertIdx];
+
+            Point3F normals[3];
+            normals[0] = MeshRenderSystemInterface::all[i]->mGeometry.mNormals[firstVertIdx.normalIdx];
+            normals[1] = MeshRenderSystemInterface::all[i]->mGeometry.mNormals[secondVertIdx.normalIdx];
+            normals[2] = MeshRenderSystemInterface::all[i]->mGeometry.mNormals[thirdVertIdx.normalIdx];
+
+            Point3F tangents[3];
+            tangents[0] = mCross(points[1] - points[0], normals[0]);
+            tangents[1] = mCross(points[2] - points[1], normals[1]);
+            tangents[2] = mCross(points[0] - points[2], normals[2]);
+
+            Point2F uvs[3];
+            uvs[0] = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s[firstVertIdx.uv0Idx];
+            uvs[1] = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s[secondVertIdx.uv0Idx];
+            uvs[2] = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s[thirdVertIdx.uv0Idx];
+
+            mStaticBuffers[bufferId].vertCount += 3;
+            mStaticBuffers[bufferId].primCount += 1;
+
+            for (U32 v = 0; v < 3; ++v)
+            {
+               //Build the vert and store it to the buffers!
+               GFXVertexPNTT bufVert;
+               bufVert.point = points[v];
+               bufVert.normal = normals[v];
+               bufVert.tangent = tangents[v];
+               bufVert.texCoord = uvs[v];
+
+               newBounds.extend(points[v]);
+
+               mStaticBuffers[bufferId].buffers.last().vertData.push_back(bufVert);
+
+               U32 vertPrimId = mStaticBuffers[bufferId].buffers.last().vertData.size() - 1;
+               mStaticBuffers[bufferId].buffers.last().primData.push_back(vertPrimId);
+
+               mStaticBuffers[bufferId].center += points[v];
+            }
+         }
+      }
+   }
+
+   //Now, iterate through the organized data and turn them into renderable buffers
+   for (U32 i = 0; i < mStaticBuffers.size(); i++)
+   {
+      for (U32 b = 0; b < mStaticBuffers[i].buffers.size(); b++)
+      {
+         BufferSet::Buffers& buffers = mStaticBuffers[i].buffers[b];
+
+         //if there's no data to be had in this buffer, just skip it
+         if (buffers.vertData.empty())
+            continue;
+
+         buffers.vertexBuffer.set(GFX, buffers.vertData.size(), GFXBufferTypeStatic);
+         GFXVertexPNTT *pVert = buffers.vertexBuffer.lock();
+
+         for (U32 v = 0; v < buffers.vertData.size(); v++)
+         {
+            pVert->normal = buffers.vertData[v].normal;
+            pVert->tangent = buffers.vertData[v].tangent;
+            //pVert->color = buffers.vertData[v].color;
+            pVert->point = buffers.vertData[v].point;
+            pVert->texCoord = buffers.vertData[v].texCoord;
+
+            pVert++;
+         }
+
+         buffers.vertexBuffer.unlock();
+
+         // Allocate PB
+         buffers.primitiveBuffer.set(GFX, buffers.primData.size(), buffers.primData.size() / 3, GFXBufferTypeStatic);
+
+         U16 *pIndex;
+         buffers.primitiveBuffer.lock(&pIndex);
+
+         for (U16 i = 0; i < buffers.primData.size(); i++)
+         {
+            *pIndex = i;
+            pIndex++;
+         }
+
+         buffers.primitiveBuffer.unlock();
+      }
+
+      mStaticBuffers[i].center /= mStaticBuffers[i].vertCount;
+   }
+
+   //mObjBox = newBounds;
+   //resetWorldBox();
+}
+
+U32 MeshRenderSystem::findBufferSetByMaterial(U32 matId)
+{
+   for (U32 i = 0; i < mStaticBuffers.size(); i++)
+   {
+      if (mStaticBuffers[i].surfaceMaterialId == matId)
+         return i;
+   }
+
+   return -1;
+}

+ 207 - 0
Engine/source/T3D/systems/render/meshRenderSystem.h

@@ -0,0 +1,207 @@
+#pragma once
+#include "scene/sceneRenderState.h"
+#include "T3D/systems/componentSystem.h"
+#include "ts/tsShape.h"
+#include "ts/tsShapeInstance.h"
+#include "T3D/assets/ShapeAsset.h"
+#include "T3D/assets/MaterialAsset.h"
+
+#ifndef _GFXVERTEXBUFFER_H_
+#include "gfx/gfxVertexBuffer.h"
+#endif
+#ifndef _GFXPRIMITIVEBUFFER_H_
+#include "gfx/gfxPrimitiveBuffer.h"
+#endif
+#ifndef _OPTIMIZEDPOLYLIST_H_
+#include "collision/optimizedPolyList.h"
+#endif
+
+class MeshRenderSystemInterface : public SystemInterface<MeshRenderSystemInterface>
+{
+public:
+   TSShapeInstance * mShapeInstance;
+
+   MatrixF                 mTransform;
+   Point3F                 mScale;
+   Box3F						   mBounds;
+   SphereF                 mSphere;
+
+   bool                    mIsClient;
+
+   struct matMap
+   {
+      //MaterialAsset* matAsset;
+      String assetId;
+      U32 slot;
+   };
+
+   Vector<matMap>  mChangingMaterials;
+   Vector<matMap>  mMaterials;
+
+   //Static geometry stuff
+   bool                    mStatic;
+
+   OptimizedPolyList       mGeometry;
+
+   MeshRenderSystemInterface() : SystemInterface(), mShapeInstance(nullptr), mTransform(MatrixF::Identity), mScale(Point3F::One), mIsClient(false), mStatic(false)
+   {
+      mBounds = Box3F(1);
+      mSphere = SphereF();
+   }
+
+   ~MeshRenderSystemInterface()
+   {
+      //SAFE_DELETE(mShape);
+      SAFE_DELETE(mShapeInstance);
+   }
+};
+
+class MeshRenderSystem
+{
+protected:
+   /*struct StaticBatchElement
+   {
+      SimObject* owner;
+      OptimizedPolyList geometry;
+      String batchName;
+   };
+
+   static Vector<StaticBatchElement> mStaticElements;*/
+
+   //We retain the pushed geometry data for rendering here. It's static(unless forced to change through editing or whatnot)
+   //so rendering the batches is real fast
+   struct BufferMaterials
+   {
+      // The name of the Material we will use for rendering
+      String            mMaterialName;
+      // The actual Material instance
+      BaseMatInstance*  mMaterialInst;
+
+      BufferMaterials()
+      {
+         mMaterialName = "";
+         mMaterialInst = NULL;
+      }
+   };
+
+   static Vector<BufferMaterials> mBufferMaterials;
+
+   struct BufferSet
+   {
+      U32 surfaceMaterialId;
+
+      U32 vertCount;
+      U32 primCount;
+
+      Point3F center;
+
+      struct Buffers
+      {
+         U32 vertStart;
+         U32 primStart;
+         U32 vertCount;
+         U32 primCount;
+
+         Vector<GFXVertexPNTT> vertData;
+         Vector<U32> primData;
+
+         GFXVertexBufferHandle< GFXVertexPNTT > vertexBuffer;
+         GFXPrimitiveBufferHandle            primitiveBuffer;
+
+         Buffers()
+         {
+            vertStart = 0;
+            primStart = 0;
+            vertCount = 0;
+            primCount = 0;
+
+            vertexBuffer = NULL;
+            primitiveBuffer = NULL;
+         }
+      };
+
+      Vector<Buffers> buffers;
+
+      BufferSet()
+      {
+         Buffers newBuffer;
+         buffers.push_back(newBuffer);
+
+         surfaceMaterialId = 0;
+
+         vertCount = 0;
+         primCount = 0;
+
+         center = Point3F::Zero;
+      }
+   };
+
+   static Vector<BufferSet> mStaticBuffers;
+
+public:
+   /*virtual void prepRenderImage(SceneRenderState *state);
+
+   bool setMeshAsset(const char* assetName);
+
+   virtual TSShape* getShape() { if (mMeshAsset)  return mMeshAsset->getShape(); else return NULL; }
+   virtual TSShapeInstance* getShapeInstance() { return mShapeInstance; }
+
+   Resource<TSShape> getShapeResource() { return mMeshAsset->getShapeResource(); }
+
+   void _onResourceChanged(const Torque::Path &path);
+
+   virtual bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info);
+
+   void mountObjectToNode(SceneObject* objB, String node, MatrixF txfm);
+
+   virtual void onDynamicModified(const char* slotName, const char* newValue);
+
+   void changeMaterial(U32 slot, MaterialAsset* newMat);
+   bool setMatInstField(U32 slot, const char* field, const char* value);
+
+   virtual void onInspect();
+   virtual void onEndInspect();
+
+   virtual Vector<MatrixF> getNodeTransforms()
+   {
+      Vector<MatrixF> bob;
+      return bob;
+   }
+
+   virtual void setNodeTransforms(Vector<MatrixF> transforms)
+   {
+      return;
+   }*/
+
+   /*MeshRenderSystem()
+   {
+
+   }
+   virtual ~MeshRenderSystem()
+   {
+      smInterfaceList.clear();
+   }
+
+   static MeshComponentInterface* GetNewInterface()
+   {
+      smInterfaceList.increment();
+
+      return &smInterfaceList.last();
+   }
+
+   static void RemoveInterface(T* q)
+   {
+      smInterfaceList.erase(q);
+   }*/
+
+   //Core render function, which does all the real work
+   static void render(SceneManager *sceneManager, SceneRenderState* state);
+
+   //Render our particular interface's data
+   static void renderInterface(U32 interfaceIndex, SceneRenderState* state);
+
+   //Static Batch rendering
+   static void rebuildBuffers();
+
+   static U32 findBufferSetByMaterial(U32 matId);
+};

+ 34 - 0
Engine/source/T3D/systems/updateSystem.cpp

@@ -0,0 +1,34 @@
+#include "T3D/systems/updateSystem.h"
+
+void UpdateSystem::processTick()
+{
+   for (U32 i = 0; i < UpdateSystemInterface::all.size(); i++)
+   {
+      if (UpdateSystemInterface::all[i]->mIsEnabled)
+      {
+         //do work
+      }
+   }
+}
+
+void UpdateSystem::advanceTime(U32 _tickMS)
+{
+   for (U32 i = 0; i < UpdateSystemInterface::all.size(); i++)
+   {
+      if (UpdateSystemInterface::all[i]->mIsEnabled)
+      {
+         //do work
+      }
+   }
+}
+
+void UpdateSystem::interpolateTick(U32 _deltaMS)
+{
+   for (U32 i = 0; i < UpdateSystemInterface::all.size(); i++)
+   {
+      if (UpdateSystemInterface::all[i]->mIsEnabled)
+      {
+         //do work
+      }
+   }
+}

+ 16 - 0
Engine/source/T3D/systems/updateSystem.h

@@ -0,0 +1,16 @@
+#pragma once
+#include "componentSystem.h"
+
+class UpdateSystemInterface : public SystemInterface<UpdateSystemInterface>
+{
+public:
+   bool mIsEnabled;
+};
+
+class UpdateSystem
+{
+public:
+   static void processTick();
+   static void advanceTime(U32 _tickMS);
+   static void interpolateTick(U32 _deltaMS);
+};

+ 1 - 1
Engine/source/assets/assetBase.cpp

@@ -69,7 +69,7 @@ AssetBase::~AssetBase()
    // If the asset manager does not own the asset then we own the
    // asset definition so delete it.
    if (!getOwned())
-      delete mpAssetDefinition;
+      SAFE_DELETE(mpAssetDefinition);
 }
 
 //-----------------------------------------------------------------------------

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

@@ -62,6 +62,7 @@ class AssetBase : public SimObject
 
    typedef SimObject Parent;
 
+protected:
    AssetManager*           mpOwningAssetManager;
    bool                    mAssetInitialized;
    AssetDefinition*        mpAssetDefinition;

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

@@ -61,6 +61,15 @@
 #ifndef COMPONENTASSET_H
 #include "T3D/assets/ComponentAsset.h"
 #endif
+#ifndef GUI_ASSET_H
+#include "T3D/assets/GUIAsset.h"
+#endif
+#ifndef SCRIPT_ASSET_H
+#include "T3D/assets/ScriptAsset.h"
+#endif
+#ifndef MATERIALASSET_H
+#include "T3D/assets/MaterialAsset.h"
+#endif
 
 // Script bindings.
 #include "assetManager_ScriptBinding.h"
@@ -251,6 +260,18 @@ bool AssetManager::loadModuleAutoLoadAssets(ModuleDefinition* pModuleDefinition)
             {
                assetBase = mTaml.read<ComponentAsset>(assetDef->mAssetBaseFilePath);
             }
+            else if (assetDef->mAssetType == StringTable->insert("GUIAsset"))
+            {
+               assetBase = mTaml.read<GUIAsset>(assetDef->mAssetBaseFilePath);
+            }
+            else if (assetDef->mAssetType == StringTable->insert("ScriptAsset"))
+            {
+               assetBase = mTaml.read<ScriptAsset>(assetDef->mAssetBaseFilePath);
+            }
+            else if (assetDef->mAssetType == StringTable->insert("MaterialAsset"))
+            {
+               assetBase = mTaml.read<MaterialAsset>(assetDef->mAssetBaseFilePath);
+            }
 
             //load the asset now if valid
             if (assetBase)
@@ -2369,6 +2390,13 @@ S32 AssetManager::findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLoos
 
 //-----------------------------------------------------------------------------
 
+AssetManager::typeAssetDependsOnHash* AssetManager::getDependedOnAssets()
+{
+   // Find any asset dependencies.
+   return &mAssetDependsOn;
+}
+//-----------------------------------------------------------------------------
+
 bool AssetManager::scanDeclaredAssets( const char* pPath, const char* pExtension, const bool recurse, ModuleDefinition* pModuleDefinition )
 {
     // Debug Profiling.

+ 13 - 8
Engine/source/assets/assetManager.h

@@ -73,15 +73,18 @@ 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;
 
+public:
+   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;
+
+private:
     /// Declared assets.
     typeDeclaredAssetsHash              mDeclaredAssets;
 
@@ -368,6 +371,8 @@ public:
     S32 findTaggedAssets( AssetQuery* pAssetQuery, const char* pAssetTagNames, const bool assetQueryAsSource = false );
     S32 findAssetLooseFile( AssetQuery* pAssetQuery, const char* pLooseFile, const bool assetQueryAsSource = false );
 
+    typeAssetDependsOnHash* getDependedOnAssets();
+
     /// Declare Console Object.
     DECLARE_CONOBJECT( AssetManager );
 

+ 25 - 2
Engine/source/gui/containers/guiDragAndDropCtrl.cpp

@@ -152,14 +152,24 @@ ConsoleDocClass( GuiDragAndDropControl,
    "@ingroup GuiUtil"
 );
 
+IMPLEMENT_CALLBACK(GuiDragAndDropControl, onControlDragCancelled, void, (), (),
+   "Called when the we cancel out of the drag and drop action.\n"
+   "@see GuiDragAndDropControl::onControlDragCancelled");
 
 //-----------------------------------------------------------------------------
+GuiDragAndDropControl::GuiDragAndDropControl() : mDeleteOnMouseUp(true), mUseWholeCanvas(false)
+{
+
+}
 
 void GuiDragAndDropControl::initPersistFields()
 {
    addField( "deleteOnMouseUp", TypeBool, Offset( mDeleteOnMouseUp, GuiDragAndDropControl ),
       "If true, the control deletes itself when the left mouse button is released.\n\n"
       "If at this point, the drag&drop control still contains its payload, it will be deleted along with the control." );
+
+   addField("useWholeCanvas", TypeBool, Offset(mUseWholeCanvas, GuiDragAndDropControl),
+      "If true, the control can be tested against ANY control active on the canvas instead of just the direct parent.\n\n");
    
    Parent::initPersistFields();
 }
@@ -226,8 +236,10 @@ void GuiDragAndDropControl::onMouseUp(const GuiEvent& event)
    mouseUnlock();
 
    GuiControl* target = findDragTarget( event.mousePoint, "onControlDropped" );
-   if( target )
-      target->onControlDropped_callback( dynamic_cast< GuiControl* >( at( 0 ) ), getDropPoint() );
+   if (target)
+      target->onControlDropped_callback(dynamic_cast<GuiControl*>(at(0)), getDropPoint());
+   else
+      onControlDragCancelled_callback();
 
    if( mDeleteOnMouseUp )
       deleteObject();
@@ -239,6 +251,13 @@ GuiControl* GuiDragAndDropControl::findDragTarget( Point2I mousePoint, const cha
 {
    // If there are any children and we have a parent.
    GuiControl* parent = getParent();
+
+   if (mUseWholeCanvas)
+   {
+      parent->setVisible(false);
+      parent = getRoot();
+   }
+
    if (size() && parent)
    {
       mVisible = false;
@@ -252,6 +271,10 @@ GuiControl* GuiDragAndDropControl::findDragTarget( Point2I mousePoint, const cha
             dropControl = dropControl->getParent();
       }
    }
+
+   if(mUseWholeCanvas)
+      parent->setVisible(true);
+
    return NULL;
 }
 

+ 5 - 1
Engine/source/gui/containers/guiDragAndDropCtrl.h

@@ -53,6 +53,8 @@ class GuiDragAndDropControl : public GuiControl
       /// If true, the control deletes itself when the left mouse button is released.
       bool mDeleteOnMouseUp;
 
+      bool mUseWholeCanvas;
+
       /// Controls may want to react when they are dragged over, entered or exited.
       SimObjectPtr<GuiControl> mLastTarget;
       
@@ -65,7 +67,7 @@ class GuiDragAndDropControl : public GuiControl
 
    public:
    
-      GuiDragAndDropControl() {}
+      GuiDragAndDropControl();
 
       void startDragging(Point2I offset = Point2I(0, 0));
 
@@ -81,6 +83,8 @@ class GuiDragAndDropControl : public GuiControl
       DECLARE_DESCRIPTION( "A special control that implements drag&drop behavior.\n"
                            "The control will notify other controls as it moves across the canvas.\n"
                            "Content can be attached through dynamic fields or child objects." );
+
+      DECLARE_CALLBACK(void, onControlDragCancelled, ());
 };
 
 #endif

+ 21 - 0
Engine/source/gui/controls/guiTreeViewCtrl.cpp

@@ -2501,6 +2501,19 @@ const char * GuiTreeViewCtrl::getItemValue(S32 itemId)
 
 //-----------------------------------------------------------------------------
 
+S32 GuiTreeViewCtrl::getItemAtPosition(Point2I position)
+{
+   BitSet32 hitFlags = 0;
+   Item* item;
+
+   if (_hitTest(position, item, hitFlags))
+      return item->mId;
+   else
+      return -1;
+}
+
+//-----------------------------------------------------------------------------
+
 bool GuiTreeViewCtrl::editItem( S32 itemId, const char* newText, const char* newValue )
 {
    Item* item = getItem( itemId );
@@ -5550,3 +5563,11 @@ DefineEngineMethod( GuiTreeViewCtrl, clearFilterText, void, (),,
 {
    object->clearFilterText();
 }
+
+DefineEngineMethod(GuiTreeViewCtrl, getItemAtPosition, S32, (Point2I position), (Point2I::Zero),
+   "Get the tree item at the passed in position.\n\n"
+   "@param position The position to check for what item is below it.\n"
+   "@return The id of the item under the position.")
+{
+   return object->getItemAtPosition(position);
+}

+ 2 - 0
Engine/source/gui/controls/guiTreeViewCtrl.h

@@ -513,6 +513,8 @@ class GuiTreeViewCtrl : public GuiArrayCtrl
       bool editItem( S32 itemId, const char* newText, const char* newValue );
 
       bool markItem( S32 itemId, bool mark );
+
+      S32 getItemAtPosition(Point2I position);
       
       bool isItemSelected( S32 itemId );
 

+ 6 - 2
Engine/source/gui/editor/guiInspector.cpp

@@ -54,7 +54,8 @@ GuiInspector::GuiInspector()
    mOverDivider( false ),
    mMovingDivider( false ),
    mHLField( NULL ),
-   mShowCustomFields( true )
+   mShowCustomFields( true ),
+   mComponentGroupTargetId(-1)
 {
    mPadding = 1;
 }
@@ -620,7 +621,10 @@ void GuiInspector::refresh()
          else
             compName = comp->getComponentName();
 
-         GuiInspectorGroup *compGroup = new GuiInspectorComponentGroup(compName, this, comp);
+         StringBuilder captionString;
+         captionString.format("%s [%i]", compName.c_str(), comp->getId());
+
+         GuiInspectorGroup *compGroup = new GuiInspectorComponentGroup(captionString.data(), this, comp);
          if (compGroup != NULL)
          {
             compGroup->registerObject();

+ 22 - 1
Engine/source/gui/editor/guiMenuBar.cpp

@@ -1472,6 +1472,17 @@ PopupMenu* GuiMenuBar::getMenu(U32 index)
    return mMenuList[index].popupMenu;
 }
 
+PopupMenu* GuiMenuBar::findMenu(StringTableEntry barTitle)
+{
+   for (U32 i = 0; i < mMenuList.size(); i++)
+   {
+      if (mMenuList[i].text == barTitle)
+         return mMenuList[i].popupMenu;
+   }
+
+   return nullptr;
+}
+
 //-----------------------------------------------------------------------------
 // Console Methods
 //-----------------------------------------------------------------------------
@@ -1506,4 +1517,14 @@ DefineConsoleMethod(GuiMenuBar, getMenu, S32, (S32 index), (0), "(Index)")
 DefineConsoleMethod(GuiMenuBar, insert, void, (SimObject* pObject, S32 pos), (nullAsType<SimObject*>(), -1), "(object, pos) insert object at position")
 {
    object->insert(pObject, pos);
-}
+}
+
+DefineConsoleMethod(GuiMenuBar, findMenu, S32, (StringTableEntry barTitle), (""), "(barTitle)")
+{
+   PopupMenu* menu = object->findMenu(barTitle);
+
+   if (menu)
+      return menu->getId();
+   else
+      return 0;
+}

+ 1 - 0
Engine/source/gui/editor/guiMenuBar.h

@@ -116,6 +116,7 @@ public:
    U32 getMenuListCount() { return mMenuList.size(); }
 
    PopupMenu* getMenu(U32 index);
+   PopupMenu* findMenu(StringTableEntry barTitle);
 
    DECLARE_CONOBJECT(GuiMenuBar);
    DECLARE_CALLBACK( void, onMouseInMenu, ( bool hasLeftMenu ));

+ 13 - 6
Engine/source/gui/editor/guiPopupMenuCtrl.cpp

@@ -59,7 +59,8 @@ void GuiPopupMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event)
 
 void GuiPopupMenuBackgroundCtrl::close()
 {
-   getRoot()->removeObject(this);
+   if(getRoot())
+      getRoot()->removeObject(this);
 
    mMenuBarCtrl = nullptr;
 }
@@ -151,16 +152,22 @@ void GuiPopupMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool s
       S32 bottom = top + 8;
       S32 middle = top + 4;
 
-      PrimBuild::begin(GFXTriangleList, 3);
+      //PrimBuild::begin(GFXTriangleList, 3);
+
+      ColorI color = ColorI::BLACK;
       if (selected || mouseOver)
-         PrimBuild::color(mProfile->mFontColorHL);
+         color = mProfile->mFontColorHL;
       else
-         PrimBuild::color(mProfile->mFontColor);
+         color = mProfile->mFontColor;
+
+      GFX->getDrawUtil()->drawLine(Point2I(left, top), Point2I(right, middle), color);
+      GFX->getDrawUtil()->drawLine(Point2I(right, middle), Point2I(left, bottom), color);
+      GFX->getDrawUtil()->drawLine(Point2I(left, bottom), Point2I(left, top), color);
 
-      PrimBuild::vertex2i(left, top);
+      /*PrimBuild::vertex2i(left, top);
       PrimBuild::vertex2i(right, middle);
       PrimBuild::vertex2i(left, bottom);
-      PrimBuild::end();
+      PrimBuild::end();*/
    }
 }
 

+ 1 - 0
Engine/source/gui/editor/inspector/variableField.h

@@ -57,6 +57,7 @@ public:
 
 protected:
    StringTableEntry mVariableName;
+   StringTableEntry mSetCallbackName;
    SimObject* mOwnerObject;
 };
 

+ 3 - 0
Engine/source/gui/editor/inspector/variableGroup.cpp

@@ -151,6 +151,9 @@ bool GuiInspectorVariableGroup::inspectGroup()
       fieldGui->setInspectorField(NULL, mFields[i]->mFieldLabel);
       fieldGui->setDocs(mFields[i]->mFieldDescription);
 
+      if(mFields[i]->mSetCallbackName != StringTable->EmptyString())
+         fieldGui->setSpecialEditCallbackName(mFields[i]->mSetCallbackName);
+
       /*if (mFields[i]->mSetCallbackName != StringTable->EmptyString())
       {
          fieldGui->on.notify()

+ 7 - 0
Engine/source/gui/editor/inspector/variableInspector.cpp

@@ -167,6 +167,10 @@ void GuiVariableInspector::addField(const char* name, const char* label, const c
       fieldTypeMask = TypeColorF;
    else if (newField.mFieldTypeName == StringTable->insert("ease"))
       fieldTypeMask = TypeEaseF;
+   else if (newField.mFieldTypeName == StringTable->insert("command"))
+      fieldTypeMask = TypeCommand;
+   else if (newField.mFieldTypeName == StringTable->insert("filename"))
+      fieldTypeMask = TypeStringFilename;
    else
       fieldTypeMask = -1;
 
@@ -191,7 +195,10 @@ void GuiVariableInspector::addCallbackField(const char* name, const char* label,
 
 void GuiVariableInspector::clearFields()
 {
+   mGroups.clear();
    mFields.clear();
+   clear();
+   
    update();
 }
 

+ 2 - 0
Engine/source/module/moduleDefinition.cpp

@@ -82,6 +82,8 @@ void ModuleDefinition::initPersistFields()
     // Call parent.
     Parent::initPersistFields();
 
+    addProtectedField("ModuleId", TypeString, Offset(mModuleId, ModuleDefinition), &defaultProtectedSetFn, &defaultProtectedGetFn, "");
+
     /// Module configuration.
     addProtectedField( "ModuleId", TypeString, Offset(mModuleId, ModuleDefinition), &setModuleId, &defaultProtectedGetFn, "A unique string Id for the module.  It can contain any characters except a comma or semi-colon (the asset scope character)." );
     addProtectedField( "VersionId", TypeS32, Offset(mVersionId, ModuleDefinition), &setVersionId, &defaultProtectedGetFn, "The version Id.  Breaking changes to a module should use a higher version Id." );

+ 103 - 2
Engine/source/module/moduleManager.cpp

@@ -70,7 +70,8 @@ S32 QSORT_CALLBACK moduleDefinitionVersionIdSort( const void* a, const void* b )
 ModuleManager::ModuleManager() :
     mEnforceDependencies(true),
     mEchoInfo(true),
-    mDatabaseLocks( 0 )
+    mDatabaseLocks( 0 ),
+    mIgnoreLoadedGroups(false)
 {
     // Set module extension.
     dStrcpy( mModuleExtension, MODULE_MANAGER_MODULE_DEFINITION_EXTENSION );
@@ -1300,6 +1301,106 @@ StringTableEntry ModuleManager::copyModule( ModuleDefinition* pSourceModuleDefin
 
 //-----------------------------------------------------------------------------
 
+bool ModuleManager::renameModule(ModuleDefinition* pSourceModuleDefinition, const char* pNewModuleName)
+{
+   // Sanity!
+   AssertFatal(pSourceModuleDefinition != NULL, "Cannot copy module using a NULL source module definition.");
+   AssertFatal(pNewModuleName != NULL, "Cannot rename a module using a NULL module name.");
+
+   // Fetch the source module Id.
+   StringTableEntry sourceModuleId = pSourceModuleDefinition->getModuleId();
+
+   // Is the source module definition registered with this module manager?
+   if (pSourceModuleDefinition->getModuleManager() != this)
+   {
+      // No, so warn.
+      Con::warnf("Module Manager: Cannot rename module Id '%s' as it is not registered with this module manager.", sourceModuleId);
+      return StringTable->EmptyString();
+   }
+
+   TamlModuleIdUpdateVisitor moduleIdUpdateVisitor;
+   moduleIdUpdateVisitor.setModuleIdFrom(sourceModuleId);
+   moduleIdUpdateVisitor.setModuleIdTo(pNewModuleName);
+
+   Vector<Platform::FileInfo> files;
+
+   const char* pExtension = (const char*)"Taml";
+   const U32 extensionLength = dStrlen(pExtension);
+
+   Vector<StringTableEntry> directories;
+
+   StringTableEntry modulePath = pSourceModuleDefinition->getModulePath();
+
+   // Find directories.
+   if (!Platform::dumpDirectories(modulePath, directories, -1))
+   {
+      // Warn.
+      Con::warnf("Module Manager: Cannot rename module Id '%s' in directory '%s' as sub-folder scanning/renaming failed.",
+         sourceModuleId, modulePath);
+      return false;
+   }
+
+   // Iterate directories.
+   for (Vector<StringTableEntry>::iterator basePathItr = directories.begin(); basePathItr != directories.end(); ++basePathItr)
+   {
+      // Fetch base path.
+      StringTableEntry basePath = *basePathItr;
+
+      // Find files.
+      files.clear();
+      if (!Platform::dumpPath(basePath, files, 0))
+      {
+         // Warn.
+         Con::warnf("Module Manager: Cannot rename module Id '%s' in directory '%s' as sub-folder scanning/renaming failed.",
+            sourceModuleId, modulePath);
+         return false;
+      }
+
+      // Iterate files.
+      for (Vector<Platform::FileInfo>::iterator fileItr = files.begin(); fileItr != files.end(); ++fileItr)
+      {
+         // Fetch file info.
+         Platform::FileInfo* pFileInfo = fileItr;
+
+         // Fetch filename.
+         const char* pFilename = pFileInfo->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;
+
+         char parseFileBuffer[1024];
+         dSprintf(parseFileBuffer, sizeof(parseFileBuffer), "%s/%s", pFileInfo->pFullPath, pFilename);
+
+         // Parse file.            
+         if (!mTaml.parse(parseFileBuffer, moduleIdUpdateVisitor))
+         {
+            // Warn.
+            Con::warnf("Module Manager: Failed to parse file '%s' whilst renaming module Id '%s' in directory '%s'.",
+               parseFileBuffer, sourceModuleId, modulePath);
+            return false;
+         }
+      }
+   }
+
+   // Info.
+   if (mEchoInfo)
+   {
+      Con::printf("Module Manager: Finished renaming module Id '%s' to '%s'.", sourceModuleId, pNewModuleName);
+   }
+
+   return true;
+}
+
+//-----------------------------------------------------------------------------
+
 bool ModuleManager::synchronizeDependencies( ModuleDefinition* pRootModuleDefinition, const char* pTargetDependencyPath )
 {
     // Sanity!
@@ -1986,7 +2087,7 @@ bool ModuleManager::registerModule( const char* pModulePath, const char* pModule
     }
 
     // Is the module group already loaded?
-    if ( findGroupLoaded( moduleGroup ) != NULL )
+    if ( findGroupLoaded( moduleGroup ) != NULL && !mIgnoreLoadedGroups)
     {
         // Yes, so warn.
         Con::warnf( "Module Manager: Found module: '%s' but it is in a module group '%s' which has already been loaded.",

+ 7 - 1
Engine/source/module/moduleManager.h

@@ -120,6 +120,7 @@ private:
     char                        mModuleExtension[256];
     Taml                        mTaml;
     SimSet                      mNotificationListeners;
+    bool                        mIgnoreLoadedGroups;
 
     // Module definition entry.
     struct ModuleDefinitionEntry : public typeModuleDefinitionVector
@@ -161,6 +162,7 @@ public:
     bool scanModules( const char* pPath, const bool rootOnly = false );
 
     /// Module unregister.
+    bool registerModule(const char* pModulePath, const char* pModuleFile);
     bool unregisterModule( const char* pModuleId, const U32 versionId );
 
     /// Module (un)loading.
@@ -179,6 +181,9 @@ public:
     StringTableEntry copyModule( ModuleDefinition* pSourceModuleDefinition, const char* pTargetModuleId, const char* pTargetPath, const bool useVersionPathing );
     bool synchronizeDependencies( ModuleDefinition* pRootModuleDefinition, const char* pTargetDependencyPath );
 
+    /// Editing modules
+    bool renameModule(ModuleDefinition* pSourceModuleDefinition, const char* pNewModuleName);
+
     /// Module updates.
     inline bool isModuleMergeAvailable( void ) const { return Platform::isFile( getModuleMergeFilePath() ); }
     bool canMergeModules( const char* pMergeSourcePath );
@@ -188,10 +193,11 @@ public:
     void addListener( SimObject* pListener );
     void removeListener( SimObject* pListener );
 
+    void setIgnoreLoadedGroups(bool doIgnore) { mIgnoreLoadedGroups = doIgnore; }
+
 private:
     void clearDatabase( void );
     bool removeModuleDefinition( ModuleDefinition* pModuleDefinition );
-    bool registerModule( const char* pModulePath, const char* pModuleFile );
 
     void raiseModulePreLoadNotifications( ModuleDefinition* pModuleDefinition );
     void raiseModulePostLoadNotifications( ModuleDefinition* pModuleDefinition );

+ 45 - 0
Engine/source/module/moduleManager_ScriptBinding.h

@@ -46,6 +46,16 @@ DefineEngineMethod(ModuleManager, scanModules, bool, (const char* pRootPath, boo
 
 //-----------------------------------------------------------------------------
 
+DefineEngineMethod(ModuleManager, registerModule, bool, (const char* pModulePath, const char* pModuleFile), ("", ""),
+   "Register the specified module.\n"
+   "@param moduleId The module Id to register.\n"
+   "@param versionId The version Id to register.\n"
+   "@return Whether the module was registered or not.\n")
+{
+   // Unregister the module.
+   return object->registerModule(pModulePath, pModuleFile);
+}
+
 DefineEngineMethod(ModuleManager, unregisterModule, bool, (const char* pModuleId, bool versionId), ("", false),
    "Unregister the specified module.\n"
    "@param moduleId The module Id to unregister.\n"
@@ -246,6 +256,30 @@ DefineEngineMethod(ModuleManager, copyModule, String, (const char* sourceModuleD
 
 //-----------------------------------------------------------------------------
 
+DefineEngineMethod(ModuleManager, renameModule, bool, (const char* sourceModuleDefinition, const char* pNewModuleName),
+("", ""),
+"Rename a module.\n"
+"@param sourceModuleDefinition The module definition to rename.\n"
+"@param pNewModuleName The new name the module should have.\n"
+"@return Weither the rename was successful or not.\n")
+{
+   // Find the source module definition.
+   ModuleDefinition* pSourceModuleDefinition = dynamic_cast<ModuleDefinition*>(Sim::findObject(sourceModuleDefinition));
+
+   // Was the module definition found?
+   if (pSourceModuleDefinition == NULL)
+   {
+      // No, so warn.
+      Con::warnf("ModuleManager::renameModule() - Could not find source module definition '%s'.", sourceModuleDefinition);
+      return "";
+   }
+
+   // Copy module.
+   return object->renameModule(pSourceModuleDefinition, pNewModuleName);
+}
+
+//-----------------------------------------------------------------------------
+
 DefineEngineMethod(ModuleManager, synchronizeDependencies, bool, (const char* rootModuleDefinition, const char* pTargetDependencyFolder), ("", ""),
    "Synchronize the module dependencies of a module definition to a target dependency folder.\n"
    "@param rootModuleDefinition The module definition used to determine dependencies.\n"
@@ -342,3 +376,14 @@ DefineEngineMethod(ModuleManager, removeListener, void, (const char* listenerObj
 
     object->removeListener( pListener );
 }
+
+//-----------------------------------------------------------------------------
+
+DefineEngineMethod(ModuleManager, ignoreLoadedGroups, void, (bool doIgnore), (false),
+   "Sets if the Module Manager should ingore laoded groups.\n"
+   "@param doIgnore Whether we should or should not ignore loaded groups.\n"
+   "@return No return value.\n")
+{
+   // Check whether the merge modules can current happen or not.
+   return object->setIgnoreLoadedGroups(doIgnore);
+}

+ 14 - 3
Engine/source/platform/nativeDialogs/fileDialog.cpp

@@ -122,6 +122,7 @@ FileDialog::FileDialog() : mData()
    // Default to File Must Exist Open Dialog style
    mData.mStyle = FileDialogData::FDS_OPEN | FileDialogData::FDS_MUSTEXIST;
    mChangePath = false;
+   mForceRelativePath = true;
 }
 
 FileDialog::~FileDialog()
@@ -151,6 +152,8 @@ void FileDialog::initPersistFields()
    addProtectedField("changePath", TypeBool, Offset(mChangePath, FileDialog), &setChangePath, &getChangePath,
       "True/False whether to set the working directory to the directory returned by the dialog.");
 
+   addField("forceRelativePath", TypeBool, Offset(mForceRelativePath, FileDialog), "True/False whether to the path returned is always made to be relative.");
+
    Parent::initPersistFields();
 }
 
@@ -267,7 +270,8 @@ bool FileDialog::Execute()
    }
 
    String resultPath = String(outPath).replace(rootDir, String(""));
-   resultPath = resultPath.replace(0, 1, String("")).c_str(); //kill '\\' prefix
+   if(resultPath[0] == '\\')
+      resultPath = resultPath.replace(0, 1, String("")).c_str(); //kill '\\' prefix
    resultPath = resultPath.replace(String("\\"), String("/"));
 
    // Did we select a file?
@@ -280,7 +284,10 @@ bool FileDialog::Execute()
    if (mData.mStyle & FileDialogData::FDS_OPEN || mData.mStyle & FileDialogData::FDS_SAVE)
    {
       // Single file selection, do it the easy way
-      mData.mFile = Platform::makeRelativePathName(resultPath.c_str(), NULL);
+      if(mForceRelativePath)
+         mData.mFile = Platform::makeRelativePathName(resultPath.c_str(), NULL);
+      else
+         mData.mFile = resultPath.c_str();
    }
    else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES)
    {
@@ -300,7 +307,11 @@ bool FileDialog::Execute()
       else
       {
          //nope, just one file, so set it as normal
-         setDataField(StringTable->insert("files"), "0", Platform::makeRelativePathName(resultPath.c_str(), NULL));
+         if (mForceRelativePath)
+            setDataField(StringTable->insert("files"), "0", Platform::makeRelativePathName(resultPath.c_str(), NULL));
+         else
+            setDataField(StringTable->insert("files"), "0", resultPath.c_str());
+
          setDataField(StringTable->insert("fileCount"), NULL, "1");
       }
    }

+ 1 - 0
Engine/source/platform/nativeDialogs/fileDialog.h

@@ -106,6 +106,7 @@ protected:
    FileDialogData mData; ///< Stores platform agnostic information about the dialogs properties
    bool mChangePath; ///< Exposed ChangePath Property
    bool mBoolTranslator; ///< Internally used to translate boolean values into their respective bits of dialog style
+   bool mForceRelativePath;
 public:
 
    FileDialog();

+ 5 - 0
Engine/source/scene/sceneManager.cpp

@@ -38,6 +38,9 @@
 #include "T3D/gameBase/gameConnection.h"
 #include "math/mathUtils.h"
 
+#include "T3D/components/render/renderComponentInterface.h"
+#include "T3D/systems/render/meshRenderSystem.h"
+
 // For player object bounds workaround.
 #include "T3D/player.h"
 
@@ -358,6 +361,8 @@ void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZ
    if( gEditingMission && state->isDiffusePass() )
       objectMask = EDITOR_RENDER_TYPEMASK;
 
+   MeshRenderSystem::render(this, state);
+
    // Update the zoning state and traverse zones.
 
    if( getZoneManager() )

+ 0 - 11
Engine/source/scene/sceneRenderState.cpp

@@ -106,17 +106,6 @@ void SceneRenderState::renderObjects( SceneObject** objects, U32 numObjects )
       object->prepRenderImage( this );
    }
 
-   U32 interfaceCount = RenderComponentInterface::all.size();
-   for (U32 i = 0; i < RenderComponentInterface::all.size(); i++)
-   {
-      Component* comp = dynamic_cast<Component*>(RenderComponentInterface::all[i]);
-
-      if (comp->isClientObject() && comp->isActive())
-      {
-         RenderComponentInterface::all[i]->prepRenderImage(this);
-      }
-   }
-
    PROFILE_END();
 
    // Render what the objects have batched.

+ 10 - 0
Templates/BaseGame/game/core/CoreComponents.cs

@@ -0,0 +1,10 @@
+
+function CoreComponentsModule::onCreate(%this)
+{
+   %classList = enumerateConsoleClasses( "Component" );
+
+   foreach$( %componentClass in %classList )
+   {
+      echo("Native Component of type: " @ %componentClass);
+   }  
+}

+ 3 - 0
Templates/BaseGame/game/core/CoreComponents.module

@@ -2,6 +2,9 @@
 	ModuleId="CoreComponentsModule"
 	VersionId="1"
 	Description="Module that implements the core engine-level components for the game."
+	ScriptFile="CoreComponents.cs"
+	CreateFunction="onCreate"
+	DestroyFunction="onDestroy"
 	Group="Game">
 	<DeclaredAssets
            canSave="true"

+ 2 - 2
Templates/BaseGame/game/core/components/game/camera.asset.taml

@@ -5,5 +5,5 @@
     componentClass="CameraComponent"
     friendlyName="Camera"
     componentType="Game"
-    scriptFile="core/components/game/camera.cs"
-    description="Allows the component owner to operate as a camera." />
+    description="Allows the component owner to operate as a camera."
+    scriptFile="core/components/game/camera.cs" />

+ 2 - 2
Templates/BaseGame/game/core/components/game/controlObject.asset.taml

@@ -6,5 +6,5 @@
     componentClass="Component"
     friendlyName="Control Object"
     componentType="Game"
-    scriptFile="core/components/game/controlObject.cs"
-    description="Allows the component owner to be controlled by a client." />
+    description="Allows the component owner to be controlled by a client."
+    scriptFile="core/components/game/controlObject.cs" />

+ 2 - 2
Templates/BaseGame/game/core/components/game/itemRotate.asset.taml

@@ -6,5 +6,5 @@
     componentClass="Component"
     friendlyName="Item Rotation"
     componentType="Game"
-    scriptFile="core/components/game/itemRotate.cs"
-    description="Rotates the entity around an axis, like an item pickup." />
+    description="Rotates the entity around an axis, like an item pickup."
+    scriptFile="core/components/game/itemRotate.cs" />

+ 2 - 2
Templates/BaseGame/game/core/components/game/playerSpawner.asset.taml

@@ -6,5 +6,5 @@
     componentClass="Component"
     friendlyName="Player Spawner"
     componentType="Game"
-    scriptFile="core/components/game/playerSpawner.cs"
-    description="When a client connects, it spawns a player object for them and attaches them to it." />
+    description="When a client connects, it spawns a player object for them and attaches them to it."
+    scriptFile="core/components/game/playerSpawner.cs" />

+ 206 - 2
Templates/BaseGame/game/core/helperFunctions.cs

@@ -202,7 +202,7 @@ function updateTSShapeLoadProgress(%progress, %msg)
 {
    // Check if the loading GUI is visible and use that instead of the
    // separate import progress GUI if possible
-   if ( isObject(LoadingGui) && LoadingGui.isAwake() )
+  /* if ( isObject(LoadingGui) && LoadingGui.isAwake() )
    {
       // Save/Restore load progress at the start/end of the import process
       if ( %progress == 0 )
@@ -245,7 +245,7 @@ function updateTSShapeLoadProgress(%progress, %msg)
       %textCtrl.setText(%msg);
    }
 
-   Canvas.repaint(33);
+   Canvas.repaint(33);*/
 }
 
 /// A helper function which will return the ghosted client object
@@ -952,3 +952,207 @@ function TestPManager::testObjectRemove(%doNotSave)
    TestPManager.removeObjectFromFile(AudioSim);
 }
 
+//Game Object management
+function findGameObject(%name)
+{
+   //find all GameObjectAssets
+   %assetQuery = new AssetQuery();
+   if(!AssetDatabase.findAssetType(%assetQuery, "GameObjectAsset"))
+      return 0; //if we didn't find ANY, just exit
+      
+   %count = %assetQuery.getCount();
+      
+	for(%i=0; %i < %count; %i++)
+	{
+	   %assetId = %assetQuery.getAsset(%i);
+	   
+	   %assetName = AssetDatabase.getAssetName(%assetId);
+      
+      if(%assetName $= %name)
+		{
+		   %gameObjectAsset = AssetDatabase.acquireAsset(%assetId);
+
+         %assetQuery.delete();
+         return %gameObjectAsset;
+		}
+	}
+		
+   %assetQuery.delete();
+	return 0;
+}
+
+function spawnGameObject(%name, %addToMissionGroup)
+{
+   if(%addToMissionGroup $= "")
+		%addToMissionGroup = true;
+		
+   //First, check if this already exists in our GameObjectPool
+   if(isObject(GameObjectPool))
+   {
+      %goCount = GameObjectPool.countKey(%name);
+      
+      //if we have some already in the pool, pull it out and use that
+      if(%goCount != 0)
+      {
+         %goIdx = GameObjectPool.getIndexFromKey(%name);
+         %go = GameObjectPool.getValue(%goIdx);
+         
+         %go.setHidden(false);
+         %go.setScopeAlways();
+         
+         if(%addToMissionGroup == true) //save instance when saving level
+            MissionGroup.add(%go);
+         else // clear instance on level exit
+            MissionCleanup.add(%go);
+            
+         //remove from the object pool's list
+         GameObjectPool.erase(%goIdx);
+         
+         return %go;
+      }
+   }
+   
+	//We have no existing pool, or no existing game objects of this type, so spawn a new one
+		
+   %gameObjectAsset = findGameObject(%name);
+   
+   if(isObject(%gameObjectAsset))
+   {
+      %newSGOObject = TamlRead(%gameObjectAsset.TAMLFilePath);
+            
+      if(%addToMissionGroup == true) //save instance when saving level
+         MissionGroup.add(%newSGOObject);
+      else // clear instance on level exit
+         MissionCleanup.add(%newSGOObject);
+         
+      return %newSGOObject;
+   }
+		
+	return 0;
+}
+
+function saveGameObject(%name, %tamlPath, %scriptPath)
+{
+	%gameObjectAsset = findGameObject(%name);
+   
+   //find if it already exists. If it does, we'll update it, if it does not, we'll  make a new asset
+   if(isObject(%gameObjectAsset))
+   {
+      %assetID = %gameObjectAsset.getAssetId();
+      
+      %gameObjectAsset.TAMLFilePath = %tamlPath;
+      %gameObjectAsset.scriptFilePath = %scriptPath;
+      
+      TAMLWrite(%gameObjectAsset, AssetDatabase.getAssetFilePath(%assetID));
+      AssetDatabase.refreshAsset(%assetID);
+   }
+   else
+   {
+      //Doesn't exist, so make a new one
+      %gameObjectAsset = new GameObjectAsset()
+      {
+         assetName = %name @ "Asset";
+         gameObjectName = %name;
+         TAMLFilePath = %tamlPath;
+         scriptFilePath = %scriptPath;
+      };
+      
+      //Save it alongside the taml file
+      %path = filePath(%tamlPath);
+      
+      TAMLWrite(%gameObjectAsset, %path @ "/" @ %name @ ".asset.taml");
+      AssetDatabase.refreshAllAssets(true);
+   }
+}
+
+//Allocates a number of a game object into a pool to be pulled from as needed
+function allocateGameObjects(%name, %amount)
+{
+   //First, we need to make sure our pool exists
+   if(!isObject(GameObjectPool))
+   {
+      new ArrayObject(GameObjectPool);  
+   }
+   
+   //Next, we loop and generate our game objects, and add them to the pool
+   for(%i=0; %i < %amount; %i++)
+   {
+      %go = spawnGameObject(%name, false);
+      
+      //When our object is in the pool, it's not "real", so we need to make sure 
+      //that we don't ghost it to clients untill we actually spawn it.
+      %go.clearScopeAlways();
+      
+      //We also hide it, so that we don't 'exist' in the scene until we spawn
+      %go.hidden = true;
+      
+      //Lastly, add us to the pool, with the key being our game object type
+      GameObjectPool.add(%name, %go);
+   }
+}
+
+function Entity::delete(%this)
+{
+   //we want to intercept the delete call, and add it to our GameObjectPool
+   //if it's a game object
+   if(%this.gameObjectAsset !$= "")
+   {
+      %this.setHidden(true);
+      %this.clearScopeAlways();
+      
+      if(!isObject(GameObjectPool))
+      {
+         new ArrayObject(GameObjectPool);
+      }
+      
+      GameObjectPool.add(%this.gameObjectAsset, %this);
+      
+      %missionSet = %this.getGroup();
+      %missionSet.remove(%this);
+   }
+   else
+   {
+      %this.superClass.delete();
+   }
+}
+
+function clearGameObjectPool()
+{
+   if(isObject(GameObjectPool))
+   {
+      %count = GameObjectPool.count();
+      
+      for(%i=0; %i < %count; %i++)
+      {
+         %go = GameObjectPool.getValue(%i);
+         
+         %go.superClass.delete();
+      }
+      
+      GameObjectPool.empty();
+   }
+}
+
+//
+function switchCamera(%client, %newCamEntity)
+{
+	if(!isObject(%client) || !isObject(%newCamEntity))
+		return error("SwitchCamera: No client or target camera!");
+		
+	%cam = %newCamEntity.getComponent(CameraComponent);
+		
+	if(!isObject(%cam))
+		return error("SwitchCamera: Target camera doesn't have a camera behavior!");
+		
+	//TODO: Cleanup clientOwner for previous camera!
+	if(%cam.clientOwner == 0 || %cam.clientOwner $= "")
+		%cam.clientOwner = 0;
+		
+	%cam.scopeToClient(%client);
+	%cam.setDirty();
+	
+	%client.setCameraObject(%newCamEntity);
+	%client.setControlCameraFov(%cam.FOV);
+	
+	%client.camera = %newCamEntity;
+}

+ 1 - 1
Templates/BaseGame/game/data/clientServer/ClientServer.cs

@@ -46,7 +46,7 @@ function ClientServer::destroy( %this )
       disconnect();
    
    // Destroy the physics plugin.
-   physicsDestroy();
+   //physicsDestroy();
    
    sfxShutdown();
       

+ 11 - 3
Templates/BaseGame/game/data/clientServer/scripts/server/server.cs

@@ -25,11 +25,14 @@ function initServer()
    echo("\n--------- Initializing " @ $appName @ ": Server Scripts ---------");
    
    //load prefs
+
+   //Force-load the defaults just so we don't have any mistakes
+   exec( "data/clientServer/scripts/server/defaults.cs" );   
+   
+   //Then, if the user has saved preferences, we load those over-top the defaults
    %prefPath = getPrefpath();
    if ( isFile( %prefPath @ "/serverPrefs.cs" ) )
       exec( %prefPath @ "/serverPrefs.cs" );
-   else
-      exec( "data/clientServer/scripts/server/defaults.cs" );
    
    exec( "data/clientServer/scripts/server/audio.cs" );
    exec( "data/clientServer/scripts/server/commands.cs" );
@@ -99,6 +102,11 @@ function createAndConnectToLocalServer( %serverType, %level )
    {
       %conn.delete();
       destroyServer();
+         
+      MessageBoxOK("Error starting local server!", "There was an error when trying to connect to the local server.");
+      
+      if(isObject(MainMenuGui))
+         Canvas.setContent(MainMenuGui);
       
       return false;
    }
@@ -201,7 +209,7 @@ function destroyServer()
    // End any running levels and shut down the physics sim
    onServerDestroyed();
 
-   physicsDestroy();
+   //physicsDestroy();
 
    // Delete all the server objects
    if (isObject(ServerGroup))

+ 50 - 18
Templates/BaseGame/game/data/ui/scripts/chooseLevelDlg.cs

@@ -31,29 +31,29 @@ function ChooseLevelDlg::onWake( %this )
    %this->LevelDescriptionLabel.visible = false;
    %this->LevelDescription.visible = false;
    
-   %count = LevelFilesList.count();
+   %assetQuery = new AssetQuery();
+   AssetDatabase.findAssetType(%assetQuery, "LevelAsset");
+      
+   %count = %assetQuery.getCount();
    
-   if(%count == 0)
+   if(%count == 0 && !IsDirectory("tools"))
    {
       //We have no levels found. Prompt the user to open the editor to the default level if the tools are present
-      if(IsDirectory("tools"))
-      {
-         MessageBoxYesNo("Error", "No levels were found in any modules. Do you want to load the editor and start a new level?", 
-            "fastLoadWorldEdit(1);", 
-            "Canvas.popDialog(ChooseLevelDlg); if(isObject(ChooseLevelDlg.returnGui) && ChooseLevelDlg.returnGui.isMethod(\"onReturnTo\")) ChooseLevelDlg.returnGui.onReturnTo();");  
-      }
-      else
-      {
-         MessageBoxOK("Error", "No levels were found in any modules. Please ensure you have modules loaded that contain gameplay code and level files.", 
-            "Canvas.popDialog(ChooseLevelDlg); if(isObject(ChooseLevelDlg.returnGui) && ChooseLevelDlg.returnGui.isMethod(\"onReturnTo\")) ChooseLevelDlg.returnGui.onReturnTo();");
-      }
-      
+      MessageBoxOK("Error", "No levels were found in any modules. Please ensure you have modules loaded that contain gameplay code and level files.", 
+         "Canvas.popDialog(ChooseLevelDlg); if(isObject(ChooseLevelDlg.returnGui) && ChooseLevelDlg.returnGui.isMethod(\"onReturnTo\")) ChooseLevelDlg.returnGui.onReturnTo();");
+         
+      %assetQuery.delete();
       return;
    }
    
-   for ( %i=0; %i < %count; %i++ )
-   {
-      %file = LevelFilesList.getKey( %i );
+   for(%i=0; %i < %count; %i++)
+	{
+	   %assetId = %assetQuery.getAsset(%i);
+      
+      %levelAsset = AssetDatabase.acquireAsset(%assetId);
+      
+      %file = %levelAsset.LevelFile;
+      
       if ( !isFile(%file @ ".mis") && !isFile(%file) )
          continue;
          
@@ -66,7 +66,7 @@ function ChooseLevelDlg::onWake( %this )
             continue;      
       }
                   
-      %this.addMissionFile( %file );
+      %this.addLevelAsset( %levelAsset );
    }
    
    // Also add the new level mission as defined in the world editor settings
@@ -218,6 +218,38 @@ function ChooseLevelDlg::addMissionFile( %this, %file )
    CL_levelList.addRow( CL_levelList.rowCount(), %levelName TAB %file TAB %levelDesc TAB %levelPreview );
 }
 
+function ChooseLevelDlg::addLevelAsset( %this, %levelAsset )
+{
+   %file = %levelAsset.LevelFile;
+   
+   /*%levelName = fileBase(%file);
+   %levelDesc = "A Torque level";
+
+   %LevelInfoObject = getLevelInfo(%file);
+
+   if (%LevelInfoObject != 0)
+   {
+      if(%LevelInfoObject.levelName !$= "")
+         %levelName = %LevelInfoObject.levelName;
+      else if(%LevelInfoObject.name !$= "")
+         %levelName = %LevelInfoObject.name;
+
+      if (%LevelInfoObject.desc0 !$= "")
+         %levelDesc = %LevelInfoObject.desc0;
+         
+      if (%LevelInfoObject.preview !$= "")
+         %levelPreview = %LevelInfoObject.preview;
+         
+      %LevelInfoObject.delete();
+   }*/
+   
+   %levelName = %levelAsset.friendlyName;
+   %levelDesc = %levelAsset.description;
+   %levelPreview = %levelAsset.levelPreviewImage;
+   
+   CL_levelList.addRow( CL_levelList.rowCount(), %levelName TAB %file TAB %levelDesc TAB %levelPreview );
+}
+
 function ChooseLevelDlg::onSleep( %this )
 {
    // This is set from the outside, only stays true for a single wake/sleep

BIN
Templates/BaseGame/game/tools/assetBrowser/art/animationIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/clientScriptIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/componentIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/gameObjectIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/guiIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/levelIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/materialIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/postEffectIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/scriptIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/serverScriptIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/soundIcon.png


BIN
Templates/BaseGame/game/tools/assetBrowser/art/stateMachineIcon.png


+ 18 - 0
Templates/BaseGame/game/tools/assetBrowser/assetImportConfigs.xml

@@ -0,0 +1,18 @@
+<AssetImportConfigs>
+    <Config Name="TestConfig">
+        <Mesh ImportMesh="1" DoUpAxisOverride="0" UpAxisOverride="Z_AXIS" DoScaleOverride="0" ScaleOverride="1" IgnoreNodeScale="0" AdjustCenter="0" AdjustFloor="1" CollapseSubmeshes="0" LODType="TrailingNumber" ImportedNodes="" IgnoreNodes="" ImportMeshes="" IgnoreMeshes="" />
+        <Materials ImportMaterials="1" CreateComposites="1" UseDiffuseSuffixOnOriginImg="1" UseExistingMaterials="1" />
+        <Animations ImportAnimations="1" SeparateAnimations="1" SeparateAnimationPrefix="" />
+        <Collisions GenerateCollisions="1" GenCollisionType="CollisionMesh" CollisionMeshPrefix="Col" GenerateLOSCollisions="1" GenLOSCollisionType="CollisionMesh" LOSCollisionMeshPrefix="LOS" />
+        <Images ImageType="N/A" DiffuseTypeSuffixes="_ALBEDO,_DIFFUSE,_ALB,_DIF,_COLOR,_COL" NormalTypeSuffixes="_NORMAL,_NORM" SpecularTypeSuffixes="_SPECULAR,_SPEC" MetalnessTypeSuffixes="_METAL,_MET,_METALNESS,_METALLIC" RoughnessTypeSuffixes="_ROUGH,_ROUGHNESS" SmoothnessTypeSuffixes="_SMOOTH,_SMOOTHNESS" AOTypeSuffixes="_AO,_AMBIENT,_AMBIENTOCCLUSION" CompositeTypeSuffixes="_COMP,_COMPOSITE" TextureFilteringMode="Bilinear" UseMips="1" IsHDR="0" Scaling="1" Compressed="0" GenerateMaterialOnImport="1" PopulateMaterialMaps="1" />
+        <Sounds VolumeAdjust="1" PitchAdjust="1" Compressed="0" />
+    </Config>
+    <Config Name="SecondTest">
+        <Mesh ImportMesh="1" DoUpAxisOverride="0" UpAxisOverride="Z_AXIS" DoScaleOverride="0" ScaleOverride="1" IgnoreNodeScale="0" AdjustCenter="0" AdjustFloor="0" CollapseSubmeshes="0" LODType="TrailingNumber" ImportedNodes="" IgnoreNodes="" ImportMeshes="" IgnoreMeshes="" />
+        <Materials ImportMaterials="1" CreateComposites="1" UseDiffuseSuffixOnOriginImg="" UseExistingMaterials="" />
+        <Animations ImportAnimations="1" SeparateAnimations="1" SeparateAnimationPrefix="" />
+        <Collisions GenerateCollisions="1" GenCollisionType="CollisionMesh" CollisionMeshPrefix="Col" GenerateLOSCollisions="1" GenLOSCollisionType="CollisionMesh" LOSCollisionMeshPrefix="LOS" />
+        <Images ImageType="N/A" DiffuseTypeSuffixes="_ALBEDO,_DIFFUSE,_ALB,_DIF,_COLOR,_COL" NormalTypeSuffixes="_NORMAL,_NORM" SpecularTypeSuffixes="_SPECULAR,_SPEC" MetalnessTypeSuffixes="_METAL,_MET,_METALNESS,_METALLIC" RoughnessTypeSuffixes="_ROUGH,_ROUGHNESS" SmoothnessTypeSuffixes="_SMOOTH,_SMOOTHNESS" AOTypeSuffixes="_AO,_AMBIENT,_AMBIENTOCCLUSION" CompositeTypeSuffixes="_COMP,_COMPOSITE" TextureFilteringMode="Bilinear" UseMips="1" IsHDR="0" Scaling="1" Compressed="0" GenerateMaterialOnImport="" PopulateMaterialMaps="" />
+        <Sounds VolumeAdjust="1" PitchAdjust="1" Compressed="0" />
+    </Config>
+</AssetImportConfigs>

+ 217 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/GameObjectCreator.gui

@@ -0,0 +1,217 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(GameObjectCreator) {
+   position = "0 0";
+   extent = "1024 768";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "ToolsGuiDefaultNonModalProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      selectedEntity = "20054";
+
+   new GuiWindowCtrl(CreateGameObjectWindow) {
+      text = "Create GameObject";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "1";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      closeCommand = "Canvas.popDialog(GameObjectCreator);";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "328 322";
+      extent = "368 123";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiButtonCtrl(GameObjectCreateBtn) {
+         text = "Done";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "224 92";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_importAssetWindow.ImportAssets();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "292 92";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "Canvas.popDialog(GameObjectCreator);";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl(GameObjectCreatorObjectName) {
+         text = "Game Object Name:";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 60";
+         extent = "116 17";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Target Module:";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 30";
+         extent = "116 17";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiBitmapButtonCtrl(GameObjectCreatorPkgBtn) {
+         bitmap = "tools/gui/images/iconAdd.png";
+         bitmapMode = "Centered";
+         autoFitExtents = "0";
+         useModifiers = "0";
+         useStates = "1";
+         masked = "0";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "342 27";
+         extent = "22 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         command = "Canvas.pushDialog(AssetBrowser_addModule);\nAssetBrowser_addModuleWindow.selectWindow();";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiPopUpMenuCtrlEx(GameObjectModuleList) {
+         maxPopupHeight = "200";
+         sbUsesNAColor = "0";
+         reverseTextList = "0";
+         bitmapBounds = "16 16";
+         hotTrackCallback = "0";
+         text = "Characters";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "134 27";
+         extent = "204 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextEditCtrl(GameObjectCreatorName) {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "116 60";
+         extent = "234 18";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextEditProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 142 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/addModuleWindow.gui

@@ -0,0 +1,142 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(AssetBrowser_AddModule) {
+   position = "0 0";
+   extent = "1024 768";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "ToolsGuiDefaultNonModalProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      Enabled = "1";
+
+   new GuiWindowCtrl(AssetBrowser_addModuleWindow) {
+      text = "Create New Module";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "0";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "362 334";
+      extent = "299 99";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      hidden = "0";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiTextEditCtrl() {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "88 35";
+         extent = "196 18";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiTextEditProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         internalName = "ModuleName";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Module Name";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 35";
+         extent = "72 16";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Create";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "88 68";
+         extent = "126 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_addModuleWindow.CreateNewModule();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "220 68";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_addModuleWindow.Close();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 142 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/addPackageWindow.gui

@@ -0,0 +1,142 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(AssetBrowser_AddPackage) {
+   position = "0 0";
+   extent = "1024 768";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "ToolsGuiDefaultNonModalProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      Enabled = "1";
+
+   new GuiWindowCtrl(AssetBrowser_addPackageWindow) {
+      text = "Create New Package";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "0";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "362 334";
+      extent = "299 99";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      hidden = "0";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiTextEditCtrl() {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "88 35";
+         extent = "196 18";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiTextEditProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         internalName = "PackageName";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Package Name";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 35";
+         extent = "72 16";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Create";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "88 68";
+         extent = "126 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_addPackageWindow.CreateNewPackage();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "220 68";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_addPackageWindow.Close();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 934 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/assetBrowser.gui

@@ -0,0 +1,934 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(AssetBrowser) {
+   position = "0 0";
+   extent = "1024 768";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "ToolsGuiDefaultNonModalProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      AddNewArtAssetPopup = "18801";
+      AddNewAssetPopup = "18802";
+      AddNewScriptAssetPopup = "18800";
+      currentPreviewPage = "0";
+      enabled = "1";
+      importAssetFinalListArray = "20465";
+      importAssetNewListArray = "20463";
+      importAssetUnprocessedListArray = "20464";
+      totalPages = "1";
+
+   new GuiWindowCtrl(AssetBrowser_addFilterWindow) {
+      text = "Create New Tag";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "0";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "321 334";
+      extent = "381 99";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "0";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      hidden = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiTextEditCtrl() {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "64 35";
+         extent = "196 18";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiTextEditProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         internalName = "tagName";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Tag Name";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 35";
+         extent = "52 16";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Create";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "64 68";
+         extent = "126 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser.createFilter( AssetBrowser_addFilterWindow-->tagName.getText() );AssetBrowser_addFilterWindow.setVisible(0);";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "196 68";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_addFilterWindow.setVisible(0);";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+   };
+   new GuiWindowCtrl(AssetBrowserWindow) {
+      text = "Asset Browser";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "1";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      closeCommand = "AssetBrowser::hideDialog();";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "256 107";
+      extent = "512 554";
+      minExtent = "383 274";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "GuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiButtonCtrl(CreateAssetButton) {
+         text = "New";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "3 22";
+         extent = "45 19";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl(ImportAssetButton) {
+         text = "Import";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "50 22";
+         extent = "45 19";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiWindowCtrl(TagFilterWindow) {
+         text = "New Window";
+         resizeWidth = "1";
+         resizeHeight = "1";
+         canMove = "1";
+         canClose = "0";
+         canMinimize = "0";
+         canMaximize = "0";
+         canCollapse = "0";
+         edgeSnap = "1";
+         docking = "None";
+         margin = "4 4 4 4";
+         padding = "0 0 0 0";
+         anchorTop = "0";
+         anchorBottom = "0";
+         anchorLeft = "0";
+         anchorRight = "0";
+         position = "129 62";
+         extent = "161 250";
+         minExtent = "161 86";
+         horizSizing = "windowRelative";
+         vertSizing = "windowRelative";
+         profile = "ToolsGuiToolbarWindowProfile";
+         visible = "0";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         internalName = "VisibilityLayerWindow";
+         hidden = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiScrollCtrl() {
+            willFirstRespond = "1";
+            hScrollBar = "alwaysOff";
+            vScrollBar = "dynamic";
+            lockHorizScroll = "1";
+            lockVertScroll = "0";
+            constantThumbHeight = "0";
+            childMargin = "2 0";
+            mouseWheelScrollSpeed = "-1";
+            docking = "Client";
+            margin = "0 0 0 0";
+            padding = "0 0 0 0";
+            anchorTop = "1";
+            anchorBottom = "0";
+            anchorLeft = "1";
+            anchorRight = "0";
+            position = "1 9";
+            extent = "159 238";
+            minExtent = "8 2";
+            horizSizing = "width";
+            vertSizing = "height";
+            profile = "ToolsGuiScrollProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "ToolsGuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+
+            new GuiStackControl(TagFilterList) {
+               stackingType = "Vertical";
+               horizStacking = "Left to Right";
+               vertStacking = "Top to Bottom";
+               padding = "-2";
+               dynamicSize = "1";
+               dynamicNonStackExtent = "0";
+               dynamicPos = "0";
+               changeChildSizeToFit = "1";
+               changeChildPosition = "1";
+               position = "3 1";
+               extent = "153 16";
+               minExtent = "16 16";
+               horizSizing = "width";
+               vertSizing = "bottom";
+               profile = "ToolsGuiDefaultProfile";
+               visible = "1";
+               active = "1";
+               tooltipProfile = "ToolsGuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "1";
+               internalName = "theVisOptionsList";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+            };
+         };
+      };
+      new GuiSplitContainer() {
+         orientation = "Vertical";
+         splitterSize = "2";
+         splitPoint = "149 100";
+         fixedPanel = "None";
+         fixedSize = "356";
+         docking = "None";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "3 42";
+         extent = "505 509";
+         minExtent = "64 64";
+         horizSizing = "relative";
+         vertSizing = "height";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiPanel() {
+            docking = "Client";
+            margin = "0 0 0 0";
+            padding = "0 0 0 0";
+            anchorTop = "1";
+            anchorBottom = "0";
+            anchorLeft = "1";
+            anchorRight = "0";
+            position = "0 0";
+            extent = "147 509";
+            minExtent = "16 16";
+            horizSizing = "right";
+            vertSizing = "bottom";
+            profile = "GuiDefaultProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            internalName = "Panel1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+
+            new GuiContainer() {
+               margin = "0 0 0 0";
+               padding = "0 0 0 0";
+               anchorTop = "1";
+               anchorBottom = "0";
+               anchorLeft = "1";
+               anchorRight = "0";
+               position = "0 0";
+               extent = "147 31";
+               minExtent = "8 2";
+               horizSizing = "width";
+               vertSizing = "bottom";
+               profile = "inspectorStyleRolloutDarkProfile";
+               visible = "1";
+               active = "1";
+               tooltipProfile = "GuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "1";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+
+               new GuiTextCtrl() {
+                  text = "Filters";
+                  maxLength = "1024";
+                  margin = "0 0 0 0";
+                  padding = "0 0 0 0";
+                  anchorTop = "1";
+                  anchorBottom = "0";
+                  anchorLeft = "1";
+                  anchorRight = "0";
+                  position = "5 0";
+                  extent = "30 16";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "ToolsGuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  tooltipProfile = "GuiToolTipProfile";
+                  hovertime = "1000";
+                  isContainer = "1";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiBitmapButtonCtrl() {
+                  bitmap = "tools/gui/images/iconNew.png";
+                  bitmapMode = "Stretched";
+                  autoFitExtents = "0";
+                  useModifiers = "0";
+                  useStates = "1";
+                  masked = "0";
+                  groupNum = "-1";
+                  buttonType = "PushButton";
+                  useMouseEvents = "0";
+                  position = "113 1";
+                  extent = "15 15";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "GuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  command = "AssetBrowser.viewTagsFilter();";
+                  tooltipProfile = "GuiToolTipProfile";
+                  tooltip = "Show assets grouped and filtered via tags.";
+                  hovertime = "1000";
+                  isContainer = "0";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiBitmapButtonCtrl() {
+                  bitmap = "tools/gui/images/iconList.png";
+                  bitmapMode = "Stretched";
+                  autoFitExtents = "0";
+                  useModifiers = "0";
+                  useStates = "1";
+                  masked = "0";
+                  groupNum = "-1";
+                  buttonType = "PushButton";
+                  useMouseEvents = "0";
+                  position = "130 1";
+                  extent = "15 15";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "GuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  command = "AssetBrowser.viewListFilter();";
+                  tooltipProfile = "GuiToolTipProfile";
+                  tooltip = "Views assets via module-oriented list tree.";
+                  hovertime = "1000";
+                  isContainer = "0";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+            };
+            new GuiContainer() {
+               margin = "0 0 0 0";
+               padding = "0 0 0 0";
+               anchorTop = "1";
+               anchorBottom = "0";
+               anchorLeft = "1";
+               anchorRight = "0";
+               position = "0 17";
+               extent = "147 493";
+               minExtent = "8 2";
+               horizSizing = "width";
+               vertSizing = "height";
+               profile = "ToolsGuiDefaultProfile";
+               visible = "1";
+               active = "1";
+               tooltipProfile = "GuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "1";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+
+               new GuiScrollCtrl() {
+                  willFirstRespond = "1";
+                  hScrollBar = "alwaysOff";
+                  vScrollBar = "dynamic";
+                  lockHorizScroll = "1";
+                  lockVertScroll = "0";
+                  constantThumbHeight = "0";
+                  childMargin = "0 0";
+                  mouseWheelScrollSpeed = "-1";
+                  docking = "Client";
+                  margin = "0 0 0 0";
+                  padding = "0 0 0 0";
+                  anchorTop = "1";
+                  anchorBottom = "0";
+                  anchorLeft = "1";
+                  anchorRight = "0";
+                  position = "0 0";
+                  extent = "147 493";
+                  minExtent = "8 8";
+                  horizSizing = "width";
+                  vertSizing = "height";
+                  profile = "GuiEditorScrollProfile";
+                  visible = "1";
+                  active = "1";
+                  tooltipProfile = "ToolsGuiDefaultProfile";
+                  hovertime = "1000";
+                  isContainer = "1";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+
+                  new GuiTreeViewCtrl(AssetBrowserFilterTree) {
+                     tabSize = "16";
+                     textOffset = "2";
+                     fullRowSelect = "0";
+                     itemHeight = "21";
+                     destroyTreeOnSleep = "1";
+                     mouseDragging = "1";
+                     multipleSelections = "1";
+                     deleteObjectAllowed = "1";
+                     dragToItemAllowed = "1";
+                     clearAllOnSingleSelection = "1";
+                     showRoot = "1";
+                     useInspectorTooltips = "0";
+                     tooltipOnWidthOnly = "0";
+                     showObjectIds = "1";
+                     showClassNames = "1";
+                     showObjectNames = "1";
+                     showInternalNames = "1";
+                     showClassNameForUnnamedObjects = "0";
+                     compareToObjectID = "1";
+                     canRenameObjects = "1";
+                     renameInternal = "0";
+                     position = "1 1";
+                     extent = "145 294";
+                     minExtent = "8 2";
+                     horizSizing = "right";
+                     vertSizing = "bottom";
+                     profile = "ToolsGuiTreeViewProfile";
+                     visible = "1";
+                     active = "1";
+                     tooltipProfile = "GuiToolTipProfile";
+                     hovertime = "1000";
+                     isContainer = "1";
+                     internalName = "filterTree";
+                     canSave = "1";
+                     canSaveDynamicFields = "0";
+                  };
+               };
+            };
+         };
+         new GuiPanel() {
+            docking = "Client";
+            margin = "0 0 0 0";
+            padding = "0 0 0 0";
+            anchorTop = "1";
+            anchorBottom = "0";
+            anchorLeft = "1";
+            anchorRight = "0";
+            position = "151 0";
+            extent = "354 509";
+            minExtent = "16 16";
+            horizSizing = "right";
+            vertSizing = "bottom";
+            profile = "GuiDefaultProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            internalName = "panel2";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+
+            new GuiContainer() {
+               margin = "0 0 0 0";
+               padding = "0 0 0 0";
+               anchorTop = "1";
+               anchorBottom = "0";
+               anchorLeft = "1";
+               anchorRight = "0";
+               position = "1 0";
+               extent = "354 41";
+               minExtent = "8 2";
+               horizSizing = "width";
+               vertSizing = "bottom";
+               profile = "inspectorStyleRolloutDarkProfile";
+               visible = "1";
+               active = "1";
+               tooltipProfile = "GuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "1";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+
+               new GuiBitmapButtonCtrl() {
+                  bitmap = "tools/gui/images/new";
+                  bitmapMode = "Stretched";
+                  autoFitExtents = "0";
+                  useModifiers = "0";
+                  useStates = "1";
+                  masked = "0";
+                  groupNum = "-1";
+                  buttonType = "PushButton";
+                  useMouseEvents = "0";
+                  position = "42 22";
+                  extent = "15 15";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "ToolsGuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  command = "AssetBrowser.createNewAsset();";
+                  tooltipProfile = "GuiToolTipProfile";
+                  tooltip = "Create New Asset";
+                  hovertime = "1000";
+                  isContainer = "0";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiBitmapButtonCtrl() {
+                  bitmap = "tools/gui/images/delete";
+                  bitmapMode = "Stretched";
+                  autoFitExtents = "0";
+                  useModifiers = "0";
+                  useStates = "1";
+                  masked = "0";
+                  groupNum = "-1";
+                  buttonType = "PushButton";
+                  useMouseEvents = "0";
+                  position = "23 22";
+                  extent = "15 15";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "ToolsGuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  command = "AssetBrowser.showDeleteDialog();";
+                  tooltipProfile = "GuiToolTipProfile";
+                  tooltip = "Delete Asset";
+                  hovertime = "1000";
+                  isContainer = "0";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiTextEditCtrl(AssetBrowserSearchFilter) {
+                  historySize = "0";
+                  tabComplete = "0";
+                  sinkAllKeyEvents = "0";
+                  password = "0";
+                  passwordMask = "*";
+                  text = "\c2Filter...";
+                  maxLength = "1024";
+                  margin = "0 0 0 0";
+                  padding = "0 0 0 0";
+                  anchorTop = "1";
+                  anchorBottom = "0";
+                  anchorLeft = "1";
+                  anchorRight = "0";
+                  position = "62 19";
+                  extent = "273 18";
+                  minExtent = "8 2";
+                  horizSizing = "width";
+                  vertSizing = "bottom";
+                  profile = "ToolsGuiTextEditProfile";
+                  visible = "1";
+                  active = "1";
+                  tooltipProfile = "GuiToolTipProfile";
+                  hovertime = "1000";
+                  isContainer = "1";
+                  class = "AssetBrowserSearchFilterText";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiBitmapButtonCtrl(TagFilterButton) {
+                  bitmap = "tools/gui/images/visible";
+                  bitmapMode = "Stretched";
+                  autoFitExtents = "0";
+                  useModifiers = "0";
+                  useStates = "1";
+                  masked = "0";
+                  groupNum = "-1";
+                  buttonType = "PushButton";
+                  useMouseEvents = "0";
+                  position = "4 19";
+                  extent = "20 20";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "GuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  command = "AssetBrowser.toggleTagFilterPopup();";
+                  tooltipProfile = "GuiToolTipProfile";
+                  hovertime = "1000";
+                  isContainer = "0";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiTextCtrl() {
+                  text = "Assets";
+                  maxLength = "1024";
+                  margin = "0 0 0 0";
+                  padding = "0 0 0 0";
+                  anchorTop = "1";
+                  anchorBottom = "0";
+                  anchorLeft = "1";
+                  anchorRight = "0";
+                  position = "5 0";
+                  extent = "53 16";
+                  minExtent = "8 2";
+                  horizSizing = "right";
+                  vertSizing = "bottom";
+                  profile = "ToolsGuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  tooltipProfile = "GuiToolTipProfile";
+                  hovertime = "1000";
+                  isContainer = "1";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+               new GuiBitmapButtonCtrl() {
+                  bitmap = "tools/gui/images/delete";
+                  bitmapMode = "Stretched";
+                  autoFitExtents = "0";
+                  useModifiers = "0";
+                  useStates = "1";
+                  masked = "0";
+                  groupNum = "-1";
+                  buttonType = "PushButton";
+                  useMouseEvents = "0";
+                  position = "337 22";
+                  extent = "15 15";
+                  minExtent = "8 2";
+                  horizSizing = "left";
+                  vertSizing = "bottom";
+                  profile = "ToolsGuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  command = "AssetBrowser.showDeleteDialog();";
+                  tooltipProfile = "GuiToolTipProfile";
+                  tooltip = "Delete Asset";
+                  hovertime = "1000";
+                  isContainer = "0";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+            };
+            new GuiContainer() {
+               margin = "0 0 0 0";
+               padding = "0 0 0 0";
+               anchorTop = "1";
+               anchorBottom = "0";
+               anchorLeft = "1";
+               anchorRight = "1";
+               position = "1 40";
+               extent = "354 468";
+               minExtent = "8 2";
+               horizSizing = "width";
+               vertSizing = "height";
+               profile = "ToolsGuiDefaultProfile";
+               visible = "1";
+               active = "1";
+               tooltipProfile = "GuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "1";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+
+               new GuiScrollCtrl(AssetListPanel) {
+                  willFirstRespond = "1";
+                  hScrollBar = "alwaysOff";
+                  vScrollBar = "dynamic";
+                  lockHorizScroll = "1";
+                  lockVertScroll = "0";
+                  constantThumbHeight = "0";
+                  childMargin = "0 0";
+                  mouseWheelScrollSpeed = "-1";
+                  docking = "Client";
+                  margin = "0 0 0 0";
+                  padding = "0 0 0 0";
+                  anchorTop = "1";
+                  anchorBottom = "0";
+                  anchorLeft = "1";
+                  anchorRight = "0";
+                  position = "0 0";
+                  extent = "354 448";
+                  minExtent = "8 8";
+                  horizSizing = "width";
+                  vertSizing = "height";
+                  profile = "GuiEditorScrollProfile";
+                  visible = "1";
+                  active = "1";
+                  tooltipProfile = "ToolsGuiDefaultProfile";
+                  hovertime = "1000";
+                  isContainer = "1";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+
+                  new GuiStackControl() {
+                     stackingType = "Vertical";
+                     horizStacking = "Left to Right";
+                     vertStacking = "Top to Bottom";
+                     padding = "0";
+                     dynamicSize = "1";
+                     dynamicNonStackExtent = "0";
+                     dynamicPos = "0";
+                     changeChildSizeToFit = "1";
+                     changeChildPosition = "0";
+                     position = "1 1";
+                     extent = "352 254";
+                     minExtent = "16 16";
+                     horizSizing = "width";
+                     vertSizing = "bottom";
+                     profile = "ToolsGuiModelessDialogProfile";
+                     visible = "1";
+                     active = "1";
+                     tooltipProfile = "GuiToolTipProfile";
+                     hovertime = "1000";
+                     isContainer = "1";
+                     canSave = "1";
+                     canSaveDynamicFields = "0";
+
+                     new GuiControl() {
+                        position = "0 0";
+                        extent = "352 4";
+                        minExtent = "8 2";
+                        horizSizing = "right";
+                        vertSizing = "bottom";
+                        profile = "GuiDefaultProfile";
+                        visible = "1";
+                        active = "1";
+                        tooltipProfile = "GuiToolTipProfile";
+                        hovertime = "1000";
+                        isContainer = "1";
+                        canSave = "1";
+                        canSaveDynamicFields = "0";
+                     };
+                     new GuiDynamicCtrlArrayControl() {
+                        colCount = "3";
+                        colSize = "100";
+                        rowCount = "2";
+                        rowSize = "124";
+                        rowSpacing = "2";
+                        colSpacing = "2";
+                        frozen = "0";
+                        autoCellSize = "1";
+                        fillRowFirst = "1";
+                        dynamicSize = "1";
+                        padding = "0 0 0 0";
+                        position = "3 4";
+                        extent = "352 250";
+                        minExtent = "8 8";
+                        horizSizing = "width";
+                        vertSizing = "bottom";
+                        profile = "ToolsGuiDefaultNonModalProfile";
+                        visible = "1";
+                        active = "1";
+                        tooltipProfile = "GuiToolTipProfile";
+                        hovertime = "1000";
+                        isContainer = "1";
+                        internalName = "materialSelection";
+                        canSave = "1";
+                        canSaveDynamicFields = "0";
+                     };
+                  };
+               };
+               new GuiContainer() {
+                  docking = "Bottom";
+                  margin = "0 0 0 0";
+                  padding = "0 0 0 0";
+                  anchorTop = "1";
+                  anchorBottom = "0";
+                  anchorLeft = "1";
+                  anchorRight = "0";
+                  position = "0 448";
+                  extent = "354 20";
+                  minExtent = "8 2";
+                  horizSizing = "width";
+                  vertSizing = "height";
+                  profile = "ToolsGuiDefaultProfile";
+                  visible = "1";
+                  active = "1";
+                  tooltipProfile = "GuiToolTipProfile";
+                  hovertime = "1000";
+                  isContainer = "1";
+                  internalName = "materialPreviewControlContainer";
+                  canSave = "1";
+                  canSaveDynamicFields = "0";
+               };
+            };
+            new GuiButtonCtrl() {
+               text = "Select";
+               groupNum = "-1";
+               buttonType = "PushButton";
+               useMouseEvents = "0";
+               position = "242 491";
+               extent = "53 19";
+               minExtent = "8 2";
+               horizSizing = "left";
+               vertSizing = "top";
+               profile = "ToolsGuiButtonProfile";
+               visible = "1";
+               active = "1";
+               command = "AssetBrowser.selectAsset( AssetBrowser.selectedAsset );";
+               tooltipProfile = "GuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "0";
+               internalName = "SelectButton";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+            };
+            new GuiButtonCtrl() {
+               text = "Cancel";
+               groupNum = "-1";
+               buttonType = "PushButton";
+               useMouseEvents = "0";
+               position = "300 491";
+               extent = "52 19";
+               minExtent = "8 2";
+               horizSizing = "left";
+               vertSizing = "top";
+               profile = "ToolsGuiButtonProfile";
+               visible = "1";
+               active = "1";
+               command = "AssetBrowser.hideDialog();";
+               tooltipProfile = "GuiToolTipProfile";
+               hovertime = "1000";
+               isContainer = "0";
+               canSave = "1";
+               canSaveDynamicFields = "0";
+            };
+         };
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 613 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/assetImport.gui

@@ -0,0 +1,613 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(AssetImportCtrl) {
+   position = "0 0";
+   extent = "1440 900";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "GuiDefaultProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+
+   new GuiWindowCtrl(ImportAssetOptionsWindow) {
+      text = "Import Options";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "0";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "633 358";
+      extent = "346 409";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "0";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      hidden = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiButtonCtrl() {
+         text = "Done";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "271 377";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "top";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "ImportAssetOptionsWindow.saveAssetOptions();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiScrollCtrl() {
+         willFirstRespond = "1";
+         hScrollBar = "dynamic";
+         vScrollBar = "dynamic";
+         lockHorizScroll = "0";
+         lockVertScroll = "0";
+         constantThumbHeight = "0";
+         childMargin = "0 0";
+         mouseWheelScrollSpeed = "-1";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "9 26";
+         extent = "326 344";
+         minExtent = "8 2";
+         horizSizing = "width";
+         vertSizing = "height";
+         profile = "GuiScrollProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiVariableInspector(ImportOptionsList) {
+            dividerMargin = "5";
+            showCustomFields = "1";
+            stackingType = "Vertical";
+            horizStacking = "Left to Right";
+            vertStacking = "Top to Bottom";
+            padding = "1";
+            dynamicSize = "1";
+            dynamicNonStackExtent = "0";
+            dynamicPos = "0";
+            changeChildSizeToFit = "1";
+            changeChildPosition = "1";
+            position = "1 1";
+            extent = "309 64";
+            minExtent = "16 16";
+            horizSizing = "right";
+            vertSizing = "bottom";
+            profile = "GuiDefaultProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+         };
+      };
+   };
+   new GuiWindowCtrl(ImportAssetConfigEditorWindow) {
+      text = "Import Options Config";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "0";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "562 251";
+      extent = "376 503";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "0";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      hidden = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiTextCtrl() {
+         text = "Configuration Name:";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "10 26";
+         extent = "100 17";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextEditCtrl(AssetImportConfigName) {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "113 25";
+         extent = "250 18";
+         minExtent = "8 2";
+         horizSizing = "width";
+         vertSizing = "bottom";
+         profile = "GuiTextEditProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Done";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "301 471";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "top";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "ImportAssetConfigEditorWindow.saveAssetOptionsConfig();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiScrollCtrl() {
+         willFirstRespond = "1";
+         hScrollBar = "dynamic";
+         vScrollBar = "dynamic";
+         lockHorizScroll = "0";
+         lockVertScroll = "0";
+         constantThumbHeight = "0";
+         childMargin = "0 0";
+         mouseWheelScrollSpeed = "-1";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "9 50";
+         extent = "356 414";
+         minExtent = "8 2";
+         horizSizing = "width";
+         vertSizing = "height";
+         profile = "GuiScrollProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiVariableInspector(ImportOptionsConfigList) {
+            dividerMargin = "5";
+            showCustomFields = "1";
+            stackingType = "Vertical";
+            horizStacking = "Left to Right";
+            vertStacking = "Top to Bottom";
+            padding = "1";
+            dynamicSize = "1";
+            dynamicNonStackExtent = "0";
+            dynamicPos = "0";
+            changeChildSizeToFit = "1";
+            changeChildPosition = "1";
+            position = "1 1";
+            extent = "339 64";
+            minExtent = "16 16";
+            horizSizing = "right";
+            vertSizing = "bottom";
+            profile = "GuiDefaultProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+         };
+      };
+   };
+   new GuiWindowCtrl(ImportAssetWindow) {
+      text = "Import Assets";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "0";
+      canMinimize = "0";
+      canMaximize = "0";
+      canCollapse = "0";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "536 205";
+      extent = "368 502";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiButtonCtrl() {
+         text = "Done";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "224 470";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "top";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "ImportAssetWindow.ImportAssets();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "292 470";
+         extent = "64 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "top";
+         profile = "ToolsGuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "Canvas.popDialog();";
+         tooltipProfile = "ToolsGuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Target Module:";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 30";
+         extent = "116 17";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiPopUpMenuCtrlEx(ImportAssetModuleList) {
+         maxPopupHeight = "200";
+         sbUsesNAColor = "0";
+         reverseTextList = "0";
+         bitmapBounds = "16 16";
+         hotTrackCallback = "0";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "134 27";
+         extent = "204 22";
+         minExtent = "8 2";
+         horizSizing = "width";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiBitmapButtonCtrl() {
+         bitmap = "tools/gui/images/iconAdd.png";
+         bitmapMode = "Centered";
+         autoFitExtents = "0";
+         useModifiers = "0";
+         useStates = "1";
+         masked = "0";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "342 27";
+         extent = "22 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         command = "Canvas.pushDialog(AssetBrowser_addModule);\nAssetBrowser_addModuleWindow.selectWindow();";
+         tooltipProfile = "GuiToolTipProfile";
+         tooltip = "New Module";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Import Options Config:";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "12 56";
+         extent = "116 17";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiPopUpMenuCtrlEx(ImportAssetConfigList) {
+         maxPopupHeight = "200";
+         sbUsesNAColor = "0";
+         reverseTextList = "0";
+         bitmapBounds = "16 16";
+         hotTrackCallback = "0";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "126 53";
+         extent = "175 22";
+         minExtent = "8 2";
+         horizSizing = "width";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiBitmapButtonCtrl() {
+         bitmap = "tools/gui/images/iconAdd.png";
+         bitmapMode = "Centered";
+         autoFitExtents = "0";
+         useModifiers = "0";
+         useStates = "1";
+         masked = "0";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "305 53";
+         extent = "15 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         command = "ImportAssetConfigEditorWindow.addNewConfig();";
+         tooltipProfile = "GuiToolTipProfile";
+         tooltip = "New Config";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiBitmapButtonCtrl() {
+         bitmap = "tools/gui/images/iconInformation.png";
+         bitmapMode = "Centered";
+         autoFitExtents = "0";
+         useModifiers = "0";
+         useStates = "1";
+         masked = "0";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "325 53";
+         extent = "15 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         command = "ImportAssetConfigEditorWindow.editConfig();";
+         tooltipProfile = "GuiToolTipProfile";
+         tooltip = "Edit Config";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiBitmapButtonCtrl() {
+         bitmap = "tools/gui/images/iconDelete.png";
+         bitmapMode = "Centered";
+         autoFitExtents = "0";
+         useModifiers = "0";
+         useStates = "1";
+         masked = "0";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "346 53";
+         extent = "15 22";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "GuiDefaultProfile";
+         visible = "1";
+         active = "1";
+         command = "ImportAssetConfigEditorWindow.deleteConfig();";
+         tooltipProfile = "GuiToolTipProfile";
+         tooltip = "Delete Config";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiScrollCtrl() {
+         willFirstRespond = "1";
+         hScrollBar = "dynamic";
+         vScrollBar = "dynamic";
+         lockHorizScroll = "0";
+         lockVertScroll = "0";
+         constantThumbHeight = "0";
+         childMargin = "0 0";
+         mouseWheelScrollSpeed = "-1";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "9 82";
+         extent = "348 381";
+         minExtent = "8 2";
+         horizSizing = "width";
+         vertSizing = "height";
+         profile = "GuiScrollProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiStackControl(ImportingAssetList) {
+            stackingType = "Vertical";
+            horizStacking = "Left to Right";
+            vertStacking = "Top to Bottom";
+            padding = "0";
+            dynamicSize = "1";
+            dynamicNonStackExtent = "0";
+            dynamicPos = "0";
+            changeChildSizeToFit = "0";
+            changeChildPosition = "1";
+            position = "1 1";
+            extent = "345 20";
+            minExtent = "16 16";
+            horizSizing = "width";
+            vertSizing = "bottom";
+            profile = "GuiDefaultProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+         };
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 147 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/editAsset.gui

@@ -0,0 +1,147 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(AssetBrowser_editAsset) {
+   position = "0 0";
+   extent = "1920 1080";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "ToolsGuiDefaultNonModalProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      enabled = "1";
+
+   new GuiWindowCtrl(AssetBrowser_editAssetWindow) {
+      text = "Asset Properties";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "1";
+      canMinimize = "1";
+      canMaximize = "0";
+      canCollapse = "0";
+      closeCommand = "Canvas.popDialog(AssetBrowser_editAsset);";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "710 375";
+      extent = "500 329";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiScrollCtrl() {
+         willFirstRespond = "1";
+         hScrollBar = "alwaysOff";
+         vScrollBar = "dynamic";
+         lockHorizScroll = "0";
+         lockVertScroll = "0";
+         constantThumbHeight = "0";
+         childMargin = "0 0";
+         mouseWheelScrollSpeed = "-1";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "1 21";
+         extent = "498 283";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiScrollProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiInspector(AssetEditInspector) {
+            dividerMargin = "5";
+            showCustomFields = "1";
+            stackingType = "Vertical";
+            horizStacking = "Left to Right";
+            vertStacking = "Top to Bottom";
+            padding = "1";
+            dynamicSize = "1";
+            dynamicNonStackExtent = "0";
+            dynamicPos = "0";
+            changeChildSizeToFit = "1";
+            changeChildPosition = "1";
+            position = "1 1";
+            extent = "481 101";
+            minExtent = "16 16";
+            horizSizing = "right";
+            vertSizing = "bottom";
+            profile = "GuiInspectorProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+         };
+      };
+      new GuiButtonCtrl() {
+         text = "Save";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "402 305";
+         extent = "45 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_editAsset.saveAsset();";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "450 305";
+         extent = "45 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "Canvas.popDialog(AssetBrowser_editAsset);";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 147 - 0
Templates/BaseGame/game/tools/assetBrowser/guis/editModule.gui

@@ -0,0 +1,147 @@
+//--- OBJECT WRITE BEGIN ---
+%guiContent = new GuiControl(AssetBrowser_editModule) {
+   position = "0 0";
+   extent = "1920 1080";
+   minExtent = "8 2";
+   horizSizing = "right";
+   vertSizing = "bottom";
+   profile = "ToolsGuiDefaultNonModalProfile";
+   visible = "1";
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      enabled = "1";
+
+   new GuiWindowCtrl(AssetBrowser_editModuleWindow) {
+      text = "Module Properties";
+      resizeWidth = "1";
+      resizeHeight = "1";
+      canMove = "1";
+      canClose = "1";
+      canMinimize = "1";
+      canMaximize = "0";
+      canCollapse = "0";
+      closeCommand = "Canvas.popDialog(AssetBrowser_editModule);";
+      edgeSnap = "1";
+      margin = "0 0 0 0";
+      padding = "0 0 0 0";
+      anchorTop = "1";
+      anchorBottom = "0";
+      anchorLeft = "1";
+      anchorRight = "0";
+      position = "710 375";
+      extent = "500 329";
+      minExtent = "48 92";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "ToolsGuiWindowProfile";
+      visible = "1";
+      active = "1";
+      tooltipProfile = "ToolsGuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
+
+      new GuiScrollCtrl() {
+         willFirstRespond = "1";
+         hScrollBar = "alwaysOff";
+         vScrollBar = "dynamic";
+         lockHorizScroll = "0";
+         lockVertScroll = "0";
+         constantThumbHeight = "0";
+         childMargin = "0 0";
+         mouseWheelScrollSpeed = "-1";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "1 21";
+         extent = "498 283";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiScrollProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+
+         new GuiInspector(ModuleEditInspector) {
+            dividerMargin = "5";
+            showCustomFields = "1";
+            stackingType = "Vertical";
+            horizStacking = "Left to Right";
+            vertStacking = "Top to Bottom";
+            padding = "1";
+            dynamicSize = "1";
+            dynamicNonStackExtent = "0";
+            dynamicPos = "0";
+            changeChildSizeToFit = "1";
+            changeChildPosition = "1";
+            position = "1 1";
+            extent = "481 101";
+            minExtent = "16 16";
+            horizSizing = "right";
+            vertSizing = "bottom";
+            profile = "GuiInspectorProfile";
+            visible = "1";
+            active = "1";
+            tooltipProfile = "GuiToolTipProfile";
+            hovertime = "1000";
+            isContainer = "1";
+            canSave = "1";
+            canSaveDynamicFields = "0";
+         };
+      };
+      new GuiButtonCtrl() {
+         text = "Save";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "402 305";
+         extent = "45 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "AssetBrowser_editModule.saveModule();";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiButtonCtrl() {
+         text = "Cancel";
+         groupNum = "-1";
+         buttonType = "PushButton";
+         useMouseEvents = "0";
+         position = "450 305";
+         extent = "45 22";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiButtonProfile";
+         visible = "1";
+         active = "1";
+         command = "Canvas.popDialog(AssetBrowser_editModule);";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "0";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+   };
+};
+//--- OBJECT WRITE END ---

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است