浏览代码

Merge branch 'development' into issue_2115

Areloch 7 年之前
父节点
当前提交
6497ea5c76
共有 46 个文件被更改,包括 805 次插入399 次删除
  1. 1 6
      Engine/source/T3D/assets/ImageAsset.cpp
  2. 0 5
      Engine/source/T3D/assets/ImageAsset.h
  3. 3 1
      Engine/source/T3D/assets/LevelAsset.cpp
  4. 1 1
      Engine/source/T3D/assets/ScriptAsset.cpp
  5. 45 1
      Engine/source/T3D/assets/ShapeAnimationAsset.cpp
  6. 26 2
      Engine/source/T3D/assets/ShapeAnimationAsset.h
  7. 36 4
      Engine/source/T3D/assets/ShapeAsset.cpp
  8. 7 4
      Engine/source/T3D/components/animation/animationComponent.cpp
  9. 5 3
      Engine/source/T3D/components/collision/collisionComponent.cpp
  10. 9 2
      Engine/source/T3D/components/component.cpp
  11. 4 0
      Engine/source/T3D/components/game/stateMachine.cpp
  12. 2 0
      Engine/source/T3D/components/game/stateMachine.h
  13. 5 2
      Engine/source/T3D/components/physics/playerControllerComponent.cpp
  14. 1 1
      Engine/source/T3D/components/render/meshComponent.cpp
  15. 11 10
      Engine/source/T3D/entity.cpp
  16. 7 7
      Engine/source/T3D/entity.h
  17. 5 2
      Engine/source/T3D/systems/render/meshRenderSystem.cpp
  18. 10 1
      Engine/source/console/consoleObject.cpp
  19. 5 6
      Engine/source/console/consoleObject.h
  20. 1 1
      Engine/source/console/engineTypes.h
  21. 14 0
      Engine/source/console/simObject.cpp
  22. 5 0
      Engine/source/console/typeValidators.h
  23. 1 1
      Engine/source/gfx/sim/cubemapData.cpp
  24. 5 5
      Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp
  25. 15 8
      Engine/source/gui/core/guiCanvas.cpp
  26. 1 0
      Engine/source/gui/core/guiCanvas.h
  27. 3 2
      Engine/source/gui/editor/guiMenuBar.cpp
  28. 2 1
      Engine/source/gui/editor/inspector/entityGroup.cpp
  29. 1 1
      Engine/source/materials/processedMaterial.cpp
  30. 23 0
      Engine/source/math/mConsoleFunctions.cpp
  31. 13 0
      Engine/source/math/mMathFn.h
  32. 225 5
      Engine/source/sim/actionMap.cpp
  33. 34 1
      Engine/source/sim/actionMap.h
  34. 90 0
      Engine/source/sim/netObject.cpp
  35. 51 0
      Engine/source/sim/netObject.h
  36. 12 1
      Engine/source/ts/collada/colladaImport.cpp
  37. 0 7
      Templates/BaseGame/game/tools/base/images/sky_skybox.dml
  38. 7 3
      Templates/BaseGame/game/tools/shapeEditor/scripts/shapeEditorActions.ed.cs
  39. 1 2
      Templates/BaseGame/game/tools/worldEditor/scripts/editorPrefs.ed.cs
  40. 0 46
      Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs
  41. 二进制
      Templates/Full/game/art/shapes/weapons/Ryder/TP_Ryder_S.dds
  42. 1 1
      Templates/Full/game/art/shapes/weapons/Ryder/materials.cs
  43. 1 1
      Templates/Full/game/art/shapes/weapons/Turret/materials.cs
  44. 116 208
      Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs
  45. 0 1
      Templates/Full/game/tools/worldEditor/scripts/editorPrefs.ed.cs
  46. 0 46
      Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs

+ 1 - 6
Engine/source/T3D/assets/ImageAsset.cpp

@@ -90,14 +90,9 @@ ConsoleSetType(TypeImageAssetPtr)
 
 //-----------------------------------------------------------------------------
 
-ImageAsset::ImageAsset()
+ImageAsset::ImageAsset() : AssetBase(), mImage(nullptr), mUseMips(true), mIsHDRImage(false), mIsValidImage(false)
 {
    mImageFileName = StringTable->EmptyString();
-
-   mImage = NULL;
-   mUseMips = true;
-   mIsHDRImage = false;
-   mIsValidImage = false;
 }
 
 //-----------------------------------------------------------------------------

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

@@ -47,11 +47,6 @@ class ImageAsset : public AssetBase
 {
    typedef AssetBase Parent;
 
-   AssetManager*           mpOwningAssetManager;
-   bool                    mAssetInitialized;
-   AssetDefinition*        mpAssetDefinition;
-   U32                     mAcquireReferenceCount;
-
    StringTableEntry mImageFileName;
 
    GFXTexHandle mImage;

+ 3 - 1
Engine/source/T3D/assets/LevelAsset.cpp

@@ -90,10 +90,12 @@ ConsoleSetType(TypeLevelAssetPtr)
 
 //-----------------------------------------------------------------------------
 
-LevelAsset::LevelAsset()
+LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false)
 {
    mLevelFile = StringTable->EmptyString();
    mPreviewImage = StringTable->EmptyString();
+
+   mMainLevelAsset = StringTable->EmptyString();
 }
 
 //-----------------------------------------------------------------------------

+ 1 - 1
Engine/source/T3D/assets/ScriptAsset.cpp

@@ -89,7 +89,7 @@ ConsoleSetType(TypeScriptAssetPtr)
 
 //-----------------------------------------------------------------------------
 
-ScriptAsset::ScriptAsset()
+ScriptAsset::ScriptAsset() : AssetBase(), mIsServerSide(true)
 {
    mScriptFilePath = StringTable->EmptyString();
 }

+ 45 - 1
Engine/source/T3D/assets/ShapeAnimationAsset.cpp

@@ -92,8 +92,13 @@ ConsoleSetType(TypeShapeAnimationAssetPtr)
 
 //-----------------------------------------------------------------------------
 
-ShapeAnimationAsset::ShapeAnimationAsset()
+ShapeAnimationAsset::ShapeAnimationAsset() : 
+   mIsEmbedded(false), mIsCyclical(true), mIsBlend(false), mBlendFrame(0), mStartFrame(0), mEndFrame(-1), mPadRotation(true), mPadTransforms(false)
 {
+   mFileName = StringTable->EmptyString();
+   mAnimationName = StringTable->EmptyString();
+
+   mBlendAnimAssetName = StringTable->EmptyString();
 }
 
 //-----------------------------------------------------------------------------
@@ -116,6 +121,14 @@ void ShapeAnimationAsset::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("isEmbedded", TypeBool, Offset(mIsEmbedded, ShapeAnimationAsset), "If true, this animation asset just referrs to an embedded animation of a regular shape mesh. If false, it is a self-contained animation file");
+
+   addField("isCyclic", TypeBool, Offset(mIsCyclical, ShapeAnimationAsset), "Is this animation looping?");
+
+   addField("isBlend", TypeBool, Offset(mIsBlend, ShapeAnimationAsset), "Is this animation blended with another?");
+   addField("blendRefAnimation", TypeString, Offset(mBlendAnimAssetName, ShapeAnimationAsset), "AssetID of the animation to reference for our blending");
+   addField("blendFrame", TypeS32, Offset(mBlendFrame, ShapeAnimationAsset), "Which frame of the reference animation do we use for our blending");
+
    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");
@@ -128,4 +141,35 @@ void ShapeAnimationAsset::copyTo(SimObject* object)
 {
    // Call to parent.
    Parent::copyTo(object);
+}
+
+void ShapeAnimationAsset::initializeAsset(void)
+{
+   if (!mIsEmbedded)
+   {
+      //If we're not embedded, we need to load in our initial shape and do some prepwork
+
+      char filenameBuf[1024];
+      Con::expandScriptFilename(filenameBuf, sizeof(filenameBuf), mFileName);
+
+      mSourceShape = ResourceManager::get().load(filenameBuf);
+
+      if (!mSourceShape->addSequence("ambient", "", mAnimationName, mStartFrame, mEndFrame, mPadRotation, mPadTransforms))
+      {
+         Con::errorf("ShapeAnimationAsset::initializeAsset - Unable to do initial setup of the animation clip named %s for asset %s", mAnimationName, getAssetName());
+         return;
+      }
+
+      S32 sequenceId = mSourceShape->findSequence(mAnimationName);
+
+      if(mIsCyclical)
+         mSourceShape->sequences[sequenceId].flags |= TSShape::Cyclic;
+      else
+         mSourceShape->sequences[sequenceId].flags &= (~(TSShape::Cyclic));
+   }
+}
+
+void ShapeAnimationAsset::onAssetRefresh(void)
+{
+
 }

+ 26 - 2
Engine/source/T3D/assets/ShapeAnimationAsset.h

@@ -37,6 +37,12 @@
 #ifndef _ASSET_FIELD_TYPES_H_
 #include "assets/assetFieldTypes.h"
 #endif
+#ifndef _TSSHAPE_H_
+#include "ts/tsShape.h"
+#endif
+#ifndef __RESOURCE_H__
+#include "core/resource.h"
+#endif
 
 //-----------------------------------------------------------------------------
 class ShapeAnimationAsset : public AssetBase
@@ -46,6 +52,15 @@ class ShapeAnimationAsset : public AssetBase
 protected:
    StringTableEntry   mFileName;
 
+   bool            mIsEmbedded;
+   bool            mIsCyclical;
+
+   bool            mIsBlend;
+
+   StringTableEntry mBlendAnimAssetName;
+
+   S32 mBlendFrame;
+
    //
    StringTableEntry mAnimationName;
    S32 mStartFrame;
@@ -53,6 +68,8 @@ protected:
    bool mPadRotation;
    bool mPadTransforms;
 
+   Resource<TSShape> mSourceShape;
+
 public:
    ShapeAnimationAsset();
    virtual ~ShapeAnimationAsset();
@@ -65,18 +82,25 @@ public:
    DECLARE_CONOBJECT(ShapeAnimationAsset);
 
 protected:
-   virtual void            initializeAsset(void) {}
-   virtual void            onAssetRefresh(void) {}
+   virtual void            initializeAsset(void);
+   virtual void            onAssetRefresh(void);
 
 public:
    StringTableEntry getAnimationFilename() { return mFileName; }
    StringTableEntry getAnimationName() { return mAnimationName; }
+   StringTableEntry getBlendAnimationName() { return mBlendAnimAssetName; }
 
    S32 getStartFrame() { return mStartFrame; }
    S32 getEndFrame() { return mEndFrame; }
 
    bool getPadRotation() { return mPadRotation; }
    bool getPadTransforms() { return mPadTransforms; }
+
+   bool isEmbedded() { return mIsEmbedded; }
+   bool isCyclic() { return mIsCyclical; }
+   bool isBlend() { return mIsBlend; }
+
+   S32 getBlendFrame() { return mBlendFrame; }
 };
 
 DefineConsoleType(TypeShapeAnimationAssetPtr, ShapeAnimationAsset)

+ 36 - 4
Engine/source/T3D/assets/ShapeAsset.cpp

@@ -182,17 +182,49 @@ bool ShapeAsset::loadShape()
       return false; //if it failed to load, bail out
    }
 
+   bool hasBlends = false;
+
    //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++)
+   for (S32 i = mAnimationAssets.size()-1; i >= 0; --i)
    {
-      String srcName;
+      String srcName = mAnimationAssets[i]->getAnimationName();
       String srcPath(mAnimationAssets[i]->getAnimationFilename());
-      SplitSequencePathAndName(srcPath, srcName);
+      //SplitSequencePathAndName(srcPath, srcName);
 
-      if (!mShape->addSequence(srcPath, srcName, mAnimationAssets[i]->getAnimationName(), 
+      if (!mShape->addSequence(srcPath, srcName, srcName,
          mAnimationAssets[i]->getStartFrame(), mAnimationAssets[i]->getEndFrame(), mAnimationAssets[i]->getPadRotation(), mAnimationAssets[i]->getPadTransforms()))
          return false;
+
+      if (mAnimationAssets[i]->isBlend())
+         hasBlends = true;
+   }
+
+   //if any of our animations are blends, set those up now
+   if (hasBlends)
+   {
+      for (U32 i=0; i < mAnimationAssets.size(); ++i)
+      {
+         if (mAnimationAssets[i]->isBlend() && mAnimationAssets[i]->getBlendAnimationName() != StringTable->EmptyString())
+         {
+            //gotta do a bit of logic here.
+            //First, we need to make sure the anim asset we depend on for our blend is loaded
+            AssetPtr<ShapeAnimationAsset> blendAnimAsset = mAnimationAssets[i]->getBlendAnimationName();
+
+            if (blendAnimAsset.isNull())
+            {
+               Con::errorf("ShapeAsset::initializeAsset - Unable to acquire reference animation asset %s for asset %s to blend!", mAnimationAssets[i]->getBlendAnimationName(), mAnimationAssets[i]->getAssetName());
+               return false;
+            }
+
+            String refAnimName = blendAnimAsset->getAnimationName();
+            if (!mShape->setSequenceBlend(mAnimationAssets[i]->getAnimationName(), true, blendAnimAsset->getAnimationName(), mAnimationAssets[i]->getBlendFrame()))
+            {
+               Con::errorf("ShapeAnimationAsset::initializeAsset - Unable to set animation clip %s for asset %s to blend!", mAnimationAssets[i]->getAnimationName(), mAnimationAssets[i]->getAssetName());
+               return false;
+            }
+         }
+      }
    }
 
    return true;

+ 7 - 4
Engine/source/T3D/components/animation/animationComponent.cpp

@@ -222,7 +222,7 @@ U32 AnimationComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stre
 {
    U32 retMask = Parent::packUpdate(con, mask, stream);
 
-   /*for (int i = 0; i < MaxScriptThreads; i++)
+   for (int i = 0; i < MaxScriptThreads; i++)
    {
       Thread& st = mAnimationThreads[i];
       if (stream->writeFlag((st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i))))
@@ -234,7 +234,7 @@ U32 AnimationComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stre
          stream->writeFlag(st.atEnd);
          stream->writeFlag(st.transition);
       }
-   }*/
+   }
 
    return retMask;
 }
@@ -243,7 +243,7 @@ void AnimationComponent::unpackUpdate(NetConnection *con, BitStream *stream)
 {
    Parent::unpackUpdate(con, stream);
 
-   /*for (S32 i = 0; i < MaxScriptThreads; i++) 
+   for (S32 i = 0; i < MaxScriptThreads; i++) 
    {
       if (stream->readFlag()) 
       {
@@ -260,7 +260,7 @@ void AnimationComponent::unpackUpdate(NetConnection *con, BitStream *stream)
          else
             updateThread(st);
       }
-   }*/
+   }
 }
 
 void AnimationComponent::processTick()
@@ -613,6 +613,9 @@ void AnimationComponent::advanceThreads(F32 dt)
    if (!mOwnerRenderInst)
       return;
 
+   if (mOwnerShapeInstance == nullptr || !getShape())
+      return;
+
    for (U32 i = 0; i < MaxScriptThreads; i++)
    {
       Thread& st = mAnimationThreads[i];

+ 5 - 3
Engine/source/T3D/components/collision/collisionComponent.cpp

@@ -142,10 +142,12 @@ CollisionComponent::CollisionComponent() : Component()
       StaticShapeObjectType | VehicleObjectType |
       VehicleBlockerObjectType | DynamicShapeObjectType | StaticObjectType | EntityObjectType | TriggerObjectType);
 
-   mPhysicsRep = NULL;
-   mPhysicsWorld = NULL;
+   mPhysicsRep = nullptr;
+   mPhysicsWorld = nullptr;
 
-   mTimeoutList = NULL;
+   mTimeoutList = nullptr;
+
+   mAnimated = false;
 }
 
 CollisionComponent::~CollisionComponent()

+ 9 - 2
Engine/source/T3D/components/component.cpp

@@ -67,6 +67,13 @@ Component::Component()
    mOriginatingAssetId = StringTable->EmptyString();
 
    mIsServerObject = true;
+
+   componentIdx = 0;
+
+   mHidden = false;
+   mEnabled = true;
+
+   mDirtyMaskBits = 0;
 }
 
 Component::~Component()
@@ -535,7 +542,7 @@ const char * Component::getDescriptionText(const char *desc)
    if (desc == NULL)
       return NULL;
 
-   char *newDesc;
+   char *newDesc = "";
 
    // [tom, 1/12/2007] If it isn't a file, just do it the easy way
    if (!Platform::isFile(desc))
@@ -568,7 +575,7 @@ const char * Component::getDescriptionText(const char *desc)
    }
 
    str.close();
-   delete stream;
+   //delete stream;
 
    return newDesc;
 }

+ 4 - 0
Engine/source/T3D/components/game/stateMachine.cpp

@@ -30,6 +30,10 @@ StateMachine::StateMachine()
    mStartingState = "";
 
    mCurCreateState = NULL;
+
+   mStateMachineFile = StringTable->EmptyString();
+
+   mCurCreateState = nullptr;
 }
 
 StateMachine::~StateMachine()

+ 2 - 0
Engine/source/T3D/components/game/stateMachine.h

@@ -158,6 +158,8 @@ public:
    {
       if (index <= mFields.size())
          return mFields[index];
+
+      return StateField(); //return a blank one
    }
 
    Signal< void(StateMachine*, S32 stateIdx) > onStateChanged;

+ 5 - 2
Engine/source/T3D/components/physics/playerControllerComponent.cpp

@@ -119,8 +119,11 @@ PlayerControllerComponent::PlayerControllerComponent() : Component()
 
    mInputVelocity = Point3F(0, 0, 0);
 
-   mPhysicsRep = NULL;
-   mPhysicsWorld = NULL;
+   mPhysicsRep = nullptr;
+   mPhysicsWorld = nullptr;
+
+   mOwnerCollisionInterface = nullptr;
+   mIntegrationCount = 0;
 }
 
 PlayerControllerComponent::~PlayerControllerComponent()

+ 1 - 1
Engine/source/T3D/components/render/meshComponent.cpp

@@ -59,7 +59,7 @@ ImplementEnumType(BatchingMode,
 //////////////////////////////////////////////////////////////////////////
 // Constructor/Destructor
 //////////////////////////////////////////////////////////////////////////
-MeshComponent::MeshComponent() : Component()
+MeshComponent::MeshComponent() : Component(), mShape(nullptr), mRenderMode(Individual)
 {
    mFriendlyName = "Mesh Component";
    mComponentType = "Render";

+ 11 - 10
Engine/source/T3D/entity.cpp

@@ -850,7 +850,7 @@ void Entity::setTransform(const MatrixF &mat)
    }
 }
 
-void Entity::setTransform(Point3F position, RotationF rotation)
+void Entity::setTransform(const Point3F& position, const RotationF& rotation)
 {
    MatrixF oldTransform = getTransform();
 
@@ -922,7 +922,7 @@ void Entity::setRenderTransform(const MatrixF &mat)
    Parent::setRenderTransform(mat);
 }
 
-void Entity::setRenderTransform(Point3F position, RotationF rotation)
+void Entity::setRenderTransform(const Point3F& position, const RotationF& rotation)
 {
    if (isMounted())
    {
@@ -977,7 +977,7 @@ MatrixF Entity::getTransform()
    }
 }
 
-void Entity::setMountOffset(Point3F posOffset)
+void Entity::setMountOffset(const Point3F& posOffset)
 {
    if (isMounted())
    {
@@ -987,7 +987,7 @@ void Entity::setMountOffset(Point3F posOffset)
    }
 }
 
-void Entity::setMountRotation(EulerF rotOffset)
+void Entity::setMountRotation(const EulerF& rotOffset)
 {
    if (isMounted())
    {
@@ -1111,11 +1111,12 @@ bool Entity::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *
 
 bool Entity::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere)
 {
-   Vector<BuildPolyListInterface*> updaters = getComponents<BuildPolyListInterface>();
+   Con::errorf("Build Poly List not yet implemented as a passthrough for Entity");
+   /*Vector<BuildPolyListInterface*> updaters = getComponents<BuildPolyListInterface>();
    for (Vector<BuildPolyListInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
    {
       return (*it)->buildPolyList(context, polyList, box, sphere);
-   }
+   }*/
 
    return false;
 }
@@ -1131,7 +1132,7 @@ void Entity::buildConvex(const Box3F& box, Convex* convex)
 
 //
 // Mounting and heirarchy manipulation
-void Entity::mountObject(SceneObject* objB, MatrixF txfm)
+void Entity::mountObject(SceneObject* objB, const MatrixF& txfm)
 {
    Parent::mountObject(objB, -1, txfm);
    Parent::addObject(objB);
@@ -1604,7 +1605,7 @@ void Entity::onCameraScopeQuery(NetConnection* connection, CameraScopeQuery* que
    }
 }
 //
-void Entity::setObjectBox(Box3F objBox)
+void Entity::setObjectBox(const Box3F& objBox)
 {
    mObjBox = objBox;
    resetWorldBox();
@@ -1705,8 +1706,8 @@ void Entity::setComponentDirty(Component *comp, bool forceUpdate)
       }
    }
 
-   if (!found)
-      return;
+   //if (!found)
+   //   return;
 
    //if(mToLoadComponents.empty())
    //	mStartComponentUpdate = true;

+ 7 - 7
Engine/source/T3D/entity.h

@@ -152,14 +152,14 @@ public:
    virtual void setTransform(const MatrixF &mat);
    virtual void setRenderTransform(const MatrixF &mat);
 
-   void setTransform(Point3F position, RotationF rotation);
+   void setTransform(const Point3F& position, const RotationF& rotation);
 
-   void setRenderTransform(Point3F position, RotationF rotation);
+   void setRenderTransform(const Point3F& position, const RotationF& rotation);
 
    virtual MatrixF getTransform();
    virtual Point3F getPosition() const { return mPos; }
 
-   void setRotation(RotationF rotation) {
+   void setRotation(const RotationF& rotation) {
       mRot = rotation;
       setMaskBits(TransformMask);
    };
@@ -167,8 +167,8 @@ public:
 
    static bool _setGameObject(void *object, const char *index, const char *data);
 
-   void setMountOffset(Point3F posOffset);
-   void setMountRotation(EulerF rotOffset);
+   void setMountOffset(const Point3F& posOffset);
+   void setMountRotation(const EulerF& rotOffset);
 
    //static bool _setEulerRotation( void *object, const char *index, const char *data );
    static bool _setPosition(void *object, const char *index, const char *data);
@@ -181,7 +181,7 @@ public:
    virtual void getRenderMountTransform(F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat);
 
    virtual void mountObject(SceneObject *obj, S32 node, const MatrixF &xfm = MatrixF::Identity);
-   void mountObject(SceneObject* objB, MatrixF txfm);
+   void mountObject(SceneObject* objB, const MatrixF& txfm);
    void onMount(SceneObject *obj, S32 node);
    void onUnmount(SceneObject *obj, S32 node);
 
@@ -218,7 +218,7 @@ public:
       return mComponents.size(); 
    }
 
-   virtual void setObjectBox(Box3F objBox);
+   virtual void setObjectBox(const Box3F& objBox);
 
    void resetWorldBox() { Parent::resetWorldBox(); }
    void resetObjectBox() { Parent::resetObjectBox(); }

+ 5 - 2
Engine/source/T3D/systems/render/meshRenderSystem.cpp

@@ -11,6 +11,9 @@ Vector<MeshRenderSystem::BufferSet> MeshRenderSystem::mStaticBuffers(0);
 
 void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* state)
 {
+   if (sceneManager == nullptr || state == nullptr)
+      return;
+
    Frustum viewFrustum = state->getCullingFrustum();
    MatrixF camTransform = state->getCameraTransform();
 
@@ -129,7 +132,7 @@ void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* stat
 
          // We sort by the material then vertex buffer
          ri->defaultKey = matInst->getStateHint();
-         ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
+         ri->defaultKey2 = (uintptr_t)ri->vertBuff;
 
                                                     // Submit our RenderInst to the RenderPassManager
          state->getRenderPass()->addInst(ri);
@@ -372,4 +375,4 @@ U32 MeshRenderSystem::findBufferSetByMaterial(U32 matId)
    }
 
    return -1;
-}
+}

+ 10 - 1
Engine/source/console/consoleObject.cpp

@@ -37,6 +37,7 @@
 #include "console/engineTypes.h"
 #include "console/engineAPI.h"
 
+#include "sim/netObject.h"
 
 IMPLEMENT_SCOPE( ConsoleAPI, Console,,
    "Functionality related to the legacy TorqueScript console system." );
@@ -372,6 +373,7 @@ void ConsoleObject::addGroup(const char* in_pGroupname, const char* in_pGroupDoc
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
    f.writeDataFn = &defaultProtectedWriteFn;
+   f.networkMask  = 0;
 
    // Add to field list.
    sg_tempFieldList.push_back(f);
@@ -396,6 +398,7 @@ void ConsoleObject::endGroup(const char*  in_pGroupname)
    f.getDataFn    = &defaultProtectedGetFn;
    f.writeDataFn = &defaultProtectedWriteFn;
    f.elementCount = 0;
+   f.networkMask  = 0;
 
    // Add to field list.
    sg_tempFieldList.push_back(f);
@@ -418,6 +421,7 @@ void ConsoleObject::addArray( const char *arrayName, S32 count )
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
    f.writeDataFn = &defaultProtectedWriteFn;
+   f.networkMask = 0;
 
    // Add to field list.
    sg_tempFieldList.push_back(f);
@@ -439,6 +443,7 @@ void ConsoleObject::endArray( const char *arrayName )
    f.getDataFn    = &defaultProtectedGetFn;
    f.writeDataFn = &defaultProtectedWriteFn;
    f.elementCount = 0;
+   f.networkMask = 0;
 
    // Add to field list.
    sg_tempFieldList.push_back(f);
@@ -515,6 +520,7 @@ void ConsoleObject::addField(const char*  in_pFieldname,
    f.setDataFn = &defaultProtectedSetFn;
    f.getDataFn = &defaultProtectedGetFn;
    f.writeDataFn = in_writeDataFn;
+   f.networkMask = 0;
 
    ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
    AssertFatal(conType, "ConsoleObject::addField - invalid console type");
@@ -609,6 +615,7 @@ void ConsoleObject::addProtectedField(const char*  in_pFieldname,
    f.setDataFn = in_setDataFn;
    f.getDataFn = in_getDataFn;
    f.writeDataFn = in_writeDataFn;
+   f.networkMask = 0;
 
    ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
    AssertFatal(conType, "ConsoleObject::addProtectedField - invalid console type");
@@ -635,6 +642,7 @@ void ConsoleObject::addFieldV(const char*  in_pFieldname,
    f.getDataFn    = &defaultProtectedGetFn;
    f.writeDataFn = &defaultProtectedWriteFn;
    f.validator    = v;
+   f.networkMask = 0;
    v->fieldIndex  = sg_tempFieldList.size();
 
    sg_tempFieldList.push_back(f);
@@ -652,11 +660,12 @@ void ConsoleObject::addDeprecatedField(const char *fieldName)
    f.setDataFn    = &defaultProtectedSetFn;
    f.getDataFn    = &defaultProtectedGetFn;
    f.writeDataFn = &defaultProtectedWriteFn;
+   f.networkMask = 0;
 
    sg_tempFieldList.push_back(f);
 }
 
-
+//------------------------------------------------------------------
 bool ConsoleObject::removeField(const char* in_pFieldname)
 {
    for (U32 i = 0; i < sg_tempFieldList.size(); i++) {

+ 5 - 6
Engine/source/console/consoleObject.h

@@ -495,7 +495,8 @@ public:
             table( NULL ),
             validator( NULL ),
             setDataFn( NULL ),
-            getDataFn( NULL )
+            getDataFn( NULL ),
+            networkMask(0)
       {
          doNotSubstitute = keepClearSubsOnly = false;
       }
@@ -515,9 +516,11 @@ public:
       TypeValidator *validator;     ///< Validator, if any.
       SetDataNotify  setDataFn;     ///< Set data notify Fn
       GetDataNotify  getDataFn;     ///< Get data notify Fn
-	  WriteDataNotify writeDataFn;  ///< Function to determine whether data should be written or not.
+	    WriteDataNotify writeDataFn;  ///< Function to determine whether data should be written or not.
       bool           doNotSubstitute;
       bool           keepClearSubsOnly;
+
+      U32            networkMask;
    };
    typedef Vector<Field> FieldList;
 
@@ -1263,10 +1266,6 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
       EnginePropertyTable _propTable( sizeof( _props ) / sizeof( _props[ 0 ] ) - 1, _props );            \
    } }
 
-/// Add an auto-doc for a class.
-#define ConsoleDocClass( className, docString ) \
-   CLASSDOC( className, docString )
-
 /// @}
 
 //------------------------------------------------------------------------------

+ 1 - 1
Engine/source/console/engineTypes.h

@@ -576,7 +576,7 @@ namespace _Private {
    uintptr_t( ( ( const char* ) &( ( ( ThisType* ) 16 )->fieldName ) ) - 16 ) // Artificial offset to avoid compiler warnings.
    
 ///
-#define CLASSDOC( className, doc ) \
+#define ConsoleDocClass( className, doc ) \
    template<> const char* EngineClassTypeInfo< className, className::_ClassBase >::smDocString = doc;
    
 

+ 14 - 0
Engine/source/console/simObject.cpp

@@ -41,6 +41,8 @@
 #include "core/fileObject.h"
 #include "persistence/taml/tamlCustom.h"
 
+#include "sim/netObject.h"
+
 IMPLEMENT_CONOBJECT( SimObject );
 
 // See full description in the new CHM manual
@@ -912,6 +914,12 @@ void SimObject::assignFieldsFrom(SimObject *parent)
 
             if((*f->setDataFn)( this, NULL, bufferSecure ) )
                Con::setData(f->type, (void *) (((const char *)this) + f->offset), j, 1, &fieldVal, f->table);
+
+            if (f->networkMask != 0)
+            {
+               NetObject* netObj = static_cast<NetObject*>(this);
+               netObj->setMaskBits(f->networkMask);
+            }
          }
       }
    }
@@ -988,6 +996,12 @@ void SimObject::setDataField(StringTableEntry slotName, const char *array, const
             if(fld->validator)
                fld->validator->validateType(this, (void *) (((const char *)this) + fld->offset));
 
+            if (fld->networkMask != 0)
+            {
+               NetObject* netObj = static_cast<NetObject*>(this);
+               netObj->setMaskBits(fld->networkMask);
+            }
+
             onStaticModified( slotName, value );
 
             return;

+ 5 - 0
Engine/source/console/typeValidators.h

@@ -53,6 +53,8 @@ public:
       maxV = maxValue;
    }
    void validateType(SimObject *object, void *typePtr);
+   F32 getMin() { return minV; };
+   F32 getMax() { return maxV; };
 };
 
 /// Signed integer min/max range validator
@@ -66,6 +68,8 @@ public:
       maxV = maxValue;
    }
    void validateType(SimObject *object, void *typePtr);
+   F32 getMin() { return minV; };
+   F32 getMax() { return maxV; };
 };
 
 /// Scaled integer field validator
@@ -93,6 +97,7 @@ class Point3NormalizeValidator : public TypeValidator
 public:
    Point3NormalizeValidator(F32 normalizeLength = 1.0f) : length(normalizeLength) { }
    void validateType(SimObject *object, void *typePtr);
+   F32 getLength() { return length; };
 };
 
 namespace CommonValidators

+ 1 - 1
Engine/source/gfx/sim/cubemapData.cpp

@@ -111,7 +111,7 @@ void CubemapData::createMap()
           {
              if (!mCubeFaceFile[i].isEmpty())
              {
-                if (!mCubeFace[i].set(mCubeFaceFile[i], &GFXStaticTextureSRGBProfile, avar("%s() - mCubeFace[%d] (line %d)", __FUNCTION__, i, __LINE__)))
+                if (!mCubeFace[i].set(mCubeFaceFile[i], &GFXStaticTextureProfile, avar("%s() - mCubeFace[%d] (line %d)", __FUNCTION__, i, __LINE__)))
                 {
                    Con::errorf("CubemapData::createMap - Failed to load texture '%s'", mCubeFaceFile[i].c_str());
                    initSuccess = false;

+ 5 - 5
Engine/source/gui/buttons/guiBitmapButtonCtrl.cpp

@@ -307,22 +307,22 @@ void GuiBitmapButtonCtrl::setBitmap( const String& name )
             if( mUseModifiers )
                baseName += modifiers[ i ];
 
-            mTextures[ i ].mTextureNormal = GFXTexHandle( baseName, &GFXTexturePersistentSRGBProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__));
+            mTextures[ i ].mTextureNormal = GFXTexHandle( baseName, &GFXDefaultGUIProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__));
             
             if( mUseStates )
             {
                if( !mTextures[ i ].mTextureNormal )
-                  mTextures[ i ].mTextureNormal = GFXTexHandle( baseName + s_n, &GFXTexturePersistentSRGBProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__));
+                  mTextures[ i ].mTextureNormal = GFXTexHandle( baseName + s_n, &GFXDefaultGUIProfile, avar("%s() - mTextureNormal (line %d)", __FUNCTION__, __LINE__));
                
-               mTextures[ i ].mTextureHilight = GFXTexHandle( baseName + s_h, &GFXTexturePersistentSRGBProfile, avar("%s() - mTextureHighlight (line %d)", __FUNCTION__, __LINE__));
+               mTextures[ i ].mTextureHilight = GFXTexHandle( baseName + s_h, &GFXDefaultGUIProfile, avar("%s() - mTextureHighlight (line %d)", __FUNCTION__, __LINE__));
                if( !mTextures[ i ].mTextureHilight )
                   mTextures[ i ].mTextureHilight = mTextures[ i ].mTextureNormal;
                   
-               mTextures[ i ].mTextureDepressed = GFXTexHandle( baseName + s_d, &GFXTexturePersistentSRGBProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__));
+               mTextures[ i ].mTextureDepressed = GFXTexHandle( baseName + s_d, &GFXDefaultGUIProfile, avar("%s() - mTextureDepressed (line %d)", __FUNCTION__, __LINE__));
                if( !mTextures[ i ].mTextureDepressed )
                   mTextures[ i ].mTextureDepressed = mTextures[ i ].mTextureHilight;
 
-               mTextures[ i ].mTextureInactive = GFXTexHandle( baseName + s_i, &GFXTexturePersistentSRGBProfile, avar("%s() - mTextureInactive (line %d)", __FUNCTION__, __LINE__));
+               mTextures[ i ].mTextureInactive = GFXTexHandle( baseName + s_i, &GFXDefaultGUIProfile, avar("%s() - mTextureInactive (line %d)", __FUNCTION__, __LINE__));
                if( !mTextures[ i ].mTextureInactive )
                   mTextures[ i ].mTextureInactive = mTextures[ i ].mTextureNormal;
             }

+ 15 - 8
Engine/source/gui/core/guiCanvas.cpp

@@ -133,7 +133,8 @@ GuiCanvas::GuiCanvas(): GuiControl(),
                         mLastRenderMs(0),
                         mPlatformWindow(NULL),
                         mDisplayWindow(true),
-                        mMenuBarCtrl(NULL)
+                        mMenuBarCtrl(nullptr),
+                        mMenuBackground(nullptr)
 {
    setBounds(0, 0, 640, 480);
    mAwake = true;
@@ -296,8 +297,11 @@ void GuiCanvas::setMenuBar(SimObject *obj)
     mMenuBarCtrl = dynamic_cast<GuiControl*>(obj);
 
     //remove old menubar
-    if( oldMenuBar )
-        Parent::removeObject( oldMenuBar );
+    if (oldMenuBar)
+    {
+        Parent::removeObject(oldMenuBar);
+        Parent::removeObject(mMenuBackground); //also remove the modeless wrapper
+    }
 
     // set new menubar    
     if (mMenuBarCtrl)
@@ -312,14 +316,17 @@ void GuiCanvas::setMenuBar(SimObject *obj)
           return;
        }
 
-       GuiControl* menuBackground = new GuiControl();
-       menuBackground->registerObject();
+       if (mMenuBackground == nullptr)
+       {
+           mMenuBackground = new GuiControl();
+           mMenuBackground->registerObject();
 
-       menuBackground->setControlProfile(profile);
+           mMenuBackground->setControlProfile(profile);
+       }
 
-       menuBackground->addObject(mMenuBarCtrl);
+       mMenuBackground->addObject(mMenuBarCtrl);
 
-       Parent::addObject(menuBackground);
+       Parent::addObject(mMenuBackground);
     }
 
     // update window accelerator keys

+ 1 - 0
Engine/source/gui/core/guiCanvas.h

@@ -198,6 +198,7 @@ protected:
 	static CanvasSizeChangeSignal smCanvasSizeChangeSignal;
 
    GuiControl *mMenuBarCtrl;
+   GuiControl* mMenuBackground;
 
 public:
    DECLARE_CONOBJECT(GuiCanvas);

+ 3 - 2
Engine/source/gui/editor/guiMenuBar.cpp

@@ -1519,9 +1519,10 @@ DefineConsoleMethod(GuiMenuBar, insert, void, (SimObject* pObject, S32 pos), (nu
    object->insert(pObject, pos);
 }
 
-DefineConsoleMethod(GuiMenuBar, findMenu, S32, (StringTableEntry barTitle), (""), "(barTitle)")
+DefineConsoleMethod(GuiMenuBar, findMenu, S32, (const char* barTitle), (""), "(barTitle)")
 {
-   PopupMenu* menu = object->findMenu(barTitle);
+   StringTableEntry barTitleStr = StringTable->insert(barTitle);
+   PopupMenu* menu = object->findMenu(barTitleStr);
 
    if (menu)
       return menu->getId();

+ 2 - 1
Engine/source/gui/editor/inspector/entityGroup.cpp

@@ -70,7 +70,8 @@ bool GuiInspectorEntityGroup::inspectGroup()
    {
       Entity* target = dynamic_cast<Entity*>(mParent->getInspectObject(0));
 
-      Con::executef(this, "inspectObject", target->getIdString());
+      if(target)
+         Con::executef(this, "inspectObject", target->getIdString());
    }
 
    return true;

+ 1 - 1
Engine/source/materials/processedMaterial.cpp

@@ -456,7 +456,7 @@ void ProcessedMaterial::_setStageData()
       // SpecularMap
       if( mMaterial->mSpecularMapFilename[i].isNotEmpty() )
       {
-         mStages[i].setTex( MFT_SpecularMap, _createTexture( mMaterial->mSpecularMapFilename[i], &GFXStaticTextureProfile) );
+         mStages[i].setTex( MFT_SpecularMap, _createTexture( mMaterial->mSpecularMapFilename[i], &GFXStaticTextureSRGBProfile) );
          if(!mStages[i].getTex( MFT_SpecularMap ))
             mMaterial->logError("Failed to load specular map %s for stage %i", _getTexturePath(mMaterial->mSpecularMapFilename[i]).c_str(), i);
       }

+ 23 - 0
Engine/source/math/mConsoleFunctions.cpp

@@ -288,6 +288,29 @@ DefineConsoleFunction( mSaturate, F32, ( F32 v ),,
    return mClampF( v, 0.0f, 1.0f );
 }
 
+DefineConsoleFunction(mWrapF, F32, (F32 v, F32 min, F32 max), ,
+	"Wrap the specified value between two bounds.\n"
+	"@param v Input value."
+	"@param min Minimum Bound."
+	"@param max Maximum Bound."
+	"@returns The specified value wrapped to the specified bounds."
+	"@ingroup Math")
+{
+	return mWrapF(v, min, max);
+}
+
+DefineConsoleFunction(mWrap, S32, (S32 v, S32 min, S32 max), ,
+	"Wrap the specified value between two bounds.\n"
+	"@param v Input value."
+	"@param min Minimum Bound."
+	"@param max Maximum Bound."
+	"@returns The specified value wrapped to the specified bounds."
+	"@ingroup Math")
+{
+	return mWrap(v, min, max);
+}
+
+
 DefineConsoleFunction( getMax, F32, ( F32 v1, F32 v2 ),,
     "Calculate the greater of two specified numbers.\n"
     "@param v1 Input value."

+ 13 - 0
Engine/source/math/mMathFn.h

@@ -237,6 +237,19 @@ inline F32 mClampF(F32 val, F32 low, F32 high)
    return (F32) getMax(getMin(val, high), low);
 }
 
+inline S32 mWrap(S32 val, S32 low, S32 high)
+{
+	int len = high - low;
+	return low + (val >= 0 ? val % len : -val % len ? len - (-val % len) : 0);
+
+}
+
+inline F32 mWrapF(F32 val, F32 low, F32 high)
+{
+	F32 t = fmod(val - low, high - low);
+	return t < 0 ? t + high : t + low;
+}
+
 /// Template function for doing a linear interpolation between any two
 /// types which implement operators for scalar multiply and addition.
 template <typename T>

+ 225 - 5
Engine/source/sim/actionMap.cpp

@@ -269,7 +269,13 @@ void ActionMap::dumpActionMap(const char* fileName, const bool append) const
             if (getKeyString(rNode.action, objectbuffer) == false)
                continue;
 
-            const char* command = (rNode.flags & Node::BindCmd) ? "bindCmd" : "bind";
+            const char* command;
+            if (rNode.flags & Node::BindCmd)
+               command = "bindCmd";
+            else if (rNode.flags & Node::Held)
+               command = "held";
+            else
+               command = "bind";
 
             dSprintf(lineBuffer, 1023, "%s.%s(%s, \"%s%s\"",
                                         getName(),
@@ -324,7 +330,16 @@ void ActionMap::dumpActionMap(const char* fileName, const bool append) const
                }
                else
                   dStrcat(lineBuffer, ", \"\"");
-            } else {
+            }
+            else if (rNode.flags & Node::Held) 
+            {
+               dStrcat(lineBuffer, ", ");
+               dStrcat(lineBuffer, rNode.consoleFunction);
+
+               dStrcat(lineBuffer, ", ");
+               dStrcat(lineBuffer, rNode.contextEvent->mConsoleFunctionHeld);
+            } 
+            else {
                dStrcat(lineBuffer, ", ");
                dStrcat(lineBuffer, rNode.consoleFunction);
             }
@@ -353,7 +368,13 @@ void ActionMap::dumpActionMap(const char* fileName, const bool append) const
             if (getKeyString(rNode.action, keybuffer) == false)
                continue;
 
-            const char* command = (rNode.flags & Node::BindCmd) ? "bindCmd" : "bind";
+            const char* command;
+            if (rNode.flags & Node::BindCmd)
+               command = "bindCmd";
+            else if (rNode.flags & Node::Held)
+               command = "held";
+            else
+               command = "bind";
 
             char finalBuffer[1024];
             dSprintf(finalBuffer, 1023, "%s.%s(%s, \"%s%s\"",
@@ -407,7 +428,16 @@ void ActionMap::dumpActionMap(const char* fileName, const bool append) const
                }
                else
                   dStrcat(finalBuffer, ", \"\"");
-            } else {
+            }
+            else if (rNode.flags & Node::Held)
+            {
+               dStrcat(finalBuffer, ", ");
+               dStrcat(finalBuffer, rNode.consoleFunction);
+
+               dStrcat(finalBuffer, ", ");
+               dStrcat(finalBuffer, rNode.contextEvent->mConsoleFunctionHeld);
+            } 
+            else {
                dStrcat(finalBuffer, ", ");
                dStrcat(finalBuffer, rNode.consoleFunction);
             }
@@ -794,6 +824,17 @@ const char* ActionMap::getCommand( const char* device, const char* action )
                      ( mapNode->breakConsoleCommand ? mapNode->breakConsoleCommand : "" ) );             
                return( returnString );
             }              
+            if (mapNode->flags & Node::Held)
+            {
+               S32 bufferLen = dStrlen(mapNode->consoleFunction) + dStrlen(mapNode->contextEvent->mConsoleFunctionHeld) + 2;
+               char* returnString = Con::getReturnBuffer(bufferLen);
+
+               dSprintf(returnString, bufferLen, "%st%s",
+                  (mapNode->consoleFunction ? mapNode->consoleFunction : ""),
+                  (mapNode->contextEvent->mConsoleFunctionHeld ? mapNode->contextEvent->mConsoleFunctionHeld : ""));
+
+               return(returnString);
+            }
             else
                return( mapNode->consoleFunction );             
          }
@@ -1310,6 +1351,76 @@ bool ActionMap::processBind(const U32 argc, const char** argv, SimObject* object
    return true;
 }
 
+//------------------------------------------------------------------------------
+bool ActionMap::processHoldBind(const char *device, const char *action, const char *holdFunc, const char *tapFunc, const U32 holdTime, const bool holdOnly, const bool retHoldTime)
+{
+   U32 deviceType;
+   U32 deviceInst;
+
+   if (!getDeviceTypeAndInstance(device, deviceType, deviceInst))
+   {
+      Con::printf("processBindCmd: unknown device: %s", device);
+      return false;
+   }
+
+   // Ok, we now have the deviceType and instance.  Create an event descriptor  
+   //  for the bind...  
+   //  
+   EventDescriptor eventDescriptor;
+   if (createEventDescriptor(action, &eventDescriptor) == false) {
+      Con::printf("Could not create a description for binding: %s", action);
+      return false;
+   }
+
+   // SI_POV == SI_MOVE, and the POV works fine with bindCmd, so we have to add these manually.  
+   if ((eventDescriptor.eventCode == SI_XAXIS) ||
+      (eventDescriptor.eventCode == SI_YAXIS) ||
+      (eventDescriptor.eventCode == SI_ZAXIS) ||
+      (eventDescriptor.eventCode == SI_RXAXIS) ||
+      (eventDescriptor.eventCode == SI_RYAXIS) ||
+      (eventDescriptor.eventCode == SI_RZAXIS) ||
+      (eventDescriptor.eventCode == SI_SLIDER) ||
+      (eventDescriptor.eventCode == SI_XPOV) ||
+      (eventDescriptor.eventCode == SI_YPOV) ||
+      (eventDescriptor.eventCode == SI_XPOV2) ||
+      (eventDescriptor.eventCode == SI_YPOV2))
+   {
+      Con::warnf("ActionMap::processBindCmd - Cannot use 'bindCmd' with a move event type. Use 'bind' instead.");
+      return false;
+   }
+
+   // Event has now been described, and device determined.  we need now to extract  
+   //  any modifiers that the action map will apply to incoming events before  
+   //  calling the bound function...  
+   //  
+   // DMMTODO  
+   F32 deadZoneBegin = 0.0f;
+   F32 deadZoneEnd = 0.0f;
+   F32 scaleFactor = 1.0f;
+
+   // Ensure that the console function is properly specified?  
+   //  
+   // DMMTODO  
+
+   // Create the full bind entry, and place it in the map  
+   //  
+   // DMMTODO  
+   Node* pBindNode = getNode(deviceType, deviceInst,
+      eventDescriptor.flags,
+      eventDescriptor.eventCode);
+
+   pBindNode->flags = Node::Held;
+   pBindNode->deadZoneBegin = deadZoneBegin;
+   pBindNode->deadZoneEnd = deadZoneEnd;
+   pBindNode->scaleFactor = scaleFactor;
+   pBindNode->consoleFunction = StringTable->insert(dStrdup(tapFunc));
+
+   pBindNode->contextEvent = new ContextAction(StringTable->insert(dStrdup(holdFunc)), holdTime, pBindNode, holdOnly);
+   pBindNode->contextEvent->mReturnHoldTime = retHoldTime;
+
+   return true;
+}
+
 //------------------------------------------------------------------------------
 bool ActionMap::processAction(const InputEventInfo* pEvent)
 {
@@ -1328,7 +1439,9 @@ bool ActionMap::processAction(const InputEventInfo* pEvent)
       // Enter the break into the table if this is a make event...
       // Do this now rather than after command is processed because
       // command might add a binding which can move the vector of nodes.
-      enterBreakEvent(pEvent, pNode);
+      // Filter to prevent Hold buttons from being eaten  
+      if (!(pNode->flags & Node::Held))
+         enterBreakEvent(pEvent, pNode);
 
       // Whadda ya know, we have this bound.  Set up, and call the console
       //  function associated with it...
@@ -1369,6 +1482,15 @@ bool ActionMap::processAction(const InputEventInfo* pEvent)
          if(pNode->makeConsoleCommand)
             Con::evaluate(pNode->makeConsoleCommand);
       }
+      else if (pNode->flags & Node::Held)
+      {
+         //check if we're already holding, if not, start our timer  
+         if (!pNode->contextEvent->mActive) {
+            pNode->contextEvent->mActive = true;
+            pNode->contextEvent->mStartTime = Sim::getCurrentTime();
+            pNode->contextEvent->mEventValue = value;
+         }
+      }
       else if ( pNode->consoleFunction[0] )
       {
          argv[0] = pNode->consoleFunction;
@@ -1529,6 +1651,20 @@ bool ActionMap::processAction(const InputEventInfo* pEvent)
    }
    else if (pEvent->action == SI_BREAK)
    {
+      const Node* button = findNode(pEvent->deviceType, pEvent->deviceInst,
+         pEvent->modifier, pEvent->objInst);
+
+      if (button != NULL) 
+      {
+         if (button->flags == Node::Held)
+         {
+            if (!button->contextEvent->mBreakEvent)
+               button->contextEvent->mBreakEvent = true;
+
+            return true;
+         }
+      }
+
       return checkBreakTable(pEvent);
    }
    else if (pEvent->action == SI_VALUE)
@@ -1808,6 +1944,78 @@ void ActionMap::fireBreakEvent( U32 i, F32 fValue )
    smBreakTable.erase(i);
 }
 
+//------------------------------------------------------------------------------
+//Context actions
+ContextAction::ContextAction(StringTableEntry func, F32 minHoldTime, ActionMap::Node* button, bool holdOnly)
+   : mStartTime(0), mEventValue(1.0f), mBreakEvent(false), mDidHold(false), mActive(false), mReturnHoldTime(false)
+{
+   mButton = button;
+   mMinHoldTime = minHoldTime;
+   mConsoleFunctionHeld = func;
+
+   mHoldOnly = holdOnly;
+}
+
+void ContextAction::processTick()
+{
+   if (mActive)
+   {
+      F32 currTime = Sim::getCurrentTime();
+      static const char *argv[2];
+
+      //see if this key even is still active  
+      if (!mBreakEvent)
+      {
+         //are we only checking if it's holding?  
+         if (mHoldOnly)
+         {
+            //yes, we are, and since it's held, we fire off our function  
+            if (mReturnHoldTime)
+            {
+               argv[0] = mConsoleFunctionHeld;
+               argv[1] = Con::getFloatArg(mEventValue);
+               argv[2] = Con::getFloatArg((currTime - mStartTime));
+               Con::execute(3, argv);
+            }
+            else
+            {
+               argv[0] = mConsoleFunctionHeld;
+               argv[1] = Con::getFloatArg(mEventValue);
+               Con::execute(2, argv);
+            }
+         }
+         //if we don't care if we're just holding, check our time  
+         //have we passed our min limit?  
+         else if ((currTime - mStartTime) >= mMinHoldTime)
+         {
+            //holy crap, we have, fire off our hold function   
+            mDidHold = true;
+            argv[0] = mConsoleFunctionHeld;
+            argv[1] = Con::getFloatArg(mEventValue);
+            Con::execute(2, argv);
+         }
+         //otherwise we haven't yet, so keep our active status  
+         return;
+      }
+      //hmm, apparently not, so see if we tapped the key instead  
+      else
+      {
+         if (!mHoldOnly && !mDidHold)
+         {
+            //yes, we tapped and we care, so fire off the tap function.  
+            argv[0] = mButton->consoleFunction;
+            argv[1] = Con::getFloatArg(mEventValue);
+            Con::execute(2, argv);
+         }
+         //otherwise we don't care and we're done, so reset everything  
+         mActive = false;
+         mStartTime = 0;
+         mBreakEvent = false;
+         mDidHold = false;
+      }
+   }
+}
+
 //------------------------------------------------------------------------------
 
 // Console interop version.
@@ -1959,6 +2167,18 @@ DefineEngineMethod( ActionMap, bindCmd, bool, ( const char* device, const char*
    return object->processBindCmd( device, action, makeCmd, breakCmd );
 }
 
+DefineEngineMethod(ActionMap, bindContext, void, (const char* device, const char* action, const char* holdFunction, const char* tapFunction, U32 holdTime),
+   ("", "", "", "", 0), "actionMap.bindCmd( device, action, holdFunction, tapFunction, holdTime)")
+{
+   object->processHoldBind(device, action, holdFunction, tapFunction, holdTime, false);
+}
+
+DefineEngineMethod(ActionMap, bindHold, void, (const char* device, const char* action, const char* holdFunction, bool returnHoldTime),
+   ("", "", "", false), "actionMap.bindCmd( device, action, holdFunction, returnHoldTime)")
+{
+   object->processHoldBind(device, action, holdFunction, "", 0, true, returnHoldTime);
+}
+
 DefineEngineMethod( ActionMap, unbind, bool, ( const char* device, const char* action ),,
    "@brief Removes the binding on an input device and action.\n"
    "@param device The device to unbind from. Can be a keyboard, mouse, joystick or a gamepad.\n"

+ 34 - 1
Engine/source/sim/actionMap.h

@@ -32,7 +32,11 @@
 #ifndef _SIMBASE_H_
 #include "console/simBase.h"
 #endif
+#ifndef _ITICKABLE_H_  
+#include "core/iTickable.h"  
+#endif  
 
+class ContextAction;
 struct InputEventInfo;
 
 struct EventDescriptor
@@ -48,6 +52,7 @@ struct EventDescriptor
 class ActionMap : public SimObject
 {
    typedef SimObject Parent;
+   friend class ContextAction;
 
   protected:
    bool onAdd();
@@ -62,7 +67,9 @@ class ActionMap : public SimObject
          HasDeadZone = BIT(2),   ///< Dead zone is present.
          Inverted    = BIT(3),   ///< Input is inverted.
          NonLinear   = BIT(4),   ///< Input should be re-fit to a non-linear scale
-         BindCmd     = BIT(5)    ///< Bind a console command to this.
+         BindCmd     = BIT(5),    ///< Bind a console command to this.
+         Held        = BIT(6),
+         DoubleTap   = BIT(7)
       };
 
       U32 flags;           ///< @see Node::Flags
@@ -75,6 +82,7 @@ class ActionMap : public SimObject
 
       char *makeConsoleCommand;         ///< Console command to execute when we make this command.
       char *breakConsoleCommand;        ///< Console command to execute when we break this command.
+      ContextAction* contextEvent;      ///< Event that kicks off via context-keybind actions such as holding or double-tapping
    };
 
    /// Used to represent a devices.
@@ -143,6 +151,7 @@ class ActionMap : public SimObject
    bool processBind(const U32 argc, const char** argv, SimObject* object = NULL);
    bool processBindCmd(const char *device, const char *action, const char *makeCmd, const char *breakCmd);
    bool processUnbind(const char *device, const char *action, SimObject* object = NULL);
+   bool processHoldBind(const char *device, const char *action, const char *holdFunc, const char *tapFunc, const U32 holdTime, const bool holdOnly, const bool returnHoldTime = false);
 
    /// @name Console Interface Functions
    /// @{
@@ -185,4 +194,28 @@ class ActionMap : public SimObject
    DECLARE_CONOBJECT(ActionMap);
 };
 
+class ContextAction : public ITickable
+{
+   ActionMap::Node* mButton;                   ///< our button we're holding  
+   F32 mMinHoldTime;                   ///< minimum time to qualify as 'held'. If we hold less than this,   
+                                       ///< it's a 'press', otherwise it's a 'held'  
+public:
+   F32 mStartTime;                      ///< Our timestamp when we first pressed.  
+   F32 mEventValue;                    ///< Event value from our key event.  
+   StringTableEntry mConsoleFunctionHeld; ///< Console function to call with new values if we held over  
+                                         ///< a certain time.  
+
+   bool mHoldOnly;                     ///< does this only care if we're holding?     
+                                       ///< true means that it only fires a function while holding  
+                                       ///< false time-contexts it  
+   bool mBreakEvent;                    ///< Button is no longer being pressed!  
+   bool mDidHold;                       ///< did we, at some point in the process, hold the button?  
+   bool mActive;                        ///< do we be tickin?  
+   bool mReturnHoldTime;                ///< Do we return back our time held?  
+
+   ContextAction(StringTableEntry func, F32 minHoldTime, ActionMap::Node* button, bool holdOnly);
+   virtual void processTick();
+   virtual void interpolateTick(F32 delta) {}   
+   virtual void advanceTime(F32 timeDelta) {}
+};
 #endif // _ACTIONMAP_H_

+ 90 - 0
Engine/source/sim/netObject.cpp

@@ -500,6 +500,96 @@ void NetObject::removeScopeRef()
 }
 #endif
 
+//Networked fields
+//------------------------------------------------------------------
+void NetObject::addNetworkedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   const char* in_pFieldDocs,
+   U32 flags,
+   U32 networkMask)
+{
+   addNetworkedField(
+      in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      1,
+      in_pFieldDocs,
+      flags,
+      networkMask);
+}
+
+void NetObject::addNetworkedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::WriteDataNotify in_writeDataFn,
+   const char* in_pFieldDocs,
+   U32 flags,
+   U32 networkMask)
+{
+   addNetworkedField(
+      in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      in_writeDataFn,
+      1,
+      in_pFieldDocs,
+      flags,
+      networkMask);
+}
+
+void NetObject::addNetworkedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   const U32 in_elementCount,
+   const char* in_pFieldDocs,
+   U32 flags,
+   U32 networkMask)
+{
+   addNetworkedField(in_pFieldname,
+      in_fieldType,
+      in_fieldOffset,
+      &defaultProtectedWriteFn,
+      in_elementCount,
+      in_pFieldDocs,
+      flags,
+      networkMask);
+}
+
+void NetObject::addNetworkedField(const char*  in_pFieldname,
+   const U32 in_fieldType,
+   const dsize_t in_fieldOffset,
+   AbstractClassRep::WriteDataNotify in_writeDataFn,
+   const U32 in_elementCount,
+   const char* in_pFieldDocs,
+   U32 flags,
+   U32 networkMask)
+{
+   AbstractClassRep::Field f;
+   f.pFieldname = StringTable->insert(in_pFieldname);
+
+   if (in_pFieldDocs)
+      f.pFieldDocs = in_pFieldDocs;
+
+   f.type = in_fieldType;
+   f.offset = in_fieldOffset;
+   f.elementCount = in_elementCount;
+   f.validator = NULL;
+   f.flag = flags;
+
+   f.setDataFn = &defaultProtectedSetFn;
+   f.getDataFn = &defaultProtectedGetFn;
+   f.writeDataFn = in_writeDataFn;
+
+   f.networkMask = networkMask;
+
+   ConsoleBaseType* conType = ConsoleBaseType::getType(in_fieldType);
+   AssertFatal(conType, "ConsoleObject::addField - invalid console type");
+   f.table = conType->getEnumTable();
+
+   sg_tempFieldList.push_back(f);
+}
+
 DefineEngineMethod(NetObject, clearScopeAlways, void, (), ,
    "@brief Clears the scope always flag on this object.\n\n")
 {

+ 51 - 0
Engine/source/sim/netObject.h

@@ -422,6 +422,57 @@ public:
    void          removeScopeRef();
    void          setScopeRegistered(bool flag) { scope_registered = flag; }
    bool          getScopeRegistered() const { return scope_registered; }
+
+protected:
+   /// Add a networked field
+   ///
+   /// A networked field is a regular field but with a bitmask flag associated to it.
+   /// When the field is set, it automatically triggers a call to setMaskBits with the mask associated to the field
+   /// in order to streamline simple networking code
+   /// Register a complex field.
+   ///
+   /// @param  in_pFieldname     Name of the field.
+   /// @param  in_fieldType      Type of the field. @see ConsoleDynamicTypes
+   /// @param  in_fieldOffset    Offset to  the field from the start of the class; calculated using the Offset() macro.
+   /// @param  in_elementCount   Number of elements in this field. Arrays of elements are assumed to be contiguous in memory.
+   /// @param  in_pFieldDocs     Usage string for this field. @see console_autodoc
+   static void addNetworkedField(const char*   in_pFieldname,
+      const U32     in_fieldType,
+      const dsize_t in_fieldOffset,
+      const U32     in_elementCount = 1,
+      const char*   in_pFieldDocs = NULL,
+      U32 flags = 0,
+      U32 networkMask = 0);
+
+   static void addNetworkedField(const char*   in_pFieldname,
+      const U32     in_fieldType,
+      const dsize_t in_fieldOffset,
+      AbstractClassRep::WriteDataNotify in_writeDataFn,
+      const U32     in_elementCount = 1,
+      const char*   in_pFieldDocs = NULL,
+      U32 flags = 0,
+      U32 networkMask = 0);
+
+   /// Register a simple field.
+   ///
+   /// @param  in_pFieldname  Name of the field.
+   /// @param  in_fieldType   Type of the field. @see ConsoleDynamicTypes
+   /// @param  in_fieldOffset Offset to  the field from the start of the class; calculated using the Offset() macro.
+   /// @param  in_pFieldDocs  Usage string for this field. @see console_autodoc
+   static void addNetworkedField(const char*   in_pFieldname,
+      const U32     in_fieldType,
+      const dsize_t in_fieldOffset,
+      const char*   in_pFieldDocs,
+      U32 flags = 0,
+      U32 networkMask = 0);
+
+   static void addNetworkedField(const char*   in_pFieldname,
+      const U32     in_fieldType,
+      const dsize_t in_fieldOffset,
+      AbstractClassRep::WriteDataNotify in_writeDataFn,
+      const char*   in_pFieldDocs,
+      U32 flags = 0,
+      U32 networkMask = 0);
 };
 
 //-----------------------------------------------------------------------------

+ 12 - 1
Engine/source/ts/collada/colladaImport.cpp

@@ -198,7 +198,7 @@ DefineConsoleFunction( enumColladaForImport, bool, (const char * shapePath, cons
       for (S32 j = 0; j < libraryMats->getMaterial_array().getCount(); j++)
       {
          domMaterial* mat = libraryMats->getMaterial_array()[j];
-         tree->insertItem(matsID, _GetNameOrId(mat), _GetNameOrId(mat), "", 0, 0);
+         tree->insertItem(matsID, _GetNameOrId(mat), "", "", 0, 0);
       }
    }
 
@@ -256,5 +256,16 @@ DefineConsoleFunction( enumColladaForImport, bool, (const char * shapePath, cons
    else
       tree->setDataField(StringTable->insert("_upAxis"), 0, "Z_AXIS");
 
+   char shapesStr[16];
+   dSprintf(shapesStr, 16, "%i", stats.numMeshes);
+   char materialsStr[16];
+   dSprintf(materialsStr, 16, "%i", stats.numMaterials);
+   char animationsStr[16];
+   dSprintf(animationsStr, 16, "%i", stats.numClips);
+
+   tree->setItemValue(nodesID, StringTable->insert(shapesStr));
+   tree->setItemValue(matsID, StringTable->insert(materialsStr));
+   tree->setItemValue(animsID, StringTable->insert(animationsStr));
+
    return true;
 }

+ 0 - 7
Templates/BaseGame/game/tools/base/images/sky_skybox.dml

@@ -1,7 +0,0 @@
-skybox_1
-skybox_2
-skybox_3
-skybox_4
-skybox_5
-skybox_6
-skybox_6

+ 7 - 3
Templates/BaseGame/game/tools/shapeEditor/scripts/shapeEditorActions.ed.cs

@@ -346,10 +346,11 @@ function ActionAddSequence::doit( %this )
       %assetDef = AssetDatabase.acquireAsset(%this.seqName);
       %moduleName = getWord(getToken(%this.seqName, ":", 0),0);
       
-      %idx = ShapeEdSequenceList.rowCount();
+      //TODO, properly ignore <rootpose> and ambient entries for our idx values, but only if they're there!
+      %idx = ShapeEdSequenceList.rowCount() - 2;
       
-      %matSet = "ShapeEditorPlugin.selectedAssetDef.animationSequence"@%idx@"=\"@Asset="@%moduleName@":"@%this.seqName.assetName@"\";";
-      eval(%matSet);
+      %animSet = "ShapeEditorPlugin.selectedAssetDef.animationSequence"@%idx@"=\"@Asset="@%moduleName@":"@%assetDef.assetName@"\";";
+      eval(%animSet);
       
       %assetPath = AssetDatabase.getAssetFilePath(ShapeEditorPlugin.selectedAssetId);
       
@@ -357,6 +358,9 @@ function ActionAddSequence::doit( %this )
       
       AssetDatabase.refreshAsset(ShapeEditorPlugin.selectedAssetId);
       
+      //force a refresh
+      ShapeEdPropWindow.update_onShapeSelectionChanged();
+      
       return true;
    }
    return false;

+ 1 - 2
Templates/BaseGame/game/tools/worldEditor/scripts/editorPrefs.ed.cs

@@ -34,7 +34,6 @@ EditorSettings.setDefaultValue(  "orthoFOV",                "50" );
 EditorSettings.setDefaultValue(  "orthoShowGrid",           "1" );
 EditorSettings.setDefaultValue(  "currentEditor",           "WorldEditorInspectorPlugin" );
 EditorSettings.setDefaultValue(  "newLevelFile",            "tools/levels/BlankRoom.mis" );
-EditorSettings.setDefaultValue(  "newGameObjectDir",        "scripts/server/gameObjects" );
 
 if( isFile( "C:/Program Files/Torsion/Torsion.exe" ) )
    EditorSettings.setDefaultValue(  "torsionPath",          "C:/Program Files/Torsion/Torsion.exe" );
@@ -128,7 +127,7 @@ EditorSettings.setDefaultValue(  "renderInfoText",          "1"               );
 
 EditorSettings.beginGroup( "Grid" );
 EditorSettings.setDefaultValue(  "gridColor",               "255 255 255 20"  );
-EditorSettings.setDefaultValue(  "gridSize",                "10 10 10"        );
+EditorSettings.setDefaultValue(  "gridSize",                "1 1 1"        );
 EditorSettings.setDefaultValue(  "snapToGrid",              "0"               ); //<-- Not currently used
 EditorSettings.setDefaultValue(  "renderPlane",             "0"               );
 EditorSettings.setDefaultValue(  "renderPlaneHashes",       "0"               );

+ 0 - 46
Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs

@@ -304,36 +304,6 @@ function EWCreatorWindow::navigate( %this, %address )
                %this.addShapeIcon( %obj );
          }
       }
-      
-      //Add a separate folder for Game Objects
-      if(isClass("Entity"))
-      {
-          if(%address $= "")
-          {
-              %this.addFolderIcon("GameObjects");
-          }
-          else
-          {
-              //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);
-
-                 %gameObjectAsset = AssetDatabase.acquireAsset(%assetId);
-
-                 if(isFile(%gameObjectAsset.TAMLFilePath))
-                 {
-                    %this.addGameObjectIcon( %gameObjectAsset.gameObjectName );
-                 }
-              }
-          }
-      }
    }
    
    if ( %this.tab $= "Meshes" )
@@ -768,22 +738,6 @@ function EWCreatorWindow::addPrefabIcon( %this, %fullPath )
    %this.contentCtrl.addGuiControl( %ctrl );   
 }
 
-function EWCreatorWindow::addGameObjectIcon( %this, %gameObjectName )
-{
-   %ctrl = %this.createIcon();
-
-   %ctrl.altCommand = "spawnGameObject( \"" @ %gameObjectName @ "\", true );";
-   %ctrl.iconBitmap = EditorIconRegistry::findIconByClassName( "Prefab" );
-   %ctrl.text = %gameObjectName;
-   %ctrl.class = "CreatorGameObjectIconBtn";
-   %ctrl.tooltip = "Spawn the " @ %gameObjectName @ " GameObject";
-   
-   %ctrl.buttonType = "radioButton";
-   %ctrl.groupNum = "-1";   
-   
-   %this.contentCtrl.addGuiControl( %ctrl );   
-}
-
 function CreatorPopupMenu::onSelect( %this, %id, %text )
 {   
    %split = strreplace( %text, "/", " " );

二进制
Templates/Full/game/art/shapes/weapons/Ryder/TP_Ryder_S.dds


+ 1 - 1
Templates/Full/game/art/shapes/weapons/Ryder/materials.cs

@@ -39,7 +39,7 @@ singleton Material(TP_Ryder_Base)
    mapTo = "TP_Ryder_Base";
    diffuseMap[0] = "./TP_Ryder_D.dds";
    normalMap[0] = "./TP_Ryder_N.dds";
-   specularMap[0] = "./TP_Ryder_D.dds";
+   specularMap[0] = "./TP_Ryder_S.dds";
    specular[0] = "1.0 1.0 1.0 1";
    specularPower[0] = "10";
    translucentBlendOp = "None";

+ 1 - 1
Templates/Full/game/art/shapes/weapons/Turret/materials.cs

@@ -29,7 +29,7 @@ singleton Material(Turret_Base)
    translucentBlendOp = "None";
    normalMap[0] = "art/shapes/weapons/Turret/Turret_N.dds";
    pixelSpecular[0] = "1";
-   specularMap[0] = "art/shapes/weapons/Turret/Turret_D.dds";
+   specularMap[0] = "art/shapes/weapons/Turret/Turret_S.dds";
    useAnisotropic[0] = "1";
    castDynamicShadows = true;    
    materialTag0 = "Weapon";

+ 116 - 208
Templates/Full/game/tools/worldEditor/scripts/EditorGui.ed.cs

@@ -1302,6 +1302,7 @@ function VisibilityDropdownToggle()
    {
       EVisibility.setVisible(true);
       visibilityToggleBtn.setStateOn(1);
+      EVisibility.setExtent("200 540");
    }
 }
 
@@ -1569,6 +1570,27 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
    %haveObjectEntries = false;
    %haveLockAndHideEntries = true;
    
+   //Set up the generic pop-up pre-emptively if we haven't already
+   if( !isObject( ETContextPopup ) )
+   {
+      %popup = new PopupMenu( ETContextPopup )
+      {
+         superClass = "MenuBuilder";
+         isPopup = "1";
+
+         item[ 0 ] = "Rename" TAB "" TAB "EditorTree.showItemRenameCtrl( EditorTree.findItemByObjectId( %this.object ) );";
+         item[ 1 ] = "Delete" TAB "" TAB "EWorldEditor.deleteMissionObject( %this.object );";
+         item[ 2 ] = "Inspect" TAB "" TAB "inspectObject( %this.object );";
+         item[ 3 ] = "-";
+         item[ 4 ] = "Locked" TAB "" TAB "%this.object.setLocked( !%this.object.locked ); EWorldEditor.syncGui();";
+         item[ 5 ] = "Hidden" TAB "" TAB "EWorldEditor.hideObject( %this.object, !%this.object.hidden ); EWorldEditor.syncGui();";
+         item[ 6 ] = "-";
+         item[ 7 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );";
+
+         object = -1;
+      };
+   }
+   
    // Handle multi-selection.
    if( %this.getSelectedItemsCount() > 1 )
    {
@@ -1615,13 +1637,13 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
             item[ 0 ] = "Add Camera Bookmark" TAB "" TAB "EditorGui.addCameraBookmarkByGui();";
          };
    }
-
-   // Open context menu if this is a SimGroup
-   else if( !%obj.isMemberOfClass( "SceneObject" ) )
+   
+   else if(%obj.isMemberOfClass("Entity"))
    {
-      %popup = ETSimGroupContextPopup;
-      if( !isObject( %popup ) )
-         %popup = new PopupMenu( ETSimGroupContextPopup )
+      %popup = EntityObjectPopup;
+      if(!isObject(EntityObjectPopup))
+      {
+         %popup = new PopupMenu( EntityObjectPopup )
          {
             superClass = "MenuBuilder";
             isPopup = "1";
@@ -1638,10 +1660,28 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
             item[ 9 ] = "Add New Objects Here" TAB "" TAB "EWCreatorWindow.setNewObjectGroup( %this.object );";
             item[ 10 ] = "Add Children to Selection" TAB "" TAB "EWorldEditor.selectAllObjectsInSet( %this.object, false );";
             item[ 11 ] = "Remove Children from Selection" TAB "" TAB "EWorldEditor.selectAllObjectsInSet( %this.object, true );";
-
+            item[ 12 ] = "-";
+            item[ 13 ] = "Convert to Game Object" TAB "" TAB "EWorldEditor.createGameObject( %this.object );";
+            item[ 14 ] = "Duplicate Game Object" TAB "" TAB "EWorldEditor.duplicateGameObject( %this.object );";
+            item[ 15 ] = "Show in Asset Browser" TAB "" TAB "EWorldEditor.showGameObjectInAssetBrowser( %this.object );";
+            
             object = -1;
          };
-
+      }
+         
+      if(!isObject(AssetDatabase.acquireAsset(%obj.gameObjectAsset)))
+      {
+         EntityObjectPopup.enableItem(13, true);
+         EntityObjectPopup.enableItem(14, false);
+         EntityObjectPopup.enableItem(15, false);
+      }
+      else
+      {
+         EntityObjectPopup.enableItem(13, false);
+         EntityObjectPopup.enableItem(14, true);
+         EntityObjectPopup.enableItem(15, true);
+      }
+      
       %popup.object = %obj;
       
       %hasChildren = %obj.getCount() > 0;
@@ -1651,13 +1691,14 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
       %haveObjectEntries = true;
       %haveLockAndHideEntries = false;
    }
-   
-   // Open generic context menu.
-   else
+
+   // Open context menu if this is a SimGroup
+   else if( !%obj.isMemberOfClass( "SceneObject" ) )
    {
-      %popup = ETContextPopup;      
+      %popup = ETSimGroupContextPopup;
       if( !isObject( %popup ) )
-         %popup = new PopupMenu( ETContextPopup )
+      {
+         %popup = new PopupMenu( ETSimGroupContextPopup )
          {
             superClass = "MenuBuilder";
             isPopup = "1";
@@ -1666,63 +1707,79 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
             item[ 1 ] = "Delete" TAB "" TAB "EWorldEditor.deleteMissionObject( %this.object );";
             item[ 2 ] = "Inspect" TAB "" TAB "inspectObject( %this.object );";
             item[ 3 ] = "-";
-            item[ 4 ] = "Locked" TAB "" TAB "%this.object.setLocked( !%this.object.locked ); EWorldEditor.syncGui();";
-            item[ 5 ] = "Hidden" TAB "" TAB "EWorldEditor.hideObject( %this.object, !%this.object.hidden ); EWorldEditor.syncGui();";
+            item[ 4 ] = "Toggle Lock Children" TAB "" TAB "EWorldEditor.toggleLockChildren( %this.object );";
+            item[ 5 ] = "Toggle Hide Children" TAB "" TAB "EWorldEditor.toggleHideChildren( %this.object );";
             item[ 6 ] = "-";
             item[ 7 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );";
+            item[ 8 ] = "-";
+            item[ 9 ] = "Add New Objects Here" TAB "" TAB "EWCreatorWindow.setNewObjectGroup( %this.object );";
+            item[ 10 ] = "Add Children to Selection" TAB "" TAB "EWorldEditor.selectAllObjectsInSet( %this.object, false );";
+            item[ 11 ] = "Remove Children from Selection" TAB "" TAB "EWorldEditor.selectAllObjectsInSet( %this.object, true );";
 
             object = -1;
          };
-         
-      if(%obj.isMemberOfClass("Entity"))
-      {
-         %popup = ETEntityContextPopup;      
-         if( !isObject( %popup ) )
-            %popup = new PopupMenu( ETEntityContextPopup : ETSimGroupContextPopup )
-            {
-               superClass = "MenuBuilder";
-               isPopup = "1";
-
-               item[ 12 ] = "-";
-               item[ 13 ] = "Convert to Game Object" TAB "" TAB "EWorldEditor.createGameObject( %this.object );";
-            };
       }
-     
-      // Specialized version for ConvexShapes. 
-      else if( %obj.isMemberOfClass( "ConvexShape" ) )
+
+      %popup.object = %obj;
+      
+      %hasChildren = %obj.getCount() > 0;
+      %popup.enableItem( 10, %hasChildren );
+      %popup.enableItem( 11, %hasChildren );
+      
+      %haveObjectEntries = true;
+      %haveLockAndHideEntries = false;
+   }
+   
+   // Specialized version for ConvexShapes. 
+   else if( %obj.isMemberOfClass( "ConvexShape" ) )
+   {
+      %popup = ETConvexShapeContextPopup;      
+      if( !isObject( %popup ) )
       {
-         %popup = ETConvexShapeContextPopup;      
-         if( !isObject( %popup ) )
-            %popup = new PopupMenu( ETConvexShapeContextPopup : ETContextPopup )
-            {
-               superClass = "MenuBuilder";
-               isPopup = "1";
-
-               item[ 8 ] = "-";
-               item[ 9 ] = "Convert to Zone" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"Zone\" );";
-               item[ 10 ] = "Convert to Portal" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"Portal\" );";
-               item[ 11 ] = "Convert to Occluder" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"OcclusionVolume\" );";
-               item[ 12 ] = "Convert to Sound Space" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"SFXSpace\" );";
-            };
+         %popup = new PopupMenu( ETConvexShapeContextPopup : ETContextPopup )
+         {
+            superClass = "MenuBuilder";
+            isPopup = "1";
+
+            item[ 8 ] = "-";
+            item[ 9 ] = "Convert to Zone" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"Zone\" );";
+            item[ 10 ] = "Convert to Portal" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"Portal\" );";
+            item[ 11 ] = "Convert to Occluder" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"OcclusionVolume\" );";
+            item[ 12 ] = "Convert to Sound Space" TAB "" TAB "EWorldEditor.convertSelectionToPolyhedralObjects( \"SFXSpace\" );";
+         };
       }
       
-      // Specialized version for polyhedral objects.
-      else if( %obj.isMemberOfClass( "Zone" ) ||
-               %obj.isMemberOfClass( "Portal" ) ||
-               %obj.isMemberOfClass( "OcclusionVolume" ) ||
-               %obj.isMemberOfClass( "SFXSpace" ) )
+      %popup.object = %obj;
+      %haveObjectEntries = true;
+   }
+   
+   // Specialized version for polyhedral objects.
+   else if( %obj.isMemberOfClass( "Zone" ) ||
+            %obj.isMemberOfClass( "Portal" ) ||
+            %obj.isMemberOfClass( "OcclusionVolume" ) ||
+            %obj.isMemberOfClass( "SFXSpace" ) )
+   {
+      %popup = ETPolyObjectContextPopup;      
+      if( !isObject( %popup ) )
       {
-         %popup = ETPolyObjectContextPopup;      
-         if( !isObject( %popup ) )
-            %popup = new PopupMenu( ETPolyObjectContextPopup : ETContextPopup )
-            {
-               superClass = "MenuBuilder";
-               isPopup = "1";
-
-               item[ 8 ] = "-";
-               item[ 9 ] = "Convert to ConvexShape" TAB "" TAB "EWorldEditor.convertSelectionToConvexShape();";
-            };
+         %popup = new PopupMenu( ETPolyObjectContextPopup : ETContextPopup )
+         {
+            superClass = "MenuBuilder";
+            isPopup = "1";
+
+            item[ 8 ] = "-";
+            item[ 9 ] = "Convert to ConvexShape" TAB "" TAB "EWorldEditor.convertSelectionToConvexShape();";
+         };
       }
+      
+      %popup.object = %obj;
+      %haveObjectEntries = true;
+   }
+   
+   // Open generic context menu.
+   else
+   {
+      %popup = ETContextPopup;      
 
       %popup.object = %obj;
       %haveObjectEntries = true;
@@ -2253,155 +2310,6 @@ function EWorldEditor::deleteMissionObject( %this, %object )
    EditorTree.buildVisibleTree( true );
 }
 
-function EWorldEditor::createGameObject( %this, %entity )
-{
-   if(!isObject(GameObjectBuilder))
-   {
-      new GuiControl(GameObjectBuilder, EditorGuiGroup) {
-         profile = "ToolsGuiDefaultProfile";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         position = "0 0";
-         extent = "800 600";
-         minExtent = "8 8";
-         visible = "1";
-         setFirstResponder = "0";
-         modal = "1";
-         helpTag = "0";
-      
-         new GuiWindowCtrl(GameObjectBuilderTargetWindow) {
-            profile = "ToolsGuiWindowProfile";
-            horizSizing = "center";
-            vertSizing = "center";
-            position = "384 205";
-            extent = "256 102";
-            minExtent = "256 8";
-            visible = "1";
-            setFirstResponder = "0";
-            modal = "1";
-            helpTag = "0";
-            resizeWidth = "1";
-            resizeHeight = "1";
-            canMove = "1";
-            canClose = "0";
-            canMinimize = "0";
-            canMaximize = "0";
-            minSize = "50 50";
-            text = "Create Object";
-      
-            new GuiTextCtrl() {
-               profile = "GuiCenterTextProfile";
-               horizSizing = "right";
-               vertSizing = "bottom";
-               position = "9 26";
-               extent = "84 16";
-               minExtent = "8 8";
-               visible = "1";
-               setFirstResponder = "0";
-               modal = "1";
-               helpTag = "0";
-               text = "Object Name:";
-            };
-            new GuiTextEditCtrl(GameObjectBuilderObjectName) {
-                class = ObjectBuilderGuiTextEditCtrl;
-               profile = "ToolsGuiTextEditProfile";
-               horizSizing = "width";
-               vertSizing = "bottom";
-               position = "78 26";
-               extent = "172 18";
-               minExtent = "8 8";
-               visible = "1";
-               setFirstResponder = "0";
-               modal = "1";
-               helpTag = "0";
-               historySize = "0";
-            };
-            new GuiButtonCtrl(GameObjectBuilderOKButton) {
-               profile = "ToolsGuiButtonProfile";
-               horizSizing = "width";
-               vertSizing = "bottom";
-               position = "7 250";
-               extent = "156 24";
-               minExtent = "8 8";
-               visible = "1";
-               setFirstResponder = "0";
-               modal = "1";
-               command = "EWorldEditor.buildGameObject();";
-               helpTag = "0";
-               text = "Create New";
-               Accelerator = "return";
-            };
-            new GuiButtonCtrl(GameObjectBuilderCancelButton) {
-               profile = "ToolsGuiButtonProfile";
-               horizSizing = "left";
-               vertSizing = "bottom";
-               position = "170 250";
-               extent = "80 24";
-               minExtent = "8 8";
-               visible = "1";
-               setFirstResponder = "0";
-               modal = "1";
-               command = "Canvas.popDialog(GameObjectBuilder);";
-               helpTag = "0";
-               text = "Cancel";
-               Accelerator = "escape";
-            };
-         };
-      };
-      
-      GameObjectBuilderTargetWindow.extent = getWord(GameObjectBuilderTargetWindow.extent, 0) SPC 88;
-      GameObjectBuilderOKButton.position = getWord(GameObjectBuilderOKButton.position, 0) SPC 57;
-      GameObjectBuilderCancelButton.position = getWord(GameObjectBuilderCancelButton.position, 0) SPC 57;
-   }
-
-   GameObjectBuilderObjectName.text = "";
-   GameObjectBuilder.selectedEntity = %entity;
-
-   Canvas.pushDialog(GameObjectBuilder);
-}
-
-function EWorldEditor::buildGameObject(%this)
-{
-	if(GameObjectBuilderObjectName.getText() $= "")
-	{
-		error("Attempted to make a new Game Object with no name!");
-		Canvas.popDialog(GameObjectBuilder);
-		return;
-	}
-
-	%path = EditorSettings.value( "WorldEditor/newGameObjectDir" );
-	%className = GameObjectBuilderObjectName.getText();
-	GameObjectBuilder.selectedEntity.class = %className;
-	Inspector.inspect(GameObjectBuilder.selectedEntity);
-	
-	%file = new FileObject();
-	
-	if(%file.openForWrite(%path @ "\\" @ %className @ ".cs"))
-	{
-		%file.writeline("function " @ %className @ "::onAdd(%this)\n{\n\n}\n");
-		%file.writeline("function " @ %className @ "::onRemove(%this)\n{\n\n}\n");
-		
-		//todo, pre-write any event functions of interest
-		
-		%file.close();
-	}
-	
-	//set up the paths
-	%tamlPath = %path @ "/" @ %className @ ".taml";
-	%scriptPath = %path @ "/" @ %className @ ".cs";
-	saveGameObject(%className, %tamlPath, %scriptPath);
-	
-	//reload it
-	execGameObjects();
-	
-	//now, add the script file and a ref to the taml into our SGO manifest so we can readily spawn it later.
-	TamlWrite(GameObjectBuilder.selectedEntity, %tamlpath);
-
-   GameObjectBuilder.selectedEntity = "";
-	
-	Canvas.popDialog(GameObjectBuilder);
-}
-
 function EWorldEditor::selectAllObjectsInSet( %this, %set, %deselect )
 {
    if( !isObject( %set ) )

+ 0 - 1
Templates/Full/game/tools/worldEditor/scripts/editorPrefs.ed.cs

@@ -34,7 +34,6 @@ EditorSettings.setDefaultValue(  "orthoFOV",                "50" );
 EditorSettings.setDefaultValue(  "orthoShowGrid",           "1" );
 EditorSettings.setDefaultValue(  "currentEditor",           "WorldEditorInspectorPlugin" );
 EditorSettings.setDefaultValue(  "newLevelFile",            "tools/levels/BlankRoom.mis" );
-EditorSettings.setDefaultValue(  "newGameObjectDir",        "scripts/server/gameObjects" );
 
 if( isFile( "C:/Program Files/Torsion/Torsion.exe" ) )
    EditorSettings.setDefaultValue(  "torsionPath",          "C:/Program Files/Torsion/Torsion.exe" );

+ 0 - 46
Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs

@@ -304,36 +304,6 @@ function EWCreatorWindow::navigate( %this, %address )
                %this.addShapeIcon( %obj );
          }
       }
-      
-      //Add a separate folder for Game Objects
-      if(isClass("Entity"))
-      {
-          if(%address $= "")
-          {
-              %this.addFolderIcon("GameObjects");
-          }
-          else
-          {
-              //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);
-
-                 %gameObjectAsset = AssetDatabase.acquireAsset(%assetId);
-
-                 if(isFile(%gameObjectAsset.TAMLFilePath))
-                 {
-                    %this.addGameObjectIcon( %gameObjectAsset.gameObjectName );
-                 }
-              }
-          }
-      }
    }
    
    if ( %this.tab $= "Meshes" )
@@ -768,22 +738,6 @@ function EWCreatorWindow::addPrefabIcon( %this, %fullPath )
    %this.contentCtrl.addGuiControl( %ctrl );   
 }
 
-function EWCreatorWindow::addGameObjectIcon( %this, %gameObjectName )
-{
-   %ctrl = %this.createIcon();
-
-   %ctrl.altCommand = "spawnGameObject( \"" @ %gameObjectName @ "\", true );";
-   %ctrl.iconBitmap = EditorIconRegistry::findIconByClassName( "Prefab" );
-   %ctrl.text = %gameObjectName;
-   %ctrl.class = "CreatorGameObjectIconBtn";
-   %ctrl.tooltip = "Spawn the " @ %gameObjectName @ " GameObject";
-   
-   %ctrl.buttonType = "radioButton";
-   %ctrl.groupNum = "-1";   
-   
-   %this.contentCtrl.addGuiControl( %ctrl );   
-}
-
 function CreatorPopupMenu::onSelect( %this, %id, %text )
 {   
    %split = strreplace( %text, "/", " " );