Explorar el Código

Merge branch 'development' of https://github.com/GarageGames/Torque3D into FrameMallocMallet

Conflicts:
	Engine/source/gfx/gl/gfxGLTextureManager.cpp
Azaezel hace 9 años
padre
commit
75fa06dec2
Se han modificado 91 ficheros con 2124 adiciones y 475 borrados
  1. 5 3
      Engine/source/T3D/lightAnimData.cpp
  2. 1 1
      Engine/source/T3D/lightAnimData.h
  3. 22 0
      Engine/source/T3D/physics/bullet/btBody.cpp
  4. 2 0
      Engine/source/T3D/physics/bullet/btBody.h
  5. 15 10
      Engine/source/T3D/physics/bullet/btPlayer.cpp
  6. 4 0
      Engine/source/T3D/physics/bullet/btPlayer.h
  7. 4 0
      Engine/source/T3D/physics/physicsBody.h
  8. 19 0
      Engine/source/T3D/physics/physx3/px3Body.cpp
  9. 2 0
      Engine/source/T3D/physics/physx3/px3Body.h
  10. 30 0
      Engine/source/T3D/physics/physx3/px3Player.cpp
  11. 2 2
      Engine/source/T3D/physics/physx3/px3Player.h
  12. 58 1
      Engine/source/T3D/physics/physx3/px3World.cpp
  13. 5 0
      Engine/source/T3D/physics/physx3/px3World.h
  14. 10 9
      Engine/source/T3D/shapeBase.cpp
  15. 42 1
      Engine/source/T3D/vehicles/vehicle.cpp
  16. 7 0
      Engine/source/T3D/vehicles/vehicle.h
  17. 2 0
      Engine/source/console/consoleTypes.h
  18. 1 1
      Engine/source/gfx/gfxDrawUtil.cpp
  19. 18 40
      Engine/source/gfx/gl/gfxGLCardProfiler.cpp
  20. 7 5
      Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h
  21. 17 1
      Engine/source/gfx/gl/gfxGLDevice.cpp
  22. 12 0
      Engine/source/gfx/gl/gfxGLDevice.h
  23. 6 1
      Engine/source/gfx/gl/gfxGLShader.cpp
  24. 3 2
      Engine/source/gfx/gl/gfxGLStateBlock.cpp
  25. 10 3
      Engine/source/gfx/gl/gfxGLTextureManager.cpp
  26. 8 3
      Engine/source/gfx/gl/gfxGLTextureObject.cpp
  27. 1 1
      Engine/source/gfx/gl/gfxGLTextureTarget.cpp
  28. 2 2
      Engine/source/gfx/gl/gfxGLVertexBuffer.cpp
  29. 2 2
      Engine/source/gfx/gl/gfxGLVertexDecl.cpp
  30. 1 1
      Engine/source/gfx/gl/gfxGLWindowTarget.cpp
  31. 2 1
      Engine/source/gui/editor/inspector/field.cpp
  32. 1 1
      Engine/source/materials/materialFeatureTypes.cpp
  33. 2 1
      Engine/source/materials/processedShaderMaterial.cpp
  34. 1 1
      Engine/source/math/mBox.h
  35. 3 0
      Engine/source/math/mMath.h
  36. 11 1
      Engine/source/math/mPolyhedron.impl.h
  37. 348 0
      Engine/source/math/mRotation.cpp
  38. 465 0
      Engine/source/math/mRotation.h
  39. 24 0
      Engine/source/math/mathIO.h
  40. 58 2
      Engine/source/math/mathTypes.cpp
  41. 3 2
      Engine/source/math/mathTypes.h
  42. 6 11
      Engine/source/math/mathUtils.cpp
  43. 13 1
      Engine/source/navigation/navMesh.cpp
  44. 51 19
      Engine/source/platform/nativeDialogs/fileDialog.cpp
  45. 1 0
      Engine/source/scene/sceneObject.cpp
  46. 1 0
      Engine/source/scene/sceneObject.h
  47. 5 2
      Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp
  48. 5 2
      Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp
  49. 3 1
      Templates/Empty/game/core/scripts/client/defaults.cs
  50. 147 0
      Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs
  51. 7 0
      Templates/Empty/game/core/scripts/client/lighting/advanced/init.cs
  52. 17 4
      Templates/Empty/game/core/scripts/client/lighting/advanced/lightViz.cs
  53. 31 5
      Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs
  54. 4 2
      Templates/Empty/game/core/scripts/client/postFx/GammaPostFX.cs
  55. 2 2
      Templates/Empty/game/core/scripts/client/postFx/caustics.cs
  56. 16 2
      Templates/Empty/game/core/scripts/client/postFx/hdr.cs
  57. 1 1
      Templates/Empty/game/core/scripts/client/postFx/turbulence.cs
  58. 16 15
      Templates/Empty/game/core/scripts/client/renderManager.cs
  59. 2 2
      Templates/Empty/game/core/scripts/client/scatterSky.cs
  60. 36 0
      Templates/Empty/game/core/scripts/client/shaders.cs
  61. 0 1
      Templates/Empty/game/shaders/common/basicCloudsV.hlsl
  62. 0 1
      Templates/Empty/game/shaders/common/cloudLayerV.hlsl
  63. 0 1
      Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl
  64. 0 1
      Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl
  65. 1 1
      Templates/Empty/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl
  66. 5 223
      Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui
  67. 0 3
      Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs
  68. 3 1
      Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs
  69. 3 0
      Templates/Empty/game/tools/worldEditor/main.cs
  70. 6 2
      Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs
  71. 2 0
      Templates/Empty/game/tools/worldEditor/scripts/menuHandlers.ed.cs
  72. 364 45
      Templates/Full/game/core/art/gui/netGraphGui.gui
  73. 1 1
      Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs
  74. 9 5
      Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs
  75. 6 1
      Templates/Full/game/scripts/client/default.bind.cs
  76. 0 1
      Templates/Full/game/shaders/common/basicCloudsV.hlsl
  77. 0 1
      Templates/Full/game/shaders/common/cloudLayerV.hlsl
  78. 0 1
      Templates/Full/game/shaders/common/gl/basicCloudsV.glsl
  79. 0 1
      Templates/Full/game/shaders/common/gl/cloudLayerV.glsl
  80. 12 2
      Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl
  81. 12 2
      Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl
  82. 12 2
      Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl
  83. 11 2
      Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl
  84. 12 2
      Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl
  85. 11 2
      Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl
  86. 23 0
      Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui
  87. 0 3
      Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs
  88. 3 1
      Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs
  89. 6 2
      Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs
  90. 9 0
      Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs
  91. 13 0
      Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs

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

@@ -190,13 +190,15 @@ void LightAnimData::AnimValue<COUNT>::updateKey()
 }
 
 template<U32 COUNT>
-bool LightAnimData::AnimValue<COUNT>::animate( F32 time, F32 *output )
+bool LightAnimData::AnimValue<COUNT>::animate(F32 time, F32 *output, bool multiply)
 {
    F32 scaledTime, lerpFactor, valueRange, keyFrameLerp;
    U32 posFrom, posTo;
    S32 keyFrameFrom, keyFrameTo;
    F32 initialValue = *output;
-   
+   if (!multiply)
+      initialValue = 1;
+
    bool wasAnimated = false;
 
    for ( U32 i=0; i < COUNT; i++ )
@@ -305,6 +307,6 @@ void LightAnimData::animate( LightInfo *lightInfo, LightAnimState *state )
    lightInfo->setColor( color );
 
    F32 brightness = state->brightness;
-   mBrightness.animate( time, &brightness );
+   mBrightness.animate( time, &brightness, true );
    lightInfo->setBrightness( brightness );
 }

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

@@ -151,7 +151,7 @@ public:
       /// Performs the animation returning the results in the output if
       /// the time scale is greater than zero.
       /// @return Returns true if the animation was performed.
-      bool animate( F32 time, F32 *output );
+      bool animate(F32 time, F32 *output, bool multiply = false);
 
       /// Called when the key string is changed to update the
       /// key length and time scale.

+ 22 - 0
Engine/source/T3D/physics/bullet/btBody.cpp

@@ -378,3 +378,25 @@ void BtBody::setSimulationEnabled( bool enabled )
 
    mIsEnabled = enabled;
 }
+
+void BtBody::moveKinematicTo(const MatrixF &transform)
+{
+   AssertFatal(mActor, "BtBody::moveKinematicTo - The actor is null!");
+
+   U32 bodyflags = mActor->getCollisionFlags();
+   const bool isKinematic = bodyflags & BF_KINEMATIC;
+   if (!isKinematic)
+   {
+      Con::errorf("BtBody::moveKinematicTo is only for kinematic bodies.");
+      return;
+   }
+
+   if (mCenterOfMass)
+   {
+      MatrixF xfm;
+      xfm.mul(transform, *mCenterOfMass);
+      mActor->setCenterOfMassTransform(btCast<btTransform>(xfm));
+   }
+   else
+      mActor->setCenterOfMassTransform(btCast<btTransform>(transform));
+}

+ 2 - 0
Engine/source/T3D/physics/bullet/btBody.h

@@ -111,6 +111,8 @@ public:
                               F32 staticFriction );
    virtual void applyCorrection( const MatrixF &xfm );
    virtual void applyImpulse( const Point3F &origin, const Point3F &force );
+   virtual void moveKinematicTo(const MatrixF &xfm);
+
 };
 
 #endif // _T3D_PHYSICS_BTBODY_H_

+ 15 - 10
Engine/source/T3D/physics/bullet/btPlayer.cpp

@@ -71,6 +71,7 @@ void BtPlayer::init( const char *type,
    mObject = obj;
    mWorld = (BtWorld*)world;
 
+   mSlopeAngle = runSurfaceCos;
    mStepHeight = stepHeight;
 
    //if ( dStricmp( type, "Capsule" ) == 0 )
@@ -102,6 +103,17 @@ Point3F BtPlayer::move( const VectorF &disp, CollisionList &outCol )
 {
    AssertFatal( mGhostObject, "BtPlayer::move - The controller is null!" );
 
+   if (!mWorld->isEnabled())
+   {
+      btTransform currentTrans = mGhostObject->getWorldTransform();
+      btVector3 currentPos = currentTrans.getOrigin();
+
+      Point3F returnPos = btCast<Point3F>(currentPos);
+     
+      returnPos.z -= mOriginOffset;
+      return returnPos;
+   }
+
    // First recover from any penetrations from the previous tick.
    U32 numPenetrationLoops = 0;
    bool touchingContact = false;
@@ -305,16 +317,9 @@ bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, Collision
          col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
          col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
 
-         if (disp.z() < 0.0f)
-         {
-            // We're sweeping down as part of the stepping routine.    In this
-            // case we want to have the collision normal only point in the opposite direction.
-            // i.e. up  If we include the sideways part of the normal then the Player class
-            // velocity calculations using this normal will affect the player's forwards
-            // momentum.  This is especially noticable on stairs as the rounded bottom of
-            // the capsule slides up the corner of a stair.
-            col.normal.set(0.0f, 0.0f, 1.0f);
-         }
+         F32 vd = col.normal.z;
+         if (vd < mSlopeAngle)
+            return false;
       }
 
       return true;

+ 4 - 0
Engine/source/T3D/physics/bullet/btPlayer.h

@@ -57,6 +57,10 @@ protected:
    ///
    F32 mOriginOffset;
 
+   ///
+   F32 mSlopeAngle;
+   ///
+
    ///
    F32 mStepHeight;
    ///

+ 4 - 0
Engine/source/T3D/physics/physicsBody.h

@@ -113,6 +113,10 @@ public:
 
    ///
    virtual void applyImpulse( const Point3F &origin, const Point3F &force ) = 0;
+
+   ///
+   virtual void moveKinematicTo(const MatrixF &xfm) = 0;
+
 };
 
 

+ 19 - 0
Engine/source/T3D/physics/physx3/px3Body.cpp

@@ -417,3 +417,22 @@ void Px3Body::applyImpulse( const Point3F &origin, const Point3F &force )
 
 }
 
+void Px3Body::moveKinematicTo(const MatrixF &transform)
+{
+   AssertFatal(mActor, "Px3Body::moveKinematicTo - The actor is null!");
+
+   const bool isKinematic = mBodyFlags & BF_KINEMATIC;
+   if (!isKinematic)
+   {
+      Con::errorf("Px3Body::moveKinematicTo is only for kinematic bodies.");
+      return;
+   }
+
+   mWorld->lockScene();
+
+   physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
+   actor->setKinematicTarget(px3Cast<physx::PxTransform>(transform));
+
+   mWorld->unlockScene();
+}
+

+ 2 - 0
Engine/source/T3D/physics/physx3/px3Body.h

@@ -117,6 +117,8 @@ public:
                               F32 staticFriction );
    virtual void applyCorrection( const MatrixF &xfm );
    virtual void applyImpulse( const Point3F &origin, const Point3F &force );
+   virtual void moveKinematicTo(const MatrixF &xfm);
+
 };
 
 #endif // _PX3BODY_H_

+ 30 - 0
Engine/source/T3D/physics/physx3/px3Player.cpp

@@ -329,3 +329,33 @@ Box3F Px3Player::getWorldBounds()
    return px3Cast<Box3F>( bounds );
 }
 
+bool Px3Player::testSpacials(const Point3F &nPos, const Point3F &nSize) const
+{
+   F32 offset = nSize.z * 0.5f;
+   F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
+   F32 height = (nSize.z - (radius * 2.0f)) * 0.5f;
+   height -= mSkinWidth * 2.0f;
+   physx::PxCapsuleGeometry geom(radius, height);
+
+   physx::PxVec3 pos(nPos.x, nPos.y, nPos.z + offset);
+   physx::PxQuat orientation(Float_HalfPi, physx::PxVec3(0.0f, 1.0f, 0.0f));
+
+   physx::PxOverlapBuffer hit;
+   physx::PxQueryFilterData queryFilter(physx::PxQueryFlag::eANY_HIT | physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC);
+   queryFilter.data.word0 = PX3_DEFAULT;
+   bool hasHit = mWorld->getScene()->overlap(geom, physx::PxTransform(pos, orientation), hit, queryFilter);
+
+   return !hasHit;   // Return true if there are no overlapping objects
+}
+
+void Px3Player::setSpacials(const Point3F &nPos, const Point3F &nSize)
+{
+   mOriginOffset = nSize.z * 0.5f;
+   F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
+   F32 height = nSize.z - (radius * 2.0f);
+   height -= mSkinWidth * 2.0f;
+
+   mWorld->releaseWriteLock();
+   mController->resize(height);
+   px3GetFirstShape(mController->getActor())->getCapsuleGeometry(mGeometry);
+}

+ 2 - 2
Engine/source/T3D/physics/physx3/px3Player.h

@@ -94,8 +94,8 @@ public:
                         PhysicsWorld *world );
    virtual Point3F move( const VectorF &displacement, CollisionList &outCol );
    virtual void findContact( SceneObject **contactObject, VectorF *contactNormal, Vector<SceneObject*> *outOverlapObjects ) const;
-   virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const { return true; }
-   virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ) {}
+   virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const;
+   virtual void setSpacials( const Point3F &nPos, const Point3F &nSize );
    virtual void enableCollision();
    virtual void disableCollision();
 };

+ 58 - 1
Engine/source/T3D/physics/physx3/px3World.cpp

@@ -62,7 +62,8 @@ Px3World::Px3World(): mScene( NULL ),
    mIsEnabled( false ),
    mEditorTimeScale( 1.0f ),
    mAccumulator( 0 ),
-   mControllerManager( NULL )
+   mControllerManager(NULL),
+   mIsSceneLocked(false)
 {
 }
 
@@ -335,6 +336,62 @@ void Px3World::releaseWriteLock()
 	//AssertFatal( mScene->isWritable(), "PhysX3World::releaseWriteLock() - We should have been writable now!" );
 }
 
+void Px3World::lockScenes()
+{
+   Px3World *world = dynamic_cast<Px3World*>(PHYSICSMGR->getWorld("server"));
+
+   if (world)
+      world->lockScene();
+
+   world = dynamic_cast<Px3World*>(PHYSICSMGR->getWorld("client"));
+
+   if (world)
+      world->lockScene();
+}
+
+void Px3World::unlockScenes()
+{
+   Px3World *world = dynamic_cast<Px3World*>(PHYSICSMGR->getWorld("server"));
+
+   if (world)
+      world->unlockScene();
+
+   world = dynamic_cast<Px3World*>(PHYSICSMGR->getWorld("client"));
+
+   if (world)
+      world->unlockScene();
+}
+
+void Px3World::lockScene()
+{
+   if (!mScene)
+      return;
+
+   if (mIsSceneLocked)
+   {
+      Con::printf("Px3World: Attempting to lock a scene that is already locked.");
+      return;
+   }
+
+   mScene->lockWrite();
+   mIsSceneLocked = true;
+}
+
+void Px3World::unlockScene()
+{
+   if (!mScene)
+      return;
+
+   if (!mIsSceneLocked)
+   {
+      Con::printf("Px3World: Attempting to unlock a scene that is not locked.");
+      return;
+   }
+
+   mScene->unlockWrite();
+   mIsSceneLocked = false;
+}
+
 bool Px3World::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
 {
     

+ 5 - 0
Engine/source/T3D/physics/physx3/px3World.h

@@ -56,6 +56,7 @@ protected:
 	bool mIsEnabled;
 	bool mIsSimulating;
 	bool mIsServer;
+   bool mIsSceneLocked;
 	U32 mTickCount;
 	ProcessList *mProcessList;
 	F32 mEditorTimeScale;
@@ -96,11 +97,15 @@ public:
 	void releaseWriteLock();
 	bool isServer(){return mIsServer;}
 	physx::PxController* createController( physx::PxControllerDesc &desc );
+   void lockScene();
+   void unlockScene();
 	//static
 	static bool restartSDK( bool destroyOnly = false, Px3World *clientWorld = NULL, Px3World *serverWorld = NULL );
 	static void releaseWriteLocks();
 	static physx::PxCooking *getCooking();
    static void setTiming(F32 stepTime,U32 maxIterations);
+   static void lockScenes();
+   static void unlockScenes();
 };
 
 #endif // _PX3WORLD_H_

+ 10 - 9
Engine/source/T3D/shapeBase.cpp

@@ -4881,17 +4881,18 @@ DefineEngineMethod( ShapeBase, getTargetCount, S32, (),,
    
    "@see getTargetName()\n")
 {
-	ShapeBase *obj = dynamic_cast< ShapeBase* > ( object );
-	if(obj)
-	{
-		// Try to use the client object (so we get the reskinned targets in the Material Editor)
-		if ((ShapeBase*)obj->getClientObject())
-			obj = (ShapeBase*)obj->getClientObject();
+   ShapeBase *obj = dynamic_cast< ShapeBase* > ( object );
+   if(obj)
+   {
+      // Try to use the client object (so we get the reskinned targets in the Material Editor)
+      if ((ShapeBase*)obj->getClientObject())
+         obj = (ShapeBase*)obj->getClientObject();
 
-		return obj->getShapeInstance()->getTargetCount();
+      if (obj->getShapeInstance() != NULL)
+         return obj->getShapeInstance()->getTargetCount();
 	}
-
-	return -1;
+   
+   return -1;
 }
 
 DefineEngineMethod( ShapeBase, changeMaterial, void, ( const char* mapTo, Material* oldMat, Material* newMat ),,

+ 42 - 1
Engine/source/T3D/vehicles/vehicle.cpp

@@ -46,6 +46,9 @@
 #include "gfx/primBuilder.h"
 #include "gfx/gfxDrawUtil.h"
 #include "materials/materialDefinition.h"
+#include "T3D/physics/physicsPlugin.h"
+#include "T3D/physics/physicsBody.h"
+#include "T3D/physics/physicsCollision.h"
 
 
 namespace {
@@ -203,7 +206,8 @@ VehicleData::VehicleData()
    dMemset(waterSound, 0, sizeof(waterSound));
 
    collDamageThresholdVel = 20;
-   collDamageMultiplier   = 0.05f;
+   collDamageMultiplier = 0.05f;
+   enablePhysicsRep = true;
 }
 
 
@@ -315,6 +319,7 @@ void VehicleData::packData(BitStream* stream)
    stream->write(softSplashSoundVel);
    stream->write(medSplashSoundVel);
    stream->write(hardSplashSoundVel);
+   stream->write(enablePhysicsRep);
 
    // write the water sound profiles
    for(i = 0; i < MaxSounds; i++)
@@ -411,6 +416,7 @@ void VehicleData::unpackData(BitStream* stream)
    stream->read(&softSplashSoundVel);
    stream->read(&medSplashSoundVel);
    stream->read(&hardSplashSoundVel);
+   stream->read(&enablePhysicsRep);
 
    // write the water sound profiles
    for(i = 0; i < MaxSounds; i++)
@@ -465,6 +471,11 @@ void VehicleData::unpackData(BitStream* stream)
 
 void VehicleData::initPersistFields()
 {
+   addGroup("Physics");
+   addField("enablePhysicsRep", TypeBool, Offset(enablePhysicsRep, VehicleData),
+      "@brief Creates a representation of the object in the physics plugin.\n");
+   endGroup("Physics");
+
    addField( "jetForce", TypeF32, Offset(jetForce, VehicleData),
       "@brief Additional force applied to the vehicle when it is jetting.\n\n"
       "For WheeledVehicles, the force is applied in the forward direction. For "
@@ -682,6 +693,8 @@ Vehicle::Vehicle()
    mWorkingQueryBox.minExtents.set(-1e9f, -1e9f, -1e9f);
    mWorkingQueryBox.maxExtents.set(-1e9f, -1e9f, -1e9f);
    mWorkingQueryBoxCountDown = sWorkingQueryBoxStaleThreshold;
+
+   mPhysicsRep = NULL;
 }
 
 U32 Vehicle::getCollisionMask()
@@ -695,6 +708,25 @@ Point3F Vehicle::getVelocity() const
    return mRigid.linVelocity;
 }
 
+void Vehicle::_createPhysics()
+{
+   SAFE_DELETE(mPhysicsRep);
+
+   if (!PHYSICSMGR || !mDataBlock->enablePhysicsRep)
+      return;
+
+   TSShape *shape = mShapeInstance->getShape();
+   PhysicsCollision *colShape = NULL;
+   colShape = shape->buildColShape(false, getScale());
+
+   if (colShape)
+   {
+      PhysicsWorld *world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
+      mPhysicsRep = PHYSICSMGR->createBody();
+      mPhysicsRep->init(colShape, 0, PhysicsBody::BF_KINEMATIC, this, world);
+      mPhysicsRep->setTransform(getTransform());
+   }
+}
 //----------------------------------------------------------------------------
 
 bool Vehicle::onAdd()
@@ -776,11 +808,15 @@ bool Vehicle::onAdd()
    mConvex.box.maxExtents.convolve(mObjScale);
    mConvex.findNodeTransform();
 
+   _createPhysics();
+
    return true;
 }
 
 void Vehicle::onRemove()
 {
+   SAFE_DELETE(mPhysicsRep);
+
    U32 i=0;
    for( i=0; i<VehicleData::VC_NUM_DUST_EMITTERS; i++ )
    {
@@ -880,6 +916,11 @@ void Vehicle::processTick(const Move* move)
       setPosition(mRigid.linPosition, mRigid.angPosition);
       setMaskBits(PositionMask);
       updateContainer();
+
+      //TODO: Only update when position has actually changed
+      //no need to check if mDataBlock->enablePhysicsRep is false as mPhysicsRep will be NULL if it is
+      if (mPhysicsRep)
+         mPhysicsRep->moveKinematicTo(getTransform());
    }
 }
 

+ 7 - 0
Engine/source/T3D/vehicles/vehicle.h

@@ -127,6 +127,8 @@ struct VehicleData: public ShapeBaseData
    F32 splashFreqMod;
    F32 splashVelEpsilon;
 
+   bool enablePhysicsRep;
+
    //
    VehicleData();
    bool preload(bool server, String &errorStr);
@@ -142,6 +144,7 @@ struct VehicleData: public ShapeBaseData
 
 
 //----------------------------------------------------------------------------
+class PhysicsBody;
 
 class Vehicle: public ShapeBase
 {
@@ -177,6 +180,8 @@ class Vehicle: public ShapeBase
       Point3F cameraRotVec;
    };
 
+   PhysicsBody *mPhysicsRep;
+
    StateDelta mDelta;
    S32 mPredictionCount;            ///< Number of ticks to predict
    VehicleData* mDataBlock;
@@ -262,6 +267,8 @@ public:
    bool onAdd();
    void onRemove();
 
+   void _createPhysics();
+
    /// Interpolates between move ticks @see processTick
    /// @param   dt   Change in time between the last call and this call to the function
    void interpolateTick(F32 dt);

+ 2 - 0
Engine/source/console/consoleTypes.h

@@ -74,6 +74,8 @@ DefineConsoleType( TypeCommand, String )
 DefineConsoleType( TypeFilename, const char * )
 DefineConsoleType( TypeStringFilename, String )
 
+DefineConsoleType(TypeRotationF, RotationF)
+
 /// A universally unique identifier.
 DefineConsoleType( TypeUUID, Torque::UUID )
 

+ 1 - 1
Engine/source/gfx/gfxDrawUtil.cpp

@@ -1015,7 +1015,7 @@ void GFXDrawUtil::_drawSolidPolyhedron( const GFXStateBlockDesc &desc, const Any
 
    // Allocate a temp buffer for the face indices.
 
-   const U32 numIndices = poly.getNumEdges() * 2;
+   const U32 numIndices = poly.getNumEdges() * 3;
    const U32 numPlanes = poly.getNumPlanes();
 
    GFXPrimitiveBufferHandle prims( mDevice, numIndices, 0, GFXBufferTypeVolatile );

+ 18 - 40
Engine/source/gfx/gl/gfxGLCardProfiler.cpp

@@ -56,54 +56,32 @@ void GFXGLCardProfiler::setupCardCapabilities()
 {
    GLint maxTexSize;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
-
-   const char* versionString = reinterpret_cast<const char*>(glGetString(GL_VERSION));
-   F32 glVersion = dAtof(versionString);
    
    // OpenGL doesn't have separate maximum width/height.
    setCapability("maxTextureWidth", maxTexSize);
    setCapability("maxTextureHeight", maxTexSize);
    setCapability("maxTextureSize", maxTexSize);
 
-   // If extensions haven't been inited, we're in trouble here.
-   bool suppVBO = (gglHasExtension(ARB_vertex_buffer_object) || glVersion >= 1.499f);
-   setCapability("GL::suppVertexBufferObject", suppVBO);
+   // Check for anisotropic filtering support.
+   setCapability("GL_EXT_texture_filter_anisotropic", gglHasExtension(EXT_texture_filter_anisotropic));
 
-   // check if render to texture supported is available
-   bool suppRTT = gglHasExtension(EXT_framebuffer_object);
-   setCapability("GL::suppRenderTexture", suppRTT);
-   
-   bool suppBlit = gglHasExtension(EXT_framebuffer_blit);
-   setCapability("GL::suppRTBlit", suppBlit);
-   
-   bool suppFloatTex = gglHasExtension(ARB_texture_float);
-   setCapability("GL::suppFloatTexture", suppFloatTex);
+   // Check for buffer storage
+   setCapability("GL_ARB_buffer_storage", gglHasExtension(ARB_buffer_storage));
 
-   // Check for anisotropic filtering support.
-   bool suppAnisotropic = gglHasExtension( EXT_texture_filter_anisotropic );
-   setCapability( "GL::suppAnisotropic", suppAnisotropic );
-
-   // check to see if we have the fragment shader extension or the gl version is high enough for glsl to be core
-   // also check to see if the language version is high enough
-   F32 glslVersion = dAtof(reinterpret_cast<const char*>(glGetString( GL_SHADING_LANGUAGE_VERSION)));
-   bool suppSPU = (gglHasExtension(ARB_fragment_shader) || glVersion >= 1.999f) && glslVersion >= 1.0999;
-   setCapability("GL::suppFragmentShader", suppSPU);
-   
-   bool suppAppleFence = gglHasExtension(APPLE_fence);
-   setCapability("GL::APPLE::suppFence", suppAppleFence);
-   
-   // When enabled, call glGenerateMipmapEXT() to generate mipmaps instead of relying on GL_GENERATE_MIPMAP
-   setCapability("GL::Workaround::needsExplicitGenerateMipmap", false);
-   // When enabled, binds and unbinds a texture target before doing the depth buffer copy.  Failure to do
-   // so will cause a hard freeze on Mac OS 10.4 with a Radeon X1600
-   setCapability("GL::Workaround::X1600DepthBufferCopy", false);
-   // When enabled, does not copy the last column and row of the depth buffer in a depth buffer copy.  Failure
-   // to do so will cause a kernel panic on Mac OS 10.5(.1) with a Radeon HD 2600 (fixed in 10.5.2)
-   setCapability("GL::Workaround::HD2600DepthBufferCopy", false);
-   
-   // Certain Intel drivers have a divide by 0 crash if mipmaps are specified with
-   // glTexSubImage2D.
-   setCapability("GL::Workaround::noManualMips", false);
+   // Check for shader model 5.0
+   setCapability("GL_ARB_gpu_shader5", gglHasExtension(ARB_gpu_shader5));
+
+   // Check for texture storage
+   setCapability("GL_ARB_texture_storage", gglHasExtension(ARB_texture_storage));
+
+   // Check for sampler objects
+   setCapability("GL_ARB_sampler_objects", gglHasExtension(ARB_sampler_objects));
+
+   // Check for copy image support
+   setCapability("GL_ARB_copy_image", gglHasExtension(ARB_copy_image));
+
+   // Check for vertex attrib binding
+   setCapability("GL_ARB_vertex_attrib_binding", gglHasExtension(ARB_vertex_attrib_binding));
 }
 
 bool GFXGLCardProfiler::_queryCardCap(const String& query, U32& foundResult)

+ 7 - 5
Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h

@@ -20,7 +20,8 @@ public:
    }
 
    void init(U32 start, U32 end)
-   {         
+   {  
+      PROFILE_SCOPE(GFXGLQueryFence_issue);
       mStart = start;
       mEnd = end;
       mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
@@ -35,7 +36,8 @@ public:
    }
 
    void wait()
-   {      
+   {   
+      PROFILE_SCOPE(GFXGLQueryFence_block);
       GLbitfield waitFlags = 0;
       GLuint64 waitDuration = 0;
       while( 1 ) 
@@ -158,7 +160,7 @@ public:
       const U32 cSizeInMB = 10;
       mBufferSize = (cSizeInMB << 20);
 
-      if( gglHasExtension(ARB_buffer_storage) )
+      if( GFXGL->mCapabilities.bufferStorage )
       {      
          const GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
          glBufferStorage(mBinding, mBufferSize, NULL, flags);
@@ -198,7 +200,7 @@ public:
 
       outOffset = mBufferFreePos;
 
-      if( gglHasExtension(ARB_buffer_storage) )
+      if( GFXGL->mCapabilities.bufferStorage )
       {         
          outPtr = (U8*)(mBufferPtr) + mBufferFreePos; 
       }
@@ -227,7 +229,7 @@ public:
 
    void unlock()
    {
-      if( gglHasExtension(ARB_buffer_storage) )
+      if( GFXGL->mCapabilities.bufferStorage )
       {
          return;
       }

+ 17 - 1
Engine/source/gfx/gl/gfxGLDevice.cpp

@@ -140,10 +140,18 @@ void GFXGLDevice::initGLState()
    
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    
+   // [JTH 5/6/2016] GLSL 1.50 is really SM 4.0
    // Setting mPixelShaderVersion to 3.0 will allow Advanced Lighting to run.   
    mPixelShaderVersion = 3.0;
 
-   mSupportsAnisotropic = mCardProfiler->queryProfile( "GL::suppAnisotropic" );
+	// Set capability extensions.
+   mCapabilities.anisotropicFiltering = mCardProfiler->queryProfile("GL_EXT_texture_filter_anisotropic");
+   mCapabilities.bufferStorage = mCardProfiler->queryProfile("GL_ARB_buffer_storage");
+   mCapabilities.shaderModel5 = mCardProfiler->queryProfile("GL_ARB_gpu_shader5");
+   mCapabilities.textureStorage = mCardProfiler->queryProfile("GL_ARB_texture_storage");
+   mCapabilities.samplerObjects = mCardProfiler->queryProfile("GL_ARB_sampler_objects");
+   mCapabilities.copyImage = mCardProfiler->queryProfile("GL_ARB_copy_image");
+   mCapabilities.vertexAttributeBinding = mCardProfiler->queryProfile("GL_ARB_vertex_attrib_binding");
 
    String vendorStr = (const char*)glGetString( GL_VENDOR );
    if( vendorStr.find("NVIDIA", 0, String::NoCase | String::Left) != String::NPos)
@@ -216,6 +224,9 @@ GFXGLDevice::GFXGLDevice(U32 adapterIndex) :
       mCurrentVB_Divisor[i] = 0;
    }
 
+   // Initiailize capabilities to false.
+   memset(&mCapabilities, 0, sizeof(GLCapabilities));
+
    loadGLCore();
 
    GFXGLEnumTranslate::init();
@@ -325,6 +336,7 @@ void GFXGLDevice::resurrect()
 
 GFXVertexBuffer* GFXGLDevice::findVolatileVBO(U32 numVerts, const GFXVertexFormat *vertexFormat, U32 vertSize)
 {
+   PROFILE_SCOPE(GFXGLDevice_findVBPool);
    for(U32 i = 0; i < mVolatileVBs.size(); i++)
       if (  mVolatileVBs[i]->mNumVerts >= numVerts &&
             mVolatileVBs[i]->mVertexFormat.isEqual( *vertexFormat ) &&
@@ -333,6 +345,7 @@ GFXVertexBuffer* GFXGLDevice::findVolatileVBO(U32 numVerts, const GFXVertexForma
          return mVolatileVBs[i];
 
    // No existing VB, so create one
+   PROFILE_SCOPE(GFXGLDevice_createVBPool);
    StrongRefPtr<GFXGLVertexBuffer> buf(new GFXGLVertexBuffer(GFX, numVerts, vertexFormat, vertSize, GFXBufferTypeVolatile));
    buf->registerResourceWithDevice(this);
    mVolatileVBs.push_back(buf);
@@ -358,6 +371,7 @@ GFXVertexBuffer *GFXGLDevice::allocVertexBuffer(   U32 numVerts,
                                                    GFXBufferType bufferType,
                                                    void* data )  
 {
+   PROFILE_SCOPE(GFXGLDevice_allocVertexBuffer);
    if(bufferType == GFXBufferTypeVolatile)
       return findVolatileVBO(numVerts, vertexFormat, vertSize);
          
@@ -523,6 +537,7 @@ inline GLsizei GFXGLDevice::primCountToIndexCount(GFXPrimitiveType primType, U32
 
 GFXVertexDecl* GFXGLDevice::allocVertexDecl( const GFXVertexFormat *vertexFormat ) 
 {
+   PROFILE_SCOPE(GFXGLDevice_allocVertexDecl);
    typedef Map<void*, GFXGLVertexDecl> GFXGLVertexDeclMap;
    static GFXGLVertexDeclMap declMap;   
    GFXGLVertexDeclMap::Iterator itr = declMap.find( (void*)vertexFormat->getDescription().c_str() ); // description string are interned, safe to use c_str()
@@ -855,6 +870,7 @@ void GFXGLDevice::setShader(GFXShader *shader, bool force)
 
 void GFXGLDevice::setShaderConstBufferInternal(GFXShaderConstBuffer* buffer)
 {
+   PROFILE_SCOPE(GFXGLDevice_setShaderConstBufferInternal);
    static_cast<GFXGLShaderConstBuffer*>(buffer)->activate();
 }
 

+ 12 - 0
Engine/source/gfx/gl/gfxGLDevice.h

@@ -45,6 +45,18 @@ class GFXGLVertexDecl;
 class GFXGLDevice : public GFXDevice
 {
 public:
+   struct GLCapabilities
+   {
+      bool anisotropicFiltering;
+      bool bufferStorage;
+      bool shaderModel5;
+      bool textureStorage;
+      bool samplerObjects;
+      bool copyImage;
+      bool vertexAttributeBinding;
+   };
+   GLCapabilities mCapabilities;
+
    void zombify();
    void resurrect();
    GFXGLDevice(U32 adapterIndex);

+ 6 - 1
Engine/source/gfx/gl/gfxGLShader.cpp

@@ -23,6 +23,7 @@
 #include "platform/platform.h"
 #include "gfx/gl/gfxGLShader.h"
 #include "gfx/gl/gfxGLVertexAttribLocation.h"
+#include "gfx/gl/gfxGLDevice.h"
 
 #include "core/frameAllocator.h"
 #include "core/stream/fileStream.h"
@@ -344,6 +345,7 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* ma
 
 void GFXGLShaderConstBuffer::activate()
 {
+   PROFILE_SCOPE(GFXGLShaderConstBuffer_activate);
    mShader->setConstantsFromBuffer(this);
    mWasLost = false;
 }
@@ -394,6 +396,7 @@ void GFXGLShader::clearShaders()
 
 bool GFXGLShader::_init()
 {
+   PROFILE_SCOPE(GFXGLShader_Init);
    // Don't initialize empty shaders.
    if ( mVertexFile.isEmpty() && mPixelFile.isEmpty() )
       return false;
@@ -956,7 +959,7 @@ bool GFXGLShader::_loadShaderFromStream(  GLuint shader,
    buffers.push_back( dStrdup( versionDecl ) );
    lengths.push_back( dStrlen( versionDecl ) );
 
-   if(gglHasExtension(ARB_gpu_shader5))
+   if(GFXGL->mCapabilities.shaderModel5)
    {
       const char *extension = "#extension GL_ARB_gpu_shader5 : enable\r\n";
       buffers.push_back( dStrdup( extension ) );
@@ -1013,6 +1016,7 @@ bool GFXGLShader::initShader( const Torque::Path &file,
                               bool isVertex, 
                               const Vector<GFXShaderMacro> &macros )
 {
+   PROFILE_SCOPE(GFXGLShader_CompileShader);
    GLuint activeShader = glCreateShader(isVertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
    if(isVertex)
       mVertexShader = activeShader;
@@ -1072,6 +1076,7 @@ bool GFXGLShader::initShader( const Torque::Path &file,
 /// Returns our list of shader constants, the material can get this and just set the constants it knows about
 const Vector<GFXShaderConstDesc>& GFXGLShader::getShaderConstDesc() const
 {
+   PROFILE_SCOPE(GFXGLShader_GetShaderConstants);
    return mConstants;
 }
 

+ 3 - 2
Engine/source/gfx/gl/gfxGLStateBlock.cpp

@@ -39,7 +39,7 @@ GFXGLStateBlock::GFXGLStateBlock(const GFXStateBlockDesc& desc) :
    mDesc(desc),
    mCachedHashValue(desc.getHashValue())
 {
-    if( !gglHasExtension(ARB_sampler_objects) )
+    if( !GFXGL->mCapabilities.samplerObjects )
 	   return;
 
    static Map<GFXSamplerStateDesc, U32> mSamplersMap;
@@ -88,6 +88,7 @@ const GFXStateBlockDesc& GFXGLStateBlock::getDesc() const
 /// @param oldState  The current state, used to make sure we don't set redundant states on the device.  Pass NULL to reset all states.
 void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState)
 {
+   PROFILE_SCOPE(GFXGLStateBlock_Activate);
    // Big scary warning copied from Apple docs 
    // http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_performance/chapter_13_section_2.html#//apple_ref/doc/uid/TP40001987-CH213-SW12
    // Don't set a state that's already set. Once a feature is enabled, it does not need to be enabled again.
@@ -165,7 +166,7 @@ void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState)
 #undef CHECK_TOGGLE_STATE
 
    //sampler objects
-   if( gglHasExtension(ARB_sampler_objects) )
+   if( GFXGL->mCapabilities.samplerObjects )
    {
       for (U32 i = 0; i < getMin(getOwningDevice()->getNumSamplers(), (U32) TEXTURE_STAGE_COUNT); i++)
       {

+ 10 - 3
Engine/source/gfx/gl/gfxGLTextureManager.cpp

@@ -146,7 +146,7 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
 
     glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 );
     
-    if( gglHasExtension(ARB_texture_storage) )
+    if( GFXGL->mCapabilities.textureStorage )
     {
         if(binding == GL_TEXTURE_2D)
             glTexStorage2D( retTex->getBinding(), retTex->mMipLevels, GFXGLTextureInternalFormat[format], width, height );
@@ -234,6 +234,7 @@ static void _fastTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL)
    
    if(pDL->getFormat() == GFXFormatR8G8B8A8 || pDL->getFormat() == GFXFormatR8G8B8X8)
    {
+      PROFILE_SCOPE(Swizzle32_Upload);
       U8* pboMemory = (U8*)dMalloc(bufSize);
       GFX->getDeviceSwizzle32()->ToBuffer(pboMemory, pDL->getBits(0), bufSize);
       glBufferSubData(GL_PIXEL_UNPACK_BUFFER_ARB, 0, bufSize, pboMemory );
@@ -241,6 +242,7 @@ static void _fastTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL)
    }
    else
    {
+      PROFILE_SCOPE(SwizzleNull_Upload);
       glBufferSubData(GL_PIXEL_UNPACK_BUFFER_ARB, 0, bufSize, pDL->getBits(0) );
    }
    
@@ -262,6 +264,7 @@ static void _slowTextureLoad(GFXGLTextureObject* texture, GBitmap* pDL)
 
 bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)
 {
+   PROFILE_SCOPE(GFXGLTextureManager_loadTexture);
    GFXGLTextureObject *texture = static_cast<GFXGLTextureObject*>(aTexture);
    
    AssertFatal(texture->getBinding() == GL_TEXTURE_1D || texture->getBinding() == GL_TEXTURE_2D, 
@@ -291,6 +294,8 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)
 
 bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
 {
+   PROFILE_SCOPE(GFXGLTextureManager_loadTextureDDS);
+
    AssertFatal(!(dds->mFormat == GFXFormatDXT2 || dds->mFormat == GFXFormatDXT4), "GFXGLTextureManager::_loadTexture - OpenGL does not support DXT2 or DXT4 compressed textures");
    GFXGLTextureObject* texture = static_cast<GFXGLTextureObject*>(aTexture);
    
@@ -304,10 +309,11 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
    glBindTexture(texture->getBinding(), texture->getHandle());
    texture->mFormat = dds->mFormat;
    U32 numMips = dds->mSurfaces[0]->mMips.size();
-   if(GFX->getCardProfiler()->queryProfile("GL::Workaround::noManualMips"))
-      numMips = 1;
+
    for(U32 i = 0; i < numMips; i++)
    {
+      PROFILE_SCOPE(GFXGLTexMan_loadSurface);
+
       if(isCompressedFormat(dds->mFormat))
       {
          if((!isPow2(dds->getWidth()) || !isPow2(dds->getHeight())) && GFX->getCardProfiler()->queryProfile("GL::Workaround::noCompressedNPoTTextures"))
@@ -344,6 +350,7 @@ bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *dds)
 
 bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, void *raw)
 {
+   PROFILE_SCOPE(GFXGLTextureManager_loadTextureRaw);
    if(aTexture->getDepth() < 1)
       return false;
    

+ 8 - 3
Engine/source/gfx/gl/gfxGLTextureObject.cpp

@@ -96,6 +96,9 @@ void GFXGLTextureObject::unlock(U32 mipLevel)
    if(!mLockedRect.bits)
       return;
 
+   // I know this is in unlock, but in GL we actually do our submission in unlock.
+   PROFILE_SCOPE(GFXGLTextureObject_lockRT);
+
    PRESERVE_TEXTURE(mBinding);
    glBindTexture(mBinding, mHandle);
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, mBuffer);
@@ -175,6 +178,7 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
 
    glGetTexImage(mBinding, 0, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], orig);
    
+   PROFILE_START(GFXGLTextureObject_copyToBmp_pixCopy);
    for(int i = 0; i < srcPixelCount; ++i)
    {
       dest[0] = orig[0];
@@ -186,6 +190,7 @@ bool GFXGLTextureObject::copyToBmp(GBitmap * bmp)
       orig += srcBytesPerPixel;
       dest += dstBytesPerPixel;
    }
+   PROFILE_END();
 
    return true;
 }
@@ -211,7 +216,7 @@ void GFXGLTextureObject::bind(U32 textureUnit)
    glBindTexture(mBinding, mHandle);
    GFXGL->getOpenglCache()->setCacheBindedTex(textureUnit, mBinding, mHandle);
 
-   if( gglHasExtension(ARB_sampler_objects) )
+   if(GFXGL->mCapabilities.samplerObjects)
 	   return;
   
    GFXGLStateBlockRef sb = mGLDevice->getCurrentStateBlock();
@@ -298,8 +303,8 @@ void GFXGLTextureObject::reloadFromCache()
    else if(mBinding == GL_TEXTURE_1D)
 		glTexSubImage1D(mBinding, 0, 0, (mTextureSize.x > 1 ? mTextureSize.x : mTextureSize.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], mZombieCache);
    
-   if(GFX->getCardProfiler()->queryProfile("GL::Workaround::needsExplicitGenerateMipmap") && mMipLevels != 1)
-      glGenerateMipmapEXT(mBinding);
+   if(mMipLevels != 1)
+      glGenerateMipmap(mBinding);
       
    delete[] mZombieCache;
    mZombieCache = NULL;

+ 1 - 1
Engine/source/gfx/gl/gfxGLTextureTarget.cpp

@@ -410,7 +410,7 @@ void GFXGLTextureTarget::resolveTo(GFXTextureObject* obj)
    AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
    GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
 
-   if( gglHasExtension(ARB_copy_image) && mTargets[Color0]->isCompatible(glTexture) )
+   if( GFXGL->mCapabilities.copyImage && mTargets[Color0]->isCompatible(glTexture) )
    {
       GLenum binding = mTargets[Color0]->getBinding();      
       binding = (binding >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && binding <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) ? GL_TEXTURE_CUBE_MAP : binding;

+ 2 - 2
Engine/source/gfx/gl/gfxGLVertexBuffer.cpp

@@ -78,7 +78,7 @@ void GFXGLVertexBuffer::lock( U32 vertexStart, U32 vertexEnd, void **vertexPtr )
    if( mBufferType == GFXBufferTypeVolatile )
    {
       AssertFatal(vertexStart == 0, "");
-      if( gglHasExtension(ARB_vertex_attrib_binding) )
+      if( GFXGL->mCapabilities.vertexAttributeBinding )
       {
          getCircularVolatileVertexBuffer()->lock( mNumVerts * mVertexSize, 0, mBufferOffset, *vertexPtr );
       }
@@ -136,7 +136,7 @@ void GFXGLVertexBuffer::prepare()
 
 void GFXGLVertexBuffer::prepare(U32 stream, U32 divisor)
 {
-   if( gglHasExtension(ARB_vertex_attrib_binding) )
+   if( GFXGL->mCapabilities.vertexAttributeBinding )
    {      
       glBindVertexBuffer( stream, mBuffer, mBufferOffset, mVertexSize );
       glVertexBindingDivisor( stream, divisor );

+ 2 - 2
Engine/source/gfx/gl/gfxGLVertexDecl.cpp

@@ -15,7 +15,7 @@ void GFXGLVertexDecl::init(const GFXVertexFormat *format)
 void GFXGLVertexDecl::prepareVertexFormat() const
 {
    AssertFatal(mFormat, "GFXGLVertexDecl - Not inited");
-   if( gglHasExtension(ARB_vertex_attrib_binding) )
+   if( GFXGL->mCapabilities.vertexAttributeBinding )
    {
       for ( U32 i=0; i < glVerticesFormat.size(); i++ )
       {
@@ -36,7 +36,7 @@ void GFXGLVertexDecl::prepareBuffer_old(U32 stream, GLint mBuffer, GLint mDiviso
    PROFILE_SCOPE(GFXGLVertexDecl_prepare);
    AssertFatal(mFormat, "GFXGLVertexDecl - Not inited");
 
-   if( gglHasExtension(ARB_vertex_attrib_binding) )
+   if( GFXGL->mCapabilities.vertexAttributeBinding )
       return;   
 
 	// Bind the buffer...

+ 1 - 1
Engine/source/gfx/gl/gfxGLWindowTarget.cpp

@@ -78,7 +78,7 @@ void GFXGLWindowTarget::resolveTo(GFXTextureObject* obj)
    AssertFatal(dynamic_cast<GFXGLTextureObject*>(obj), "GFXGLTextureTarget::resolveTo - Incorrect type of texture, expected a GFXGLTextureObject");
    GFXGLTextureObject* glTexture = static_cast<GFXGLTextureObject*>(obj);
 
-   if( gglHasExtension(ARB_copy_image) )
+   if( GFXGL->mCapabilities.copyImage )
    {
       if(mBackBufferColorTex.getWidth() == glTexture->getWidth()
          && mBackBufferColorTex.getHeight() == glTexture->getHeight()

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

@@ -284,7 +284,8 @@ void GuiInspectorField::setData( const char* data, bool callbacks )
                   || type == TypeMatrixPosition
                   || type == TypeMatrixRotation
                   || type == TypeBox3F
-                  || type == TypeRectUV )
+                  || type == TypeRectUV
+                  || type == TypeRotationF)
          {
             //TODO: we should actually take strings into account and not chop things up between quotes
 

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

@@ -30,7 +30,6 @@ ImplementFeatureType( MFT_VertTransform, MFG_Transform, 0, true );
 
 ImplementFeatureType( MFT_TexAnim, MFG_PreTexture, 1.0f, true );
 ImplementFeatureType( MFT_Parallax, MFG_PreTexture, 2.0f, true );
-ImplementFeatureType( MFT_DiffuseVertColor, MFG_PreTexture, 3.0f, true );
 
 ImplementFeatureType( MFT_AccuScale, MFG_PreTexture, 4.0f, true );
 ImplementFeatureType( MFT_AccuDirection, MFG_PreTexture, 4.0f, true );
@@ -42,6 +41,7 @@ ImplementFeatureType( MFT_DiffuseMap, MFG_Texture, 2.0f, true );
 ImplementFeatureType( MFT_OverlayMap, MFG_Texture, 3.0f, true );
 ImplementFeatureType( MFT_DetailMap, MFG_Texture, 4.0f, true );
 ImplementFeatureType( MFT_DiffuseColor, MFG_Texture, 5.0f, true );
+ImplementFeatureType( MFT_DiffuseVertColor, MFG_Texture, 6.0f, true );
 ImplementFeatureType( MFT_AlphaTest, MFG_Texture, 7.0f, true );
 ImplementFeatureType( MFT_SpecularMap, MFG_Texture, 8.0f, true );
 ImplementFeatureType( MFT_NormalMap, MFG_Texture, 9.0f, true );

+ 2 - 1
Engine/source/materials/processedShaderMaterial.cpp

@@ -1153,7 +1153,8 @@ void ProcessedShaderMaterial::_setShaderConstants(SceneRenderState * state, cons
 
    // Deferred Shading: Determine Material Info Flags
    S32 matInfoFlags = 
-            (mMaterial->mEmissive[stageNum] ? 1 : 0);
+            (mMaterial->mEmissive[stageNum] ? 1 : 0) | //emissive
+            (mMaterial->mSubSurface[stageNum] ? 2 : 0); //subsurface
    mMaterial->mMatInfoFlags[stageNum] = matInfoFlags / 255.0f;
    shaderConsts->setSafe(handles->mMatInfoFlagsSC, mMaterial->mMatInfoFlags[stageNum]);   
    if( handles->mAccuScaleSC->isValid() )

+ 1 - 1
Engine/source/math/mBox.h

@@ -415,7 +415,7 @@ inline void Box3F::extend(const Point3F & p)
 #define EXTEND_AXIS(AXIS)    \
 if (p.AXIS < minExtents.AXIS)       \
    minExtents.AXIS = p.AXIS;        \
-else if (p.AXIS > maxExtents.AXIS)  \
+if (p.AXIS > maxExtents.AXIS)  \
    maxExtents.AXIS = p.AXIS;
 
    EXTEND_AXIS(x)

+ 3 - 0
Engine/source/math/mMath.h

@@ -48,5 +48,8 @@
 #ifndef _MEASE_H_
 #include "math/mEase.h"
 #endif
+#ifndef MROTATION_H
+#include "math/mRotation.h"
+#endif
 
 #endif //_MMATH_H_

+ 11 - 1
Engine/source/math/mPolyhedron.impl.h

@@ -385,6 +385,8 @@ U32 PolyhedronImpl< Base >::extractFace( U32 plane, IndexType* outIndices, U32 m
    // so it should be sufficiently fast to just loop over the original
    // set.
 
+   U32 indexItr = 0;
+
    do 
    {
       // Add the vertex for the current edge.
@@ -392,7 +394,15 @@ U32 PolyhedronImpl< Base >::extractFace( U32 plane, IndexType* outIndices, U32 m
       if( idx >= maxOutIndices )
          return 0;
 
-      outIndices[ idx ++ ] = currentVertex;
+      ++indexItr;
+
+      if (indexItr >= 3)
+      {
+         outIndices[idx++] = firstEdge->vertex[0];
+         indexItr = 0;
+      }
+
+      outIndices[idx++] = currentVertex;
 
       // Look for next edge.
 

+ 348 - 0
Engine/source/math/mRotation.cpp

@@ -0,0 +1,348 @@
+//-----------------------------------------------------------------------------
+// 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 "math/mRotation.h"
+#include "console/console.h"
+#include "console/engineAPI.h"
+
+#ifdef TORQUE_TESTS_ENABLED
+#include "testing/unitTesting.h"
+#endif
+
+//====================================================================
+//Eulers setup
+//====================================================================
+RotationF::RotationF(EulerF _euler, UnitFormat format)
+{
+   set(_euler.x, _euler.y, _euler.z, format);
+}
+
+RotationF::RotationF(F32 _x, F32 _y, F32 _z, UnitFormat format)
+{
+   set(_x, _y, _z, format);
+}
+
+void RotationF::set(EulerF _euler, UnitFormat format)
+{
+   x = format == Degrees ? mDegToRad(_euler.x) : _euler.x;
+   y = format == Degrees ? mDegToRad(_euler.y) : _euler.y;
+   z = format == Degrees ? mDegToRad(_euler.z) : _euler.z;
+
+   mRotationType = Euler;
+}
+
+void RotationF::set(F32 _x, F32 _y, F32 _z, UnitFormat format)
+{
+   EulerF tempEul;
+   if (format == Degrees)
+   {
+      tempEul.set(mDegToRad(_x), mDegToRad(_y), mDegToRad(_z));
+   }
+   else
+   {
+      tempEul.set(_x, _y, _z);
+   }
+
+   set(tempEul);
+}
+
+//====================================================================
+//AxisAngle setup
+//====================================================================
+RotationF::RotationF(AngAxisF _aa, UnitFormat format)
+{
+   set(_aa, format);
+}
+
+void RotationF::set(AngAxisF _aa, UnitFormat format)
+{
+   x = _aa.axis.x;
+   y = _aa.axis.y;
+   z = _aa.axis.z;
+
+   w = format == Degrees ? mDegToRad(_aa.angle) : _aa.angle;
+
+   mRotationType = AxisAngle;
+}
+
+//====================================================================
+//QuatF setup
+//====================================================================
+RotationF::RotationF(QuatF _quat)
+{
+   set(_quat);
+}
+
+void RotationF::set(QuatF _quat)
+{
+   AngAxisF tmpAA;
+   tmpAA.set(_quat);
+
+   set(tmpAA);
+}
+
+//====================================================================
+//MatrixF setup
+//====================================================================
+RotationF::RotationF(MatrixF _mat)
+{
+   set(_mat);
+}
+
+void RotationF::set(MatrixF _mat)
+{
+   set(_mat.toEuler());
+}
+
+//
+inline F32 RotationF::len() const
+{
+   return asEulerF().len();
+}
+
+inline void RotationF::interpolate(const RotationF& _from, const RotationF& _to, F32 _factor)
+{
+   QuatF tmpQuat;
+
+   tmpQuat.interpolate(_from.asQuatF(), _to.asQuatF(), _factor);
+
+   set(tmpQuat);
+}
+
+void RotationF::lookAt(const Point3F& _origin, const Point3F& _target, const Point3F& _up)
+{
+   MatrixF mat;
+
+   VectorF newForward = _target - _origin;
+   newForward.normalize();
+
+   VectorF up(0.0f, 0.0f, 1.0f);
+   VectorF axisX;
+   VectorF axisY = newForward;
+   VectorF axisZ;
+
+   if (_up != VectorF::Zero)
+      up = _up;
+
+   // Validate and normalize input:  
+   F32 lenSq;
+   lenSq = axisY.lenSquared();
+   if (lenSq < 0.000001f)
+   {
+      //degenerate forward vector
+      axisY.set(0.0f, 1.0f, 0.0f);
+   }
+   else
+   {
+      axisY /= mSqrt(lenSq);
+   }
+
+
+   lenSq = up.lenSquared();
+   if (lenSq < 0.000001f)
+   {
+      //degenerate up vector - too small
+      up.set(0.0f, 0.0f, 1.0f);
+   }
+   else
+   {
+      up /= mSqrt(lenSq);
+   }
+
+   if (fabsf(mDot(up, axisY)) > 0.9999f)
+   {
+      //degenerate up vector - same as forward
+      F32 tmp = up.x;
+      up.x = -up.y;
+      up.y = up.z;
+      up.z = tmp;
+   }
+
+   // construct the remaining axes:  
+   mCross(axisY, up, &axisX);
+   mCross(axisX, axisY, &axisZ);
+
+   mat.setColumn(0, axisX);
+   mat.setColumn(1, axisY);
+   mat.setColumn(2, axisZ);
+
+   set(mat);
+}
+
+//========================================================
+EulerF RotationF::asEulerF(UnitFormat _format) const
+{
+   if (mRotationType == Euler)
+   {
+      if (_format == Degrees)
+      {
+         return EulerF(mRadToDeg(x), mRadToDeg(y), mRadToDeg(z));
+      }
+      else
+      {
+         return EulerF(x, y, z);
+      }
+   }
+   else
+   {
+      EulerF returnEuler = asMatrixF().toEuler();
+
+      if (_format == Degrees)
+      {
+         returnEuler.x = mRadToDeg(returnEuler.x);
+         returnEuler.y = mRadToDeg(returnEuler.y);
+         returnEuler.z = mRadToDeg(returnEuler.z);
+      }
+
+      return returnEuler;
+   }
+}
+
+AngAxisF RotationF::asAxisAngle(UnitFormat format) const
+{
+   AngAxisF returnAA;
+
+   if (mRotationType == Euler)
+   {
+      returnAA.set(EulerF(x, y, z));
+   }
+   else
+   {
+      returnAA.set(Point3F(x, y, z), w);
+   }
+
+   if (format == Radians)
+   {
+      returnAA.angle = mDegToRad(returnAA.angle);
+   }
+
+   return returnAA;
+}
+
+MatrixF RotationF::asMatrixF() const
+{
+   MatrixF returnMat;
+   if (mRotationType == Euler)
+   {
+      returnMat.set(EulerF(x, y, z));
+   }
+   else
+   {
+      AngAxisF aa;
+      aa.set(Point3F(x, y, z), w);
+
+      aa.setMatrix(&returnMat);
+   }
+
+   return returnMat;
+}
+
+QuatF RotationF::asQuatF() const
+{
+   QuatF returnQuat;
+   if (mRotationType == Euler)
+   {
+      returnQuat.set(EulerF(x, y, z));
+   }
+   else
+   {
+      AngAxisF aa;
+      aa.set(Point3F(x, y, z), w);
+
+      returnQuat.set(aa);
+   }
+
+   return returnQuat;
+}
+
+void RotationF::normalize()
+{
+   if (mRotationType == Euler)
+   {
+      EulerF eul = EulerF(x, y, z);
+      eul.normalize();
+      set(eul);
+   }
+   else
+   {
+      QuatF quat;
+      quat.set(Point3F(x, y, z), w);
+
+      quat.normalize();
+
+      set(quat);
+   }
+}
+
+//Testing
+#ifdef TORQUE_TESTS_ENABLED
+TEST(Maths, RotationF_Calculations)
+{
+   //TODO: implement unit test
+};
+#endif
+
+DefineConsoleStaticMethod(Rotation, Add, RotationF, (RotationF a, RotationF b), ,
+   "Adds two rotations together.\n"
+   "@param a Rotation one."
+   "@param b Rotation two."
+   "@returns v sum of both rotations."
+   "@ingroup Math")
+{
+   return a + b;
+}
+
+DefineConsoleStaticMethod(Rotation, Subtract, RotationF, (RotationF a, RotationF b), ,
+   "Subtracts two rotations.\n"
+   "@param a Rotation one."
+   "@param b Rotation two."
+   "@returns v difference of both rotations."
+   "@ingroup Math")
+{
+   return a - b;
+}
+
+DefineConsoleStaticMethod(Rotation, Interpolate, RotationF, (RotationF a, RotationF b, F32 factor), ,
+   "Interpolates between two rotations.\n"
+   "@param a Rotation one."
+   "@param b Rotation two."
+   "@param factor The amount to interpolate between the two."
+   "@returns v, interpolated result."
+   "@ingroup Math")
+{
+   RotationF result;
+   result.interpolate(a, b, factor);
+   return result;
+}
+
+DefineConsoleStaticMethod(Rotation, LookAt, RotationF, (Point3F origin, Point3F target, Point3F up),
+   (Point3F(0, 0, 0), Point3F(0, 0, 0), Point3F(0, 0, 1)),
+   "Provides a rotation orientation to look at a target from a given position.\n"
+   "@param origin Position of the object doing the looking."
+   "@param target Position to be looked at."
+   "@param up The up angle to orient the rotation."
+   "@returns v orientation result."
+   "@ingroup Math")
+{
+   RotationF result;
+   result.lookAt(origin, target, up);
+   return result;
+}

+ 465 - 0
Engine/source/math/mRotation.h

@@ -0,0 +1,465 @@
+//-----------------------------------------------------------------------------
+// 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 MROTATION_H
+#define MROTATION_H
+
+#ifndef _MMATHFN_H_
+#include "math/mMathFn.h"
+#endif
+
+#ifndef _MPOINT3_H_
+#include "math/mPoint3.h"
+#endif
+
+#ifndef _MQUAT_H_
+#include "math/mQuat.h"
+#endif
+
+#ifndef _MMATRIX_H_
+#include "math/mMatrix.h"
+#endif
+
+#ifndef _MANGAXIS_H_
+#include "math/mAngAxis.h"
+#endif
+
+//------------------------------------------------------------------------------
+/// Rotation Interop Utility class
+///
+/// Useful for easily handling rotations/orientations in transforms while manipulating or converting between formats.
+class RotationF
+{
+   //-------------------------------------- Public data
+public:
+   F32 x;   ///< X co-ordinate.
+   F32 y;   ///< Y co-ordinate.
+   F32 z;   ///< Z co-ordinate.
+   F32 w;   ///< W co-ordinate.
+
+   enum RotationTypes
+   {
+      Euler = 0,
+      AxisAngle
+   };
+   RotationTypes mRotationType;
+
+   enum UnitFormat
+   {
+      Radians = 0,
+      Degrees
+   };
+
+   RotationF();               ///< Create an uninitialized point.
+   RotationF(const RotationF&); ///< Copy constructor.
+
+   //
+   //Eulers
+   RotationF(EulerF euler, UnitFormat format = Radians);
+   RotationF(F32 _x, F32 _y, F32 _z, UnitFormat format = Radians);
+
+   void set(EulerF euler, UnitFormat format = Radians);
+   void set(F32 _x, F32 _y, F32 _z, UnitFormat format = Radians);
+
+   //As with AxisAngles, we make the assumption here that if not told otherwise, inbound rotations are in Degrees.
+   RotationF operator=(const EulerF&);
+   RotationF operator-(const EulerF&) const;
+   RotationF operator+(const EulerF&) const;
+   RotationF& operator-=(const EulerF&);
+   RotationF& operator+=(const EulerF&);
+   S32 operator==(const EulerF&) const;
+   S32 operator!=(const EulerF&) const;
+
+   //
+   //AxisAngle
+   RotationF(AngAxisF aa, UnitFormat format = Radians);
+   void set(AngAxisF aa, UnitFormat format = Radians);
+
+   //As with Eulers, we make the assumption here that if not told otherwise, inbound rotations are in Degrees.
+   RotationF operator=(const AngAxisF&);
+   RotationF operator-(const AngAxisF&) const;
+   RotationF operator+(const AngAxisF&) const;
+   RotationF& operator-=(const AngAxisF&);
+   RotationF& operator+=(const AngAxisF&);
+   S32 operator==(const AngAxisF&) const;
+   S32 operator!=(const AngAxisF&) const;
+
+   //
+   //Quat
+   RotationF(QuatF quat);
+   void set(QuatF _quat);
+
+   RotationF operator=(const QuatF&);
+   RotationF operator-(const QuatF&) const;
+   RotationF operator+(const QuatF&) const;
+   RotationF& operator-=(const QuatF&);
+   RotationF& operator+=(const QuatF&);
+   S32 operator==(const QuatF&) const;
+   S32 operator!=(const QuatF&) const;
+
+   //
+   //Matrix
+   RotationF(MatrixF mat);
+   void set(MatrixF _mat);
+
+   RotationF operator=(const MatrixF&);
+   RotationF operator-(const MatrixF&) const;
+   RotationF operator+(const MatrixF&) const;
+   RotationF& operator-=(const MatrixF&);
+   RotationF& operator+=(const MatrixF&);
+   S32 operator==(const MatrixF&) const;
+   S32 operator!=(const MatrixF&) const;
+
+   //
+   void interpolate(const RotationF& _pt1, const RotationF& _pt2, F32 _factor);
+   void lookAt(const Point3F& _origin, const Point3F& _target, const Point3F& _up = Point3F(0, 0, 1));
+
+   F32 len() const;
+
+   void normalize();
+
+   //Non-converting operators
+   S32 operator ==(const RotationF &) const;
+   S32 operator !=(const RotationF &) const;
+
+   RotationF  operator+(const RotationF&) const;
+   RotationF& operator+=(const RotationF&);
+   RotationF  operator-(const RotationF&) const;
+   RotationF&  operator-=(const RotationF&);
+
+   RotationF& operator=(const RotationF&);
+
+   //Conversion stuffs
+   EulerF asEulerF(UnitFormat format = Radians) const;
+   AngAxisF asAxisAngle(UnitFormat format = Radians) const;
+   MatrixF asMatrixF() const;
+   QuatF asQuatF() const;
+};
+
+inline RotationF::RotationF()
+{
+   x = 0;
+   y = 0;
+   z = 0;
+   w = 0;
+
+   mRotationType = AxisAngle;
+}
+
+inline RotationF::RotationF(const RotationF& _copy)
+   : x(_copy.x), y(_copy.y), z(_copy.z), w(_copy.w), mRotationType(_copy.mRotationType)
+{}
+
+inline int RotationF::operator ==(const RotationF& _rotation) const
+{
+   return (x == _rotation.x && y == _rotation.y && z == _rotation.z && w == _rotation.w);
+}
+
+inline int RotationF::operator !=(const RotationF& _rotation) const
+{
+   return (x != _rotation.x || y != _rotation.y || z != _rotation.z || w != _rotation.w);
+}
+
+//When it comes to actually trying to add rotations, we, in fact, actually multiply their data together.
+//Since we're specifically operating on usability for RotationF, we'll operate on this, rather than the literal addition of the values
+inline RotationF& RotationF::operator +=(const RotationF& _rotation)
+{
+   if (mRotationType == Euler)
+   {
+      x += _rotation.x;
+      y += _rotation.y;
+      z += _rotation.z;
+   }
+   else
+   {
+      MatrixF tempMat = asMatrixF();
+      MatrixF tempMatAdd = _rotation.asMatrixF();
+
+      tempMat.mul(tempMatAdd);
+
+      this->set(tempMat);
+   }
+
+   return *this;
+}
+
+inline RotationF RotationF::operator +(const RotationF& _rotation) const
+{
+   RotationF result = *this;
+
+   if (mRotationType == Euler)
+   {
+      result.x += _rotation.x;
+      result.y += _rotation.y;
+      result.z += _rotation.z;
+   }
+   else
+   {
+      MatrixF tempMat = asMatrixF();
+      MatrixF tempMatAdd = _rotation.asMatrixF();
+
+      tempMat.mul(tempMatAdd);
+
+      result.set(tempMat);
+   }
+
+   return result;
+}
+
+//Much like addition, when subtracting, we're not literally subtracting the values, but infact multiplying the inverse.
+//This subtracts the rotation angles to get the difference
+inline RotationF& RotationF::operator -=(const RotationF& _rotation)
+{
+   if (mRotationType == Euler)
+   {
+      x -= _rotation.x;
+      y -= _rotation.y;
+      z -= _rotation.z;
+   }
+   else
+   {
+      MatrixF tempMat = asMatrixF();
+      MatrixF tempMatAdd = _rotation.asMatrixF();
+
+      tempMatAdd.inverse();
+
+      tempMat.mul(tempMatAdd);
+
+      this->set(tempMat);
+   }
+
+   return *this;
+}
+
+inline RotationF RotationF::operator -(const RotationF& _rotation) const
+{
+   RotationF result = *this;
+
+   if (mRotationType == Euler)
+   {
+      result.x += _rotation.x;
+      result.y += _rotation.y;
+      result.z += _rotation.z;
+   }
+   else
+   {
+      MatrixF tempMat = asMatrixF();
+      MatrixF tempMatAdd = _rotation.asMatrixF();
+      tempMatAdd.inverse();
+
+      tempMat.mul(tempMatAdd);
+
+      result.set(tempMat);
+   }
+
+   return result;
+}
+
+inline RotationF& RotationF::operator =(const RotationF& _rotation)
+{
+   x = _rotation.x;
+   y = _rotation.y;
+   z = _rotation.z;
+   w = _rotation.w;
+
+   mRotationType = _rotation.mRotationType;
+
+   return *this;
+}
+
+//====================================================================
+// Euler operators
+//====================================================================
+inline RotationF RotationF::operator=(const EulerF& _euler)
+{
+   return RotationF(_euler, Radians);
+}
+
+inline RotationF RotationF::operator-(const EulerF& _euler) const
+{
+   RotationF temp = *this;
+   temp -= RotationF(_euler, Radians);
+   return temp;
+}
+
+inline RotationF RotationF::operator+(const EulerF& _euler) const
+{
+   RotationF temp = *this;
+   temp += RotationF(_euler, Radians);
+   return temp;
+}
+
+inline RotationF& RotationF::operator-=(const EulerF& _euler)
+{
+   *this -= RotationF(_euler, Radians);
+   return *this;
+}
+
+inline RotationF& RotationF::operator+=(const EulerF& _euler)
+{
+   *this += RotationF(_euler, Radians);
+   return *this;
+}
+
+inline S32 RotationF::operator==(const EulerF& _euler) const
+{
+   return *this == RotationF(_euler);
+}
+
+inline S32 RotationF::operator!=(const EulerF& _euler) const
+{
+   return *this != RotationF(_euler);
+}
+
+//====================================================================
+// AxisAngle operators
+//====================================================================
+inline RotationF RotationF::operator=(const AngAxisF& _aa)
+{
+   return RotationF(_aa, Radians);
+}
+
+inline RotationF RotationF::operator-(const AngAxisF& _aa) const
+{
+   RotationF temp = *this;
+   temp -= RotationF(_aa, Radians);
+   return temp;
+}
+
+inline RotationF RotationF::operator+(const AngAxisF& _aa) const
+{
+   RotationF temp = *this;
+   temp += RotationF(_aa, Radians);
+   return temp;
+}
+
+inline RotationF& RotationF::operator-=(const AngAxisF& _aa)
+{
+   *this -= RotationF(_aa, Radians);
+   return *this;
+}
+
+inline RotationF& RotationF::operator+=(const AngAxisF& _aa)
+{
+   *this += RotationF(_aa, Radians);
+   return *this;
+}
+
+inline S32 RotationF::operator==(const AngAxisF& _aa) const
+{
+   return *this == RotationF(_aa);
+}
+
+inline S32 RotationF::operator!=(const AngAxisF& _aa) const
+{
+   return *this != RotationF(_aa);
+}
+
+//====================================================================
+// QuatF operators
+//====================================================================
+inline RotationF RotationF::operator=(const QuatF& _quat)
+{
+   return RotationF(_quat);
+}
+
+inline RotationF RotationF::operator-(const QuatF& _quat) const
+{
+   RotationF temp = *this;
+   temp -= RotationF(_quat);
+   return temp;
+}
+
+inline RotationF RotationF::operator+(const QuatF& _quat) const
+{
+   RotationF temp = *this;
+   temp += RotationF(_quat);
+   return temp;
+}
+
+inline RotationF& RotationF::operator-=(const QuatF& _quat)
+{
+   *this -= RotationF(_quat);
+   return *this;
+}
+
+inline RotationF& RotationF::operator+=(const QuatF& _quat)
+{
+   *this += RotationF(_quat);
+   return *this;
+}
+
+inline S32 RotationF::operator==(const QuatF& _quat) const
+{
+   return *this == RotationF(_quat);
+}
+
+inline S32 RotationF::operator!=(const QuatF& _quat) const
+{
+   return *this != RotationF(_quat);
+}
+
+//====================================================================
+// MatrixF operators
+//====================================================================
+inline RotationF RotationF::operator=(const MatrixF& _mat)
+{
+   return RotationF(_mat);
+}
+
+inline RotationF RotationF::operator-(const MatrixF& _mat) const
+{
+   RotationF temp = *this;
+   temp -= RotationF(_mat);
+   return temp;
+}
+
+inline RotationF RotationF::operator+(const MatrixF& _mat) const
+{
+   RotationF temp = *this;
+   temp += RotationF(_mat);
+   return temp;
+}
+
+inline RotationF& RotationF::operator-=(const MatrixF& _mat)
+{
+   *this -= RotationF(_mat);
+   return *this;
+}
+
+inline RotationF& RotationF::operator+=(const MatrixF& _mat)
+{
+   *this += RotationF(_mat);
+   return *this;
+}
+
+inline S32 RotationF::operator==(const MatrixF& _mat) const
+{
+   return *this == RotationF(_mat);
+}
+
+inline S32 RotationF::operator!=(const MatrixF& _mat) const
+{
+   return *this != RotationF(_mat);
+}
+
+#endif // MROTATION_H

+ 24 - 0
Engine/source/math/mathIO.h

@@ -149,6 +149,20 @@ inline bool mathRead(Stream& stream, EaseF* e)
    return success;
 }
 
+inline bool mathRead(Stream& stream, RotationF* e)
+{
+   bool success = stream.read(&e->x);
+   success &= stream.read(&e->y);
+   success &= stream.read(&e->z);
+   success &= stream.read(&e->w);
+
+   U32 rotType;
+   success &= stream.read(&rotType);
+   e->mRotationType = (RotationF::RotationTypes)rotType;
+
+   return success;
+}
+
 //------------------------------------------------------------------------------
 //-------------------------------------- WRITING
 //
@@ -263,5 +277,15 @@ inline bool mathWrite(Stream& stream, const EaseF& e)
    return success;
 }
 
+inline bool mathWrite(Stream& stream, const RotationF& e)
+{
+   bool success = stream.write(e.x);
+   success &= stream.write(e.y);
+   success &= stream.write(e.z);
+   success &= stream.write(e.w);
+   success &= stream.write(e.mRotationType);
+   return success;;
+}
+
 #endif //_MATHIO_H_
 

+ 58 - 2
Engine/source/math/mathTypes.cpp

@@ -36,7 +36,7 @@
 #include "math/mRandom.h"
 #include "math/mEase.h"
 #include "math/mathUtils.h"
-
+#include "math/mRotation.h"
 #include "core/strings/stringUnit.h"
 
 IMPLEMENT_SCOPE( MathTypes, Math,, "" );
@@ -113,7 +113,14 @@ IMPLEMENT_STRUCT( EaseF,
    EaseF, MathTypes,
    "" )
 END_IMPLEMENT_STRUCT;
-
+IMPLEMENT_STRUCT(RotationF,
+   RotationF, MathTypes,
+   "")
+   FIELD(x, x, 1, "X coordinate.")
+   FIELD(y, y, 1, "Y coordinate.")
+   FIELD(z, z, 1, "Z coordinate.")
+   FIELD(w, w, 1, "W coordinate.")
+END_IMPLEMENT_STRUCT;
 
 //-----------------------------------------------------------------------------
 // TypePoint2I
@@ -572,6 +579,55 @@ ConsoleSetType( TypeEaseF )
    }
 }
 
+//-----------------------------------------------------------------------------
+// TypeRotationF
+//-----------------------------------------------------------------------------
+ConsoleType(RotationF, TypeRotationF, RotationF, "")
+ImplementConsoleTypeCasters( TypeRotationF, RotationF )
+
+ConsoleGetType(TypeRotationF)
+{
+   RotationF *pt = (RotationF *)dptr;
+   static const U32 bufSize = 256;
+   char* returnBuffer = Con::getReturnBuffer(bufSize);
+
+   EulerF out = pt->asEulerF(RotationF::Degrees);
+   dSprintf(returnBuffer, bufSize, "%g %g %g", out.x, out.y, out.z);
+
+   return returnBuffer;
+}
+
+ConsoleSetType(TypeRotationF)
+{
+   if (argc == 1)
+   {
+      U32 elements = StringUnit::getUnitCount(argv[0], " \t\n");
+      if (elements == 3)
+      {
+         EulerF in;
+         dSscanf(argv[0], "%g %g %g", &in.x, &in.y, &in.z);
+         ((RotationF *)dptr)->set(in, RotationF::Degrees);
+      }
+      else
+      {
+         AngAxisF in;
+         dSscanf(argv[0], "%g %g %g %g", &in.axis.x, &in.axis.y, &in.axis.z, &in.angle);
+         ((RotationF *)dptr)->set(in, RotationF::Degrees);
+      }
+   }
+   else if (argc == 3)
+   {
+      EulerF in(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2]));
+      ((RotationF *)dptr)->set(in, RotationF::Degrees);
+   }
+   else if (argc == 4)
+   {
+      AngAxisF in(Point3F(dAtof(argv[0]), dAtof(argv[1]), dAtof(argv[2])), dAtof(argv[3]));
+      ((RotationF *)dptr)->set(in, RotationF::Degrees);
+   }
+   else
+      Con::printf("RotationF must be set as { x, y, z, w } or \"x y z w\"");
+}
 
 //-----------------------------------------------------------------------------
 

+ 3 - 2
Engine/source/math/mathTypes.h

@@ -43,7 +43,7 @@ class Box3F;
 class EaseF;
 class AngAxisF;
 class TransformF;
-
+class RotationF;
 
 DECLARE_SCOPE( MathTypes );
 
@@ -60,6 +60,7 @@ DECLARE_STRUCT( AngAxisF );
 DECLARE_STRUCT( TransformF );
 DECLARE_STRUCT( Box3F );
 DECLARE_STRUCT( EaseF );
+DECLARE_STRUCT(RotationF);
 
 
 // Legacy console types.
@@ -77,6 +78,6 @@ DefineConsoleType( TypeAngAxisF, AngAxisF )
 DefineConsoleType( TypeTransformF, TransformF )
 DefineConsoleType( TypeBox3F, Box3F )
 DefineConsoleType( TypeEaseF, EaseF )
-
+DefineConsoleType(TypeRotationF, RotationF)
 
 #endif

+ 6 - 11
Engine/source/math/mathUtils.cpp

@@ -30,7 +30,6 @@
 #include "platform/profiler.h"
 #include "core/tAlgorithm.h"
 
-#include "gfx/gfxDevice.h"
 namespace MathUtils
 {
 
@@ -1450,8 +1449,6 @@ void makeProjection( MatrixF *outMatrix,
                      F32 farPlane,
                      bool gfxRotate )
 {
-   bool isGL = GFX->getAdapterType() == OpenGL;
-
    Point4F row;
    row.x = 2.0*nearPlane / (right-left);
    row.y = 0.0;
@@ -1467,13 +1464,13 @@ void makeProjection( MatrixF *outMatrix,
 
    row.x = (left+right) / (right-left);
    row.y = (top+bottom) / (top-bottom);
-   row.z = isGL ? -(farPlane + nearPlane) / (farPlane - nearPlane) : farPlane / (nearPlane - farPlane);
+   row.z = farPlane / (nearPlane - farPlane);
    row.w = -1.0;
    outMatrix->setRow( 2, row );
 
    row.x = 0.0;
    row.y = 0.0;
-   row.z = isGL ? 2 * nearPlane * farPlane / (nearPlane - farPlane)  : nearPlane * farPlane / (nearPlane - farPlane);
+   row.z = nearPlane * farPlane / (nearPlane - farPlane);
    row.w = 0.0;
    outMatrix->setRow( 3, row );
 
@@ -1494,8 +1491,6 @@ void makeOrthoProjection(  MatrixF *outMatrix,
                            F32 farPlane,
                            bool gfxRotate )
 {
-   bool isGL = GFX->getAdapterType() == OpenGL;
-
    Point4F row;
    row.x = 2.0f / (right - left);
    row.y = 0.0f;
@@ -1513,15 +1508,15 @@ void makeOrthoProjection(  MatrixF *outMatrix,
    row.y = 0.0f;
    row.w = 0.0f;
 
-   // This needs to be modified to work with OpenGL (d3d has 0..1 
-   // projection for z, vs -1..1 in OpenGL)
-   row.z = isGL ? 2.0f / (nearPlane - farPlane) : 1.0f / (nearPlane - farPlane);
+   //Unlike D3D, which has a 0-1 range, OpenGL uses a -1-1 range. 
+   //However, epoxy internally handles the swap, so the math here is the same for both APIs
+   row.z = 1.0f / (nearPlane - farPlane);
 
    outMatrix->setRow( 2, row );
 
    row.x = (left + right) / (left - right);
    row.y = (top + bottom) / (bottom - top);
-   row.z = isGL ? (nearPlane + farPlane) / (nearPlane - farPlane) : nearPlane / (nearPlane - farPlane);
+   row.z = nearPlane / (nearPlane - farPlane);
    row.w = 1.0f;
    outMatrix->setRow( 3, row );
 

+ 13 - 1
Engine/source/navigation/navMesh.cpp

@@ -145,6 +145,17 @@ DefineConsoleFunction(NavMeshUpdateAroundObject, void, (S32 objid, bool remove),
       obj->enableCollision();
 }
 
+
+DefineConsoleFunction(NavMeshIgnore, void, (S32 objid, bool _ignore), (0, true),
+   "@brief Flag this object as not generating a navmesh result.")
+{
+   SceneObject *obj;
+   if(!Sim::findObject(objid, obj))
+      return;
+
+      obj->mPathfindingIgnore = _ignore;
+}
+
 DefineConsoleFunction(NavMeshUpdateOne, void, (S32 meshid, S32 objid, bool remove), (0, 0, false),
    "@brief Update all tiles in a given NavMesh that intersect the given object's world box.")
 {
@@ -839,6 +850,7 @@ void NavMesh::buildNextTile()
 static void buildCallback(SceneObject* object,void *key)
 {
    SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key);
+   if (!object->mPathfindingIgnore)
    object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere);
 }
 
@@ -861,7 +873,7 @@ unsigned char *NavMesh::buildTileData(const Tile &tile, TileData &data, U32 &dat
    data.geom.clear();
    info.polyList = &data.geom;
    info.key = this;
-   getContainer()->findObjects(box, StaticShapeObjectType | TerrainObjectType, buildCallback, &info);
+   getContainer()->findObjects(box, StaticObjectType | DynamicShapeObjectType, buildCallback, &info);
 
    // Parse water objects into the same list, but remember how much geometry was /not/ water.
    U32 nonWaterVertCount = data.geom.getVertCount();

+ 51 - 19
Engine/source/platform/nativeDialogs/fileDialog.cpp

@@ -184,40 +184,63 @@ static const U32 convertUTF16toUTF8DoubleNULL(const UTF16 *unistring, UTF8  *out
 //
 bool FileDialog::Execute()
 {
-   String suffix;
+   String strippedFilters;
 
    U32 filtersCount = StringUnit::getUnitCount(mData.mFilters, "|");
 
    for (U32 i = 1; i < filtersCount; ++i)
    {
       //The first of each pair is the name, which we'll skip because NFD doesn't support named filters atm
-      const char *filter = StringUnit::getUnit(mData.mFilters, i, "|");
+      String filter = StringUnit::getUnit(mData.mFilters, i, "|");
 
-      if (!dStrcmp(filter, "*.*"))
+      if (!dStrcmp(filter.c_str(), "*.*"))
          continue;
 
-      U32 c = 2;
-      const char* tmpchr = &filter[c];
-      String tString = String(tmpchr);
-      tString.ToLower(tString);
-      suffix += tString;
-      suffix += String(",");
-      suffix += tString.ToUpper(tString);
+      U32 subFilterCount = StringUnit::getUnitCount(filter, ";");
+
+      //if we have a 'super filter', break it down to sub-options as well
+      if (subFilterCount > 1)
+      {
+         String suffixFilter;
+         String subFilters;
+
+         for (U32 f = 0; f < subFilterCount; ++f)
+         {
+            String subFilter = StringUnit::getUnit(filter, f, ";");
+
+            suffixFilter += String::ToLower(subFilter) + "," + String::ToUpper(subFilter) + ",";
+            subFilters += String::ToLower(subFilter) + "," + String::ToUpper(subFilter) + ";";
+         }
+
+         suffixFilter = suffixFilter.substr(0, suffixFilter.length() - 1);
+         suffixFilter += ";";
+
+         strippedFilters += suffixFilter + subFilters;
+      }
+      else //otherwise, just add the filter
+      {
+         strippedFilters += String::ToLower(filter) + "," + String::ToUpper(filter) + ";";
+      }
 
       ++i;
-      if (i < filtersCount-2)
-         suffix += String(";");
+      if (i < filtersCount - 2)
+         strippedFilters += String(";");
    }
-   String strippedFilters = suffix;
-   strippedFilters.replace(";",",");
-      strippedFilters += String(";") + suffix;
+
+   //strip the last character, if it's unneeded
+   if (strippedFilters.endsWith(";"))
+   {
+      strippedFilters = strippedFilters.substr(0, strippedFilters.length() - 1);
+   }
+
+   strippedFilters.replace("*.", "");
 
    // Get the current working directory, so we can back up to it once Windows has
    // done its craziness and messed with it.
    StringTableEntry cwd = Platform::getCurrentDirectory();
    if (mData.mDefaultPath == StringTable->lookup("") || !Platform::isDirectory(mData.mDefaultPath))
       mData.mDefaultPath = cwd;
-
+   String rootDir = String(cwd);
    // Execute Dialog (Blocking Call)
    nfdchar_t *outPath = NULL;
    nfdpathset_t pathSet;
@@ -226,6 +249,7 @@ bool FileDialog::Execute()
    String defaultPath = String(mData.mDefaultPath);
 #if defined(TORQUE_OS_WIN)
    defaultPath.replace("/", "\\");
+   rootDir.replace("/", "\\");
 #endif
 
    if (mData.mStyle & FileDialogData::FDS_OPEN)
@@ -235,6 +259,15 @@ bool FileDialog::Execute()
    else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES)
       result = NFD_OpenDialogMultiple(strippedFilters.c_str(), defaultPath.c_str(), &pathSet);
 
+   if (result == NFD_CANCEL)
+   {
+      return false;
+   }
+
+   String resultPath = String(outPath).replace(rootDir, String(""));
+   resultPath = resultPath.replace(0, 1, String("")).c_str(); //kill '\\' prefix
+   resultPath = resultPath.replace(String("\\"), String("/"));
+
    // Did we select a file?
    if (result != NFD_OKAY)
    {
@@ -245,7 +278,7 @@ bool FileDialog::Execute()
    if (mData.mStyle & FileDialogData::FDS_OPEN || mData.mStyle & FileDialogData::FDS_SAVE)
    {
       // Single file selection, do it the easy way
-      mData.mFile = StringTable->insert(outPath);
+      mData.mFile = Platform::makeRelativePathName(resultPath.c_str(), NULL);
    }
    else if (mData.mStyle & FileDialogData::FDS_MULTIPLEFILES)
    {
@@ -265,14 +298,13 @@ bool FileDialog::Execute()
       else
       {
          //nope, just one file, so set it as normal
-         setDataField(StringTable->insert("files"), "0", outPath);
+         setDataField(StringTable->insert("files"), "0", Platform::makeRelativePathName(resultPath.c_str(), NULL));
          setDataField(StringTable->insert("fileCount"), NULL, "1");
       }
    }
 
    // Return success.
    return true;
-
 }
 
 DefineEngineMethod(FileDialog, Execute, bool, (), ,

+ 1 - 0
Engine/source/scene/sceneObject.cpp

@@ -144,6 +144,7 @@ SceneObject::SceneObject()
    mIsScopeAlways = false;
 
    mAccuTex = NULL;
+   mPathfindingIgnore = false;
 }
 
 //-----------------------------------------------------------------------------

+ 1 - 0
Engine/source/scene/sceneObject.h

@@ -371,6 +371,7 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce
 
       SceneObject();
       virtual ~SceneObject();
+      bool mPathfindingIgnore;
 
       /// Triggered when a SceneObject onAdd is called.
       static Signal< void( SceneObject* ) > smSceneObjectAdd;

+ 5 - 2
Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp

@@ -1194,7 +1194,10 @@ void DiffuseVertColorFeatureGLSL::processPix(   Vector<ShaderComponent*> &compon
    }
    
    MultiLine* meta = new MultiLine;
-   meta->addStatement( new GenOp( "   @;\r\n", assignColor( vertColor, Material::Mul ) ) );
+   if (fd.features[MFT_isDeferred])
+      meta->addStatement(new GenOp("   @;\r\n", assignColor(vertColor, Material::Mul, NULL, ShaderFeature::RenderTarget1)));
+   else
+      meta->addStatement(new GenOp("   @;\r\n", assignColor(vertColor, Material::Mul)));
    output = meta;
 }
 
@@ -2805,7 +2808,7 @@ void DeferredSkyGLSL::processVert( Vector<ShaderComponent*> &componentList,
 {
    Var *outPosition = (Var*)LangElement::find( "gl_Position" );
    MultiLine *meta = new MultiLine;
-   meta->addStatement( new GenOp( "   @.w = @.z;\r\n", outPosition, outPosition ) );
+   //meta->addStatement( new GenOp( "   @.w = @.z;\r\n", outPosition, outPosition ) );
 
    output = meta;
 }

+ 5 - 2
Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp

@@ -1258,7 +1258,10 @@ void DiffuseVertColorFeatureHLSL::processPix(   Vector<ShaderComponent*> &compon
    }
    
    MultiLine* meta = new MultiLine;
-   meta->addStatement( new GenOp( "   @;\r\n", assignColor( vertColor, Material::Mul ) ) );
+   if (fd.features[MFT_isDeferred])
+      meta->addStatement(new GenOp("   @;\r\n", assignColor(vertColor, Material::Mul, NULL, ShaderFeature::RenderTarget1)));
+   else
+      meta->addStatement(new GenOp("   @;\r\n", assignColor(vertColor, Material::Mul)));
    output = meta;
 }
 
@@ -3000,7 +3003,7 @@ void DeferredSkyHLSL::processVert( Vector<ShaderComponent*> &componentList,
 {
    Var *outPosition = (Var*)LangElement::find( "hpos" );
    MultiLine *meta = new MultiLine;
-   meta->addStatement( new GenOp( "   @.w = @.z;\r\n", outPosition, outPosition ) );
+   //meta->addStatement( new GenOp( "   @.w = @.z;\r\n", outPosition, outPosition ) );
 
    output = meta;
 }

+ 3 - 1
Templates/Empty/game/core/scripts/client/defaults.cs

@@ -73,7 +73,9 @@ $pref::Video::disableCubemapping = false;
 ///
 $pref::Video::disableParallaxMapping = false;
 
-$pref::Video::Gamma = 1.0;
+$pref::Video::Gamma = 2.2;
+$pref::Video::Contrast = 1.0;
+$pref::Video::Brightness = 0;
 
 // Console-friendly defaults
 if($platform $= "xenon")

+ 147 - 0
Templates/Empty/game/core/scripts/client/lighting/advanced/deferredShading.cs

@@ -0,0 +1,147 @@
+singleton ShaderData( ClearGBufferShader )
+{
+   DXVertexShaderFile = "shaders/common/lighting/advanced/deferredClearGBufferV.hlsl";
+   DXPixelShaderFile  = "shaders/common/lighting/advanced/deferredClearGBufferP.hlsl";
+
+   OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
+   OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/deferredClearGBufferP.glsl";
+
+   pixVersion = 2.0;   
+};
+
+singleton ShaderData( DeferredColorShader )
+{
+   DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
+   DXPixelShaderFile  = "shaders/common/lighting/advanced/deferredColorShaderP.hlsl";
+   
+   OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
+   OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/deferredColorShaderP.glsl";
+
+   pixVersion = 2.0;   
+};
+
+// Primary Deferred Shader
+new GFXStateBlockData( AL_DeferredShadingState : PFX_DefaultStateBlock )
+{  
+   cullMode = GFXCullNone;
+   
+   blendDefined = true;
+   blendEnable = true; 
+   blendSrc = GFXBlendSrcAlpha;
+   blendDest = GFXBlendInvSrcAlpha;
+   
+   samplersDefined = true;
+   samplerStates[0] = SamplerWrapLinear;
+   samplerStates[1] = SamplerWrapLinear;
+   samplerStates[2] = SamplerWrapLinear;
+   samplerStates[3] = SamplerWrapLinear;
+};
+
+new ShaderData( AL_DeferredShader )
+{
+   DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
+   DXPixelShaderFile  = "shaders/common/lighting/advanced/deferredShadingP.hlsl";
+   
+   OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
+   OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/deferredShadingP.glsl";
+
+   samplerNames[0] = "colorBufferTex";
+   samplerNames[1] = "lightPrePassTex";
+   samplerNames[2] = "matInfoTex";
+   samplerNames[3] = "prepassTex";
+   
+   pixVersion = 2.0;
+};
+
+singleton PostEffect( AL_DeferredShading )
+{
+   renderTime = "PFXAfterBin";
+   renderBin = "SkyBin";
+   shader = AL_DeferredShader;
+   stateBlock = AL_DeferredShadingState;
+   texture[0] = "#color";
+   texture[1] = "#lightinfo";
+   texture[2] = "#matinfo";
+   texture[3] = "#prepass";
+   
+   target = "$backBuffer";
+   renderPriority = 10000;
+   allowReflectPass = true;
+};
+
+// Debug Shaders.
+new ShaderData( AL_ColorBufferShader )
+{
+   DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
+   DXPixelShaderFile  = "shaders/common/lighting/advanced/dbgColorBufferP.hlsl";
+   
+   OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
+   OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/dbgColorBufferP.glsl";
+
+   samplerNames[0] = "colorBufferTex";
+   pixVersion = 2.0;
+};
+
+singleton PostEffect( AL_ColorBufferVisualize )
+{   
+   shader = AL_ColorBufferShader;
+   stateBlock = AL_DefaultVisualizeState;
+   texture[0] = "#color";
+   target = "$backBuffer";
+   renderPriority = 9999;
+};
+
+/// Toggles the visualization of the AL lighting specular power buffer.
+function toggleColorBufferViz( %enable )
+{   
+   if ( %enable $= "" )
+   {
+      $AL_ColorBufferShaderVar = AL_ColorBufferVisualize.isEnabled() ? false : true;
+      AL_ColorBufferVisualize.toggle();
+   }
+   else if ( %enable )
+   {
+      AL_DeferredShading.disable();
+      AL_ColorBufferVisualize.enable();
+   }
+   else if ( !%enable )
+   {
+      AL_ColorBufferVisualize.disable();    
+      AL_DeferredShading.enable();
+   }
+}
+
+new ShaderData( AL_SpecMapShader )
+{
+   DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl";
+   DXPixelShaderFile  = "shaders/common/lighting/advanced/dbgSpecMapVisualizeP.hlsl";
+
+   OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
+   OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/dbgSpecMapVisualizeP.glsl";
+
+   samplerNames[0] = "matinfoTex";
+   pixVersion = 2.0;
+};
+
+singleton PostEffect( AL_SpecMapVisualize )
+{   
+   shader = AL_SpecMapShader;
+   stateBlock = AL_DefaultVisualizeState;
+   texture[0] = "#matinfo";
+   target = "$backBuffer";
+   renderPriority = 9999;
+};
+
+/// Toggles the visualization of the AL lighting specular power buffer.
+function toggleSpecMapViz( %enable )
+{   
+   if ( %enable $= "" )
+   {
+      $AL_SpecMapShaderVar = AL_SpecMapVisualize.isEnabled() ? false : true;
+      AL_SpecMapVisualize.toggle();
+   }
+   else if ( %enable )
+      AL_SpecMapVisualize.enable();
+   else if ( !%enable )
+      AL_SpecMapVisualize.disable();    
+}

+ 7 - 0
Templates/Empty/game/core/scripts/client/lighting/advanced/init.cs

@@ -43,6 +43,7 @@ exec( "./shaders.cs" );
 exec( "./lightViz.cs" );
 exec( "./shadowViz.cs" );
 exec( "./shadowViz.gui" );
+exec( "./deferredShading.cs" );
 
 function onActivateAdvancedLM()
 {
@@ -58,12 +59,18 @@ function onActivateAdvancedLM()
    // Enable the offscreen target so that AL will work
    // with MSAA back buffers and for HDR rendering.   
    AL_FormatToken.enable();
+   
+   // Activate Deferred Shading
+   AL_DeferredShading.enable();
 }
 
 function onDeactivateAdvancedLM()
 {
    // Disable the offscreen render target.
    AL_FormatToken.disable();
+   
+   // Deactivate Deferred Shading
+   AL_DeferredShading.disable();
 }
 
 function setAdvancedLighting()

+ 17 - 4
Templates/Empty/game/core/scripts/client/lighting/advanced/lightViz.cs

@@ -56,7 +56,7 @@ new ShaderData( AL_DepthVisualizeShader )
    OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
    OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/dbgDepthVisualizeP.glsl";
 
-   samplerNames[0] = "prepassBuffer";
+   samplerNames[0] = "prepassTex";
    samplerNames[1] = "depthViz";
 
    pixVersion = 2.0;
@@ -113,7 +113,7 @@ new ShaderData( AL_NormalsVisualizeShader )
    OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
    OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/dbgNormalVisualizeP.glsl";
    
-   samplerNames[0] = "prepassBuffer";
+   samplerNames[0] = "prepassTex";
    
    pixVersion = 2.0;
 };
@@ -149,7 +149,7 @@ new ShaderData( AL_LightColorVisualizeShader )
    OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
    OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/dbgLightColorVisualizeP.glsl";
    
-   samplerNames[0] = "lightInfoBuffer";
+   samplerNames[0] = "lightPrePassTex";
    
    pixVersion = 2.0;
 };
@@ -184,7 +184,7 @@ new ShaderData( AL_LightSpecularVisualizeShader )
    OGLVertexShaderFile = "shaders/common/postFx/gl/postFxV.glsl";
    OGLPixelShaderFile  = "shaders/common/lighting/advanced/gl/dbgLightSpecularVisualizeP.glsl";
    
-   samplerNames[0] = "lightInfoBuffer";
+   samplerNames[0] = "lightPrePassTex";
    
    pixVersion = 2.0;
 };
@@ -280,3 +280,16 @@ function toggleLightSpecularViz( %enable )
       AL_LightSpecularVisualize.disable();    
 }
 
+function toggleBackbufferViz( %enable )
+{   
+   if ( %enable $= "" )
+   {
+      $AL_BackbufferVisualizeVar = AL_DeferredShading.isEnabled() ? true : false;
+      AL_DeferredShading.toggle();
+   }
+   else if ( %enable )
+      AL_DeferredShading.disable();
+   else if ( !%enable )
+      AL_DeferredShading.enable();    
+}
+

+ 31 - 5
Templates/Empty/game/core/scripts/client/lighting/advanced/shaders.cs

@@ -36,9 +36,14 @@ new GFXStateBlockData( AL_VectorLightState )
 
    samplersDefined = true;
    samplerStates[0] = SamplerClampPoint;  // G-buffer
+   mSamplerNames[0] = "prePassBuffer";
    samplerStates[1] = SamplerClampPoint;  // Shadow Map (Do not change this to linear, as all cards can not filter equally.)
-   samplerStates[2] = SamplerClampLinear;  // SSAO Mask
-   samplerStates[3] = SamplerWrapPoint;   // Random Direction Map
+   mSamplerNames[1] = "shadowMap";
+   samplerStates[2] = SamplerClampPoint;  // Shadow Map (Do not change this to linear, as all cards can not filter equally.)
+   mSamplerNames[2] = "dynamicShadowMap";
+   samplerStates[3] = SamplerClampLinear;  // SSAO Mask
+   mSamplerNames[3] = "ssaoMask";
+   samplerStates[4] = SamplerWrapPoint;   // Random Direction Map
    
    cullDefined = true;
    cullMode = GFXCullNone;
@@ -66,7 +71,9 @@ new ShaderData( AL_VectorLightShader )
    samplerNames[2] = "$dynamicShadowMap";
    samplerNames[3] = "$ssaoMask";
    samplerNames[4] = "$gTapRotationTex";
-   
+   samplerNames[5] = "$lightBuffer";
+   samplerNames[6] = "$colorBuffer";
+   samplerNames[7] = "$matInfoBuffer";  
    pixVersion = 3.0;
 };
 
@@ -79,6 +86,9 @@ new CustomMaterial( AL_VectorLightMaterial )
    sampler["shadowMap"] = "$dynamiclight";
    sampler["dynamicShadowMap"] = "$dynamicShadowMap";
    sampler["ssaoMask"] = "#ssaoMask";
+   sampler["lightBuffer"] = "#lightinfo";
+   sampler["colorBuffer"] = "#color";
+   sampler["matInfoBuffer"] = "#matinfo";
    
    target = "lightinfo";
    
@@ -103,9 +113,13 @@ new GFXStateBlockData( AL_ConvexLightState )
 
    samplersDefined = true;
    samplerStates[0] = SamplerClampPoint;  // G-buffer
+   mSamplerNames[0] = "prePassBuffer";
    samplerStates[1] = SamplerClampPoint;  // Shadow Map (Do not use linear, these are perspective projections)
-   samplerStates[2] = SamplerClampLinear; // Cookie Map   
-   samplerStates[3] = SamplerWrapPoint;   // Random Direction Map
+   mSamplerNames[1] = "shadowMap";
+   samplerStates[2] = SamplerClampPoint;  // Shadow Map (Do not use linear, these are perspective projections)
+   mSamplerNames[2] = "dynamicShadowMap";
+   samplerStates[3] = SamplerClampLinear; // Cookie Map   
+   samplerStates[4] = SamplerWrapPoint;   // Random Direction Map
    
    cullDefined = true;
    cullMode = GFXCullCW;
@@ -133,6 +147,9 @@ new ShaderData( AL_PointLightShader )
    samplerNames[2] = "$dynamicShadowMap";
    samplerNames[3] = "$cookieMap";
    samplerNames[4] = "$gTapRotationTex";
+   samplerNames[5] = "$lightBuffer";
+   samplerNames[6] = "$colorBuffer";
+   samplerNames[7] = "$matInfoBuffer";
    
    pixVersion = 3.0;
 };
@@ -146,6 +163,9 @@ new CustomMaterial( AL_PointLightMaterial )
    sampler["shadowMap"] = "$dynamiclight";
    sampler["dynamicShadowMap"] = "$dynamicShadowMap";
    sampler["cookieMap"] = "$dynamiclightmask";
+   sampler["lightBuffer"] = "#lightinfo";
+   sampler["colorBuffer"] = "#color";
+   sampler["matInfoBuffer"] = "#matinfo";
    
    target = "lightinfo";
    
@@ -166,6 +186,9 @@ new ShaderData( AL_SpotLightShader )
    samplerNames[2] = "$dynamicShadowMap";
    samplerNames[3] = "$cookieMap";
    samplerNames[4] = "$gTapRotationTex";
+   samplerNames[5] = "$lightBuffer";
+   samplerNames[6] = "$colorBuffer";
+   samplerNames[7] = "$matInfoBuffer";
    
    pixVersion = 3.0;
 };
@@ -179,6 +202,9 @@ new CustomMaterial( AL_SpotLightMaterial )
    sampler["shadowMap"] = "$dynamiclight";
    sampler["dynamicShadowMap"] = "$dynamicShadowMap";
    sampler["cookieMap"] = "$dynamiclightmask";
+   sampler["lightBuffer"] = "#lightinfo";
+   sampler["colorBuffer"] = "#color";
+   sampler["matInfoBuffer"] = "#matinfo";
    
    target = "lightinfo";
    

+ 4 - 2
Templates/Empty/game/core/scripts/client/postFx/GammaPostFX.cs

@@ -44,7 +44,7 @@ singleton GFXStateBlockData( GammaStateBlock : PFX_DefaultStateBlock )
 singleton PostEffect( GammaPostFX )
 {
    isEnabled = true;
-   allowReflectPass = false;
+   allowReflectPass = true;
    
    renderTime = "PFXBeforeBin";
    renderBin = "EditorBin";
@@ -65,6 +65,8 @@ function GammaPostFX::preProcess( %this )
 
 function GammaPostFX::setShaderConsts( %this )
 {
-   %clampedGamma  = mClamp( $pref::Video::Gamma, 0.001, 2.2);
+   %clampedGamma  = mClamp( $pref::Video::Gamma, 2.0, 2.5);
    %this.setShaderConst( "$OneOverGamma", 1 / %clampedGamma );
+   %this.setShaderConst( "$Brightness", $pref::Video::Brightness );
+   %this.setShaderConst( "$Contrast", $pref::Video::Contrast );
 }

+ 2 - 2
Templates/Empty/game/core/scripts/client/postFx/caustics.cs

@@ -38,7 +38,7 @@ singleton ShaderData( PFX_CausticsShader )
    DXVertexShaderFile 	= "shaders/common/postFx/postFxV.hlsl";
    DXPixelShaderFile 	= "shaders/common/postFx/caustics/causticsP.hlsl";
          
-   OGLVertexShaderFile  = "shaders/common/postFx/gl//postFxV.glsl";
+   OGLVertexShaderFile  = "shaders/common/postFx/gl/postFxV.glsl";
    OGLPixelShaderFile   = "shaders/common/postFx/caustics/gl/causticsP.glsl";
       
    samplerNames[0] = "$prepassTex";
@@ -51,7 +51,7 @@ singleton ShaderData( PFX_CausticsShader )
 singleton PostEffect( CausticsPFX )
 {
    isEnabled = false;
-   renderTime = "PFXBeforeBin";
+   renderTime = "PFXAfterDiffuse";
    renderBin = "ObjTranslucentBin";      
    //renderPriority = 0.1;
       

+ 16 - 2
Templates/Empty/game/core/scripts/client/postFx/hdr.cs

@@ -172,6 +172,8 @@ singleton ShaderData( HDR_CombineShader )
    samplerNames[2] = "$bloomTex";
    samplerNames[3] = "$colorCorrectionTex";
    
+   samplerNames[4] = "prepassTex";
+
    pixVersion = 3.0;
 };
 
@@ -253,8 +255,10 @@ function HDRPostFX::setShaderConsts( %this )
    %combinePass.setShaderConst( "$g_fEnableBlueShift", $HDRPostFX::enableBlueShift );   
    %combinePass.setShaderConst( "$g_fBlueShiftColor", $HDRPostFX::blueShiftColor );   
    
-   %clampedGamma  = mClamp( $pref::Video::Gamma, 0.001, 2.2);
+   %clampedGamma  = mClamp( $pref::Video::Gamma, 2.0, 2.5);
    %combinePass.setShaderConst( "$g_fOneOverGamma",  1 / %clampedGamma );       
+   %combinePass.setShaderConst( "$Brightness", $pref::Video::Brightness );
+   %combinePass.setShaderConst( "$Contrast", $pref::Video::Contrast );
 
    %whiteCutoff = ( $HDRPostFX::whiteCutoff * $HDRPostFX::whiteCutoff ) *
                   ( $HDRPostFX::whiteCutoff * $HDRPostFX::whiteCutoff );                  
@@ -329,7 +333,7 @@ function HDRPostFX::onDisabled( %this )
 singleton PostEffect( HDRPostFX )
 {
    isEnabled = false;
-   allowReflectPass = false;
+   allowReflectPass = true;
       
    // Resolve the HDR before we render any editor stuff
    // and before we resolve the scene to the backbuffer.
@@ -355,6 +359,7 @@ singleton PostEffect( HDRPostFX )
       
       new PostEffect()
       {
+         allowReflectPass = true;
          shader = HDR_DownScale4x4Shader;
          stateBlock = HDR_DownSampleStateBlock;
          texture[0] = "$inTex";
@@ -365,6 +370,7 @@ singleton PostEffect( HDRPostFX )
       
       new PostEffect()
       {
+         allowReflectPass = true;
          internalName = "bloomH";
          
          shader = HDR_BloomGaussBlurHShader;
@@ -376,6 +382,7 @@ singleton PostEffect( HDRPostFX )
 
       new PostEffect()
       {
+         allowReflectPass = true;
          internalName = "bloomV";
                   
          shader = HDR_BloomGaussBlurVShader;
@@ -390,6 +397,7 @@ singleton PostEffect( HDRPostFX )
    // Now calculate the adapted luminance.
    new PostEffect()
    {
+      allowReflectPass = true;
       internalName = "adaptLum";
       
       shader = HDR_SampleLumShader;
@@ -401,6 +409,7 @@ singleton PostEffect( HDRPostFX )
       
       new PostEffect()
       {
+         allowReflectPass = true;
          shader = HDR_DownSampleLumShader;
          stateBlock = HDR_DownSampleStateBlock;
          texture[0] = "$inTex";
@@ -411,6 +420,7 @@ singleton PostEffect( HDRPostFX )
       
       new PostEffect()
       {
+         allowReflectPass = true;
          shader = HDR_DownSampleLumShader;
          stateBlock = HDR_DownSampleStateBlock;
          texture[0] = "$inTex";
@@ -421,6 +431,7 @@ singleton PostEffect( HDRPostFX )
       
       new PostEffect()
       {
+         allowReflectPass = true;
          shader = HDR_DownSampleLumShader;
          stateBlock = HDR_DownSampleStateBlock;
          texture[0] = "$inTex";
@@ -434,6 +445,7 @@ singleton PostEffect( HDRPostFX )
       // one... PostEffect takes care to manage that.
       new PostEffect()
       {
+         allowReflectPass = true;
          internalName = "finalLum";         
          shader = HDR_CalcAdaptedLumShader;
          stateBlock = HDR_DownSampleStateBlock;
@@ -450,6 +462,7 @@ singleton PostEffect( HDRPostFX )
    // version of the scene.
    new PostEffect()
    {
+      allowReflectPass = true;
       internalName = "combinePass";
       
       shader = HDR_CombineShader;
@@ -458,6 +471,7 @@ singleton PostEffect( HDRPostFX )
       texture[1] = "#adaptedLum";            
       texture[2] = "#bloomFinal";
       texture[3] = $HDRPostFX::colorCorrectionRamp;
+      texture[4] = "#prepass";
       target = "$backBuffer";
    };
 };

+ 1 - 1
Templates/Empty/game/core/scripts/client/postFx/turbulence.cs

@@ -47,7 +47,7 @@ singleton PostEffect( TurbulenceFx )
    isEnabled = false;    
    allowReflectPass = true;  
          
-   renderTime = "PFXAfterBin";
+   renderTime = "PFXAfterDiffuse";
    renderBin = "GlowBin";
    renderPriority = 0.5; // Render after the glows themselves
      

+ 16 - 15
Templates/Empty/game/core/scripts/client/renderManager.cs

@@ -33,7 +33,7 @@ function initRenderManager()
    {
       enabled = "false";
       
-      format = "GFXFormatR8G8B8A8";
+      format = "GFXFormatR16G16B16A16F";
       depthFormat = "GFXFormatD24S8";
       aaLevel = 0; // -1 = match backbuffer
       
@@ -49,20 +49,21 @@ function initRenderManager()
      
    // We really need to fix the sky to render after all the 
    // meshes... but that causes issues in reflections.
-   DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } );
+   DiffuseRenderPassManager.addManager( new RenderObjectMgr(SkyBin) { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } );
    
    //DiffuseRenderPassManager.addManager( new RenderVistaMgr()               { bintype = "Vista"; renderOrder = 0.15; processAddOrder = 0.15; } );
    
-   DiffuseRenderPassManager.addManager( new RenderObjectMgr()              { bintype = "Begin"; renderOrder = 0.2; processAddOrder = 0.2; } );
+   DiffuseRenderPassManager.addManager( new RenderObjectMgr(BeginBin)      { bintype = "Begin"; renderOrder = 0.2; processAddOrder = 0.2; } );
    // Normal mesh rendering.
-   DiffuseRenderPassManager.addManager( new RenderTerrainMgr()             { renderOrder = 0.4; processAddOrder = 0.4; } );
-   DiffuseRenderPassManager.addManager( new RenderMeshMgr()                { bintype = "Mesh"; renderOrder = 0.5; processAddOrder = 0.5; } );
-   DiffuseRenderPassManager.addManager( new RenderImposterMgr()            { renderOrder = 0.56; processAddOrder = 0.56; } );
-   DiffuseRenderPassManager.addManager( new RenderObjectMgr()              { bintype = "Object"; renderOrder = 0.6; processAddOrder = 0.6; } );
+   DiffuseRenderPassManager.addManager( new RenderTerrainMgr(TerrainBin)   { renderOrder = 0.4; processAddOrder = 0.4; basicOnly = true; } );
+   DiffuseRenderPassManager.addManager( new RenderMeshMgr(MeshBin)         { bintype = "Mesh"; renderOrder = 0.5; processAddOrder = 0.5; basicOnly = true; } );
+   DiffuseRenderPassManager.addManager( new RenderImposterMgr(ImposterBin) { renderOrder = 0.56; processAddOrder = 0.56; } );
+   DiffuseRenderPassManager.addManager( new RenderObjectMgr(ObjectBin)     { bintype = "Object"; renderOrder = 0.6; processAddOrder = 0.6; } );
      
-   DiffuseRenderPassManager.addManager( new RenderObjectMgr()              { bintype = "Shadow"; renderOrder = 0.7; processAddOrder = 0.7; } );
-   DiffuseRenderPassManager.addManager( new RenderMeshMgr()                { bintype = "Decal"; renderOrder = 0.8; processAddOrder = 0.8; } );
-   DiffuseRenderPassManager.addManager( new RenderOcclusionMgr()           { bintype = "Occluder"; renderOrder = 0.9; processAddOrder = 0.9; } );
+   DiffuseRenderPassManager.addManager( new RenderObjectMgr(ShadowBin)     { bintype = "Shadow"; renderOrder = 0.7; processAddOrder = 0.7; } );
+   DiffuseRenderPassManager.addManager( new RenderMeshMgr(DecalRoadBin)    { bintype = "DecalRoad"; renderOrder = 0.8; processAddOrder = 0.8; } );
+   DiffuseRenderPassManager.addManager( new RenderMeshMgr(DecalBin)        { bintype = "Decal"; renderOrder = 0.81; processAddOrder = 0.81; } );
+   DiffuseRenderPassManager.addManager( new RenderOcclusionMgr(OccluderBin){ bintype = "Occluder"; renderOrder = 0.9; processAddOrder = 0.9; } );
      
    // We now render translucent objects that should handle
    // their own fogging and lighting.
@@ -70,10 +71,10 @@ function initRenderManager()
    // Note that the fog effect is triggered before this bin.
    DiffuseRenderPassManager.addManager( new RenderObjectMgr(ObjTranslucentBin) { bintype = "ObjectTranslucent"; renderOrder = 1.0; processAddOrder = 1.0; } );
          
-   DiffuseRenderPassManager.addManager( new RenderObjectMgr()              { bintype = "Water"; renderOrder = 1.2; processAddOrder = 1.2; } );
-   DiffuseRenderPassManager.addManager( new RenderObjectMgr()              { bintype = "Foliage"; renderOrder = 1.3; processAddOrder = 1.3; } );
-	DiffuseRenderPassManager.addManager( new RenderParticleMgr()            { renderOrder = 1.35; processAddOrder = 1.35; } );
-   DiffuseRenderPassManager.addManager( new RenderTranslucentMgr()         { renderOrder = 1.4; processAddOrder = 1.4; } );
+   DiffuseRenderPassManager.addManager( new RenderObjectMgr(WaterBin)          { bintype = "Water"; renderOrder = 1.2; processAddOrder = 1.2; } );
+   DiffuseRenderPassManager.addManager( new RenderObjectMgr(FoliageBin)        { bintype = "Foliage"; renderOrder = 1.3; processAddOrder = 1.3; } );
+	DiffuseRenderPassManager.addManager( new RenderParticleMgr(ParticleBin)    { renderOrder = 1.35; processAddOrder = 1.35; } );
+   DiffuseRenderPassManager.addManager( new RenderTranslucentMgr(TranslucentBin){ renderOrder = 1.4; processAddOrder = 1.4; } );
    
    DiffuseRenderPassManager.addManager(new RenderObjectMgr(FogBin){ bintype = "ObjectVolumetricFog"; renderOrder = 1.45; processAddOrder = 1.45; } );
    
@@ -85,7 +86,7 @@ function initRenderManager()
    DiffuseRenderPassManager.addManager( new RenderObjectMgr(EditorBin) { bintype = "Editor"; renderOrder = 1.6; processAddOrder = 1.6; } );
                
    // Resolve format change token last.
-   DiffuseRenderPassManager.addManager( new RenderPassStateBin() { renderOrder = 1.7; stateToken = AL_FormatToken; } );
+   DiffuseRenderPassManager.addManager( new RenderPassStateBin(FinalBin)       { renderOrder = 1.7; stateToken = AL_FormatToken; } );
 }
 
 /// This post effect is used to copy data from the non-MSAA back-buffer to the

+ 2 - 2
Templates/Empty/game/core/scripts/client/scatterSky.cs

@@ -22,13 +22,13 @@
 
 new GFXStateBlockData( ScatterSkySBData )
 {
-   cullDefined = true;
+   //cullDefined = true;
    cullMode = "GFXCullNone";
    
    zDefined = true;
    zEnable = true;
    zWriteEnable = false;
-   zFunc = "GFXCmpLessEqual";
+   //zFunc = "GFXCmpLessEqual";
    
    samplersDefined = true;
    samplerStates[0] = SamplerClampLinear;   

+ 36 - 0
Templates/Empty/game/core/scripts/client/shaders.cs

@@ -101,4 +101,40 @@ new ShaderData( fxFoliageReplicatorShader )
    samplerNames[1] = "$alphaMap";
    
    pixVersion = 1.4;
+};
+
+singleton ShaderData( VolumetricFogPrePassShader )
+{
+   DXVertexShaderFile = "shaders/common/VolumetricFog/VFogPreV.hlsl";
+   DXPixelShaderFile = "shaders/common/VolumetricFog/VFogPreP.hlsl";
+	
+   OGLVertexShaderFile  = "shaders/common/VolumetricFog/gl/VFogPreV.glsl";
+   OGLPixelShaderFile   = "shaders/common/VolumetricFog/gl/VFogPreP.glsl";
+   
+   pixVersion = 3.0;
+};
+singleton ShaderData( VolumetricFogShader )
+{
+   DXVertexShaderFile = "shaders/common/VolumetricFog/VFogV.hlsl";
+   DXPixelShaderFile = "shaders/common/VolumetricFog/VFogP.hlsl";
+	
+   OGLVertexShaderFile  = "shaders/common/VolumetricFog/gl/VFogV.glsl";
+   OGLPixelShaderFile   = "shaders/common/VolumetricFog/gl/VFogP.glsl";	
+	
+   samplerNames[0] = "$prepassTex";
+   samplerNames[1] = "$depthBuffer";
+   samplerNames[2] = "$frontBuffer";
+   samplerNames[3] = "$density";
+   
+   pixVersion = 3.0;
+};
+singleton ShaderData( VolumetricFogReflectionShader )
+{
+   DXVertexShaderFile = "shaders/common/VolumetricFog/VFogPreV.hlsl";
+   DXPixelShaderFile = "shaders/common/VolumetricFog/VFogRefl.hlsl";
+	
+   OGLVertexShaderFile  = "shaders/common/VolumetricFog/gl/VFogPreV.glsl";
+   OGLPixelShaderFile   = "shaders/common/VolumetricFog/gl/VFogRefl.glsl";
+	
+   pixVersion = 3.0;
 };

+ 0 - 1
Templates/Empty/game/shaders/common/basicCloudsV.hlsl

@@ -46,7 +46,6 @@ ConnectData main( CloudVert IN )
    ConnectData OUT;
 
    OUT.hpos = mul(modelview, float4(IN.pos,1.0));
-   OUT.hpos.w = OUT.hpos.z;
 
    float2 uv = IN.uv0;
    uv += texOffset;

+ 0 - 1
Templates/Empty/game/shaders/common/cloudLayerV.hlsl

@@ -63,7 +63,6 @@ ConnectData main( CloudVert IN )
    ConnectData OUT;
 
    OUT.hpos = mul(modelview, float4(IN.pos,1.0));
-   OUT.hpos.w = OUT.hpos.z;
    // Offset the uv so we don't have a seam directly over our head.
    float2 uv = IN.uv0 + float2( 0.5, 0.5 );
    

+ 0 - 1
Templates/Empty/game/shaders/common/gl/basicCloudsV.glsl

@@ -41,7 +41,6 @@ out vec2 texCoord;
 void main()
 {  
    gl_Position = tMul(modelview, IN_pos);
-   gl_Position.w = gl_Position.z;
    
    vec2 uv = IN_uv0;
    uv += texOffset;

+ 0 - 1
Templates/Empty/game/shaders/common/gl/cloudLayerV.glsl

@@ -62,7 +62,6 @@ void main()
    vec2 IN_uv0 = vTexCoord0.st;
 
    gl_Position = modelview * IN_pos;
-   gl_Position.w = gl_Position.z;
    
    // Offset the uv so we don't have a seam directly over our head.
    vec2 uv = IN_uv0 + vec2( 0.5, 0.5 );

+ 1 - 1
Templates/Empty/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl

@@ -22,7 +22,7 @@
 
 #include "../../../gl/hlslCompat.glsl"
 #include "shadergen:/autogenConditioners.h"
-#include "../../../postfx/gl/postFx.glsl"
+#include "../../../postFx/gl/postFX.glsl"
 #include "../../../gl/torque.glsl"
 
 uniform sampler2D colorBufferTex;

+ 5 - 223
Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui

@@ -1354,132 +1354,6 @@
                            bitmap = "tools/gui/images/delete";
                         };
                      };
-                     new GuiBitmapCtrl(){
-                        position="6 357";
-                        extent ="175 2";
-                        HorizSizing = "width";
-                        bitmap ="tools/gui/images/separator-v"; 
-                     };
-                     new GuiContainer(){ // Environment Map
-                        profile="ToolsGuiDefaultProfile";
-                        isContainer = "1";
-                        position = "6 359";
-                        Extent = "185 52";
-                        HorizSizing = "width";
-                        
-                        new GuiBitmapCtrl() {
-                           canSaveDynamicFields = "0";
-                           internalName = "envMapDisplayBitmap";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiDefaultProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "1 1";
-                           Extent = "48 48";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           hovertime = "1000";
-                           bitmap = "tools/materialeditor/gui/unknownImage";
-                           wrap = "0";
-                        };
-                        new GuiTextCtrl() {
-                           canSaveDynamicFields = "0";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "EditorTextProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "56 -3";
-                           Extent = "72 18";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           hovertime = "1000";
-                           Margin = "0 0 0 0";
-                           Padding = "0 0 0 0";
-                           AnchorTop = "1";
-                           AnchorBottom = "0";
-                           AnchorLeft = "1";
-                           AnchorRight = "0";
-                           text = "Env Map";
-                           maxLength = "1024";
-                        };
-                        new GuiBitmapButtonCtrl() {
-                           canSaveDynamicFields = "0";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiDefaultProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "1 1";
-                           Extent = "48 48";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           Command = "MaterialEditorGui.updateTextureMap(\"env\", 1);";
-                           tooltipprofile = "ToolsGuiDefaultProfile";
-                           ToolTip = "Change the active Environment Map for this layer.";
-                           hovertime = "1000";
-                           groupNum = "-1";
-                           buttonType = "PushButton";
-                           useMouseEvents = "0";
-                           bitmap = "tools/materialEditor/gui/cubemapBtnBorder";
-                        };
-                        new GuiTextCtrl() {
-                           canSaveDynamicFields = "0";
-                           internalName = "envMapNameText";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiTextProfile";
-                           HorizSizing = "width";
-                           VertSizing = "bottom";
-                           position = "56 16";
-                           Extent = "143 17";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           hovertime = "1000";
-                           Margin = "0 0 0 0";
-                           Padding = "0 0 0 0";
-                           AnchorTop = "1";
-                           AnchorBottom = "0";
-                           AnchorLeft = "1";
-                           AnchorRight = "0";
-                           text = "None";
-                           maxLength = "1024";
-                        };
-                        new GuiButtonCtrl(){
-                           profile="ToolsGuiButtonProfile";
-                           text ="Edit";
-                           HorizSizing = "left";
-                           VertSizing = "bottom"; 
-                           position = "134 34";
-                           Extent = "40 16";
-                           buttonType = "PushButton";
-                           command="MaterialEditorGui.updateTextureMap(\"env\", 1);";
-                        };
-                        new GuiBitmapButtonCtrl() {
-                           canSaveDynamicFields = "0";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiDefaultProfile";
-                           HorizSizing = "left";
-                           VertSizing = "bottom";
-                           position = "177 34";
-                           Extent = "16 16";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           Command = "MaterialEditorGui.updateTextureMap(\"env\", 0);";
-                           hovertime = "1000";
-                           groupNum = "-1";
-                           buttonType = "PushButton";
-                           useMouseEvents = "0";
-                           bitmap = "tools/gui/images/delete";
-                        };
-                     };
                   };
                };
                new GuiRolloutCtrl() {
@@ -1491,6 +1365,7 @@
                   Position = "0 0";
                   Extent = "195 0";
                   Caption = "Accumulation Properties";
+                  Expanded = false;
                   Margin = "-1 0 0 0";
                   DragSizable = false;
                   container = true;
@@ -1967,6 +1842,7 @@
                   Position = "0 0";
                   Extent = "185 0";
                   Caption = "Lighting Properties";
+                  Expanded = false;
                   Margin = "-1 0 0 0";
                   DragSizable = false;
                   container = true;
@@ -2364,101 +2240,6 @@
                            useMouseEvents = "0";
                            useInactiveState = "0";
                         };
-                        new GuiCheckBoxCtrl() {
-                           canSaveDynamicFields = "0";
-                           internalName = "subSurfaceCheckbox";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiCheckBoxProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "8 46";
-                           Extent = "79 16";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           Command = "MaterialEditorGui.updateActiveMaterial(\"subSurface[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
-                           tooltipprofile = "ToolsGuiDefaultProfile";
-                           ToolTip = "Enables the use of subsurface scattering for this layer.";
-                           hovertime = "1000";
-                           text = "Sub Surface";
-                           groupNum = "-1";
-                           buttonType = "ToggleButton";
-                           useMouseEvents = "0";
-                           useInactiveState = "0";
-                        };
-                        new GuiSwatchButtonCtrl() {
-                           canSaveDynamicFields = "0";
-                           internalName = "subSurfaceColorSwatch";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "GuiInspectorSwatchButtonProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "90 46";
-                           Extent = "16 16";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           Command = "getColorF(materialEd_PreviewMaterial.subSurfaceColor[MaterialEditorGui.currentLayer], \"MaterialEditorGui.updateSubSurfaceColor\");";
-                           tooltip = "Set the subsurface scattering color";
-                           hovertime = "1000";
-                           groupNum = "-1";
-                           buttonType = "PushButton";
-                           useMouseEvents = "0";
-                        };
-                        new GuiTextEditCtrl() {
-                           canSaveDynamicFields = "0";
-                           internalName = "subSurfaceRolloffTextEdit";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiTextEditProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "114 45";
-                           Extent = "29 18";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           tooltip = "Set the subsurface rolloff factor";
-                           Command = "MaterialEditorGui.updateActiveMaterial(\"subSurfaceRolloff[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getText());";
-                           hovertime = "1000";
-                           AnchorTop = "1";
-                           AnchorBottom = "0";
-                           AnchorLeft = "1";
-                           AnchorRight = "0";
-                           text = "32";
-                           maxLength = "5";
-                        };
-                        new GuiTextCtrl() {
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "9 65";
-                           Extent = "89 16";
-                           text = "Minnaert constant";
-                        };
-                        new GuiTextEditCtrl() {
-                           canSaveDynamicFields = "0";
-                           internalName = "minnaertTextEdit";
-                           Enabled = "1";
-                           isContainer = "0";
-                           Profile = "ToolsGuiTextEditProfile";
-                           HorizSizing = "right";
-                           VertSizing = "bottom";
-                           position = "114 65";
-                           Extent = "29 18";
-                           MinExtent = "8 2";
-                           canSave = "1";
-                           Visible = "1";
-                           Command = "MaterialEditorGui.updateActiveMaterial(\"minnaertConstant[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getText());";
-                           hovertime = "1000";
-                           AnchorTop = "1";
-                           AnchorBottom = "0";
-                           AnchorLeft = "1";
-                           AnchorRight = "0";
-                           text = "32";
-                           maxLength = "3";
-                        };
                      };
                   };
                };
@@ -2471,9 +2252,9 @@
                   Position = "0 0";
                   Extent = "185 0";
                   Caption = "Animation Properties";
+                  Expanded = false;
                   Margin = "-1 0 0 0";
                   DragSizable = false;
-                  Expanded = false;
                   container = true;
                   parentRollout = %this.rollout;
                   object = %behavior;
@@ -3283,6 +3064,7 @@
                   Position = "0 0";
                   Extent = "202 0";
                   Caption = "Advanced (all layers)";
+                  Expanded = false;
                   Margin = "4 4 4 0";
                   DragSizable = false;
                   container = true;
@@ -3519,7 +3301,7 @@
                            Profile = "ToolsGuiCheckBoxProfile";
                            HorizSizing = "right";
                            VertSizing = "bottom";
-                           position = "100 56";
+                           position = "105 55";
                            Extent = "85 16";
                            MinExtent = "8 2";
                            canSave = "1";

+ 0 - 3
Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs

@@ -918,9 +918,6 @@ function MaterialEditorGui::guiSync( %this, %material )
    MaterialEditorPropertiesWindow-->vertLitCheckbox.setValue((%material).vertLit[%layer]);
    MaterialEditorPropertiesWindow-->vertColorSwatch.color = (%material).vertColor[%layer];
    MaterialEditorPropertiesWindow-->subSurfaceCheckbox.setValue((%material).subSurface[%layer]);
-   MaterialEditorPropertiesWindow-->subSurfaceColorSwatch.color = (%material).subSurfaceColor[%layer];
-   MaterialEditorPropertiesWindow-->subSurfaceRolloffTextEdit.setText((%material).subSurfaceRolloff[%layer]);
-   MaterialEditorPropertiesWindow-->minnaertTextEdit.setText((%material).minnaertConstant[%layer]);
 
    // Animation properties
    MaterialEditorPropertiesWindow-->RotationAnimation.setValue(0);

+ 3 - 1
Templates/Empty/game/tools/shapeEditor/scripts/shapeEditor.ed.cs

@@ -380,7 +380,8 @@ function ShapeEdSelectWindow::navigate( %this, %address )
 
       // Ignore assets in the tools folder
       %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() );
-      %splitPath = strreplace( %fullPath, "/", " " );
+      %splitPath = strreplace( %fullPath, " ", "_" );
+      %splitPath = strreplace( %splitPath, "/", " " );
       if ( getWord( %splitPath, 0 ) $= "tools" )
       {
          %fullPath = findNextFileMultiExpr( %filePatterns );
@@ -393,6 +394,7 @@ function ShapeEdSelectWindow::navigate( %this, %address )
       // Add this file's path ( parent folders ) to the
       // popup menu if it isn't there yet.
       %temp = strreplace( %pathFolders, " ", "/" );
+      %temp = strreplace( %temp, "_", " " );
       %r = ShapeEdSelectMenu.findText( %temp );
       if ( %r == -1 )
          ShapeEdSelectMenu.add( %temp );

+ 3 - 0
Templates/Empty/game/tools/worldEditor/main.cs

@@ -120,6 +120,9 @@ function initializeWorldEditor()
    EVisibility.addOption( "AL: Light Specular Viz", "$AL_LightSpecularVisualizeVar", "toggleLightSpecularViz" );
    EVisibility.addOption( "AL: Normals Viz", "$AL_NormalsVisualizeVar", "toggleNormalsViz" );
    EVisibility.addOption( "AL: Depth Viz", "$AL_DepthVisualizeVar", "toggleDepthViz" );
+   EVisibility.addOption( "AL: Color Buffer", "$AL_ColorBufferShaderVar", "toggleColorBufferViz" );
+   EVisibility.addOption( "AL: Spec Map", "$AL_SpecMapShaderVar", "toggleSpecMapViz");
+   EVisibility.addOption( "AL: Backbuffer", "$AL_BackbufferVisualizeVar", "toggleBackbufferViz" );
    EVisibility.addOption( "AL: Glow Buffer", "$AL_GlowVisualizeVar", "toggleGlowViz" );
    EVisibility.addOption( "AL: PSSM Cascade Viz", "$AL::PSSMDebugRender", "" );
    EVisibility.addOption( "Frustum Lock", "$Scene::lockCull", "" );

+ 6 - 2
Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs

@@ -318,7 +318,8 @@ function EWCreatorWindow::navigate( %this, %address )
          }
 
          %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() );                                  
-         %splitPath = strreplace( %fullPath, "/", " " );     
+         %splitPath = strreplace( %fullPath, " ", "_" );
+         %splitPath = strreplace( %splitPath, "/", " " );    
          if( getWord(%splitPath, 0) $= "tools" )
          {
             %fullPath = findNextFileMultiExpr( getFormatExtensions() );
@@ -332,6 +333,7 @@ function EWCreatorWindow::navigate( %this, %address )
          // Add this file's path (parent folders) to the
          // popup menu if it isn't there yet.
          %temp = strreplace( %pathFolders, " ", "/" );         
+         %temp = strreplace( %temp, "_", " " );
          %r = CreatorPopupMenu.findText( %temp );
          if ( %r == -1 )
          {
@@ -430,7 +432,8 @@ function EWCreatorWindow::navigate( %this, %address )
       while ( %fullPath !$= "" )
       {         
          %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() );                                  
-         %splitPath = strreplace( %fullPath, "/", " " );     
+         %splitPath = strreplace( %fullPath, " ", "_" );
+         %splitPath = strreplace( %splitPath, "/", " " );
          if( getWord(%splitPath, 0) $= "tools" )
          {
             %fullPath = findNextFile( %expr );
@@ -444,6 +447,7 @@ function EWCreatorWindow::navigate( %this, %address )
          // Add this file's path (parent folders) to the
          // popup menu if it isn't there yet.
          %temp = strreplace( %pathFolders, " ", "/" );         
+         %temp = strreplace( %temp, "_", " " );
          %r = CreatorPopupMenu.findText( %temp );
          if ( %r == -1 )
          {

+ 2 - 0
Templates/Empty/game/tools/worldEditor/scripts/menuHandlers.ed.cs

@@ -244,6 +244,8 @@ function EditorSaveMissionMenu()
 
 function EditorSaveMission()
 {
+   // just save the mission without renaming it
+   
    // first check for dirty and read-only files:
    if((EWorldEditor.isDirty || ETerrainEditor.isMissionDirty) && !isWriteableFileName($Server::MissionFile))
    {

+ 364 - 45
Templates/Full/game/core/art/gui/netGraphGui.gui

@@ -73,100 +73,380 @@ new GuiControlProfile (NetGraphPacketLossProfile)
 };
 
 //--- OBJECT WRITE BEGIN ---
-new GuiControl(NetGraphGui) {
-   profile = "NetGraphProfile";
-   horizSizing = "left";
-   vertSizing = "bottom";
+%guiContent = new GuiControl(NetGraphGui) {
    position = "0 0";
-   extent = "640 480";
+   extent = "1024 768";
    minExtent = "8 2";
+   horizSizing = "left";
+   vertSizing = "bottom";
+   profile = "NetGraphProfile";
    visible = "1";
-   noCursor = "1";
-   
+   active = "1";
+   tooltipProfile = "GuiToolTipProfile";
+   hovertime = "1000";
+   isContainer = "1";
+   canSave = "1";
+   canSaveDynamicFields = "1";
+      noCursor = "1";
+
    new GuiGraphCtrl(NetGraph) {
-      profile = "NetGraphKeyContainerProfile";
-      horizSizing = "left";
-      vertSizing = "bottom";
-      position = "432 5";
+      centerY = "1";
+      plotColor[0] = "1 1 1 1";
+      plotColor[1] = "1 0 0 1";
+      plotColor[2] = "0 1 0 1";
+      plotColor[3] = "0 0 1 1";
+      plotColor[4] = "0 1 1 1";
+      plotColor[5] = "0 0 0 1";
+      plotType[0] = "PolyLine";
+      plotType[1] = "PolyLine";
+      plotType[2] = "PolyLine";
+      plotType[3] = "PolyLine";
+      plotType[4] = "PolyLine";
+      plotType[5] = "PolyLine";
+      plotInterval[0] = "0";
+      plotInterval[1] = "0";
+      plotInterval[2] = "0";
+      plotInterval[3] = "0";
+      plotInterval[4] = "0";
+      plotInterval[5] = "0";
+      position = "816 5";
       extent = "200 200";
       minExtent = "8 2";
+      horizSizing = "left";
+      vertSizing = "bottom";
+      profile = "NetGraphKeyContainerProfile";
       visible = "1";
+      active = "1";
+      tooltipProfile = "GuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "0";
+      canSave = "1";
+      canSaveDynamicFields = "0";
    };
-   
    new GuiControl() {
-      profile = "NetGraphKeyContainerProfile";
+      position = "816 205";
+      extent = "200 104";
+      minExtent = "8 2";
       horizSizing = "left";
       vertSizing = "bottom";
-      position = "432 205";
-      extent = "200 52";
-      minExtent = "8 2";
+      profile = "NetGraphKeyContainerProfile";
       visible = "1";
+      active = "1";
+      tooltipProfile = "GuiToolTipProfile";
+      hovertime = "1000";
+      isContainer = "1";
+      canSave = "1";
+      canSaveDynamicFields = "0";
 
       new GuiTextCtrl(GhostsActive) {
-         profile = "NetGraphGhostsActiveProfile";
-         horizSizing = "left";
-         vertSizing = "bottom";
+         text = "Ghosts Active";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
          position = "0 0";
          extent = "100 18";
          minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphGhostsActiveProfile";
          visible = "1";
-         text = "Ghosts Active";
-         maxLength = "255";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl(GhostUpdates) {
-         profile = "NetGraphGhostUpdatesProfile";
-         horizSizing = "left";
-         vertSizing = "bottom";
+         text = "Ghost Updates";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
          position = "100 0";
          extent = "100 18";
          minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphGhostUpdatesProfile";
          visible = "1";
-         text = "Ghost Updates";
-         maxLength = "255";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl(BitsSent) {
-         profile = "NetGraphBitsSentProfile";
-         horizSizing = "left";
-         vertSizing = "bottom";
-         position = "0 18 ";
+         text = "Bytes Sent";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "0 18";
          extent = "100 18";
          minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphBitsSentProfile";
          visible = "1";
-         text = "Bytes Sent";
-         maxLength = "255";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl(BitsReceived) {
-         profile = "NetGraphBitsReceivedProfile";
-         horizSizing = "left";
-         vertSizing = "bottom";
+         text = "Bytes Received";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
          position = "100 18";
          extent = "100 18";
          minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphBitsReceivedProfile";
          visible = "1";
-         text = "Bytes Received";
-         maxLength = "255";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl(Latency) {
-         profile = "NetGraphLatencyProfile";
-         horizSizing = "left";
-         vertSizing = "bottom";
+         text = "Latency";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
          position = "0 36";
          extent = "100 18";
          minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphLatencyProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl(PacketLoss) {
+         text = "Packet Loss";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "100 36";
+         extent = "59 18";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphPacketLossProfile";
          visible = "1";
-         text = "Latency";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Network Simulation:";
          maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "0 52";
+         extent = "97 18";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphPacketLossProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
       };
-      new GuiTextCtrl(PacketLoss) {
+      new GuiTextCtrl() {
+         text = "Simulated Latency:";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "0 68";
+         extent = "91 18";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
          profile = "NetGraphPacketLossProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "ms";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "179 68";
+         extent = "20 18";
+         minExtent = "8 2";
          horizSizing = "left";
          vertSizing = "bottom";
-         position = "100 36";
-         extent = "59 18";
+         profile = "NetGraphPacketLossProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextEditCtrl(NetGraphSimLatency) {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         text = "0";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "112 67";
+         extent = "64 18";
          minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextEditProfile";
          visible = "1";
-         text = "Packet Loss";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "Simulated Packet Loss:";
          maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "0 83";
+         extent = "111 18";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphPacketLossProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextCtrl() {
+         text = "%";
+         maxLength = "255";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "179 84";
+         extent = "20 18";
+         minExtent = "8 2";
+         horizSizing = "left";
+         vertSizing = "bottom";
+         profile = "NetGraphPacketLossProfile";
+         visible = "1";
+         active = "1";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
+      };
+      new GuiTextEditCtrl(NetGraphSimPacket) {
+         historySize = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+         password = "0";
+         passwordMask = "*";
+         text = "0";
+         maxLength = "1024";
+         margin = "0 0 0 0";
+         padding = "0 0 0 0";
+         anchorTop = "1";
+         anchorBottom = "0";
+         anchorLeft = "1";
+         anchorRight = "0";
+         position = "112 85";
+         extent = "64 18";
+         minExtent = "8 2";
+         horizSizing = "right";
+         vertSizing = "bottom";
+         profile = "GuiTextEditProfile";
+         visible = "1";
+         active = "1";
+         command = "if(NetGraphSimLatency.text $= \"\" || NetGraphSimLatency.text  < 0)\n{\n   NetGraphSimLatency.text = 0;\n}\n\nif(NetGraphSimPacket.text $= \"\" || NetGraphSimPacket.text  < 0)\n{\n   NetGraphSimLatency.text = 0;\n}\nelse if(NetGraphSimPacket.text > 100)\n{\n   NetGraphSimPacket.text = 100;\n}\n\nnetSimulateLag( NetGraphSimLatency.text, NetGraphSimPacket.text );";
+         tooltipProfile = "GuiToolTipProfile";
+         hovertime = "1000";
+         isContainer = "1";
+         canSave = "1";
+         canSaveDynamicFields = "0";
       };
    };
 };
@@ -186,7 +466,10 @@ function toggleNetGraph()
         Canvas.add(NetGraphGui);
     }
     else
+    {
       Canvas.remove(NetGraphGui);
+      netSimulateLag( 0, 0 ); 
+    }
 }
 
 function NetGraph::updateStats()
@@ -236,3 +519,39 @@ function NetGraph::toggleKey()
     PacketLoss.visible = 0;
   }
 }
+
+function NetGraphSimLatency::onReturn(%this)
+{
+   NetGraph.updateNetworkSimulation();
+}
+
+function NetGraphSimPacket::onReturn(%this)
+{
+   NetGraph.updateNetworkSimulation();
+}
+
+function NetGraph::updateNetworkSimulation(%this)
+{
+   %latency = NetGraphSimLatency.getText();
+   
+   if(%latency $= "" || %latency  < 0)
+   {
+      NetGraphSimLatency.text = 0;
+      %latency = 0;
+   }
+   
+   %packetLoss = NetGraphSimPacket.getText();
+   
+   if(%packetLoss $= "" || %packetLoss  < 0)
+   {
+      NetGraphSimLatency.text = 0;
+      %packetLoss = 0;
+   }
+   else if(%packetLoss > 100)
+   {
+      NetGraphSimPacket.text = 100;
+      %packetLoss = 100;
+   }
+   
+   netSimulateLag( %latency, %packetLoss );
+}

+ 1 - 1
Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs

@@ -55,7 +55,7 @@ new ShaderData( AL_DeferredShader )
 
 singleton PostEffect( AL_DeferredShading )
 {
-   renderTime = "PFXBeforeBin";
+   renderTime = "PFXAfterBin";
    renderBin = "SkyBin";
    shader = AL_DeferredShader;
    stateBlock = AL_DeferredShadingState;

+ 9 - 5
Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs

@@ -39,9 +39,11 @@ new GFXStateBlockData( AL_VectorLightState )
    mSamplerNames[0] = "prePassBuffer";
    samplerStates[1] = SamplerClampPoint;  // Shadow Map (Do not change this to linear, as all cards can not filter equally.)
    mSamplerNames[1] = "shadowMap";
-   samplerStates[2] = SamplerClampLinear;  // SSAO Mask
-   mSamplerNames[2] = "ssaoMask";
-   samplerStates[3] = SamplerWrapPoint;   // Random Direction Map
+   samplerStates[2] = SamplerClampPoint;  // Shadow Map (Do not change this to linear, as all cards can not filter equally.)
+   mSamplerNames[2] = "dynamicShadowMap";
+   samplerStates[3] = SamplerClampLinear;  // SSAO Mask
+   mSamplerNames[3] = "ssaoMask";
+   samplerStates[4] = SamplerWrapPoint;   // Random Direction Map
    
    cullDefined = true;
    cullMode = GFXCullNone;
@@ -114,8 +116,10 @@ new GFXStateBlockData( AL_ConvexLightState )
    mSamplerNames[0] = "prePassBuffer";
    samplerStates[1] = SamplerClampPoint;  // Shadow Map (Do not use linear, these are perspective projections)
    mSamplerNames[1] = "shadowMap";
-   samplerStates[2] = SamplerClampLinear; // Cookie Map   
-   samplerStates[3] = SamplerWrapPoint;   // Random Direction Map
+   samplerStates[2] = SamplerClampPoint;  // Shadow Map (Do not use linear, these are perspective projections)
+   mSamplerNames[2] = "dynamicShadowMap";
+   samplerStates[3] = SamplerClampLinear; // Cookie Map   
+   samplerStates[4] = SamplerWrapPoint;   // Random Direction Map
    
    cullDefined = true;
    cullMode = GFXCullCW;

+ 6 - 1
Templates/Full/game/scripts/client/default.bind.cs

@@ -618,7 +618,12 @@ GlobalActionMap.bind(keyboard, "ctrl o", bringUpOptions);
 function showMetrics(%val)
 {
    if(%val)
-      metrics("fps gfx shadow sfx terrain groundcover forest net");
+   {
+      if(!Canvas.isMember(FrameOverlayGui))
+         metrics("fps gfx shadow sfx terrain groundcover forest net");
+      else
+         metrics("");
+   }
 }
 GlobalActionMap.bind(keyboard, "ctrl F2", showMetrics);
 

+ 0 - 1
Templates/Full/game/shaders/common/basicCloudsV.hlsl

@@ -46,7 +46,6 @@ ConnectData main( CloudVert IN )
    ConnectData OUT;
 
    OUT.hpos = mul(modelview, float4(IN.pos,1.0));
-   OUT.hpos.w = OUT.hpos.z;
 
    float2 uv = IN.uv0;
    uv += texOffset;

+ 0 - 1
Templates/Full/game/shaders/common/cloudLayerV.hlsl

@@ -63,7 +63,6 @@ ConnectData main( CloudVert IN )
    ConnectData OUT;
 
    OUT.hpos = mul(modelview, float4(IN.pos,1.0));
-   OUT.hpos.w = OUT.hpos.z;
    // Offset the uv so we don't have a seam directly over our head.
    float2 uv = IN.uv0 + float2( 0.5, 0.5 );
    

+ 0 - 1
Templates/Full/game/shaders/common/gl/basicCloudsV.glsl

@@ -41,7 +41,6 @@ out vec2 texCoord;
 void main()
 {  
    gl_Position = tMul(modelview, IN_pos);
-   gl_Position.w = gl_Position.z;
    
    vec2 uv = IN_uv0;
    uv += texOffset;

+ 0 - 1
Templates/Full/game/shaders/common/gl/cloudLayerV.glsl

@@ -62,7 +62,6 @@ void main()
    vec2 IN_uv0 = vTexCoord0.st;
 
    gl_Position = modelview * IN_pos;
-   gl_Position.w = gl_Position.z;
    
    // Offset the uv so we don't have a seam directly over our head.
    vec2 uv = IN_uv0 + vec2( 0.5, 0.5 );

+ 12 - 2
Templates/Full/game/shaders/common/lighting/advanced/gl/pointLightP.glsl

@@ -147,6 +147,17 @@ void main()
 	   return;
    }
 
+   vec4 colorSample = texture( colorBuffer, uvScene );
+   vec3 subsurface = vec3(0.0,0.0,0.0); 
+   if (getFlag( matInfo.r, 1 ))
+   {
+      subsurface = colorSample.rgb;
+      if (colorSample.r>colorSample.g)
+         subsurface = vec3(0.772549, 0.337255, 0.262745);
+	  else
+         subsurface = vec3(0.337255, 0.772549, 0.262745);
+	}
+	
    // Sample/unpack the normal/z data
    vec4 prepassSample = prepassUncondition( prePassBuffer, uvScene );
    vec3 normal = prepassSample.rgb;
@@ -258,6 +269,5 @@ void main()
       addToResult = ( 1.0 - shadowed ) * abs(lightMapParams);
    }
 
-   vec4 colorSample = texture( colorBuffer, uvScene );
-   OUT_col = AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
+   OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
 }

+ 12 - 2
Templates/Full/game/shaders/common/lighting/advanced/gl/spotLightP.glsl

@@ -89,6 +89,17 @@ void main()
 	   return;
    }
    
+   vec4 colorSample = texture( colorBuffer, uvScene );
+   vec3 subsurface = vec3(0.0,0.0,0.0); 
+   if (getFlag( matInfo.r, 1 ))
+   {
+      subsurface = colorSample.rgb;
+      if (colorSample.r>colorSample.g)
+         subsurface = vec3(0.772549, 0.337255, 0.262745);
+	  else
+         subsurface = vec3(0.337255, 0.772549, 0.262745);
+	}
+	
    // Sample/unpack the normal/z data
    vec4 prepassSample = prepassUncondition( prePassBuffer, uvScene );
    vec3 normal = prepassSample.rgb;
@@ -195,6 +206,5 @@ void main()
       addToResult = ( 1.0 - shadowed ) * abs(lightMapParams);
    }
 
-   vec4 colorSample = texture( colorBuffer, uvScene );
-   OUT_col = AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
+   OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
 }

+ 12 - 2
Templates/Full/game/shaders/common/lighting/advanced/gl/vectorLightP.glsl

@@ -202,6 +202,17 @@ void main()
        return;
    }
    
+   vec4 colorSample = texture( colorBuffer, uv0 );
+   vec3 subsurface = vec3(0.0,0.0,0.0); 
+   if (getFlag( matInfo.r, 1 ))
+   {
+      subsurface = colorSample.rgb;
+      if (colorSample.r>colorSample.g)
+         subsurface = vec3(0.772549, 0.337255, 0.262745);
+	  else
+         subsurface = vec3(0.337255, 0.772549, 0.262745);
+	}
+	
    // Sample/unpack the normal/z data
    vec4 prepassSample = prepassUncondition( prePassBuffer, uv0 );
    vec3 normal = prepassSample.rgb;
@@ -312,6 +323,5 @@ void main()
       lightColorOut = debugColor;
    #endif
 
-   vec4 colorSample = texture( colorBuffer, uv0 );
-   OUT_col = AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); 
+   OUT_col = AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att); 
 }

+ 11 - 2
Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl

@@ -149,6 +149,16 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0
    {
        return float4(0.0, 0.0, 0.0, 0.0);
    }
+   float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene );
+   float3 subsurface = float3(0.0,0.0,0.0); 
+   if (getFlag( matInfo.r, 1 ))
+   {
+      subsurface = colorSample.rgb;
+      if (colorSample.r>colorSample.g)
+         subsurface = float3(0.772549, 0.337255, 0.262745);
+	  else
+         subsurface = float3(0.337255, 0.772549, 0.262745);
+	}
    
    // Sample/unpack the normal/z data
    float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, uvScene );
@@ -263,6 +273,5 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0
       addToResult = ( 1.0 - shadowed ) * abs(lightMapParams);
    }
 
-   float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene );
-   return AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
+   return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
 }

+ 12 - 2
Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl

@@ -87,6 +87,17 @@ float4 main(   ConvexConnectP IN ) : TORQUE_TARGET0
        return float4(0.0, 0.0, 0.0, 0.0);
    }
 
+   float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene );
+   float3 subsurface = float3(0.0,0.0,0.0); 
+   if (getFlag( matInfo.r, 1 ))
+   {
+      subsurface = colorSample.rgb;
+      if (colorSample.r>colorSample.g)
+         subsurface = float3(0.772549, 0.337255, 0.262745);
+	  else
+         subsurface = float3(0.337255, 0.772549, 0.262745);
+	}
+	
    // Sample/unpack the normal/z data
    float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, uvScene );
    float3 normal = prepassSample.rgb;
@@ -194,6 +205,5 @@ float4 main(   ConvexConnectP IN ) : TORQUE_TARGET0
       addToResult = ( 1.0 - shadowed ) * abs(lightMapParams);
    }
 
-   float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene );
-   return AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
+   return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
 }

+ 11 - 2
Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl

@@ -202,6 +202,16 @@ float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0
        return float4(1.0, 1.0, 1.0, 0.0);
    }
    
+   float4 colorSample = TORQUE_TEX2D( colorBuffer, IN.uv0 );
+   float3 subsurface = float3(0.0,0.0,0.0); 
+   if (getFlag( matInfo.r, 1 ))
+   {
+      subsurface = colorSample.rgb;
+      if (colorSample.r>colorSample.g)
+         subsurface = float3(0.772549, 0.337255, 0.262745);
+	  else
+         subsurface = float3(0.337255, 0.772549, 0.262745);
+	}
    // Sample/unpack the normal/z data
    float4 prepassSample = TORQUE_PREPASS_UNCONDITION( prePassBuffer, IN.uv0 );
    float3 normal = prepassSample.rgb;
@@ -314,6 +324,5 @@ float4 main( FarFrustumQuadConnectP IN ) : TORQUE_TARGET0
       lightColorOut = debugColor;
    #endif
 
-   float4 colorSample = TORQUE_TEX2D( colorBuffer, IN.uv0 );
-   return AL_DeferredOutput(lightColorOut, colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
+   return AL_DeferredOutput(lightColorOut+subsurface*(1.0-Sat_NL_Att), colorSample.rgb, matInfo, addToResult, specular, Sat_NL_Att);
 }

+ 23 - 0
Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui

@@ -2240,6 +2240,29 @@
                            useMouseEvents = "0";
                            useInactiveState = "0";
                         };
+                        new GuiCheckBoxCtrl() {
+                           canSaveDynamicFields = "0";
+                           internalName = "subSurfaceCheckbox";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "ToolsGuiCheckBoxProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 46";
+                           Extent = "79 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           Command = "MaterialEditorGui.updateActiveMaterial(\"subSurface[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                           tooltipprofile = "ToolsGuiDefaultProfile";
+                           ToolTip = "Enables the use of subsurface scattering for this layer.";
+                           hovertime = "1000";
+                           text = "Sub Surface";
+                           groupNum = "-1";
+                           buttonType = "ToggleButton";
+                           useMouseEvents = "0";
+                           useInactiveState = "0";
+                        };
                      };
                   };
                };

+ 0 - 3
Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs

@@ -918,9 +918,6 @@ function MaterialEditorGui::guiSync( %this, %material )
    MaterialEditorPropertiesWindow-->vertLitCheckbox.setValue((%material).vertLit[%layer]);
    MaterialEditorPropertiesWindow-->vertColorSwatch.color = (%material).vertColor[%layer];
    MaterialEditorPropertiesWindow-->subSurfaceCheckbox.setValue((%material).subSurface[%layer]);
-   MaterialEditorPropertiesWindow-->subSurfaceColorSwatch.color = (%material).subSurfaceColor[%layer];
-   MaterialEditorPropertiesWindow-->subSurfaceRolloffTextEdit.setText((%material).subSurfaceRolloff[%layer]);
-   MaterialEditorPropertiesWindow-->minnaertTextEdit.setText((%material).minnaertConstant[%layer]);
 
    // Animation properties
    MaterialEditorPropertiesWindow-->RotationAnimation.setValue(0);

+ 3 - 1
Templates/Full/game/tools/shapeEditor/scripts/shapeEditor.ed.cs

@@ -380,7 +380,8 @@ function ShapeEdSelectWindow::navigate( %this, %address )
 
       // Ignore assets in the tools folder
       %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() );
-      %splitPath = strreplace( %fullPath, "/", " " );
+      %splitPath = strreplace( %fullPath, " ", "_" );
+      %splitPath = strreplace( %splitPath, "/", " " );
       if ( getWord( %splitPath, 0 ) $= "tools" )
       {
          %fullPath = findNextFileMultiExpr( %filePatterns );
@@ -393,6 +394,7 @@ function ShapeEdSelectWindow::navigate( %this, %address )
       // Add this file's path ( parent folders ) to the
       // popup menu if it isn't there yet.
       %temp = strreplace( %pathFolders, " ", "/" );
+      %temp = strreplace( %temp, "_", " " );
       %r = ShapeEdSelectMenu.findText( %temp );
       if ( %r == -1 )
          ShapeEdSelectMenu.add( %temp );

+ 6 - 2
Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs

@@ -318,7 +318,8 @@ function EWCreatorWindow::navigate( %this, %address )
          }
 
          %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() );                                  
-         %splitPath = strreplace( %fullPath, "/", " " );     
+         %splitPath = strreplace( %fullPath, " ", "_" );
+         %splitPath = strreplace( %splitPath, "/", " " );
          if( getWord(%splitPath, 0) $= "tools" )
          {
             %fullPath = findNextFileMultiExpr( getFormatExtensions() );
@@ -332,6 +333,7 @@ function EWCreatorWindow::navigate( %this, %address )
          // Add this file's path (parent folders) to the
          // popup menu if it isn't there yet.
          %temp = strreplace( %pathFolders, " ", "/" );         
+         %temp = strreplace( %temp, "_", " " );
          %r = CreatorPopupMenu.findText( %temp );
          if ( %r == -1 )
          {
@@ -430,7 +432,8 @@ function EWCreatorWindow::navigate( %this, %address )
       while ( %fullPath !$= "" )
       {         
          %fullPath = makeRelativePath( %fullPath, getMainDotCSDir() );                                  
-         %splitPath = strreplace( %fullPath, "/", " " );     
+         %splitPath = strreplace( %fullPath, " ", "_" );
+         %splitPath = strreplace( %splitPath, "/", " " );
          if( getWord(%splitPath, 0) $= "tools" )
          {
             %fullPath = findNextFile( %expr );
@@ -444,6 +447,7 @@ function EWCreatorWindow::navigate( %this, %address )
          // Add this file's path (parent folders) to the
          // popup menu if it isn't there yet.
          %temp = strreplace( %pathFolders, " ", "/" );         
+         %temp = strreplace( %temp, "_", " " );
          %r = CreatorPopupMenu.findText( %temp );
          if ( %r == -1 )
          {

+ 9 - 0
Templates/Full/game/tools/worldEditor/scripts/menuHandlers.ed.cs

@@ -770,6 +770,15 @@ function EditorCameraSpeedMenu::setupGuiControls(%this)
    // Set up min/max camera slider range
    eval("CameraSpeedDropdownCtrlContainer-->Slider.range = \"" @ %minSpeed @ " " @ %maxSpeed @ "\";");
 }
+
+//////////////////////////////////////////////////////////////////////////
+// Tools Menu Handler
+//////////////////////////////////////////////////////////////////////////
+function EditorUtilitiesMenu::onSelectItem(%this, %id, %text)
+{
+   return Parent::onSelectItem(%this, %id, %text);
+}
+
 //////////////////////////////////////////////////////////////////////////
 // World Menu Handler Object Menu
 //////////////////////////////////////////////////////////////////////////

+ 13 - 0
Templates/Full/game/tools/worldEditor/scripts/menus.ed.cs

@@ -252,6 +252,19 @@ function EditorGui::buildMenus(%this)
          // last menu items in EditorLightingMenu::onAdd().
    };
    %this.menuBar.insert(%lightingMenu, %this.menuBar.getCount());
+   
+   // Tools Menu
+   %toolsMenu = new PopupMenu()
+   {
+      superClass = "MenuBuilder";
+      class = "EditorUtilitiesMenu";
+
+      barTitle = "Tools";
+         
+      item[0] = "Network Graph" TAB "n" TAB "toggleNetGraph();";
+      item[1] = "Profiler" TAB "ctrl F2" TAB "showMetrics(true);";
+   };
+   %this.menuBar.insert(%toolsMenu, %this.menuBar.getCount());
       
    // Help Menu
    %helpMenu = new PopupMenu()