소스 검색

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

Conflicts:
	Engine/source/T3D/aiPlayer.cpp
Azaezel 9 년 전
부모
커밋
262cc4bac1
100개의 변경된 파일4867개의 추가작업 그리고 607개의 파일을 삭제
  1. 44 2
      Engine/source/T3D/aiPlayer.cpp
  2. 3 1
      Engine/source/T3D/aiPlayer.h
  3. 1 1
      Engine/source/T3D/assets/ShapeAsset.h
  4. 1 0
      Engine/source/T3D/decal/decalData.cpp
  5. 45 0
      Engine/source/T3D/decal/decalManager.cpp
  6. 3 3
      Engine/source/T3D/fx/fxFoliageReplicator.cpp
  7. 1 1
      Engine/source/T3D/fx/fxShapeReplicator.cpp
  8. 32 62
      Engine/source/T3D/player.cpp
  9. 3 1
      Engine/source/T3D/player.h
  10. 2 2
      Engine/source/T3D/rigid.cpp
  11. 1 0
      Engine/source/T3D/shapeBase.cpp
  12. 1 0
      Engine/source/T3D/shapeBase.h
  13. 60 0
      Engine/source/T3D/tsStatic.cpp
  14. 9 0
      Engine/source/T3D/tsStatic.h
  15. 20 0
      Engine/source/app/game.cpp
  16. 86 1
      Engine/source/app/net/tcpObject.cpp
  17. 11 1
      Engine/source/app/net/tcpObject.h
  18. 1 1
      Engine/source/console/codeBlock.cpp
  19. 557 0
      Engine/source/console/consoleFunctions.cpp
  20. 16 0
      Engine/source/console/consoleFunctions.h
  21. 196 162
      Engine/source/console/consoleObject.h
  22. 1 1
      Engine/source/console/engineTypeInfo.h
  23. 285 0
      Engine/source/core/color.h
  24. 1 1
      Engine/source/core/idGenerator.h
  25. 1 1
      Engine/source/core/stream/stream.cpp
  26. 9 0
      Engine/source/core/strings/stringFunctions.h
  27. 100 0
      Engine/source/core/util/str.cpp
  28. 1 0
      Engine/source/core/util/str.h
  29. 1 2
      Engine/source/core/util/swizzle.h
  30. 1319 0
      Engine/source/environment/VolumetricFog.cpp
  31. 243 0
      Engine/source/environment/VolumetricFog.h
  32. 299 0
      Engine/source/environment/VolumetricFogRTManager.cpp
  33. 92 0
      Engine/source/environment/VolumetricFogRTManager.h
  34. 1 1
      Engine/source/environment/basicClouds.cpp
  35. 1 1
      Engine/source/environment/cloudLayer.cpp
  36. 1 1
      Engine/source/environment/decalRoad.cpp
  37. 10 1
      Engine/source/environment/scatterSky.cpp
  38. 2 1
      Engine/source/environment/skyBox.cpp
  39. 2 2
      Engine/source/environment/timeOfDay.cpp
  40. 2 0
      Engine/source/gfx/D3D9/gfxD3D9CardProfiler.cpp
  41. 24 4
      Engine/source/gfx/D3D9/gfxD3D9Device.cpp
  42. 4 2
      Engine/source/gfx/D3D9/gfxD3D9Device.h
  43. 1 0
      Engine/source/gfx/D3D9/pc/gfxD3D9PrimitiveBuffer.pc.cpp
  44. 5 0
      Engine/source/gfx/D3D9/pc/gfxPCD3D9Target.cpp
  45. 4 2
      Engine/source/gfx/Null/gfxNullDevice.cpp
  46. 4 2
      Engine/source/gfx/Null/gfxNullDevice.h
  47. 1 1
      Engine/source/gfx/bitmap/gBitmap.cpp
  48. 1 1
      Engine/source/gfx/bitmap/loaders/bitmapTga.cpp
  49. 1 1
      Engine/source/gfx/gfxDevice.cpp
  50. 9 2
      Engine/source/gfx/gfxDevice.h
  51. 4 4
      Engine/source/gfx/gfxDrawUtil.cpp
  52. 4 3
      Engine/source/gfx/gfxEnums.h
  53. 13 0
      Engine/source/gfx/gfxPrimitiveBuffer.cpp
  54. 2 0
      Engine/source/gfx/gfxPrimitiveBuffer.h
  55. 1 1
      Engine/source/gfx/gfxTextureManager.cpp
  56. 6 1
      Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h
  57. 31 7
      Engine/source/gfx/gl/gfxGLDevice.cpp
  58. 3 2
      Engine/source/gfx/gl/gfxGLDevice.h
  59. 1 0
      Engine/source/gfx/gl/gfxGLEnumTranslate.cpp
  60. 8 0
      Engine/source/gfx/gl/gfxGLStateBlock.cpp
  61. 22 1
      Engine/source/gfx/gl/gfxGLTextureTarget.cpp
  62. 9 0
      Engine/source/gfx/gl/gfxGLWindowTarget.cpp
  63. 3 1
      Engine/source/gfx/gl/gfxGLWindowTarget.h
  64. 4 0
      Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp
  65. 1 0
      Engine/source/gfx/gl/tGL/tGL.cpp
  66. 6 0
      Engine/source/gfx/gl/tGL/tGL.h
  67. 108 2
      Engine/source/gfx/sim/debugDraw.cpp
  68. 10 2
      Engine/source/gfx/sim/debugDraw.h
  69. 241 126
      Engine/source/gui/controls/guiColorPicker.cpp
  70. 25 20
      Engine/source/gui/controls/guiColorPicker.h
  71. 73 24
      Engine/source/gui/controls/guiTextEditCtrl.cpp
  72. 6 0
      Engine/source/gui/controls/guiTextEditCtrl.h
  73. 3 0
      Engine/source/gui/core/guiCanvas.cpp
  74. 10 0
      Engine/source/gui/core/guiCanvas.h
  75. 66 0
      Engine/source/gui/core/guiControl.cpp
  76. 6 0
      Engine/source/gui/core/guiControl.h
  77. 3 0
      Engine/source/gui/core/guiTypes.cpp
  78. 1 0
      Engine/source/gui/core/guiTypes.h
  79. 2 2
      Engine/source/gui/worldEditor/worldEditor.cpp
  80. 5 9
      Engine/source/lighting/advanced/advancedLightBinManager.cpp
  81. 1 1
      Engine/source/lighting/advanced/advancedLightManager.cpp
  82. 16 14
      Engine/source/lighting/advanced/glsl/advancedLightingFeaturesGLSL.cpp
  83. 190 0
      Engine/source/lighting/advanced/glsl/deferredShadingFeaturesGLSL.cpp
  84. 85 0
      Engine/source/lighting/advanced/glsl/deferredShadingFeaturesGLSL.h
  85. 2 2
      Engine/source/lighting/advanced/glsl/gBufferConditionerGLSL.cpp
  86. 9 7
      Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp
  87. 187 0
      Engine/source/lighting/advanced/hlsl/deferredShadingFeaturesHLSL.cpp
  88. 84 0
      Engine/source/lighting/advanced/hlsl/deferredShadingFeaturesHLSL.h
  89. 1 1
      Engine/source/lighting/advanced/hlsl/gBufferConditionerHLSL.cpp
  90. 7 24
      Engine/source/lighting/shadowMap/lightShadowMap.cpp
  91. 6 16
      Engine/source/lighting/shadowMap/lightShadowMap.h
  92. 7 7
      Engine/source/lighting/shadowMap/shadowMapPass.cpp
  93. 9 2
      Engine/source/materials/matTextureTarget.cpp
  94. 13 7
      Engine/source/materials/materialDefinition.cpp
  95. 6 2
      Engine/source/materials/materialDefinition.h
  96. 16 5
      Engine/source/materials/materialFeatureTypes.cpp
  97. 11 2
      Engine/source/materials/materialFeatureTypes.h
  98. 0 8
      Engine/source/materials/processedMaterial.cpp
  99. 19 39
      Engine/source/materials/processedShaderMaterial.cpp
  100. 3 0
      Engine/source/materials/processedShaderMaterial.h

+ 44 - 2
Engine/source/T3D/aiPlayer.cpp

@@ -564,6 +564,21 @@ bool AIPlayer::getAIMove(Move *movePtr)
          }
       }
 
+   Pose desiredPose = mPose;
+
+   if ( mSwimming )  
+      desiredPose = SwimPose;   
+   else if ( mAiPose == 1 && canCrouch() )   
+      desiredPose = CrouchPose;  
+   else if ( mAiPose == 2 && canProne() )  
+      desiredPose = PronePose;  
+   else if ( mAiPose == 3 && canSprint() )  
+      desiredPose = SprintPose;  
+   else if ( canStand() )  
+      desiredPose = StandPose;  
+  
+   setPose( desiredPose );
+   
    // Replicate the trigger state into the move so that
    // triggers can be controlled from scripts.
    for( U32 i = 0; i < MaxTriggerKeys; i++ )
@@ -592,12 +607,24 @@ bool AIPlayer::getAIMove(Move *movePtr)
    return true;
 }
 
-void AIPlayer::updateMove(const Move* move)  
+void AIPlayer::updateMove(const Move* move)
+{
+   if (!getControllingClient() && isGhost())
+      return;
+
+   Parent::updateMove(move);
+}
+
+void AIPlayer::setAiPose( S32 pose )  
 {  
    if (!getControllingClient() && isGhost())  
       return;  
+   mAiPose = pose;  
+}  
   
-   Parent::updateMove(move);  
+S32 AIPlayer::getAiPose()  
+{  
+   return mAiPose;  
 }
 
 /**
@@ -1397,3 +1424,18 @@ DefineEngineMethod(AIPlayer, getTargetDistance, bool, (ShapeBase* obj, bool chec
 {
    return object->getTargetDistance(obj, checkEnabled);
 }
+
+DefineEngineMethod( AIPlayer, setAiPose, void, ( S32 pose ),,  
+   "@brief Sets the AiPose for an AI object.\n"
+   "@param pose StandPose=0, CrouchPose=1, PronePose=2, SprintPose=3.\n"
+   "Uses the new AiPose variable from shapebase (as defined in its PlayerData datablock).\n")  
+{  
+   object->setAiPose(pose);  
+}  
+  
+DefineEngineMethod( AIPlayer, getAiPose, S32, (),,  
+   "@brief Get the object's current AiPose.\n"
+   "@return StandPose=0, CrouchPose=1, PronePose=2, SprintPose=3.\n")  
+{  
+   return object->getAiPose();  
+}

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

@@ -182,7 +182,9 @@ public:
    void setMoveDestination( const Point3F &location, bool slowdown );
    Point3F getMoveDestination() const { return mMoveDestination; }
    void stopMove();
-
+   void setAiPose( S32 pose );
+   S32  getAiPose();
+	
    // Trigger sets/gets
    void setMoveTrigger( U32 slot, const bool isSet = true );
    bool getMoveTrigger( U32 slot ) const;

+ 1 - 1
Engine/source/T3D/assets/ShapeAsset.h

@@ -39,7 +39,7 @@
 #endif
 
 #ifndef _TSSHAPE_H_
-#include "ts/TSShape.h"
+#include "ts/tsShape.h"
 #endif
 #ifndef __RESOURCE_H__
 #include "core/resource.h"

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

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

+ 45 - 0
Engine/source/T3D/decal/decalManager.cpp

@@ -1744,3 +1744,48 @@ DefineEngineFunction( decalManagerRemoveDecal, bool, ( S32 decalID ),,
    gDecalManager->removeDecal(inst);
    return true;
 }
+
+DefineEngineFunction( decalManagerEditDecal, bool, ( S32 decalID, Point3F pos, Point3F normal, F32 rotAroundNormal, F32 decalScale ),,
+   "Edit specified decal of the decal manager.\n"
+   "@param decalID ID of the decal to edit.\n"
+   "@param pos World position for the decal.\n"
+   "@param normal Decal normal vector (if the decal was a tire lying flat on a "
+   "surface, this is the vector pointing in the direction of the axle).\n"
+   "@param rotAroundNormal Angle (in radians) to rotate this decal around its normal vector.\n"
+   "@param decalScale Scale factor applied to the decal.\n"
+   "@return Returns true if successful, false if decalID not found.\n"
+   "" )
+{
+   DecalInstance *decalInstance = gDecalManager->getDecal( decalID );
+   if( !decalInstance )
+		return false;
+
+   //Internally we need Point3F tangent instead of the user friendly F32 rotAroundNormal
+   MatrixF mat( true );
+   MathUtils::getMatrixFromUpVector( normal, &mat );
+
+   AngAxisF rot( normal, rotAroundNormal );
+   MatrixF rotmat;
+   rot.setMatrix( &rotmat );
+   mat.mul( rotmat );
+
+   Point3F tangent;
+   mat.getColumn( 1, &tangent );
+   
+   //if everything is unchanged just do nothing and  return "everything is ok"
+   if ( pos.equal(decalInstance->mPosition) &&
+        normal.equal(decalInstance->mNormal) &&
+        tangent.equal(decalInstance->mTangent) &&
+        mFabs( decalInstance->mSize - (decalInstance->mDataBlock->size * decalScale) ) < POINT_EPSILON )
+           return true;
+
+   decalInstance->mPosition = pos;
+   decalInstance->mNormal = normal;
+   decalInstance->mTangent = tangent;
+   decalInstance->mSize = decalInstance->mDataBlock->size * decalScale;
+
+   gDecalManager->clipDecal( decalInstance, NULL, NULL);
+   
+   gDecalManager->notifyDecalModified( decalInstance );
+   return true;
+}

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

@@ -426,7 +426,7 @@ void fxFoliageReplicator::CreateFoliage(void)
    Point3F	MaxPoint(  0.5,  0.5,  0.5 );
 
    // Check Host.
-   AssertFatal(isClientObject(), "Trying to create Foliage on Server, this is bad!")
+   AssertFatal(isClientObject(), "Trying to create Foliage on Server, this is bad!");
 
       // Cannot continue without Foliage Texture!
       if (dStrlen(mFieldData.mFoliageFile) == 0) 
@@ -1134,7 +1134,7 @@ void fxFoliageReplicator::ProcessQuadrant(fxFoliageQuadrantNode* pParentNode, fx
 void fxFoliageReplicator::SyncFoliageReplicators(void)
 {
    // Check Host.
-   AssertFatal(isServerObject(), "We *MUST* be on server when Synchronising Foliage!")
+   AssertFatal(isServerObject(), "We *MUST* be on server when Synchronising Foliage!");
 
       // Find the Replicator Set.
    SimSet *fxFoliageSet = dynamic_cast<SimSet*>(Sim::findObject("fxFoliageSet"));
@@ -1196,7 +1196,7 @@ void fxFoliageReplicator::DestroyFoliageItems()
 void fxFoliageReplicator::DestroyFoliage(void)
 {
    // Check Host.
-   AssertFatal(isClientObject(), "Trying to destroy Foliage on Server, this is bad!")
+   AssertFatal(isClientObject(), "Trying to destroy Foliage on Server, this is bad!");
 
       // Destroy Quad-tree.
       mPotentialFoliageNodes = 0;

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

@@ -224,7 +224,7 @@ void fxShapeReplicator::CreateShapes(void)
    }
 
    // Check Shapes.
-   AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!")
+   AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!");
 
       // Check that we have a shape...
       if (!mFieldData.mShapeFile) return;

+ 32 - 62
Engine/source/T3D/player.cpp

@@ -3173,18 +3173,21 @@ void Player::updateMove(const Move* move)
    // Update the PlayerPose
    Pose desiredPose = mPose;
 
-   if ( mSwimming )
-      desiredPose = SwimPose; 
-   else if ( runSurface && move->trigger[sCrouchTrigger] && canCrouch() )     
-      desiredPose = CrouchPose;
-   else if ( runSurface && move->trigger[sProneTrigger] && canProne() )
-      desiredPose = PronePose;
-   else if ( move->trigger[sSprintTrigger] && canSprint() )
-      desiredPose = SprintPose;
-   else if ( canStand() )
-      desiredPose = StandPose;
+   if ( !mIsAiControlled )
+   {
+      if ( mSwimming )
+         desiredPose = SwimPose; 
+      else if ( runSurface && move->trigger[sCrouchTrigger] && canCrouch() )     
+         desiredPose = CrouchPose;
+      else if ( runSurface && move->trigger[sProneTrigger] && canProne() )
+         desiredPose = PronePose;
+      else if ( move->trigger[sSprintTrigger] && canSprint() )
+         desiredPose = SprintPose;
+      else if ( canStand() )
+         desiredPose = StandPose;
 
-   setPose( desiredPose );
+      setPose( desiredPose );
+   }
 }
 
 
@@ -4659,9 +4662,9 @@ Point3F Player::_move( const F32 travelTime, Collision *outCol )
       }
       Point3F distance = end - start;
 
-      if (mFabs(distance.x) < mObjBox.len_x() &&
-          mFabs(distance.y) < mObjBox.len_y() &&
-          mFabs(distance.z) < mObjBox.len_z())
+      if (mFabs(distance.x) < mScaledBox.len_x() &&
+          mFabs(distance.y) < mScaledBox.len_y() &&
+          mFabs(distance.z) < mScaledBox.len_z())
       {
          // We can potentially early out of this.  If there are no polys in the clipped polylist at our
          //  end position, then we can bail, and just set start = end;
@@ -6186,6 +6189,10 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
    {
       stream->writeFlag(mFalling);
 
+      stream->writeFlag(mSwimming);
+      stream->writeFlag(mJetting);  
+      stream->writeInt(mPose, NumPoseBits);
+	  
       stream->writeInt(mState,NumStateBits);
       if (stream->writeFlag(mState == RecoverState))
          stream->writeInt(mRecoverTicks,PlayerData::RecoverDelayBits);
@@ -6282,7 +6289,11 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
    if (stream->readFlag()) {
       mPredictionCount = sMaxPredictionTicks;
       mFalling = stream->readFlag();
-
+ 
+      mSwimming = stream->readFlag();
+      mJetting = stream->readFlag();  
+      mPose = (Pose)(stream->readInt(NumPoseBits)); 
+	  
       ActionState actionState = (ActionState)stream->readInt(NumStateBits);
       if (stream->readFlag()) {
          mRecoverTicks = stream->readInt(PlayerData::RecoverDelayBits);
@@ -6873,31 +6884,13 @@ void Player::playFootstepSound( bool triggeredLeft, Material* contactMaterial, S
       // Play default sound.
 
       S32 sound = -1;
-      if( contactMaterial && contactMaterial->mFootstepSoundId != -1 )
+      if (contactMaterial && (contactMaterial->mImpactSoundId>-1 && contactMaterial->mImpactSoundId<PlayerData::MaxSoundOffsets))
          sound = contactMaterial->mFootstepSoundId;
       else if( contactObject && contactObject->getTypeMask() & VehicleObjectType )
          sound = 2;
 
-      switch ( sound )
-      {
-      case 0: // Soft
-         SFX->playOnce( mDataBlock->sound[PlayerData::FootSoft], &footMat );
-         break;
-      case 1: // Hard
-         SFX->playOnce( mDataBlock->sound[PlayerData::FootHard], &footMat );
-         break;
-      case 2: // Metal
-         SFX->playOnce( mDataBlock->sound[PlayerData::FootMetal], &footMat );
-         break;
-      case 3: // Snow
-         SFX->playOnce( mDataBlock->sound[PlayerData::FootSnow], &footMat );
-         break;
-      /*
-      default: //Hard
-         SFX->playOnce( mDataBlock->sound[PlayerData::FootHard], &footMat );
-         break;
-      */
-      }
+      if (sound>=0)
+         SFX->playOnce(mDataBlock->sound[sound], &footMat);
    }
 }
 
@@ -6922,36 +6915,13 @@ void Player:: playImpactSound()
          else
          {
             S32 sound = -1;
-            if( material && material->mImpactSoundId )
+            if (material && (material->mImpactSoundId>-1 && material->mImpactSoundId<PlayerData::MaxSoundOffsets))
                sound = material->mImpactSoundId;
             else if( rInfo.object->getTypeMask() & VehicleObjectType )
                sound = 2; // Play metal;
 
-            switch( sound )
-            {
-            case 0:
-               //Soft
-               SFX->playOnce( mDataBlock->sound[ PlayerData::ImpactSoft ], &getTransform() );
-               break;
-            case 1:
-               //Hard
-               SFX->playOnce( mDataBlock->sound[ PlayerData::ImpactHard ], &getTransform() );
-               break;
-            case 2:
-               //Metal
-               SFX->playOnce( mDataBlock->sound[ PlayerData::ImpactMetal ], &getTransform() );
-               break;
-            case 3:
-               //Snow
-               SFX->playOnce( mDataBlock->sound[ PlayerData::ImpactSnow ], &getTransform() );
-               break;
-               /*
-            default:
-               //Hard
-               alxPlay(mDataBlock->sound[PlayerData::ImpactHard], &getTransform());
-               break;
-               */
-            }
+            if (sound >= 0)
+               SFX->playOnce(mDataBlock->sound[PlayerData::ImpactStart + sound], &getTransform());
          }
       }
    }

+ 3 - 1
Engine/source/T3D/player.h

@@ -190,13 +190,15 @@ struct PlayerData: public ShapeBaseData {
       FootHard,
       FootMetal,
       FootSnow,
+      MaxSoundOffsets,
       FootShallowSplash,
       FootWading,
       FootUnderWater,
       FootBubbles,
       MoveBubbles,
       WaterBreath,
-      ImpactSoft,
+      ImpactStart,
+      ImpactSoft = ImpactStart,
       ImpactHard,
       ImpactMetal,
       ImpactSnow,

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

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

+ 1 - 0
Engine/source/T3D/shapeBase.cpp

@@ -879,6 +879,7 @@ IMPLEMENT_CALLBACK( ShapeBase, validateCameraFov, F32, (F32 fov), (fov),
 ShapeBase::ShapeBase()
  : mDataBlock( NULL ),
    mIsAiControlled( false ),
+   mAiPose( 0 ),
    mControllingObject( NULL ),
    mMoveMotion( false ),
    mShapeBaseMount( NULL ),

+ 1 - 0
Engine/source/T3D/shapeBase.h

@@ -874,6 +874,7 @@ protected:
    /// @name Physical Properties
    /// @{
 
+   S32 mAiPose;                     ///< Current pose.
    F32 mEnergy;                     ///< Current enery level.
    F32 mRechargeRate;               ///< Energy recharge rate (in units/tick).
 

+ 60 - 0
Engine/source/T3D/tsStatic.cpp

@@ -91,6 +91,9 @@ ConsoleDocClass( TSStatic,
 );
 
 TSStatic::TSStatic()
+:
+   cubeDescId( 0 ),
+   reflectorDesc( NULL )
 {
    mNetFlags.set(Ghostable | ScopeAlways);
 
@@ -186,6 +189,11 @@ void TSStatic::initPersistFields()
 
    endGroup("Rendering");
 
+   addGroup( "Reflection" );
+      addField( "cubeReflectorDesc", TypeRealString, Offset( cubeDescName, TSStatic ), 
+         "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
+   endGroup( "Reflection" );
+
    addGroup("Collision");
 
       addField( "collisionType",    TypeTSMeshType,   Offset( mCollisionType,   TSStatic ),
@@ -292,6 +300,14 @@ bool TSStatic::onAdd()
 
    addToScene();
 
+   if ( isClientObject() )
+   {      
+      mCubeReflector.unregisterReflector();
+
+      if ( reflectorDesc )
+         mCubeReflector.registerReflector( this, reflectorDesc );      
+   }
+
    _updateShouldTick();
 
    // Accumulation
@@ -357,6 +373,16 @@ bool TSStatic::_createShape()
    if ( mAmbientThread )
       mShapeInstance->setSequence( mAmbientThread, ambientSeq, 0);
 
+   // Resolve CubeReflectorDesc.
+   if ( cubeDescName.isNotEmpty() )
+   {
+      Sim::findObject( cubeDescName, reflectorDesc );
+   }
+   else if( cubeDescId > 0 )
+   {
+      Sim::findObject( cubeDescId, reflectorDesc );
+   }
+
    return true;
 }
 
@@ -429,6 +455,8 @@ void TSStatic::onRemove()
    mShapeInstance = NULL;
 
    mAmbientThread = NULL;
+   if ( isClientObject() )
+       mCubeReflector.unregisterReflector();
 
    Parent::onRemove();
 }
@@ -561,6 +589,12 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
 
    F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));   
 
+   // If we're currently rendering our own reflection we
+   // don't want to render ourselves into it.
+   if ( mCubeReflector.isRendering() )
+      return;
+
+
    if ( mForceDetail == -1 )
       mShapeInstance->setDetailFromDistance( state, dist * invScale );
    else
@@ -577,6 +611,9 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    rdata.setFadeOverride( 1.0f );
    rdata.setOriginSort( mUseOriginSort );
 
+   if ( mCubeReflector.isEnabled() )
+      rdata.setCubemap( mCubeReflector.getCubemap() );
+
    // Acculumation
    rdata.setAccuTex(mAccuTex);
 
@@ -604,6 +641,20 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    mat.scale( mObjScale );
    GFX->setWorldMatrix( mat );
 
+   if ( state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery() )
+   {
+       RenderPassManager *pass = state->getRenderPass();
+       OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>();  
+       
+       ri->type = RenderPassManager::RIT_Occluder;
+       ri->query = mCubeReflector.getOcclusionQuery();
+       mObjToWorld.mulP( mObjBox.getCenter(), &ri->position );
+       ri->scale.set( mObjBox.getExtents() );
+       ri->orientation = pass->allocUniqueXform( mObjToWorld ); 
+       ri->isSphere = false;
+       state->getRenderPass()->addInst( ri );
+   }
+
    mShapeInstance->animate();
    if(mShapeInstance)
    {
@@ -715,6 +766,10 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
    if ( mLightPlugin )
       retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
 
+   if( stream->writeFlag( reflectorDesc != NULL ) )
+   {
+      stream->writeRangedU32( reflectorDesc->getId(), DataBlockObjectIdFirst,  DataBlockObjectIdLast );
+   }
    return retMask;
 }
 
@@ -782,6 +837,11 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
       mLightPlugin->unpackUpdate(this, con, stream);
    }
 
+   if( stream->readFlag() )
+   {
+      cubeDescId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
+   }
+
    if ( isProperlyAdded() )
       _updateShouldTick();
 }

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

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

+ 20 - 0
Engine/source/app/game.cpp

@@ -202,6 +202,26 @@ DefineConsoleFunction( getRealTime, S32, (), , "()"
    return Platform::getRealMilliseconds();
 }
 
+ConsoleFunction( getLocalTime, const char *, 1, 1, "Return the current local time as: weekday month day year hour min sec.\n\n"
+                "Local time is platform defined.")
+{
+   Platform::LocalTime lt;
+   Platform::getLocalTime(lt);
+
+   static const U32 bufSize = 128;
+   char *retBuffer = Con::getReturnBuffer(bufSize);
+   dSprintf(retBuffer, bufSize, "%d %d %d %d %02d %02d %02d",
+      lt.weekday,
+      lt.month + 1,
+      lt.monthday,
+      lt.year + 1900,
+      lt.hour,
+      lt.min,
+      lt.sec);
+
+   return retBuffer;
+}
+
 ConsoleFunctionGroupEnd(Platform);
 
 //-----------------------------------------------------------------------------

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

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

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

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

+ 1 - 1
Engine/source/console/codeBlock.cpp

@@ -61,7 +61,7 @@ CodeBlock::CodeBlock()
 CodeBlock::~CodeBlock()
 {
    // Make sure we aren't lingering in the current code block...
-   AssertFatal(smCurrentCodeBlock != this, "CodeBlock::~CodeBlock - Caught lingering in smCurrentCodeBlock!")
+   AssertFatal(smCurrentCodeBlock != this, "CodeBlock::~CodeBlock - Caught lingering in smCurrentCodeBlock!");
 
    if(name)
       removeFromCodeList();

+ 557 - 0
Engine/source/console/consoleFunctions.cpp

@@ -25,6 +25,11 @@
 #include "console/consoleInternal.h"
 #include "console/engineAPI.h"
 #include "console/ast.h"
+
+#ifndef _CONSOLFUNCTIONS_H_
+#include "console/consoleFunctions.h"
+#endif
+
 #include "core/strings/findMatch.h"
 #include "core/strings/stringUnit.h"
 #include "core/strings/unicode.h"
@@ -32,7 +37,11 @@
 #include "console/compiler.h"
 #include "platform/platformInput.h"
 #include "core/util/journal/journal.h"
+#include "gfx/gfxEnums.h"
 #include "core/util/uuid.h"
+#include "core/color.h"
+#include "math/mPoint3.h"
+#include "math/mathTypes.h"
 
 // This is a temporary hack to get tools using the library to
 // link in this module which contains no other references.
@@ -41,6 +50,132 @@ bool LinkConsoleFunctions = false;
 // Buffer for expanding script filenames.
 static char scriptFilenameBuffer[1024];
 
+bool isInt(const char* str)
+{
+   int len = dStrlen(str);
+   if(len <= 0)
+      return false;
+
+   // Ignore whitespace
+   int start = 0;
+   for(int i = start; i < len; i++)
+      if(str[i] != ' ')
+      {
+         start = i;
+         break;
+      }
+
+      for(int i = start; i < len; i++)
+         switch(str[i])
+      {
+         case '+': case '-':
+            if(i != 0)
+               return false;
+            break;
+         case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': 
+            break;
+         case ' ': // ignore whitespace
+            for(int j = i+1; j < len; j++)
+               if(str[j] != ' ')
+                  return false;
+            return true;
+            break;
+         default:
+            return false;
+      }
+      return true;
+}
+
+bool isFloat(const char* str, bool sciOk = false)
+{
+   int len = dStrlen(str);
+   if(len <= 0)
+      return false;
+
+   // Ingore whitespace
+   int start = 0;
+   for(int i = start; i < len; i++)
+      if(str[i] != ' ')
+      {
+         start = i;
+         break;
+      }
+
+      bool seenDot = false;
+      int eLoc = -1;
+      for(int i = 0; i < len; i++)
+         switch(str[i])
+      {
+         case '+': case '-':
+            if(sciOk)
+            {
+               //Haven't found e or scientific notation symbol
+               if(eLoc == -1)
+               {
+                  //only allowed in beginning
+                  if(i != 0)
+                     return false;
+               }
+               else
+               {
+                  //if not right after the e
+                  if(i != (eLoc + 1))
+                     return false;
+               }
+            }
+            else
+            {
+               //only allowed in beginning
+               if(i != 0)
+                  return false;
+            }
+            break;
+         case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': 
+            break;
+         case 'e': case 'E':
+            if(!sciOk)
+               return false;
+            else
+            {
+               //already saw it so can't have 2
+               if(eLoc != -1)
+                  return false;
+
+               eLoc = i;
+            }
+            break;
+         case '.':
+            if(seenDot | (sciOk && eLoc != -1))
+               return false;
+            seenDot = true;
+            break;
+         case ' ': // ignore whitespace
+            for(int j = i+1; j < len; j++)
+               if(str[j] != ' ')
+                  return false;
+            return true;
+            break;
+         default:
+            return false;
+      }
+      return true;
+}
+
+bool isValidIP(const char* ip)
+{
+   unsigned b1, b2, b3, b4;
+   unsigned char c;
+   int rc = dSscanf(ip, "%3u.%3u.%3u.%3u%c", &b1, &b2, &b3, &b4, &c);
+   if (rc != 4 && rc != 5) return false;
+   if ((b1 | b2 | b3 | b4) > 255) return false;
+   if (dStrspn(ip, "0123456789.") < dStrlen(ip)) return false;
+   return true;
+}
+
+bool isValidPort(U16 port)
+{
+   return (port >= 0 && port <=65535);
+}
 
 //=============================================================================
 //    String Functions.
@@ -235,6 +370,40 @@ DefineConsoleFunction( strlen, S32, ( const char* str ),,
    return dStrlen( str );
 }
 
+//-----------------------------------------------------------------------------
+DefineConsoleFunction( strlenskip, S32, ( const char* str, const char* first, const char* last ),,
+   "Calculate the length of a string in characters, skipping everything between and including first and last.\n"
+   "@param str A string.\n"
+   "@param first First character to look for to skip block of text.\n"
+   "@param last Second character to look for to skip block of text.\n"
+   "@return The length of the given string skipping blocks of text between characters.\n"
+   "@ingroup Strings" )
+{
+   const UTF8* pos = str;
+   U32 size = 0;
+   U32 length = dStrlen(str);
+   bool count = true;
+
+   //loop through each character counting each character, skipping tags (anything with < followed by >)
+   for(U32 i = 0; i < length; i++, pos++)
+   {
+      if(count)
+      {
+         if(*pos == first[0])
+            count = false;
+         else
+            size++;
+      }
+      else
+      {
+         if(*pos == last[0])
+            count = true;
+      }
+   }
+
+   return S32(size);
+}
+
 //-----------------------------------------------------------------------------
 
 DefineConsoleFunction( strstr, S32, ( const char* string, const char* substring ),,
@@ -281,6 +450,33 @@ DefineConsoleFunction( strpos, S32, ( const char* haystack, const char* needle,
 
 //-----------------------------------------------------------------------------
 
+DefineConsoleFunction( strposr, S32, ( const char* haystack, const char* needle, S32 offset ), ( 0 ),
+   "Find the start of @a needle in @a haystack searching from right to left beginning at the given offset.\n"
+   "@param haystack The string to search.\n"
+   "@param needle The string to search for.\n"
+   "@return The index at which the first occurrence of @a needle was found in @a heystack or -1 if no match was found.\n\n"
+   "@tsexample\n"
+   "strposr( \"b ab\", \"b\", 1 ) // Returns 2.\n"
+   "@endtsexample\n"
+   "@ingroup Strings" )
+{
+   U32 sublen = dStrlen( needle );
+   U32 strlen = dStrlen( haystack );
+   S32 start = strlen - offset;
+   	
+   if(start < 0 || start > strlen)
+      return -1;
+   
+   if (start + sublen > strlen)
+	  start = strlen - sublen;
+   for(; start >= 0; start--)
+      if(!dStrncmp(haystack + start, needle, sublen))
+         return start;
+   return -1;
+}
+
+//-----------------------------------------------------------------------------
+
 DefineConsoleFunction( ltrim, const char*, ( const char* str ),,
    "Remove leading whitespace from the string.\n"
    "@param str A string.\n"
@@ -627,6 +823,18 @@ DefineConsoleFunction( stripTrailingNumber, String, ( const char* str ),,
    return String::GetTrailingNumber( str, suffix );
 }
 
+//-----------------------------------------------------------------------------
+
+DefineConsoleFunction( getFirstNumber, String, ( const char* str ),,
+   "Get the first occuring number from @a str.\n"
+   "@param str The string from which to read out the first number.\n"
+   "@return String representation of the number or "" if no number.\n\n")
+{
+   U32 start;
+   U32 end;
+   return String::GetFirstNumber(str, start, end);
+}
+
 //----------------------------------------------------------------
 
 DefineConsoleFunction( isspace, bool, ( const char* str, S32 index ),,
@@ -811,6 +1019,192 @@ DefineConsoleFunction( strrchrpos, S32, ( const char* str, const char* chr, S32
    return index;
 }
 
+//----------------------------------------------------------------
+
+DefineConsoleFunction(ColorFloatToInt, ColorI, (ColorF color), ,
+	"Convert from a float color to an integer color (0.0 - 1.0 to 0 to 255).\n"
+	"@param color Float color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha.\n"
+	"@return Converted color value (0 - 255)\n\n"
+	"@tsexample\n"
+	"ColorFloatToInt( \"0 0 1 0.5\" ) // Returns \"0 0 255 128\".\n"
+	"@endtsexample\n"
+	"@ingroup Strings")
+{
+	return (ColorI)color;
+}
+
+DefineConsoleFunction(ColorIntToFloat, ColorF, (ColorI color), ,
+   "Convert from a integer color to an float color (0 to 255 to 0.0 - 1.0).\n"
+   "@param color Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha.\n"
+   "@return Converted color value (0.0 - 1.0)\n\n"
+   "@tsexample\n"
+   "ColorIntToFloat( \"0 0 255 128\" ) // Returns \"0 0 1 0.5\".\n"
+   "@endtsexample\n"
+   "@ingroup Strings")
+{
+   return (ColorF)color;
+}
+
+DefineConsoleFunction(ColorRGBToHEX, const char*, (ColorI color), ,
+   "Convert from a integer RGB (red, green, blue) color to hex color value (0 to 255 to 00 - FF).\n"
+   "@param color Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. It excepts an alpha, but keep in mind this will not be converted.\n"
+   "@return Hex color value (#000000 - #FFFFFF), alpha isn't handled/converted so it is only the RGB value\n\n"
+   "@tsexample\n"
+   "ColorRBGToHEX( \"0 0 255 128\" ) // Returns \"#0000FF\".\n"
+   "@endtsexample\n"
+   "@ingroup Strings")
+{
+   return Con::getReturnBuffer(color.getHex());
+}
+
+DefineConsoleFunction(ColorRGBToHSB, const char*, (ColorI color), ,
+   "Convert from a integer RGB (red, green, blue) color to HSB (hue, saturation, brightness). HSB is also know as HSL or HSV as well, with the last letter standing for lightness or value.\n"
+   "@param color Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. It excepts an alpha, but keep in mind this will not be converted.\n"
+   "@return HSB color value, alpha isn't handled/converted so it is only the RGB value\n\n"
+   "@tsexample\n"
+   "ColorRBGToHSB( \"0 0 255 128\" ) // Returns \"240 100 100\".\n"
+   "@endtsexample\n"
+   "@ingroup Strings")
+{
+   ColorI::Hsb hsb(color.getHSB());
+   String s(String::ToString(hsb.hue) + " " + String::ToString(hsb.sat) + " " + String::ToString(hsb.brightness));
+   return Con::getReturnBuffer(s);
+}
+
+DefineConsoleFunction(ColorHEXToRGB, ColorI, (const char* hex), ,
+   "Convert from a hex color value to an integer RGB (red, green, blue) color (00 - FF to 0 to 255).\n"
+   "@param hex Hex color value (#000000 - #FFFFFF) to be converted to an RGB (red, green, blue) value.\n"
+   "@return Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. Alpha isn't handled/converted so only pay attention to the RGB value\n\n"
+   "@tsexample\n"
+   "ColorHEXToRGB( \"#0000FF\" ) // Returns \"0 0 255 0\".\n"
+   "@endtsexample\n"
+   "@ingroup Strings")
+{
+   S32 rgb = dAtoui(hex, 16);
+
+   ColorI color;
+   color.set(rgb & 0x000000FF, (rgb & 0x0000FF00) >> 8, (rgb & 0x00FF0000) >> 16);
+   return color;
+}
+
+DefineConsoleFunction(ColorHSBToRGB, ColorI, (Point3I hsb), ,
+   "Convert from a HSB (hue, saturation, brightness) to an integer RGB (red, green, blue) color. HSB is also know as HSL or HSV as well, with the last letter standing for lightness or value.\n"
+   "@param hsb HSB (hue, saturation, brightness) value to be converted.\n"
+   "@return Integer color value to be converted in the form \"R G B A\", where R is red, G is green, B is blue, and A is alpha. Alpha isn't handled/converted so only pay attention to the RGB value\n\n"
+   "@tsexample\n"
+   "ColorHSBToRGB( \"240 100 100\" ) // Returns \"0 0 255 0\".\n"
+   "@endtsexample\n"
+   "@ingroup Strings")
+{
+   ColorI color;
+   color.set(ColorI::Hsb(hsb.x, hsb.y, hsb.z));
+   return color;
+}
+
+//----------------------------------------------------------------
+
+DefineConsoleFunction( strToggleCaseToWords, const char*, ( const char* str ),,
+   "Parse a Toggle Case word into separate words.\n"
+   "@param str The string to parse.\n"
+   "@return new string space separated.\n\n"
+   "@tsexample\n"
+   "strToggleCaseToWords( \"HelloWorld\" ) // Returns \"Hello World\".\n"
+   "@endtsexample\n"
+   "@ingroup Strings" )
+{
+   String newStr;
+   for(S32 i = 0; str[i]; i++)
+   {
+      //If capitol add a space
+      if(i != 0 && str[i] >= 65 && str[i] <= 90)
+         newStr += " "; 
+
+      newStr += str[i]; 
+   }
+
+   return Con::getReturnBuffer(newStr);
+}
+
+//----------------------------------------------------------------
+
+// Warning: isInt and isFloat are very 'strict' and might need to be adjusted to allow other values. //seanmc
+DefineConsoleFunction( isInt, bool, ( const char* str),,
+   "Returns true if the string is an integer.\n"
+   "@param str The string to test.\n"
+   "@return true if @a str is an integer and false if not\n\n"
+   "@tsexample\n"
+   "isInt( \"13\" ) // Returns true.\n"
+   "@endtsexample\n"
+   "@ingroup Strings" )
+{
+   return isInt(str);
+}
+
+//----------------------------------------------------------------
+
+DefineConsoleFunction( isFloat, bool, ( const char* str, bool sciOk), (false),
+   "Returns true if the string is a float.\n"
+   "@param str The string to test.\n"
+   "@param sciOk Test for correct scientific notation and accept it (ex. 1.2e+14)"
+   "@return true if @a str is a float and false if not\n\n"
+   "@tsexample\n"
+   "isFloat( \"13.5\" ) // Returns true.\n"
+   "@endtsexample\n"
+   "@ingroup Strings" )
+{
+   return isFloat(str, sciOk);
+}
+
+//----------------------------------------------------------------
+
+DefineConsoleFunction( isValidPort, bool, ( const char* str),,
+   "Returns true if the string is a valid port number.\n"
+   "@param str The string to test.\n"
+   "@return true if @a str is a port and false if not\n\n"
+   "@tsexample\n"
+   "isValidPort( \"8080\" ) // Returns true.\n"
+   "@endtsexample\n"
+   "@ingroup Strings" )
+{
+   if(isInt(str))
+   {
+      U16 port = dAtous(str);
+      return isValidPort(port);
+   }
+   else
+      return false;
+}
+
+//----------------------------------------------------------------
+
+DefineConsoleFunction( isValidIP, bool, ( const char* str),,
+   "Returns true if the string is a valid ip address, excepts localhost.\n"
+   "@param str The string to test.\n"
+   "@return true if @a str is a valid ip address and false if not\n\n"
+   "@tsexample\n"
+   "isValidIP( \"localhost\" ) // Returns true.\n"
+   "@endtsexample\n"
+   "@ingroup Strings" )
+{
+   if(dStrcmp(str, "localhost") == 0)
+   {
+      return true;
+   }
+   else
+      return isValidIP(str);
+}
+
+//----------------------------------------------------------------
+
+// Torque won't normally add another string if it already exists with another casing,
+// so this forces the addition. It should be called once near the start, such as in main.cs.
+ConsoleFunction(addCaseSensitiveStrings,void,2,0,"[string1, string2, ...]"
+                "Adds case sensitive strings to the StringTable.")
+{
+	for(int i = 1; i < argc; i++)
+		StringTable->insert(argv[i], true);
+}
+
 //=============================================================================
 //    Field Manipulators.
 //=============================================================================
@@ -829,6 +1223,7 @@ DefineConsoleFunction( getWord, const char*, ( const char* text, S32 index ),,
    "@endtsexample\n\n"
    "@see getWords\n"
    "@see getWordCount\n"
+   "@see getToken\n"
    "@see getField\n"
    "@see getRecord\n"
    "@ingroup FieldManip" )
@@ -852,6 +1247,7 @@ DefineConsoleFunction( getWords, const char*, ( const char* text, S32 startIndex
    "@endtsexample\n\n"
    "@see getWord\n"
    "@see getWordCount\n"
+   "@see getTokens\n"
    "@see getFields\n"
    "@see getRecords\n"
    "@ingroup FieldManip" )
@@ -876,6 +1272,7 @@ DefineConsoleFunction( setWord, const char*, ( const char* text, S32 index, cons
       "setWord( \"a b c d\", 2, \"f\" ) // Returns \"a b f d\"\n"
    "@endtsexample\n\n"
    "@see getWord\n"
+   "@see setToken\n"
    "@see setField\n"
    "@see setRecord\n"
    "@ingroup FieldManip" )
@@ -895,6 +1292,7 @@ DefineConsoleFunction( removeWord, const char*, ( const char* text, S32 index ),
    "@tsexample\n"
       "removeWord( \"a b c d\", 2 ) // Returns \"a b d\"\n"
    "@endtsexample\n\n"
+   "@see removeToken\n"
    "@see removeField\n"
    "@see removeRecord\n"
    "@ingroup FieldManip" )
@@ -912,6 +1310,7 @@ DefineConsoleFunction( getWordCount, S32, ( const char* text ),,
    "@tsexample\n"
       "getWordCount( \"a b c d e\" ) // Returns 5\n"
    "@endtsexample\n\n"
+   "@see getTokenCount\n"
    "@see getFieldCount\n"
    "@see getRecordCount\n"
    "@ingroup FieldManip" )
@@ -921,6 +1320,49 @@ DefineConsoleFunction( getWordCount, S32, ( const char* text ),,
 
 //-----------------------------------------------------------------------------
 
+DefineEngineFunction( monthNumToStr, String, ( S32 num, bool abbreviate ), (false),
+   "@brief returns month as a word given a number or \"\" if number is bad"
+   "@return month as a word given a number or \"\" if number is bad"
+   "@ingroup FileSystem")
+{
+   switch(num)
+   {
+      case 1: return abbreviate ? "Jan" : "January"; break;
+      case 2: return abbreviate ? "Feb" : "February"; break;
+      case 3: return abbreviate ? "Mar" : "March"; break;
+      case 4: return abbreviate ? "Apr" : "April"; break;
+      case 5: return "May"; break;
+      case 6: return abbreviate ? "Jun" : "June"; break;
+      case 7: return abbreviate ? "Jul" : "July"; break;
+      case 8: return abbreviate ? "Aug" : "August"; break;
+      case 9: return abbreviate ? "Sep" : "September"; break;
+      case 10: return abbreviate ? "Oct" : "October"; break;
+      case 11: return abbreviate ? "Nov" : "November"; break;
+      case 12: return abbreviate ? "Dec" : "December"; break;
+      default: return "";
+   }
+}
+
+DefineEngineFunction( weekdayNumToStr, String, ( S32 num, bool abbreviate ), (false),
+   "@brief returns weekday as a word given a number or \"\" if number is bad"
+   "@return weekday as a word given a number or \"\" if number is bad"
+   "@ingroup FileSystem")
+{
+   switch(num)
+   {
+      case 0: return abbreviate ? "Sun" : "Sunday"; break;
+      case 1: return abbreviate ? "Mon" : "Monday"; break;
+      case 2: return abbreviate ? "Tue" : "Tuesday"; break;
+      case 3: return abbreviate ? "Wed" : "Wednesday"; break;
+      case 4: return abbreviate ? "Thu" : "Thursday"; break;
+      case 5: return abbreviate ? "Fri" : "Friday"; break;
+      case 6: return abbreviate ? "Sat" : "Saturday"; break;
+      default: return "";
+   }
+}
+
+//-----------------------------------------------------------------------------
+
 DefineConsoleFunction( getField, const char*, ( const char* text, S32 index ),,
    "Extract the field at the given @a index in the newline and/or tab separated list in @a text.\n"
    "Fields in @a text must be separated by newlines and/or tabs.\n"
@@ -1242,6 +1684,114 @@ DefineConsoleFunction( nextToken, const char*, ( const char* str1, const char* t
    return ret;
 }
 
+//-----------------------------------------------------------------------------
+
+DefineConsoleFunction( getToken, const char*, ( const char* text, const char* delimiters, S32 index ),,
+   "Extract the substring at the given @a index in the @a delimiters separated list in @a text.\n"
+   "@param text A @a delimiters list of substrings.\n"
+   "@param delimiters Character or characters that separate the list of substrings in @a text.\n"
+   "@param index The zero-based index of the substring to extract.\n"
+   "@return The substring at the given index or \"\" if the index is out of range.\n\n"
+   "@tsexample\n"
+      "getToken( \"a b c d\", \" \", 2 ) // Returns \"c\"\n"
+   "@endtsexample\n\n"
+   "@see getTokens\n"
+   "@see getTokenCount\n"
+   "@see getWord\n"
+   "@see getField\n"
+   "@see getRecord\n"
+   "@ingroup FieldManip" )
+{
+   return Con::getReturnBuffer( StringUnit::getUnit(text, index, delimiters));
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleFunction( getTokens, const char*, ( const char* text, const char* delimiters, S32 startIndex, S32 endIndex ), ( -1 ),
+   "Extract a range of substrings separated by @a delimiters at the given @a startIndex onwards thru @a endIndex.\n"
+   "@param text A @a delimiters list of substrings.\n"
+   "@param delimiters Character or characters that separate the list of substrings in @a text.\n"
+   "@param startIndex The zero-based index of the first substring to extract from @a text.\n"
+   "@param endIndex The zero-based index of the last substring to extract from @a text.  If this is -1, all words beginning "
+      "with @a startIndex are extracted from @a text.\n"
+   "@return A string containing the specified range of substrings from @a text or \"\" if @a startIndex "
+      "is out of range or greater than @a endIndex.\n\n"
+   "@tsexample\n"
+      "getTokens( \"a b c d\", \" \", 1, 2, ) // Returns \"b c\"\n"
+   "@endtsexample\n\n"
+   "@see getToken\n"
+   "@see getTokenCount\n"
+   "@see getWords\n"
+   "@see getFields\n"
+   "@see getRecords\n"
+   "@ingroup FieldManip" )
+{
+   if( endIndex < 0 )
+      endIndex = 1000000;
+
+   return Con::getReturnBuffer( StringUnit::getUnits( text, startIndex, endIndex, delimiters ) );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleFunction( setToken, const char*, ( const char* text, const char* delimiters, S32 index, const char* replacement ),,
+   "Replace the substring in @a text separated by @a delimiters at the given @a index with @a replacement.\n"
+   "@param text A @a delimiters list of substrings.\n"
+   "@param delimiters Character or characters that separate the list of substrings in @a text.\n"
+   "@param index The zero-based index of the substring to replace.\n"
+   "@param replacement The string with which to replace the substring.\n"
+   "@return A new string with the substring at the given @a index replaced by @a replacement or the original "
+      "string if @a index is out of range.\n\n"
+   "@tsexample\n"
+      "setToken( \"a b c d\", \" \", 2, \"f\" ) // Returns \"a b f d\"\n"
+   "@endtsexample\n\n"
+   "@see getToken\n"
+   "@see setWord\n"
+   "@see setField\n"
+   "@see setRecord\n"
+   "@ingroup FieldManip" )
+{
+   return Con::getReturnBuffer( StringUnit::setUnit( text, index, replacement, delimiters) );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleFunction( removeToken, const char*, ( const char* text, const char* delimiters, S32 index ),,
+   "Remove the substring in @a text separated by @a delimiters at the given @a index.\n"
+   "@param text A @a delimiters list of substrings.\n"
+   "@param delimiters Character or characters that separate the list of substrings in @a text.\n"
+   "@param index The zero-based index of the word in @a text.\n"
+   "@return A new string with the substring at the given index removed or the original string if @a index is "
+      "out of range.\n\n"
+   "@tsexample\n"
+      "removeToken( \"a b c d\", \" \", 2 ) // Returns \"a b d\"\n"
+   "@endtsexample\n\n"
+   "@see removeWord\n"
+   "@see removeField\n"
+   "@see removeRecord\n"
+   "@ingroup FieldManip" )
+{
+   return Con::getReturnBuffer( StringUnit::removeUnit( text, index, delimiters ) );
+}
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleFunction( getTokenCount, S32, ( const char* text, const char* delimiters),,
+   "Return the number of @a delimiters substrings in @a text.\n"
+   "@param text A @a delimiters list of substrings.\n"
+   "@param delimiters Character or characters that separate the list of substrings in @a text.\n"
+   "@return The number of @a delimiters substrings in @a text.\n\n"
+   "@tsexample\n"
+      "getTokenCount( \"a b c d e\", \" \" ) // Returns 5\n"
+   "@endtsexample\n\n"
+   "@see getWordCount\n"
+   "@see getFieldCount\n"
+   "@see getRecordCount\n"
+   "@ingroup FieldManip" )
+{
+   return StringUnit::getUnitCount( text, delimiters );
+}
+
 //=============================================================================
 //    Tagged Strings.
 //=============================================================================
@@ -2597,3 +3147,10 @@ DefineEngineFunction( isToolBuild, bool, (),,
    return false;
 #endif
 }
+
+DefineEngineFunction( getMaxDynamicVerts, S32, (),,
+	"Get max number of allowable dynamic vertices in a single vertex buffer.\n\n"
+	"@return the max number of allowable dynamic vertices in a single vertex buffer" )
+{
+   return MAX_DYNAMIC_VERTS / 2;
+}

+ 16 - 0
Engine/source/console/consoleFunctions.h

@@ -0,0 +1,16 @@
+#ifndef _CONSOLFUNCTIONS_H_
+#define _CONSOLFUNCTIONS_H_
+
+#ifndef _STRINGFUNCTIONS_H_
+#include "core/strings/stringFunctions.h"
+#endif
+
+bool isInt(const char* str);
+
+bool isFloat(const char* str);
+
+bool isValidIP(const char* ip);
+
+bool isValidPort(U16 port);
+
+#endif

+ 196 - 162
Engine/source/console/consoleObject.h

@@ -48,7 +48,7 @@
    #include "console/simObjectRef.h"
 #endif
 #ifndef TINYXML_INCLUDED
-   #include "tinyXML/tinyxml.h"
+   #include "tinyxml.h"
 #endif
 
 /// @file
@@ -212,7 +212,7 @@ public:
    ///
    /// @param conIdPtr Pointer to the static S32 console ID.
    /// @param conTypeName Console type name.
-   AbstractClassRep( S32* conIdPtr, const char* typeName ) 
+   AbstractClassRep( S32* conIdPtr, const char* typeName )
       : Parent( sizeof( void* ), conIdPtr, typeName )
    {
       VECTOR_SET_ASSOCIATION( mFieldList );
@@ -323,13 +323,13 @@ public:
 
    /// Return the namespace that contains the methods of this class.
    Namespace* getNameSpace() const { return mNamespace; }
-   
+
    /// Return the AbstractClassRep of the class that this class is derived from.
    AbstractClassRep* getParentClass() const { return parentClass; }
 
    virtual AbstractClassRep*    getContainerChildClass(const bool recurse) = 0;
    virtual WriteCustomTamlSchema getCustomTamlSchema(void) = 0;
-   
+
    /// Return the size of instances of this class in bytes.
    S32 getSizeof() const { return mClassSizeof; }
 
@@ -396,7 +396,7 @@ protected:
    Namespace *        mNamespace;
 
    /// @}
-   
+
 public:
 
    bool mIsRenderEnabled;
@@ -404,23 +404,23 @@ public:
 
    bool isRenderEnabled() const { return mIsRenderEnabled; }
    bool isSelectionEnabled() const { return mIsSelectionEnabled; }
-      
+
    /// @name Categories
    /// @{
-   
+
 protected:
 
    const char* mCategory;
    const char* mDescription;
-      
+
 public:
 
    /// Return the space separated category path for the class.
    const char* getCategory() const { return mCategory; }
-   
+
    /// Return a short description string suitable for displaying in tooltips.
    const char* getDescription() const { return mDescription; }
-   
+
    /// @}
 
    /// @name Fields
@@ -434,16 +434,12 @@ public:
    /// This is a function pointer typedef to support optional writing for fields.
    typedef bool(*WriteDataNotify)(void* obj, StringTableEntry pFieldName);
 
-   /// Allows the writing of a custom TAML schema.
-   typedef void(*WriteCustomTamlSchema)(const AbstractClassRep* pClassRep, TiXmlElement* pParentElement);
-
-
    /// These are special field type values used to mark
    /// groups and arrays in the field list.
    /// @see Field::type
    /// @see addArray, endArray
-   /// @see addGroup, endGroup   
-   /// @see addGroup, endGroup   
+   /// @see addGroup, endGroup
+   /// @see addGroup, endGroup
    /// @see addDeprecatedField
    enum ACRFieldTypes
    {
@@ -451,35 +447,35 @@ public:
       /// types greater or equal to this one are not
       /// console data types.
       ARCFirstCustomField = 0xFFFFFFFB,
-      
+
       /// Marks the start of a fixed size array of fields.
       /// @see addArray
       StartArrayFieldType = 0xFFFFFFFB,
-      
+
       /// Marks the end of a fixed size array of fields.
       /// @see endArray
       EndArrayFieldType   = 0xFFFFFFFC,
-      
+
       /// Marks the beginning of a group of fields.
       /// @see addGroup
       StartGroupFieldType = 0xFFFFFFFD,
-      
+
       /// Marks the beginning of a group of fields.
       /// @see endGroup
       EndGroupFieldType   = 0xFFFFFFFE,
-      
-      /// Marks a field that is depreciated and no 
+
+      /// Marks a field that is depreciated and no
       /// longer stores a value.
       /// @see addDeprecatedField
       DeprecatedFieldType = 0xFFFFFFFF
    };
-   
+
    enum FieldFlags
    {
       FIELD_HideInInspectors     = BIT( 0 ),    ///< Do not show the field in inspectors.
    };
 
-   struct Field 
+   struct Field
    {
       Field()
          :  pFieldname( NULL ),
@@ -525,10 +521,10 @@ public:
 
    /// @name Console Type Interface
    /// @{
-   
+
    virtual void* getNativeVariable() { return new ( AbstractClassRep* ); } // Any pointer-sized allocation will do.
    virtual void deleteNativeVariable( void* var ) { delete reinterpret_cast< AbstractClassRep** >( var ); }
-   
+
    /// @}
 
    /// @name Abstract Class Database
@@ -571,122 +567,141 @@ extern AbstractClassRep::FieldList sg_tempFieldList;
 /// @see AbtractClassRep
 /// @see ConsoleObject
 template< class T >
-class ConcreteClassRep : public AbstractClassRep
+class ConcreteAbstractClassRep : public AbstractClassRep
 {
-   public:
-   
-      static EnginePropertyTable _smPropertyTable;
-      static EnginePropertyTable& smPropertyTable;
-      
-      ConcreteClassRep(    const char* name,
-                           const char* conTypeName,
-                           S32* conTypeIdPtr,
-                           S32 netClassGroupMask,
-                           S32 netClassType,
-                           S32 netEventDir,
-                           AbstractClassRep* parent,
-                           const char* ( *parentDesc )() )
-         : AbstractClassRep( conTypeIdPtr, conTypeName )
-      {
-         mClassName = StringTable->insert( name );
-         mCategory = T::__category();
-         mTypeInfo = _MAPTYPE< T >();
-         
-         if( mTypeInfo )
-            const_cast< EngineTypeInfo* >( mTypeInfo )->mPropertyTable = &smPropertyTable;
-         
-         if( &T::__description != parentDesc )
-            mDescription = T::__description();
-
-         // Clean up mClassId
-         for(U32 i = 0; i < NetClassGroupsCount; i++)
-            mClassId[i] = -1;
-
-         // Set properties for this ACR
-         mClassType      = netClassType;
-         mClassGroupMask = netClassGroupMask;
-         mNetEventDir    = netEventDir;
-         parentClass     = parent;
-         mClassSizeof    = sizeof(T);
-
-         // Finally, register ourselves.
-         registerClassRep(this);
-      };
-
-      virtual AbstractClassRep* getContainerChildClass(const bool recurse)
-      {
-         // Fetch container children type.
-         AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
-         if (!recurse || pChildren != NULL)
-            return pChildren;
-
-         // Fetch parent type.
-         AbstractClassRep* pParent = T::getParentStaticClassRep();
-         if (pParent == NULL)
-            return NULL;
-
-         // Get parent container children.
-         return pParent->getContainerChildClass(recurse);
-      }
+public:
 
-      virtual WriteCustomTamlSchema getCustomTamlSchema(void)
-      {
-         return T::getStaticWriteCustomTamlSchema();
-      }
+   virtual AbstractClassRep* getContainerChildClass(const bool recurse)
+   {
+      // Fetch container children type.
+      AbstractClassRep* pChildren = T::getContainerChildStaticClassRep();
+      if (!recurse || pChildren != NULL)
+         return pChildren;
+
+      // Fetch parent type.
+      AbstractClassRep* pParent = T::getParentStaticClassRep();
+      if (pParent == NULL)
+         return NULL;
+
+      // Get parent container children.
+      return pParent->getContainerChildClass(recurse);
+   }
 
-      /// Perform class specific initialization tasks.
-      ///
-      /// Link namespaces, call initPersistFields() and consoleInit().
-      void init()
-      {
-         // Get handle to our parent class, if any, and ourselves (we are our parent's child).
-         AbstractClassRep *parent = T::getParentStaticClassRep();
-         AbstractClassRep *child  = T::getStaticClassRep();
-                  
-         // If we got reps, then link those namespaces! (To get proper inheritance.)
-         if(parent && child)
-            Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
-
-         // Finally, do any class specific initialization...
-         T::initPersistFields();
-         T::consoleInit();
-
-         // Let the base finish up.
-         AbstractClassRep::init();
-      }
+   virtual WriteCustomTamlSchema getCustomTamlSchema(void)
+   {
+      return T::getStaticWriteCustomTamlSchema();
+   }
 
-      /// Wrap constructor.
-      ConsoleObject* create() const { return new T; }
-      
-      /// @name Console Type Interface
-      /// @{
+   static EnginePropertyTable _smPropertyTable;
+   static EnginePropertyTable& smPropertyTable;
+
+   ConcreteAbstractClassRep(const char* name,
+      const char* conTypeName,
+      S32* conTypeIdPtr,
+      S32 netClassGroupMask,
+      S32 netClassType,
+      S32 netEventDir,
+      AbstractClassRep* parent,
+      const char* (*parentDesc)())
+      : AbstractClassRep(conTypeIdPtr, conTypeName)
+   {
+      mClassName = StringTable->insert(name);
+      mCategory = T::__category();
+      mTypeInfo = _MAPTYPE< T >();
+
+      if (mTypeInfo)
+         const_cast< EngineTypeInfo* >(mTypeInfo)->mPropertyTable = &smPropertyTable;
+
+      if (&T::__description != parentDesc)
+          mDescription = T::__description();
+
+      // Clean up mClassId
+      for (U32 i = 0; i < NetClassGroupsCount; i++)
+         mClassId[i] = -1;
+
+      // Set properties for this ACR
+      mClassType = netClassType;
+      mClassGroupMask = netClassGroupMask;
+      mNetEventDir = netEventDir;
+      parentClass = parent;
+      mClassSizeof = sizeof(T);
+ 
+      // Finally, register ourselves.
+      registerClassRep(this);
+   };
+ 
+   /// Wrap constructor.
+   ConsoleObject* create() const { return NULL; }
 
-      virtual void setData( void* dptr, S32 argc, const char** argv, const EnumTable* tbl, BitSet32 flag )
-      {
-         if( argc == 1 )
-         {
-            T** obj = ( T** ) dptr;
-            *obj = dynamic_cast< T* >( T::__findObject( argv[ 0 ] ) );
-         }
-         else
-            Con::errorf( "Cannot set multiple args to a single ConsoleObject*.");
-      }
-      
-      virtual const char* getData( void* dptr, const EnumTable* tbl, BitSet32 flag )
+   /// Perform class specific initialization tasks.
+   ///
+   /// Link namespaces, call initPersistFields() and consoleInit().
+   void init()
+   {
+      // Get handle to our parent class, if any, and ourselves (we are our parent's child).
+      AbstractClassRep *parent = T::getParentStaticClassRep();
+      AbstractClassRep *child = T::getStaticClassRep();
+ 
+       // If we got reps, then link those namespaces! (To get proper inheritance.)
+      if (parent && child)
+         Con::classLinkNamespaces(parent->getNameSpace(), child->getNameSpace());
+
+      // Finally, do any class specific initialization...
+      T::initPersistFields();
+      T::consoleInit();
+ 
+      // Let the base finish up.
+      AbstractClassRep::init();
+   }
+ 
+   /// @name Console Type Interface
+   /// @{
+ 
+   virtual void setData(void* dptr, S32 argc, const char** argv, const EnumTable* tbl, BitSet32 flag)
+   {
+      if (argc == 1)
       {
-         T** obj = ( T** ) dptr;
-         return Con::getReturnBuffer( T::__getObjectId( *obj ) );
+         T** obj = (T**)dptr;
+         *obj = dynamic_cast< T* >(T::__findObject(argv[0]));
       }
-      
-      virtual const char* getTypeClassName() { return mClassName; }
-      virtual const bool isDatablock() { return T::__smIsDatablock; };
-      
-      /// @}
-};
+      else
+          Con::errorf("Cannot set multiple args to a single ConsoleObject*.");
+   }
+ 
+   virtual const char* getData(void* dptr, const EnumTable* tbl, BitSet32 flag)
+   {
+       T** obj = (T**)dptr;
+       return Con::getReturnBuffer(T::__getObjectId(*obj));
+   }
+ 
+   virtual const char* getTypeClassName() { return mClassName; }
+   virtual const bool isDatablock() { return T::__smIsDatablock; };
 
-template< typename T > EnginePropertyTable ConcreteClassRep< T >::_smPropertyTable( 0, NULL );
-template< typename T > EnginePropertyTable& ConcreteClassRep< T >::smPropertyTable = ConcreteClassRep< T >::_smPropertyTable;
+   /// @}
+ };
+ 
+ template< class T >
+ class ConcreteClassRep : public ConcreteAbstractClassRep<T>
+ {
+ public:
+    ConcreteClassRep(const char* name,
+       const char* conTypeName,
+       S32* conTypeIdPtr,
+       S32 netClassGroupMask,
+       S32 netClassType,
+       S32 netEventDir,
+       AbstractClassRep* parent,
+       const char* (*parentDesc)())
+       : ConcreteAbstractClassRep<T>(name, conTypeName, conTypeIdPtr, netClassGroupMask, netClassType, netEventDir, parent, parentDesc)
+    {
+    }
+ 
+   /// Wrap constructor.
+   ConsoleObject* create() const { return new T; }
+};
 
+template< typename T > EnginePropertyTable ConcreteAbstractClassRep< T >::_smPropertyTable(0, NULL);
+template< typename T > EnginePropertyTable& ConcreteAbstractClassRep< T >::smPropertyTable = ConcreteAbstractClassRep< T >::_smPropertyTable;
 
 //------------------------------------------------------------------------------
 // Forward declaration of this function so  it can be used in the class
@@ -751,7 +766,7 @@ bool defaultProtectedWriteFn(void* obj, StringTableEntry pFieldName);
 class ConsoleObject : public EngineObject
 {
    DECLARE_ABSTRACT_CLASS( ConsoleObject, EngineObject );
-   
+
 protected:
 
    /// @deprecated This is disallowed.
@@ -760,16 +775,25 @@ protected:
 public:
 
    ConsoleObject() {}
-   
+
    /// Get a reference to a field by name.
    const AbstractClassRep::Field *findField(StringTableEntry fieldName) const;
 
    /// Gets the ClassRep.
    virtual AbstractClassRep* getClassRep() const;
 
+#define DECLARE_ABSTRACT_CONOBJECT( className )                \
+   DECLARE_ABSTRACT_CLASS( className, Parent );                \
+   static S32 _smTypeId;                                       \
+   static ConcreteAbstractClassRep< className > dynClassRep;   \
+   static AbstractClassRep* getParentStaticClassRep();         \
+   static AbstractClassRep* getStaticClassRep();               \
+   static SimObjectRefConsoleBaseType< className > ptrRefType; \
+   virtual AbstractClassRep* getClassRep() const 
+
    /// Set the value of a field.
    bool setField(const char *fieldName, const char *value);
-   
+
 public:
 
    /// @name Object Creation
@@ -799,11 +823,11 @@ public:
    static void endGroup(const char*  in_pGroupname);
 
    /// Marks the start of a fixed size array of fields.
-   /// @see console_autodoc   
+   /// @see console_autodoc
    static void addArray( const char *arrayName, S32 count );
 
    /// Marks the end of an array of fields.
-   /// @see console_autodoc      
+   /// @see console_autodoc
    static void endArray( const char *arrayName );
 
    /// Register a complex field.
@@ -928,16 +952,16 @@ public:
    static bool removeField(const char* in_pFieldname);
 
    /// @}
-   
+
    /// @name Logging
    /// @{
-   
+
    /// Overload this in subclasses to change the message formatting.
    /// @param fmt A printf style format string.
    /// @param args A va_list containing the args passed ot a log function.
    /// @note It is suggested that you use String::VToString.
    virtual String _getLogMessage(const char* fmt, va_list args) const;
-   
+
    /// @}
 
 public:
@@ -946,16 +970,16 @@ public:
    /// These functions will try to print out a message along the lines
    /// of "ObjectClass - ObjectName(ObjectId) - formatted message"
    /// @{
-   
+
    /// Logs with Con::printf.
    void logMessage(const char* fmt, ...) const;
-   
+
    /// Logs with Con::warnf.
    void logWarning(const char* fmt, ...) const;
-   
+
    /// Logs with Con::errorf.
    void logError(const char* fmt, ...) const;
-   
+
    /// @}
 
    /// Register dynamic fields in a subclass of ConsoleObject.
@@ -1016,16 +1040,16 @@ public:
 
    static const char* __category() { return ""; }
    static const char* __description() { return ""; }
-   
+
    /// Subclasses of ConsoleObjects that are datablocks should redefine this static member variable
    /// and set it to true.
    static const bool __smIsDatablock = false;
-   
+
    /// @name Object IDs and lookup.
    /// For a subclass hierarchy based on ConsoleObject to become functional for use as a console object type,
    /// the hierarchy must implement a naming scheme and indexing function for looking up objects by name.
    /// @{
-   
+
    static ConsoleObject* __findObject( const char* ) { return NULL; }
    static const char* __getObjectId( ConsoleObject* ) { return ""; }
 };
@@ -1120,11 +1144,11 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    static SimObjectRefConsoleBaseType< className > ptrRefType;         \
    static AbstractClassRep::WriteCustomTamlSchema getStaticWriteCustomTamlSchema();         \
    static AbstractClassRep* getContainerChildStaticClassRep();         \
-   virtual AbstractClassRep* getClassRep() const      
-      
+   virtual AbstractClassRep* getClassRep() const
+
 #define DECLARE_CATEGORY( string )                      \
    static const char* __category() { return string; }
-   
+
 #define DECLARE_DESCRIPTION( string )                   \
    static const char* __description() { return string; }
 
@@ -1140,7 +1164,7 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
 
-#define IMPLEMENT_CONOBJECT_CHILDREN( className )                                                           \
+#define IMPLEMENT_CONOBJECT_CHILDREN( className )                                                  \
    IMPLEMENT_CLASS( className, NULL )                                                              \
    END_IMPLEMENT_CLASS;                                                                            \
    S32 className::_smTypeId;                                                                       \
@@ -1148,11 +1172,11 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
-   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }                 \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }        \
    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
 
-#define IMPLEMENT_CONOBJECT_SCHEMA( className, schema )                                                           \
+#define IMPLEMENT_CONOBJECT_SCHEMA( className, schema )                                            \
    IMPLEMENT_CLASS( className, NULL )                                                              \
    END_IMPLEMENT_CLASS;                                                                            \
    S32 className::_smTypeId;                                                                       \
@@ -1164,7 +1188,7 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; }            \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
 
-#define IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA( className, schema )                                                           \
+#define IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA( className, schema )                                   \
    IMPLEMENT_CLASS( className, NULL )                                                              \
    END_IMPLEMENT_CLASS;                                                                            \
    S32 className::_smTypeId;                                                                       \
@@ -1172,10 +1196,20 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
-   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }                 \
+   AbstractClassRep* className::getContainerChildStaticClassRep() { return Children::getStaticClassRep(); }          \
    AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return schema; }            \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
 
+#define IMPLEMENT_ABSTRACT_CONOBJECT( className )                                                  \
+   IMPLEMENT_NONINSTANTIABLE_CLASS( className, NULL )                                              \
+   END_IMPLEMENT_CLASS;                                                                            \
+   S32 className::_smTypeId;                                                                       \
+   SimObjectRefConsoleBaseType< className > className::ptrRefType( "Type" #className "Ref" );      \
+   AbstractClassRep* className::getClassRep() const { return &className::dynClassRep; }            \
+   AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                       \
+   AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }  \
+   ConcreteAbstractClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, 0, -1, 0, className::getParentStaticClassRep(), &Parent::__description )
+
 #define IMPLEMENT_CO_NETOBJECT_V1( className )                                                           \
    IMPLEMENT_CLASS( className, NULL )                                                                    \
    END_IMPLEMENT_CLASS;                                                                                  \
@@ -1185,7 +1219,7 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                             \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }        \
    AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }        \
-   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }  \
    ConcreteClassRep<className> className::dynClassRep( #className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeObject, 0, className::getParentStaticClassRep(), &Parent::__description )
 
 #define IMPLEMENT_CO_DATABLOCK_V1( className )                                                           \
@@ -1197,9 +1231,9 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    AbstractClassRep* className::getStaticClassRep() { return &dynClassRep; }                             \
    AbstractClassRep* className::getParentStaticClassRep() { return Parent::getStaticClassRep(); }        \
    AbstractClassRep* className::getContainerChildStaticClassRep() { return NULL; }                 \
-   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }            \
+   AbstractClassRep::WriteCustomTamlSchema className::getStaticWriteCustomTamlSchema() { return NULL; }  \
    ConcreteClassRep<className> className::dynClassRep(#className, "Type" #className, &_smTypeId, NetClassGroupGameMask, NetClassTypeDataBlock, 0, className::getParentStaticClassRep(), &Parent::__description )
-   
+
 // Support for adding properties to classes CONOBJECT style.
 #define PROPERTY_TABLE( className )                                                                      \
    namespace { namespace _ ## className {                                                                \
@@ -1209,13 +1243,13 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
    ConcreteClassRep< className >::smPropertyTable = _ ## className::_propTable;                          \
    namespace { namespace _ ## className {                                                                \
       EnginePropertyTable::Property _props[] = {
-      
+
 #define END_PROPERTY_TABLE                                                                               \
          { NULL }                                                                                        \
       };                                                                                                 \
       EnginePropertyTable _propTable( sizeof( _props ) / sizeof( _props[ 0 ] ) - 1, _props );            \
    } }
-   
+
 /// Add an auto-doc for a class.
 #define ConsoleDocClass( className, docString ) \
    CLASSDOC( className, docString )
@@ -1225,7 +1259,7 @@ inline bool& ConsoleObject::getDynamicGroupExpand()
 //------------------------------------------------------------------------------
 // Protected field default get/set functions
 //
-// The reason for these functions is that it will save one branch per console 
+// The reason for these functions is that it will save one branch per console
 // data request and script functions will still execute at the same speed as
 // before the modifications to allow protected static fields. These will just
 // inline and the code should be roughly the same size, and just as fast as

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

@@ -362,7 +362,7 @@ class EngineTypeInfo : public EngineExportScope
       // them to retroactively install property tables.  Will be removed
       // when the console interop is removed and all classes are migrated
       // to the new system.
-      template< typename T > friend class ConcreteClassRep;
+      template< typename T > friend class ConcreteAbstractClassRep;
       
    protected:
       

+ 285 - 0
Engine/source/core/color.h

@@ -30,6 +30,10 @@
 #include "math/mPoint4.h" 
 #endif
 
+#ifndef _ENGINEAPI_H_
+#include "console/engineAPI.h"
+#endif
+
 class ColorI;
 
 
@@ -121,9 +125,20 @@ class ColorI
    U8 blue;
    U8 alpha;
 
+   struct Hsb
+   {
+      Hsb() :hue(0), sat(0), brightness(0){};
+      Hsb(U32 h, U32 s, U32 b) :hue(h), sat(s), brightness(b){};
+
+      U32 hue;   ///Hue
+      U32 sat;   ///Saturation
+      U32 brightness;   //Brightness/Value/Lightness
+   };
+
   public:
    ColorI() { }
    ColorI(const ColorI& in_rCopy);
+   ColorI(const Hsb& color);
    ColorI(const U8 in_r,
           const U8 in_g,
           const U8 in_b,
@@ -132,6 +147,12 @@ class ColorI
 
    ColorI( const char* pStockColorName );
 
+   void set(const Hsb& color);
+
+   void HSLtoRGB_Subfunction(U32& c, const F64& temp1, const F64& temp2, const F64& temp3);
+
+   void set(const String& hex);
+
    void set(const U8 in_r,
             const U8 in_g,
             const U8 in_b,
@@ -176,6 +197,11 @@ class ColorI
    U16 get565()  const;
    U16 get4444() const;
 
+   Hsb getHSB() const;
+
+   String getHex() const;
+   S32 convertFromHex(const String& hex) const;
+
    operator ColorF() const;
 
    operator const U8*() const { return &red; }
@@ -459,6 +485,174 @@ inline void ColorI::set(const ColorI& in_rCopy,
    alpha = in_a;
 }
 
+inline void ColorI::set(const Hsb& color)
+{
+	U32 r = 0;
+	U32 g = 0;
+	U32 b = 0;
+
+	F64 L = ((F64)color.brightness) / 100.0;
+	F64 S = ((F64)color.sat) / 100.0;
+	F64 H = ((F64)color.hue) / 360.0;
+
+	if (color.sat == 0)
+	{
+		r = color.brightness;
+		g = color.brightness;
+		b = color.brightness;
+	}
+	else
+	{
+		F64 temp1 = 0;
+		if (L < 0.50)
+		{
+			temp1 = L*(1 + S);
+		}
+		else
+		{
+			temp1 = L + S - (L*S);
+		}
+
+		F64 temp2 = 2.0*L - temp1;
+
+		F64 temp3 = 0;
+		for (S32 i = 0; i < 3; i++)
+		{
+			switch (i)
+			{
+			case 0: // red
+			{
+				temp3 = H + 0.33333;
+				if (temp3 > 1.0)
+					temp3 -= 1.0;
+				HSLtoRGB_Subfunction(r, temp1, temp2, temp3);
+				break;
+			}
+			case 1: // green
+			{
+				temp3 = H;
+				HSLtoRGB_Subfunction(g, temp1, temp2, temp3);
+				break;
+			}
+			case 2: // blue
+			{
+				temp3 = H - 0.33333;
+				if (temp3 < 0)
+					temp3 += 1;
+				HSLtoRGB_Subfunction(b, temp1, temp2, temp3);
+				break;
+			}
+			default:
+			{
+
+			}
+			}
+		}
+	}
+	red = (U32)((((F64)r) / 100) * 255);
+	green = (U32)((((F64)g) / 100) * 255);
+	blue = (U32)((((F64)b) / 100) * 255);
+}
+
+// This is a subfunction of HSLtoRGB
+inline void ColorI::HSLtoRGB_Subfunction(U32& c, const F64& temp1, const F64& temp2, const F64& temp3)
+{
+	if ((temp3 * 6.0) < 1.0)
+		c = (U32)((temp2 + (temp1 - temp2)*6.0*temp3)*100.0);
+	else
+		if ((temp3 * 2.0) < 1.0)
+			c = (U32)(temp1*100.0);
+		else
+			if ((temp3 * 3.0) < 2.0)
+				c = (U32)((temp2 + (temp1 - temp2)*(0.66666 - temp3)*6.0)*100.0);
+			else
+				c = (U32)(temp2*100.0);
+	return;
+}
+
+inline void ColorI::set(const String& hex)
+{
+	String redString;
+	String greenString;
+	String blueString;
+
+	//if the prefix # was attached to hex
+	if (hex[0] == '#')
+	{
+		redString = hex.substr(1, 2);
+		greenString = hex.substr(3, 2);
+		blueString = hex.substr(5, 2);
+	}
+	else
+	{
+		// since there is no prefix attached to hex
+		redString = hex.substr(0, 2);
+		greenString = hex.substr(2, 2);
+		blueString = hex.substr(4, 2);
+	}
+
+	red = (U8)(convertFromHex(redString));
+	green = (U8)(convertFromHex(greenString));
+	blue = (U8)(convertFromHex(blueString));
+}
+
+inline S32 ColorI::convertFromHex(const String& hex) const
+{
+	S32 hexValue = 0;
+
+	S32 a = 0;
+	S32 b = hex.length() - 1;
+
+	for (; b >= 0; a++, b--)
+	{
+		if (hex[b] >= '0' && hex[b] <= '9')
+		{
+			hexValue += (hex[b] - '0') * (1 << (a * 4));
+		}
+		else
+		{
+			switch (hex[b])
+			{
+			case 'A':
+			case 'a':
+				hexValue += 10 * (1 << (a * 4));
+				break;
+
+			case 'B':
+			case 'b':
+				hexValue += 11 * (1 << (a * 4));
+				break;
+
+			case 'C':
+			case 'c':
+				hexValue += 12 * (1 << (a * 4));
+				break;
+
+			case 'D':
+			case 'd':
+				hexValue += 13 * (1 << (a * 4));
+				break;
+
+			case 'E':
+			case 'e':
+				hexValue += 14 * (1 << (a * 4));
+				break;
+
+			case 'F':
+			case 'f':
+				hexValue += 15 * (1 << (a * 4));
+				break;
+
+			default:
+				Con::errorf("Error, invalid character '%c' in hex number", hex[a]);
+				break;
+			}
+		}
+	}
+
+	return hexValue;
+}
+
 inline ColorI::ColorI(const ColorI& in_rCopy)
 {
    red   = in_rCopy.red;
@@ -467,6 +661,11 @@ inline ColorI::ColorI(const ColorI& in_rCopy)
    alpha = in_rCopy.alpha;
 }
 
+inline ColorI::ColorI(const Hsb& color)
+{
+	set(color);
+}
+
 inline ColorI::ColorI(const U8 in_r,
                const U8 in_g,
                const U8 in_b,
@@ -503,6 +702,7 @@ inline ColorI& ColorI::operator*=(const S32 in_mul)
 
 inline ColorI& ColorI::operator/=(const S32 in_mul)
 {
+   AssertFatal(in_mul != 0.0f, "Error, div by zero...");
    red   = red    / in_mul;
    green = green  / in_mul;
    blue  = blue   / in_mul;
@@ -647,6 +847,91 @@ inline U16 ColorI::get4444() const
               U16(U16(blue  >> 4) <<  0));
 }
 
+inline ColorI::Hsb ColorI::getHSB() const
+{
+	F64 rPercent = ((F64)red) / 255;
+	F64 gPercent = ((F64)green) / 255;
+	F64 bPercent = ((F64)blue) / 255;
+
+	F64 maxColor = 0.0;
+	if ((rPercent >= gPercent) && (rPercent >= bPercent))
+		maxColor = rPercent;
+	if ((gPercent >= rPercent) && (gPercent >= bPercent))
+		maxColor = gPercent;
+	if ((bPercent >= rPercent) && (bPercent >= gPercent))
+		maxColor = bPercent;
+
+	F64 minColor = 0.0;
+	if ((rPercent <= gPercent) && (rPercent <= bPercent))
+		minColor = rPercent;
+	if ((gPercent <= rPercent) && (gPercent <= bPercent))
+		minColor = gPercent;
+	if ((bPercent <= rPercent) && (bPercent <= gPercent))
+		minColor = bPercent;
+
+	F64 H = 0.0;
+	F64 S = 0.0;
+	F64 B = 0.0;
+
+	B = (maxColor + minColor) / 2.0;
+
+	if (maxColor == minColor)
+	{
+		H = 0.0;
+		S = 0.0;
+	}
+	else
+	{
+		if (B < 0.50)
+		{
+			S = (maxColor - minColor) / (maxColor + minColor);
+		}
+		else
+		{
+			S = (maxColor - minColor) / (2.0 - maxColor - minColor);
+		}
+		if (maxColor == rPercent)
+		{
+			H = (gPercent - bPercent) / (maxColor - minColor);
+		}
+		if (maxColor == gPercent)
+		{
+			H = 2.0 + (bPercent - rPercent) / (maxColor - minColor);
+		}
+		if (maxColor == bPercent)
+		{
+			H = 4.0 + (rPercent - gPercent) / (maxColor - minColor);
+		}
+	}
+
+	ColorI::Hsb val;
+	val.sat = (U32)(S * 100);
+	val.brightness = (U32)(B * 100);
+	H = H*60.0;
+	if (H < 0.0)
+		H += 360.0;
+	val.hue = (U32)H;
+
+	return val;
+}
+
+inline String ColorI::getHex() const
+{
+	char r[255];
+	dSprintf(r, sizeof(r), "%.2X", red);
+	String result(r);
+
+	char g[255];
+	dSprintf(g, sizeof(g), "%.2X", green);
+	result += g;
+
+	char b[255];
+	dSprintf(b, sizeof(b), "%.2X", blue);
+	result += b;
+
+	return result;
+}
+
 //-------------------------------------- INLINE CONVERSION OPERATORS
 inline ColorF::operator ColorI() const
 {

+ 1 - 1
Engine/source/core/idGenerator.h

@@ -74,7 +74,7 @@ public:
 
    void free(U32 id)
    {
-      AssertFatal(id >= mIdBlockBase, "IdGenerator::alloc: invalid id, id does not belong to this IdGenerator.")
+      AssertFatal(id >= mIdBlockBase, "IdGenerator::alloc: invalid id, id does not belong to this IdGenerator.");
       if(id == mNextId - 1)
       {
          mNextId--;

+ 1 - 1
Engine/source/core/stream/stream.cpp

@@ -128,7 +128,7 @@ bool Stream::writeFormattedBuffer(const char *format, ...)
    char buffer[4096];
    va_list args;
    va_start(args, format);
-   const S32 length = vsprintf(buffer, format, args);
+   const S32 length = dVsprintf(buffer, sizeof(buffer), format, args);
 
    // Sanity!
    AssertFatal(length <= sizeof(buffer), "writeFormattedBuffer - String format exceeded buffer size.  This will cause corruption.");

+ 9 - 0
Engine/source/core/strings/stringFunctions.h

@@ -152,11 +152,20 @@ inline U32 dAtoui(const char *str, U32 base = 10)
    return strtoul(str, NULL, base);
 }
 
+inline U16 dAtous(const char *str, U32 base = 10)
+{
+   return strtoul(str, NULL, base);
+}
+
 inline F32 dAtof(const char *str)
 {
    return strtof(str, NULL);
 }
 
+inline F64 dAtod(const char *str)
+{
+   return strtod(str, NULL);
+}
 
 inline char dToupper(const char c)
 {

+ 100 - 0
Engine/source/core/util/str.cpp

@@ -1628,3 +1628,103 @@ String String::GetTrailingNumber(const char* str, S32& number)
 
    return base.substr(0, p - base.c_str());
 }
+
+String String::GetFirstNumber(const char* str, U32& startPos, U32& endPos)
+{
+   // Check for trivial strings
+   if (!str || !str[0])
+      return String::EmptyString;
+
+   // Find the number at the end of the string
+   String base(str);
+   const char* p = base.c_str();
+   const char* end = base.c_str() + base.length() - 1;
+   bool dec = false;
+   startPos = 0;
+
+   //Check if we are just a digit
+   if(p == end && isdigit(*p))
+      return base;
+
+   //Look for the first digit
+   while ((p != end) && (dIsspace(*p) || !isdigit(*p)))
+   {
+      p++;
+      startPos++;
+   }
+
+   //Handle if we are at the end and found nothing
+   if(p == end && !isdigit(*p))
+      return "";
+
+   //update our end position at least to the start of our number
+   endPos = startPos;
+
+   //Backup our ptr
+   const char* backup = p;
+
+   //Check for any negative or decimal values
+   if(startPos > 0)
+   {
+      p--;
+      startPos--;
+      if(*p == '.')
+      {
+         dec = true;
+
+         //ignore any duplicate periods
+         while ((p != base.c_str()) && (*p == '.'))
+         {
+            p--;
+            startPos--;
+         }
+
+         //Found a decimal lets still check for negative sign
+         if(startPos > 0)
+         {
+            p--;
+            startPos--;
+            if((*p != '-') && (*p != '_'))
+            {
+               startPos++;
+               p++;
+            }
+         }
+      }
+      else if((*p != '-') && (*p != '_'))
+      {
+         //go back to where we where cause no decimal or negative sign found
+         startPos++;
+         p++;
+      }
+   }
+
+   //Restore where we were
+   p = backup;
+
+   //look for the end of the digits
+   bool justFoundDec = false;
+   while (p != end)
+   {
+      if(*p == '.')
+      {
+         if(dec && !justFoundDec)
+            break;
+         else
+         {
+            dec = true;
+            justFoundDec = true;
+         }
+      }
+      else if(!isdigit(*p))
+         break;
+      else if(justFoundDec)
+         justFoundDec = false;
+
+      p++;
+      endPos++;
+   }
+
+   U32 len = (!isdigit(*p)) ? endPos - startPos : (endPos + 1) - startPos;
+   return base.substr(startPos, len);
+}

+ 1 - 0
Engine/source/core/util/str.h

@@ -191,6 +191,7 @@ public:
    static String ToUpper(const String &string);
 
    static String GetTrailingNumber(const char* str, S32& number);
+   static String GetFirstNumber(const char* str, U32& startPos, U32& endPos);
 
    /// @}
 

+ 1 - 2
Engine/source/core/util/swizzle.h

@@ -120,8 +120,7 @@ inline void Swizzle<T, mapLength>::ToBuffer( void *destination, const void *sour
 {
    // TODO: OpenMP?
    AssertFatal( size % ( sizeof( T ) * mapLength ) == 0, "Bad buffer size for swizzle, see docs." );
-   AssertFatal( destination != NULL, "Swizzle::ToBuffer - got a NULL destination pointer!" );
-   AssertFatal( source != NULL, "Swizzle::ToBuffer - got a NULL source pointer!" );
+   if (!destination || !source) return;
 
    T *dest = reinterpret_cast<T *>( destination );
    const T *src = reinterpret_cast<const T *>( source );

+ 1319 - 0
Engine/source/environment/VolumetricFog.cpp

@@ -0,0 +1,1319 @@
+//-----------------------------------------------------------------------------
+// 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 "environment/VolumetricFog.h"
+#include "windowManager/platformWindowMgr.h"
+#include "gfx/gfxTransformSaver.h"
+#include "renderInstance/renderPassManager.h"
+#include "math/mathIO.h"
+#include "materials/shaderData.h"
+#include "math/util/matrixSet.h"
+#include "core/resourceManager.h"
+#include "core/stream/bitStream.h"
+#include "T3D/gameBase/gameConnection.h"
+#include "T3D/shapeBase.h"
+#include "ts/tsShapeInstance.h"
+#include "console/engineAPI.h"
+#include "gui/core/guiCanvas.h"
+#include "VolumetricFogRTManager.h"
+#include "lighting/lightInfo.h"
+#include "lighting/lightManager.h"
+
+#define COLBOX_SCALE Point3F(1.02f, 1.02f, 1.02f)
+
+IMPLEMENT_CO_NETOBJECT_V1(VolumetricFog);
+
+ConsoleDocClass(VolumetricFog,
+"@brief Volumetric Fog Object class. Main class defining the Volumetric\n"
+"Fog objects in the scene. Used in conjunction with the VolumetricFogRTManager\n"
+"class which is responsible for the required rendertargets.\n\n"
+"Methods (exposed to script):\n"
+" setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\n;"
+" setFogColor(color) Changes the overall fog color color.rgba range 0 - 255).\n;"
+" setFogDensity(density) Changes the overall fog density.\n"
+" setFogModulation(strength, speed1, speed2) changes the strength\n"
+" and the speeds of the 2 animation layers.\n\n"
+"Callbacks:\n"
+"onEnterFog triggered whenever the controlobject (Player or Camera) enters the Fog.\n"
+" (current Fog object and the controlobject are exposed to script.\n"
+"onLeaveFog triggered whenever the controlobject (Player or Camera) left the Fog.\n"
+" (current Fog object and the controlobject are exposed to script.\n\n"
+"@tsexample\n"
+" new VolumetricFog()\n"
+" {\n"
+" shapeName = \"art/environment/FogRCube.dts\";\n"
+" fogColor = \"200 200 200 128\";\n"
+" fogDensity = \"0.2\";\n"
+" ignoreWater = \"0\";\n"
+" MinSize = \"250\";\n"
+" FadeSize = \"750\";\n"
+" texture = \"art/environment/FogMod_heavy.dds\";\n"
+" tiles = \"1.5\";\n"
+" modStrength = \"0.2\";\n"
+" PrimSpeed = \"-0.01 0.04\";\n"
+" SecSpeed = \"0.02 -0.02\";\n"
+" position = \"748.644 656.371 65.3506\"; \n"
+" rotation = \"0 0 1 20.354\";\n"
+" scale = \"40 30 6\";\n"
+" };\n"
+"@endtsexample\n"
+);
+
+IMPLEMENT_CALLBACK(VolumetricFog, onEnterFog, void, (SimObjectId obj), (obj),
+"@brief Called when an object enters the volume of the Fog instance.\n\n"
+
+"@param obj the controlobject entering the fog.");
+
+IMPLEMENT_CALLBACK(VolumetricFog, onLeaveFog, void, (SimObjectId obj), (obj),
+"@brief Called when an object left the volume of the Fog instance.\n\n"
+
+"@param obj the controlobject leaving the fog.");
+
+
+VolumetricFog::VolumetricFog()
+{
+   AssertFatal(VFRTM != NULL, "VolumetricFog Fatal Error: No Manager found");
+
+   if (!VFRTM->IsInitialized())
+   VFRTM->Init();
+
+   mNetFlags.set(Ghostable | ScopeAlways);
+
+   mTypeMask |= EnvironmentObjectType | StaticObjectType;
+
+   mPrepassTarget = NULL;
+   mDepthBufferTarget = NULL;
+   mFrontBufferTarget = NULL;
+
+   z_buf = NULL;
+   mTexture = NULL;
+
+   mIsVBDirty = false;
+   mIsPBDirty = false;
+
+   mFogColor.set(200, 200, 200, 255);
+   mFogDensity = 0.3f;
+   mIgnoreWater = false;
+   mReflect = false;
+   mCamInFog = false;
+   mResizing = false;
+   mFogReflStrength = 20.0;
+   mUseGlow = false;
+   mGlowStrength = 0.3f;
+   mGlowing = 0;
+   mModifLightRays = false;
+   mLightRayMod = 1.0f;
+   mOldLightRayStrength = 0.1f;
+
+   mShapeName = "";
+   mShapeLoaded = false;
+   mMinDisplaySize = 10.0f;
+   mFadeSize = 0.0f;
+   mCurDetailLevel = 0;
+   mNumDetailLevels = 0;
+   det_size.clear();
+
+   mTextureName = "";
+   mIsTextured = false;
+   mStrength = 0.5f;
+   mTexTiles = 1.0f;
+   mSpeed1.set(0.5f, 0.0f);
+   mSpeed2.set(0.1f, 0.1f);
+}
+
+VolumetricFog::~VolumetricFog()
+{
+   if (isClientObject())
+      return;
+
+   for (S32 i = 0; i < det_size.size(); i++)
+   {
+      if (det_size[i].indices != NULL)
+         delete(det_size[i].indices);
+      if (det_size[i].piArray != NULL)
+         delete(det_size[i].piArray);
+      if (det_size[i].verts != NULL)
+         delete(det_size[i].verts);
+   }
+   det_size.clear();
+
+   if (z_buf.isValid())
+      SAFE_DELETE(z_buf);
+
+   if (!mTexture.isNull())
+      mTexture.free();
+}
+
+void VolumetricFog::initPersistFields()
+{
+   addGroup("VolumetricFogData");
+   addField("shapeName", TypeShapeFilename, Offset(mShapeName, VolumetricFog),
+      "Path and filename of the model file (.DTS, .DAE) to use for this Volume.");
+   addField("FogColor", TypeColorI, Offset(mFogColor, VolumetricFog),
+      "Fog color RGBA (Alpha is ignored)");
+   addField("FogDensity", TypeF32, Offset(mFogDensity, VolumetricFog), 
+      "Overal fog density value (0 disables the fog).");
+   addField("IgnoreWater", TypeBool, Offset(mIgnoreWater, VolumetricFog), 
+      "Set to true if volumetric fog should continue while submerged.");
+   addField("MinSize", TypeF32, Offset(mMinDisplaySize, VolumetricFog), 
+      "Min size (in pixels) for fog to be rendered.");
+   addField("FadeSize", TypeF32, Offset(mFadeSize, VolumetricFog), 
+      "Object size in pixels at which the FX-fading kicks in (0 disables fading).");
+   endGroup("VolumetricFogData");
+
+   addGroup("VolumetricFogModulation");
+   addField("texture", TypeImageFilename, Offset(mTextureName, VolumetricFog),
+      "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation.");
+   addField("tiles", TypeF32, Offset(mTexTiles, VolumetricFog), 
+      "How many times the texture is mapped to the object.");
+   addField("modStrength", TypeF32, Offset(mStrength, VolumetricFog),
+      "Overall strength of the density modulation (0 disables modulation).");
+   addField("PrimSpeed", TypePoint2F, Offset(mSpeed1, VolumetricFog),
+      "Overall primary speed of the density modulation (x-speed(u) y-speed(v))");
+   addField("SecSpeed", TypePoint2F, Offset(mSpeed2, VolumetricFog),
+      "Overall secundary speed of the density modulation (x-speed(u) y-speed(v))");
+   endGroup("VolumetricFogModulation");
+
+   addGroup("Reflections");
+   addField("Reflectable", TypeBool, Offset(mReflect, VolumetricFog), 
+      "Set to true if volumetric fog should be reflected.");
+   addField("ReflectStrength", TypeF32, Offset(mFogReflStrength, VolumetricFog), 
+      "Strength of the reflections (0 disables the fog).");
+   endGroup("Reflections");
+
+   addGroup("PostFX");
+   addField("useGlow", TypeBool, Offset(mUseGlow, VolumetricFog), 
+      "Set to true if volumetric fog should use glow PostFX.");
+   addField("glowStrength", TypeF32, Offset(mGlowStrength, VolumetricFog),
+      "Overall strength of the glow PostFX.");
+   addField("modLightRay", TypeBool, Offset(mModifLightRays, VolumetricFog), 
+      "Set to true if volumetric fog should modify the brightness of the Lightrays.");
+   addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog),
+      "Modifier for LightRay PostFX when inside Fog.");
+   endGroup("PostFX");
+   Parent::initPersistFields();
+}
+
+void VolumetricFog::inspectPostApply()
+{
+   Parent::inspectPostApply();
+   mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y);
+   setMaskBits(VolumetricFogMask | FogColorMask | FogDensityMask | FogModulationMask | FogPostFXMask | FogShapeMask);
+}
+
+bool VolumetricFog::onAdd()
+{
+   if (!Parent::onAdd())
+      return false;
+
+   if (!VFRTM->IsInitialized())
+   {
+      Con::errorf("No VolumetricFogRTManager present!!");
+      return false;
+   }
+
+   resetWorldBox();
+
+   mShapeLoaded = LoadShape();
+
+   setRenderTransform(mObjToWorld);
+
+   addToScene();
+   ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE));
+   mObjSize = mWorldBox.getGreatestDiagonalLength();
+   mObjScale = getScale();
+   mTexTiles = mAbs(mTexTiles);
+   mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y);
+   mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
+
+   if (isClientObject())
+   {
+      conn = GameConnection::getConnectionToServer();
+      if (!conn)
+      {  
+         Con::errorf("VolumetricFog::onAdd - No Serverconnection");
+         return false;
+      }
+
+      glowFX = static_cast<PostEffect*>(Sim::findObject("VolFogGlowPostFx"));
+
+      mOldLightRayStrength = Con::getFloatVariable("$LightRayPostFX::brightScalar",1.0f);
+
+      GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas"));
+      if (cv == NULL)
+      {
+         Con::errorf("VolumetricFog::onAdd - Canvas not found!!");
+         return false;
+      }
+      mPlatformWindow = cv->getPlatformWindow();
+      VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().notify(this, &VolumetricFog::handleResize);
+      GuiCanvas::getCanvasSizeChangeSignal().notify(this, &VolumetricFog::handleCanvasResize);
+
+      InitTexture();
+      return setupRenderer();
+   }
+
+   VFRTM->IncFogObjects();
+   
+   return true;
+}
+
+void VolumetricFog::onRemove()
+{
+   if (isClientObject())
+   {
+      if (isTicking())
+      {
+         setProcessTick(false);
+         if (mGlowing != 0)
+         {
+            mGlowing = 0;
+            glowFX->disable();
+         }
+         _leaveFog(static_cast<ShapeBase*>(conn->getControlObject()));
+      }
+      VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().remove(this, &VolumetricFog::handleResize);
+      GuiCanvas::getCanvasSizeChangeSignal().remove(this, &VolumetricFog::handleCanvasResize);
+   }
+   removeFromScene();
+   VFRTM->DecFogObjects();
+   Parent::onRemove();
+}
+void VolumetricFog::handleCanvasResize(GuiCanvas* canvas)
+{
+   UpdateBuffers(0,true);
+}
+
+void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize)
+{
+   if (resize)
+   {
+      mResizing = true;
+      RTM->FogAnswered();
+   }
+   else
+      mResizing = false;
+
+   if (mIsTextured)
+   {
+      F32 width = (F32)mPlatformWindow->getClientExtent().x;
+      F32 height = (F32)mPlatformWindow->getClientExtent().y;
+      if (!mPlatformWindow->isFullscreen())
+         height -= 20;//subtract caption bar from rendertarget size.
+      mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width);
+      mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height);
+   }
+
+   UpdateBuffers(0,true);
+}
+
+//-----------------------------------------------------------------------------
+// Loadshape extracted from TSMesh and TSShapeInstance
+//-----------------------------------------------------------------------------
+
+bool VolumetricFog::LoadShape()
+{
+   GFXPrimitiveType GFXdrawTypes[] = { GFXTriangleList, GFXTriangleStrip };
+   if (!mShapeName || mShapeName[0] == '\0')
+   {
+      Con::errorf("VolumetricFog::LoadShape() - No shape name! Volumetric Fog will not be rendered!");
+      return false;
+   }
+
+   // Load shape, server side only reads bounds and radius
+
+   Resource<TSShape> mShape;
+   mShape = ResourceManager::get().load(mShapeName);
+   if (bool(mShape) == false)
+   {
+      Con::errorf("VolumetricFog::LoadShape() - Unable to load shape: %s", mShapeName);
+      return false;
+   }
+
+   mObjBox = mShape->bounds;
+   mRadius = mShape->radius;
+   resetWorldBox();
+
+   if (!isClientObject())
+      return false;
+
+   TSShapeInstance *mShapeInstance = new TSShapeInstance(mShape, false);
+   meshes mesh_detail;
+
+   for (S32 i = 0; i < det_size.size(); i++)
+   {
+      if (det_size[i].indices != NULL)
+         delete(det_size[i].indices);
+      if (det_size[i].piArray != NULL)
+         delete(det_size[i].piArray);
+      if (det_size[i].verts != NULL)
+         delete(det_size[i].verts);
+   }
+   det_size.clear();
+
+   // browsing model for detail levels
+
+   for (U32 i = 0; i < mShape->details.size(); i++)
+   {
+      const TSDetail *detail = &mShape->details[i];
+      mesh_detail.det_size = detail->size;
+      mesh_detail.sub_shape = detail->subShapeNum;
+      mesh_detail.obj_det = detail->objectDetailNum;
+      mesh_detail.verts = NULL;
+      mesh_detail.piArray = NULL;
+      mesh_detail.indices = NULL;
+      if (detail->size >= 0.0f && detail->subShapeNum >= 0)
+         det_size.push_back(mesh_detail);
+   }
+
+   for (U32 i = 0; i < det_size.size(); i++)
+   {
+      const S32 ss = det_size[i].sub_shape;
+      if (ss >= 0)
+      {
+         const S32 start = mShape->subShapeFirstObject[ss];
+         const S32 end = start + mShape->subShapeNumObjects[ss];
+         for (S32 j = start; j < end; j++)
+         {
+            // Loading shape, only the first mesh for each detail will be used!
+            TSShapeInstance::MeshObjectInstance *meshObj = &mShapeInstance->mMeshObjects[j];
+            if (!meshObj)
+               continue;
+            TSMesh *mesh = meshObj->getMesh(det_size[i].obj_det);
+            if (mesh != NULL)
+            {
+               const U32 numNrms = mesh->mNumVerts;
+               GFXVertexPNTT *tmpVerts = NULL;
+               tmpVerts = new GFXVertexPNTT[numNrms];
+               mIsVBDirty = true;
+               for (U32 k = 0; k < numNrms; k++)
+                  {
+                     Point3F norm = mesh->mVertexData[k].normal();
+                     Point3F vert = mesh->mVertexData[k].vert();
+                     Point2F uv = mesh->mVertexData[k].tvert();
+                     tmpVerts[k].point = vert;
+                     tmpVerts[k].texCoord = uv;
+                     tmpVerts[k].normal = norm;
+                  }
+               det_size[i].verts = tmpVerts;
+               det_size[i].num_verts = numNrms;
+
+               det_size[i].piArray = new Vector<GFXPrimitive>();
+               GFXPrimitive pInfo;
+
+               det_size[i].indices = new Vector<U32>();
+
+               for (U32 k = 0; k < mesh->indices.size(); k++)
+                  det_size[i].indices->push_back(mesh->indices[k]);
+
+               U32 primitivesSize = mesh->primitives.size();
+               for (U32 k = 0; k < primitivesSize; k++)
+               {
+                  const TSDrawPrimitive & draw = mesh->primitives[k];
+                  GFXPrimitiveType drawType = GFXdrawTypes[draw.matIndex >> 30];
+                  switch (drawType)
+                  {
+                     case GFXTriangleList:
+                        pInfo.type = drawType;
+                        pInfo.numPrimitives = draw.numElements / 3;
+                        pInfo.startIndex = draw.start;
+                        // Use the first index to determine which 16-bit address space we are operating in
+                        pInfo.startVertex = mesh->indices[draw.start] & 0xFFFF0000;
+                        pInfo.minIndex = pInfo.startVertex;
+                        pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex);
+                        break;
+                     case GFXTriangleStrip:
+                        pInfo.type = drawType;
+                        pInfo.numPrimitives = draw.numElements - 2;
+                        pInfo.startIndex = draw.start;
+                        // Use the first index to determine which 16-bit address space we are operating in
+                        pInfo.startVertex = mesh->indices[draw.start] & 0xFFFF0000;
+                        pInfo.minIndex = pInfo.startVertex;
+                        pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex);
+                        break;
+                     default:
+                        Con::errorf("VolumetricFog::LoadShape Unknown drawtype!?!");
+                        return false;
+                        break;
+                  }
+               det_size[i].piArray->push_back(pInfo);
+               j = end;
+            }
+         }
+         else
+         {
+            Con::errorf("VolumetricFog::LoadShape Error loading mesh from shape!");
+            delete mShapeInstance;
+            return false;
+         }
+         mIsVBDirty = true;
+         mIsPBDirty = true;
+         }
+      }
+   }
+
+   mNumDetailLevels = det_size.size();
+   mCurDetailLevel = 0;
+   UpdateBuffers(mCurDetailLevel);
+   delete mShapeInstance;
+
+   return true;
+}
+
+//-----------------------------------------------------------------------------
+// UpdateBuffers called whenever detaillevel changes (LOD)
+//-----------------------------------------------------------------------------
+
+
+bool VolumetricFog::UpdateBuffers(U32 dl, bool force)
+{
+   if (mVB.isNull() || mIsVBDirty || dl != mCurDetailLevel || force)
+   {
+      mVB.set(GFX, det_size[dl].num_verts, GFXBufferTypeDynamic);
+      mIsVBDirty = false;
+   }
+   GFXVertexPNTT *vertPtr = mVB.lock();
+   if (!vertPtr)
+   {
+      mVB.unlock();
+      return false;
+   }
+   dMemcpy(vertPtr, det_size[dl].verts, sizeof (GFXVertexPNTT)* det_size[dl].num_verts);
+   mVB.unlock();
+
+   if (mIsPBDirty || mPB.isNull() || dl != mCurDetailLevel || force)
+   {
+      #ifdef TORQUE_DEBUG
+      mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic, avar("%s() - VolFogPrimBuffer (line %d)", __FUNCTION__, __LINE__));
+      #else
+      mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic);
+      #endif
+      U16 *ibIndices = NULL;
+      GFXPrimitive *piInput = NULL;
+      mPB.lock(&ibIndices, &piInput);
+      dCopyArray(ibIndices, det_size[dl].indices->address(), det_size[dl].indices->size());
+      dMemcpy(piInput, det_size[dl].piArray->address(), det_size[dl].piArray->size() * sizeof(GFXPrimitive));
+      mPB.unlock();
+      mIsPBDirty = false;
+   }
+   mCurDetailLevel = dl;
+   return true;
+}
+
+U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
+{
+   U32 retMask = Parent::packUpdate(con, mask, stream);
+   if (stream->writeFlag(mask & FogColorMask))
+      stream->write(mFogColor);
+   if (stream->writeFlag(mask & FogDensityMask))
+      stream->write(mFogDensity);
+   if (stream->writeFlag(mask & FogModulationMask))
+   {
+      stream->write(mTextureName);
+      mTexTiles = mFabs(mTexTiles);
+      stream->write(mTexTiles);
+      stream->write(mStrength);
+      mathWrite(*stream, mSpeed);
+   }
+   if (stream->writeFlag(mask & FogPostFXMask))
+   {
+      stream->writeFlag(mUseGlow);
+      stream->write(mGlowStrength);
+      stream->writeFlag(mModifLightRays);
+      stream->write(mLightRayMod);
+   }
+   if (stream->writeFlag(mask & VolumetricFogMask))
+   {
+      stream->writeFlag(mIgnoreWater);
+      stream->writeFlag(mReflect);
+      stream->write(mFogReflStrength);
+      stream->writeFlag(mResizing);
+      stream->write(mMinDisplaySize);
+      stream->write(mFadeSize);
+   }
+   if (stream->writeFlag(mask & FogShapeMask))
+   {
+      stream->writeString(mShapeName);
+      mathWrite(*stream, getTransform());
+      mathWrite(*stream, getScale());
+      if (!mShapeName || mShapeName[0] == '\0')
+         return retMask;
+      Resource<TSShape> mShape;
+      mShape = ResourceManager::get().load(mShapeName);
+      if (bool(mShape) == false)
+         return retMask;
+      mObjBox = mShape->bounds;
+      mRadius = mShape->radius;
+      resetWorldBox();
+      mObjSize = mWorldBox.getGreatestDiagonalLength();
+      mObjScale = getScale();
+      mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
+   }
+   return retMask;
+}
+
+void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream)
+{
+   Parent::unpackUpdate(con, stream);
+   MatrixF mat;
+   VectorF scale;
+   VectorF mOldScale = getScale();
+   String oldTextureName = mTextureName;
+   StringTableEntry oldShape = mShapeName;
+
+   if (stream->readFlag())// Fog color
+      stream->read(&mFogColor);
+   if (stream->readFlag())// Fog Density
+   {
+      stream->read(&mFogDensity);
+      if (isTicking())
+      {
+         char buf[20];
+         dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity);
+         Con::setVariable("$VolumetricFog::density", buf);
+      }
+   }
+   if (stream->readFlag())// Fog Modulation
+   {
+      stream->read(&mTextureName);
+      stream->read(&mTexTiles);
+      mTexTiles = mFabs(mTexTiles);
+      stream->read(&mStrength);
+      mathRead(*stream, &mSpeed);
+      mSpeed1.set(mSpeed.x, mSpeed.y);
+      mSpeed2.set(mSpeed.z, mSpeed.w);
+
+      if (isProperlyAdded())
+      {
+         if (oldTextureName != mTextureName)
+            InitTexture();
+         if (oldTextureName.isNotEmpty() && mTextureName.isEmpty())
+         {
+            mIsTextured = false;
+            mTexture.free();
+         }
+      }
+   }
+   if (stream->readFlag())//Fog PostFX
+   {
+      mUseGlow = stream->readFlag();
+      stream->read(&mGlowStrength);
+      mModifLightRays = stream->readFlag();
+      stream->read(&mLightRayMod);
+      if (isTicking())
+      {
+         char buf[20];
+         dSprintf(buf, sizeof(buf), "%3.7f", mGlowStrength);
+         Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
+         if (mUseGlow && !glowFX->isEnabled())
+            glowFX->enable();
+         if (!mUseGlow && glowFX->isEnabled())
+            glowFX->disable();
+         if (mModifLightRays)
+         {
+            char buf[20];
+            dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength * mLightRayMod);
+            Con::setVariable("$LightRayPostFX::brightScalar", buf);
+         }
+         if (!mModifLightRays)
+         {
+            char buf[20];
+            dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength);
+            Con::setVariable("$LightRayPostFX::brightScalar", buf);
+         }
+      }
+   }
+   if (stream->readFlag())//Volumetric Fog
+   {
+      mIgnoreWater = stream->readFlag();
+      mReflect = stream->readFlag();
+      stream->read(&mFogReflStrength);
+      mResizing = stream->readFlag();
+      stream->read(&mMinDisplaySize);
+      stream->read(&mFadeSize);
+   }
+   if (stream->readFlag())//Fog shape
+   {
+      mShapeName = stream->readSTString();
+      mathRead(*stream, &mat);
+      mathRead(*stream, &scale);
+      if (strcmp(oldShape, mShapeName) != 0)
+      {
+         mIsVBDirty = true;
+         mShapeLoaded = LoadShape();
+      }
+      setScale(scale);
+      setTransform(mat);
+      ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE));
+      mObjSize = mWorldBox.getGreatestDiagonalLength();
+      mObjScale = getScale();
+      mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
+   }
+}
+
+void VolumetricFog::processTick(const Move* move)
+{
+   Parent::processTick(move);
+   mCounter++;
+   if ( mGlowing==1 && mCurGlow < mGlowStrength )
+   {
+      mCurGlow += (mGlowStrength / 10.0);
+      char buf[20];
+      dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow);
+      Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
+   }
+   else if ( mGlowing == 2 && mCurGlow > 0.0f )
+   {
+      mCurGlow -= (mGlowStrength / 5.0f);
+      if (mCurGlow <= 0.0f)
+      {
+         glowFX->disable();
+         mGlowing = 0;
+         setProcessTick(false);
+         return;
+      }
+      else
+      {
+         char buf[20];
+         dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow);
+         Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
+      }
+   }
+   if (mCounter == 3)
+   {
+      ShapeBase* control = static_cast<ShapeBase*>(conn->getControlObject());
+      MatrixF xfm;
+      control->getRenderEyeTransform(&xfm);
+      Point3F pos = xfm.getPosition();
+      if (!ColBox.isContained(pos))
+         _leaveFog(control);
+      mCounter = 0;
+   }
+}
+
+void VolumetricFog::_enterFog(ShapeBase *control)
+{
+   if (mUseGlow)
+   {
+      if (glowFX)
+      {
+         mCurGlow = 0.0f;
+         Con::setVariable("$VolFogGlowPostFx::glowStrength", "0.0");
+         glowFX->enable();
+         mGlowing = 1;
+      }
+   }
+   if (mModifLightRays)
+   {
+      char buf[20];
+      dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength * mLightRayMod);
+      Con::setVariable("$LightRayPostFX::brightScalar", buf);
+   }
+   mCounter = 0;
+   char buf[20];
+   dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity);
+   Con::setVariable("$VolumetricFog::density", buf);
+   setProcessTick(true);
+   if (control)
+      onEnterFog_callback(control->getId());
+}
+
+void VolumetricFog::_leaveFog(ShapeBase *control)
+{
+   mCamInFog = false;
+   Con::setVariable("$VolumetricFog::density", "0.0");
+   if (mModifLightRays)
+   {
+      char buf[20];
+      dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength);
+      Con::setVariable("$LightRayPostFX::brightScalar", buf);
+   }
+   if (mUseGlow)
+   {
+      if (glowFX && mGlowing != 2)
+      {
+         mCurGlow = mGlowStrength;
+         mGlowing = 2;
+         if (control)
+            onLeaveFog_callback(control->getId());
+      }
+   }
+   else
+   {
+      setProcessTick(false);
+      if (control)
+         onLeaveFog_callback(control->getId());
+   }
+}
+
+//-----------------------------------------------------------------------------
+// Setting up the renderers
+//-----------------------------------------------------------------------------
+
+bool VolumetricFog::setupRenderer()
+{
+   // Search for the prepass rendertarget and shadermacros.
+   mPrepassTarget = NamedTexTarget::find("prepass");
+   if (!mPrepassTarget.isValid())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find PrepassTarget");
+      return false;
+   }
+
+   Vector<GFXShaderMacro> macros;
+   if (mPrepassTarget)
+      mPrepassTarget->getShaderMacros(&macros);
+
+   // Search the depth and frontbuffers which are created by the VolumetricFogRTManager
+
+   mDepthBufferTarget = NamedTexTarget::find("volfogdepth");
+   if (!mDepthBufferTarget.isValid())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find depthbuffer");
+      return false;
+   }
+
+   mFrontBufferTarget = NamedTexTarget::find("volfogfront");
+   if (!mFrontBufferTarget.isValid())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find frontbuffer");
+      return false;
+   }
+
+   // Find and setup the prepass Shader
+
+   ShaderData *shaderData;
+   mPrePassShader = Sim::findObject("VolumetricFogPrePassShader", shaderData) ?
+   shaderData->getShader() : NULL;
+   if (!mPrePassShader)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogPrePassShader");
+      return false;
+   }
+
+   // Create ShaderConstBuffer and Handles
+
+   mPPShaderConsts = mPrePassShader->allocConstBuffer();
+   if (mPPShaderConsts.isNull())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 1.");
+      return false;
+   }
+
+   mPPModelViewProjSC = mPrePassShader->getShaderConstHandle("$modelView");
+
+   // Find and setup the VolumetricFog Shader
+
+   shaderData = NULL;
+   mShader = Sim::findObject("VolumetricFogShader", shaderData) ?
+   shaderData->getShader(macros) : NULL;
+   if (!mShader)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogShader");
+      return false;
+   }
+
+   // Create ShaderConstBuffer and Handles
+
+   mShaderConsts = mShader->allocConstBuffer();
+   if (mShaderConsts.isNull())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 2.");
+      return false;
+   }
+
+   mModelViewProjSC = mShader->getShaderConstHandle("$modelView");
+   mFadeSizeSC = mShader->getShaderConstHandle("$fadesize");
+   mFogColorSC = mShader->getShaderConstHandle("$fogColor");
+   mFogDensitySC = mShader->getShaderConstHandle("$fogDensity");
+   mPreBias = mShader->getShaderConstHandle("$preBias");
+   mAccumTime = mShader->getShaderConstHandle("$accumTime");
+   mIsTexturedSC = mShader->getShaderConstHandle("$textured");
+   mTexTilesSC = mShader->getShaderConstHandle("$numtiles");
+   mModStrengthSC = mShader->getShaderConstHandle("$modstrength");
+   mModSpeedSC = mShader->getShaderConstHandle("$modspeed");
+   mViewPointSC = mShader->getShaderConstHandle("$viewpoint");
+   mTexScaleSC = mShader->getShaderConstHandle("$texscale");
+   mAmbientColorSC = mShader->getShaderConstHandle("$ambientColor");
+
+   // Find and setup the reflection Shader
+
+   shaderData = NULL;
+   mReflectionShader = Sim::findObject("VolumetricFogReflectionShader", shaderData) ?
+   shaderData->getShader() : NULL;
+   if (!mReflectionShader)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogReflectionShader");
+      return false;
+   }
+
+   mReflShaderConsts = mReflectionShader->allocConstBuffer();
+   if (mReflShaderConsts.isNull())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants for VolumetricFogReflectionShader.");
+      return false;
+   }
+
+   mReflModelViewProjSC = mReflectionShader->getShaderConstHandle("$modelView");
+   mReflFogColorSC = mReflectionShader->getShaderConstHandle("$fogColor");
+   mReflFogDensitySC = mReflectionShader->getShaderConstHandle("$fogDensity");
+   mReflFogStrengthSC = mReflectionShader->getShaderConstHandle("$reflStrength");
+
+   // Create the prepass StateBlock
+
+   desc_preD.setCullMode(GFXCullCW);
+   desc_preD.setBlend(true);
+   desc_preD.setZReadWrite(false, false);
+   desc_preD.stencilEnable = false;
+   desc_preF.setCullMode(GFXCullCCW);
+   desc_preF.setBlend(true);
+   desc_preF.setZReadWrite(true, false);
+   desc_preF.stencilEnable = false;
+   
+   // Create the VolumetricFog StateBlock
+
+   descD.setCullMode(GFXCullCW);
+   descD.setBlend(true);
+   descD.setZReadWrite(false, false);// desc.setZReadWrite(true, false);
+
+   // prepassBuffer sampler
+   descD.samplersDefined = true;
+   descD.samplers[0].addressModeU = GFXAddressClamp;
+   descD.samplers[0].addressModeV = GFXAddressClamp;
+   descD.samplers[0].addressModeW = GFXAddressClamp;
+   descD.samplers[0].magFilter = GFXTextureFilterLinear;
+   descD.samplers[0].minFilter = GFXTextureFilterLinear;
+   descD.samplers[0].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[0].textureColorOp = GFXTOPDisable;
+
+   // DepthBuffer sampler
+   descD.samplers[1].addressModeU = GFXAddressClamp;
+   descD.samplers[1].addressModeV = GFXAddressClamp;
+   descD.samplers[1].addressModeW = GFXAddressClamp;
+   descD.samplers[1].magFilter = GFXTextureFilterLinear;
+   descD.samplers[1].minFilter = GFXTextureFilterLinear;
+   descD.samplers[1].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[1].textureColorOp = GFXTOPModulate;
+
+   // FrontBuffer sampler
+   descD.samplers[2].addressModeU = GFXAddressClamp;
+   descD.samplers[2].addressModeV = GFXAddressClamp;
+   descD.samplers[2].addressModeW = GFXAddressClamp;
+   descD.samplers[2].magFilter = GFXTextureFilterLinear;
+   descD.samplers[2].minFilter = GFXTextureFilterLinear;
+   descD.samplers[2].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[2].textureColorOp = GFXTOPModulate;
+
+   // animated density modifier map sampler
+   descD.samplers[3].addressModeU = GFXAddressWrap;
+   descD.samplers[3].addressModeV = GFXAddressWrap;
+   descD.samplers[3].addressModeW = GFXAddressWrap;
+   descD.samplers[3].magFilter = GFXTextureFilterLinear;
+   descD.samplers[3].minFilter = GFXTextureFilterLinear;
+   descD.samplers[3].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[3].textureColorOp = GFXTOPModulate;
+
+   dMemcpy(&descF, &descD, sizeof(GFXStateBlockDesc));
+   descF.setCullMode(GFXCullCCW);
+   descF.setBlend(true);
+   descF.setZReadWrite(true, false);
+
+   desc_refl.setCullMode(GFXCullCCW);
+   desc_refl.setBlend(true);
+   desc_refl.setZReadWrite(true, false);
+
+   mStateblock_preD = GFX->createStateBlock(desc_preD);
+   mStateblock_preF = GFX->createStateBlock(desc_preF);
+   mStateblockD = GFX->createStateBlock(descD);
+   mStateblockF = GFX->createStateBlock(descF);
+   mStateblock_refl = GFX->createStateBlock(desc_refl);
+
+   // Create Rendertarget
+
+   z_buf = GFX->allocRenderToTextureTarget();
+   if (z_buf == NULL)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - Could not create Render Target");
+      return false;
+   }
+
+   return true;
+}
+
+void VolumetricFog::prepRenderImage(SceneRenderState *state)
+{
+   if (!mShapeLoaded || mFogDensity <= 0.0f || mResizing)
+      return;
+
+   if (!state->isDiffusePass())
+   {
+      if (!state->isReflectPass())
+      return;
+   }
+   
+   PROFILE_SCOPE(VolumetricFog_prepRenderImage);
+
+   // Time critical therefore static_cast
+   ShapeBase* control = static_cast<ShapeBase*>(conn->getControlObject());
+   if (control->getWaterCoverage() >= 0.9f && !mIgnoreWater)
+      return;
+
+   camPos = state->getCameraPosition();
+   F32 dist = (camPos - getBoxCenter()).len();
+   F32 scaleFactor = dist * mInvScale;
+   if (scaleFactor <= 0.0f)
+   {
+      if (mCurDetailLevel != 0)
+         UpdateBuffers(0);
+   }
+   const F32 pixelScale = state->getViewport().extent.y / 300.0f;
+
+   mPixelSize = (mRadius / scaleFactor) * state->getWorldToScreenScale().y * pixelScale;
+   if (mPixelSize < mMinDisplaySize)
+      return;
+   if (mNumDetailLevels > 1)
+   {
+      if ((det_size[mCurDetailLevel].det_size > mPixelSize) && (mCurDetailLevel < mNumDetailLevels - 1))
+         UpdateBuffers(mCurDetailLevel + 1);
+      else if (mCurDetailLevel > 0)
+      {
+         if (mPixelSize >= det_size[mCurDetailLevel - 1].det_size)
+            UpdateBuffers(mCurDetailLevel - 1);
+      }
+   }
+
+   if (state->isReflectPass() && mReflect)
+   {
+      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
+      ri->renderDelegate.bind(this, &VolumetricFog::reflect_render);
+      ri->type = RenderPassManager::RIT_VolumetricFog;
+      ri->translucentSort = true;
+      ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos);
+      if (dist < 1.0f)
+         ri->defaultKey = 1;
+      else
+         ri->defaultKey = U32(dist);
+      state->getRenderPass()->addInst(ri);
+      return;
+   }
+   else if (state->isDiffusePass())
+   {
+      viewDist = state->getFarPlane();
+      mFOV = state->getCameraFrustum().getFov() / M_PI_F;
+      Point3F mEyeVec = state->getVectorEye() * viewDist;
+
+      mViewPoint.x = ((mAtan2(mEyeVec.x, mEyeVec.y) / M_PI_F) + 1.0f) * mTexTiles;
+      mViewPoint.y = (0.5f - (mAsin(mEyeVec.z) / M_PI_F)) * mTexTiles;
+
+      bool isInside = ColBox.isContained(camPos);
+      if (isInside && !mCamInFog)
+      {
+         mCamInFog = true;
+         _enterFog(control);
+      }
+      else if (!isInside && mCamInFog)
+         mCamInFog = false;
+
+      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
+      ri->renderDelegate.bind(this, &VolumetricFog::render);
+      ri->type = RenderPassManager::RIT_VolumetricFog;
+      ri->translucentSort = true;
+      ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos);
+      if (dist < 1.0f)
+         ri->defaultKey = 1;
+      else
+         ri->defaultKey = U32(dist);
+      state->getRenderPass()->addInst(ri);
+      return;
+   }
+   return;
+}
+
+void VolumetricFog::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
+{
+   if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing)
+      return;
+
+   PROFILE_SCOPE(VolumetricFog_Render);
+
+   GFXTransformSaver saver;
+   GFX->setVertexBuffer(mVB);
+   GFX->setPrimitiveBuffer(mPB);
+
+   MatrixF mat = getRenderTransform();
+   mat.scale(mObjScale);
+   GFX->multWorld(mat);
+
+   GFX->setShader(mPrePassShader);
+   GFX->setShaderConstBuffer(mPPShaderConsts);
+   GFX->setStateBlock(mStateblock_preD);
+
+   // Set all the shader consts...
+
+   MatrixF xform(GFX->getProjectionMatrix());
+   xform *= GFX->getViewMatrix();
+   xform *= GFX->getWorldMatrix();
+
+   mPPShaderConsts->setSafe(mPPModelViewProjSC, xform);
+
+   LightInfo *lightinfo = LIGHTMGR->getSpecialLight(LightManager::slSunLightType);
+   const ColorF &sunlight = state->getAmbientLightColor();
+
+   Point3F ambientColor(sunlight.red, sunlight.green, sunlight.blue);
+   mShaderConsts->setSafe(mAmbientColorSC, ambientColor);
+
+   GFXTextureObject *mDepthBuffer = mDepthBufferTarget ? mDepthBufferTarget->getTexture(0) : NULL;
+   GFXTextureObject *mFrontBuffer = mFrontBufferTarget ? mFrontBufferTarget->getTexture(0) : NULL;
+
+   GFX->pushActiveRenderTarget();
+
+   //render backside to target mDepthBuffer
+   z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
+   z_buf->attachTexture(GFXTextureTarget::Color0, mDepthBuffer);
+
+   GFX->setActiveRenderTarget(z_buf);
+   GFX->clear(GFXClearStencil | GFXClearTarget , ColorI(0,0,0,0), 1.0f, 0);
+
+   GFX->drawPrimitive(0);
+   z_buf->resolve();
+
+   //render frontside to target mFrontBuffer
+   z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
+   z_buf->attachTexture(GFXTextureTarget::Color0, mFrontBuffer);
+   GFX->clear(GFXClearStencil | GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0);
+
+   GFX->setStateBlock(mStateblock_preF);
+
+   GFX->drawPrimitive(0);
+   z_buf->resolve();
+
+   GFX->popActiveRenderTarget();
+   z_buf->attachTexture(GFXTextureTarget::Color0, NULL);
+
+   //render Volumetric Fog
+   GFX->setShader(mShader);
+   GFX->setShaderConstBuffer(mShaderConsts);
+
+   mShaderConsts->setSafe(mModelViewProjSC, xform);
+   if (mFadeSize > 0.0f)
+      mShaderConsts->setSafe(mFadeSizeSC, mClampF(mPixelSize / mFadeSize, 0.0f, 1.0f));
+   else
+      mShaderConsts->setSafe(mFadeSizeSC, 1.0f);
+   mShaderConsts->setSafe(mFogColorSC, mFogColor);
+   mShaderConsts->setSafe(mFogDensitySC, mFogDensity);
+   mShaderConsts->setSafe(mPreBias, viewDist);
+   mShaderConsts->setSafe(mAccumTime, (F32)Sim::getCurrentTime() / 1000.0f);
+   mShaderConsts->setSafe(mModStrengthSC, mStrength);
+   mShaderConsts->setSafe(mModSpeedSC, mSpeed);
+   mShaderConsts->setSafe(mViewPointSC, mViewPoint);
+   mShaderConsts->setSafe(mTexScaleSC, mTexScale * mFOV);
+   mShaderConsts->setSafe(mTexTilesSC, mTexTiles);
+
+   GFXTextureObject *prepasstex = mPrepassTarget ? mPrepassTarget->getTexture(0) : NULL;
+
+   GFX->setTexture(0, prepasstex);
+   GFX->setTexture(1, mDepthBuffer);
+   GFX->setTexture(2, mFrontBuffer);
+
+   if (mIsTextured && mStrength > 0.0f)
+   {
+      GFX->setTexture(3, mTexture);
+      mShaderConsts->setSafe(mIsTexturedSC, 1.0f);
+   }
+   else
+      mShaderConsts->setSafe(mIsTexturedSC, 0.0f);
+
+   if (mCamInFog)
+   {
+      /*GFXLockedRect *rect=mDepthBuffer->lock();
+      U32 pixoffset = 0;// 1572864 + (512 * 4);
+      U8 red = rect->bits[pixoffset];
+      U8 green = rect->bits[pixoffset+1];
+      U8 blue = rect->bits[pixoffset+2];
+      U8 alpha = rect->bits[pixoffset+3];
+      mDepthBuffer->unlock();
+      S32 lval = ((alpha << 24) + (blue << 16) + (green << 8) + (red));
+      F32 fval = ((F32)lval / S32_MAX);
+      Con::printf("Color %d %d %d %d %d %f", red, green, blue, alpha, lval, fval);*/
+      GFX->setStateBlock(mStateblockD);
+   }
+   else
+      GFX->setStateBlock(mStateblockF);
+
+   GFX->drawPrimitive(0);
+}
+
+void VolumetricFog::reflect_render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
+{
+   if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing || (mFogReflStrength==0.0f))
+      return;
+
+   GFXTransformSaver saver;
+   GFX->setVertexBuffer(mVB);
+   GFX->setPrimitiveBuffer(mPB);
+
+   MatrixF mat = getRenderTransform();
+   mat.scale(mObjScale);
+   GFX->multWorld(mat);
+
+   GFX->setShader(mReflectionShader);
+   GFX->setShaderConstBuffer(mReflShaderConsts);
+   GFX->setStateBlock(mStateblock_refl);
+
+   // Set all the shader consts...
+   MatrixF xform(GFX->getProjectionMatrix());
+   xform *= GFX->getViewMatrix();
+   xform *= GFX->getWorldMatrix();
+
+   mReflShaderConsts->setSafe(mReflModelViewProjSC, xform);
+   mReflShaderConsts->setSafe(mReflFogColorSC, mFogColor);
+   mReflShaderConsts->setSafe(mReflFogDensitySC, mFogDensity);
+   mReflShaderConsts->setSafe(mReflFogStrengthSC, mFogReflStrength);
+
+   GFX->drawPrimitive(0);
+}
+
+//-----------------------------------------------------------------------------
+// InitTexture is called whenever a modulation texture is added to the object
+//-----------------------------------------------------------------------------
+
+void VolumetricFog::InitTexture()
+{
+   mIsTextured = false;
+
+   if (mTextureName.isNotEmpty())
+      mTexture.set(mTextureName, &GFXDefaultStaticDiffuseProfile, "VolumetricFogMod");
+
+   if (!mTexture.isNull())
+   {
+      mIsTextured = true;
+
+      F32 width = (F32)mPlatformWindow->getClientExtent().x;
+      F32 height = (F32)mPlatformWindow->getClientExtent().y;
+
+      if (!mPlatformWindow->isFullscreen())
+         height -= 20;//subtract caption bar from rendertarget size.
+
+      mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width);
+      mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height);
+   }
+}
+
+void VolumetricFog::setFogColor(ColorF color)
+{
+   mFogColor.set(255 * color.red,255 * color.green,255 * color.blue);
+   setMaskBits(FogColorMask);
+}
+
+void VolumetricFog::setFogColor(ColorI color)
+{
+   mFogColor = color;
+   setMaskBits(FogColorMask);
+}
+
+void VolumetricFog::setFogDensity(F32 density)
+{
+   if (density < 0.0f)
+      density = 0.0f;
+   mFogDensity = density;
+   setMaskBits(FogDensityMask);
+}
+
+void VolumetricFog::setFogModulation(F32 strength,Point2F speed1,Point2F speed2)
+{
+   mStrength = strength;
+   mSpeed1 = speed1;
+   mSpeed2 = speed2;
+   mSpeed.set(speed1.x, speed1.y, speed2.x, speed2.y);
+   setMaskBits(FogModulationMask);
+}
+
+void VolumetricFog::setFogGlow(bool on_off, F32 strength)
+{
+   mUseGlow = on_off;
+   mGlowStrength = strength;
+   setMaskBits(FogPostFXMask);
+}
+
+void VolumetricFog::setFogLightray(bool on_off, F32 strength)
+{
+   mModifLightRays = on_off;
+   mLightRayMod = strength;
+   setMaskBits(FogPostFXMask);
+}
+
+bool VolumetricFog::isInsideFog()
+{
+   return mCamInFog;
+}
+
+DefineEngineMethod(VolumetricFog, SetFogColorF, void, (ColorF new_color), ,
+"@brief Changes the color of the fog\n\n."
+"@params new_color the new fog color (rgb 0.0 - 1.0, a is ignored.")
+{
+   object->setFogColor(new_color);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogColor, void, (ColorI new_color), ,
+"@brief Changes the color of the fog\n\n."
+"@params new_color the new fog color (rgb 0-255, a is ignored.")
+{
+   object->setFogColor(new_color);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogDensity, void, (F32 new_density), ,
+"@brief Changes the density of the fog\n\n."
+"@params new_density the new fog density.")
+{
+   object->setFogDensity(new_density);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogModulation, void, (F32 new_strenght, Point2F new_speed1, Point2F new_speed2), ,
+"@brief Changes the modulation of the fog\n\n."
+"@params new_strenght the new strength of the modulation.\n"
+"@params new_speed1 the new speed (x y) of the modulation layer 1.\n"
+"@params new_speed2 the new speed (x y) of the modulation layer 2.\n")
+{
+   object->setFogModulation(new_strenght, new_speed1, new_speed2);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogGlow, void, (bool on_off,F32 strength), ,
+"@brief Changes the glow postfx when inside the fog\n\n."
+"@params on_off set to true to enable glow.\n"
+"@params strength glow strength.\n")
+{
+   object->setFogGlow(on_off, strength);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogLightray, void, (bool on_off, F32 strength), ,
+"@brief Changes the lightrays postfx when inside the fog\n\n."
+"@params on_off set to true to modification of the lightray postfx.\n"
+"@params strength lightray strength.\n")
+{
+   object->setFogLightray(on_off, strength);
+}
+
+DefineEngineMethod(VolumetricFog, isInsideFog, bool, (), ,
+"@brief returns true if control object is inside the fog\n\n.")
+{
+   return object->isInsideFog();
+}

+ 243 - 0
Engine/source/environment/VolumetricFog.h

@@ -0,0 +1,243 @@
+//-----------------------------------------------------------------------------
+// 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 _VolumetricFog_H_
+#define _VolumetricFog_H_
+   
+#ifndef _SCENEOBJECT_H_
+#include "scene/sceneObject.h"
+#endif
+#ifndef _MATTEXTURETARGET_H_
+#include "materials/matTextureTarget.h"
+#endif
+#ifndef _GFXSHADER_H_
+#include "gfx/gfxShader.h"
+#endif
+#ifndef _GFXTARGET_H_
+#include "gfx/gfxTarget.h"
+#endif
+#ifndef _GFXVERTEXBUFFER_H_
+#include "gfx/gfxVertexBuffer.h"
+#endif
+#ifndef _TSSHAPE_H_
+#include "ts/tsShape.h"
+#endif
+#ifndef _POST_EFFECT_H_
+#include "postFx/postEffect.h"
+#endif
+   
+#include "gui/core/guiCanvas.h"
+   
+class VolumetricFogRTManager;
+   
+class VolumetricFog : public SceneObject
+{
+   typedef SceneObject Parent;
+   
+   // Maskbits for updating
+   enum
+   {
+      VolumetricFogMask = Parent::NextFreeMask,
+      FogColorMask = Parent::NextFreeMask << 1,
+      FogDensityMask = Parent::NextFreeMask << 2,
+      FogModulationMask = Parent::NextFreeMask << 3,
+      FogPostFXMask = Parent::NextFreeMask << 4,
+      FogShapeMask = Parent::NextFreeMask << 5,
+      NextFreeMask = Parent::NextFreeMask << 6
+   };
+   
+// Struct which holds the shape details
+   struct meshes
+   {
+      F32 det_size;
+      S32 sub_shape;
+      S32 obj_det;
+      U32 num_verts;
+      GFXVertexPNTT *verts;
+      Vector <GFXPrimitive> *piArray;
+      Vector <U32> *indices;
+   };
+   
+   protected:
+      // Rendertargets;
+      GFXTextureTargetRef z_buf;
+      NamedTexTargetRef mPrepassTarget;
+      NamedTexTargetRef mDepthBufferTarget;
+      NamedTexTargetRef mFrontBufferTarget;
+   
+      // Fog Modulation texture
+      GFXTexHandle mTexture;
+   
+      // Shaders
+      GFXShaderRef mShader;
+      GFXShaderRef mPrePassShader;
+      GFXShaderRef mReflectionShader;
+   
+      // Stateblocks
+      GFXStateBlockDesc descD;
+      GFXStateBlockDesc descF;
+      GFXStateBlockDesc desc_preD;
+      GFXStateBlockDesc desc_preF;
+      GFXStateBlockDesc desc_refl;
+   
+      GFXStateBlockRef mStateblockD;
+      GFXStateBlockRef mStateblockF;
+      GFXStateBlockRef mStateblock_preD;
+      GFXStateBlockRef mStateblock_preF;
+      GFXStateBlockRef mStateblock_refl;
+   
+      // Shaderconstants
+      GFXShaderConstBufferRef mShaderConsts;
+      GFXShaderConstHandle *mModelViewProjSC;
+      GFXShaderConstHandle *mFadeSizeSC;
+      GFXShaderConstHandle *mFogColorSC;
+      GFXShaderConstHandle *mFogDensitySC;
+      GFXShaderConstHandle *mPreBias;
+      GFXShaderConstHandle *mAccumTime;
+      GFXShaderConstHandle *mIsTexturedSC;
+      GFXShaderConstHandle *mModSpeedSC;
+      GFXShaderConstHandle *mModStrengthSC;
+      GFXShaderConstHandle *mViewPointSC;
+      GFXShaderConstHandle *mTexScaleSC;
+      GFXShaderConstHandle *mTexTilesSC;
+   
+      GFXShaderConstBufferRef mPPShaderConsts;
+      GFXShaderConstHandle *mPPModelViewProjSC;
+
+      GFXShaderConstHandle *mAmbientColorSC;
+   
+      GFXShaderConstBufferRef mReflShaderConsts;
+      GFXShaderConstHandle *mReflModelViewProjSC;
+      GFXShaderConstHandle *mReflFogColorSC;
+      GFXShaderConstHandle *mReflFogDensitySC;
+      GFXShaderConstHandle *mReflFogStrengthSC;
+   
+      // Vertex and Prim. Buffer
+      GFXVertexBufferHandle<GFXVertexPNTT> mVB;
+      GFXPrimitiveBufferHandle mPB;
+   
+      // Fog volume data;
+      StringTableEntry mShapeName;
+      ColorI mFogColor;
+      F32 mFogDensity;
+      bool mIgnoreWater;
+      bool mReflect;
+      Vector<meshes> det_size;
+      bool mShapeLoaded;
+      F32 mPixelSize;
+      F32 mFadeSize;
+      U32 mCurDetailLevel;
+      U32 mNumDetailLevels;
+      F32 mObjSize;
+      F32 mRadius;
+      OrientedBox3F ColBox;
+      VectorF mObjScale;
+      F32 mMinDisplaySize;
+      F32 mInvScale;
+   
+      // Fog Modulation data
+      String mTextureName;
+      bool mIsTextured;
+      F32 mTexTiles;
+      F32 mStrength;
+      Point2F mSpeed1;
+      Point2F mSpeed2;
+      Point4F mSpeed;
+      Point2F mTexScale;
+   
+      // Fog Rendering data
+      Point3F camPos;
+      Point2F mViewPoint;
+      F32 mFOV;
+      F32 viewDist;
+      bool mIsVBDirty;
+      bool mIsPBDirty;
+      bool mCamInFog;
+      bool mResizing;
+      PlatformWindow *mPlatformWindow;
+   
+      // Reflections
+      F32 mFogReflStrength;
+   
+      // PostFX
+      PostEffect *glowFX;
+      bool mUseGlow;
+      F32 mGlowStrength;
+      U8 mGlowing;
+      F32 mCurGlow;
+   
+      bool mModifLightRays;
+      F32 mLightRayMod;
+      F32 mOldLightRayStrength;
+   
+      GameConnection* conn;
+      U32 mCounter;
+   
+      void ResizeRT(PlatformWindow *win, bool resize);
+   
+   protected:
+      // Protected methods
+      bool onAdd();
+      void onRemove();
+      void handleResize(VolumetricFogRTManager *RTM, bool resize);
+      void handleCanvasResize(GuiCanvas* canvas);
+   
+      bool LoadShape();
+      bool setupRenderer();
+      void InitTexture();
+      bool UpdateBuffers(U32 dl,bool force=true);
+   
+      void processTick(const Move *move);
+      void _enterFog(ShapeBase *control);
+      void _leaveFog(ShapeBase *control);
+   
+   public:
+      // Public methods
+      VolumetricFog();
+      ~VolumetricFog();
+   
+      static void initPersistFields();
+      virtual void inspectPostApply();
+   
+      U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
+      void unpackUpdate(NetConnection *conn, BitStream *stream);
+   
+      void prepRenderImage(SceneRenderState* state);
+      void render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
+      void reflect_render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
+   
+      // Methods for modifying & networking various fog elements
+      // Used in script
+      void setFogColor(ColorF color);
+      void setFogColor(ColorI color);
+      void setFogDensity(F32 density);
+      void setFogModulation(F32 strength, Point2F speed1, Point2F speed2);
+      void setFogGlow(bool on_off, F32 strength);
+      void setFogLightray(bool on_off, F32 strength);
+      bool isInsideFog();
+   
+      DECLARE_CONOBJECT(VolumetricFog);
+   
+      DECLARE_CALLBACK(void, onEnterFog, (SimObjectId obj));
+      DECLARE_CALLBACK(void, onLeaveFog, (SimObjectId obj));
+};
+#endif

+ 299 - 0
Engine/source/environment/VolumetricFogRTManager.cpp

@@ -0,0 +1,299 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+   
+//-----------------------------------------------------------------------------
+// Volumetric Fog Rendertarget Manager
+//
+// Creates and maintains one set of rendertargets to be used by every
+// VolumetricFog object in the scene.
+//
+// Will be loaded at startup end removed when ending game.
+//
+//-----------------------------------------------------------------------------
+   
+#include "VolumetricFogRTManager.h"
+#include "core/module.h"
+#include "scene/sceneManager.h"
+#include "windowManager/platformWindowMgr.h"
+#include "console/engineAPI.h"
+#include "gui/core/guiCanvas.h"
+   
+MODULE_BEGIN(VolumetricFogRTManager)
+   
+MODULE_INIT_AFTER(Scene)
+MODULE_SHUTDOWN_BEFORE(Scene)
+   
+MODULE_INIT
+{
+   gVolumetricFogRTManager = new VolumetricFogRTManager;
+   gClientSceneGraph->addObjectToScene(gVolumetricFogRTManager);
+}
+   
+MODULE_SHUTDOWN
+{
+   gClientSceneGraph->removeObjectFromScene(gVolumetricFogRTManager);
+   SAFE_DELETE(gVolumetricFogRTManager);
+}
+   
+MODULE_END;
+   
+ConsoleDocClass( VolumetricFogRTManager,
+"@brief Creates and maintains one set of rendertargets to be used by every\n"
+"VolumetricFog object in the scene.\n\n"
+"Will be loaded at startup end removed when ending game.\n\n"
+"Methods:\n"
+" get() returns the currently loaded VolumetricFogRTManager, also accessible\n"
+" through VFRTM define.\n"
+" Init() Initializes the rendertargets, called when a VolumetricFog object is\n"
+" added to the scene.\n"
+" isInitialed() returns true if Rendertargets are present, false if not, then\n"
+" Init() should be called to create the rendertargets.\n"
+" setQuality(U32 Quality) Normally a rendertarget has the same size as the view,\n"
+" with this method you can scale down the size of it.\n"
+" Be aware that scaling down will introduce renderartefacts.\n"
+"@ingroup Atmosphere"
+);
+   
+VolumetricFogRTMResizeSignal VolumetricFogRTManager::smVolumetricFogRTMResizeSignal;
+   
+VolumetricFogRTManager *gVolumetricFogRTManager = NULL;
+
+S32 VolumetricFogRTManager::mTargetScale = 1;
+   
+IMPLEMENT_CONOBJECT(VolumetricFogRTManager);
+   
+VolumetricFogRTManager::VolumetricFogRTManager()
+{
+   setGlobalBounds();
+   mTypeMask |= EnvironmentObjectType;
+   mNetFlags.set(IsGhost);
+   mIsInitialized = false;
+   mNumFogObjects = 0;
+}
+   
+VolumetricFogRTManager::~VolumetricFogRTManager()
+{
+   if (mFrontTarget.isRegistered())
+      mFrontTarget.unregister();
+   
+   if (mDepthTarget.isRegistered())
+      mDepthTarget.unregister();
+   
+   if (mDepthBuffer.isValid())
+      mDepthBuffer->kill();
+   
+   if (mFrontBuffer.isValid())
+      mFrontBuffer->kill();
+}
+   
+void VolumetricFogRTManager::onSceneRemove()
+{
+   if (mIsInitialized)
+      mPlatformWindow->getScreenResChangeSignal().remove(this, &VolumetricFogRTManager::ResizeRT);
+}
+   
+void VolumetricFogRTManager::onRemove()
+{
+   removeFromScene();
+   Parent::onRemove();
+}
+   
+void VolumetricFogRTManager::consoleInit()
+{
+   Con::addVariable("$pref::VolumetricFog::Quality", TypeS32, &mTargetScale,
+   "The scale of the rendertargets.\n"
+   "@ingroup Rendering\n");
+}
+   
+bool VolumetricFogRTManager::Init()
+{
+   if (mIsInitialized)
+      {
+      Con::errorf("VolumetricFogRTManager allready initialized!!");
+      return true;
+      }
+   
+   GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas"));
+   if (cv == NULL)
+   {
+      Con::errorf("VolumetricFogRTManager::Init() - Canvas not found!!");
+      return false;
+   }
+   
+   mPlatformWindow = cv->getPlatformWindow();
+   mPlatformWindow->getScreenResChangeSignal().notify(this,&VolumetricFogRTManager::ResizeRT);
+   
+   if (mTargetScale < 1)
+      mTargetScale = 1;
+   
+   mWidth = mFloor(mPlatformWindow->getClientExtent().x / mTargetScale);
+   mHeight = mPlatformWindow->getClientExtent().y;
+   mFullScreen = mPlatformWindow->isFullscreen();
+   if (!mFullScreen)
+      mHeight -= 20;//subtract caption bar from rendertarget size.
+   mHeight = mFloor(mHeight / mTargetScale);
+   
+   mDepthBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mDepthBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mDepthBuffer.isValid())
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error: Unable to create Depthbuffer");
+      return false;
+   }
+   if (!mDepthTarget.registerWithName("volfogdepth"))
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error : Unable to register Depthbuffer");
+      return false;
+   }
+   mDepthTarget.setTexture(mDepthBuffer);
+   
+   mFrontBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mFrontBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mFrontBuffer.isValid())
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error: Unable to create front buffer");
+      return false;
+   }
+   if (!mFrontTarget.registerWithName("volfogfront"))
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error : Unable to register Frontbuffer");
+      return false;
+   }
+   
+   mFrontTarget.setTexture(mFrontBuffer);
+   
+   Con::setVariable("$VolumetricFog::density", "0.0");
+   
+   mIsInitialized = true;
+   
+   return true;
+}
+   
+U32 VolumetricFogRTManager::IncFogObjects()
+{
+   mNumFogObjects++;
+   return mNumFogObjects;
+}
+   
+U32 VolumetricFogRTManager::DecFogObjects()
+{
+   if (mNumFogObjects > 0)
+      mNumFogObjects--;
+   return mNumFogObjects;
+}
+   
+void VolumetricFogRTManager::ResizeRT(PlatformWindow* win,bool resize)
+{
+   mFogHasAnswered = 0;
+   smVolumetricFogRTMResizeSignal.trigger(this, true);
+}
+   
+void VolumetricFogRTManager::FogAnswered()
+{
+   mFogHasAnswered++;
+   if (mFogHasAnswered == mNumFogObjects)
+   {
+      if (Resize())
+         smVolumetricFogRTMResizeSignal.trigger(this, false);
+      else
+         Con::errorf("VolumetricFogRTManager::FogAnswered - Error resizing rendertargets!");
+   }
+}
+   
+bool VolumetricFogRTManager::Resize()
+{
+   if (mTargetScale < 1)
+      mTargetScale = 1;
+   mWidth = mFloor(mPlatformWindow->getClientExtent().x / mTargetScale);
+   mHeight = mPlatformWindow->getClientExtent().y;
+     
+   if (!mPlatformWindow->isFullscreen())
+      mHeight -= 20;//subtract caption bar from rendertarget size.
+   mHeight = mFloor(mHeight / mTargetScale);
+   
+   if (mWidth < 16 || mHeight < 16)
+      return false;
+   
+   if (mFrontTarget.isRegistered())
+      mFrontTarget.setTexture(NULL);
+   
+   if (mDepthTarget.isRegistered())
+      mDepthTarget.setTexture(NULL);
+   
+   if (mDepthBuffer.isValid())
+      mDepthBuffer->kill();
+   
+   if (mFrontBuffer.isValid())
+      mFrontBuffer->kill();
+   
+   mFrontBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mFrontBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mFrontBuffer.isValid())
+      {
+      Con::errorf("VolumetricFogRTManager::Resize() Fatal Error: Unable to create front buffer");
+      return false;
+      }
+   mFrontTarget.setTexture(mFrontBuffer);
+   
+   mDepthBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mDepthBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mDepthBuffer.isValid())
+      {
+         Con::errorf("VolumetricFogRTManager::Resize() Fatal Error: Unable to create Depthbuffer");
+         return false;
+      }
+   mDepthTarget.setTexture(mDepthBuffer);
+   return true;
+}
+   
+S32 VolumetricFogRTManager::setQuality(U32 Quality)
+{
+   if (!mIsInitialized)
+      return (mTargetScale = Quality);
+      
+   if (Quality < 1)
+      Quality = 1;
+   
+   if (Quality == mTargetScale)
+      return mTargetScale;
+   
+   mTargetScale = Quality;
+   
+   mFogHasAnswered = 0;
+   smVolumetricFogRTMResizeSignal.trigger(this, true);
+   
+   return mTargetScale;
+}
+   
+VolumetricFogRTManager* VolumetricFogRTManager::get()
+{
+   return gVolumetricFogRTManager;
+}
+   
+DefineConsoleFunction(SetFogVolumeQuality, S32, (U32 new_quality), ,
+"@brief Resizes the rendertargets of the Volumetric Fog object.\n"
+"@params new_quality new quality for the rendertargets 1 = full size, 2 = halfsize, 3 = 1/3, 4 = 1/4 ...")
+{
+   if (VFRTM == NULL)
+      return -1;
+   return VFRTM->setQuality(new_quality);
+}

+ 92 - 0
Engine/source/environment/VolumetricFogRTManager.h

@@ -0,0 +1,92 @@
+//-----------------------------------------------------------------------------
+// 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 _VolumetricFogRTManager_H_
+#define _VolumetricFogRTManager_H_
+   
+#ifndef _SCENEOBJECT_H_
+#include "scene/sceneObject.h"
+#endif
+#ifndef _MATTEXTURETARGET_H_
+#include "materials/matTextureTarget.h"
+#endif
+#ifndef _GFXTARGET_H_
+#include "gfx/gfxTarget.h"
+#endif
+#ifndef _SIGNAL_H_
+#include "core/util/tSignal.h"
+#endif
+   
+class VolumetricFogRTManager;
+   
+typedef Signal<void(VolumetricFogRTManager *VolumetricFogRTManager, bool resize)> VolumetricFogRTMResizeSignal;
+   
+#define VFRTM VolumetricFogRTManager::get()
+   
+class VolumetricFogRTManager : public SceneObject
+{
+   public:
+      typedef SceneObject Parent;
+   
+   protected:
+      GFXTexHandle mDepthBuffer;
+      GFXTexHandle mFrontBuffer;
+   
+      NamedTexTarget mDepthTarget;
+      NamedTexTarget mFrontTarget;
+   
+      PlatformWindow* mPlatformWindow;
+   
+      static S32 mTargetScale;
+      bool mIsInitialized;
+      U32 mNumFogObjects;
+      U32 mFogHasAnswered;
+      U32 mWidth;
+      U32 mHeight;
+      bool mFullScreen;
+   
+      void onRemove();
+      void onSceneRemove();
+      void ResizeRT(PlatformWindow *win, bool resize);
+   
+      static VolumetricFogRTMResizeSignal smVolumetricFogRTMResizeSignal;
+
+   public:
+      VolumetricFogRTManager();
+      ~VolumetricFogRTManager();
+      static VolumetricFogRTManager *get();
+      bool Init();
+      bool IsInitialized() { return mIsInitialized; }
+      static void consoleInit();
+      static VolumetricFogRTMResizeSignal& getVolumetricFogRTMResizeSignal() { return smVolumetricFogRTMResizeSignal; }
+      void FogAnswered();
+      S32 setQuality(U32 Quality);
+      bool Resize();
+      U32 IncFogObjects();
+      U32 DecFogObjects();
+   
+   DECLARE_CONOBJECT(VolumetricFogRTManager);
+};
+   
+extern VolumetricFogRTManager* gVolumetricFogRTManager;
+   
+#endif

+ 1 - 1
Engine/source/environment/basicClouds.cpp

@@ -141,7 +141,7 @@ bool BasicClouds::onAdd()
       GFXStateBlockDesc desc;
       desc.setCullMode( GFXCullNone );
       desc.setBlend( true );
-      desc.setZReadWrite( false, false );
+      desc.setZReadWrite( true, false );
       desc.samplersDefined = true;
       desc.samplers[0].addressModeU = GFXAddressWrap;
       desc.samplers[0].addressModeV = GFXAddressWrap;

+ 1 - 1
Engine/source/environment/cloudLayer.cpp

@@ -161,7 +161,7 @@ bool CloudLayer::onAdd()
       GFXStateBlockDesc desc;
       desc.setCullMode( GFXCullNone );
       desc.setBlend( true );
-      desc.setZReadWrite( false, false );
+      desc.setZReadWrite( true, false );
       desc.samplersDefined = true;
       desc.samplers[0].addressModeU = GFXAddressWrap;
       desc.samplers[0].addressModeV = GFXAddressWrap;

+ 1 - 1
Engine/source/environment/decalRoad.cpp

@@ -732,7 +732,7 @@ void DecalRoad::prepRenderImage( SceneRenderState* state )
    MathUtils::getZBiasProjectionMatrix( gDecalBias, frustum, tempMat );
    coreRI.projection = tempMat;
 
-   coreRI.type = RenderPassManager::RIT_Decal;
+   coreRI.type = RenderPassManager::RIT_DecalRoad;
    coreRI.vertBuff = &mVB;
    coreRI.primBuff = &mPB;
    coreRI.matInst = matInst;

+ 10 - 1
Engine/source/environment/scatterSky.cpp

@@ -955,12 +955,21 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat
 
    Point3F camPos2 = state->getCameraPosition();
    MatrixF xfm(true);
-   xfm.setPosition(camPos2 - Point3F( 0, 0, mZOffset));
+   
    GFX->multWorld(xfm);
    MatrixF xform(proj);//GFX->getProjectionMatrix());
    xform *= GFX->getViewMatrix();
    xform *=  GFX->getWorldMatrix();
 
+   if(state->isReflectPass())
+   {
+      static MatrixF rotMat(EulerF(0.0, 0.0, M_PI_F));
+      xform.mul(rotMat);
+      rotMat.set(EulerF(M_PI_F, 0.0, 0.0));
+      xform.mul(rotMat);
+   }
+   xform.setPosition(xform.getPosition() - Point3F(0, 0, mZOffset));
+
    mShaderConsts->setSafe( mModelViewProjSC, xform );
    mShaderConsts->setSafe( mMiscSC, miscParams );
    mShaderConsts->setSafe( mSphereRadiiSC, sphereRadii );

+ 2 - 1
Engine/source/environment/skyBox.cpp

@@ -599,7 +599,8 @@ void SkyBox::_initMaterial()
 
    // We want to disable culling and z write.
    GFXStateBlockDesc desc;
-   desc.setCullMode( GFXCullCW );
+   desc.setCullMode( GFXCullNone );
+   desc.setBlend( true );
    desc.setZReadWrite( true, false );
    mMatInstance->addStateBlockDesc( desc );
 

+ 2 - 2
Engine/source/environment/timeOfDay.cpp

@@ -402,7 +402,7 @@ void TimeOfDay::_getSunColor( ColorF *outColor ) const
    //simple check
    if ( mColorTargets[0].elevation != 0.0f )
    {
-      AssertFatal(0, "TimeOfDay::GetColor() - First elevation must be 0.0 radians")
+      AssertFatal(0, "TimeOfDay::GetColor() - First elevation must be 0.0 radians");
       outColor->set(1.0f, 1.0f, 1.0f);
       //mBandMod = 1.0f;
       //mCurrentBandColor = color;
@@ -411,7 +411,7 @@ void TimeOfDay::_getSunColor( ColorF *outColor ) const
 
    if ( mColorTargets[mColorTargets.size()-1].elevation != M_PI_F )
    {
-      AssertFatal(0, "Celestails::GetColor() - Last elevation must be PI")
+      AssertFatal(0, "Celestails::GetColor() - Last elevation must be PI");
       outColor->set(1.0f, 1.0f, 1.0f);
       //mBandMod = 1.0f;
       //mCurrentBandColor = color;

+ 2 - 0
Engine/source/gfx/D3D9/gfxD3D9CardProfiler.cpp

@@ -87,9 +87,11 @@ void GFXD3D9CardProfiler::setupCardCapabilities()
    bool canDoFourStageDetailBlend = ( caps.TextureOpCaps & D3DTEXOPCAPS_SUBTRACT ) &&
                                     ( caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP ) &&
                                     ( caps.MaxTextureBlendStages > 3 );
+   bool canDoIndependentMrtBitDepth = (caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS ? 1 : 0 );
 
    setCapability( "lerpDetailBlend", canDoLERPDetailBlend );
    setCapability( "fourStageDetailBlend", canDoFourStageDetailBlend );
+   setCapability( "independentMrtBitDepth", canDoIndependentMrtBitDepth);
 }
 
 bool GFXD3D9CardProfiler::_queryCardCap(const String &query, U32 &foundResult)

+ 24 - 4
Engine/source/gfx/D3D9/gfxD3D9Device.cpp

@@ -731,7 +731,8 @@ void GFXD3D9Device::setShader( GFXShader *shader, bool force )
 //-----------------------------------------------------------------------------
 GFXPrimitiveBuffer * GFXD3D9Device::allocPrimitiveBuffer(   U32 numIndices, 
                                                             U32 numPrimitives, 
-                                                            GFXBufferType bufferType )
+                                                            GFXBufferType bufferType,
+                                                            void* data )
 {
    // Allocate a buffer to return
    GFXD3D9PrimitiveBuffer * res = new GFXD3D9PrimitiveBuffer(this, numIndices, numPrimitives, bufferType);
@@ -741,12 +742,13 @@ GFXPrimitiveBuffer * GFXD3D9Device::allocPrimitiveBuffer(   U32 numIndices,
    D3DPOOL pool = D3DPOOL_DEFAULT;
 
    // Assumptions:
-   //    - static buffers are write once, use many
+   //    - static buffers are write rarely, use many
    //    - dynamic buffers are write many, use many
    //    - volatile buffers are write once, use once
    // You may never read from a buffer.
    switch(bufferType)
    {
+   case GFXBufferTypeImmutable:
    case GFXBufferTypeStatic:
       pool = isD3D9Ex() ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED;
       break;
@@ -781,6 +783,14 @@ GFXPrimitiveBuffer * GFXD3D9Device::allocPrimitiveBuffer(   U32 numIndices,
       D3D9Assert(mD3DDevice->CreateIndexBuffer( sizeof(U16) * numIndices , usage, GFXD3D9IndexFormat[GFXIndexFormat16], pool, &res->ib, 0),
          "Failed to allocate an index buffer.");
    }
+   
+   if(data)
+   {
+      void* dest;
+      res->lock(0, numIndices, &dest);
+      dMemcpy(dest, data, sizeof(U16) * numIndices);
+      res->unlock();
+   }
 
    return res;
 }
@@ -791,7 +801,8 @@ GFXPrimitiveBuffer * GFXD3D9Device::allocPrimitiveBuffer(   U32 numIndices,
 GFXVertexBuffer * GFXD3D9Device::allocVertexBuffer(   U32 numVerts, 
                                                       const GFXVertexFormat *vertexFormat, 
                                                       U32 vertSize, 
-                                                      GFXBufferType bufferType )
+                                                      GFXBufferType bufferType, 
+                                                      void* data)
 {
    PROFILE_SCOPE( GFXD3D9Device_allocVertexBuffer );
 
@@ -808,7 +819,7 @@ GFXVertexBuffer * GFXD3D9Device::allocVertexBuffer(   U32 numVerts,
    res->mNumVerts = 0;
 
    // Assumptions:
-   //    - static buffers are write once, use many
+   //    - static buffers are write rarely, use many
    //    - dynamic buffers are write many, use many
    //    - volatile buffers are write once, use once
    // You may never read from a buffer.
@@ -850,6 +861,15 @@ GFXVertexBuffer * GFXD3D9Device::allocVertexBuffer(   U32 numVerts,
    }
 
    res->mNumVerts = numVerts;
+   
+   if(data)
+   {
+      void* dest;
+      res->lock(0, numVerts, &dest);
+      dMemcpy(dest, data, vertSize * numVerts);
+      res->unlock();
+   }
+   
    return res;
 }
 

+ 4 - 2
Engine/source/gfx/D3D9/gfxD3D9Device.h

@@ -298,10 +298,12 @@ public:
    virtual GFXVertexBuffer* allocVertexBuffer(  U32 numVerts, 
                                                 const GFXVertexFormat *vertexFormat,
                                                 U32 vertSize,
-                                                GFXBufferType bufferType );
+                                                GFXBufferType bufferType,
+                                                void* data = NULL );
    virtual GFXPrimitiveBuffer *allocPrimitiveBuffer(  U32 numIndices, 
                                                       U32 numPrimitives, 
-                                                      GFXBufferType bufferType );
+                                                      GFXBufferType bufferType,
+                                                      void* data = NULL );
    virtual void deallocVertexBuffer( GFXD3D9VertexBuffer *vertBuff );
    virtual GFXVertexDecl* allocVertexDecl( const GFXVertexFormat *vertexFormat );
    virtual void setVertexDecl( const GFXVertexDecl *decl );

+ 1 - 0
Engine/source/gfx/D3D9/pc/gfxD3D9PrimitiveBuffer.pc.cpp

@@ -31,6 +31,7 @@ void GFXD3D9PrimitiveBuffer::lock(U32 indexStart, U32 indexEnd, void **indexPtr)
    U32 flags=0;
    switch(mBufferType)
    {
+   case GFXBufferTypeImmutable:
    case GFXBufferTypeStatic:
       // flags |= D3DLOCK_DISCARD;
       break;

+ 5 - 0
Engine/source/gfx/D3D9/pc/gfxPCD3D9Target.cpp

@@ -31,6 +31,9 @@
 #include "gfx/gfxDebugEvent.h"
 #include "windowManager/win32/win32Window.h"
 
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
 
 GFXPCD3D9TextureTarget::GFXPCD3D9TextureTarget() 
    :  mTargetSize( Point2I::Zero ),
@@ -451,6 +454,7 @@ void GFXPCD3D9WindowTarget::createAdditionalSwapChain()
 
 void GFXPCD3D9WindowTarget::resetMode()
 {
+   GFX->beginReset();
    mWindow->setSuppressReset(true);
 
    if (mSwapChain)
@@ -509,6 +513,7 @@ void GFXPCD3D9WindowTarget::zombify()
 
 void GFXPCD3D9WindowTarget::resurrect()
 {
+   GFX->beginReset();
    if(mImplicit)
    {
       setImplicitSwapChain();

+ 4 - 2
Engine/source/gfx/Null/gfxNullDevice.cpp

@@ -276,14 +276,16 @@ GFXNullDevice::~GFXNullDevice()
 GFXVertexBuffer *GFXNullDevice::allocVertexBuffer( U32 numVerts, 
                                                    const GFXVertexFormat *vertexFormat,
                                                    U32 vertSize, 
-                                                   GFXBufferType bufferType ) 
+                                                   GFXBufferType bufferType,
+                                                   void* data ) 
 {
    return new GFXNullVertexBuffer(GFX, numVerts, vertexFormat, vertSize, bufferType);
 }
 
 GFXPrimitiveBuffer *GFXNullDevice::allocPrimitiveBuffer( U32 numIndices, 
                                                          U32 numPrimitives, 
-                                                         GFXBufferType bufferType) 
+                                                         GFXBufferType bufferType,
+                                                         void* data ) 
 {
    return new GFXNullPrimitiveBuffer(GFX, numIndices, numPrimitives, bufferType);
 }

+ 4 - 2
Engine/source/gfx/Null/gfxNullDevice.h

@@ -115,10 +115,12 @@ protected:
    virtual GFXVertexBuffer *allocVertexBuffer(  U32 numVerts, 
                                                 const GFXVertexFormat *vertexFormat, 
                                                 U32 vertSize, 
-                                                GFXBufferType bufferType );
+                                                GFXBufferType bufferType,
+                                                void* data = NULL );
    virtual GFXPrimitiveBuffer *allocPrimitiveBuffer(  U32 numIndices, 
                                                       U32 numPrimitives, 
-                                                      GFXBufferType bufferType );
+                                                      GFXBufferType bufferType,
+                                                      void* data = NULL );
 
    virtual GFXVertexDecl* allocVertexDecl( const GFXVertexFormat *vertexFormat ) { return NULL; }
    virtual void setVertexDecl( const GFXVertexDecl *decl ) {  }

+ 1 - 1
Engine/source/gfx/bitmap/gBitmap.cpp

@@ -326,7 +326,7 @@ void GBitmap::allocateBitmap(const U32 in_width, const U32 in_height, const bool
 
          mNumMipLevels++;
          allocPixels += currWidth * currHeight * mBytesPerPixel;
-      } while (currWidth != 1 || currHeight != 1);
+      } while (currWidth != 1 && currHeight != 1);
    }
    AssertFatal(mNumMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
 

+ 1 - 1
Engine/source/gfx/bitmap/loaders/bitmapTga.cpp

@@ -483,7 +483,7 @@ static bool sReadTGA(Stream &stream, GBitmap *bitmap)
 
 static bool sWriteTGA(GBitmap *bitmap, Stream &stream, U32 compressionLevel)
 {
-   AssertISV(false, "GBitmap::writeTGA - doesn't support writing tga files!")
+   AssertISV(false, "GBitmap::writeTGA - doesn't support writing tga files!");
 
    return false;
 }

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

@@ -148,7 +148,7 @@ GFXDevice::GFXDevice()
    mGlobalAmbientColor = ColorF(0.0f, 0.0f, 0.0f, 1.0f);
 
    mLightMaterialDirty = false;
-   dMemset(&mCurrentLightMaterial, NULL, sizeof(GFXLightMaterial));
+   dMemset(&mCurrentLightMaterial, 0, sizeof(GFXLightMaterial));
 
    // State block 
    mStateBlockDirty = false;

+ 9 - 2
Engine/source/gfx/gfxDevice.h

@@ -302,6 +302,7 @@ protected:
    /// This will allow querying to see if a device is initialized and ready to
    /// have operations performed on it.
    bool mInitialized;
+   bool mReset;
 
    /// This is called before this, or any other device, is deleted in the global destroy()
    /// method. It allows the device to clean up anything while everything is still valid.
@@ -326,6 +327,10 @@ public:
    /// @see endScene
    bool canCurrentlyRender() const { return mCanCurrentlyRender; }
 
+   bool recentlyReset(){ return mReset; }
+   void beginReset(){ mReset = true; }
+   void finalizeReset(){ mReset = false; }
+
    void setAllowRender( bool render ) { mAllowRender = render; }
 
    inline bool allowRender() const { return mAllowRender; }
@@ -637,7 +642,8 @@ protected:
    virtual GFXVertexBuffer *allocVertexBuffer(  U32 numVerts, 
                                                 const GFXVertexFormat *vertexFormat, 
                                                 U32 vertSize, 
-                                                GFXBufferType bufferType ) = 0;
+                                                GFXBufferType bufferType,
+                                                void* data = NULL ) = 0;
 
    /// Called from GFXVertexFormat to allocate the hardware 
    /// specific vertex declaration for rendering.
@@ -674,7 +680,8 @@ protected:
    /// @note All index buffers use unsigned 16-bit indices.
    virtual GFXPrimitiveBuffer *allocPrimitiveBuffer(  U32 numIndices, 
                                                       U32 numPrimitives, 
-                                                      GFXBufferType bufferType ) = 0;
+                                                      GFXBufferType bufferType,
+                                                      void* data = NULL ) = 0;
 
    /// @}
 

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

@@ -526,10 +526,10 @@ void GFXDrawUtil::drawRectFill( const Point2F &upperLeft, const Point2F &lowerRi
 
    F32 ulOffset = 0.5f - mDevice->getFillConventionOffset();
    
-   verts[0].point.set( upperLeft.x+nw.x+ulOffset, upperLeft.y+nw.y+ulOffset, 0.0f );
-   verts[1].point.set( lowerRight.x+ne.x, upperLeft.y+ne.y+ulOffset, 0.0f );
-   verts[2].point.set( upperLeft.x-ne.x+ulOffset, lowerRight.y-ne.y, 0.0f );
-   verts[3].point.set( lowerRight.x-nw.x, lowerRight.y-nw.y, 0.0f );
+   verts[0].point.set( upperLeft.x + nw.x + ulOffset, upperLeft.y + nw.y + ulOffset, 0.0f);
+   verts[1].point.set( lowerRight.x + ne.x + ulOffset, upperLeft.y + ne.y + ulOffset, 0.0f);
+   verts[2].point.set( upperLeft.x - ne.x + ulOffset, lowerRight.y - ne.y + ulOffset, 0.0f);
+   verts[3].point.set( lowerRight.x - nw.x + ulOffset, lowerRight.y - nw.y + ulOffset, 0.0f);
 
    for (S32 i=0; i<4; i++)
       verts[i].color = color;

+ 4 - 3
Engine/source/gfx/gfxEnums.h

@@ -39,8 +39,8 @@
 
 enum GFXBufferType
 {
-      GFXBufferTypeStatic,   ///< Static vertex buffers are created and filled one time.
-                   ///< incur a performance penalty.  Resizing a static vertex buffer is not
+      GFXBufferTypeStatic,   ///< Static vertex buffers are created and rarely updated.
+                   ///< Updating might incur a performance penalty.  Resizing a static vertex buffer is not
                    ///< allowed.
       GFXBufferTypeDynamic,  ///< Dynamic vertex buffers are meant for vertices that can be changed
                    ///< often.  Vertices written into dynamic vertex buffers will remain valid
@@ -48,7 +48,8 @@ enum GFXBufferType
                    ///< allowed.
       GFXBufferTypeVolatile, ///< Volatile vertex or index buffers are meant for vertices or indices that are essentially
                    ///< only used once.  They can be resized without any performance penalty.
-      
+      GFXBufferTypeImmutable, ///< Immutable buffers must specify the data when creating the buffer. Cannot be modified.
+
       GFXBufferType_COUNT ///< Number of buffer types.
 };
 

+ 13 - 0
Engine/source/gfx/gfxPrimitiveBuffer.cpp

@@ -80,3 +80,16 @@ void GFXPrimitiveBufferHandle::set(GFXDevice *theDevice, U32 indexCount, U32 pri
       getPointer()->mDebugCreationPath = desc;
 #endif
 }
+
+//-----------------------------------------------------------------------------
+// immutable
+//-----------------------------------------------------------------------------
+void GFXPrimitiveBufferHandle::immutable(GFXDevice *theDevice, U32 indexCount, U32 primitiveCount, void* data, String desc)
+{
+   StrongRefPtr<GFXPrimitiveBuffer>::operator=( theDevice->allocPrimitiveBuffer(indexCount, primitiveCount, GFXBufferTypeImmutable, data) );
+
+#ifdef TORQUE_DEBUG
+   if( desc.isNotEmpty() )
+      getPointer()->mDebugCreationPath = desc;
+#endif
+}

+ 2 - 0
Engine/source/gfx/gfxPrimitiveBuffer.h

@@ -140,6 +140,8 @@ public:
    }
 
    void set(GFXDevice *theDevice, U32 indexCount, U32 primitiveCount, GFXBufferType bufferType, String desc = String::EmptyString );
+   
+   void immutable(GFXDevice *theDevice, U32 indexCount, U32 primitiveCount, void* data, String desc = String::EmptyString );
 
    void lock(U16 **indexBuffer, GFXPrimitive **primitiveBuffer = NULL, U32 indexStart = 0, U32 indexEnd = 0)
    {

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

@@ -1099,7 +1099,7 @@ void GFXTextureManager::_validateTexParams( const U32 width, const U32 height,
                currHeight = 1;
 
             inOutNumMips++;
-         } while ( currWidth != 1 || currHeight != 1 );
+         } while ( currWidth != 1 && currHeight != 1 );
       }
    }
 }

+ 6 - 1
Engine/source/gfx/gl/gfxGLCircularVolatileBuffer.h

@@ -143,6 +143,11 @@ public:
       init();
    }
 
+   ~GLCircularVolatileBuffer()
+   {
+      glDeleteBuffers(1, &mBufferName);
+   }
+
    void init()
    {
       glGenBuffers(1, &mBufferName);
@@ -290,4 +295,4 @@ protected:
 };
 
 
-#endif
+#endif

+ 31 - 7
Engine/source/gfx/gl/gfxGLDevice.cpp

@@ -355,23 +355,47 @@ GFXPrimitiveBuffer* GFXGLDevice::findVolatilePBO(U32 numIndices, U32 numPrimitiv
 GFXVertexBuffer *GFXGLDevice::allocVertexBuffer(   U32 numVerts, 
                                                    const GFXVertexFormat *vertexFormat, 
                                                    U32 vertSize, 
-                                                   GFXBufferType bufferType ) 
+                                                   GFXBufferType bufferType,
+                                                   void* data )  
 {
    if(bufferType == GFXBufferTypeVolatile)
       return findVolatileVBO(numVerts, vertexFormat, vertSize);
          
    GFXGLVertexBuffer* buf = new GFXGLVertexBuffer( GFX, numVerts, vertexFormat, vertSize, bufferType );
-   buf->registerResourceWithDevice(this);
+   buf->registerResourceWithDevice(this);   
+
+   if(data)
+   {
+      void* dest;
+      buf->lock(0, numVerts, &dest);
+      dMemcpy(dest, data, vertSize * numVerts);
+      buf->unlock();
+   }
+
    return buf;
 }
 
-GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType ) 
+GFXPrimitiveBuffer *GFXGLDevice::allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType, void* data ) 
 {
+   GFXPrimitiveBuffer* buf;
+   
    if(bufferType == GFXBufferTypeVolatile)
-      return findVolatilePBO(numIndices, numPrimitives);
-         
-   GFXGLPrimitiveBuffer* buf = new GFXGLPrimitiveBuffer(GFX, numIndices, numPrimitives, bufferType);
-   buf->registerResourceWithDevice(this);
+   {
+      buf = findVolatilePBO(numIndices, numPrimitives);
+   }
+   else
+   {
+      buf = new GFXGLPrimitiveBuffer(GFX, numIndices, numPrimitives, bufferType);
+      buf->registerResourceWithDevice(this);
+   }
+   
+   if(data)
+   {
+      void* dest;
+      buf->lock(0, numIndices, &dest);
+      dMemcpy(dest, data, sizeof(U16) * numIndices);
+      buf->unlock();
+   }
    return buf;
 }
 

+ 3 - 2
Engine/source/gfx/gl/gfxGLDevice.h

@@ -173,8 +173,9 @@ protected:
    virtual GFXVertexBuffer *allocVertexBuffer(  U32 numVerts, 
                                                 const GFXVertexFormat *vertexFormat,
                                                 U32 vertSize, 
-                                                GFXBufferType bufferType );
-   virtual GFXPrimitiveBuffer *allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType );
+                                                GFXBufferType bufferType,
+                                                void* data = NULL);
+   virtual GFXPrimitiveBuffer *allocPrimitiveBuffer( U32 numIndices, U32 numPrimitives, GFXBufferType bufferType, void* data = NULL );
    
    // NOTE: The GL device doesn't need a vertex declaration at
    // this time, but we need to return something to keep the system

+ 1 - 0
Engine/source/gfx/gl/gfxGLEnumTranslate.cpp

@@ -45,6 +45,7 @@ void GFXGLEnumTranslate::init()
    GFXGLBufferType[GFXBufferTypeStatic] = GL_STATIC_DRAW;
    GFXGLBufferType[GFXBufferTypeDynamic] = GL_DYNAMIC_DRAW;
    GFXGLBufferType[GFXBufferTypeVolatile] = GL_STREAM_DRAW;
+   GFXGLBufferType[GFXBufferTypeImmutable] = GL_STATIC_DRAW;
 
    // Primitives
    GFXGLPrimType[GFXPointList] = GL_POINTS;

+ 8 - 0
Engine/source/gfx/gl/gfxGLStateBlock.cpp

@@ -107,6 +107,14 @@ void GFXGLStateBlock::activate(const GFXGLStateBlock* oldState)
    if(STATE_CHANGE(blendOp))
       glBlendEquation(GFXGLBlendOp[mDesc.blendOp]);
 
+   if (mDesc.separateAlphaBlendEnable == true)
+   {
+       if (STATE_CHANGE(separateAlphaBlendSrc) || STATE_CHANGE(separateAlphaBlendDest))
+           glBlendFuncSeparate(GFXGLBlend[mDesc.blendSrc], GFXGLBlend[mDesc.blendDest], GFXGLBlend[mDesc.separateAlphaBlendSrc], GFXGLBlend[mDesc.separateAlphaBlendDest]);
+       if (STATE_CHANGE(separateAlphaBlendOp))
+           glBlendEquationSeparate(GFXGLBlendOp[mDesc.blendOp], GFXGLBlendOp[mDesc.separateAlphaBlendOp]);
+   }
+
    // Color write masks
    if(STATE_CHANGE(colorWriteRed) || STATE_CHANGE(colorWriteBlue) || STATE_CHANGE(colorWriteGreen) || STATE_CHANGE(colorWriteAlpha))
       glColorMask(mDesc.colorWriteRed, mDesc.colorWriteBlue, mDesc.colorWriteGreen, mDesc.colorWriteAlpha);

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

@@ -163,6 +163,10 @@ void _GFXGLTextureTargetFBOImpl::applyState()
    PRESERVE_FRAMEBUFFER();
    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
 
+   bool drawbufs[16];
+   int bufsize = 0;
+   for (int i = 0; i < 16; i++)
+           drawbufs[i] = false;
    bool hasColor = false;
    for(int i = 0; i < GFXGL->getNumRenderTargets(); ++i)
    {   
@@ -200,6 +204,20 @@ void _GFXGLTextureTargetFBOImpl::applyState()
       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
    }
 
+   GLenum *buf = new GLenum[bufsize];
+   int count = 0;
+   for (int i = 0; i < bufsize; i++)
+   {
+           if (drawbufs[i])
+           {
+                   buf[count] = GL_COLOR_ATTACHMENT0 + i;
+                   count++;
+           }
+   }
+ 
+   glDrawBuffers(bufsize, buf);
+ 
+   delete[] buf;
    CHECK_FRAMEBUFFER_STATUS();
 }
 
@@ -260,7 +278,10 @@ GFXGLTextureTarget::GFXGLTextureTarget() : mCopyFboSrc(0), mCopyFboDst(0)
 
 GFXGLTextureTarget::~GFXGLTextureTarget()
 {
-   GFXTextureManager::removeEventDelegate( this, &GFXGLTextureTarget::_onTextureEvent );
+   GFXTextureManager::removeEventDelegate(this, &GFXGLTextureTarget::_onTextureEvent);
+
+   glDeleteFramebuffers(1, &mCopyFboSrc);
+   glDeleteFramebuffers(1, &mCopyFboDst);
 }
 
 const Point2I GFXGLTextureTarget::getSize()

+ 9 - 0
Engine/source/gfx/gl/gfxGLWindowTarget.cpp

@@ -42,6 +42,14 @@ GFXGLWindowTarget::GFXGLWindowTarget(PlatformWindow *win, GFXDevice *d)
    win->appEvent.notify(this, &GFXGLWindowTarget::_onAppSignal);
 }
 
+GFXGLWindowTarget::~GFXGLWindowTarget()
+{
+   if(glIsFramebuffer(mCopyFBO))
+   {
+      glDeleteFramebuffers(1, &mCopyFBO);
+   }
+}
+
 void GFXGLWindowTarget::resetMode()
 {
    if(mWindow->getVideoMode().fullScreen != mWindow->isFullscreen())
@@ -49,6 +57,7 @@ void GFXGLWindowTarget::resetMode()
       _teardownCurrentMode();
       _setupNewMode();
    }
+   GFX->beginReset();
 }
 
 void GFXGLWindowTarget::_onAppSignal(WindowId wnd, S32 event)

+ 3 - 1
Engine/source/gfx/gl/gfxGLWindowTarget.h

@@ -30,6 +30,8 @@ class GFXGLWindowTarget : public GFXWindowTarget
 public:
 
    GFXGLWindowTarget(PlatformWindow *win, GFXDevice *d);
+   ~GFXGLWindowTarget();
+
    const Point2I getSize() 
    { 
       return mWindow->getClientExtent();
@@ -64,4 +66,4 @@ private:
    void _WindowPresent();
 };
 
-#endif
+#endif

+ 4 - 0
Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp

@@ -83,6 +83,10 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
     );
 
    SDL_ClearError();
+   SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+   SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+   SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+
    SDL_GLContext tempContext = SDL_GL_CreateContext( tempWindow );
    if( !tempContext )
    {

+ 1 - 0
Engine/source/gfx/gl/tGL/tGL.cpp

@@ -29,6 +29,7 @@ namespace GL
 {
    void gglPerformBinds()
    {
+      glewExperimental = GL_TRUE;
       GLenum err = glewInit();
       AssertFatal(GLEW_OK == err, avar("Error: %s\n", glewGetErrorString(err)) );
    }

+ 6 - 0
Engine/source/gfx/gl/tGL/tGL.h

@@ -24,7 +24,13 @@
 #define T_GL_H
 #include "GL/glew.h"
 
+#if defined (TORQUE_OS_WIN)
+// This doesn't work on Mesa drivers.
 #define gglHasExtension(EXTENSION) GLEW_##EXTENSION
+#else
+// Slower but reliably detects extensions on Mesa.
+#define gglHasExtension(EXTENSION) glewGetExtension("GL_" # EXTENSION)
+#endif
 
 #endif
 

+ 108 - 2
Engine/source/gfx/sim/debugDraw.cpp

@@ -132,6 +132,11 @@ void DebugDrawer::setupStateBlocks()
    
    d.setZReadWrite(false);
    mRenderZOffSB = GFX->createStateBlock(d);
+   
+   d.setCullMode(GFXCullCCW);
+   d.setZReadWrite(true, false);
+   d.setBlend(true);
+   mRenderAlpha = GFX->createStateBlock(d);
 }
 
 void DebugDrawer::render()
@@ -158,10 +163,13 @@ void DebugDrawer::render()
 
       // Set up the state block...
       GFXStateBlockRef currSB;
-      if(p->useZ)
+      if(p->type==DebugPrim::Capsule){
+         currSB = mRenderAlpha;
+      }else if(p->useZ){
          currSB = mRenderZOnSB;
-      else
+      }else{
          currSB = mRenderZOffSB;
+      }
       GFX->setStateBlock( currSB );
 
       Point3F d;
@@ -180,6 +188,47 @@ void DebugDrawer::render()
 
          PrimBuild::end();
          break;
+      case DebugPrim::DirectionLine:
+         {
+            const static   F32      ARROW_LENGTH = 0.2f, ARROW_RADIUS = 0.035f, CYLINDER_RADIUS = 0.008f;
+            Point3F  &start = p->a, &end = p->b;
+            Point3F  direction = end - start;
+            F32      length = direction.len();
+            if( length>ARROW_LENGTH ){
+               //cylinder with arrow on end
+               direction *= (1.0f/length);
+               Point3F  baseArrow = end - (direction*ARROW_LENGTH);
+               GFX->getDrawUtil()->drawCone(currSB->getDesc(),  baseArrow, end, ARROW_RADIUS, p->color);
+               GFX->getDrawUtil()->drawCylinder(currSB->getDesc(),  start, baseArrow, CYLINDER_RADIUS, p->color);
+            }else if( length>0 ){
+               //short, so just draw arrow
+               GFX->getDrawUtil()->drawCone(currSB->getDesc(), start, end, ARROW_RADIUS, p->color);
+            }
+         }
+         break;
+      case DebugPrim::Capsule:
+         GFX->getDrawUtil()->drawCapsule(currSB->getDesc(),  p->a, p->b.x, p->b.y, p->color);
+         break;
+      case DebugPrim::OutlinedText:
+         {
+            GFXTransformSaver saver;            
+            Point3F result;
+            if (MathUtils::mProjectWorldToScreen(p->a, &result, GFX->getViewport(), GFX->getWorldMatrix(), GFX->getProjectionMatrix()))
+            {
+               GFX->setClipRect(GFX->getViewport());
+               Point2I  where = Point2I(result.x, result.y);
+
+               GFX->getDrawUtil()->setBitmapModulation(p->color2); 
+               GFX->getDrawUtil()->drawText(mFont, Point2I(where.x-1, where.y), p->mText);
+               GFX->getDrawUtil()->drawText(mFont, Point2I(where.x+1, where.y), p->mText);
+               GFX->getDrawUtil()->drawText(mFont, Point2I(where.x, where.y-1), p->mText);
+               GFX->getDrawUtil()->drawText(mFont, Point2I(where.x, where.y+1), p->mText);
+
+               GFX->getDrawUtil()->setBitmapModulation(p->color); 
+               GFX->getDrawUtil()->drawText(mFont, where, p->mText);
+            }
+         }
+         break;
       case DebugPrim::Box:
          d = p->a - p->b;
          GFX->getDrawUtil()->drawCube(currSB->getDesc(), d * 0.5, (p->a + p->b) * 0.5, p->color);
@@ -262,6 +311,63 @@ void DebugDrawer::drawLine(const Point3F &a, const Point3F &b, const ColorF &col
    mHead = n;
 }
 
+void DebugDrawer::drawCapsule(const Point3F &a, const F32 &radius, const F32 &height, const ColorF &color)
+{
+   if(isFrozen || !isDrawing)
+      return;
+
+   DebugPrim *n = mPrimChunker.alloc();
+
+   n->useZ = true;
+   n->dieTime = 0;
+   n->a = a;
+   n->b.x = radius;
+   n->b.y = height;
+   n->color = color;
+   n->type = DebugPrim::Capsule;
+
+   n->next = mHead;
+   mHead = n;
+
+}
+
+void DebugDrawer::drawDirectionLine(const Point3F &a, const Point3F &b, const ColorF &color)
+{
+   if(isFrozen || !isDrawing)
+      return;
+
+   DebugPrim *n = mPrimChunker.alloc();
+
+   n->useZ = true;
+   n->dieTime = 0;
+   n->a = a;
+   n->b = b;
+   n->color = color;
+   n->type = DebugPrim::DirectionLine;
+
+   n->next = mHead;
+   mHead = n;
+}
+
+void DebugDrawer::drawOutlinedText(const Point3F& pos, const String& text, const ColorF &color, const ColorF &colorOutline)
+{
+   if(isFrozen || !isDrawing)
+      return;
+
+   DebugPrim *n = mPrimChunker.alloc();
+
+   n->useZ = false;
+   n->dieTime = 0;
+   n->a = pos;
+   n->color = color;
+   n->color2 = colorOutline;
+   dStrncpy(n->mText, text.c_str(), 256);   
+   n->type = DebugPrim::OutlinedText;
+
+   n->next = mHead;
+   mHead = n;
+}
+
 void DebugDrawer::drawTri(const Point3F &a, const Point3F &b, const Point3F &c, const ColorF &color)
 {
    if(isFrozen || !isDrawing)

+ 10 - 2
Engine/source/gfx/sim/debugDraw.h

@@ -124,7 +124,10 @@ public:
    void drawLine(const Point3F &a, const Point3F &b, const ColorF &color = ColorF(1.0f,1.0f,1.0f));	
    void drawTri(const Point3F &a, const Point3F &b, const Point3F &c, const ColorF &color = ColorF(1.0f,1.0f,1.0f));
    void drawText(const Point3F& pos, const String& text, const ColorF &color = ColorF(1.0f,1.0f,1.0f));
-
+   void drawCapsule(const Point3F &a, const F32 &radius, const F32 &height, const ColorF &color = ColorF(1.0f, 1.0f, 1.0f));
+   void drawDirectionLine(const Point3F &a, const Point3F &b, const ColorF &color = ColorF(1.0f, 1.0f, 1.0f));
+   void drawOutlinedText(const Point3F& pos, const String& text, const ColorF &color = ColorF(1.0f, 1.0f, 1.0f), const ColorF &colorOutline = ColorF(0.0f, 0.0f, 0.0f));
+   
    /// Render a wireframe view of the given polyhedron.
    void drawPolyhedron( const AnyPolyhedron& polyhedron, const ColorF& color = ColorF( 1.f, 1.f, 1.f ) );
 
@@ -161,6 +164,7 @@ private:
    {
       /// Color used for this primitive.
       ColorF color;
+      ColorF color2;
 
       /// Points used to store positional data. Exact semantics determined by type.
       Point3F a, b, c;
@@ -168,7 +172,10 @@ private:
          Tri,
          Box,
          Line,
-         Text
+         Text,
+         DirectionLine,
+         OutlinedText,
+         Capsule,
       } type;	   ///< Type of the primitive. The meanings of a,b,c are determined by this.
 
       SimTime dieTime;   ///< Time at which we should remove this from the list.
@@ -188,6 +195,7 @@ private:
 
    GFXStateBlockRef mRenderZOffSB;
    GFXStateBlockRef mRenderZOnSB;
+   GFXStateBlockRef mRenderAlpha;
 
    Resource<GFont> mFont;
 

+ 241 - 126
Engine/source/gui/controls/guiColorPicker.cpp

@@ -39,13 +39,13 @@ ColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f);
 ColorF colorAlphaW(1.0f, 1.0f, 1.0f, 0.0f);
 
 ColorI GuiColorPickerCtrl::mColorRange[7] = {
-    ColorI(255,0,0),     // Red
-	ColorI(255,0,255),   // Pink
-	ColorI(0,0,255),     // Blue
-	ColorI(0,255,255),   // Light blue
-	ColorI(0,255,0),     // Green
-	ColorI(255,255,0),   // Yellow
-	ColorI(255,0,0),      // Red
+   ColorI(255,0,0),     // Red
+   ColorI(255,0,255),   // Pink
+   ColorI(0,0,255),     // Blue
+   ColorI(0,255,255),   // Light blue
+   ColorI(0,255,0),     // Green
+   ColorI(255,255,0),   // Yellow
+   ColorI(255,0,0),     // Red
 };
 /// @}
 
@@ -57,7 +57,6 @@ ConsoleDocClass( GuiColorPickerCtrl,
    "@internal"
 );
 
-//--------------------------------------------------------------------------
 GuiColorPickerCtrl::GuiColorPickerCtrl()
 {
    setExtent(140, 30);
@@ -70,44 +69,50 @@ GuiColorPickerCtrl::GuiColorPickerCtrl()
    mPositionChanged = false;
    mSelectorGap = 1;
    mActionOnMove = false;
-	mShowReticle = true;
+   mShowReticle = true;
+   mSelectColor = false;
+   mSetColor = mSetColor.BLACK;
+   mBitmap = NULL;
 }
 
-//--------------------------------------------------------------------------
+GuiColorPickerCtrl::~GuiColorPickerCtrl()
+{
+   if (mBitmap)
+   {
+      delete mBitmap;
+      mBitmap = NULL;
+   }
+}
 
 ImplementEnumType( GuiColorPickMode,
    "\n\n"
    "@ingroup GuiUtil"
    "@internal" )
-   { GuiColorPickerCtrl::pPallet,		"Pallete"   },
-   { GuiColorPickerCtrl::pHorizColorRange,	"HorizColor"},
-   { GuiColorPickerCtrl::pVertColorRange,	"VertColor" },
-   { GuiColorPickerCtrl::pHorizColorBrightnessRange,	"HorizBrightnessColor"},
-   { GuiColorPickerCtrl::pVertColorBrightnessRange,	"VertBrightnessColor" },
-   { GuiColorPickerCtrl::pBlendColorRange,	"BlendColor"},
-   { GuiColorPickerCtrl::pHorizAlphaRange,	"HorizAlpha"},
-   { GuiColorPickerCtrl::pVertAlphaRange,	"VertAlpha" },
-   { GuiColorPickerCtrl::pDropperBackground,	"Dropper" },
+   { GuiColorPickerCtrl::pPallet, "Pallete" },
+   { GuiColorPickerCtrl::pHorizColorRange, "HorizColor"},
+   { GuiColorPickerCtrl::pVertColorRange, "VertColor" },
+   { GuiColorPickerCtrl::pHorizColorBrightnessRange, "HorizBrightnessColor" },
+   { GuiColorPickerCtrl::pVertColorBrightnessRange, "VertBrightnessColor" },
+   { GuiColorPickerCtrl::pBlendColorRange, "BlendColor" },
+   { GuiColorPickerCtrl::pHorizAlphaRange, "HorizAlpha" },
+   { GuiColorPickerCtrl::pVertAlphaRange, "VertAlpha" },
+   { GuiColorPickerCtrl::pDropperBackground, "Dropper" },
 EndImplementEnumType;
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::initPersistFields()
 {
    addGroup("ColorPicker");
-   
       addField("baseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl));
       addField("pickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl));
       addField("selectorGap", TypeS32,  Offset(mSelectorGap, GuiColorPickerCtrl)); 
       addField("displayMode", TYPEID< PickMode >(), Offset(mDisplayMode, GuiColorPickerCtrl) );
       addField("actionOnMove", TypeBool,Offset(mActionOnMove, GuiColorPickerCtrl));
       addField("showReticle", TypeBool, Offset(mShowReticle, GuiColorPickerCtrl));
-   
    endGroup("ColorPicker");
 
    Parent::initPersistFields();
 }
 
-//--------------------------------------------------------------------------
 // Function to draw a box which can have 4 different colors in each corner blended together
 void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4)
 {
@@ -119,54 +124,54 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col
    //A couple of checks to determine if color blend
    if(c1 == colorWhite && c3 == colorAlpha && c4 == colorBlack)
    {
-		//Color
-		PrimBuild::begin( GFXTriangleFan, 4 );
-		PrimBuild::color( c2 );
-		PrimBuild::vertex2i( r, t );
+      //Color
+      PrimBuild::begin(GFXTriangleFan, 4);
+      PrimBuild::color( c2 );
+      PrimBuild::vertex2i( r, t );
 
-		PrimBuild::color( c2 );
-		PrimBuild::vertex2i( r, b );
+      PrimBuild::color( c2 );
+      PrimBuild::vertex2i( r, b );
 
-		PrimBuild::color( c2 );
-		PrimBuild::vertex2i( l, b );
+      PrimBuild::color( c2 );
+      PrimBuild::vertex2i( l, b );
 
-		PrimBuild::color( c2 );
-		PrimBuild::vertex2i( l, t );
-		PrimBuild::end();
+      PrimBuild::color( c2 );
+      PrimBuild::vertex2i( l, t );
+      PrimBuild::end();
 
-		//White
-		PrimBuild::begin( GFXTriangleFan, 4 );
-		PrimBuild::color( colorAlphaW );
-		PrimBuild::vertex2i( r, t );
+      //White
+      PrimBuild::begin( GFXTriangleFan, 4 );
+      PrimBuild::color( colorAlphaW );
+      PrimBuild::vertex2i( r, t );
 
-		PrimBuild::color( colorAlphaW );
-		PrimBuild::vertex2i( r, b );
+      PrimBuild::color( colorAlphaW );
+      PrimBuild::vertex2i( r, b );
 
-		PrimBuild::color( c1 );
-		PrimBuild::vertex2i( l, b );
+      PrimBuild::color( c1 );
+      PrimBuild::vertex2i( l, b );
 
-		PrimBuild::color( c1 );
-		PrimBuild::vertex2i( l, t );
-		PrimBuild::end();
+      PrimBuild::color( c1 );
+      PrimBuild::vertex2i( l, t );
+      PrimBuild::end();
 
-		//Black 
-		PrimBuild::begin( GFXTriangleFan, 4 );
-		PrimBuild::color( c3 );
-		PrimBuild::vertex2i( r, t );
+      //Black
+      PrimBuild::begin( GFXTriangleFan, 4 );
+      PrimBuild::color( c3 );
+      PrimBuild::vertex2i( r, t );
 
-		PrimBuild::color( c4 );
-		PrimBuild::vertex2i( r, b );
+      PrimBuild::color( c4 );
+      PrimBuild::vertex2i( r, b );
 
-		PrimBuild::color( c4 );
-		PrimBuild::vertex2i( l, b );
+      PrimBuild::color( c4 );
+      PrimBuild::vertex2i( l, b );
 
-		PrimBuild::color( c3 );
-		PrimBuild::vertex2i( l, t );
-		PrimBuild::end();
+      PrimBuild::color( c3 );
+      PrimBuild::vertex2i( l, t );
+      PrimBuild::end();
    }
    else
    {
-	  PrimBuild::begin( GFXTriangleFan, 4 );
+      PrimBuild::begin( GFXTriangleFan, 4 );
       PrimBuild::color( c1 );
       PrimBuild::vertex2i( l, t );
 
@@ -233,31 +238,29 @@ void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numC
 
 void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode)
 {
-	if( !mShowReticle )
-		return; 
-
-	U16 sMax = mSelectorGap*2;
-	switch (mode)
-	{
-		case sVertical:
-			// Now draw the vertical selector
-			// Up -> Pos
-			if (selectorPos.y != bounds.point.y+1)
-				GFX->getDrawUtil()->drawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, colorWhiteBlend);
-			// Down -> Pos
-			if (selectorPos.y != bounds.point.y+bounds.extent.y) 
-				GFX->getDrawUtil()->drawLine(selectorPos.x,	selectorPos.y + sMax, selectorPos.x, bounds.point.y + bounds.extent.y, colorWhiteBlend);
-		break;
-		case sHorizontal:
-			// Now draw the horizontal selector
-			// Left -> Pos
-			if (selectorPos.x != bounds.point.x) 
+   if( !mShowReticle )
+      return; 
+
+   U16 sMax = mSelectorGap*2;
+   switch (mode)
+   {
+      case sVertical:
+         // Now draw the vertical selector Up -> Pos
+         if (selectorPos.y != bounds.point.y+1)
+            GFX->getDrawUtil()->drawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, colorWhiteBlend);
+         // Down -> Pos
+         if (selectorPos.y != bounds.point.y+bounds.extent.y) 
+            GFX->getDrawUtil()->drawLine(selectorPos.x,	selectorPos.y + sMax, selectorPos.x, bounds.point.y + bounds.extent.y, colorWhiteBlend);
+      break;
+      case sHorizontal:
+         // Now draw the horizontal selector Left -> Pos
+         if (selectorPos.x != bounds.point.x) 
             GFX->getDrawUtil()->drawLine(bounds.point.x, selectorPos.y-1, selectorPos.x-sMax, selectorPos.y-1, colorWhiteBlend);
-			// Right -> Pos
-			if (selectorPos.x != bounds.point.x) 
+         // Right -> Pos
+         if (selectorPos.x != bounds.point.x) 
             GFX->getDrawUtil()->drawLine(bounds.point.x+mSelectorPos.x+sMax, selectorPos.y-1, bounds.point.x + bounds.extent.x, selectorPos.y-1, colorWhiteBlend);
-		break;
-	}
+      break;
+   }
 }
 
 //--------------------------------------------------------------------------
@@ -269,10 +272,10 @@ void GuiColorPickerCtrl::renderColorBox(RectI &bounds)
    pickerBounds.point.y = bounds.point.y+1;
    pickerBounds.extent.x = bounds.extent.x-1;
    pickerBounds.extent.y = bounds.extent.y-1;
-   
+
    if (mProfile->mBorder)
       GFX->getDrawUtil()->drawRect(bounds, mProfile->mBorderColor);
-      
+
    Point2I selectorPos = Point2I(bounds.point.x+mSelectorPos.x+1, bounds.point.y+mSelectorPos.y+1);
 
    // Draw color box differently depending on mode
@@ -338,56 +341,169 @@ void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect)
       desc.setZReadWrite(false);
       desc.zWriteEnable = false;
       desc.setCullMode(GFXCullNone);
-      mStateBlock = GFX->createStateBlock( desc );
+      mStateBlock = GFX->createStateBlock(desc);
    }
 
-   RectI boundsRect(offset, getExtent()); 
+   RectI boundsRect(offset, getExtent());
    renderColorBox(boundsRect);
 
-   if (mPositionChanged) 
+   if (mPositionChanged || mBitmap == NULL)
    {
+      bool nullBitmap = false;
+
+      if (mPositionChanged == false && mBitmap == NULL)
+         nullBitmap = true;
+
       mPositionChanged = false;
       Point2I extent = getRoot()->getExtent();
+
       // If we are anything but a pallete, change the pick color
       if (mDisplayMode != pPallet)
       {
          Point2I resolution = getRoot()->getExtent();
 
          U32 buf_x = offset.x + mSelectorPos.x + 1;
-         U32 buf_y = resolution.y - ( extent.y - ( offset.y + mSelectorPos.y + 1 ) );
+         U32 buf_y = resolution.y - (extent.y - (offset.y + mSelectorPos.y + 1));
 
-         GFXTexHandle bb( resolution.x, 
-                          resolution.y, 
-                          GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
-         
-         Point2I tmpPt( buf_x, buf_y );
+         GFXTexHandle bb( resolution.x, resolution.y, GFXFormatR8G8B8A8, &GFXDefaultRenderTargetProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__) );
+
+         Point2I tmpPt(buf_x, buf_y);
 
          GFXTarget *targ = GFX->getActiveRenderTarget();
-         targ->resolveTo( bb );
-         
-         GBitmap bmp( bb.getWidth(), bb.getHeight() );
+         targ->resolveTo(bb);
+
+         if (mBitmap)
+         {
+            delete mBitmap;
+            mBitmap = NULL;
+         }
+
+         mBitmap = new GBitmap(bb.getWidth(), bb.getHeight());
+
+         bb.copyToBmp(mBitmap);
+
+         if (!nullBitmap)
+         {
+            if (mSelectColor)
+            {
+               Point2I pos = findColor(mSetColor, offset, resolution, *mBitmap);
+               mSetColor = mSetColor.BLACK;
+               mSelectColor = false;
+               setSelectorPos(pos);
+            }
+            else
+            {
+               ColorI tmp;
+               mBitmap->getColor(buf_x, buf_y, tmp);
+
+               mPickColor = (ColorF)tmp;
+
+               // Now do onAction() if we are allowed
+               if (mActionOnMove)
+                  onAction();
+            }
+         }
+      }
+   }
 
-         bb.copyToBmp( &bmp );
-         
-         //bmp.writePNGDebug( "foo.png" );
+   //render the children
+   renderChildControls(offset, updateRect);
+}
 
-         ColorI tmp;
-         bmp.getColor( buf_x, buf_y, tmp );
+void GuiColorPickerCtrl::setSelectorPos(const ColorF & color)
+{
+   if (mBitmap && !mPositionChanged)
+   {
+      Point2I resolution = getRoot() ? getRoot()->getExtent() : Point2I(1024, 768);
+      RectI rect(getGlobalBounds());
+      Point2I pos = findColor(color, rect.point, resolution, *mBitmap);
+      mSetColor = mSetColor.BLACK;
+      mSelectColor = false;
 
-         mPickColor = (ColorF)tmp;
+      setSelectorPos(pos);
+   }
+   else
+   {
+      mSetColor = color;
+      mSelectColor = true;
+      mPositionChanged = true;
+   }
+}
+
+Point2I GuiColorPickerCtrl::findColor(const ColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp)
+{
+   RectI rect;
+   Point2I ext = getExtent();
+   if (mDisplayMode != pDropperBackground)
+   {
+      ext.x -= 3;
+      ext.y -= 2;
+      rect = RectI(Point2I(1, 1), ext);
+   }
+   else
+   {
+      rect = RectI(Point2I(0, 0), ext);
+   }
+
+   Point2I closestPos(-1, -1);
+
+   /* Debugging
+   char filename[256];
+   dSprintf( filename, 256, "%s.%s", "colorPickerTest", "png" );
+
+   // Open up the file on disk.
+   FileStream fs;
+   if ( !fs.open( filename, Torque::FS::File::Write ) )
+   Con::errorf( "GuiObjectView::saveAsImage() - Failed to open output file '%s'!", filename );
+   else
+   {
+   // Write it and close.
+   bmp.writeBitmap( "png", fs );
+
+   fs.close();
+   }
+   */
 
-         // Now do onAction() if we are allowed
-         if (mActionOnMove) 
-            onAction();
+   ColorI tmp;
+   U32 buf_x;
+   U32 buf_y;
+   ColorF curColor;
+   F32 val(10000.0f);
+   F32 closestVal(10000.0f);
+   bool closestSet = false;
+
+   for (S32 x = rect.point.x; x <= rect.extent.x; x++)
+   {
+      for (S32 y = rect.point.y; y <= rect.extent.y; y++)
+      {
+         buf_x = offset.x + x + 1;
+         buf_y = (resolution.y - (offset.y + y + 1));
+         buf_y = resolution.y - buf_y;
+
+         //Get the color at that position
+         bmp.getColor(buf_x, buf_y, tmp);
+         curColor = (ColorF)tmp;
+
+         //Evaluate how close the color is to our desired color
+         val = mFabs(color.red - curColor.red) + mFabs(color.green - curColor.green) + mFabs(color.blue - curColor.blue);
+
+         if (!closestSet)
+         {
+            closestVal = val;
+            closestPos.set(x, y);
+            closestSet = true;
+         }
+         else if (val < closestVal)
+         {
+            closestVal = val;
+            closestPos.set(x, y);
+         }
       }
-      
    }
-   
-   //render the children
-   renderChildControls( offset, updateRect);
+
+   return closestPos;
 }
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
 {
    Point2I extent = getExtent();
@@ -432,7 +548,6 @@ void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos)
    }
 }
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event)
 {
    if (!mActive)
@@ -445,14 +560,14 @@ void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event)
    
    if (mProfile->mCanKeyFocus)
       setFirstResponder();
-	
-	if (mActive && (mDisplayMode != pDropperBackground)) 
+
+   if (mActive && (mDisplayMode != pDropperBackground))
       onAction();
 
    // Update the picker cross position
    if (mDisplayMode != pPallet)
-      setSelectorPos(globalToLocalCoord(event.mousePoint)); 
-   
+      setSelectorPos(globalToLocalCoord(event.mousePoint));
+
    mMouseDown = true;
 }
 
@@ -468,10 +583,8 @@ void GuiColorPickerCtrl::onMouseDragged(const GuiEvent &event)
 
    if( !mActionOnMove )
       execAltConsoleCallback();
-
 }
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event)
 {
    // Only for dropper mode
@@ -479,45 +592,40 @@ void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event)
       setSelectorPos(globalToLocalCoord(event.mousePoint));
 }
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::onMouseEnter(const GuiEvent &event)
 {
    mMouseOver = true;
 }
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::onMouseLeave(const GuiEvent &)
 {
    // Reset state
    mMouseOver = false;
 }
 
-//--------------------------------------------------------------------------
 void GuiColorPickerCtrl::onMouseUp(const GuiEvent &)
 {
    //if we released the mouse within this control, perform the action
-	if (mActive && mMouseDown && (mDisplayMode != pDropperBackground)) 
+   if (mActive && mMouseDown && (mDisplayMode != pDropperBackground))
       mMouseDown = false;
 
-   if (mActive && (mDisplayMode == pDropperBackground)) 
+   if (mActive && (mDisplayMode == pDropperBackground))
    {
       // In a dropper, the alt command executes the mouse up action (to signal stopping)
       execAltConsoleCallback();
    }
-   
+
    mouseUnlock();
 }
 
-//--------------------------------------------------------------------------
 const char *GuiColorPickerCtrl::getScriptValue()
 {
    static char temp[256];
    ColorF color = getValue();
-   dSprintf(temp,256,"%f %f %f %f",color.red, color.green, color.blue, color.alpha);
-   return temp; 
+   dSprintf( temp, 256, "%f %f %f %f", color.red, color.green, color.blue, color.alpha );
+   return temp;
 }
 
-//--------------------------------------------------------------------------    
 void GuiColorPickerCtrl::setScriptValue(const char *value)
 {
    ColorF newValue;
@@ -537,5 +645,12 @@ DefineConsoleMethod(GuiColorPickerCtrl, setSelectorPos, void, (Point2I newPos),
 
 DefineConsoleMethod(GuiColorPickerCtrl, updateColor, void, (), , "Forces update of pick color")
 {
-	object->updateColor();
+   object->updateColor();
+}
+
+DefineEngineMethod(GuiColorPickerCtrl, setSelectorColor, void, (ColorF color), ,
+   "Sets the current position of the selector based on a color.n"
+   "@param color Color to look for.n")
+{
+   object->setSelectorPos(color);
 }

+ 25 - 20
Engine/source/gui/controls/guiColorPicker.h

@@ -59,29 +59,28 @@ class GuiColorPickerCtrl : public GuiControl
   public:
    enum PickMode
    {
-     pPallet = 0,		///< We just have a solid color; We just act like a pallet 
-     pHorizColorRange,		///< We have a range of base colors going horizontally
-     pVertColorRange,		///< We have a range of base colors going vertically
+     pPallet = 0,                ///< We just have a solid color; We just act like a pallet 
+     pHorizColorRange,           ///< We have a range of base colors going horizontally
+     pVertColorRange,            ///< We have a range of base colors going vertically
      pHorizColorBrightnessRange, ///< HorizColorRange with brightness
-     pVertColorBrightnessRange, ///< VertColorRange with brightness
-     pBlendColorRange,		///< We have a box which shows a range in brightness of the color
-     pHorizAlphaRange,		///< We have a box which shows a range in alpha going horizontally
-     pVertAlphaRange,		///< We have a box which shows a range in alpha going vertically
-     pDropperBackground		///< The control does not draw anything; Only does something when you click, or move the mouse (when active)
+     pVertColorBrightnessRange,  ///< VertColorRange with brightness
+     pBlendColorRange,           ///< We have a box which shows a range in brightness of the color
+     pHorizAlphaRange,           ///< We have a box which shows a range in alpha going horizontally
+     pVertAlphaRange,            ///< We have a box which shows a range in alpha going vertically
+     pDropperBackground          ///< The control does not draw anything; Only does something when you click, or move the mouse (when active)
    };
    
    enum SelectorMode
    {
-     sHorizontal = 0,		///< Horizontal selector with small gap
-     sVertical,			///< Vertical selector with small gap
+     sHorizontal = 0,            ///< Horizontal selector with small gap
+     sVertical,                  ///< Vertical selector with small gap
    };
-  
+
   protected:
-   
    /// @name Core Rendering functions
    /// @{
-   void renderColorBox(RectI &bounds);			///< Function that draws the actual color box
-   void drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode);	///< Function that draws the selection indicator
+   void renderColorBox(RectI &bounds); ///< Function that draws the actual color box
+   void drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode); /// < Function that draws the selection indicator
    void drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, ColorF &c3, ColorF &c4);
    void drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors);
    /// @}
@@ -98,7 +97,11 @@ class GuiColorPickerCtrl : public GuiControl
    bool mMouseDown;		///< Mouse button down?
    bool mActionOnMove;		///< Perform onAction() when position has changed?
 
-	
+   bool mSelectColor;
+   ColorF mSetColor;
+   GBitmap* mBitmap;
+
+   Point2I findColor(const ColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp);
    
    S32   mSelectorGap;		///< The half-way "gap" between the selector pos and where the selector is allowed to draw. 
 
@@ -107,12 +110,13 @@ class GuiColorPickerCtrl : public GuiControl
    static ColorI mColorRange[7]; ///< Color range for pHorizColorRange and pVertColorRange
    /// @}
 
-  public:   
-   
+  public:
+
    DECLARE_CONOBJECT(GuiColorPickerCtrl);
    DECLARE_CATEGORY( "Gui Editor" );
    
    GuiColorPickerCtrl();
+   ~GuiColorPickerCtrl();
 
    static void initPersistFields();
    void onRender(Point2I offset, const RectI &updateRect);
@@ -122,18 +126,19 @@ class GuiColorPickerCtrl : public GuiControl
    /// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful
    void setValue(ColorF &value) {mBaseColor = value;}
    /// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colours themselves)
-   ColorF getValue() {return mDisplayMode == pPallet ? mBaseColor : mPickColor;}
+   ColorF getValue() { return mDisplayMode == pPallet ? mBaseColor : mPickColor; }
    const char *getScriptValue();
    void setScriptValue(const char *value);
    void updateColor() {mPositionChanged = true;}
    /// @}
-   
+
    /// @name Selector Functions
    /// @{
    void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords)
+   void setSelectorPos(const ColorF & color);
    Point2I getSelectorPos() {return mSelectorPos;}
    /// @}
-   
+
    /// @name Input Events
    /// @{
    void onMouseDown(const GuiEvent &);

+ 73 - 24
Engine/source/gui/controls/guiTextEditCtrl.cpp

@@ -128,6 +128,8 @@ GuiTextEditCtrl::GuiTextEditCtrl()
 
    mActive = true;
 
+   mTextValid = true;
+
    mTextOffsetReset = true;
 
    mHistoryDirty = false;
@@ -1252,14 +1254,16 @@ void GuiTextEditCtrl::onLoseFirstResponder()
    Parent::onLoseFirstResponder();
 }
 
-void GuiTextEditCtrl::onRender(Point2I offset, const RectI &updateRect)
+void GuiTextEditCtrl::onRender( Point2I offset, const RectI &updateRect )
 {
    RectI ctrlRect( offset, getExtent() );
 
    //if opaque, fill the update rect with the fill color
    if ( mProfile->mOpaque )
    {
-      if(isFirstResponder())
+      if ( !mTextValid )
+         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorERR );
+      else if ( isFirstResponder() )
          GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorHL );
       else
          GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColor );
@@ -1267,7 +1271,11 @@ void GuiTextEditCtrl::onRender(Point2I offset, const RectI &updateRect)
 
    //if there's a border, draw the border
    if ( mProfile->mBorder )
+   {
       renderBorder( ctrlRect, mProfile );
+      if ( !mTextValid )
+         GFX->getDrawUtil()->drawRectFill( ctrlRect, mProfile->mFillColorERR );
+   }
 
    drawText( ctrlRect, isFirstResponder() );
 }
@@ -1490,7 +1498,25 @@ void GuiTextEditCtrl::drawText( const RectI &drawRect, bool isFocused )
 
 bool GuiTextEditCtrl::hasText()
 {
-   return (mTextBuffer.length());
+   return ( mTextBuffer.length() );
+}
+
+void GuiTextEditCtrl::invalidText(bool playSound)
+{
+   mTextValid = false;
+
+   if ( playSound )
+      playDeniedSound();
+}
+
+void GuiTextEditCtrl::validText()
+{
+   mTextValid = true;
+}
+
+bool GuiTextEditCtrl::isValidText()
+{
+   return mTextValid;
 }
 
 void GuiTextEditCtrl::playDeniedSound()
@@ -1520,27 +1546,29 @@ void GuiTextEditCtrl::handleCharInput( U16 ascii )
    //see if it's a number field
    if ( mProfile->mNumbersOnly )
    {
-      if ( ascii == '-')
-      {
-         //a minus sign only exists at the beginning, and only a single minus sign
-         if ( mCursorPos != 0 && !isAllTextSelected() )
-         {
-            playDeniedSound();
-            return;
-         }
-
-         if ( mInsertOn && ( mTextBuffer.getChar(0) == '-' ) ) 
-         {
-            playDeniedSound();
-            return;
-         }
-      }
-      // BJTODO: This is probably not unicode safe.
-      else if (  ascii != '.' && (ascii < '0' || ascii > '9')  )
-      {
-         playDeniedSound();
-         return;
-      }
+	   if (ascii == '-')
+	   {
+		   //a minus sign only exists at the beginning, and only a single minus sign
+		   if (mCursorPos != 0 && !isAllTextSelected())
+		   {
+			   invalidText();
+			   return;
+		   }
+
+		   if (mInsertOn && (mTextBuffer.getChar(0) == '-'))
+		   {
+			   invalidText();
+			   return;
+		   }
+	   }
+	   // BJTODO: This is probably not unicode safe.
+	   else if (ascii != '.' && (ascii < '0' || ascii > '9'))
+	   {
+		   invalidText();
+		   return;
+	   }
+	   else
+		   validText();
    }
 
    //save the current state
@@ -1748,3 +1776,24 @@ DefineEngineMethod( GuiTextEditCtrl, forceValidateText, void, (),,
 {
    object->forceValidateText();
 }
+
+DefineEngineMethod(GuiTextEditCtrl, invalidText, void, (bool playSound), (true),
+	"@brief Trigger the invalid sound and make the box red.nn"
+	"@param playSound Play the invalid text sound or not.n")
+{
+	object->invalidText(playSound);
+}
+
+
+DefineEngineMethod(GuiTextEditCtrl, validText, void, (), ,
+	"@brief Restores the box to normal color.nn")
+{
+	object->validText();
+}
+
+DefineEngineMethod(GuiTextEditCtrl, isValidText, bool, (), ,
+	"@brief Returns if the text is set to valid or not.n"
+	"@Return true if text is set to valid, false if not.nn")
+{
+	return object->isValidText();
+}

+ 6 - 0
Engine/source/gui/controls/guiTextEditCtrl.h

@@ -93,6 +93,8 @@ protected:
    void playDeniedSound();
    void execConsoleCallback();
 
+   bool mTextValid;
+
    virtual void handleCharInput( U16 ascii );
 
    S32 findNextWord();   
@@ -119,6 +121,10 @@ public:
    S32   getCursorPos()   { return( mCursorPos ); }
    void  setCursorPos( const S32 newPos );
    
+   void invalidText(bool playSound = true);
+   void validText();
+   bool isValidText();
+
    bool isAllTextSelected();
    void selectAllText();
    void clearSelectedText();

+ 3 - 0
Engine/source/gui/core/guiCanvas.cpp

@@ -321,8 +321,11 @@ void GuiCanvas::setWindowTitle(const char *newTitle)
       mPlatformWindow->setCaption(newTitle);
 }
 
+CanvasSizeChangeSignal GuiCanvas::smCanvasSizeChangeSignal;
+
 void GuiCanvas::handleResize( WindowId did, S32 width, S32 height )
 {
+   getCanvasSizeChangeSignal().trigger(this);
 	if (Journal::IsPlaying() && mPlatformWindow)
 	{
 		mPlatformWindow->lockSize(false);

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

@@ -33,6 +33,10 @@
 #include "platform/platformInput.h"
 #endif
 
+#ifndef _SIGNAL_H_
+#include "core/util/tSignal.h"
+#endif
+
 #include "component/interfaces/IProcessInput.h"
 #include "windowManager/platformWindowMgr.h"
 #include "gfx/gfxFence.h"
@@ -74,6 +78,8 @@
 /// screen will be painted normally. If you are making an animated GuiControl
 /// you need to add your control to the dirty areas of the canvas.
 ///
+class guiCanvas;
+typedef Signal<void(GuiCanvas* canvas)> CanvasSizeChangeSignal;
 class GuiCanvas : public GuiControl, public IProcessInput
 {
 
@@ -183,6 +189,8 @@ protected:
    virtual void setupFences();
    
    void checkLockMouseMove( const GuiEvent& event );
+   //Signal used to let others know this canvas has changed size.
+	static CanvasSizeChangeSignal smCanvasSizeChangeSignal;
 
    GuiControl *mMenuBarCtrl;
 
@@ -200,6 +208,8 @@ public:
 
    static void initPersistFields();
 
+   static CanvasSizeChangeSignal& getCanvasSizeChangeSignal() { return smCanvasSizeChangeSignal; }
+
    /// @name Rendering methods
    ///
    /// @{

+ 66 - 0
Engine/source/gui/core/guiControl.cpp

@@ -175,6 +175,9 @@ ImplementEnumType( GuiHorizontalSizing,
 	{ GuiControl::horizResizeLeft,            "left"      },
    { GuiControl::horizResizeCenter,          "center"    },
    { GuiControl::horizResizeRelative,        "relative"  },
+   { GuiControl::horizResizeAspectLeft,      "aspectLeft" },
+   { GuiControl::horizResizeAspectRight,     "aspectRight" },
+   { GuiControl::horizResizeAspectCenter,    "aspectCenter" },
 	{ GuiControl::horizResizeWindowRelative,  "windowRelative"  }
 EndImplementEnumType;
 
@@ -186,6 +189,9 @@ ImplementEnumType( GuiVerticalSizing,
 	{ GuiControl::vertResizeTop,              "top"        },
    { GuiControl::vertResizeCenter,           "center"     },
    { GuiControl::vertResizeRelative,         "relative"   },
+   { GuiControl::vertResizeAspectTop,        "aspectTop"  },
+   { GuiControl::vertResizeAspectBottom,     "aspectBottom" },
+   { GuiControl::vertResizeAspectCenter,     "aspectCenter" },
 	{ GuiControl::vertResizeWindowRelative,   "windowRelative"   }
 EndImplementEnumType;
 
@@ -1370,6 +1376,36 @@ void GuiControl::parentResized(const RectI &oldParentRect, const RectI &newParen
       newPosition.x = newLeft;
       newExtent.x = newWidth;
    }
+   else if (mHorizSizing == horizResizeAspectLeft && oldParentRect.extent.x != 0)
+   {
+      S32 newLeft = mRoundToNearest((F32(newPosition.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
+      S32 newWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
+
+      newPosition.x = newLeft;
+      newExtent.x = newWidth;
+   }
+   else if (mHorizSizing == horizResizeAspectRight && oldParentRect.extent.x != 0)
+   {
+      S32 newLeft = mRoundToNearest((F32(newPosition.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
+      S32 newWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //origional aspect ratio corrected width
+      S32 rWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //parent aspect ratio relative width
+
+      S32 offset = rWidth - newWidth; // account for change in relative width
+      newLeft += offset;
+      newPosition.x = newLeft;
+      newExtent.x = newWidth;
+   }
+   else if (mHorizSizing == horizResizeAspectCenter && oldParentRect.extent.x != 0)
+   {
+      S32 newLeft = mRoundToNearest((F32(newPosition.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
+      S32 newWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //origional aspect ratio corrected width
+      S32 rWidth = mRoundToNearest((F32(newExtent.x) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //parent aspect ratio relative width
+
+      S32 offset = rWidth - newWidth; // account for change in relative width
+      newLeft += offset/2;
+      newPosition.x = newLeft;
+      newExtent.x = newWidth;
+   }
 
 	if (mVertSizing == vertResizeCenter)
 	   newPosition.y = (newParentRect.extent.y - getHeight()) >> 1;
@@ -1385,6 +1421,36 @@ void GuiControl::parentResized(const RectI &oldParentRect, const RectI &newParen
       newPosition.y = newTop;
       newExtent.y = newHeight;
    }
+   else if (mVertSizing == vertResizeAspectTop && oldParentRect.extent.y != 0)
+   {
+      S32 newTop = mRoundToNearest((F32(newPosition.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
+      S32 newHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x));
+
+      newPosition.y = newTop;
+      newExtent.y = newHeight;
+   }
+   else if (mVertSizing == vertResizeAspectBottom && oldParentRect.extent.y != 0)
+   {
+      S32 newTop = mRoundToNearest((F32(newPosition.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
+      S32 newHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //origional aspect ratio corrected hieght
+      S32 rHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //parent aspect ratio relative hieght
+
+      S32 offset = rHeight - newHeight; // account for change in relative hieght
+      newTop += offset;
+      newPosition.y = newTop;
+      newExtent.y = newHeight;
+   }
+   else if (mVertSizing == vertResizeAspectCenter && oldParentRect.extent.y != 0)
+   {
+      S32 newTop = mRoundToNearest((F32(newPosition.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y));
+      S32 newHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.x)) * F32(newParentRect.extent.x)); //origional aspect ratio corrected hieght
+      S32 rHeight = mRoundToNearest((F32(newExtent.y) / F32(oldParentRect.extent.y)) * F32(newParentRect.extent.y)); //parent aspect ratio relative hieght
+
+      S32 offset = rHeight - newHeight; // account for change in relative hieght
+      newTop += offset / 2;
+      newPosition.y = newTop;
+      newExtent.y = newHeight;
+   }
 
    // Resizing Re factor [9/18/2006]
    // Only resize if our minExtent is satisfied with it.

+ 6 - 0
Engine/source/gui/core/guiControl.h

@@ -121,6 +121,9 @@ class GuiControl : public SimGroup
          horizResizeLeft,        ///< fixed on the right and width
          horizResizeCenter,
          horizResizeRelative,     ///< resize relative
+         horizResizeAspectLeft,    ///< resize relative to height delta (offset Left)
+         horizResizeAspectRight,   ///< resize relative to height delta (offset Right)
+         horizResizeAspectCenter,  ///< resize relative to height delta (Centered)
          horizResizeWindowRelative ///< resize window relative
       };
       enum vertSizingOptions
@@ -130,6 +133,9 @@ class GuiControl : public SimGroup
          vertResizeTop,          ///< fixed in height and on the bottom
          vertResizeCenter,
          vertResizeRelative,      ///< resize relative
+         vertResizeAspectTop,     ///< resize relative to width delta (offset Left)
+         vertResizeAspectBottom,  ///< resize relative to width delta (offset Right)
+         vertResizeAspectCenter,  ///< resize relative to width delta Centered)
          vertResizeWindowRelative ///< resize window relative
       };
       

+ 3 - 0
Engine/source/gui/core/guiTypes.cpp

@@ -269,6 +269,7 @@ GuiControlProfile::GuiControlProfile(void) :
    mFillColor(255,0,255,255),
    mFillColorHL(255,0,255,255),
    mFillColorNA(255,0,255,255),
+   mFillColorERR(255,0,0,255),
    mFillColorSEL(255,0,255,255),
    mBorderColor(255,0,255,255),
    mBorderColorHL(255,0,255,255),
@@ -334,6 +335,7 @@ GuiControlProfile::GuiControlProfile(void) :
       mFillColor     = def->mFillColor;
       mFillColorHL   = def->mFillColorHL;
       mFillColorNA   = def->mFillColorNA;
+      mFillColorERR  = def->mFillColorERR;
       mFillColorSEL  = def->mFillColorSEL;
 
       mBorder        = def->mBorder;
@@ -398,6 +400,7 @@ void GuiControlProfile::initPersistFields()
       addField("fillColor",     TypeColorI,     Offset(mFillColor, GuiControlProfile));
       addField("fillColorHL",   TypeColorI,     Offset(mFillColorHL, GuiControlProfile));
       addField("fillColorNA",   TypeColorI,     Offset(mFillColorNA, GuiControlProfile));
+      addField("fillColorERR",  TypeColorI,     Offset(mFillColorERR, GuiControlProfile));
       addField("fillColorSEL",  TypeColorI,     Offset(mFillColorSEL, GuiControlProfile));
       addField("border",        TypeS32,        Offset(mBorder, GuiControlProfile),
          "Border type (0=no border)." );

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

@@ -385,6 +385,7 @@ public:
    ColorI mFillColor;                              ///< Fill color, this is used to fill the bounds of the control if it is opaque
    ColorI mFillColorHL;                            ///< This is used instead of mFillColor if the object is highlighted
    ColorI mFillColorNA;                            ///< This is used instead of mFillColor if the object is not active or disabled
+   ColorI mFillColorERR;                           ///< This is used instead of mFillColor if the object has an error or is invalid
    ColorI mFillColorSEL;                           ///< This is used instead of mFillColor if the object is selected
 
    S32 mBorder;                                    ///< For most controls, if mBorder is > 0 a border will be drawn, some controls use this to draw different types of borders however @see guiDefaultControlRender.cc

+ 2 - 2
Engine/source/gui/worldEditor/worldEditor.cpp

@@ -2810,7 +2810,7 @@ void WorldEditor::clearSelection()
 
 void WorldEditor::selectObject( SimObject *obj )
 {
-   if ( mSelectionLocked || !mSelected )
+   if ( mSelectionLocked || !mSelected || !obj )
       return;
 
    // Don't check isSelectionEnabled of SceneObjects here as we
@@ -2833,7 +2833,7 @@ void WorldEditor::selectObject( const char* obj )
 
 void WorldEditor::unselectObject( SimObject *obj )
 {
-   if ( mSelectionLocked || !mSelected )
+   if ( mSelectionLocked || !mSelected || !obj )
       return;
 
    if ( !objClassIgnored( obj ) && mSelected->objInSet( obj ) )

+ 5 - 9
Engine/source/lighting/advanced/advancedLightBinManager.cpp

@@ -318,6 +318,8 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
       const U32 numPrims = curEntry.numPrims;
       const U32 numVerts = curEntry.vertBuffer->mNumVerts;
 
+      ShadowMapParams *lsp = curLightInfo->getExtended<ShadowMapParams>();
+
       // Skip lights which won't affect the scene.
       if ( !curLightMat || curLightInfo->getBrightness() <= 0.001f )
          continue;
@@ -329,15 +331,12 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
       mShadowManager->setLightShadowMap( curEntry.shadowMap );
       mShadowManager->setLightDynamicShadowMap( curEntry.dynamicShadowMap );
 
-      // Let the shadow know we're about to render from it.
-      if ( curEntry.shadowMap )
-         curEntry.shadowMap->preLightRender();
-      if ( curEntry.dynamicShadowMap ) curEntry.dynamicShadowMap->preLightRender();
-
       // Set geometry
       GFX->setVertexBuffer( curEntry.vertBuffer );
       GFX->setPrimitiveBuffer( curEntry.primBuffer );
 
+      lsp->getOcclusionQuery()->begin();
+
       // Render the material passes
       while( curLightMat->matInstance->setupPass( state, sgData ) )
       {
@@ -352,10 +351,7 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
             GFX->drawPrimitive(GFXTriangleList, 0, numPrims);
       }
 
-      // Tell it we're done rendering.
-      if ( curEntry.shadowMap )
-         curEntry.shadowMap->postLightRender();
-      if ( curEntry.dynamicShadowMap ) curEntry.dynamicShadowMap->postLightRender();
+      lsp->getOcclusionQuery()->end();
    }
 
    // Set NULL for active shadow map (so nothing gets confused)

+ 1 - 1
Engine/source/lighting/advanced/advancedLightManager.cpp

@@ -105,7 +105,7 @@ void AdvancedLightManager::activate( SceneManager *sceneManager )
    // we prefer the floating point format if it works.
    Vector<GFXFormat> formats;
    formats.push_back( GFXFormatR16G16B16A16F );
-   formats.push_back( GFXFormatR16G16B16A16 );
+   //formats.push_back( GFXFormatR16G16B16A16 );
    GFXFormat blendTargetFormat = GFX->selectSupportedFormat( &GFXDefaultRenderTargetProfile,
                                                          formats,
                                                          true,

+ 16 - 14
Engine/source/lighting/advanced/glsl/advancedLightingFeaturesGLSL.cpp

@@ -156,8 +156,8 @@ void DeferredRTLightingFeatGLSL::processPix( Vector<ShaderComponent*> &component
          oneOverTargetSize->constSortPos = cspPass;
       }
 
-      meta->addStatement( new GenOp( "   float id_NL_Att, id_specular;\r\n   float3 id_lightcolor;\r\n" ) );
-      meta->addStatement( new GenOp( avar( "   %s(tex2D(@, @ + float2(0.0, @.y)), id_lightcolor, id_NL_Att, id_specular);\r\n", 
+      meta->addStatement( new GenOp( "   float id_NL_Att, id_specular;\r\n   vec3 id_lightcolor;\r\n" ) );
+      meta->addStatement( new GenOp( avar( "   %s(tex2D(@, @ + vec2(0.0, @.y)), id_lightcolor, id_NL_Att, id_specular);\r\n", 
          unconditionLightInfo.c_str() ), lightInfoBuffer, uvScene, oneOverTargetSize ) );
 
       meta->addStatement( new GenOp("   @ = lerp(@, id_lightcolor, 0.5);\r\n", d_lightcolor, d_lightcolor ) );
@@ -167,7 +167,7 @@ void DeferredRTLightingFeatGLSL::processPix( Vector<ShaderComponent*> &component
 
    // This is kind of weak sauce
    if( !fd.features[MFT_VertLit] && !fd.features[MFT_ToneMap] && !fd.features[MFT_LightMap] && !fd.features[MFT_SubSurface] )
-      meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "float4(@, 1.0)", d_lightcolor ), Material::Mul ) ) );
+      meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "vec4(@, 1.0)", d_lightcolor ), Material::Mul ) ) );
 
    output = meta;
 }
@@ -311,7 +311,7 @@ void DeferredBumpFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
          meta->addStatement( new GenOp( "   @.xy += @.xy * @;\r\n", bumpNorm, detailBump, detailBumpScale ) );
       }
 
-      // This var is read from GBufferConditionerHLSL and 
+      // This var is read from GBufferConditionerGLSL and 
       // used in the prepass output.
       //
       // By using the 'half' type here we get a bunch of partial
@@ -533,11 +533,13 @@ void DeferredPixelSpecularGLSL::processPix(  Vector<ShaderComponent*> &component
       specPow->constSortPos = cspPotentialPrimitive;
    }
 
-   Var *specStrength = new Var;
-   specStrength->setType( "float" );
-   specStrength->setName( "specularStrength" );
-   specStrength->uniform = true;
-   specStrength->constSortPos = cspPotentialPrimitive;
+   Var *specStrength = (Var*)LangElement::find( "specularStrength" );
+   if (!specStrength)
+   {
+       specStrength = new Var( "specularStrength", "float" );
+       specStrength->uniform = true;
+       specStrength->constSortPos = cspPotentialPrimitive;
+   }
 
    Var *lightInfoSamp = (Var *)LangElement::find( "lightInfoSample" );
    Var *d_specular = (Var*)LangElement::find( "d_specular" );
@@ -555,10 +557,10 @@ void DeferredPixelSpecularGLSL::processPix(  Vector<ShaderComponent*> &component
          meta->addStatement(new GenOp("   @ = clamp( lerp( @, @ * @, @.a), 0, 1);\r\n", d_specular, d_specular, accuSpecular, d_specular, accuPlc));
    }
    // (a^m)^n = a^(m*n)
-   meta->addStatement( new GenOp( "   @ = pow( abs(@), max((@ / AL_ConstantSpecularPower),1.0f)) * @;\r\n", 
+   		meta->addStatement( new GenOp( "   @ = pow( abs(@), max((@ / AL_ConstantSpecularPower),1.0f)) * @;\r\n", 
       specDecl, d_specular, specPow, specStrength ) );
 
-   LangElement *specMul = new GenOp( "float4( @.rgb, 0 ) * @", specCol, specular );
+   LangElement *specMul = new GenOp( "vec4( @.rgb, 0 ) * @", specCol, specular );
    LangElement *final = specMul;
 
    // We we have a normal map then mask the specular 
@@ -682,10 +684,10 @@ void DeferredMinnaertGLSL::processPix( Vector<ShaderComponent*> &componentList,
 
    Var *d_NL_Att = (Var*)LangElement::find( "d_NL_Att" );
 
-   meta->addStatement( new GenOp( avar( "   float4 normalDepth = %s(@, @);\r\n", unconditionPrePassMethod.c_str() ), prepassBuffer, uvScene ) );
+   meta->addStatement( new GenOp( avar( "   vec4 normalDepth = %s(@, @);\r\n", unconditionPrePassMethod.c_str() ), prepassBuffer, uvScene ) );
    meta->addStatement( new GenOp( "   float vDotN = dot(normalDepth.xyz, @);\r\n", wsViewVec ) );
    meta->addStatement( new GenOp( "   float Minnaert = pow( @, @) * pow(vDotN, 1.0 - @);\r\n", d_NL_Att, minnaertConstant, minnaertConstant ) );
-   meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "float4(Minnaert, Minnaert, Minnaert, 1.0)" ), Material::Mul ) ) );
+   meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "vec4(Minnaert, Minnaert, Minnaert, 1.0)" ), Material::Mul ) ) );
 
    output = meta;
 }
@@ -713,7 +715,7 @@ void DeferredSubSurfaceGLSL::processPix(  Vector<ShaderComponent*> &componentLis
    MultiLine *meta = new MultiLine;
    meta->addStatement( new GenOp( "   float subLamb = smoothstep([email protected], 1.0, @) - smoothstep(0.0, 1.0, @);\r\n", subSurfaceParams, d_NL_Att, d_NL_Att ) );
    meta->addStatement( new GenOp( "   subLamb = max(0.0, subLamb);\r\n" ) );
-   meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "float4(@ + (subLamb * @.rgb), 1.0)", d_lightcolor, subSurfaceParams ), Material::Mul ) ) );
+   meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "vec4(@ + (subLamb * @.rgb), 1.0)", d_lightcolor, subSurfaceParams ), Material::Mul ) ) );
 
    output = meta;
 }

+ 190 - 0
Engine/source/lighting/advanced/glsl/deferredShadingFeaturesGLSL.cpp

@@ -0,0 +1,190 @@
+//-----------------------------------------------------------------------------
+// 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 "platform/platform.h"
+#include "lighting/advanced/glsl/deferredShadingFeaturesGLSL.h"
+
+#include "lighting/advanced/advancedLightBinManager.h"
+#include "shaderGen/langElement.h"
+#include "shaderGen/shaderOp.h"
+#include "shaderGen/conditionerFeature.h"
+#include "renderInstance/renderPrePassMgr.h"
+#include "materials/processedMaterial.h"
+#include "materials/materialFeatureTypes.h"
+
+
+//****************************************************************************
+// Deferred Shading Features
+//****************************************************************************
+
+// Specular Map -> Blue of Material Buffer ( greyscaled )
+// Gloss Map (Alpha Channel of Specular Map) -> Alpha ( Spec Power ) of Material Info Buffer.
+void DeferredSpecMapGLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+   // Get the texture coord.
+   Var *texCoord = getInTexCoord( "texCoord", "vec2", true, componentList );
+
+   // search for color var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   MultiLine * meta = new MultiLine;
+   if ( !material )
+   {
+      // create color var
+      material = new Var;
+      material->setType( "vec4" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName("OUT");
+   }
+
+   // create texture var
+   Var *specularMap = new Var;
+   specularMap->setType( "sampler2D" );
+   specularMap->setName( "specularMap" );
+   specularMap->uniform = true;
+   specularMap->sampler = true;
+   specularMap->constNum = Var::getTexUnitNum();
+   LangElement *texOp = new GenOp( "tex2D(@, @)", specularMap, texCoord );
+   //matinfo.g slot reserved for AO later
+   meta->addStatement(new GenOp("   @.g = 1.0;\r\n", material));
+   meta->addStatement(new GenOp("   @.b = dot(tex2D(@, @).rgb, vec3(0.3, 0.59, 0.11));\r\n", material, specularMap, texCoord));
+   meta->addStatement(new GenOp("   @.a = tex2D(@, @).a;\r\n", material, specularMap, texCoord));
+   output = meta;
+}
+
+ShaderFeature::Resources DeferredSpecMapGLSL::getResources( const MaterialFeatureData &fd )
+{
+   Resources res; 
+   res.numTex = 1;
+   res.numTexReg = 1;
+
+   return res;
+}
+
+void DeferredSpecMapGLSL::setTexData(   Material::StageData &stageDat,
+                                       const MaterialFeatureData &fd,
+                                       RenderPassData &passData,
+                                       U32 &texIndex )
+{
+   GFXTextureObject *tex = stageDat.getTex( MFT_SpecularMap );
+   if ( tex )
+   {
+      passData.mTexType[ texIndex ] = Material::Standard;
+      passData.mSamplerNames[ texIndex ] = "specularMap";
+      passData.mTexSlot[ texIndex++ ].texObject = tex;
+   }
+}
+
+void DeferredSpecMapGLSL::processVert( Vector<ShaderComponent*> &componentList, 
+                                       const MaterialFeatureData &fd )
+{
+   MultiLine *meta = new MultiLine;
+   getOutTexCoord(   "texCoord", 
+                     "vec2", 
+                     true, 
+                     fd.features[MFT_TexAnim], 
+                     meta, 
+                     componentList );
+   output = meta;
+}
+
+// Material Info Flags -> Red ( Flags ) of Material Info Buffer.
+void DeferredMatInfoFlagsGLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+	MultiLine *meta = new MultiLine;
+
+   // search for material var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   if ( !material )
+   {
+      // create material var
+      material = new Var;
+      material->setType( "vec4" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName("OUT");
+   }
+
+   Var *matInfoFlags = new Var;
+   matInfoFlags->setType( "float" );
+   matInfoFlags->setName( "matInfoFlags" );
+   matInfoFlags->uniform = true;
+   matInfoFlags->constSortPos = cspPotentialPrimitive;
+
+   meta->addStatement(output = new GenOp("   @.r = @;\r\n", material, matInfoFlags));
+   output = meta;
+}
+
+// Spec Strength -> Blue Channel of Material Info Buffer.
+// Spec Power -> Alpha Channel ( of Material Info Buffer.
+void DeferredSpecVarsGLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+
+   // search for material var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   if ( !material )
+   {
+      // create material var
+      material = new Var;
+      material->setType( "vec4" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName("OUT");
+   }
+
+   Var *specStrength = new Var;
+   specStrength->setType( "float" );
+   specStrength->setName( "specularStrength" );
+   specStrength->uniform = true;
+   specStrength->constSortPos = cspPotentialPrimitive;
+
+   Var *specPower = new Var;
+   specPower->setType("float");
+   specPower->setName("specularPower");
+   specPower->uniform = true;
+   specPower->constSortPos = cspPotentialPrimitive;
+
+   MultiLine *meta = new MultiLine;
+   //matinfo.g slot reserved for AO later
+   meta->addStatement(new GenOp("   @.g = 1.0;\r\n", material));
+   meta->addStatement(new GenOp("   @.a = @/128;\r\n", material, specPower));
+   meta->addStatement(new GenOp("   @.b = @/5;\r\n", material, specStrength));
+   output = meta;
+}
+
+// Black -> Blue and Alpha of Color Buffer (representing no specular)
+void DeferredEmptySpecGLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{    
+   // search for material var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   if ( !material )
+   {
+      // create material var
+      material = new Var;
+      material->setType( "vec4" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName("OUT");
+   }
+
+   MultiLine * meta = new MultiLine;
+   //matinfo.g slot reserved for AO later
+   meta->addStatement(new GenOp("   @.g = 1.0;\r\n", material));
+   meta->addStatement(new GenOp("   @.ba = vec2(0.0);\r\n", material));
+   output = meta;
+}

+ 85 - 0
Engine/source/lighting/advanced/glsl/deferredShadingFeaturesGLSL.h

@@ -0,0 +1,85 @@
+//-----------------------------------------------------------------------------
+// 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 _DEFERREDSHADINGGLSL_H_
+#define _DEFERREDSHADINGGLSL_H_
+
+#include "shaderGen/GLSL/shaderFeatureGLSL.h"
+#include "shaderGen/GLSL/bumpGLSL.h"
+#include "shaderGen/GLSL/pixSpecularGLSL.h"
+
+// Specular Outputs
+class DeferredSpecMapGLSL : public ShaderFeatureGLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Specular Map"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual Resources getResources( const MaterialFeatureData &fd );
+
+   // Sets textures and texture flags for current pass
+   virtual void setTexData( Material::StageData &stageDat,
+                            const MaterialFeatureData &fd,
+                            RenderPassData &passData,
+                            U32 &texIndex );
+   
+   virtual void processVert( Vector<ShaderComponent*> &componentList,
+                             const MaterialFeatureData &fd );
+};
+
+class DeferredMatInfoFlagsGLSL : public ShaderFeatureGLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Mat Info Flags"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual U32 getOutputTargets( const MaterialFeatureData &fd ) const { return ShaderFeature::RenderTarget2; }
+};
+
+class DeferredSpecVarsGLSL : public ShaderFeatureGLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Specular Explicit Numbers"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual U32 getOutputTargets( const MaterialFeatureData &fd ) const { return ShaderFeature::RenderTarget2; }
+};
+
+
+class DeferredEmptySpecGLSL : public ShaderFeatureGLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Empty Specular"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual U32 getOutputTargets( const MaterialFeatureData &fd ) const { return ShaderFeature::RenderTarget2; }
+};
+
+#endif

+ 2 - 2
Engine/source/lighting/advanced/glsl/gBufferConditionerGLSL.cpp

@@ -170,7 +170,7 @@ void GBufferConditionerGLSL::processPix(  Vector<ShaderComponent*> &componentLis
    if ( fd.features[ MFT_IsTranslucentZWrite ] )
    {
       alphaVal = new Var( "outAlpha", "float" );
-      meta->addStatement( new GenOp( "   @ = col.a; // MFT_IsTranslucentZWrite\r\n", new DecOp( alphaVal ) ) );
+      meta->addStatement( new GenOp( "   @ = OUT_col1.a; // MFT_IsTranslucentZWrite\r\n", new DecOp( alphaVal ) ) );
    }
 
    // If using interlaced normals, invert the normal
@@ -397,7 +397,7 @@ Var* GBufferConditionerGLSL::_unconditionInput( Var *conditionedInput, MultiLine
    // Recover depth from encoding
    if(mNormalStorageType != CartesianXYZ)
    {
-      const U64 maxValPerChannel = 1 << mBitsPerChannel;
+      const U64 maxValPerChannel = (U64)1 << mBitsPerChannel;
       meta->addStatement( new GenOp( "   \r\n   // Decode depth\r\n" ) );
       meta->addStatement( new GenOp( avar( "   @.w = dot( @.zw, float2(1.0, 1.0/%llu.0));\r\n", maxValPerChannel - 1 ), 
          retVar, conditionedInput ) );

+ 9 - 7
Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp

@@ -227,7 +227,7 @@ void DeferredBumpFeatHLSL::processVert(   Vector<ShaderComponent*> &componentLis
 
       const bool useTexAnim = fd.features[MFT_TexAnim];
       // Make sure there are texcoords
-      if( !fd.features[MFT_Parallax] && !fd.features[MFT_DiffuseMap] )
+      if( !fd.features[MFT_Parallax] && !fd.features[MFT_DiffuseMap])
       {
 
          getOutTexCoord(   "texCoord", 
@@ -532,11 +532,13 @@ void DeferredPixelSpecularHLSL::processPix(  Vector<ShaderComponent*> &component
       specPow->constSortPos = cspPotentialPrimitive;
    }
 
-   Var *specStrength = new Var;
-   specStrength->setType( "float" );
-   specStrength->setName( "specularStrength" );
-   specStrength->uniform = true;
-   specStrength->constSortPos = cspPotentialPrimitive;
+   Var *specStrength = (Var*)LangElement::find( "specularStrength" );
+   if (!specStrength)
+   {
+       specStrength = new Var( "specularStrength", "float" );
+       specStrength->uniform = true;
+       specStrength->constSortPos = cspPotentialPrimitive;
+   }
 
    Var *lightInfoSamp = (Var *)LangElement::find( "lightInfoSample" );
    Var *d_specular = (Var*)LangElement::find( "d_specular" );
@@ -556,7 +558,7 @@ void DeferredPixelSpecularHLSL::processPix(  Vector<ShaderComponent*> &component
 	  
    // (a^m)^n = a^(m*n)
    meta->addStatement( new GenOp( "   @ = pow( abs(@), max((@ / AL_ConstantSpecularPower),1.0f)) * @;\r\n", 
-      specDecl, d_specular, specPow, specStrength ) );
+		   specDecl, d_specular, specPow, specStrength));
 
    LangElement *specMul = new GenOp( "float4( @.rgb, 0 ) * @", specCol, specular );
    LangElement *final = specMul;

+ 187 - 0
Engine/source/lighting/advanced/hlsl/deferredShadingFeaturesHLSL.cpp

@@ -0,0 +1,187 @@
+//-----------------------------------------------------------------------------
+// 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 "platform/platform.h"
+#include "lighting/advanced/hlsl/deferredShadingFeaturesHLSL.h"
+
+#include "lighting/advanced/advancedLightBinManager.h"
+#include "shaderGen/langElement.h"
+#include "shaderGen/shaderOp.h"
+#include "shaderGen/conditionerFeature.h"
+#include "renderInstance/renderPrePassMgr.h"
+#include "materials/processedMaterial.h"
+#include "materials/materialFeatureTypes.h"
+
+
+//****************************************************************************
+// Deferred Shading Features
+//****************************************************************************
+
+// Specular Map -> Blue of Material Buffer ( greyscaled )
+// Gloss Map (Alpha Channel of Specular Map) -> Alpha ( Spec Power ) of Material Info Buffer.
+void DeferredSpecMapHLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+   // Get the texture coord.
+   Var *texCoord = getInTexCoord( "texCoord", "float2", true, componentList );
+
+   // search for color var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   MultiLine * meta = new MultiLine;
+   if ( !material )
+   {
+      // create color var
+      material = new Var;
+      material->setType( "fragout" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName( "OUT" );
+   }
+
+   // create texture var
+   Var *specularMap = new Var;
+   specularMap->setType( "sampler2D" );
+   specularMap->setName( "specularMap" );
+   specularMap->uniform = true;
+   specularMap->sampler = true;
+   specularMap->constNum = Var::getTexUnitNum();
+   LangElement *texOp = new GenOp( "tex2D(@, @)", specularMap, texCoord );
+
+   //matinfo.g slot reserved for AO later
+   meta->addStatement(new GenOp("   @.g = 1.0;\r\n", material));
+   meta->addStatement(new GenOp("   @.b = dot(tex2D(@, @).rgb, float3(0.3, 0.59, 0.11));\r\n", material, specularMap, texCoord));
+   meta->addStatement(new GenOp("   @.a = tex2D(@, @).a;\r\n", material, specularMap, texCoord));
+   output = meta;
+}
+
+ShaderFeature::Resources DeferredSpecMapHLSL::getResources( const MaterialFeatureData &fd )
+{
+   Resources res; 
+   res.numTex = 1;
+   res.numTexReg = 1;
+
+   return res;
+}
+
+void DeferredSpecMapHLSL::setTexData(   Material::StageData &stageDat,
+                                       const MaterialFeatureData &fd,
+                                       RenderPassData &passData,
+                                       U32 &texIndex )
+{
+   GFXTextureObject *tex = stageDat.getTex( MFT_SpecularMap );
+   if ( tex )
+   {
+      passData.mTexType[ texIndex ] = Material::Standard;
+      passData.mSamplerNames[ texIndex ] = "specularMap";
+      passData.mTexSlot[ texIndex++ ].texObject = tex;
+   }
+}
+
+void DeferredSpecMapHLSL::processVert( Vector<ShaderComponent*> &componentList, 
+                                       const MaterialFeatureData &fd )
+{
+   MultiLine *meta = new MultiLine;
+   getOutTexCoord(   "texCoord", 
+                     "float2", 
+                     true, 
+                     fd.features[MFT_TexAnim], 
+                     meta, 
+                     componentList );
+   output = meta;
+}
+
+// Material Info Flags -> Red ( Flags ) of Material Info Buffer.
+void DeferredMatInfoFlagsHLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+   // search for material var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   if ( !material )
+   {
+      // create material var
+      material = new Var;
+      material->setType( "fragout" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName( "OUT" );
+   }
+
+   Var *matInfoFlags = new Var;
+   matInfoFlags->setType( "float" );
+   matInfoFlags->setName( "matInfoFlags" );
+   matInfoFlags->uniform = true;
+   matInfoFlags->constSortPos = cspPotentialPrimitive;
+
+   output = new GenOp( "   @.r = @;\r\n", material, matInfoFlags );
+}
+
+// Spec Strength -> Blue Channel of Material Info Buffer.
+// Spec Power -> Alpha Channel ( of Material Info Buffer.
+void DeferredSpecVarsHLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+   // search for material var
+   Var *material = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+   if ( !material )
+   {
+      // create material var
+      material = new Var;
+      material->setType( "fragout" );
+      material->setName( getOutputTargetVarName(ShaderFeature::RenderTarget2) );
+      material->setStructName( "OUT" );
+   }
+
+   Var *specStrength = new Var;
+   specStrength->setType( "float" );
+   specStrength->setName( "specularStrength" );
+   specStrength->uniform = true;
+   specStrength->constSortPos = cspPotentialPrimitive;
+
+   Var *specPower = new Var;
+   specPower->setType( "float" );
+   specPower->setName( "specularPower" );
+   specPower->uniform = true;
+   specPower->constSortPos = cspPotentialPrimitive;
+
+   MultiLine * meta = new MultiLine;
+   //matinfo.g slot reserved for AO later
+   meta->addStatement(new GenOp("   @.g = 1.0;\r\n", material));
+   meta->addStatement(new GenOp("   @.a = @/128;\r\n", material, specPower));
+   meta->addStatement(new GenOp("   @.b = @/5;\r\n", material, specStrength));
+   output = meta;
+}
+
+// Black -> Blue and Alpha of matinfo Buffer (representing no specular), White->G (representing No AO)
+void DeferredEmptySpecHLSL::processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+{
+   // search for material var
+   Var *material = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::RenderTarget2));
+   if (!material)
+   {
+       // create color var
+      material = new Var;
+      material->setType("fragout");
+      material->setName(getOutputTargetVarName(ShaderFeature::RenderTarget2));
+      material->setStructName("OUT");
+   }
+
+   MultiLine * meta = new MultiLine;
+   //matinfo.g slot reserved for AO later
+   meta->addStatement(new GenOp("   @.g = 1.0;\r\n", material));
+   meta->addStatement(new GenOp("   @.ba = 0.0;\r\n", material));
+   output = meta;
+}

+ 84 - 0
Engine/source/lighting/advanced/hlsl/deferredShadingFeaturesHLSL.h

@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------------
+// 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 _DEFERREDSHADINGHLSL_H_
+#define _DEFERREDSHADINGHLSL_H_
+
+#include "shaderGen/HLSL/shaderFeatureHLSL.h"
+#include "shaderGen/HLSL/bumpHLSL.h"
+#include "shaderGen/HLSL/pixSpecularHLSL.h"
+
+// Specular Outputs
+class DeferredSpecMapHLSL : public ShaderFeatureHLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Specular Map"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual Resources getResources( const MaterialFeatureData &fd );
+
+   // Sets textures and texture flags for current pass
+   virtual void setTexData( Material::StageData &stageDat,
+                            const MaterialFeatureData &fd,
+                            RenderPassData &passData,
+                            U32 &texIndex );
+   
+   virtual void processVert( Vector<ShaderComponent*> &componentList,
+                             const MaterialFeatureData &fd );
+};
+
+class DeferredMatInfoFlagsHLSL : public ShaderFeatureHLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Mat Info Flags"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual U32 getOutputTargets( const MaterialFeatureData &fd ) const { return ShaderFeature::RenderTarget2; }
+};
+
+class DeferredSpecVarsHLSL : public ShaderFeatureHLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Specular Explicit Numbers"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual U32 getOutputTargets( const MaterialFeatureData &fd ) const { return ShaderFeature::RenderTarget2; }
+};
+
+class DeferredEmptySpecHLSL : public ShaderFeatureHLSL
+{
+public:
+   virtual String getName() { return "Deferred Shading: Empty Specular"; }
+
+   virtual void processPix( Vector<ShaderComponent*> &componentList, 
+      const MaterialFeatureData &fd );
+   
+   virtual U32 getOutputTargets( const MaterialFeatureData &fd ) const { return ShaderFeature::RenderTarget2; }
+};
+
+#endif

+ 1 - 1
Engine/source/lighting/advanced/hlsl/gBufferConditionerHLSL.cpp

@@ -170,7 +170,7 @@ void GBufferConditionerHLSL::processPix(  Vector<ShaderComponent*> &componentLis
    if ( fd.features[ MFT_IsTranslucentZWrite ] )
    {
       alphaVal = new Var( "outAlpha", "float" );
-      meta->addStatement( new GenOp( "   @ = OUT.col.a; // MFT_IsTranslucentZWrite\r\n", new DecOp( alphaVal ) ) );
+      meta->addStatement( new GenOp( "   @ = OUT.col1.a; // MFT_IsTranslucentZWrite\r\n", new DecOp( alphaVal ) ) );
    }
 
    // If using interlaced normals, invert the normal

+ 7 - 24
Engine/source/lighting/shadowMap/lightShadowMap.cpp

@@ -89,8 +89,6 @@ LightShadowMap::LightShadowMap( LightInfo *light )
       mLastUpdate( 0 ),
       mLastCull( 0 ),
       mIsViewDependent( false ),
-      mVizQuery( NULL ),
-      mWasOccluded( false ),
       mLastScreenSize( 0.0f ),
       mLastPriority( 0.0f ),
       mIsDynamic( false )
@@ -98,9 +96,7 @@ LightShadowMap::LightShadowMap( LightInfo *light )
    GFXTextureManager::addEventDelegate( this, &LightShadowMap::_onTextureEvent );
 
    mTarget = GFX->allocRenderToTextureTarget();
-   mVizQuery = GFX->createOcclusionQuery();
-
-   smShadowMaps.push_back(this);
+   smShadowMaps.push_back( this );
    mStaticRefreshTimer = PlatformTimer::create();
    mDynamicRefreshTimer = PlatformTimer::create();
 }
@@ -108,8 +104,9 @@ LightShadowMap::LightShadowMap( LightInfo *light )
 LightShadowMap::~LightShadowMap()
 {
    mTarget = NULL;
-   SAFE_DELETE( mVizQuery );   
-   
+   SAFE_DELETE(mStaticRefreshTimer);
+   SAFE_DELETE(mDynamicRefreshTimer);
+
    releaseTextures();
 
    smShadowMaps.remove( this );
@@ -334,23 +331,6 @@ void LightShadowMap::render(  RenderPassManager* renderPass,
    mLastUpdate = Sim::getCurrentTime();
 }
 
-void LightShadowMap::preLightRender()
-{
-   PROFILE_SCOPE( LightShadowMap_prepLightRender );
-
-   if ( mVizQuery )
-   {
-      mWasOccluded = mVizQuery->getStatus( true ) == GFXOcclusionQuery::Occluded;
-      mVizQuery->begin();
-   }
-}
-
-void LightShadowMap::postLightRender()
-{
-   if ( mVizQuery )
-      mVizQuery->end();
-}
-
 BaseMatInstance* LightShadowMap::getShadowMaterial( BaseMatInstance *inMat ) const
 {
    // See if we have an existing material hook.
@@ -610,11 +590,14 @@ ShadowMapParams::ShadowMapParams( LightInfo *light )
    shadowSoftness = 0.15f;
    fadeStartDist = 0.0f;
    lastSplitTerrainOnly = false;
+   mQuery = GFX->createOcclusionQuery();
+
    _validate();
 }
 
 ShadowMapParams::~ShadowMapParams()
 {
+   SAFE_DELETE( mQuery );
    SAFE_DELETE( mShadowMap );
    SAFE_DELETE( mDynamicShadowMap );
 }

+ 6 - 16
Engine/source/lighting/shadowMap/lightShadowMap.h

@@ -47,6 +47,9 @@
 #ifndef _GFXSHADER_H_
 #include "gfx/gfxShader.h"
 #endif
+#ifndef _GFXOCCLUSIONQUERY_H_
+#include "gfx/gfxOcclusionQuery.h"
+#endif
 #ifndef _PLATFORM_PLATFORMTIMER_H_
 #include "platform/platformTimer.h"
 #endif
@@ -61,7 +64,6 @@ struct SceneData;
 class GFXShaderConstBuffer;
 class GFXShaderConstHandle;
 class GFXShader;
-class GFXOcclusionQuery;
 class LightManager;
 class RenderPassManager;
 
@@ -169,12 +171,6 @@ public:
 
    bool isViewDependent() const { return mIsViewDependent; }
 
-   bool wasOccluded() const { return mWasOccluded; }
-
-   void preLightRender();
-
-   void postLightRender();
-
    void updatePriority( const SceneRenderState *state, U32 currTimeMs );
 
    F32 getLastScreenSize() const { return mLastScreenSize; }
@@ -257,15 +253,6 @@ protected:
    /// The time this shadow was last culled and prioritized.
    U32 mLastCull;
 
-   /// The shadow occlusion query used when the light is
-   /// rendered to determine if any pixel of it is visible.
-   GFXOcclusionQuery *mVizQuery;
-
-   /// If true the light was occluded by geometry the
-   /// last frame it was updated.
-   //the last frame.
-   bool mWasOccluded;
-
    F32 mLastScreenSize;
 
    F32 mLastPriority;
@@ -325,6 +312,8 @@ public:
 
    bool hasCookieTex() const { return cookie.isNotEmpty(); }
 
+   GFXOcclusionQuery* getOcclusionQuery() const { return mQuery; }
+
    GFXTextureObject* getCookieTex();
 
    GFXCubemap* getCookieCubeTex();
@@ -339,6 +328,7 @@ protected:
    ///
    LightShadowMap *mShadowMap;
    LightShadowMap *mDynamicShadowMap;
+   GFXOcclusionQuery* mQuery;
 
    LightInfo *mLight;
 

+ 7 - 7
Engine/source/lighting/shadowMap/shadowMapPass.cpp

@@ -174,12 +174,12 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
          continue;
       
       // --- Static Shadow Map ---
-	  LightShadowMap *lsm = params->getOrCreateShadowMap();
-     LightShadowMap *dlsm = params->getOrCreateShadowMap(true);
+      LightShadowMap *lsm = params->getOrCreateShadowMap();
+      LightShadowMap *dlsm = params->getOrCreateShadowMap(true);
 
       // First check the visiblity query... if it wasn't 
       // visible skip it.
-     if (lsm->wasOccluded() || dlsm->wasOccluded())
+      if(params->getOcclusionQuery()->getStatus(true) == GFXOcclusionQuery::Occluded)
          continue;
 
       // Any shadow that is visible is counted as being 
@@ -187,9 +187,9 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
       ++smActiveShadowMaps;
 
       // Do a priority update for this shadow.
-	  lsm->updatePriority(diffuseState, currTime);
+      lsm->updatePriority(diffuseState, currTime);
 
-	  shadowMaps.push_back(lsm);
+      shadowMaps.push_back(lsm);
 
       // --- Dynamic Shadow Map ---
 
@@ -198,7 +198,7 @@ void ShadowMapPass::render(   SceneManager *sceneManager,
       ++smActiveShadowMaps;
 
       // Do a priority update for this shadow.
-	  dlsm->updatePriority(diffuseState, currTime);
+      dlsm->updatePriority(diffuseState, currTime);
 
       shadowMaps.push_back( dlsm );
    }
@@ -306,4 +306,4 @@ void DynamicShadowRenderPassManager::addInst( RenderInst *inst )
    }
 
    Parent::addInst(inst);
-}
+}

+ 9 - 2
Engine/source/materials/matTextureTarget.cpp

@@ -47,9 +47,16 @@ bool NamedTexTarget::registerWithName( const String &name )
    }
 
    // Make sure the target name isn't empty or already taken.
-   if ( name.isEmpty() || smTargets.contains( name ) )
+   if ( name.isEmpty())
+   {
+       Con::errorf("NamedTexTarget::registerWithName( const String &name ) No name given!");
+       return false;
+   }
+   if (smTargets.contains( name ) )
+   {
+       Con::errorf("NamedTexTarget::registerWithName( %s ) Already used!", name.c_str());
       return false;
-
+   }
    mName = name;
    mIsRegistered = true;
    smTargets.insert( mName, this );

+ 13 - 7
Engine/source/materials/materialDefinition.cpp

@@ -162,6 +162,9 @@ Material::Material()
 
       mSeqFramePerSec[i] = 0.0f;
       mSeqSegSize[i] = 0.0f;
+
+      // Deferred Shading
+      mMatInfoFlags[i] = 0.0f;
    }
 
    dMemset(mCellIndex, 0, sizeof(mCellIndex));
@@ -170,6 +173,9 @@ Material::Material()
    dMemset(mNormalMapAtlas, 0, sizeof(mNormalMapAtlas));
    dMemset(mUseAnisotropic, 0, sizeof(mUseAnisotropic));
 
+   // Deferred Shading : Metalness
+   dMemset(mUseMetalness, 0, sizeof(mUseMetalness));
+
    mImposterLimits = Point4F::Zero;
 
    mDoubleSided = false;
@@ -204,6 +210,9 @@ Material::Material()
    
    mDirectSoundOcclusion = 1.f;
    mReverbSoundOcclusion = 1.0;
+
+   // Deferred Shading
+   mIsSky = false;
 }
 
 void Material::initPersistFields()
@@ -289,10 +298,7 @@ void Material::initPersistFields()
       
       addField( "useAnisotropic", TypeBool, Offset(mUseAnisotropic, Material), MAX_STAGES,
          "Use anisotropic filtering for the textures of this stage." );
-      
-      addField("envMap", TypeImageFilename, Offset(mEnvMapFilename, Material), MAX_STAGES,
-         "The name of an environment map cube map to apply to this material." );
-
+     
       addField("vertLit", TypeBool, Offset(mVertLit, Material), MAX_STAGES,
          "If true the vertex color is used for lighting." );
 
@@ -379,9 +385,6 @@ void Material::initPersistFields()
       addProtectedField("bumpTex",        TypeImageFilename,   Offset(mNormalMapFilename, Material),
          defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES, 
          "For backwards compatibility.\n@see normalMap\n"); 
-      addProtectedField("envTex",         TypeImageFilename,   Offset(mEnvMapFilename, Material),
-         defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
-         "For backwards compatibility.\n@see envMap\n"); 
       addProtectedField("colorMultiply",  TypeColorF,          Offset(mDiffuse, Material),
          defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
          "For backwards compatibility.\n@see diffuseColor\n"); 
@@ -417,6 +420,9 @@ void Material::initPersistFields()
    addField("dynamicCubemap", TypeBool, Offset(mDynamicCubemap, Material),
       "Enables the material to use the dynamic cubemap from the ShapeBase object its applied to." );
 
+   addField("isSky", TypeBool, Offset(mIsSky, Material),
+       "Sky support. Alters draw dimensions." );
+
    addGroup( "Behavioral" );
 
       addField( "showFootprints", TypeBool, Offset( mShowFootprints, Material ),

+ 6 - 2
Engine/source/materials/materialDefinition.h

@@ -221,8 +221,6 @@ public:
    /// The strength scalar for the detail normal map.
    F32 mDetailNormalMapStrength[MAX_STAGES];   
       
-   FileName mEnvMapFilename[MAX_STAGES];
-   
    /// This color is the diffuse color of the material
    /// or if it has a texture it is multiplied against 
    /// the diffuse texture color.
@@ -287,12 +285,18 @@ public:
    /// If the stage should use anisotropic filtering.
    bool mUseAnisotropic[MAX_STAGES];
 
+   // Deferred Shading: Metalness
+   bool mUseMetalness[MAX_STAGES];
+
    bool mDoubleSided;
 
    String mCubemapName;
    CubemapData* mCubemapData;
    bool mDynamicCubemap;
 
+   // Deferred Shading
+   bool mIsSky;
+   F32 mMatInfoFlags[MAX_STAGES];
    bool mTranslucent;   
    BlendOp mTranslucentBlendOp;
    bool mTranslucentZWrite;

+ 16 - 5
Engine/source/materials/materialFeatureTypes.cpp

@@ -46,6 +46,7 @@ ImplementFeatureType( MFT_AlphaTest, MFG_Texture, 7.0f, true );
 ImplementFeatureType( MFT_SpecularMap, MFG_Texture, 8.0f, true );
 ImplementFeatureType( MFT_NormalMap, MFG_Texture, 9.0f, true );
 ImplementFeatureType( MFT_DetailNormalMap, MFG_Texture, 10.0f, true );
+ImplementFeatureType( MFT_Imposter, U32(-1), -1, true );
 
 ImplementFeatureType( MFT_AccuMap, MFG_PreLighting, 2.0f, true );
 
@@ -55,10 +56,9 @@ ImplementFeatureType( MFT_LightMap, MFG_Lighting, 4.0f, true );
 ImplementFeatureType( MFT_ToneMap, MFG_Lighting, 5.0f, true );
 ImplementFeatureType( MFT_VertLitTone, MFG_Lighting, 6.0f, false );
 ImplementFeatureType( MFT_VertLit, MFG_Lighting, 7.0f, true );
-ImplementFeatureType( MFT_EnvMap, MFG_Lighting, 8.0f, true );
-ImplementFeatureType( MFT_CubeMap, MFG_Lighting, 9.0f, true );
-ImplementFeatureType( MFT_PixSpecular, MFG_Lighting, 10.0f, true );
-ImplementFeatureType( MFT_MinnaertShading, MFG_Lighting, 12.0f, true );
+ImplementFeatureType( MFT_PixSpecular, MFG_Lighting, 9.0f, true );
+ImplementFeatureType( MFT_MinnaertShading, MFG_Lighting, 10.0f, true );
+ImplementFeatureType( MFT_CubeMap, MFG_Lighting, 11.0f, true );
 
 ImplementFeatureType( MFT_GlowMask, MFG_PostLighting, 1.0f, true );
 ImplementFeatureType( MFT_Visibility, MFG_PostLighting, 2.0f, true );
@@ -84,6 +84,8 @@ ImplementFeatureType( MFT_NormalsOut, MFG_PreLighting, 1.0f, false );
 
 ImplementFeatureType( MFT_LightbufferMRT, MFG_PreLighting, 1.0f, false );
 ImplementFeatureType( MFT_RenderTarget1_Zero, MFG_PreTexture, 1.0f, false );
+ImplementFeatureType( MFT_RenderTarget2_Zero, MFG_PreTexture, 1.0f, false );
+ImplementFeatureType( MFT_RenderTarget3_Zero, MFG_PreTexture, 1.0f, false );
 
 ImplementFeatureType( MFT_Foliage, MFG_PreTransform, 1.0f, false );
 
@@ -91,4 +93,13 @@ ImplementFeatureType( MFT_ParticleNormal, MFG_PreTransform, 2.0f, false );
 
 ImplementFeatureType( MFT_ForwardShading, U32(-1), -1, true );
 
-ImplementFeatureType( MFT_ImposterVert, MFG_PreTransform, 1.0, false );
+ImplementFeatureType( MFT_ImposterVert, MFG_PreTransform, 1.0, false );
+
+// Deferred Shading
+ImplementFeatureType( MFT_isDeferred, U32(-1), -1, true );
+ImplementFeatureType( MFT_SkyBox, MFG_Transform, 1.0f, true );
+ImplementFeatureType( MFT_DeferredEmptySpec, MFG_Texture, 8.01f, false );
+
+ImplementFeatureType( MFT_DeferredSpecMap, MFG_Texture, 8.2f, false );
+ImplementFeatureType( MFT_DeferredSpecVars, MFG_Texture, 8.5f, false );
+ImplementFeatureType( MFT_DeferredMatInfoFlags, MFG_Texture, 8.7f, false );

+ 11 - 2
Engine/source/materials/materialFeatureTypes.h

@@ -94,6 +94,7 @@ DeclareFeatureType( MFT_OverlayMap );
 DeclareFeatureType( MFT_DetailMap );
 DeclareFeatureType( MFT_DiffuseColor );
 DeclareFeatureType( MFT_DetailNormalMap );
+DeclareFeatureType( MFT_Imposter );
 
 DeclareFeatureType( MFT_AccuMap );
 DeclareFeatureType( MFT_AccuScale );
@@ -120,7 +121,6 @@ DeclareFeatureType( MFT_ToneMap );
 DeclareFeatureType( MFT_VertLit );
 DeclareFeatureType( MFT_VertLitTone );
 
-DeclareFeatureType( MFT_EnvMap );
 DeclareFeatureType( MFT_CubeMap );
 DeclareFeatureType( MFT_PixSpecular );
 DeclareFeatureType( MFT_SpecularMap );
@@ -157,8 +157,10 @@ DeclareFeatureType( MFT_InterlacedPrePass );
 /// to the second render-target
 DeclareFeatureType( MFT_LightbufferMRT );
 
-/// This feature outputs black to RenderTarget1
+/// This feature outputs black to RenderTarget3
 DeclareFeatureType( MFT_RenderTarget1_Zero );
+DeclareFeatureType( MFT_RenderTarget2_Zero );
+DeclareFeatureType( MFT_RenderTarget3_Zero );
 
 DeclareFeatureType( MFT_Foliage );
 
@@ -178,4 +180,11 @@ DeclareFeatureType( MFT_ForwardShading );
 DeclareFeatureType( MFT_ImposterVert );
 
 
+// Deferred Shading
+DeclareFeatureType( MFT_isDeferred );
+DeclareFeatureType( MFT_SkyBox );
+DeclareFeatureType( MFT_DeferredSpecMap );
+DeclareFeatureType( MFT_DeferredSpecVars );
+DeclareFeatureType( MFT_DeferredMatInfoFlags );
+DeclareFeatureType( MFT_DeferredEmptySpec );
 #endif // _MATERIALFEATURETYPES_H_

+ 0 - 8
Engine/source/materials/processedMaterial.cpp

@@ -455,14 +455,6 @@ void ProcessedMaterial::_setStageData()
          if(!mStages[i].getTex( MFT_SpecularMap ))
             mMaterial->logError("Failed to load specular map %s for stage %i", _getTexturePath(mMaterial->mSpecularMapFilename[i]).c_str(), i);
       }
-
-      // EnironmentMap
-      if( mMaterial->mEnvMapFilename[i].isNotEmpty() )
-      {
-         mStages[i].setTex( MFT_EnvMap, _createTexture( mMaterial->mEnvMapFilename[i], &GFXDefaultStaticDiffuseProfile ) );
-         if(!mStages[i].getTex( MFT_EnvMap ))
-            mMaterial->logError("Failed to load environment map %s for stage %i", _getTexturePath(mMaterial->mEnvMapFilename[i]).c_str(), i);
-      }
    }
 
 	mMaterial->mCubemapData = dynamic_cast<CubemapData*>(Sim::findObject( mMaterial->mCubemapName ));

+ 19 - 39
Engine/source/materials/processedShaderMaterial.cpp

@@ -106,6 +106,9 @@ void ShaderConstHandles::init( GFXShader *shader, CustomMaterial* mat /*=NULL*/
       for (S32 i = 0; i < Material::MAX_TEX_PER_PASS; ++i)
          mTexHandlesSC[i] = shader->getShaderConstHandle(mat->mSamplerNames[i]);
    }
+
+   // Deferred Shading
+   mMatInfoFlagsSC = shader->getShaderConstHandle(ShaderGenVars::matInfoFlags);
 }
 
 ///
@@ -208,28 +211,6 @@ bool ProcessedShaderMaterial::init( const FeatureSet &features,
       mInstancingState = new InstancingState();
       mInstancingState->setFormat( &_getRPD( 0 )->shader->mInstancingFormat, mVertexFormat );
    }
-
-   // Check for a RenderTexTargetBin assignment
-   // *IMPORTANT NOTE* 
-   // This is a temporary solution for getting diffuse mapping working with tex targets for standard materials
-   // It should be removed once this is done properly, at that time the sAllowTextureTargetAssignment should also be removed 
-   // from Material (it is necessary for catching shadow maps/post effect this shouldn't be applied to)
-   if (Material::sAllowTextureTargetAssignment)
-      if (mMaterial && mMaterial->mDiffuseMapFilename[0].isNotEmpty() && mMaterial->mDiffuseMapFilename[0].substr( 0, 1 ).equal("#"))
-      {
-         String texTargetBufferName = mMaterial->mDiffuseMapFilename[0].substr(1, mMaterial->mDiffuseMapFilename[0].length() - 1);
-         NamedTexTarget *texTarget = NamedTexTarget::find( texTargetBufferName ); 
-
-         RenderPassData* rpd = getPass(0);      
-
-         if (rpd)
-         {
-            rpd->mTexSlot[0].texTarget = texTarget;
-            rpd->mTexType[0] = Material::TexTarget;
-            rpd->mSamplerNames[0] = "diffuseMap";
-         }
-      }
-
    return true;
 }
 
@@ -353,11 +334,18 @@ void ProcessedShaderMaterial::_determineFeatures(  U32 stageNum,
       fd.features.addFeature( MFT_VertLit );
    
    // cubemaps only available on stage 0 for now - bramage   
-   if ( stageNum < 1 && 
+   if ( stageNum < 1 && mMaterial->isTranslucent() &&
          (  (  mMaterial->mCubemapData && mMaterial->mCubemapData->mCubemap ) ||
                mMaterial->mDynamicCubemap ) )
-   fd.features.addFeature( MFT_CubeMap );
+   {
+       fd.features.addFeature( MFT_CubeMap );
+   }
 
+   if (mMaterial->mIsSky)
+   {
+      fd.features.addFeature(MFT_CubeMap);
+      fd.features.addFeature(MFT_SkyBox);
+   }
    fd.features.addFeature( MFT_Visibility );
 
    if (  lastStage && 
@@ -428,7 +416,6 @@ void ProcessedShaderMaterial::_determineFeatures(  U32 stageNum,
 
    if ( mMaterial->mAccuEnabled[stageNum] )
    {
-      fd.features.addFeature( MFT_AccuMap );
       mHasAccumulation = true;
    }
 
@@ -441,19 +428,7 @@ void ProcessedShaderMaterial::_determineFeatures(  U32 stageNum,
       fd.features.removeFeature( MFT_AccuMap );
       mHasAccumulation = false;
    }
-
-   // if we still have the AccuMap feature, we add all accu constant features
-   if ( fd.features[ MFT_AccuMap ] ) {
-      // add the dependencies of the accu map
-      fd.features.addFeature( MFT_AccuScale );
-      fd.features.addFeature( MFT_AccuDirection );
-      fd.features.addFeature( MFT_AccuStrength );
-      fd.features.addFeature( MFT_AccuCoverage );
-      fd.features.addFeature( MFT_AccuSpecular );
-      // now remove some features that are not compatible with this
-      fd.features.removeFeature( MFT_UseInstancing );
-   }
-
+   
    // Without a base texture use the diffuse color
    // feature to ensure some sort of output.
    if (!fd.features[MFT_DiffuseMap])
@@ -1175,7 +1150,12 @@ void ProcessedShaderMaterial::_setShaderConstants(SceneRenderState * state, cons
          0.0f, 0.0f ); // TODO: Wrap mode flags?
       shaderConsts->setSafe(handles->mBumpAtlasTileSC, atlasTileParams);
    }
-   
+
+   // Deferred Shading: Determine Material Info Flags
+   S32 matInfoFlags = 
+            (mMaterial->mEmissive[stageNum] ? 1 : 0);
+   mMaterial->mMatInfoFlags[stageNum] = matInfoFlags / 255.0f;
+   shaderConsts->setSafe(handles->mMatInfoFlagsSC, mMaterial->mMatInfoFlags[stageNum]);   
    if( handles->mAccuScaleSC->isValid() )
       shaderConsts->set( handles->mAccuScaleSC, mMaterial->mAccuScale[stageNum] );
    if( handles->mAccuDirectionSC->isValid() )

+ 3 - 0
Engine/source/materials/processedShaderMaterial.h

@@ -87,6 +87,9 @@ public:
    GFXShaderConstHandle *mImposterUVs;
    GFXShaderConstHandle *mImposterLimits;
 
+   // Deferred Shading : Material Info Flags
+   GFXShaderConstHandle* mMatInfoFlagsSC;
+
    GFXShaderConstHandle* mTexHandlesSC[Material::MAX_TEX_PER_PASS];
    GFXShaderConstHandle* mRTParamsSC[TEXTURE_STAGE_COUNT];
 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.