Răsfoiți Sursa

Catch the template files up and add the improved convex editor bits.

Areloch 6 ani în urmă
părinte
comite
ebb51bb178

+ 503 - 129
Engine/source/T3D/convexShape.cpp

@@ -42,6 +42,7 @@
 #include "T3D/physics/physicsBody.h"
 #include "T3D/physics/physicsBody.h"
 #include "T3D/physics/physicsCollision.h"
 #include "T3D/physics/physicsCollision.h"
 #include "console/engineAPI.h"
 #include "console/engineAPI.h"
+#include "core/strings/stringUnit.h"
 
 
 IMPLEMENT_CO_NETOBJECT_V1( ConvexShape );
 IMPLEMENT_CO_NETOBJECT_V1( ConvexShape );
 
 
@@ -206,6 +207,12 @@ bool ConvexShape::protectedSetSurface( void *object, const char *index, const ch
 	Point3F pos;
 	Point3F pos;
 	//MatrixF mat;
 	//MatrixF mat;
 
 
+   U32 matID;
+   Point2F offset;
+   Point2F scale;
+   F32 rot = 0;
+   bool horz = true, vert = true;
+
 	/*
 	/*
    dSscanf( data, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
    dSscanf( data, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", 
       &mat[0], &mat[1], &mat[2], &mat[3], 
       &mat[0], &mat[1], &mat[2], &mat[3], 
@@ -214,23 +221,61 @@ bool ConvexShape::protectedSetSurface( void *object, const char *index, const ch
       &mat[12], &mat[13], &mat[14], &mat[15] );
       &mat[12], &mat[13], &mat[14], &mat[15] );
 	*/
 	*/
 
 
-	dSscanf( data, "%g %g %g %g %g %g %g", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z );
+   String t = data;
+   S32 len = t.length();
+
+	dSscanf( data, "%g %g %g %g %g %g %g %i %g %g %g %g %f", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z,
+      &matID, &offset.x, &offset.y, &scale.x, &scale.y, &rot);
 
 
 	MatrixF surface;
 	MatrixF surface;
 	quat.setMatrix( &surface );
 	quat.setMatrix( &surface );
 	surface.setPosition( pos );
 	surface.setPosition( pos );
 
 
-   shape->mSurfaces.push_back( surface );   
+   shape->mSurfaces.push_back( surface );  
+
+   surfaceUV surfUV;
+   if (StringUnit::getUnitCount(data, " ") > 7)
+   {
+      surfUV.matID = matID;
+      surfUV.offset = offset;
+      surfUV.scale = scale;
+      surfUV.zRot = rot;
+      surfUV.horzFlip = horz;
+      surfUV.vertFlip = vert;
+   }
+   else
+   {
+      surfUV.matID = 0;
+      surfUV.offset = Point2F(0,0);
+      surfUV.scale = Point2F(1, 1);
+      surfUV.zRot = 0;
+      surfUV.horzFlip = false;
+      surfUV.vertFlip = false;
+   }
+
+   shape->mSurfaceUVs.push_back(surfUV);
 
 
    return false;
    return false;
 }
 }
 
 
+bool ConvexShape::protectedSetSurfaceTexture(void *object, const char *index, const char *data)
+{
+   ConvexShape *shape = static_cast< ConvexShape* >(object);
+
+   surfaceMaterial surface;
+
+   surface.materialName = data;
+
+   shape->mSurfaceTextures.push_back(surface);
+
+   return false;
+}
 
 
 ConvexShape::ConvexShape()
 ConvexShape::ConvexShape()
  : mMaterialName( "Grid512_OrangeLines_Mat" ),
  : mMaterialName( "Grid512_OrangeLines_Mat" ),
    mMaterialInst( NULL ),
    mMaterialInst( NULL ),
-   mVertCount( 0 ),
-   mPrimCount( 0 ),
+   //mVertCount( 0 ),
+   //mPrimCount( 0 ),
    mPhysicsRep( NULL ),
    mPhysicsRep( NULL ),
    mNormalLength( 0.3f )
    mNormalLength( 0.3f )
 {   
 {   
@@ -240,6 +285,10 @@ ConvexShape::ConvexShape()
                 StaticShapeObjectType;    
                 StaticShapeObjectType;    
 
 
    mConvexList = new Convex;
    mConvexList = new Convex;
+
+   mSurfaceBuffers.clear();
+   mSurfaceUVs.clear();
+   mSurfaceTextures.clear();
 }
 }
 
 
 ConvexShape::~ConvexShape()
 ConvexShape::~ConvexShape()
@@ -247,6 +296,12 @@ ConvexShape::~ConvexShape()
    if ( mMaterialInst )
    if ( mMaterialInst )
       SAFE_DELETE( mMaterialInst );
       SAFE_DELETE( mMaterialInst );
 
 
+   for(U32 i=0; i<mSurfaceTextures.size(); i++)
+   {
+      if (mSurfaceTextures[i].materialInst)
+	      SAFE_DELETE(mSurfaceTextures[i].materialInst);
+   }
+
    delete mConvexList;
    delete mConvexList;
    mConvexList = NULL;
    mConvexList = NULL;
 }
 }
@@ -264,6 +319,9 @@ void ConvexShape::initPersistFields()
       addProtectedField( "surface", TypeRealString, NULL, &protectedSetSurface, &defaultProtectedGetFn, 
       addProtectedField( "surface", TypeRealString, NULL, &protectedSetSurface, &defaultProtectedGetFn, 
          "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
          "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
 
 
+	  addProtectedField( "surfaceTexture", TypeRealString, NULL, &protectedSetSurfaceTexture, &defaultProtectedGetFn, 
+         "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
+
    endGroup( "Internal" );
    endGroup( "Internal" );
 
 
    Parent::initPersistFields();
    Parent::initPersistFields();
@@ -334,7 +392,15 @@ bool ConvexShape::onAdd()
          surf.setColumn( 0, cubeTangents[i] );
          surf.setColumn( 0, cubeTangents[i] );
          surf.setColumn( 1, cubeBinormals[i] );
          surf.setColumn( 1, cubeBinormals[i] );
          surf.setColumn( 2, cubeNormals[i] );
          surf.setColumn( 2, cubeNormals[i] );
-         surf.setPosition( cubeNormals[i] * 0.5f );         
+         surf.setPosition( cubeNormals[i] * 0.5f );   
+
+         mSurfaceUVs.increment();
+         mSurfaceUVs[i].offset = Point2F(0, 0);
+         mSurfaceUVs[i].scale = Point2F(1, 1);
+         mSurfaceUVs[i].zRot = 0;
+         mSurfaceUVs[i].horzFlip = false;
+         mSurfaceUVs[i].vertFlip = false;
+         mSurfaceUVs[i].matID = 0;
       }
       }
    }
    }
 
 
@@ -345,6 +411,20 @@ bool ConvexShape::onAdd()
 
 
    addToScene();
    addToScene();
 
 
+   PlaneF p = PlaneF(Point3F(0, 0, 0), Point3F(0, 0, 1));
+
+   Point3F a = Point3F(0, 0, 1);
+   Point3F b = Point3F(1, 0, -1);
+   Point3F c = Point3F(-1, 0, -1);
+
+   Vector<Point3F> points;
+   points.push_back(a);
+   points.push_back(b);
+   points.push_back(c);
+
+   Point3F vertices[64];
+   p.clipPolygon(points.address(), points.size(), vertices);
+
    return true;
    return true;
 }
 }
 
 
@@ -374,6 +454,20 @@ void ConvexShape::writeFields( Stream &stream, U32 tabStop )
        count = smMaxSurfaces;
        count = smMaxSurfaces;
    }
    }
 
 
+   for (U32 i = 0; i < mSurfaceTextures.size(); i++)
+   {
+      stream.writeTabs(tabStop);
+
+      char buffer[1024];
+      dMemset(buffer, 0, 1024);
+
+      const char* tex = mSurfaceTextures[i].materialName.c_str();
+
+      dSprintf(buffer, 1024, "surfaceTexture = \"%s\";", mSurfaceTextures[i].materialName.c_str());
+
+      stream.writeLine((const U8*)buffer);
+   }
+
    for ( U32 i = 0; i < count; i++ )
    for ( U32 i = 0; i < count; i++ )
    {      
    {      
       const MatrixF &mat = mSurfaces[i];
       const MatrixF &mat = mSurfaces[i];
@@ -386,8 +480,10 @@ void ConvexShape::writeFields( Stream &stream, U32 tabStop )
       char buffer[1024];
       char buffer[1024];
       dMemset( buffer, 0, 1024 );      
       dMemset( buffer, 0, 1024 );      
       
       
-      dSprintf( buffer, 1024, "surface = \"%g %g %g %g %g %g %g\";", 
-         quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z );      
+      dSprintf( buffer, 1024, "surface = \"%g %g %g %g %g %g %g %i %g %g %g %g %g %i %i\";", 
+         quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z, mSurfaceUVs[i].matID,
+         mSurfaceUVs[i].offset.x, mSurfaceUVs[i].offset.y, mSurfaceUVs[i].scale.x, 
+         mSurfaceUVs[i].scale.y, mSurfaceUVs[i].zRot, mSurfaceUVs[i].horzFlip, mSurfaceUVs[i].vertFlip);
 
 
       stream.writeLine( (const U8*)buffer );
       stream.writeLine( (const U8*)buffer );
    }
    }
@@ -398,6 +494,9 @@ bool ConvexShape::writeField( StringTableEntry fieldname, const char *value )
    if ( fieldname == StringTable->insert("surface") )
    if ( fieldname == StringTable->insert("surface") )
       return false;
       return false;
 
 
+   if ( fieldname == StringTable->insert("surfaceTexture") )
+      return false;
+
    return Parent::writeField( fieldname, value );
    return Parent::writeField( fieldname, value );
 }
 }
 
 
@@ -440,8 +539,26 @@ U32 ConvexShape::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
 		 Point3F pos( mSurfaces[i].getPosition() );
 		 Point3F pos( mSurfaces[i].getPosition() );
 
 
          mathWrite( *stream, quat );
          mathWrite( *stream, quat );
-         mathWrite( *stream, pos );                    
+         mathWrite( *stream, pos );   
+
+         mathWrite(*stream, mSurfaceUVs[i].offset);
+         mathWrite(*stream, mSurfaceUVs[i].scale);
+
+         stream->writeFlag(mSurfaceUVs[i].horzFlip);
+         stream->writeFlag(mSurfaceUVs[i].vertFlip);
+
+         stream->writeInt(mSurfaceUVs[i].matID, 16);
       }
       }
+
+	  const U32 surfaceTex = mSurfaceTextures.size();
+
+	  stream->writeInt( surfaceTex, 32 );
+	  //next check for any texture coord or scale mods
+	  for(U32 i=0; i < surfaceTex; i++)
+     {
+        String a = mSurfaceTextures[i].materialName;
+			stream->write( mSurfaceTextures[i].materialName );
+	  }
    }
    }
 
 
    return retMask;
    return retMask;
@@ -464,10 +581,8 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream )
    {
    {
       stream->read( &mMaterialName );      
       stream->read( &mMaterialName );      
 
 
-      if ( isProperlyAdded() )
-         _updateMaterial();
-
       mSurfaces.clear();
       mSurfaces.clear();
+      mSurfaceUVs.clear();
 
 
       const U32 surfCount = stream->readInt( 32 );
       const U32 surfCount = stream->readInt( 32 );
       for ( S32 i = 0; i < surfCount; i++ )
       for ( S32 i = 0; i < surfCount; i++ )
@@ -483,8 +598,33 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream )
 
 
          quat.setMatrix( &mat );
          quat.setMatrix( &mat );
          mat.setPosition( pos );
          mat.setPosition( pos );
+
+         mSurfaceUVs.increment();
+
+         mathRead(*stream, &mSurfaceUVs[i].offset);
+         mathRead(*stream, &mSurfaceUVs[i].scale);
+
+         mSurfaceUVs[i].horzFlip = stream->readFlag();
+         mSurfaceUVs[i].vertFlip = stream->readFlag();
+
+         mSurfaceUVs[i].matID = stream->readInt(16);
       }
       }
 
 
+	  //now fetch our text coord mods to store into the geometry data
+      mSurfaceTextures.clear();
+	  const U32 surfaceTex = stream->readInt( 32 );
+
+	  //next check for any texture coord or scale mods
+	  for(U32 i=0; i < surfaceTex; i++)
+     {
+        mSurfaceTextures.increment();
+
+		  stream->read( &mSurfaceTextures[i].materialName );
+	  }
+
+     if (isProperlyAdded())
+        _updateMaterial();
+
       if ( isProperlyAdded() )
       if ( isProperlyAdded() )
          _updateGeometry( true );
          _updateGeometry( true );
    }
    }
@@ -492,6 +632,7 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream )
 
 
 void ConvexShape::prepRenderImage( SceneRenderState *state )
 void ConvexShape::prepRenderImage( SceneRenderState *state )
 {   
 {   
+   /*
    if ( state->isDiffusePass() )
    if ( state->isDiffusePass() )
    {
    {
       ObjectRenderInst *ri2 = state->getRenderPass()->allocInst<ObjectRenderInst>();
       ObjectRenderInst *ri2 = state->getRenderPass()->allocInst<ObjectRenderInst>();
@@ -499,82 +640,95 @@ void ConvexShape::prepRenderImage( SceneRenderState *state )
       ri2->type = RenderPassManager::RIT_Editor;
       ri2->type = RenderPassManager::RIT_Editor;
       state->getRenderPass()->addInst( ri2 );
       state->getRenderPass()->addInst( ri2 );
    }
    }
-   
-   if ( mVertexBuffer.isNull() || !state)
-      return;
+   */
 
 
-   // If we don't have a material instance after the override then 
-   // we can skip rendering all together.
-   BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance() );
-   if ( !matInst )
-      return;
+   for (U32 i = 0; i < mSurfaceBuffers.size(); i++)
+   {
+      if (mSurfaceBuffers[i].mPrimitiveBuffer.isNull())
+         continue;
 
 
-   // Get a handy pointer to our RenderPassmanager
-   RenderPassManager *renderPass = state->getRenderPass();
+      // If we don't have a material instance after the override then 
+      // we can skip rendering all together.
+      BaseMatInstance *matInst;
+      if (i == 0)
+      {
+         matInst = state->getOverrideMaterial(mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance());
+      }
+      else
+      {
+         matInst = state->getOverrideMaterial(mSurfaceTextures[i - 1].materialInst ? mSurfaceTextures[i - 1].materialInst : MATMGR->getWarningMatInstance());
+      }
 
 
-   // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
-   MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
+      if (!matInst)
+         continue;
 
 
-   // Set our RenderInst as a standard mesh render
-   ri->type = RenderPassManager::RIT_Mesh;
+      // Get a handy pointer to our RenderPassmanager
+      RenderPassManager *renderPass = state->getRenderPass();
 
 
-   // Calculate our sorting point
-   if ( state )
-   {
-      // Calculate our sort point manually.
-      const Box3F& rBox = getRenderWorldBox();
-      ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() );      
-   } 
-   else 
-      ri->sortDistSq = 0.0f;
-
-   // Set up our transforms
-   MatrixF objectToWorld = getRenderTransform();
-   objectToWorld.scale( getScale() );
-
-   ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld );
-   ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
-   ri->projection    = renderPass->allocSharedXform(RenderPassManager::Projection);
-
-	// If we need lights then set them up.
-   if ( matInst->isForwardLit() )
-   {
-      LightQuery query;
-      query.init( getWorldSphere() );
-		query.getLights( ri->lights, 8 );
-   }
+      // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
+      MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
 
 
-   // Make sure we have an up-to-date backbuffer in case
-   // our Material would like to make use of it
-   // NOTICE: SFXBB is removed and refraction is disabled!
-   //ri->backBuffTex = GFX->getSfxBackBuffer();
+      // Set our RenderInst as a standard mesh render
+      ri->type = RenderPassManager::RIT_Mesh;
 
 
-   // Set our Material
-   ri->matInst = matInst;
-   if ( matInst->getMaterial()->isTranslucent() )
-   {
-      ri->translucentSort = true;
-      ri->type = RenderPassManager::RIT_Translucent;
-   }
+      // Calculate our sorting point
+      if (state)
+      {
+         // Calculate our sort point manually.
+         const Box3F& rBox = getRenderWorldBox();
+         ri->sortDistSq = rBox.getSqDistanceToPoint(state->getCameraPosition());
+      }
+      else
+         ri->sortDistSq = 0.0f;
 
 
-   // Set up our vertex buffer and primitive buffer
-   ri->vertBuff = &mVertexBuffer;
-   ri->primBuff = &mPrimitiveBuffer;
+      // Set up our transforms
+      MatrixF objectToWorld = getRenderTransform();
+      objectToWorld.scale(getScale());
 
 
-   ri->prim = renderPass->allocPrim();
-   ri->prim->type = GFXTriangleList;
-   ri->prim->minIndex = 0;
-   ri->prim->startIndex = 0;
-   ri->prim->numPrimitives = mPrimCount;
-   ri->prim->startVertex = 0;
-   ri->prim->numVertices = mVertCount;
+      ri->objectToWorld = renderPass->allocUniqueXform(objectToWorld);
+      ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
+      ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
 
 
-   // We sort by the material then vertex buffer.
-   ri->defaultKey = matInst->getStateHint();
-   ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
+      // If we need lights then set them up.
+      if (matInst->isForwardLit())
+      {
+         LightQuery query;
+         query.init(getWorldSphere());
+         query.getLights(ri->lights, 8);
+      }
+
+      // Make sure we have an up-to-date backbuffer in case
+      // our Material would like to make use of it
+      // NOTICE: SFXBB is removed and refraction is disabled!
+      //ri->backBuffTex = GFX->getSfxBackBuffer();
+
+      // Set our Material
+      ri->matInst = matInst;
+      if (matInst->getMaterial()->isTranslucent())
+      {
+         ri->translucentSort = true;
+         ri->type = RenderPassManager::RIT_Translucent;
+      }
 
 
-   // Submit our RenderInst to the RenderPassManager
-   state->getRenderPass()->addInst( ri );
+      // Set up our vertex buffer and primitive buffer
+      ri->vertBuff = &mSurfaceBuffers[i].mVertexBuffer;
+      ri->primBuff = &mSurfaceBuffers[i].mPrimitiveBuffer;
+
+      ri->prim = renderPass->allocPrim();
+      ri->prim->type = GFXTriangleList;
+      ri->prim->minIndex = 0;
+      ri->prim->startIndex = 0;
+      ri->prim->numPrimitives = mSurfaceBuffers[i].mPrimCount;
+      ri->prim->startVertex = 0;
+      ri->prim->numVertices = mSurfaceBuffers[i].mVertCount;
+
+      // We sort by the material then vertex buffer.
+      ri->defaultKey = matInst->getStateHint();
+      ri->defaultKey2 = (U32)ri->vertBuff; // Not 64bit safe!
+
+      // Submit our RenderInst to the RenderPassManager
+      state->getRenderPass()->addInst(ri);
+   }
 }
 }
 
 
 void ConvexShape::buildConvex( const Box3F &box, Convex *convex )
 void ConvexShape::buildConvex( const Box3F &box, Convex *convex )
@@ -791,10 +945,21 @@ bool ConvexShape::castRay( const Point3F &start, const Point3F &end, RayInfo *in
    F32 t;
    F32 t;
    F32 tmin = F32_MAX;
    F32 tmin = F32_MAX;
    S32 hitFace = -1;
    S32 hitFace = -1;
-   Point3F pnt;
+   Point3F hitPnt, pnt;
    VectorF rayDir( end - start );
    VectorF rayDir( end - start );
    rayDir.normalizeSafe();
    rayDir.normalizeSafe();
-   
+
+   if ( false )
+   {
+      PlaneF plane( Point3F(0,0,0), Point3F(0,0,1) );
+      Point3F sp( 0,0,-1 );
+      Point3F ep( 0,0,1 );
+
+      F32 t = plane.intersect( sp, ep );
+      Point3F hitPnt;
+      hitPnt.interpolate( sp, ep, t );
+   }
+
    for ( S32 i = 0; i < planeCount; i++ )
    for ( S32 i = 0; i < planeCount; i++ )
    {
    {
       // Don't hit the back-side of planes.
       // Don't hit the back-side of planes.
@@ -1037,8 +1202,33 @@ void ConvexShape::getSurfaceLineList( S32 surfId, Vector< Point3F > &lineList )
 
 
 void ConvexShape::_updateMaterial()
 void ConvexShape::_updateMaterial()
 {   
 {   
+   //update our custom surface materials
+   for (U32 i = 0; i<mSurfaceTextures.size(); i++)
+   {
+      //If we already have the material inst and it hasn't changed, skip
+      if (mSurfaceTextures[i].materialInst && mSurfaceTextures[i].materialName.equal(mSurfaceTextures[i].materialInst->getMaterial()->getName(), String::NoCase))
+         continue;
+
+      Material *material;
+
+      if (!Sim::findObject(mSurfaceTextures[i].materialName, material))
+         //bail
+         continue;
+
+      mSurfaceTextures[i].materialInst = material->createMatInstance();
+
+      FeatureSet features = MATMGR->getDefaultFeatures();
+
+      mSurfaceTextures[i].materialInst->init(features, getGFXVertexFormat<VertexType>());
+
+      if (!mSurfaceTextures[i].materialInst->isValid())
+      {
+         SAFE_DELETE(mSurfaceTextures[i].materialInst);
+      }
+   }
+
    // If the material name matches then don't bother updating it.
    // If the material name matches then don't bother updating it.
-   if ( mMaterialInst && mMaterialName.equal( mMaterialInst->getMaterial()->getName(), String::NoCase ) )
+   if (mMaterialInst && mMaterialName.equal(mMaterialInst->getMaterial()->getName(), String::NoCase))
       return;
       return;
 
 
    SAFE_DELETE( mMaterialInst );
    SAFE_DELETE( mMaterialInst );
@@ -1074,34 +1264,85 @@ void ConvexShape::_updateGeometry( bool updateCollision )
    for ( S32 i = 0; i < mSurfaces.size(); i++ )   
    for ( S32 i = 0; i < mSurfaces.size(); i++ )   
       mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) );
       mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) );
 
 
-	Vector< Point3F > tangents;
-	for ( S32 i = 0; i < mSurfaces.size(); i++ )
-		tangents.push_back( mSurfaces[i].getRightVector() );
-   
-   mGeometry.generate( mPlanes, tangents );
+   Vector< Point3F > tangents;
+   for (S32 i = 0; i < mSurfaces.size(); i++)
+      tangents.push_back(mSurfaces[i].getRightVector());
+
+   //prepping the texture info
+   Vector<Point2F> texOffset;
+   Vector<Point2F> texScale;
+   Vector<bool> horzFlip;
+   Vector<bool> vertFlip;
+   //step in here, and add new surfaceTextures if we don't match the count of surfaces, we use
+   //msurfaces as the counter, because we need to match it.
+   if (mSurfaceUVs.size() > mSurfaces.size())
+   {
+      for (U32 x = mSurfaceUVs.size(); x > mSurfaces.size(); x--)
+         mSurfaceUVs.pop_front();
+   }
+   else if (mSurfaceUVs.size() < mSurfaces.size())
+   {
+      for (U32 x = mSurfaceUVs.size(); x <= mSurfaces.size(); x++)
+      {
+         mSurfaceUVs.increment();
+         mSurfaceUVs[x].offset = Point2F(0, 0);
+         mSurfaceUVs[x].scale = Point2F(1, 1);
+         mSurfaceUVs[x].zRot = 0;
+         mSurfaceUVs[x].horzFlip = false;
+         mSurfaceUVs[x].vertFlip = false;
+         mSurfaceUVs[x].matID = 0;
+      }
+   }
+
+   for (S32 i = 0; i < mSurfaceUVs.size(); i++)
+   {
+      //add our offsets/scales for passing to the geometry now
+      texOffset.push_back(mSurfaceUVs[i].offset);
+      texScale.push_back(mSurfaceUVs[i].scale);
+      horzFlip.push_back(mSurfaceUVs[i].horzFlip);
+      vertFlip.push_back(mSurfaceUVs[i].vertFlip);
+   }
 
 
-   AssertFatal( mGeometry.faces.size() <= mSurfaces.size(), "Got more faces than planes?" );
+   mGeometry.generate(mPlanes, tangents, mSurfaceTextures, texOffset, texScale, horzFlip, vertFlip);
+
+   AssertFatal(mGeometry.faces.size() <= mSurfaces.size(), "Got more faces than planes?");
 
 
    const Vector< ConvexShape::Face > &faceList = mGeometry.faces;
    const Vector< ConvexShape::Face > &faceList = mGeometry.faces;
    const Vector< Point3F > &pointList = mGeometry.points;
    const Vector< Point3F > &pointList = mGeometry.points;
 
 
    // Reset our surface center points.
    // Reset our surface center points.
 
 
-   for ( S32 i = 0; i < faceList.size(); i++ )
-		mSurfaces[ faceList[i].id ].setPosition( faceList[i].centroid );
+   for (S32 i = 0; i < faceList.size(); i++)
+      mSurfaces[faceList[i].id].setPosition(faceList[i].centroid);
 
 
    mPlanes.clear();
    mPlanes.clear();
 
 
-   for ( S32 i = 0; i < mSurfaces.size(); i++ )   
-      mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) );
+   for (S32 i = 0; i < mSurfaces.size(); i++)
+      mPlanes.push_back(PlaneF(mSurfaces[i].getPosition(), mSurfaces[i].getUpVector()));
 
 
    // Update bounding box.   
    // Update bounding box.   
    updateBounds( false );
    updateBounds( false );
 
 
-	mVertexBuffer = NULL;
-	mPrimitiveBuffer = NULL;
-	mVertCount = 0;
-	mPrimCount = 0;
+   /*mVertexBuffer = NULL;
+   mPrimitiveBuffer = NULL;
+   mVertCount = 0;
+   mPrimCount = 0;*/
+
+   mSurfaceBuffers.clear();
+
+   //set up buffers based on how many materials we have, but we always have at least one for our default mat
+   mSurfaceBuffers.increment();
+   mSurfaceBuffers[0].mVertexBuffer = NULL;
+   mSurfaceBuffers[0].mVertCount = 0;
+   mSurfaceBuffers[0].mPrimCount = 0;
+
+   for (U32 i = 0; i < mSurfaceTextures.size(); i++)
+   {
+      mSurfaceBuffers.increment();
+      mSurfaceBuffers[i+1].mVertexBuffer = NULL;
+      mSurfaceBuffers[i + 1].mVertCount = 0;
+      mSurfaceBuffers[i + 1].mPrimCount = 0;
+   }
 
 
    if ( updateCollision )
    if ( updateCollision )
       _updateCollision();
       _updateCollision();
@@ -1113,59 +1354,173 @@ void ConvexShape::_updateGeometry( bool updateCollision )
    if ( faceList.empty() )   
    if ( faceList.empty() )   
       return;
       return;
 
 
+   //We do this in 2 parts. First, going through and building the buffers for all faces with the default material(matID -1)
+   //After that, we then through and build buffers for all faces sharing materials. This means we can have a single buffer,
+   //or one for each face of the brush, depending on how it's textured
 
 
 	// Get total vert and prim count.
 	// Get total vert and prim count.
 
 
 	for ( S32 i = 0; i < faceList.size(); i++ )	
 	for ( S32 i = 0; i < faceList.size(); i++ )	
 	{
 	{
-		U32 count = faceList[i].triangles.size();
-		mPrimCount += count;
-		mVertCount += count * 3;		
+      U32 count = faceList[i].triangles.size();
+
+      S32 matID = mSurfaceUVs[i].matID;
+
+      mSurfaceBuffers[mSurfaceUVs[i].matID].mPrimCount += count;
+      mSurfaceBuffers[mSurfaceUVs[i].matID].mVertCount += count * 3;
 	}
 	}
 
 
-	// Allocate VB and copy in data.
+   //Build the buffer for our default material
+   /*if (mVertCount > 0)
+   {
+      mVertexBuffer.set(GFX, mVertCount, GFXBufferTypeStatic);
+      VertexType *pVert = mVertexBuffer.lock();
 
 
-	mVertexBuffer.set( GFX, mVertCount, GFXBufferTypeStatic );
-	VertexType *pVert = mVertexBuffer.lock();
+      for (S32 i = 0; i < faceList.size(); i++)
+      {
+         if (mSurfaceUVs[i].matID == -1)
+         {
+            const ConvexShape::Face &face = faceList[i];
+            const Vector< U32 > &facePntMap = face.points;
+            const Vector< ConvexShape::Triangle > &triangles = face.triangles;
+            const ColorI &faceColor = sgConvexFaceColors[i % sgConvexFaceColorCount];
 
 
-	for ( S32 i = 0; i < faceList.size(); i++ )
-	{
-		const ConvexShape::Face &face = faceList[i];
-		const Vector< U32 > &facePntMap = face.points;
-		const Vector< ConvexShape::Triangle > &triangles = face.triangles;
-		const ColorI &faceColor = sgConvexFaceColors[ i % sgConvexFaceColorCount ];
+            const Point3F binormal = mCross(face.normal, face.tangent);
 
 
-		for ( S32 j = 0; j < triangles.size(); j++ )
-		{
-			for ( S32 k = 0; k < 3; k++ )
-			{
-				pVert->normal = face.normal;
-				pVert->tangent = face.tangent;
-				pVert->color = faceColor;			
-				pVert->point = pointList[ facePntMap[ triangles[j][k] ] ];
-				pVert->texCoord = face.texcoords[ triangles[j][k] ];
+                  pVert++;
+               }
+            }
+         }
+      }
 
 
-				pVert++;
-			}
-		}		
-	}	
+      mVertexBuffer.unlock();
+
+      // Allocate PB
 
 
-	mVertexBuffer.unlock();
+      mPrimitiveBuffer.set(GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic);
 
 
-	// Allocate PB
+      U16 *pIndex;
+      mPrimitiveBuffer.lock(&pIndex);
 
 
-   mPrimitiveBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic );
+      for (U16 i = 0; i < mPrimCount * 3; i++)
+      {
+         *pIndex = i;
+         pIndex++;
+      }
 
 
-   U16 *pIndex;
-   mPrimitiveBuffer.lock( &pIndex );
+      mPrimitiveBuffer.unlock();
+   }*/
 
 
-   for ( U16 i = 0; i < mPrimCount * 3; i++ )
+   //
+   //
+   for (U32 i = 0; i < mSurfaceBuffers.size(); i++)
    {
    {
-      *pIndex = i;
-      pIndex++;
+      if (mSurfaceBuffers[i].mVertCount > 0)
+      {
+         U32 primCount = mSurfaceBuffers[i].mPrimCount;
+         U32 vertCount = mSurfaceBuffers[i].mVertCount;
+
+         mSurfaceBuffers[i].mVertexBuffer.set(GFX, mSurfaceBuffers[i].mVertCount, GFXBufferTypeStatic);
+         VertexType *pVert = mSurfaceBuffers[i].mVertexBuffer.lock();
+
+         U32 vc = 0;
+
+         for (S32 f = 0; f < faceList.size(); f++)
+         {
+            if (mSurfaceUVs[f].matID == i)
+            {
+               const ConvexShape::Face &face = faceList[f];
+               const Vector< U32 > &facePntMap = face.points;
+               const Vector< ConvexShape::Triangle > &triangles = face.triangles;
+               const ColorI &faceColor = sgConvexFaceColors[f % sgConvexFaceColorCount];
+
+               const Point3F binormal = mCross(face.normal, face.tangent);
+
+               for (S32 j = 0; j < triangles.size(); j++)
+               {
+                  for (S32 k = 0; k < 3; k++)
+                  {
+                     pVert->normal = face.normal;
+                     pVert->tangent = face.tangent;
+                     pVert->color = faceColor;
+                     pVert->point = pointList[facePntMap[triangles[j][k]]];
+                     pVert->texCoord = face.texcoords[triangles[j][k]];
+
+                     pVert++;
+                     vc++;
+                  }
+               }
+            }
+         }
+
+         mSurfaceBuffers[i].mVertexBuffer.unlock();
+
+         // Allocate PB
+
+         mSurfaceBuffers[i].mPrimitiveBuffer.set(GFX, mSurfaceBuffers[i].mPrimCount * 3, mSurfaceBuffers[i].mPrimCount, GFXBufferTypeStatic);
+
+         U16 *pIndex;
+         mSurfaceBuffers[i].mPrimitiveBuffer.lock(&pIndex);
+
+         for (U16 p = 0; p < mSurfaceBuffers[i].mPrimCount * 3; p++)
+         {
+            *pIndex = p;
+            pIndex++;
+         }
+
+         mSurfaceBuffers[i].mPrimitiveBuffer.unlock();
+      }
    }
    }
+   //
+   //
+
+   /*// Allocate VB and copy in data.
+   for (S32 i = 0; i < faceList.size(); i++)
+   {
+      mVertexBuffer.set(GFX, mVertCount, GFXBufferTypeStatic);
+      VertexType *pVert = mVertexBuffer.lock();
 
 
-   mPrimitiveBuffer.unlock();
+      for (S32 i = 0; i < faceList.size(); i++)
+      {
+         const ConvexShape::Face &face = faceList[i];
+         const Vector< U32 > &facePntMap = face.points;
+         const Vector< ConvexShape::Triangle > &triangles = face.triangles;
+         const ColorI &faceColor = sgConvexFaceColors[i % sgConvexFaceColorCount];
+
+         const Point3F binormal = mCross(face.normal, face.tangent);
+
+         for (S32 j = 0; j < triangles.size(); j++)
+         {
+            for (S32 k = 0; k < 3; k++)
+            {
+               pVert->normal = face.normal;
+               pVert->tangent = face.tangent;
+               pVert->color = faceColor;
+               pVert->point = pointList[facePntMap[triangles[j][k]]];
+               pVert->texCoord = face.texcoords[triangles[j][k]];
+
+               pVert++;
+            }
+         }
+      }
+
+      mVertexBuffer.unlock();
+
+      // Allocate PB
+
+      mPrimitiveBuffer.set(GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic);
+
+      U16 *pIndex;
+      mPrimitiveBuffer.lock(&pIndex);
+
+      for (U16 i = 0; i < mPrimCount * 3; i++)
+      {
+         *pIndex = i;
+         pIndex++;
+      }
+
+      mPrimitiveBuffer.unlock();
+   }*/
 }
 }
 
 
 void ConvexShape::_updateCollision()
 void ConvexShape::_updateCollision()
@@ -1488,7 +1843,7 @@ void ConvexShape::getSurfaceTriangles( S32 surfId, Vector< Point3F > *outPoints,
          objToWorld.mulP( (*outPoints)[i] );      
          objToWorld.mulP( (*outPoints)[i] );      
    }
    }
 }
 }
-void ConvexShape::Geometry::generate( const Vector< PlaneF > &planes, const Vector< Point3F > &tangents )
+void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vector< Point3F > &tangents, const Vector< surfaceMaterial > surfaceTextures, const Vector< Point2F > texOffset, const Vector< Point2F > texScale, const Vector< bool > horzFlip, const Vector< bool > vertFlip)
 {
 {
    PROFILE_SCOPE( Geometry_generate );
    PROFILE_SCOPE( Geometry_generate );
 
 
@@ -1759,7 +2114,26 @@ void ConvexShape::Geometry::generate( const Vector< PlaneF > &planes, const Vect
 			F32 x = planex.distToPlane( points[ newFace.points[ j ] ] );
 			F32 x = planex.distToPlane( points[ newFace.points[ j ] ] );
 			F32 y = planey.distToPlane( points[ newFace.points[ j ] ] );
 			F32 y = planey.distToPlane( points[ newFace.points[ j ] ] );
 
 
-			newFace.texcoords[j].set( -x, -y );
+			if (!texOffset.empty())
+	         {
+	            x += texOffset[i].x;
+	            y += texOffset[i].y;
+	         }
+	
+	         //now scale
+	         if (!texScale.empty() && !texScale[i].isZero())
+	         {
+	            x *= (texScale[i].x);
+	            y *= (texScale[i].y);
+	         }
+	
+	         if (horzFlip.size() > 0 && horzFlip[i])
+	            x *= -1;
+	
+	         if (vertFlip.size() > 0 && vertFlip[i])
+	            y *= -1;
+	
+	         newFace.texcoords[j].set(-x, -y);
 		}
 		}
 
 
       // Data verification tests.
       // Data verification tests.

+ 48 - 3
Engine/source/T3D/convexShape.h

@@ -131,9 +131,46 @@ public:
       S32 id;
       S32 id;
    }; 
    }; 
 
 
+   struct surfaceMaterial
+   {
+      // The name of the Material we will use for rendering
+      String            materialName;
+
+      // The actual Material instance
+      BaseMatInstance*  materialInst;
+
+      surfaceMaterial()
+      {
+         materialName = "";
+         materialInst = NULL;
+      }
+   };
+
+   struct surfaceUV
+   {
+      S32 matID;
+      Point2F offset;
+      Point2F scale;
+      float   zRot;
+      bool horzFlip;
+      bool vertFlip;
+
+      surfaceUV() : matID(0), offset(Point2F(0.0f, 0.0f)), scale(Point2F(1.0f, 1.0f)), zRot(0.0f), horzFlip(false), vertFlip(false) {}
+   };
+
+   struct surfaceBuffers
+   {
+      // The GFX vertex and primitive buffers
+      GFXVertexBufferHandle< VertexType > mVertexBuffer;
+      GFXPrimitiveBufferHandle            mPrimitiveBuffer;
+
+      U32 mVertCount;
+      U32 mPrimCount;
+   };
+
 	struct Geometry
 	struct Geometry
 	{  
 	{  
-		void generate( const Vector< PlaneF > &planes, const Vector< Point3F > &tangents );   
+      void generate(const Vector< PlaneF > &planes, const Vector< Point3F > &tangents, const Vector< surfaceMaterial > surfaceTextures, const Vector< Point2F > texOffset, const Vector< Point2F > texScale, const Vector< bool > horzFlip, const Vector< bool > vertFlip);
 
 
 		Vector< Point3F > points;      
 		Vector< Point3F > points;      
 		Vector< Face > faces;
 		Vector< Face > faces;
@@ -215,6 +252,9 @@ protected:
    static S32 QSORT_CALLBACK _comparePlaneDist( const void *a, const void *b );
    static S32 QSORT_CALLBACK _comparePlaneDist( const void *a, const void *b );
 
 
    static bool protectedSetSurface( void *object, const char *index, const char *data );
    static bool protectedSetSurface( void *object, const char *index, const char *data );
+
+   static bool protectedSetSurfaceTexture( void *object, const char *index, const char *data );
+   static bool protectedSetSurfaceUV(void *object, const char *index, const char *data);
   
   
 protected:
 protected:
    
    
@@ -225,11 +265,11 @@ protected:
    BaseMatInstance*  mMaterialInst;
    BaseMatInstance*  mMaterialInst;
 
 
    // The GFX vertex and primitive buffers
    // The GFX vertex and primitive buffers
-   GFXVertexBufferHandle< VertexType > mVertexBuffer;
+   /*GFXVertexBufferHandle< VertexType > mVertexBuffer;
    GFXPrimitiveBufferHandle            mPrimitiveBuffer;
    GFXPrimitiveBufferHandle            mPrimitiveBuffer;
 
 
    U32 mVertCount;
    U32 mVertCount;
-   U32 mPrimCount;
+   U32 mPrimCount;*/
 
 
    Geometry mGeometry;  
    Geometry mGeometry;  
 
 
@@ -239,6 +279,11 @@ protected:
 
 
    Vector< Point3F > mFaceCenters;
    Vector< Point3F > mFaceCenters;
 
 
+   //this is mostly for storage purposes, so we can save the texture mods
+   Vector< surfaceMaterial > mSurfaceTextures;
+   Vector< surfaceUV > mSurfaceUVs;
+   Vector< surfaceBuffers > mSurfaceBuffers;
+
    Convex *mConvexList;
    Convex *mConvexList;
 
 
    PhysicsBody *mPhysicsRep; 
    PhysicsBody *mPhysicsRep; 

+ 576 - 6
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp

@@ -80,7 +80,8 @@ GuiConvexEditorCtrl::GuiConvexEditorCtrl()
    mHasCopied( false ),
    mHasCopied( false ),
    mLastUndo( NULL ),
    mLastUndo( NULL ),
    mUndoManager( NULL ),
    mUndoManager( NULL ),
-   mCtrlDown( false )
+   mCtrlDown( false ),
+   mGridSnap(false)
 {   
 {   
 	mMaterialName = StringTable->insert("Grid512_OrangeLines_Mat");
 	mMaterialName = StringTable->insert("Grid512_OrangeLines_Mat");
 }
 }
@@ -630,10 +631,44 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
          submitUndo( ModifyShape, mConvexSEL );
          submitUndo( ModifyShape, mConvexSEL );
       }      
       }      
 
 
-      if ( mGizmo->getMode() == ScaleMode )
+      if ( mGizmo->getMode() == ScaleMode &&  !(event.modifier & SI_CTRL))
       {
       {
          scaleFace( mConvexSEL, mFaceSEL, mGizmo->getScale() );
          scaleFace( mConvexSEL, mFaceSEL, mGizmo->getScale() );
       }
       }
+
+	  else if ( mGizmo->getMode() == ScaleMode &&  (event.modifier & SI_CTRL) )
+      {
+          Point3F scale = mGizmo->getDeltaScale();
+
+	     F32 scalar = 1;
+		  mConvexSEL->mSurfaceUVs[mFaceSEL].scale += (Point2F(scale.x, scale.y) * scalar);
+
+        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x < 0.01)
+           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x = 0.01;
+
+        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y < 0.01)
+           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y = 0.01;
+
+        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x > 100)
+           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x = 100;
+
+        if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y > 100)
+           mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y = 100;
+
+        Point2F test = mConvexSEL->mSurfaceUVs[mFaceSEL].scale;
+		  mConvexSEL->setMaskBits( ConvexShape::UpdateMask );
+
+		  updateShape( mConvexSEL, mFaceSEL );
+     }
+	  /*else if ( mGizmo->getMode() == MoveMode && event.modifier & SI_CTRL ) {
+		  Point3F scale = mGizmo->getOffset();
+
+          F32 scalar = 0.8;
+		  mConvexSEL->mSurfaceTextures[mFaceSEL].offset += (Point2F(-scale.x, scale.z) * scalar);
+		  mConvexSEL->setMaskBits( ConvexShape::UpdateMask );
+
+		  updateShape( mConvexSEL, mFaceSEL );
+	  }*/
       else
       else
       {
       {
          // Why does this have to be so ugly.
          // Why does this have to be so ugly.
@@ -662,6 +697,20 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
             // Clear out floating point errors.
             // Clear out floating point errors.
             cleanMatrix( surfMat );
             cleanMatrix( surfMat );
 
 
+            if (mGizmo->getSelection() == Gizmo::Axis_Z)
+            {
+               MatrixF curSurfMat = mConvexSEL->mSurfaces[mFaceSEL];
+               EulerF curSufRot = curSurfMat.toEuler();
+
+               EulerF newSufRot = surfMat.toEuler();
+
+               float zRot = mRadToDeg(newSufRot.z - curSufRot.z);
+
+               float curZRot = mConvexSEL->mSurfaceUVs[mFaceSEL].zRot;
+
+               mConvexSEL->mSurfaceUVs[mFaceSEL].zRot += zRot;
+            }
+
             mConvexSEL->mSurfaces[mFaceSEL] = surfMat;
             mConvexSEL->mSurfaces[mFaceSEL] = surfMat;
 
 
             updateShape( mConvexSEL, mFaceSEL );         
             updateShape( mConvexSEL, mFaceSEL );         
@@ -699,7 +748,28 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
 
 
    if ( mGizmo->getMode() == MoveMode )
    if ( mGizmo->getMode() == MoveMode )
    {
    {
-      mConvexSEL->setPosition( mGizmo->getPosition() );
+      //mConvexSEL->setPosition( mGizmo->getPosition() );
+
+      //MatrixF mat = mGizmo->getTransform();
+      Point3F wPos = mGizmo->getPosition();
+      //mat.getColumn(3, &wPos);
+
+      // adjust
+      //wPos += offset;
+
+      if (mGridSnap && mGridPlaneSize != 0.f)
+      {
+         if (mGizmo->getSelection() == Gizmo::Selection::Axis_X || mGizmo->getSelection() == Gizmo::Selection::Plane_XY || mGizmo->getSelection() == Gizmo::Selection::Plane_XZ)
+            wPos.x -= mFmod(wPos.x, mGridPlaneSize);
+
+         if (mGizmo->getSelection() == Gizmo::Selection::Axis_Y || mGizmo->getSelection() == Gizmo::Selection::Plane_XY || mGizmo->getSelection() == Gizmo::Selection::Plane_YZ)
+            wPos.y -= mFmod(wPos.y, mGridPlaneSize);
+
+         if (mGizmo->getSelection() == Gizmo::Selection::Axis_Z || mGizmo->getSelection() == Gizmo::Selection::Plane_XZ || mGizmo->getSelection() == Gizmo::Selection::Plane_YZ)
+            wPos.z -= mFmod(wPos.z, mGridPlaneSize);
+      }
+
+      mConvexSEL->setPosition(wPos);
    }
    }
    else if ( mGizmo->getMode() == RotateMode )
    else if ( mGizmo->getMode() == RotateMode )
    {   
    {   
@@ -845,8 +915,10 @@ void GuiConvexEditorCtrl::updateGizmo()
 
 
    if ( mFaceSEL != -1 && mode == MoveMode )
    if ( mFaceSEL != -1 && mode == MoveMode )
    {
    {
-      if ( mCtrlDown )      
-         flags &= ~( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn );      
+      if ( mCtrlDown )  
+         //hijacking the CTRL modifier for texture offsetting control
+         //flags &= ~( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn ); 
+         flags &= ~GizmoProfile::CanScaleZ;
       else      
       else      
          flags |= ( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn );      
          flags |= ( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn );      
    }
    }
@@ -1201,13 +1273,51 @@ void GuiConvexEditorCtrl::translateFace( ConvexShape *shape, S32 faceId, const P
 
 
    AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." );
    AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." );
 
 
+   Point3F modDisplace = Point3F(displace.x, displace.y, displace.z);
+
+   //snapping
+   if (mGridSnap && mGridPlaneSize != 0)
+   {
+      Point3F faceCenter = Point3F::Zero;
+
+      for (S32 i = 0; i < face.points.size(); i++)
+      {
+         Point3F &pnt = pointList[face.points[i]];
+         faceCenter += pnt;
+      }
+
+      faceCenter /= face.points.size();
+
+      // Transform displacement into object space.    
+      MatrixF objToWorld(shape->getWorldTransform());
+      objToWorld.scale(shape->getScale());
+      objToWorld.inverse();
+
+      objToWorld.mulP(faceCenter);
+
+      modDisplace = faceCenter + displace;
+      Point3F fMod = Point3F::Zero;
+
+      if (!mIsZero(displace.x))
+         fMod.x = mFmod(modDisplace.x - (displace.x > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize);
+
+      if (!mIsZero(displace.y))
+         fMod.y = mFmod(modDisplace.y - (displace.y > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize);
+
+      if (!mIsZero(displace.z))
+         fMod.z = mFmod(modDisplace.z - (displace.z > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize);
+
+      modDisplace -= fMod;
+      modDisplace -= faceCenter;
+   }
+
    // Transform displacement into object space.    
    // Transform displacement into object space.    
    MatrixF worldToObj( shape->getTransform() );
    MatrixF worldToObj( shape->getTransform() );
    worldToObj.scale( shape->getScale() );
    worldToObj.scale( shape->getScale() );
    worldToObj.inverse();
    worldToObj.inverse();
 
 
    Point3F displaceOS;
    Point3F displaceOS;
-   worldToObj.mulV( displace, &displaceOS );
+   worldToObj.mulV(modDisplace, &displaceOS);
 
 
    for ( S32 i = 0; i < face.points.size(); i++ )
    for ( S32 i = 0; i < face.points.size(); i++ )
    {                  
    {                  
@@ -1776,6 +1886,281 @@ bool GuiConvexEditorCtrl::getEdgesTouchingPoint( ConvexShape *shape, S32 faceId,
    return !edgeIdxList.empty();
    return !edgeIdxList.empty();
 }
 }
 
 
+Point2F GuiConvexEditorCtrl::getSelectedFaceUVOffset()
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return Point2F(0, 0);
+
+   return mConvexSEL->mSurfaceUVs[mFaceSEL].offset;
+}
+
+Point2F GuiConvexEditorCtrl::getSelectedFaceUVScale()
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return Point2F(0, 0);
+
+   return mConvexSEL->mSurfaceUVs[mFaceSEL].scale;
+}
+
+const char* GuiConvexEditorCtrl::getSelectedFaceMaterial()
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return "";
+
+   if (mConvexSEL->mSurfaceUVs[mFaceSEL].matID == 0)
+   {
+      return mConvexSEL->mMaterialName;
+   }
+   else
+   {
+      return mConvexSEL->mSurfaceTextures[mConvexSEL->mSurfaceUVs[mFaceSEL].matID - 1].materialName;
+   }
+}
+
+bool GuiConvexEditorCtrl::getSelectedFaceHorzFlip()
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return false;
+
+   return mConvexSEL->mSurfaceUVs[mFaceSEL].horzFlip;
+}
+
+bool GuiConvexEditorCtrl::getSelectedFaceVertFlip()
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return false;
+
+   return mConvexSEL->mSurfaceUVs[mFaceSEL].vertFlip;
+}
+
+float GuiConvexEditorCtrl::getSelectedFaceZRot()
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return false;
+
+   return mConvexSEL->mSurfaceUVs[mFaceSEL].zRot;
+}
+
+void GuiConvexEditorCtrl::setSelectedFaceUVOffset(Point2F offset)
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return;
+
+   mConvexSEL->mSurfaceUVs[mFaceSEL].offset = offset;
+
+   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
+}
+
+void GuiConvexEditorCtrl::setSelectedFaceUVScale(Point2F scale)
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return;
+
+   mConvexSEL->mSurfaceUVs[mFaceSEL].scale = scale;
+
+   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
+}
+
+void GuiConvexEditorCtrl::setSelectedFaceMaterial(const char* materialName)
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return;
+
+   if (mConvexSEL->mSurfaceUVs.size() < mFaceSEL)
+      return;
+
+   //first, see if the mat already exists in our list
+   bool found = false;
+   U32 oldmatID = mConvexSEL->mSurfaceUVs[mFaceSEL].matID;
+
+   if (dStrcmp(materialName, mConvexSEL->getMaterialName().c_str()))
+   {
+      for (U32 i = 0; i < mConvexSEL->mSurfaceTextures.size(); i++)
+      {
+         if (!dStrcmp(mConvexSEL->mSurfaceTextures[i].materialName, materialName))
+         {
+            //found a match
+            mConvexSEL->mSurfaceUVs[mFaceSEL].matID = i + 1;
+            found = true;
+         }
+      }
+
+      if (!found)
+      {
+         //add a new one
+         ConvexShape::surfaceMaterial newMat;
+         newMat.materialName = materialName;
+
+         mConvexSEL->mSurfaceTextures.push_back(newMat);
+
+         mConvexSEL->mSurfaceUVs[mFaceSEL].matID = mConvexSEL->mSurfaceTextures.size();
+      }
+   }
+   else
+   {
+      mConvexSEL->mSurfaceUVs[mFaceSEL].matID = 0;
+   }
+
+   //run through and find out if there are any other faces still using the old mat texture
+   if (oldmatID != 0)
+   {
+      S32 curMatCount = mConvexSEL->mSurfaceTextures.size();
+
+      bool used = false;
+      for (U32 i = 0; i < mConvexSEL->mSurfaceUVs.size(); i++)
+      {
+         if (mConvexSEL->mSurfaceUVs[i].matID == oldmatID)
+         {
+            used = true;
+            break;
+         }
+      }
+
+      if (!used)
+      {
+         //that was the last reference, so let's update the listings on the shape
+         if (mConvexSEL->mSurfaceTextures[oldmatID - 1].materialInst)
+            SAFE_DELETE(mConvexSEL->mSurfaceTextures[oldmatID - 1].materialInst);
+
+         mConvexSEL->mSurfaceTextures.erase(oldmatID-1);
+
+         for (U32 i = 0; i < mConvexSEL->mSurfaceUVs.size(); i++)
+         {
+            if (mConvexSEL->mSurfaceUVs[i].matID > oldmatID)
+               mConvexSEL->mSurfaceUVs[i].matID--;
+         }
+      }
+   }
+
+   //mConvexSEL->mSurfaceUVs[mFaceSEL].materialName = materialName;
+
+   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
+}
+
+void GuiConvexEditorCtrl::setSelectedFaceHorzFlip(bool flipped)
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return;
+
+   mConvexSEL->mSurfaceUVs[mFaceSEL].horzFlip = flipped;
+
+   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
+}
+
+void GuiConvexEditorCtrl::setSelectedFaceVertFlip(bool flipped)
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return;
+
+   mConvexSEL->mSurfaceUVs[mFaceSEL].vertFlip = flipped;
+
+   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
+}
+
+void GuiConvexEditorCtrl::setSelectedFaceZRot(float degrees)
+{
+   if (mFaceSEL == -1 || mConvexSEL == NULL)
+      return;
+
+   F32 oldRot = mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot);
+   mConvexSEL->mSurfaceUVs[mFaceSEL].zRot = degrees;
+
+   EulerF curEul = mConvexSEL->mSurfaces[mFaceSEL].toEuler();
+
+   MatrixF oldRotMat = MatrixF(EulerF(0, 0, -oldRot));
+
+   mConvexSEL->mSurfaces[mFaceSEL].mul(oldRotMat);
+
+   MatrixF newRotMat = MatrixF(EulerF(0, 0, mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)));
+
+   mConvexSEL->mSurfaces[mFaceSEL].mul(newRotMat);
+
+   //Point3F curPos = mConvexSEL->mSurfaces[mFaceSEL].getPosition();
+
+   //we roll back our existing modified rotation before setting the new one, just to keep it consistent
+   //const MatrixF &gMat = MatrixF(EulerF(curEul.x, curEul.y, curEul.z - oldRot + mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)), curPos);
+
+   //mConvexSEL->mSurfaces[mFaceSEL] = MatrixF(EulerF(curEul.x, curEul.y, mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)), curPos);
+
+   /*MatrixF surfMat;
+   surfMat.mul(mConvexSEL->mWorldToObj, gMat);
+
+   MatrixF worldToObj(mConvexSEL->getTransform());
+   worldToObj.scale(mConvexSEL->getScale());
+   worldToObj.inverse();
+
+   Point3F newPos;
+   newPos = gMat.getPosition();
+
+   worldToObj.mulP(newPos);
+   surfMat.setPosition(newPos);
+
+   // Clear out floating point errors.
+   cleanMatrix(surfMat);
+
+   mConvexSEL->mSurfaces[mFaceSEL] = surfMat;*/
+
+   updateShape(mConvexSEL, mFaceSEL);
+
+   mConvexSEL->setMaskBits(ConvexShape::UpdateMask);
+
+   /*
+   const MatrixF &gMat = mGizmo->getTransform();
+   MatrixF surfMat;
+   surfMat.mul( mConvexSEL->mWorldToObj, gMat );
+
+   MatrixF worldToObj ( mConvexSEL->getTransform() );
+   worldToObj.scale( mConvexSEL->getScale() );
+   worldToObj.inverse();
+
+   Point3F newPos;
+   newPos = gMat.getPosition();
+
+   worldToObj.mulP( newPos );
+   surfMat.setPosition( newPos );
+
+   // Clear out floating point errors.
+   cleanMatrix( surfMat );
+
+   if (mGizmo->getSelection() == Gizmo::Axis_Z)
+   {
+   MatrixF curSurfMat = mConvexSEL->mSurfaces[mFaceSEL];
+   EulerF curSufRot = curSurfMat.toEuler();
+
+   EulerF newSufRot = surfMat.toEuler();
+
+   float zRot = mRadToDeg(newSufRot.z - curSufRot.z);
+
+   float curZRot = mConvexSEL->mSurfaceTextures[mFaceSEL].zRot;
+
+   mConvexSEL->mSurfaceTextures[mFaceSEL].zRot += zRot;
+   }
+
+   mConvexSEL->mSurfaces[mFaceSEL] = surfMat;
+
+   updateShape( mConvexSEL, mFaceSEL );
+   */
+}
+
+void GuiConvexEditorCtrl::toggleGridSnapping()
+{
+   if (mGridSnap)
+      mGridSnap = false;
+   else
+      mGridSnap = true;
+}
+
+void GuiConvexEditorCtrl::updateShape()
+{
+   if (mConvexSEL)
+      mConvexSEL->inspectPostApply();
+}
+
+void GuiConvexEditorCtrl::setGridSnapSize(float gridSize)
+{
+   mGridPlaneSize = gridSize;
+}
+
 void GuiConvexEditorUndoAction::undo()
 void GuiConvexEditorUndoAction::undo()
 {
 {
    ConvexShape *object = NULL;
    ConvexShape *object = NULL;
@@ -2514,3 +2899,188 @@ DefineEngineMethod( GuiConvexEditorCtrl, splitSelectedFace, void, (), , "" )
 {
 {
    object->splitSelectedFace();
    object->splitSelectedFace();
 }
 }
+
+DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceUVOffset, Point2F, (), ,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   //return Point2F(0, 0);
+   return object->getSelectedFaceUVOffset();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceUVScale, Point2F, (), ,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   //return Point2F(0, 0);
+   return object->getSelectedFaceUVScale();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceUVOffset, void, ( Point2F offset ), ( Point2F(0,0) ),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   //return Point2F(0, 0);
+   return object->setSelectedFaceUVOffset(offset);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceUVScale, void, (Point2F scale), (Point2F(0, 0)),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   //return Point2F(0, 0);
+   return object->setSelectedFaceUVScale(scale);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceMaterial, void, (const char* materialName), (""),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   //return Point2F(0, 0);
+   if (!dStrcmp(materialName, ""))
+      return;
+
+   object->setSelectedFaceMaterial(materialName);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceMaterial, const char*, (), ,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   return object->getSelectedFaceMaterial();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceHorzFlip, void, (bool flipped), (false),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   object->setSelectedFaceHorzFlip(flipped);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceVertFlip, void, (bool flipped), (false),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   object->setSelectedFaceVertFlip(flipped);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceHorzFlip, bool, (), ,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   return object->getSelectedFaceHorzFlip();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceVertFlip, bool, (), ,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   return object->getSelectedFaceVertFlip();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceZRot, void, (float degrees), (0.0),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   object->setSelectedFaceZRot(degrees);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceZRot, float, (), ,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   return object->getSelectedFaceZRot();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, toggleGridSnapping, void, (),,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   object->toggleGridSnapping();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, setGridSnapSize, void, (float gridSize), (1.0),
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   object->setGridSnapSize(gridSize);
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, getGridSnapSize, float, (),,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   return object->getGridSnapSize();
+}
+
+DefineEngineMethod(GuiConvexEditorCtrl, updateShape, void, (),,
+   "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
+
+   "@param objB  Object to mount onto us\n"
+   "@param slot  Mount slot ID\n"
+   "@param txfm (optional) mount offset transform\n"
+   "@return true if successful, false if failed (objB is not valid)")
+{
+   //return Point2F(0, 0);
+   return object->updateShape();
+}

+ 35 - 0
Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h

@@ -116,6 +116,25 @@ public:
 
 
    SceneObject* createPolyhedralObject(const char* className, SceneObject* geometryProvider);
    SceneObject* createPolyhedralObject(const char* className, SceneObject* geometryProvider);
    ConvexShape* createConvexShapeFrom(SceneObject* polyObject);
    ConvexShape* createConvexShapeFrom(SceneObject* polyObject);
+   Point2F getSelectedFaceUVOffset();
+   Point2F getSelectedFaceUVScale();
+   const char* getSelectedFaceMaterial();
+   bool getSelectedFaceHorzFlip();
+   bool getSelectedFaceVertFlip();
+   float getSelectedFaceZRot();
+
+   void setSelectedFaceUVOffset(Point2F offset);
+   void setSelectedFaceUVScale(Point2F offset);
+   void setSelectedFaceMaterial(const char* materialName);
+   void setSelectedFaceHorzFlip(bool flipped);
+   void setSelectedFaceVertFlip(bool flipped);
+   void setSelectedFaceZRot(float degrees);
+   void toggleGridSnapping();
+   void setGridSnapSize(float gridSize);
+
+   void updateShape();
+
+   float getGridSnapSize() { return mGridPlaneSize; }
    /// Interface with Tools.
    /// Interface with Tools.
    /// @{ 
    /// @{ 
 
 
@@ -158,6 +177,20 @@ protected:
 
 
    U32 mSavedGizmoFlags;
    U32 mSavedGizmoFlags;
 
 
+   Vector<SimObjectPtr<ConvexShape>> mSelectedBrushes;
+   struct selectedFace
+   {
+      SimObjectPtr<ConvexShape> mOwnerBrush;
+      U32 faceId;
+   };
+   Vector<selectedFace> mSelectedFaces;
+
+   struct selectedVert
+   {
+      SimObjectPtr<ConvexShape> mOwnerBrush;
+      U32 vertId;
+   };
+   Vector<selectedVert>  mSelectedVerts;
    /// The selected ConvexShape.
    /// The selected ConvexShape.
    SimObjectPtr<ConvexShape> mConvexSEL;      
    SimObjectPtr<ConvexShape> mConvexSEL;      
 
 
@@ -183,6 +216,8 @@ protected:
    bool mHasCopied;
    bool mHasCopied;
    RayInfo mLastRayInfo;
    RayInfo mLastRayInfo;
 
 
+   bool mGridSnap;
+
    Gui3DMouseEvent mMouseDownEvent;
    Gui3DMouseEvent mMouseDownEvent;
 
 
    Point3F mGizmoMatOffset;
    Point3F mGizmoMatOffset;

+ 0 - 50
Engine/source/materials/processedShaderMaterial.cpp

@@ -1211,31 +1211,6 @@ void ProcessedShaderMaterial::_setShaderConstants(SceneRenderState * state, cons
       shaderConsts->set( handles->mAccuCoverageSC, mMaterial->mAccuCoverage[stageNum] );
       shaderConsts->set( handles->mAccuCoverageSC, mMaterial->mAccuCoverage[stageNum] );
    if( handles->mAccuSpecularSC->isValid() )
    if( handles->mAccuSpecularSC->isValid() )
       shaderConsts->set( handles->mAccuSpecularSC, mMaterial->mAccuSpecular[stageNum] );
       shaderConsts->set( handles->mAccuSpecularSC, mMaterial->mAccuSpecular[stageNum] );
-
-	/*for (U32 i = 0; i < sgData.customShaderData.size(); i++)
-	{
-		//roll through and try setting our data!
-		for (U32 h = 0; h < handles->mCustomHandles.size(); ++h)
-		{
-			StringTableEntry handleName = sgData.customShaderData[i]->getHandleName();
-			StringTableEntry rpdHandleName = handles->mCustomHandles[h].handleName;
-			if (handles->mCustomHandles[h].handleName == sgData.customShaderData[i]->getHandleName())
-			{
-				if (handles->mCustomHandles[h].handle->isValid())
-				{
-					if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float)
-						shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat());
-					else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float2)
-						shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat2());
-					else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float3)
-						shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat3());
-					else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float4)
-						shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat4());
-					break;
-}
-			}
-		}
-	}*/
 }
 }
 
 
 bool ProcessedShaderMaterial::_hasCubemap(U32 pass)
 bool ProcessedShaderMaterial::_hasCubemap(U32 pass)
@@ -1383,31 +1358,6 @@ void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const Scene
    for (U32 i = 0; i < rpd->featureShaderHandles.size(); i++)
    for (U32 i = 0; i < rpd->featureShaderHandles.size(); i++)
       rpd->featureShaderHandles[i]->setConsts(state, sgData, shaderConsts);
       rpd->featureShaderHandles[i]->setConsts(state, sgData, shaderConsts);
 
 
-   /*for (U32 i = 0; i < sgData.customShaderData.size(); i++)
-   {
-	   //roll through and try setting our data!
-	   for (U32 h = 0; h < handles->mCustomHandles.size(); ++h)
-	   {
-		   StringTableEntry handleName = sgData.customShaderData[i]->getHandleName();
-		   StringTableEntry rpdHandleName = handles->mCustomHandles[h].handleName;
-		   if (handles->mCustomHandles[h].handleName == sgData.customShaderData[i]->getHandleName())
-		   {
-			   if (handles->mCustomHandles[h].handle->isValid())
-			   {
-				   if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float)
-					   shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat());
-				   else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float2)
-					   shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat2());
-				   else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float3)
-					   shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat3());
-				   else if (sgData.customShaderData[i]->getType() == CustomShaderBindingData::Float4)
-					   shaderConsts->setSafe(handles->mCustomHandles[h].handle, sgData.customShaderData[i]->getFloat4());
-				   break;
-			   }
-		   }
-	   }
-   }*/
-
    LIGHTMGR->setLightInfo(this, mMaterial, sgData, state, pass, shaderConsts);
    LIGHTMGR->setLightInfo(this, mMaterial, sgData, state, pass, shaderConsts);
 
 
    PROBEMGR->setProbeInfo(this, mMaterial, sgData, state, pass, shaderConsts);
    PROBEMGR->setProbeInfo(this, mMaterial, sgData, state, pass, shaderConsts);

BIN
Templates/BaseGame/game/core/gui/scripts/fonts/Arial 14 (ansi).uft


BIN
Templates/BaseGame/game/core/gui/scripts/fonts/ArialItalic 14 (ansi).uft


BIN
Templates/BaseGame/game/core/gui/scripts/fonts/Lucida Console 12 (ansi).uft


+ 1 - 1
Templates/BaseGame/game/tools/MainEditor/MainEditor.cs

@@ -99,7 +99,7 @@ function togglePanelLayout()
       }
       }
       
       
       EditorTree.open($scenesRootGroup,true);
       EditorTree.open($scenesRootGroup,true);
-      
+
       Editor_PropertiesPanel.add(EWInspectorWindow);
       Editor_PropertiesPanel.add(EWInspectorWindow);
       EWInspectorWindow.resize(0,0, Editor_PropertiesPanel.extent.x, Editor_PropertiesPanel.extent.y);
       EWInspectorWindow.resize(0,0, Editor_PropertiesPanel.extent.x, Editor_PropertiesPanel.extent.y);
       EWInspectorWindow.horizSizing = "width";
       EWInspectorWindow.horizSizing = "width";

+ 155 - 1
Templates/BaseGame/game/tools/convexEditor/convexEditorGui.cs

@@ -22,6 +22,19 @@
    
    
 function ConvexEditorGui::onWake( %this )
 function ConvexEditorGui::onWake( %this )
 {   
 {   
+	convexEditorToolbar-->gridSnapSizeEdit.setText(%this.getGridSnapSize());
+	
+	if(ConvexEditorOptionssWindow-->matPreviewBtn.bitmap $= "")
+	{
+		//no active material, so set one	
+		ConvexEditorOptionssWindow-->matPreviewBtn.setText("");
+		
+		%mat = EditorSettings.Value("ConvexEditor/MaterialName");
+		
+		ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%mat.diffuseMap[0]);
+		
+		ConvexEditorOptionssWindow.activeMaterial = %mat;
+	}
 }
 }
 
 
 function ConvexEditorGui::onSleep( %this )
 function ConvexEditorGui::onSleep( %this )
@@ -45,18 +58,159 @@ function ConvexEditorGui::onSelectionChanged( %this, %shape, %face )
    ConvexEditorDeleteFaceBtn.setActive( false );
    ConvexEditorDeleteFaceBtn.setActive( false );
    ConvexEditorDeleteFaceBtn.ToolTip = "Delete selection [Disabled] (Delete)"; 
    ConvexEditorDeleteFaceBtn.ToolTip = "Delete selection [Disabled] (Delete)"; 
    
    
-   if ( !isObject( %shape ) )      
+   if ( !isObject( %shape ) )  
+   {
+      ConvexEditorOptionssWindow-->defMatPreviewBtn.setText("No Brush Selected");
+      ConvexEditorOptionssWindow.activeShape = "";
       return;   
       return;   
+   }
       
       
    ConvexEditorDeleteFaceBtn.setActive( true );
    ConvexEditorDeleteFaceBtn.setActive( true );
+
+   ConvexEditorOptionssWindow-->defMatPreviewBtn.setText("");
+   ConvexEditorOptionssWindow-->defMatPreviewBtn.setBitmap(%shape.material.diffuseMap[0]);
+
+   ConvexEditorOptionssWindow.activeShape = %shape;
       
       
    if ( %face == -1 )     
    if ( %face == -1 )     
+   {
       ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected ConvexShape (Delete)";
       ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected ConvexShape (Delete)";
+	
+	  ConvexEditorOptionssWindow-->UOffset.setText("");
+	  ConvexEditorOptionssWindow-->VOffset.setText("");
+	
+	  ConvexEditorOptionssWindow-->UScale.setText("");
+	  ConvexEditorOptionssWindow-->VScale.setText("");
+	
+	  ConvexEditorOptionssWindow-->ZRotation.setText("");
+   }
    else
    else
    {
    {
       ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected Face (Delete)";
       ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected Face (Delete)";
       
       
       ConvexEditorSplitFaceBtn.ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control";
       ConvexEditorSplitFaceBtn.ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control";
       ConvexEditorSplitFaceBtn.setActive( true );
       ConvexEditorSplitFaceBtn.setActive( true );
+	
+	  %UVOffset = %this.getSelectedFaceUVOffset();
+	
+	  ConvexEditorOptionssWindow-->UOffset.setText(%UVOffset.x);
+	  ConvexEditorOptionssWindow-->VOffset.setText(%UVOffset.y);
+	
+	  %UVScale = %this.getSelectedFaceUVScale();
+	
+     ConvexEditorOptionssWindow-->UScale.setText(%UVScale.x);
+     ConvexEditorOptionssWindow-->VScale.setText(%UVScale.y);
+	
+	  ConvexEditorOptionssWindow-->ZRotation.setText(ConvexEditorGui.getSelectedFaceZRot());
    }
    }
+}
+
+function ConvexEditorUVFld::onReturn(%this)
+{
+   EWorldEditor.isDirty = true;
+
+   %offset = "0 0";
+   %offset.x = ConvexEditorOptionssWindow-->UOffset.getText();
+   %offset.y = ConvexEditorOptionssWindow-->VOffset.getText();
+
+   %scale = "0 0";
+   %scale.x = ConvexEditorOptionssWindow-->UScale.getText();
+   %scale.y = ConvexEditorOptionssWindow-->VScale.getText();
+
+   %rot = ConvexEditorOptionssWindow-->ZRotation.getText();
+
+   ConvexEditorGui.setSelectedFaceUVOffset(%offset);
+   ConvexEditorGui.setSelectedFaceUVScale(%scale);
+   ConvexEditorGui.setSelectedFaceZRot(%rot);
+}
+
+function ConvexEditorUVHorzFlipBtn::onClick(%this)
+{
+	EWorldEditor.isDirty = true;
+   %current = ConvexEditorGui.getSelectedFaceHorzFlip();
+   ConvexEditorGui.setSelectedFaceHorzFlip(!%current);
+}
+
+function ConvexEditorUVVertFlipBtn::onClick(%this)
+{
+	EWorldEditor.isDirty = true;
+   %current = ConvexEditorGui.getSelectedFaceVertFlip();
+   ConvexEditorGui.setSelectedFaceVertFlip(!%current);
+}
+
+function ConvexEditorMaterialBtn::onClick(%this)
+{
+	%this.getMaterialName();
+}
+
+function ConvexEditorMaterialBtn::getMaterialName(%this)
+{
+   materialSelector.showDialog(%this @ ".gotMaterialName", "name");
+}
+
+function ConvexEditorMaterialBtn::gotMaterialName(%this, %name)
+{
+   //eval(%this.object @ "." @ %this.targetField @ " = " @ %name @ ";");
+   //%this.object.changeMaterial(getTrailingNumber(%this.targetField), %name);
+   //%this.object.inspectorApply();
+   %diffusemap = %name.diffuseMap[0];
+
+   ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%diffusemap);
+
+   ConvexEditorOptionssWindow.activeMaterial = %name;
+}
+
+function ConvexEditorMaterialApplyBtn::onClick(%this)
+{
+	EWorldEditor.isDirty = true;
+    ConvexEditorGui.setSelectedFaceMaterial(ConvexEditorOptionssWindow.activeMaterial);
+    ConvexEditorGui.updateShape();
+}
+
+function ConvexEditorMaterialLiftBtn::onClick(%this)
+{
+   %mat = ConvexEditorGui.getSelectedFaceMaterial();
+   ConvexEditorOptionssWindow.activeMaterial = %mat;
+   ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%mat.diffuseMap[0]);
+}
+
+function ConvexEditorMaterialResetBtn::onClick(%this)
+{
+	EWorldEditor.isDirty = true;
+    ConvexEditorGui.setSelectedFaceMaterial(ConvexEditorOptionssWindow.activeShape.material);
+    ConvexEditorGui.updateShape();
+}
+
+function ConvexEditorGui::toggleGridSnap(%this)
+{
+	%this.toggleGridSnapping();
+}
+
+function ConvexEditorGridSnapSizeFld::onReturn(%this)
+{
+   ConvexEditorGui.setGridSnapSize(%this.getText());
+}
+
+function ConvexEditorDefaultMaterialBtn::onClick(%this)
+{
+	%this.getMaterialName();
+}
+
+function ConvexEditorDefaultMaterialBtn::getMaterialName(%this)
+{
+   materialSelector.showDialog(%this @ ".gotMaterialName", "name");
+}
+
+function ConvexEditorDefaultMaterialBtn::gotMaterialName(%this, %name)
+{
+   //eval(%this.object @ "." @ %this.targetField @ " = " @ %name @ ";");
+   //%this.object.changeMaterial(getTrailingNumber(%this.targetField), %name);
+   //%this.object.inspectorApply();
+   %diffusemap = %name.diffuseMap[0];
+
+   ConvexEditorOptionssWindow-->defMatPreviewBtn.setBitmap(%diffusemap);
+
+   ConvexEditorOptionssWindow.activeShape.material = %name;
+
+   ConvexEditorGui.updateShape();
 }
 }

+ 140 - 58
Templates/BaseGame/game/tools/convexEditor/convexEditorToolbar.ed.gui

@@ -21,6 +21,95 @@
    EdgeSnap = "0";
    EdgeSnap = "0";
    text ="";
    text ="";
    
    
+   new GuiTextCtrl() {
+      profile = "ToolsGuiTextProfile";
+      horizSizing = "right";
+      vertSizing = "bottom";
+      position = "15 7";
+      extent = "86 16";
+      minExtent = "8 8";
+      visible = "1";
+      text = "Sketch Tool";
+      maxLength = "255";
+      helpTag = "0";
+   };
+   new GuiBitmapCtrl() {
+      Profile = "ToolsGuiDefaultProfile";
+      position = "94 3";
+      Extent = "2 26";
+      MinExtent = "1 1";
+      bitmap = "tools/gui/images/separator-h.png";
+   };
+   new GuiBitmapButtonCtrl(ConvexEditorCreateBoxBtn) {
+      canSaveDynamicFields = "0";
+      isContainer = "0";
+      Profile = "ToolsGuiButtonProfile";
+      HorizSizing = "right";
+      VertSizing = "bottom";
+      Position = "100 3";
+      Extent = "29 27";
+      MinExtent = "8 8";
+      canSave = "1";
+      Visible = "1";
+      Command = "ConvexEditorGui.createConvexBox();";
+      tooltipprofile = "ToolsGuiToolTipProfile";
+      ToolTip = "Create ConvexShape Box" NL "Use Alt + Click-Drag instead of this for more control of starting placement.";
+      hovertime = "1000";
+      bitmap = "tools/convexEditor/images/convex-editor-btn";
+      text = "";
+      groupNum = "-1";
+      buttonType = "pushButton";
+      useMouseEvents = "0";
+   }; 
+   new GuiBitmapButtonCtrl(ConvexEditorSplitFaceBtn) {
+      canSaveDynamicFields = "0";
+      isContainer = "0";
+      Profile = "ToolsGuiButtonProfile";
+      HorizSizing = "right";
+      VertSizing = "bottom";
+      Position = "134 3";
+      Extent = "29 27";
+      MinExtent = "8 8";
+      canSave = "1";
+      Visible = "1";
+      Command = "ConvexEditorGui.splitSelectedFace();";
+      tooltipprofile = "ToolsGuiToolTipProfile";
+      ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control.";
+      hovertime = "1000";
+      bitmap = "tools/convexEditor/images/split-face-btn";
+      text = "";
+      groupNum = "-1";
+      buttonType = "PushButton";
+      useMouseEvents = "0";
+   }; 
+   new GuiBitmapButtonCtrl(ConvexEditorDeleteFaceBtn) {
+      canSaveDynamicFields = "0";
+      isContainer = "0";
+      Profile = "ToolsGuiButtonProfile";
+      HorizSizing = "right";
+      VertSizing = "bottom";
+      Position = "166 3";
+      Extent = "29 27";
+      MinExtent = "8 8";
+      canSave = "1";
+      Visible = "1";
+      Command = "ConvexEditorGui.handleDelete();";
+      tooltipprofile = "ToolsGuiToolTipProfile";
+      ToolTip = "Delete selected face" NL "(Delete)";
+      hovertime = "1000";
+      bitmap = "tools/gui/images/menubar/delete-btn";
+      text = "";
+      groupNum = "-1";
+      buttonType = "PushButton";
+      useMouseEvents = "0";
+   }; 
+   new GuiBitmapCtrl() {
+      Profile = "ToolsGuiDefaultProfile";
+      position = "190 3";
+      Extent = "2 26";
+      MinExtent = "1 1";
+      bitmap = "tools/gui/images/separator-h.png";
+   };
    new GuiContainer() {
    new GuiContainer() {
       canSaveDynamicFields = "0";
       canSaveDynamicFields = "0";
       Enabled = "1";
       Enabled = "1";
@@ -28,94 +117,87 @@
       Profile = "menubarProfile";
       Profile = "menubarProfile";
       HorizSizing = "width";
       HorizSizing = "width";
       VertSizing = "bottom";
       VertSizing = "bottom";
-      Position = "0 0";
-      Extent = "800 32";
+      Position = "195 0";
+      Extent = "190 32";
       MinExtent = "8 8";
       MinExtent = "8 8";
       canSave = "1";
       canSave = "1";
       Visible = "1";
       Visible = "1";
       hovertime = "1000";
       hovertime = "1000";
-
-      new GuiTextCtrl() {
-         profile = "ToolsGuiTextProfile";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         position = "15 7";
-         extent = "86 16";
-         minExtent = "8 8";
-         visible = "1";
-         text = "Sketch Tool";
-         maxLength = "255";
-         helpTag = "0";
-      };
-      new GuiBitmapCtrl() {
-         Profile = "ToolsGuiDefaultProfile";
-         position = "94 3";
-         Extent = "2 26";
-         MinExtent = "1 1";
-         bitmap = "tools/gui/images/separator-h.png";
-      };
-      new GuiBitmapButtonCtrl(ConvexEditorCreateBoxBtn) {
+   
+      new GuiBitmapButtonCtrl() {
          canSaveDynamicFields = "0";
          canSaveDynamicFields = "0";
+         internalName = "objectGridSnapBtn";
+         Enabled = "1";
          isContainer = "0";
          isContainer = "0";
          Profile = "ToolsGuiButtonProfile";
          Profile = "ToolsGuiButtonProfile";
          HorizSizing = "right";
          HorizSizing = "right";
          VertSizing = "bottom";
          VertSizing = "bottom";
-         Position = "100 3";
+         Position = "5 3";
          Extent = "29 27";
          Extent = "29 27";
          MinExtent = "8 8";
          MinExtent = "8 8";
          canSave = "1";
          canSave = "1";
          Visible = "1";
          Visible = "1";
-         Command = "ConvexEditorGui.createConvexBox();";
+         Command = "ConvexEditorGui.toggleGridSnap();";
          tooltipprofile = "ToolsGuiToolTipProfile";
          tooltipprofile = "ToolsGuiToolTipProfile";
-         ToolTip = "Create ConvexShape Box" NL "Use Alt + Click-Drag instead of this for more control of starting placement.";
+         ToolTip = "Toggles grid snapping (G)";
          hovertime = "1000";
          hovertime = "1000";
-         bitmap = "tools/convexEditor/images/convex-editor-btn";
-         text = "";
          groupNum = "-1";
          groupNum = "-1";
-         buttonType = "pushButton";
+         buttonType = "toggleButton";
          useMouseEvents = "0";
          useMouseEvents = "0";
-      }; 
-      new GuiBitmapButtonCtrl(ConvexEditorSplitFaceBtn) {
+         groupNum = "-1";
+         bitmap = "tools/gui/images/menubar/snap-grid";
+         textMargin = "4";
+      };
+      new GuiTextCtrl() {
          canSaveDynamicFields = "0";
          canSaveDynamicFields = "0";
+         Enabled = "1";
          isContainer = "0";
          isContainer = "0";
-         Profile = "ToolsGuiButtonProfile";
+         Profile = "ToolsGuiTextProfile";
          HorizSizing = "right";
          HorizSizing = "right";
          VertSizing = "bottom";
          VertSizing = "bottom";
-         Position = "134 3";
-         Extent = "29 27";
-         MinExtent = "8 8";
+         position = "39 10";
+         Extent = "108 10";
+         MinExtent = "8 2";
          canSave = "1";
          canSave = "1";
          Visible = "1";
          Visible = "1";
-         Command = "ConvexEditorGui.splitSelectedFace();";
-         tooltipprofile = "ToolsGuiToolTipProfile";
-         ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control.";
          hovertime = "1000";
          hovertime = "1000";
-         bitmap = "tools/convexEditor/images/split-face-btn";
-         text = "";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-      }; 
-      new GuiBitmapButtonCtrl(ConvexEditorDeleteFaceBtn) {
+         Margin = "0 0 0 0";
+         Padding = "0 0 0 0";
+         AnchorTop = "1";
+         AnchorBottom = "0";
+         AnchorLeft = "1";
+         AnchorRight = "0";
+         text = "Grid snap size(m)";
+         maxLength = "1024";
+      };
+      new GuiTextEditCtrl() {
          canSaveDynamicFields = "0";
          canSaveDynamicFields = "0";
+         internalName = "gridSnapSizeEdit";
          isContainer = "0";
          isContainer = "0";
-         Profile = "ToolsGuiButtonProfile";
+         profile="ToolsGuiNumericDropSliderTextProfile";
          HorizSizing = "right";
          HorizSizing = "right";
          VertSizing = "bottom";
          VertSizing = "bottom";
-         Position = "166 3";
-         Extent = "29 27";
-         MinExtent = "8 8";
+         position = "130 6";
+         Extent = "42 16";
+         MinExtent = "8 16";
          canSave = "1";
          canSave = "1";
          Visible = "1";
          Visible = "1";
-         Command = "ConvexEditorGui.handleDelete();";
-         tooltipprofile = "ToolsGuiToolTipProfile";
-         ToolTip = "Delete selected face" NL "(Delete)";
+         class = "ConvexEditorGridSnapSizeFld";
          hovertime = "1000";
          hovertime = "1000";
-         bitmap = "tools/gui/images/menubar/delete-btn";
-         text = "";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-      }; 
+         text = "1";
+         maxLength = "4";
+         historySize = "0";
+         password = "0";
+         tabComplete = "0";
+         sinkAllKeyEvents = "0";
+      };
    };
    };
+   new GuiBitmapCtrl() {
+      Profile = "ToolsGuiDefaultProfile";
+      position = "380 3";
+      Extent = "2 26";
+      MinExtent = "1 1";
+      bitmap = "tools/gui/images/separator-h.png";
+   };	  
 };
 };
+//--- OBJECT WRITE END ---

+ 7 - 1
Templates/BaseGame/game/tools/convexEditor/main.cs

@@ -28,16 +28,20 @@ function initializeConvexEditor()
    exec( "./convexEditorGui.gui" );
    exec( "./convexEditorGui.gui" );
    exec( "./convexEditorToolbar.ed.gui" );
    exec( "./convexEditorToolbar.ed.gui" );
    exec( "./convexEditorGui.cs" );
    exec( "./convexEditorGui.cs" );
-   
+   exec( "./convexEditorSidebarGui.gui" );
+   exec( "./materials.cs" );
+
    ConvexEditorGui.setVisible( false );  
    ConvexEditorGui.setVisible( false );  
    ConvexEditorOptionsWindow.setVisible( false );  
    ConvexEditorOptionsWindow.setVisible( false );  
    ConvexEditorTreeWindow.setVisible( false ); 
    ConvexEditorTreeWindow.setVisible( false ); 
    ConvexEditorToolbar.setVisible( false );
    ConvexEditorToolbar.setVisible( false );
+   ConvexEditorOptionssWindow.setVisible( false );
    
    
    EditorGui.add( ConvexEditorGui );
    EditorGui.add( ConvexEditorGui );
    EditorGui.add( ConvexEditorOptionsWindow );
    EditorGui.add( ConvexEditorOptionsWindow );
    EditorGui.add( ConvexEditorTreeWindow );
    EditorGui.add( ConvexEditorTreeWindow );
    EditorGui.add( ConvexEditorToolbar );
    EditorGui.add( ConvexEditorToolbar );
+   EditorGui.add( ConvexEditorOptionssWindow );
       
       
    new ScriptObject( ConvexEditorPlugin )
    new ScriptObject( ConvexEditorPlugin )
    {
    {
@@ -98,6 +102,7 @@ function ConvexEditorPlugin::onActivated( %this )
    EditorGui.bringToFront( ConvexEditorGui );
    EditorGui.bringToFront( ConvexEditorGui );
    ConvexEditorGui.setVisible( true );
    ConvexEditorGui.setVisible( true );
    ConvexEditorToolbar.setVisible( true );
    ConvexEditorToolbar.setVisible( true );
+   ConvexEditorOptionssWindow.setVisible( true );
    ConvexEditorGui.makeFirstResponder( true ); 
    ConvexEditorGui.makeFirstResponder( true ); 
    %this.map.push();   
    %this.map.push();   
    
    
@@ -132,6 +137,7 @@ function ConvexEditorPlugin::onDeactivated( %this )
    ConvexEditorGui.setVisible( false );
    ConvexEditorGui.setVisible( false );
    ConvexEditorOptionsWindow.setVisible( false );
    ConvexEditorOptionsWindow.setVisible( false );
    ConvexEditorTreeWindow.setVisible( false );
    ConvexEditorTreeWindow.setVisible( false );
+   ConvexEditorOptionssWindow.setVisible( false );
    ConvexEditorToolbar.setVisible( false );
    ConvexEditorToolbar.setVisible( false );
    %this.map.pop();
    %this.map.pop();
    
    

+ 0 - 1
Templates/BaseGame/game/tools/main.cs

@@ -153,7 +153,6 @@ package Tools
       popInstantGroup();
       popInstantGroup();
       $instantGroup = MissionCleanup;
       $instantGroup = MissionCleanup;
       pushInstantGroup();
       pushInstantGroup();
-      
    }
    }
    
    
    function startToolTime(%tool)
    function startToolTime(%tool)

+ 78 - 41
Templates/BaseGame/game/tools/settings.xml

@@ -1,65 +1,45 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <EditorSettings>
 <EditorSettings>
     <Group name="AxisGizmo">
     <Group name="AxisGizmo">
+        <Setting name="renderWhenUsed">0</Setting>
+        <Setting name="renderInfoText">1</Setting>
         <Setting name="axisGizmoMaxScreenLen">100</Setting>
         <Setting name="axisGizmoMaxScreenLen">100</Setting>
-        <Setting name="mouseScaleScalar">0.8</Setting>
         <Setting name="rotationSnap">15</Setting>
         <Setting name="rotationSnap">15</Setting>
-        <Setting name="renderWhenUsed">0</Setting>
         <Setting name="snapRotations">0</Setting>
         <Setting name="snapRotations">0</Setting>
-        <Setting name="renderInfoText">1</Setting>
         <Setting name="mouseRotateScalar">0.8</Setting>
         <Setting name="mouseRotateScalar">0.8</Setting>
+        <Setting name="mouseScaleScalar">0.8</Setting>
         <Group name="Grid">
         <Group name="Grid">
-            <Setting name="planeDim">500</Setting>
-            <Setting name="gridColor">255 255 255 20</Setting>
-            <Setting name="snapToGrid">0</Setting>
+            <Setting name="renderPlaneHashes">0</Setting>
             <Setting name="gridSize">10 10 10</Setting>
             <Setting name="gridSize">10 10 10</Setting>
             <Setting name="renderPlane">0</Setting>
             <Setting name="renderPlane">0</Setting>
-            <Setting name="renderPlaneHashes">0</Setting>
+            <Setting name="snapToGrid">0</Setting>
+            <Setting name="gridColor">255 255 255 20</Setting>
+            <Setting name="planeDim">500</Setting>
         </Group>
         </Group>
     </Group>
     </Group>
     <Group name="WorldEditor">
     <Group name="WorldEditor">
+        <Setting name="forceLoadDAE">0</Setting>
         <Setting name="displayType">6</Setting>
         <Setting name="displayType">6</Setting>
-        <Setting name="dropType">screenCenter</Setting>
         <Setting name="orthoFOV">50</Setting>
         <Setting name="orthoFOV">50</Setting>
-        <Setting name="undoLimit">40</Setting>
         <Setting name="orthoShowGrid">1</Setting>
         <Setting name="orthoShowGrid">1</Setting>
-        <Setting name="forceLoadDAE">0</Setting>
         <Setting name="currentEditor">WorldEditorInspectorPlugin</Setting>
         <Setting name="currentEditor">WorldEditorInspectorPlugin</Setting>
-        <Group name="Grid">
-            <Setting name="gridSnap">0</Setting>
-            <Setting name="gridMinorColor">51 51 51 100</Setting>
-            <Setting name="gridColor">102 102 102 100</Setting>
-            <Setting name="gridSize">1</Setting>
-            <Setting name="gridOriginColor">255 255 255 100</Setting>
-        </Group>
-        <Group name="Docs">
-            <Setting name="forumURL">http://www.garagegames.com/products/torque-3d/forums</Setting>
-            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
-            <Setting name="documentationReference">../../../Documentation/Torque 3D - Script Manual.chm</Setting>
-            <Setting name="documentationLocal">../../../Documentation/Official Documentation.html</Setting>
-        </Group>
-        <Group name="Render">
-            <Setting name="renderObjText">1</Setting>
-            <Setting name="showMousePopupInfo">1</Setting>
-            <Setting name="renderObjHandle">1</Setting>
-            <Setting name="renderSelectionBox">1</Setting>
-            <Setting name="renderPopupBackground">1</Setting>
-        </Group>
+        <Setting name="dropType">screenCenter</Setting>
+        <Setting name="undoLimit">40</Setting>
         <Group name="Color">
         <Group name="Color">
-            <Setting name="objSelectColor">255 0 0 255</Setting>
-            <Setting name="selectionBoxColor">255 255 0 255</Setting>
-            <Setting name="objectTextColor">255 255 255 255</Setting>
             <Setting name="popupBackgroundColor">100 100 100 255</Setting>
             <Setting name="popupBackgroundColor">100 100 100 255</Setting>
             <Setting name="objMouseOverSelectColor">0 0 255 255</Setting>
             <Setting name="objMouseOverSelectColor">0 0 255 255</Setting>
             <Setting name="dragRectColor">255 255 0 255</Setting>
             <Setting name="dragRectColor">255 255 0 255</Setting>
+            <Setting name="objectTextColor">255 255 255 255</Setting>
+            <Setting name="objSelectColor">255 0 0 255</Setting>
+            <Setting name="selectionBoxColor">255 255 0 255</Setting>
             <Setting name="objMouseOverColor">0 255 0 255</Setting>
             <Setting name="objMouseOverColor">0 255 0 255</Setting>
         </Group>
         </Group>
         <Group name="ObjectIcons">
         <Group name="ObjectIcons">
-            <Setting name="fadeIcons">1</Setting>
-            <Setting name="fadeIconsEndAlpha">0</Setting>
             <Setting name="fadeIconsStartAlpha">255</Setting>
             <Setting name="fadeIconsStartAlpha">255</Setting>
             <Setting name="fadeIconsEndDist">20</Setting>
             <Setting name="fadeIconsEndDist">20</Setting>
             <Setting name="fadeIconsStartDist">8</Setting>
             <Setting name="fadeIconsStartDist">8</Setting>
+            <Setting name="fadeIcons">1</Setting>
+            <Setting name="fadeIconsEndAlpha">0</Setting>
         </Group>
         </Group>
         <Group name="Images">
         <Group name="Images">
             <Setting name="selectHandle">tools/worldEditor/images/SelectHandle</Setting>
             <Setting name="selectHandle">tools/worldEditor/images/SelectHandle</Setting>
@@ -67,17 +47,68 @@
             <Setting name="defaultHandle">tools/worldEditor/images/DefaultHandle</Setting>
             <Setting name="defaultHandle">tools/worldEditor/images/DefaultHandle</Setting>
         </Group>
         </Group>
         <Group name="Tools">
         <Group name="Tools">
-            <Setting name="objectsUseBoxCenter">1</Setting>
-            <Setting name="snapGround">0</Setting>
-            <Setting name="boundingBoxCollision">0</Setting>
-            <Setting name="snapSoft">0</Setting>
             <Setting name="snapSoftSize">2</Setting>
             <Setting name="snapSoftSize">2</Setting>
+            <Setting name="snapSoft">0</Setting>
             <Setting name="dropAtScreenCenterMax">100</Setting>
             <Setting name="dropAtScreenCenterMax">100</Setting>
+            <Setting name="objectsUseBoxCenter">1</Setting>
+            <Setting name="boundingBoxCollision">0</Setting>
             <Setting name="dropAtScreenCenterScalar">1</Setting>
             <Setting name="dropAtScreenCenterScalar">1</Setting>
+            <Setting name="snapGround">0</Setting>
+        </Group>
+        <Group name="Render">
+            <Setting name="renderSelectionBox">1</Setting>
+            <Setting name="renderObjText">1</Setting>
+            <Setting name="renderPopupBackground">1</Setting>
+            <Setting name="renderObjHandle">1</Setting>
+            <Setting name="showMousePopupInfo">1</Setting>
+        </Group>
+        <Group name="Grid">
+            <Setting name="gridMinorColor">51 51 51 100</Setting>
+            <Setting name="gridSnap">0</Setting>
+            <Setting name="gridOriginColor">255 255 255 100</Setting>
+            <Setting name="gridSize">1</Setting>
+            <Setting name="gridColor">102 102 102 100</Setting>
+        </Group>
+        <Group name="Docs">
+            <Setting name="forumURL">http://www.garagegames.com/products/torque-3d/forums</Setting>
+            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
+            <Setting name="documentationLocal">../../../Documentation/Official Documentation.html</Setting>
+            <Setting name="documentationReference">../../../Documentation/Torque 3D - Script Manual.chm</Setting>
         </Group>
         </Group>
     </Group>
     </Group>
-    <Group name="NavEditor">
-        <Setting name="SpawnClass">AIPlayer</Setting>
+    <Group name="GuiEditor">
+        <Setting name="lastPath">tools/materialEditor/gui</Setting>
+        <Setting name="previewResolution">1024 768</Setting>
+        <Group name="Snapping">
+            <Setting name="snapToGuides">1</Setting>
+            <Setting name="sensitivity">2</Setting>
+            <Setting name="snapToEdges">1</Setting>
+            <Setting name="snapToControls">1</Setting>
+            <Setting name="snap2GridSize">8</Setting>
+            <Setting name="snapToCenters">1</Setting>
+            <Setting name="snap2Grid">0</Setting>
+            <Setting name="snapToCanvas">1</Setting>
+        </Group>
+        <Group name="Rendering">
+            <Setting name="drawBorderLines">1</Setting>
+            <Setting name="drawGuides">1</Setting>
+        </Group>
+        <Group name="Help">
+            <Setting name="documentationURL">http://www.garagegames.com/products/torque-3d/documentation/user</Setting>
+            <Setting name="documentationReference">../../../Documentation/Torque 3D - Script Manual.chm</Setting>
+            <Setting name="documentationLocal">../../../Documentation/Official Documentation.html</Setting>
+        </Group>
+        <Group name="Library">
+            <Setting name="viewType">Categorized</Setting>
+        </Group>
+        <Group name="EngineDevelopment">
+            <Setting name="showEditorGuis">0</Setting>
+            <Setting name="showEditorProfiles">0</Setting>
+            <Setting name="toggleIntoEditor">0</Setting>
+        </Group>
+        <Group name="Selection">
+            <Setting name="fullBox">0</Setting>
+        </Group>
     </Group>
     </Group>
     <Group name="LevelInformation">
     <Group name="LevelInformation">
         <Setting name="levelsDirectory">data/FPSGameplay/levels</Setting>
         <Setting name="levelsDirectory">data/FPSGameplay/levels</Setting>
@@ -87,4 +118,10 @@
             </Group>
             </Group>
         </Group>
         </Group>
     </Group>
     </Group>
+    <Group name="NavEditor">
+        <Setting name="SpawnClass">AIPlayer</Setting>
+    </Group>
+    <Group name="ConvexEditor">
+        <Setting name="materialName">Grid_512_Orange</Setting>
+    </Group>
 </EditorSettings>
 </EditorSettings>

+ 18 - 0
Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui

@@ -877,6 +877,24 @@ function ObjectBuilderGui::buildParticleSimulation(%this)
 	%this.process();
 	%this.process();
 }
 }
 
 
+function ObjectBuilderGui::buildReflectionProbe(%this)
+{
+   %this.objectClassName = "ReflectionProbe";
+   %this.process();
+   
+   %defaultPath = filePath($Server::MissionFile) @ "/" @ fileBase($Server::MissionFile) @ "/probes/";   
+   %this.addField("reflectionPath", "TypeFilepath", "reflectionPath", %defaultPath);
+}
+
+function ObjectBuilderGui::buildSkylight(%this)
+{
+   %this.objectClassName = "Skylight";
+   %this.process();
+   
+   %defaultPath = filePath($Server::MissionFile) @ "/" @ fileBase($Server::MissionFile) @ "/probes/";   
+   %this.addField("reflectionPath", "TypeFilepath", "reflectionPath", %defaultPath);
+}
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Mission
 // Mission
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------

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

@@ -55,6 +55,11 @@ function EWCreatorWindow::init( %this )
       
       
       %this.registerMissionObject( "PointLight",          "Point Light" );
       %this.registerMissionObject( "PointLight",          "Point Light" );
       %this.registerMissionObject( "SpotLight",           "Spot Light" );
       %this.registerMissionObject( "SpotLight",           "Spot Light" );
+      
+      %this.registerMissionObject( "BoxEnvironmentProbe",       "Box Environment Probe" );
+      %this.registerMissionObject( "SphereEnvironmentProbe",    "Sphere Environment Probe" );
+      %this.registerMissionObject( "Skylight",       "Skylight" );
+      
       %this.registerMissionObject( "GroundCover",         "Ground Cover" );
       %this.registerMissionObject( "GroundCover",         "Ground Cover" );
       %this.registerMissionObject( "TerrainBlock",        "Terrain Block" );
       %this.registerMissionObject( "TerrainBlock",        "Terrain Block" );
       %this.registerMissionObject( "GroundPlane",         "Ground Plane" );
       %this.registerMissionObject( "GroundPlane",         "Ground Plane" );
@@ -85,6 +90,8 @@ function EWCreatorWindow::init( %this )
       %this.registerMissionObject( "SFXSpace",      "Sound Space" );
       %this.registerMissionObject( "SFXSpace",      "Sound Space" );
       %this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
       %this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
       %this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
       %this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
+      %this.registerMissionObject("NavMesh", "Navigation mesh");
+      %this.registerMissionObject("NavPath", "Path");
       %this.registerMissionObject( "Entity",       "Entity" );
       %this.registerMissionObject( "Entity",       "Entity" );
       
       
    %this.endGroup();
    %this.endGroup();

+ 5 - 0
Templates/BaseGame/game/tools/worldEditor/scripts/lighting.ed.cs

@@ -61,3 +61,8 @@ function EditorLightingMenu::onMenuSelect( %this )
    //%selSize = EWorldEditor.getSelectionSize();
    //%selSize = EWorldEditor.getSelectionSize();
    %this.enableItem( 1, true /*%selSize == 1*/ );   
    %this.enableItem( 1, true /*%selSize == 1*/ );   
 }
 }
+
+function updateReflectionProbes()
+{
+  Canvas.pushDialog(ProbeBakeDlg);
+}

+ 2 - 0
Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.cs

@@ -322,6 +322,8 @@ function EditorGui::buildMenus(%this)
       item[0] = "Full Relight" TAB "Alt L" TAB "Editor.lightScene(\"\", forceAlways);";
       item[0] = "Full Relight" TAB "Alt L" TAB "Editor.lightScene(\"\", forceAlways);";
       item[1] = "Toggle ShadowViz" TAB "" TAB "toggleShadowViz();";
       item[1] = "Toggle ShadowViz" TAB "" TAB "toggleShadowViz();";
       item[2] = "-";
       item[2] = "-";
+      item[3] = "Update Reflection Probes" TAB "" TAB "updateReflectionProbes();";
+      item[4] = "-";
          
          
          // NOTE: The light managers will be inserted as the
          // NOTE: The light managers will be inserted as the
          // last menu items in EditorLightingMenu::onAdd().
          // last menu items in EditorLightingMenu::onAdd().