2
0
Эх сурвалжийг харах

Hardware Skinning Support

- Supports GL, D3D9 & D3D11
- Extends vertex formats & shadergen to support blend indices and weights
- Adds basic support for using 4x3 matrices for shader constants
- Supports software fallback
James Urquhart 10 жил өмнө
parent
commit
3496c549b5
72 өөрчлөгдсөн 2003 нэмэгдсэн , 1179 устгасан
  1. 4 3
      Engine/source/environment/VolumetricFog.cpp
  2. 50 11
      Engine/source/gfx/D3D11/gfxD3D11Device.cpp
  3. 1 0
      Engine/source/gfx/D3D11/gfxD3D11EnumTranslate.cpp
  4. 63 14
      Engine/source/gfx/D3D11/gfxD3D11Shader.cpp
  5. 20 4
      Engine/source/gfx/D3D9/gfxD3D9Device.cpp
  6. 1 0
      Engine/source/gfx/D3D9/gfxD3D9PrimitiveBuffer.cpp
  7. 0 1
      Engine/source/gfx/D3D9/gfxD3D9PrimitiveBuffer.h
  8. 72 8
      Engine/source/gfx/D3D9/gfxD3D9Shader.cpp
  9. 0 1
      Engine/source/gfx/D3D9/gfxD3D9VertexBuffer.cpp
  10. 1 0
      Engine/source/gfx/D3D9/pc/gfxD3D9EnumTranslate.pc.cpp
  11. 1 0
      Engine/source/gfx/D3D9/pc/gfxD3D9PrimitiveBuffer.pc.cpp
  12. 6 1
      Engine/source/gfx/genericConstBuffer.cpp
  13. 4 0
      Engine/source/gfx/genericConstBuffer.h
  14. 7 1
      Engine/source/gfx/gfxEnums.h
  15. 6 3
      Engine/source/gfx/gfxPrimitiveBuffer.h
  16. 4 4
      Engine/source/gfx/gfxVertexBuffer.h
  17. 39 0
      Engine/source/gfx/gfxVertexFormat.cpp
  18. 12 0
      Engine/source/gfx/gfxVertexFormat.h
  19. 5 0
      Engine/source/gfx/gfxVertexTypes.cpp
  20. 4 0
      Engine/source/gfx/gfxVertexTypes.h
  21. 2 4
      Engine/source/gfx/gl/gfxGLDevice.cpp
  22. 28 0
      Engine/source/gfx/gl/gfxGLShader.cpp
  23. 8 0
      Engine/source/gfx/gl/gfxGLVertexAttribLocation.h
  24. 22 0
      Engine/source/gfx/gl/gfxGLVertexDecl.cpp
  25. 8 0
      Engine/source/materials/baseMatInstance.h
  26. 17 0
      Engine/source/materials/matInstance.cpp
  27. 5 0
      Engine/source/materials/matInstance.h
  28. 3 0
      Engine/source/materials/materialFeatureTypes.cpp
  29. 2 0
      Engine/source/materials/materialFeatureTypes.h
  30. 3 1
      Engine/source/materials/miscShdrDat.h
  31. 1 0
      Engine/source/materials/processedFFMaterial.h
  32. 3 0
      Engine/source/materials/processedMaterial.h
  33. 26 0
      Engine/source/materials/processedShaderMaterial.cpp
  34. 3 0
      Engine/source/materials/processedShaderMaterial.h
  35. 6 0
      Engine/source/renderInstance/renderGlowMgr.cpp
  36. 6 0
      Engine/source/renderInstance/renderMeshMgr.cpp
  37. 11 0
      Engine/source/renderInstance/renderPassManager.h
  38. 6 0
      Engine/source/renderInstance/renderPrePassMgr.cpp
  39. 6 0
      Engine/source/renderInstance/renderTranslucentMgr.cpp
  40. 24 0
      Engine/source/shaderGen/GLSL/shaderCompGLSL.cpp
  41. 66 1
      Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp
  42. 13 0
      Engine/source/shaderGen/GLSL/shaderFeatureGLSL.h
  43. 13 0
      Engine/source/shaderGen/GLSL/shaderGenGLSL.cpp
  44. 1 0
      Engine/source/shaderGen/GLSL/shaderGenGLSLInit.cpp
  45. 84 4
      Engine/source/shaderGen/HLSL/shaderCompHLSL.cpp
  46. 64 0
      Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp
  47. 13 0
      Engine/source/shaderGen/HLSL/shaderFeatureHLSL.h
  48. 19 0
      Engine/source/shaderGen/HLSL/shaderGenHLSL.cpp
  49. 1 1
      Engine/source/shaderGen/HLSL/shaderGenHLSLInit.cpp
  50. 2 0
      Engine/source/shaderGen/shaderComp.cpp
  51. 4 0
      Engine/source/shaderGen/shaderComp.h
  52. 9 2
      Engine/source/shaderGen/shaderFeature.h
  53. 3 0
      Engine/source/shaderGen/shaderGen.cpp
  54. 0 6
      Engine/source/ts/arch/tsMeshIntrinsics.arch.h
  55. 0 113
      Engine/source/ts/arch/tsMeshIntrinsics.sse.cpp
  56. 0 80
      Engine/source/ts/arch/tsMeshIntrinsics.sse4.cpp
  57. 1 0
      Engine/source/ts/loader/appMesh.cpp
  58. 1 0
      Engine/source/ts/loader/tsShapeLoader.cpp
  59. 8 1
      Engine/source/ts/tsCollision.cpp
  60. 340 370
      Engine/source/ts/tsMesh.cpp
  61. 238 141
      Engine/source/ts/tsMesh.h
  62. 30 14
      Engine/source/ts/tsMeshFit.cpp
  63. 0 39
      Engine/source/ts/tsMeshIntrinsics.cpp
  64. 0 14
      Engine/source/ts/tsMeshIntrinsics.h
  65. 5 1
      Engine/source/ts/tsPartInstance.cpp
  66. 7 2
      Engine/source/ts/tsRenderState.cpp
  67. 11 1
      Engine/source/ts/tsRenderState.h
  68. 405 263
      Engine/source/ts/tsShape.cpp
  69. 45 8
      Engine/source/ts/tsShape.h
  70. 4 45
      Engine/source/ts/tsShapeEdit.cpp
  71. 109 11
      Engine/source/ts/tsShapeInstance.cpp
  72. 17 6
      Engine/source/ts/tsShapeInstance.h

+ 4 - 3
Engine/source/environment/VolumetricFog.cpp

@@ -406,9 +406,10 @@ bool VolumetricFog::LoadShape()
                mIsVBDirty = true;
                mIsVBDirty = true;
                for (U32 k = 0; k < numNrms; k++)
                for (U32 k = 0; k < numNrms; k++)
                   {
                   {
-                     Point3F norm = mesh->mVertexData[k].normal();
-                     Point3F vert = mesh->mVertexData[k].vert();
-                     Point2F uv = mesh->mVertexData[k].tvert();
+                     const TSMesh::__TSMeshVertexBase &vd = mesh->mVertexData.getBase(k);
+                     Point3F norm = vd.normal();
+                     Point3F vert = vd.vert();
+                     Point2F uv = vd.tvert();
                      tmpVerts[k].point = vert;
                      tmpVerts[k].point = vert;
                      tmpVerts[k].texCoord = uv;
                      tmpVerts[k].texCoord = uv;
                      tmpVerts[k].normal = norm;
                      tmpVerts[k].normal = norm;

+ 50 - 11
Engine/source/gfx/D3D11/gfxD3D11Device.cpp

@@ -1426,6 +1426,8 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
    StringBuilder mainBodyData;
    StringBuilder mainBodyData;
    //make shader
    //make shader
    mainBodyData.append("VertOut main(VertIn IN){VertOut OUT;");
    mainBodyData.append("VertOut main(VertIn IN){VertOut OUT;");
+
+   bool addedPadding = false;
    for (U32 i = 0; i < elemCount; i++)
    for (U32 i = 0; i < elemCount; i++)
    {
    {
       const GFXVertexElement &element = vertexFormat->getElement(i);
       const GFXVertexElement &element = vertexFormat->getElement(i);
@@ -1433,6 +1435,8 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
       String semanticOut = semantic;
       String semanticOut = semantic;
       String type;
       String type;
 
 
+      AssertFatal(!(addedPadding && !element.isSemantic(GFXSemantic::PADDING)), "Padding added before data");
+
       if (element.isSemantic(GFXSemantic::POSITION))
       if (element.isSemantic(GFXSemantic::POSITION))
       {
       {
          semantic = "POSITION";
          semantic = "POSITION";
@@ -1458,6 +1462,21 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
          semantic = "BINORMAL";
          semantic = "BINORMAL";
          semanticOut = semantic;
          semanticOut = semantic;
       }
       }
+      else if (element.isSemantic(GFXSemantic::BLENDINDICES))
+      {
+         semantic = String::ToString("BLENDINDICES%d", element.getSemanticIndex());
+         semanticOut = semantic;
+      }
+      else if (element.isSemantic(GFXSemantic::BLENDWEIGHT))
+      {
+         semantic = String::ToString("BLENDWEIGHT%d", element.getSemanticIndex());
+         semanticOut = semantic;
+      }
+      else if (element.isSemantic(GFXSemantic::PADDING))
+      {
+         addedPadding = true;
+         continue;
+      }
       else
       else
       {
       {
          //Anything that falls thru to here will be a texture coord.
          //Anything that falls thru to here will be a texture coord.
@@ -1481,6 +1500,9 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
       case DXGI_FORMAT_R8G8B8A8_UNORM:
       case DXGI_FORMAT_R8G8B8A8_UNORM:
          type = "float4";
          type = "float4";
          break;
          break;
+      case DXGI_FORMAT_R8G8B8A8_UINT:
+         type = "uint4";
+         break;
       }
       }
 
 
       StringBuilder in;
       StringBuilder in;
@@ -1570,16 +1592,17 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor
    U32 stream;
    U32 stream;
    D3D11_INPUT_ELEMENT_DESC *vd = new D3D11_INPUT_ELEMENT_DESC[ elemCount];
    D3D11_INPUT_ELEMENT_DESC *vd = new D3D11_INPUT_ELEMENT_DESC[ elemCount];
 
 
-   for ( U32 i=0; i < elemCount; i++ )
+   S32 elemIndex = 0;
+   for (S32 i = 0; i < elemCount; i++, elemIndex++)
    {
    {
-	   
-      const GFXVertexElement &element = vertexFormat->getElement( i );
-      
+
+      const GFXVertexElement &element = vertexFormat->getElement(elemIndex);
+
       stream = element.getStreamIndex();
       stream = element.getStreamIndex();
 
 
       vd[i].InputSlot = stream;
       vd[i].InputSlot = stream;
-	 
-      vd[i].AlignedByteOffset =  D3D11_APPEND_ALIGNED_ELEMENT;
+
+      vd[i].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
       vd[i].Format = GFXD3D11DeclType[element.getType()];
       vd[i].Format = GFXD3D11DeclType[element.getType()];
       // If instancing is enabled, the per instance data is only used on stream 1.
       // If instancing is enabled, the per instance data is only used on stream 1.
       if (vertexFormat->hasInstancing() && stream == 1)
       if (vertexFormat->hasInstancing() && stream == 1)
@@ -1596,16 +1619,32 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor
       // texture coords for now... this may change later.
       // texture coords for now... this may change later.
       vd[i].SemanticIndex = 0;
       vd[i].SemanticIndex = 0;
 
 
-      if ( element.isSemantic( GFXSemantic::POSITION ) )
+      if (element.isSemantic(GFXSemantic::POSITION))
          vd[i].SemanticName = "POSITION";
          vd[i].SemanticName = "POSITION";
-      else if ( element.isSemantic( GFXSemantic::NORMAL ) )
+      else if (element.isSemantic(GFXSemantic::NORMAL))
          vd[i].SemanticName = "NORMAL";
          vd[i].SemanticName = "NORMAL";
-      else if ( element.isSemantic( GFXSemantic::COLOR ) )
+      else if (element.isSemantic(GFXSemantic::COLOR))
          vd[i].SemanticName = "COLOR";
          vd[i].SemanticName = "COLOR";
-      else if ( element.isSemantic( GFXSemantic::TANGENT ) )
+      else if (element.isSemantic(GFXSemantic::TANGENT))
          vd[i].SemanticName = "TANGENT";
          vd[i].SemanticName = "TANGENT";
-      else if ( element.isSemantic( GFXSemantic::BINORMAL ) )
+      else if (element.isSemantic(GFXSemantic::BINORMAL))
          vd[i].SemanticName = "BINORMAL";
          vd[i].SemanticName = "BINORMAL";
+      else if (element.isSemantic(GFXSemantic::BLENDWEIGHT))
+      {
+         vd[i].SemanticName = "BLENDWEIGHT";
+         vd[i].SemanticIndex = element.getSemanticIndex();
+      }
+      else if (element.isSemantic(GFXSemantic::BLENDINDICES))
+      {
+         vd[i].SemanticName = "BLENDINDICES";
+         vd[i].SemanticIndex = element.getSemanticIndex();
+      }
+      else if (element.isSemantic(GFXSemantic::PADDING))
+      {
+         i--;
+         elemCount--;
+         continue;
+      }
       else
       else
       {
       {
           //Anything that falls thru to here will be a texture coord.
           //Anything that falls thru to here will be a texture coord.

+ 1 - 0
Engine/source/gfx/D3D11/gfxD3D11EnumTranslate.cpp

@@ -152,5 +152,6 @@ void GFXD3D11EnumTranslate::init()
    GFXD3D11DeclType[GFXDeclType_Float3] = DXGI_FORMAT_R32G32B32_FLOAT;
    GFXD3D11DeclType[GFXDeclType_Float3] = DXGI_FORMAT_R32G32B32_FLOAT;
    GFXD3D11DeclType[GFXDeclType_Float4] = DXGI_FORMAT_R32G32B32A32_FLOAT;
    GFXD3D11DeclType[GFXDeclType_Float4] = DXGI_FORMAT_R32G32B32A32_FLOAT;
    GFXD3D11DeclType[GFXDeclType_Color] =  DXGI_FORMAT_B8G8R8A8_UNORM; // DXGI_FORMAT_R8G8B8A8_UNORM;
    GFXD3D11DeclType[GFXDeclType_Color] =  DXGI_FORMAT_B8G8R8A8_UNORM; // DXGI_FORMAT_R8G8B8A8_UNORM;
+   GFXD3D11DeclType[GFXDeclType_UByte4] = DXGI_FORMAT_R8G8B8A8_UINT;
 }
 }
 
 

+ 63 - 14
Engine/source/gfx/D3D11/gfxD3D11Shader.cpp

@@ -150,9 +150,11 @@ bool GFXD3D11ConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstTyp
       (
       (
       (pd.constType == GFXSCT_Float2x2 ||
       (pd.constType == GFXSCT_Float2x2 ||
       pd.constType == GFXSCT_Float3x3 ||
       pd.constType == GFXSCT_Float3x3 ||
+      pd.constType == GFXSCT_Float4x3 ||
       pd.constType == GFXSCT_Float4x4) &&
       pd.constType == GFXSCT_Float4x4) &&
       (constType == GFXSCT_Float2x2 ||
       (constType == GFXSCT_Float2x2 ||
       constType == GFXSCT_Float3x3 ||
       constType == GFXSCT_Float3x3 ||
+      constType == GFXSCT_Float4x3 ||
       constType == GFXSCT_Float4x4)
       constType == GFXSCT_Float4x4)
       ), "Mismatched const type!");
       ), "Mismatched const type!");
 
 
@@ -161,6 +163,7 @@ bool GFXD3D11ConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstTyp
    {
    {
    case GFXSCT_Float2x2:
    case GFXSCT_Float2x2:
    case GFXSCT_Float3x3:
    case GFXSCT_Float3x3:
+   case GFXSCT_Float4x3:
    case GFXSCT_Float4x4:
    case GFXSCT_Float4x4:
       return setMatrix(pd, constType, size, data, basePointer);
       return setMatrix(pd, constType, size, data, basePointer);
       break;
       break;
@@ -201,6 +204,40 @@ bool GFXD3D11ConstBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
 
 
       return false;
       return false;
    }
    }
+   else if (pd.constType == GFXSCT_Float4x3)
+   {
+      F32 buffer[4 * 4];
+      const U32 csize = 48;
+
+      // Loop through and copy 
+      bool ret = false;
+      U8* currDestPointer = basePointer + pd.offset;
+      const U8* currSourcePointer = static_cast<const U8*>(data);
+      const U8* endData = currSourcePointer + size;
+      while (currSourcePointer < endData)
+      {
+#ifdef TORQUE_DOUBLE_CHECK_43MATS
+         Point4F col;
+         ((MatrixF*)currSourcePointer)->getRow(3, &col);
+         AssertFatal(col.x == 0.0f && col.y == 0.0f && col.z == 0.0f && col.w == 1.0f, "3rd row used");
+#endif
+
+         if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0)
+         {
+            dMemcpy(currDestPointer, currSourcePointer, csize);
+            ret = true;
+         }
+         else if (pd.constType == GFXSCT_Float4x3)
+         {
+            ret = true;
+         }
+
+         currDestPointer += csize;
+         currSourcePointer += sizeof(MatrixF);
+      }
+
+      return ret;
+   }
    else
    else
    {
    {
       PROFILE_SCOPE(GFXD3D11ConstBufferLayout_setMatrix_not4x4);
       PROFILE_SCOPE(GFXD3D11ConstBufferLayout_setMatrix_not4x4);
@@ -480,8 +517,15 @@ void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF&
    AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
    AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
    AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 
    AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 
 
 
-   MatrixF transposed;   
-   mat.transposeTo(transposed);
+   MatrixF transposed;
+   if (matrixType == GFXSCT_Float4x3)
+   {
+      transposed = mat;
+   }
+   else
+   {
+      mat.transposeTo(transposed);
+   }
 
 
    if (h->mInstancingConstant) 
    if (h->mInstancingConstant) 
    {
    {
@@ -510,9 +554,17 @@ void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF*
 
 
    static Vector<MatrixF> transposed;
    static Vector<MatrixF> transposed;
    if (arraySize > transposed.size())
    if (arraySize > transposed.size())
-      transposed.setSize(arraySize);   
-   for (U32 i = 0; i < arraySize; i++)
-      mat[i].transposeTo(transposed[i]);
+      transposed.setSize(arraySize);
+
+   if (matrixType == GFXSCT_Float4x3)
+   {
+      dMemcpy(transposed.address(), mat, arraySize * sizeof(MatrixF));
+   }
+   else
+   {
+      for (U32 i = 0; i < arraySize; i++)
+         mat[i].transposeTo(transposed[i]);
+   }
 
 
    // TODO: Maybe support this in the future?
    // TODO: Maybe support this in the future?
    if (h->mInstancingConstant) 
    if (h->mInstancingConstant) 
@@ -1190,19 +1242,13 @@ bool GFXD3D11Shader::_convertShaderVariable(const D3D11_SHADER_TYPE_DESC &typeDe
       case D3D_SVC_MATRIX_ROWS:
       case D3D_SVC_MATRIX_ROWS:
       case D3D_SVC_MATRIX_COLUMNS:
       case D3D_SVC_MATRIX_COLUMNS:
       {
       {
-         switch (typeDesc.Columns)
+         switch (typeDesc.Rows)
          {
          {
          case 3:
          case 3:
-            if (typeDesc.Rows == 3)
-            {
-               desc.constType = GFXSCT_Float3x3;
-            }
+            desc.constType = typeDesc.Columns == 4 ? GFXSCT_Float3x4 : GFXSCT_Float3x3;
             break;
             break;
          case 4:
          case 4:
-            if (typeDesc.Rows == 4)
-            {
-               desc.constType = GFXSCT_Float4x4;
-            }
+            desc.constType = typeDesc.Columns == 3 ? GFXSCT_Float4x3 : GFXSCT_Float4x4;
             break;
             break;
          }
          }
       }
       }
@@ -1513,6 +1559,9 @@ U32 GFXD3D11Shader::getAlignmentValue(const GFXShaderConstType constType) const
       case GFXSCT_Float3x3 : 
       case GFXSCT_Float3x3 : 
          return mRowSizeF * 3;
          return mRowSizeF * 3;
          break;
          break;
+      case GFXSCT_Float4x3:
+         return mRowSizeF * 3;
+         break;
       case GFXSCT_Float4x4 :
       case GFXSCT_Float4x4 :
          return mRowSizeF * 4;
          return mRowSizeF * 4;
          break;   
          break;   

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

@@ -629,6 +629,8 @@ void GFXD3D9Device::setVertexStream( U32 stream, GFXVertexBuffer *buffer )
          mVolatileVB = NULL;
          mVolatileVB = NULL;
    }
    }
 
 
+   U32 offset = d3dBuffer && stream != 0 ? d3dBuffer->mVolatileStart * d3dBuffer->mVertexSize : 0;
+
    // NOTE: We do not use the stream offset here for stream 0
    // NOTE: We do not use the stream offset here for stream 0
    // as that feature is *supposedly* not as well supported as 
    // as that feature is *supposedly* not as well supported as 
    // using the start index in drawPrimitive.
    // using the start index in drawPrimitive.
@@ -638,7 +640,7 @@ void GFXD3D9Device::setVertexStream( U32 stream, GFXVertexBuffer *buffer )
    
    
    D3D9Assert( mD3DDevice->SetStreamSource(  stream, 
    D3D9Assert( mD3DDevice->SetStreamSource(  stream, 
                                              d3dBuffer ? d3dBuffer->vb : NULL,
                                              d3dBuffer ? d3dBuffer->vb : NULL,
-                                             d3dBuffer && stream != 0 ? d3dBuffer->mVolatileStart * d3dBuffer->mVertexSize : 0, 
+                                             offset, 
                                              d3dBuffer ? d3dBuffer->mVertexSize : 0 ),
                                              d3dBuffer ? d3dBuffer->mVertexSize : 0 ),
                                              "GFXD3D9Device::setVertexStream - Failed to set stream source." );
                                              "GFXD3D9Device::setVertexStream - Failed to set stream source." );
 }
 }
@@ -929,10 +931,12 @@ GFXVertexDecl* GFXD3D9Device::allocVertexDecl( const GFXVertexFormat *vertexForm
    U32 elemCount = vertexFormat->getElementCount();
    U32 elemCount = vertexFormat->getElementCount();
    U32 offsets[4] = { 0 };
    U32 offsets[4] = { 0 };
    U32 stream;
    U32 stream;
+   S32 i = 0;
+   S32 elemIdx = 0;
    D3DVERTEXELEMENT9 *vd = new D3DVERTEXELEMENT9[ elemCount + 1 ];
    D3DVERTEXELEMENT9 *vd = new D3DVERTEXELEMENT9[ elemCount + 1 ];
-   for ( U32 i=0; i < elemCount; i++ )
+   for ( i=0; elemIdx < elemCount; i++, elemIdx++ )
    {
    {
-      const GFXVertexElement &element = vertexFormat->getElement( i );
+      const GFXVertexElement &element = vertexFormat->getElement( elemIdx );
       
       
       stream = element.getStreamIndex();
       stream = element.getStreamIndex();
 
 
@@ -955,6 +959,18 @@ GFXVertexDecl* GFXD3D9Device::allocVertexDecl( const GFXVertexFormat *vertexForm
          vd[i].Usage = D3DDECLUSAGE_TANGENT;
          vd[i].Usage = D3DDECLUSAGE_TANGENT;
       else if ( element.isSemantic( GFXSemantic::BINORMAL ) )
       else if ( element.isSemantic( GFXSemantic::BINORMAL ) )
          vd[i].Usage = D3DDECLUSAGE_BINORMAL;
          vd[i].Usage = D3DDECLUSAGE_BINORMAL;
+      else if ( element.isSemantic( GFXSemantic::BLENDINDICES ) )
+      {
+         vd[i].Usage = D3DDECLUSAGE_BLENDINDICES;
+         vd[i].UsageIndex = element.getSemanticIndex();
+      }
+      else if ( element.isSemantic( GFXSemantic::BLENDWEIGHT ) )
+      {
+         vd[i].Usage = D3DDECLUSAGE_BLENDWEIGHT;
+         vd[i].UsageIndex = element.getSemanticIndex();
+      }
+      else if ( element.isSemantic( GFXSemantic::PADDING ) )
+         i--;
       else
       else
       {
       {
          // Anything that falls thru to here will be a texture coord.
          // Anything that falls thru to here will be a texture coord.
@@ -966,7 +982,7 @@ GFXVertexDecl* GFXD3D9Device::allocVertexDecl( const GFXVertexFormat *vertexForm
    }
    }
 
 
    D3DVERTEXELEMENT9 declEnd = D3DDECL_END();
    D3DVERTEXELEMENT9 declEnd = D3DDECL_END();
-   vd[elemCount] = declEnd;
+   vd[i] = declEnd;
 
 
    decl = new D3D9VertexDecl();
    decl = new D3D9VertexDecl();
    D3D9Assert( mD3DDevice->CreateVertexDeclaration( vd, &decl->decl ), 
    D3D9Assert( mD3DDevice->CreateVertexDeclaration( vd, &decl->decl ), 

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

@@ -112,3 +112,4 @@ void GFXD3D9PrimitiveBuffer::resurrect()
         usage , GFXD3D9IndexFormat[GFXIndexFormat16], pool, &ib, 0),
         usage , GFXD3D9IndexFormat[GFXIndexFormat16], pool, &ib, 0),
         "GFXD3D9PrimitiveBuffer::resurrect - Failed to allocate an index buffer.");
         "GFXD3D9PrimitiveBuffer::resurrect - Failed to allocate an index buffer.");
 }
 }
+

+ 0 - 1
Engine/source/gfx/D3D9/gfxD3D9PrimitiveBuffer.h

@@ -35,7 +35,6 @@ class GFXD3D9PrimitiveBuffer : public GFXPrimitiveBuffer
    public:
    public:
       IDirect3DIndexBuffer9 *ib;
       IDirect3DIndexBuffer9 *ib;
       StrongRefPtr<GFXD3D9PrimitiveBuffer> mVolatileBuffer;
       StrongRefPtr<GFXD3D9PrimitiveBuffer> mVolatileBuffer;
-      U32 mVolatileStart;
 
 
 #ifdef TORQUE_DEBUG
 #ifdef TORQUE_DEBUG
    #define _PBGuardString "GFX_PRIMTIVE_BUFFER_GUARD_STRING"
    #define _PBGuardString "GFX_PRIMTIVE_BUFFER_GUARD_STRING"

+ 72 - 8
Engine/source/gfx/D3D9/gfxD3D9Shader.cpp

@@ -35,6 +35,8 @@
 #include "core/stream/fileStream.h"
 #include "core/stream/fileStream.h"
 #include "core/util/safeDelete.h"
 #include "core/util/safeDelete.h"
 #include "console/console.h"
 #include "console/console.h"
+#include "math/mMathFn.h"
+
 
 
 using namespace Torque;
 using namespace Torque;
 
 
@@ -172,6 +174,40 @@ bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
 
 
       return false;
       return false;
    }
    }
+   else if (pd.constType == GFXSCT_Float4x3)
+   {
+      F32 buffer[4*4];
+      const U32 csize = 48;
+
+      // Loop through and copy 
+      bool ret = false;
+      U8* currDestPointer = basePointer + pd.offset;
+      const U8* currSourcePointer = static_cast<const U8*>(data);
+      const U8* endData = currSourcePointer + size;
+      while (currSourcePointer < endData)
+      {
+#ifdef TORQUE_DOUBLE_CHECK_43MATS
+         Point4F col;
+         ((MatrixF*)currSourcePointer)->getRow(3, &col);
+         AssertFatal(col.x == 0.0f && col.y == 0.0f && col.z == 0.0f && col.w == 1.0f, "3rd row used");
+#endif
+
+         if (dMemcmp(currDestPointer, currSourcePointer, csize) != 0)
+         {
+            dMemcpy(currDestPointer, currSourcePointer, csize);
+            ret = true;
+         }
+         else if (pd.constType == GFXSCT_Float4x3)
+         {
+            ret = true;
+         }
+
+         currDestPointer += csize;
+         currSourcePointer += sizeof(MatrixF);
+      }
+
+      return ret;
+   }
    else
    else
    {
    {
       PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix_not4x4);
       PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix_not4x4);
@@ -186,6 +222,9 @@ bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
       case GFXSCT_Float3x3 :
       case GFXSCT_Float3x3 :
          csize = 48;
          csize = 48;
          break;
          break;
+      case GFXSCT_Float3x4 :
+         csize = 64;
+         break;
       default:
       default:
          AssertFatal(false, "Unhandled case!");
          AssertFatal(false, "Unhandled case!");
          return false;
          return false;
@@ -204,6 +243,10 @@ bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
             dMemcpy(currDestPointer, currSourcePointer, csize);            
             dMemcpy(currDestPointer, currSourcePointer, csize);            
             ret = true;
             ret = true;
          }
          }
+         else if (pd.constType == GFXSCT_Float4x3)
+         {
+            ret = true;
+         }
 
 
          currDestPointer += csize;
          currDestPointer += csize;
          currSourcePointer += sizeof(MatrixF);
          currSourcePointer += sizeof(MatrixF);
@@ -390,8 +433,15 @@ void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF&
    AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
    AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
    AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 
    AssertFatal(h->mShader == mShader, "Mismatched shaders!"); 
 
 
-   MatrixF transposed;   
-   mat.transposeTo(transposed);
+   MatrixF transposed;
+   if (matrixType == GFXSCT_Float4x3)
+   {
+      transposed = mat;
+   }
+   else
+   {
+      mat.transposeTo(transposed);
+   }
 
 
    if (h->mInstancingConstant) 
    if (h->mInstancingConstant) 
    {
    {
@@ -420,9 +470,17 @@ void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF*
 
 
    static Vector<MatrixF> transposed;
    static Vector<MatrixF> transposed;
    if (arraySize > transposed.size())
    if (arraySize > transposed.size())
-      transposed.setSize(arraySize);   
-   for (U32 i = 0; i < arraySize; i++)
-      mat[i].transposeTo(transposed[i]);
+      transposed.setSize(arraySize);
+
+   if (matrixType == GFXSCT_Float4x3)
+   {
+      dMemcpy(transposed.address(), mat, arraySize * sizeof(MatrixF));
+   }
+   else
+   {
+      for (U32 i = 0; i < arraySize; i++)
+         mat[i].transposeTo(transposed[i]);
+   }
 
 
    // TODO: Maybe support this in the future?
    // TODO: Maybe support this in the future?
    if (h->mInstancingConstant) 
    if (h->mInstancingConstant) 
@@ -1069,13 +1127,13 @@ void GFXD3D9Shader::_getShaderConstants( ID3DXConstantTable *table,
                   case D3DXPC_MATRIX_ROWS :
                   case D3DXPC_MATRIX_ROWS :
                   case D3DXPC_MATRIX_COLUMNS :                     
                   case D3DXPC_MATRIX_COLUMNS :                     
                      {
                      {
-                        switch (constantDesc.RegisterCount)                        
+                        switch (constantDesc.Rows)                        
                         {
                         {
                            case 3 :
                            case 3 :
-                              desc.constType = GFXSCT_Float3x3;
+                              desc.constType = constantDesc.Columns == 4 ? GFXSCT_Float3x4 : GFXSCT_Float3x3;
                               break;
                               break;
                            case 4 :
                            case 4 :
-                              desc.constType = GFXSCT_Float4x4;
+                              desc.constType = constantDesc.Columns == 3 ? GFXSCT_Float4x3 : GFXSCT_Float4x4;
                               break;
                               break;
                         }
                         }
                      }
                      }
@@ -1436,9 +1494,15 @@ U32 GFXD3D9Shader::getAlignmentValue(const GFXShaderConstType constType) const
       case GFXSCT_Float3x3 : 
       case GFXSCT_Float3x3 : 
          return mRowSizeF * 3;
          return mRowSizeF * 3;
          break;
          break;
+      case GFXSCT_Float3x4 : 
+         return mRowSizeF * 4;
+         break;
       case GFXSCT_Float4x4 :
       case GFXSCT_Float4x4 :
          return mRowSizeF * 4;
          return mRowSizeF * 4;
          break;   
          break;   
+      case GFXSCT_Float4x3 : 
+         return mRowSizeF * 3;
+         break;
       //// Scalar
       //// Scalar
       case GFXSCT_Int :
       case GFXSCT_Int :
       case GFXSCT_Int2 :
       case GFXSCT_Int2 :

+ 0 - 1
Engine/source/gfx/D3D9/gfxD3D9VertexBuffer.cpp

@@ -228,4 +228,3 @@ void GFXD3D9VertexBuffer::resurrect()
          "GFXD3D9VertexBuffer::resurrect - Failed to allocate VB" );
          "GFXD3D9VertexBuffer::resurrect - Failed to allocate VB" );
    }
    }
 }
 }
-

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

@@ -372,6 +372,7 @@ void GFXD3D9EnumTranslate::init()
    GFXD3D9DeclType[GFXDeclType_Float3] = D3DDECLTYPE_FLOAT3;
    GFXD3D9DeclType[GFXDeclType_Float3] = D3DDECLTYPE_FLOAT3;
    GFXD3D9DeclType[GFXDeclType_Float4] = D3DDECLTYPE_FLOAT4;
    GFXD3D9DeclType[GFXDeclType_Float4] = D3DDECLTYPE_FLOAT4;
    GFXD3D9DeclType[GFXDeclType_Color] = D3DDECLTYPE_D3DCOLOR;
    GFXD3D9DeclType[GFXDeclType_Color] = D3DDECLTYPE_D3DCOLOR;
+   GFXD3D9DeclType[GFXDeclType_UByte4] = D3DDECLTYPE_UBYTE4;
    VALIDATE_LOOKUPTABLE( GFXD3D9DeclType, GFXDeclType );
    VALIDATE_LOOKUPTABLE( GFXD3D9DeclType, GFXDeclType );
 }
 }
 
 

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

@@ -27,6 +27,7 @@
 void GFXD3D9PrimitiveBuffer::lock(U32 indexStart, U32 indexEnd, void **indexPtr)
 void GFXD3D9PrimitiveBuffer::lock(U32 indexStart, U32 indexEnd, void **indexPtr)
 {
 {
    AssertFatal(!mLocked, "GFXD3D9PrimitiveBuffer::lock - Can't lock a primitive buffer more than once!");
    AssertFatal(!mLocked, "GFXD3D9PrimitiveBuffer::lock - Can't lock a primitive buffer more than once!");
+
    mLocked = true;
    mLocked = true;
    U32 flags=0;
    U32 flags=0;
    switch(mBufferType)
    switch(mBufferType)

+ 6 - 1
Engine/source/gfx/genericConstBuffer.cpp

@@ -80,9 +80,13 @@ bool GenericConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstType
                ( 
                ( 
                  ( pd.constType == GFXSCT_Float2x2 || 
                  ( pd.constType == GFXSCT_Float2x2 || 
                    pd.constType == GFXSCT_Float3x3 || 
                    pd.constType == GFXSCT_Float3x3 || 
+                   pd.constType == GFXSCT_Float3x4 ||  
+                   pd.constType == GFXSCT_Float4x3 || 
                    pd.constType == GFXSCT_Float4x4 ) && 
                    pd.constType == GFXSCT_Float4x4 ) && 
                  ( constType == GFXSCT_Float2x2 || 
                  ( constType == GFXSCT_Float2x2 || 
-                   constType == GFXSCT_Float3x3 || 
+                   constType == GFXSCT_Float3x3 ||  
+                   constType == GFXSCT_Float3x4 ||  
+                   constType == GFXSCT_Float4x3 ||
                    constType == GFXSCT_Float4x4 )
                    constType == GFXSCT_Float4x4 )
                ), "Mismatched const type!" );
                ), "Mismatched const type!" );
 
 
@@ -91,6 +95,7 @@ bool GenericConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstType
    {
    {
    case GFXSCT_Float2x2 :
    case GFXSCT_Float2x2 :
    case GFXSCT_Float3x3 :
    case GFXSCT_Float3x3 :
+   case GFXSCT_Float4x3 :
    case GFXSCT_Float4x4 :
    case GFXSCT_Float4x4 :
       return setMatrix(pd, constType, size, data, basePointer);
       return setMatrix(pd, constType, size, data, basePointer);
       break;
       break;

+ 4 - 0
Engine/source/gfx/genericConstBuffer.h

@@ -190,6 +190,8 @@ public:
    {
    {
       AssertFatal(   matrixType == GFXSCT_Float2x2 || 
       AssertFatal(   matrixType == GFXSCT_Float2x2 || 
                      matrixType == GFXSCT_Float3x3 || 
                      matrixType == GFXSCT_Float3x3 || 
+                     matrixType == GFXSCT_Float3x4 || 
+                     matrixType == GFXSCT_Float4x3 || 
                      matrixType == GFXSCT_Float4x4, 
                      matrixType == GFXSCT_Float4x4, 
          "GenericConstBuffer::set() - Invalid matrix type!" );
          "GenericConstBuffer::set() - Invalid matrix type!" );
 
 
@@ -200,6 +202,8 @@ public:
    {
    {
       AssertFatal(   matrixType == GFXSCT_Float2x2 || 
       AssertFatal(   matrixType == GFXSCT_Float2x2 || 
                      matrixType == GFXSCT_Float3x3 || 
                      matrixType == GFXSCT_Float3x3 || 
+                     matrixType == GFXSCT_Float3x4 ||
+                     matrixType == GFXSCT_Float4x3 ||  
                      matrixType == GFXSCT_Float4x4, 
                      matrixType == GFXSCT_Float4x4, 
          "GenericConstBuffer::set() - Invalid matrix type!" );
          "GenericConstBuffer::set() - Invalid matrix type!" );
 
 

+ 7 - 1
Engine/source/gfx/gfxEnums.h

@@ -48,6 +48,7 @@ enum GFXBufferType
                    ///< allowed.
                    ///< allowed.
       GFXBufferTypeVolatile, ///< Volatile vertex or index buffers are meant for vertices or indices that are essentially
       GFXBufferTypeVolatile, ///< Volatile vertex or index buffers are meant for vertices or indices that are essentially
                    ///< only used once.  They can be resized without any performance penalty.
                    ///< only used once.  They can be resized without any performance penalty.
+
       GFXBufferTypeImmutable, ///< Immutable buffers must specify the data when creating the buffer. Cannot be modified.
       GFXBufferTypeImmutable, ///< Immutable buffers must specify the data when creating the buffer. Cannot be modified.
 
 
       GFXBufferType_COUNT ///< Number of buffer types.
       GFXBufferType_COUNT ///< Number of buffer types.
@@ -581,7 +582,9 @@ enum GFXShaderConstType
    GFXSCT_Float4, 
    GFXSCT_Float4, 
    // Matrices
    // Matrices
    GFXSCT_Float2x2, 
    GFXSCT_Float2x2, 
-   GFXSCT_Float3x3, 
+   GFXSCT_Float3x3,
+   GFXSCT_Float3x4,
+   GFXSCT_Float4x3,
    GFXSCT_Float4x4, 
    GFXSCT_Float4x4, 
    // Scalar
    // Scalar
    GFXSCT_Int, 
    GFXSCT_Int, 
@@ -621,6 +624,9 @@ enum GFXDeclType
    /// @see GFXVertexColor
    /// @see GFXVertexColor
    GFXDeclType_Color,
    GFXDeclType_Color,
 
 
+   /// Four-component, packed, unsigned bytes ranged 0-255
+   GFXDeclType_UByte4,
+
    /// The count of total GFXDeclTypes.
    /// The count of total GFXDeclTypes.
    GFXDeclType_COUNT,
    GFXDeclType_COUNT,
 };
 };

+ 6 - 3
Engine/source/gfx/gfxPrimitiveBuffer.h

@@ -43,7 +43,9 @@ public: //protected:
    U32 mPrimitiveCount;
    U32 mPrimitiveCount;
    GFXBufferType mBufferType;
    GFXBufferType mBufferType;
    GFXPrimitive *mPrimitiveArray;
    GFXPrimitive *mPrimitiveArray;
-   GFXDevice *mDevice;  
+   GFXDevice *mDevice;
+
+   U32 mVolatileStart;
 
 
 #ifdef TORQUE_DEBUG
 #ifdef TORQUE_DEBUG
    // In debug builds we provide a TOC leak tracking system.
    // In debug builds we provide a TOC leak tracking system.
@@ -59,7 +61,8 @@ public: //protected:
    GFXPrimitiveBuffer(  GFXDevice *device, 
    GFXPrimitiveBuffer(  GFXDevice *device, 
                         U32 indexCount, 
                         U32 indexCount, 
                         U32 primitiveCount, 
                         U32 primitiveCount, 
-                        GFXBufferType bufferType )
+                        GFXBufferType bufferType ) :
+   mVolatileStart(0)
    {
    {
       mDevice = device;
       mDevice = device;
       mIndexCount = indexCount;
       mIndexCount = indexCount;
@@ -122,7 +125,7 @@ public: //protected:
 
 
    // GFXResource interface
    // GFXResource interface
    /// The resource should put a description of itself (number of vertices, size/width of texture, etc.) in buffer
    /// The resource should put a description of itself (number of vertices, size/width of texture, etc.) in buffer
-   virtual const String describeSelf() const;   
+   virtual const String describeSelf() const; 
 };
 };
 
 
 class GFXPrimitiveBufferHandle : public StrongRefPtr<GFXPrimitiveBuffer>
 class GFXPrimitiveBufferHandle : public StrongRefPtr<GFXPrimitiveBuffer>

+ 4 - 4
Engine/source/gfx/gfxVertexBuffer.h

@@ -64,11 +64,11 @@ public:
                      const GFXVertexFormat *vertexFormat, 
                      const GFXVertexFormat *vertexFormat, 
                      U32 vertexSize, 
                      U32 vertexSize, 
                      GFXBufferType bufferType )
                      GFXBufferType bufferType )
-      :  mNumVerts( numVerts ),
+      :  mDevice( device ),
+         mVolatileStart( 0 ),
+         mNumVerts( numVerts ),
          mVertexSize( vertexSize ),
          mVertexSize( vertexSize ),
-         mBufferType( bufferType ),
-         mDevice( device ),
-         mVolatileStart( 0 )
+         mBufferType( bufferType )
    {
    {
       if ( vertexFormat )
       if ( vertexFormat )
       {
       {

+ 39 - 0
Engine/source/gfx/gfxVertexFormat.cpp

@@ -37,6 +37,9 @@ namespace GFXSemantic
    const String TANGENTW = String( "TANGENTW" ).intern();
    const String TANGENTW = String( "TANGENTW" ).intern();
    const String COLOR = String( "COLOR" ).intern();
    const String COLOR = String( "COLOR" ).intern();
    const String TEXCOORD = String( "TEXCOORD" ).intern();
    const String TEXCOORD = String( "TEXCOORD" ).intern();
+   const String BLENDINDICES = String( "BLENDINDICES" ).intern();
+   const String BLENDWEIGHT = String( "BLENDWEIGHT" ).intern();
+   const String PADDING = String( "PADDING" ).intern();
 }
 }
 
 
 
 
@@ -59,6 +62,9 @@ U32 GFXVertexElement::getSizeInBytes() const
       case GFXDeclType_Color:
       case GFXDeclType_Color:
          return 4;
          return 4;
 
 
+      case GFXDeclType_UByte4:
+         return 4;
+
       default:
       default:
          return 0;
          return 0;
    };
    };
@@ -85,6 +91,7 @@ void GFXVertexFormat::copy( const GFXVertexFormat &format )
    mHasTangent = format.mHasTangent;
    mHasTangent = format.mHasTangent;
    mHasColor = format.mHasColor;
    mHasColor = format.mHasColor;
    mHasInstancing = format.mHasInstancing;
    mHasInstancing = format.mHasInstancing;
+   mHasBlendIndices = format.mHasBlendIndices;
    mTexCoordCount = format.mTexCoordCount;
    mTexCoordCount = format.mTexCoordCount;
    mSizeInBytes = format.mSizeInBytes;
    mSizeInBytes = format.mSizeInBytes;
    mDescription = format.mDescription;
    mDescription = format.mDescription;
@@ -171,6 +178,35 @@ bool GFXVertexFormat::hasInstancing() const
    return mHasInstancing;
    return mHasInstancing;
 }
 }
 
 
+bool GFXVertexFormat::hasBlendIndices() const
+{
+   if ( mDirty )
+      const_cast<GFXVertexFormat*>(this)->_updateDirty();
+   
+   return mHasBlendIndices;
+}
+
+U32 GFXVertexFormat::getNumBlendIndices() const
+{
+   if ( mDirty )
+      const_cast<GFXVertexFormat*>(this)->_updateDirty();
+   
+   if ( !mHasBlendIndices )
+      return 0;
+
+   U32 numIndices = 0;
+   
+   for ( U32 i=0; i < mElements.size(); i++ )
+   {
+      const GFXVertexElement &element = mElements[i];
+
+      if ( element.isSemantic( GFXSemantic::BLENDINDICES ) )
+         numIndices++;
+   }
+
+   return numIndices;
+}
+
 U32 GFXVertexFormat::getTexCoordCount() const
 U32 GFXVertexFormat::getTexCoordCount() const
 {
 {
    if ( mDirty )
    if ( mDirty )
@@ -199,6 +235,7 @@ void GFXVertexFormat::_updateDirty()
    mTexCoordCount = 0;
    mTexCoordCount = 0;
 
 
    mHasColor = false;
    mHasColor = false;
+   mHasBlendIndices = false;
    mHasNormal = false;
    mHasNormal = false;
    mHasTangent = false;
    mHasTangent = false;
    mSizeInBytes = 0;
    mSizeInBytes = 0;
@@ -222,6 +259,8 @@ void GFXVertexFormat::_updateDirty()
          mHasColor = true;
          mHasColor = true;
       else if ( element.isSemantic( GFXSemantic::TEXCOORD ) )
       else if ( element.isSemantic( GFXSemantic::TEXCOORD ) )
          ++mTexCoordCount;
          ++mTexCoordCount;
+      else if ( element.isSemantic( GFXSemantic::BLENDINDICES ) )
+         mHasBlendIndices = true;
 
 
       mSizeInBytes += element.getSizeInBytes();
       mSizeInBytes += element.getSizeInBytes();
    }
    }

+ 12 - 0
Engine/source/gfx/gfxVertexFormat.h

@@ -45,6 +45,9 @@ namespace GFXSemantic
    extern const String TANGENTW;
    extern const String TANGENTW;
    extern const String COLOR;
    extern const String COLOR;
    extern const String TEXCOORD;
    extern const String TEXCOORD;
+   extern const String BLENDWEIGHT;
+   extern const String BLENDINDICES;
+   extern const String PADDING;
 }
 }
 
 
 
 
@@ -184,10 +187,16 @@ public:
 
 
    /// Returns true if there is a COLOR semantic in this vertex format.
    /// Returns true if there is a COLOR semantic in this vertex format.
    bool hasColor() const;
    bool hasColor() const;
+   
+   /// Returns true if there is a BLENDWEIGHT or BLENDINDICES semantic in this vertex format.
+   bool hasBlendIndices() const;
 
 
    /// Return true if instancing is used with this vertex format.
    /// Return true if instancing is used with this vertex format.
    bool hasInstancing() const;
    bool hasInstancing() const;
 
 
+   /// Returns number of blend indices
+   U32 getNumBlendIndices() const;
+
    /// Returns the texture coordinate count by 
    /// Returns the texture coordinate count by 
    /// counting the number of TEXCOORD semantics.
    /// counting the number of TEXCOORD semantics.
    U32 getTexCoordCount() const;
    U32 getTexCoordCount() const;
@@ -230,6 +239,9 @@ protected:
 
 
    /// Is true if there is a COLOR semantic in this vertex format.
    /// Is true if there is a COLOR semantic in this vertex format.
    bool mHasColor;
    bool mHasColor;
+   
+   /// Is true if there is a BLENDWEIGHT or BLENDINDICES semantic in this vertex format.
+   bool mHasBlendIndices;
 
 
    /// Is instaning used with this vertex format.
    /// Is instaning used with this vertex format.
    bool mHasInstancing;
    bool mHasInstancing;

+ 5 - 0
Engine/source/gfx/gfxVertexTypes.cpp

@@ -29,6 +29,11 @@ GFXImplementVertexFormat( GFXVertexP )
    addElement( "POSITION", GFXDeclType_Float3 );
    addElement( "POSITION", GFXDeclType_Float3 );
 }
 }
 
 
+GFXImplementVertexFormat( GFXVertexPad )
+{
+   addElement("PADDING", GFXDeclType_UByte4);
+}
+
 GFXImplementVertexFormat( GFXVertexPT )
 GFXImplementVertexFormat( GFXVertexPT )
 {
 {
    addElement( "POSITION", GFXDeclType_Float3 );
    addElement( "POSITION", GFXDeclType_Float3 );

+ 4 - 0
Engine/source/gfx/gfxVertexTypes.h

@@ -36,6 +36,10 @@
 #include "math/mPoint3.h"
 #include "math/mPoint3.h"
 #endif
 #endif
 
 
+GFXDeclareVertexFormat( GFXVertexPad )
+{
+   U32 data;
+};
 
 
 GFXDeclareVertexFormat( GFXVertexP )
 GFXDeclareVertexFormat( GFXVertexP )
 {
 {

+ 2 - 4
Engine/source/gfx/gl/gfxGLDevice.cpp

@@ -608,13 +608,11 @@ void GFXGLDevice::drawIndexedPrimitive(   GFXPrimitiveType primType,
                                           U32 startIndex, 
                                           U32 startIndex, 
                                           U32 primitiveCount )
                                           U32 primitiveCount )
 {
 {
-   AssertFatal( startVertex == 0, "GFXGLDevice::drawIndexedPrimitive() - Non-zero startVertex unsupported!" );
-
    preDrawPrimitive();
    preDrawPrimitive();
 
 
-   U16* buf = (U16*)static_cast<GFXGLPrimitiveBuffer*>(mCurrentPrimitiveBuffer.getPointer())->getBuffer() + startIndex;
+   U16* buf = (U16*)static_cast<GFXGLPrimitiveBuffer*>(mCurrentPrimitiveBuffer.getPointer())->getBuffer() + startIndex + mCurrentPrimitiveBuffer->mVolatileStart;
 
 
-   const U32 baseVertex = mCurrentVB[0]->mBufferVertexOffset;
+   const U32 baseVertex = mCurrentVB[0]->mBufferVertexOffset + startVertex;
 
 
    if(mDrawInstancesCount)
    if(mDrawInstancesCount)
       glDrawElementsInstancedBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, mDrawInstancesCount, baseVertex);
       glDrawElementsInstancedBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, mDrawInstancesCount, baseVertex);

+ 28 - 0
Engine/source/gfx/gl/gfxGLShader.cpp

@@ -92,6 +92,8 @@ static U32 shaderConstTypeSize(GFXShaderConstType type)
       return 16;
       return 16;
    case GFXSCT_Float3x3:
    case GFXSCT_Float3x3:
       return 36;
       return 36;
+   case GFXSCT_Float4x3:
+      return 48;
    case GFXSCT_Float4x4:
    case GFXSCT_Float4x4:
       return 64;
       return 64;
    default:
    default:
@@ -305,6 +307,9 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF& ma
       reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[7] = mat[9];
       reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[7] = mat[9];
       reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[8] = mat[10];
       reinterpret_cast<F32*>(mBuffer + _glHandle->mOffset)[8] = mat[10];
       break;
       break;
+   case GFXSCT_Float4x3:
+      dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, (sizeof(F32) * 12));// matrix with end row chopped off
+      break;
    case GFXSCT_Float4x4:
    case GFXSCT_Float4x4:
    {      
    {      
       if(_glHandle->mInstancingConstant)
       if(_glHandle->mInstancingConstant)
@@ -334,6 +339,13 @@ void GFXGLShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF* ma
    AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for matrix arrays");
    AssertFatal(!_glHandle->mInstancingConstant, "GFXGLShaderConstBuffer::set - Instancing not supported for matrix arrays");
 
 
    switch (matrixType) {
    switch (matrixType) {
+      case GFXSCT_Float4x3:
+         // Copy each item with the last row chopped off
+         for (int i = 0; i<arraySize; i++)
+         {
+            dMemcpy(mBuffer + _glHandle->mOffset + (i*(sizeof(F32) * 12)), (F32*)(mat + i), sizeof(F32) * 12);
+         }
+      break;
       case GFXSCT_Float4x4:
       case GFXSCT_Float4x4:
          dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize());
          dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize());
          break;
          break;
@@ -443,6 +455,14 @@ bool GFXGLShader::_init()
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Tangent,     "vTangent");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Tangent,     "vTangent");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TangentW,    "vTangentW");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TangentW,    "vTangentW");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Binormal,    "vBinormal");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Binormal,    "vBinormal");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendIndex0, "vBlendIndex0");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendIndex1, "vBlendIndex1");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendIndex2, "vBlendIndex2");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendIndex3, "vBlendIndex3");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendWeight0, "vBlendWeight0");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendWeight1, "vBlendWeight1");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendWeight2, "vBlendWeight2");
+   glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_BlendWeight3, "vBlendWeight3");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord0,   "vTexCoord0");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord0,   "vTexCoord0");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord1,   "vTexCoord1");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord1,   "vTexCoord1");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord2,   "vTexCoord2");
    glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord2,   "vTexCoord2");
@@ -572,6 +592,9 @@ void GFXGLShader::initConstantDescs()
          case GL_FLOAT_MAT4:
          case GL_FLOAT_MAT4:
             desc.constType = GFXSCT_Float4x4;
             desc.constType = GFXSCT_Float4x4;
             break;
             break;
+         case GL_FLOAT_MAT4x3: // jamesu - columns, rows
+            desc.constType = GFXSCT_Float4x3;
+            break;
          case GL_SAMPLER_1D:
          case GL_SAMPLER_1D:
          case GL_SAMPLER_2D:
          case GL_SAMPLER_2D:
          case GL_SAMPLER_3D:
          case GL_SAMPLER_3D:
@@ -805,6 +828,11 @@ void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer)
          case GFXSCT_Float3x3:
          case GFXSCT_Float3x3:
             glUniformMatrix3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
             glUniformMatrix3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
             break;
             break;
+         case GFXSCT_Float4x3:
+            // NOTE: To save a transpose here we could store the matrix transposed (i.e. column major) in the constant buffer.
+            // See _mesa_uniform_matrix in the mesa source for the correct transpose algorithm for a 4x3 matrix. 
+            glUniformMatrix4x3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
+            break;
          case GFXSCT_Float4x4:
          case GFXSCT_Float4x4:
             glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
             glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
             break;
             break;

+ 8 - 0
Engine/source/gfx/gl/gfxGLVertexAttribLocation.h

@@ -11,6 +11,14 @@ namespace Torque
       GL_VertexAttrib_Tangent,
       GL_VertexAttrib_Tangent,
       GL_VertexAttrib_TangentW,
       GL_VertexAttrib_TangentW,
       GL_VertexAttrib_Binormal,
       GL_VertexAttrib_Binormal,
+      GL_VertexAttrib_BlendIndex0,
+      GL_VertexAttrib_BlendIndex1,
+      GL_VertexAttrib_BlendIndex2,
+      GL_VertexAttrib_BlendIndex3,
+      GL_VertexAttrib_BlendWeight0,
+      GL_VertexAttrib_BlendWeight1,
+      GL_VertexAttrib_BlendWeight2,
+      GL_VertexAttrib_BlendWeight3,
       GL_VertexAttrib_TexCoord0,
       GL_VertexAttrib_TexCoord0,
       GL_VertexAttrib_TexCoord1,
       GL_VertexAttrib_TexCoord1,
       GL_VertexAttrib_TexCoord2,
       GL_VertexAttrib_TexCoord2,

+ 22 - 0
Engine/source/gfx/gl/gfxGLVertexDecl.cpp

@@ -187,6 +187,28 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream)
 
 
          buffer += element.getSizeInBytes();
          buffer += element.getSizeInBytes();
       }
       }
+      else if ( element.isSemantic( GFXSemantic::BLENDWEIGHT ) )
+      {
+         glElement.attrIndex = Torque::GL_VertexAttrib_BlendWeight0 + element.getSemanticIndex();
+         glElement.elementCount = 4;
+         glElement.normalized = false;
+         glElement.type = GL_FLOAT;
+         glElement.stride = vertexSize;
+         glElement.pointerFirst = (void*)buffer;
+
+         buffer += element.getSizeInBytes();
+      }
+      else if ( element.isSemantic( GFXSemantic::BLENDINDICES ) )
+      {
+         glElement.attrIndex = Torque::GL_VertexAttrib_BlendIndex0 + element.getSemanticIndex();
+         glElement.elementCount = 4;
+         glElement.normalized = false;
+         glElement.type = GL_UNSIGNED_BYTE;
+         glElement.stride = vertexSize;
+         glElement.pointerFirst = (void*)buffer;
+
+         buffer += element.getSizeInBytes();
+      }
       else // Everything else is a texture coordinate.
       else // Everything else is a texture coordinate.
       {
       {
          String name = element.getSemantic();
          String name = element.getSemantic();

+ 8 - 0
Engine/source/materials/baseMatInstance.h

@@ -80,6 +80,9 @@ protected:
    /// This is set by initialization and used by the prepass.
    /// This is set by initialization and used by the prepass.
    bool mHasNormalMaps;
    bool mHasNormalMaps;
 
 
+   /// This material makes use of bone transforms
+   bool mUsesHardwareSkinning;
+
 public:
 public:
 
 
    virtual ~BaseMatInstance();
    virtual ~BaseMatInstance();
@@ -149,6 +152,9 @@ public:
    /// @see setupPass
    /// @see setupPass
    virtual void setTransforms( const MatrixSet &matrixSet, SceneRenderState *state ) = 0;
    virtual void setTransforms( const MatrixSet &matrixSet, SceneRenderState *state ) = 0;
 
 
+   /// Sets node transforms for the current stage. Used for hardware skinning.
+   virtual void setNodeTransforms( const MatrixF *address, const U32 numTransforms ) = 0;
+
    /// This initializes various material scene state settings and
    /// This initializes various material scene state settings and
    /// should be called after setupPass() within the pass loop.
    /// should be called after setupPass() within the pass loop.
    /// @see setupPass
    /// @see setupPass
@@ -214,6 +220,8 @@ public:
    /// Fast test for use of normal maps in this material.
    /// Fast test for use of normal maps in this material.
    bool hasNormalMap() const { return mHasNormalMaps; }
    bool hasNormalMap() const { return mHasNormalMaps; }
 
 
+   bool usesHardwareSkinning() const { return mUsesHardwareSkinning; }
+
    ///
    ///
    MatFeaturesDelegate& getFeaturesDelegate() { return mFeaturesDelegate; }
    MatFeaturesDelegate& getFeaturesDelegate() { return mFeaturesDelegate; }
 
 

+ 17 - 0
Engine/source/materials/matInstance.cpp

@@ -35,6 +35,7 @@
 #include "gfx/sim/cubemapData.h"
 #include "gfx/sim/cubemapData.h"
 #include "gfx/gfxCubemap.h"
 #include "gfx/gfxCubemap.h"
 #include "core/util/safeDelete.h"
 #include "core/util/safeDelete.h"
+#include "ts/tsShape.h"
 
 
 class MatInstParameters;
 class MatInstParameters;
 
 
@@ -248,8 +249,10 @@ void MatInstance::construct()
    mActiveParameters = NULL;
    mActiveParameters = NULL;
    mDefaultParameters = NULL;
    mDefaultParameters = NULL;
    mHasNormalMaps = false;
    mHasNormalMaps = false;
+   mUsesHardwareSkinning = false;
    mIsForwardLit = false;
    mIsForwardLit = false;
    mIsValid = false;
    mIsValid = false;
+   mIsHardwareSkinned = false;
 
 
    MATMGR->_track(this);
    MATMGR->_track(this);
 }
 }
@@ -360,6 +363,11 @@ bool MatInstance::processMaterial()
 
 
       FeatureSet features( mFeatureList );
       FeatureSet features( mFeatureList );
       features.exclude( MATMGR->getExclusionFeatures() );
       features.exclude( MATMGR->getExclusionFeatures() );
+
+      if (mVertexFormat->hasBlendIndices() && TSShape::smUseHardwareSkinning)
+      {
+         features.addFeature( MFT_HardwareSkinning );
+      }
       
       
       if( !mProcessedMaterial->init(features, mVertexFormat, mFeaturesDelegate) )
       if( !mProcessedMaterial->init(features, mVertexFormat, mFeaturesDelegate) )
       {
       {
@@ -373,11 +381,14 @@ bool MatInstance::processMaterial()
 
 
       const FeatureSet &finalFeatures = mProcessedMaterial->getFeatures();
       const FeatureSet &finalFeatures = mProcessedMaterial->getFeatures();
       mHasNormalMaps = finalFeatures.hasFeature( MFT_NormalMap );
       mHasNormalMaps = finalFeatures.hasFeature( MFT_NormalMap );
+      mUsesHardwareSkinning = finalFeatures.hasFeature( MFT_HardwareSkinning );
 
 
       mIsForwardLit =   (  custMat && custMat->mForwardLit ) || 
       mIsForwardLit =   (  custMat && custMat->mForwardLit ) || 
                         (  !finalFeatures.hasFeature( MFT_IsEmissive ) &&
                         (  !finalFeatures.hasFeature( MFT_IsEmissive ) &&
                            finalFeatures.hasFeature( MFT_ForwardShading ) );
                            finalFeatures.hasFeature( MFT_ForwardShading ) );
 
 
+      mIsHardwareSkinned = finalFeatures.hasFeature( MFT_HardwareSkinning );
+
       return true;
       return true;
    }
    }
    
    
@@ -455,6 +466,12 @@ void MatInstance::setTransforms(const MatrixSet &matrixSet, SceneRenderState *st
    mProcessedMaterial->setTransforms(matrixSet, state, getCurPass());
    mProcessedMaterial->setTransforms(matrixSet, state, getCurPass());
 }
 }
 
 
+void MatInstance::setNodeTransforms(const MatrixF *address, const U32 numTransforms)
+{
+   PROFILE_SCOPE(MatInstance_setNodeTransforms);
+   mProcessedMaterial->setNodeTransforms(address, numTransforms, getCurPass());
+}
+
 void MatInstance::setSceneInfo(SceneRenderState * state, const SceneData& sgData)
 void MatInstance::setSceneInfo(SceneRenderState * state, const SceneData& sgData)
 {
 {
    PROFILE_SCOPE(MatInstance_setSceneInfo);
    PROFILE_SCOPE(MatInstance_setSceneInfo);

+ 5 - 0
Engine/source/materials/matInstance.h

@@ -65,12 +65,14 @@ public:
    virtual MaterialParameterHandle* getMaterialParameterHandle(const String& name);
    virtual MaterialParameterHandle* getMaterialParameterHandle(const String& name);
    virtual bool setupPass(SceneRenderState *, const SceneData &sgData );
    virtual bool setupPass(SceneRenderState *, const SceneData &sgData );
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state);
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state);
+   virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms);
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData);
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData);
    virtual void setTextureStages(SceneRenderState * state, const SceneData &sgData );
    virtual void setTextureStages(SceneRenderState * state, const SceneData &sgData );
    virtual void setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer);
    virtual void setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer);
    virtual bool isInstanced() const;
    virtual bool isInstanced() const;
    virtual bool stepInstance();
    virtual bool stepInstance();
    virtual bool isForwardLit() const { return mIsForwardLit; }
    virtual bool isForwardLit() const { return mIsForwardLit; }
+   virtual bool isHardwareSkinned() const { return mIsHardwareSkinned; }
    virtual void setUserObject( SimObject *userObject ) { mUserObject = userObject; }
    virtual void setUserObject( SimObject *userObject ) { mUserObject = userObject; }
    virtual SimObject* getUserObject() const { return mUserObject; }
    virtual SimObject* getUserObject() const { return mUserObject; }
    virtual Material *getMaterial() { return mMaterial; }
    virtual Material *getMaterial() { return mMaterial; }
@@ -113,6 +115,9 @@ protected:
    /// If the processed material requires forward lighting or not.
    /// If the processed material requires forward lighting or not.
    bool mIsForwardLit;
    bool mIsForwardLit;
 
 
+   /// If the processed material requires bone transforms
+   bool mIsHardwareSkinned;
+
    S32               mCurPass;
    S32               mCurPass;
    U32               mMaxStages;
    U32               mMaxStages;
 
 

+ 3 - 0
Engine/source/materials/materialFeatureTypes.cpp

@@ -103,3 +103,6 @@ ImplementFeatureType( MFT_DeferredEmptySpec, MFG_Texture, 8.01f, false );
 ImplementFeatureType( MFT_DeferredSpecMap, MFG_Texture, 8.2f, false );
 ImplementFeatureType( MFT_DeferredSpecMap, MFG_Texture, 8.2f, false );
 ImplementFeatureType( MFT_DeferredSpecVars, MFG_Texture, 8.5f, false );
 ImplementFeatureType( MFT_DeferredSpecVars, MFG_Texture, 8.5f, false );
 ImplementFeatureType( MFT_DeferredMatInfoFlags, MFG_Texture, 8.7f, false );
 ImplementFeatureType( MFT_DeferredMatInfoFlags, MFG_Texture, 8.7f, false );
+
+ImplementFeatureType( MFT_HardwareSkinning, MFG_Transform,-2.0, false );
+

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

@@ -179,6 +179,8 @@ DeclareFeatureType( MFT_ForwardShading );
 /// so that the rest of the material features can work on it.
 /// so that the rest of the material features can work on it.
 DeclareFeatureType( MFT_ImposterVert );
 DeclareFeatureType( MFT_ImposterVert );
 
 
+DeclareFeatureType( MFT_HardwareSkinning );
+
 
 
 // Deferred Shading
 // Deferred Shading
 DeclareFeatureType( MFT_isDeferred );
 DeclareFeatureType( MFT_isDeferred );

+ 3 - 1
Engine/source/materials/miscShdrDat.h

@@ -41,7 +41,9 @@ enum RegisterType
    RT_COLOR,
    RT_COLOR,
    RT_TEXCOORD,
    RT_TEXCOORD,
    RT_VPOS,
    RT_VPOS,
-   RT_SVPOSITION
+   RT_SVPOSITION,
+   RT_BLENDINDICES,
+   RT_BLENDWEIGHT
 };
 };
 
 
 enum Components
 enum Components

+ 1 - 0
Engine/source/materials/processedFFMaterial.h

@@ -53,6 +53,7 @@ public:
    virtual MaterialParameters* getDefaultMaterialParameters();      
    virtual MaterialParameters* getDefaultMaterialParameters();      
    
    
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass);
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass);
+   virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms, const U32 pass) {;}
 
 
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass);
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass);
 
 

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

@@ -142,6 +142,9 @@ public:
    /// Sets the transformation matrix, i.e. Model * View * Projection
    /// Sets the transformation matrix, i.e. Model * View * Projection
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass) = 0;
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass) = 0;
    
    
+   /// Sets the node transforms for HW Skinning
+   virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms, const U32 pass) = 0;
+   
    /// Sets the scene info like lights for the given pass.
    /// Sets the scene info like lights for the given pass.
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass) = 0;
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass) = 0;
 
 

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

@@ -44,6 +44,9 @@
 // We need to include customMaterialDefinition for ShaderConstHandles::init
 // We need to include customMaterialDefinition for ShaderConstHandles::init
 #include "materials/customMaterialDefinition.h"
 #include "materials/customMaterialDefinition.h"
 
 
+
+#include "ts/tsShape.h"
+
 ///
 ///
 /// ShaderConstHandles
 /// ShaderConstHandles
 ///
 ///
@@ -99,6 +102,9 @@ void ShaderConstHandles::init( GFXShader *shader, CustomMaterial* mat /*=NULL*/
    for (S32 i = 0; i < TEXTURE_STAGE_COUNT; ++i)
    for (S32 i = 0; i < TEXTURE_STAGE_COUNT; ++i)
       mRTParamsSC[i] = shader->getShaderConstHandle( String::ToString( "$rtParams%d", i ) );
       mRTParamsSC[i] = shader->getShaderConstHandle( String::ToString( "$rtParams%d", i ) );
 
 
+   // MFT_HardwareSkinning
+   mNodeTransforms = shader->getShaderConstHandle( "$nodeTransforms" );
+
    // Clear any existing texture handles.
    // Clear any existing texture handles.
    dMemset( mTexHandlesSC, 0, sizeof( mTexHandlesSC ) );
    dMemset( mTexHandlesSC, 0, sizeof( mTexHandlesSC ) );
    if(mat)
    if(mat)
@@ -491,6 +497,12 @@ void ProcessedShaderMaterial::_determineFeatures(  U32 stageNum,
                                        &fd );
                                        &fd );
    }
    }
 
 
+   // Need to add the Hardware Skinning feature if its used
+   if ( features.hasFeature( MFT_HardwareSkinning ) )
+   {
+      fd.features.addFeature( MFT_HardwareSkinning );
+   }
+
    // Now disable any features that were 
    // Now disable any features that were 
    // not part of the input feature handle.
    // not part of the input feature handle.
    fd.features.filter( features );
    fd.features.filter( features );
@@ -1217,6 +1229,20 @@ void ProcessedShaderMaterial::setTransforms(const MatrixSet &matrixSet, SceneRen
       shaderConsts->set( handles->m_vEyeSC, state->getVectorEye() );
       shaderConsts->set( handles->m_vEyeSC, state->getVectorEye() );
 }
 }
 
 
+void ProcessedShaderMaterial::setNodeTransforms(const MatrixF *transforms, const U32 transformCount, const U32 pass)
+{
+   PROFILE_SCOPE( ProcessedShaderMaterial_setNodeTransforms );
+
+   GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass);
+   ShaderConstHandles* handles = _getShaderConstHandles(pass);
+
+   if ( handles->mNodeTransforms->isValid() )
+   {
+      S32 realTransformCount = getMin( transformCount, TSShape::smMaxSkinBones );
+      shaderConsts->set( handles->mNodeTransforms, transforms, realTransformCount, GFXSCT_Float4x3 );
+   }
+}
+
 void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const SceneData& sgData, U32 pass)
 void ProcessedShaderMaterial::setSceneInfo(SceneRenderState * state, const SceneData& sgData, U32 pass)
 {
 {
    PROFILE_SCOPE( ProcessedShaderMaterial_setSceneInfo );
    PROFILE_SCOPE( ProcessedShaderMaterial_setSceneInfo );

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

@@ -93,6 +93,8 @@ public:
    GFXShaderConstHandle* mTexHandlesSC[Material::MAX_TEX_PER_PASS];
    GFXShaderConstHandle* mTexHandlesSC[Material::MAX_TEX_PER_PASS];
    GFXShaderConstHandle* mRTParamsSC[TEXTURE_STAGE_COUNT];
    GFXShaderConstHandle* mRTParamsSC[TEXTURE_STAGE_COUNT];
 
 
+   GFXShaderConstHandle* mNodeTransforms;
+
    void init( GFXShader* shader, CustomMaterial* mat = NULL );
    void init( GFXShader* shader, CustomMaterial* mat = NULL );
 };
 };
 
 
@@ -128,6 +130,7 @@ public:
    virtual bool setupPass(SceneRenderState *, const SceneData& sgData, U32 pass);
    virtual bool setupPass(SceneRenderState *, const SceneData& sgData, U32 pass);
    virtual void setTextureStages(SceneRenderState *, const SceneData &sgData, U32 pass );
    virtual void setTextureStages(SceneRenderState *, const SceneData &sgData, U32 pass );
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass);
    virtual void setTransforms(const MatrixSet &matrixSet, SceneRenderState *state, const U32 pass);
+   virtual void setNodeTransforms(const MatrixF *address, const U32 numTransforms, const U32 pass);
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass);
    virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass);
    virtual void setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer); 
    virtual void setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer); 
    virtual bool stepInstance();
    virtual bool stepInstance();

+ 6 - 0
Engine/source/renderInstance/renderGlowMgr.cpp

@@ -245,6 +245,12 @@ void RenderGlowMgr::render( SceneRenderState *state )
             matrixSet.setProjection(*passRI->projection);
             matrixSet.setProjection(*passRI->projection);
             glowMat->setTransforms(matrixSet, state);
             glowMat->setTransforms(matrixSet, state);
 
 
+            // Setup HW skinning transforms if applicable
+            if (glowMat->usesHardwareSkinning())
+            {
+               glowMat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount);
+            }
+
             glowMat->setSceneInfo(state, sgData);
             glowMat->setSceneInfo(state, sgData);
             glowMat->setBuffers(passRI->vertBuff, passRI->primBuff);
             glowMat->setBuffers(passRI->vertBuff, passRI->primBuff);
 
 

+ 6 - 0
Engine/source/renderInstance/renderMeshMgr.cpp

@@ -176,6 +176,12 @@ void RenderMeshMgr::render(SceneRenderState * state)
             matrixSet.setProjection(*passRI->projection);
             matrixSet.setProjection(*passRI->projection);
             mat->setTransforms(matrixSet, state);
             mat->setTransforms(matrixSet, state);
 
 
+            // Setup HW skinning transforms if applicable
+            if (mat->usesHardwareSkinning())
+            {
+               mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount);
+            }
+
             setupSGData( passRI, sgData );
             setupSGData( passRI, sgData );
             mat->setSceneInfo( state, sgData );
             mat->setSceneInfo( state, sgData );
 
 

+ 11 - 0
Engine/source/renderInstance/renderPassManager.h

@@ -371,6 +371,17 @@ struct MeshRenderInst : public RenderInst
    GFXTextureObject *accuTex;
    GFXTextureObject *accuTex;
    GFXCubemap   *cubemap;
    GFXCubemap   *cubemap;
 
 
+   /// @name Hardware Skinning
+   /// {
+   MatrixF *mNodeTransforms;
+   U32 mNodeTransformCount;
+   /// }
+
+#ifdef TORQUE_ENABLE_GFXDEBUGEVENTS
+   const char *meshName;
+   const char *objectName;
+#endif
+
    void clear();
    void clear();
 };
 };
 
 

+ 6 - 0
Engine/source/renderInstance/renderPrePassMgr.cpp

@@ -430,6 +430,12 @@ void RenderPrePassMgr::render( SceneRenderState *state )
             matrixSet.setProjection(*passRI->projection);
             matrixSet.setProjection(*passRI->projection);
             mat->setTransforms(matrixSet, state);
             mat->setTransforms(matrixSet, state);
 
 
+            // Setup HW skinning transforms if applicable
+            if (mat->usesHardwareSkinning())
+            {
+               mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount);
+            }
+
             // If we're instanced then don't render yet.
             // If we're instanced then don't render yet.
             if ( mat->isInstanced() )
             if ( mat->isInstanced() )
             {
             {

+ 6 - 0
Engine/source/renderInstance/renderTranslucentMgr.cpp

@@ -243,6 +243,12 @@ void RenderTranslucentMgr::render( SceneRenderState *state )
                matrixSet.setProjection(*passRI->projection);
                matrixSet.setProjection(*passRI->projection);
                mat->setTransforms(matrixSet, state);
                mat->setTransforms(matrixSet, state);
 
 
+               // Setup HW skinning transforms if applicable
+               if (mat->usesHardwareSkinning())
+               {
+                  mat->setNodeTransforms(passRI->mNodeTransforms, passRI->mNodeTransformCount);
+               }
+
                // If we're instanced then don't render yet.
                // If we're instanced then don't render yet.
                if ( mat->isInstanced() )
                if ( mat->isInstanced() )
                {
                {

+ 24 - 0
Engine/source/shaderGen/GLSL/shaderCompGLSL.cpp

@@ -101,6 +101,30 @@ Var * AppVertConnectorGLSL::getElement(   RegisterType type,
          return newVar;
          return newVar;
       }
       }
 
 
+      case RT_BLENDINDICES:
+      {
+         Var *newVar = new Var;
+         newVar->constNum = mCurBlendIndicesElem;
+         mElementList.push_back(newVar);
+         char out[32];
+         dSprintf((char*)out, sizeof(out), "vBlendIndex%d", mCurBlendIndicesElem);
+         mCurBlendIndicesElem += 1;
+         newVar->setConnectName(out);
+         return newVar;
+      }
+
+      case RT_BLENDWEIGHT:
+      {
+         Var *newVar = new Var;
+         newVar->constNum = mCurBlendWeightsElem;
+         mElementList.push_back(newVar);
+         char out[32];
+         dSprintf((char*)out, sizeof(out), "vBlendWeight%d", mCurBlendWeightsElem);
+         mCurBlendWeightsElem += 1;
+         newVar->setConnectName(out);
+         return newVar;
+      }
+
       default:
       default:
          break;
          break;
    }
    }

+ 66 - 1
Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp

@@ -33,6 +33,7 @@
 #include "core/util/autoPtr.h"
 #include "core/util/autoPtr.h"
 
 
 #include "lighting/advanced/advancedLightBinManager.h"
 #include "lighting/advanced/advancedLightBinManager.h"
+#include "ts/tsShape.h"
 
 
 LangElement * ShaderFeatureGLSL::setupTexSpaceMat( Vector<ShaderComponent*> &, // componentList
 LangElement * ShaderFeatureGLSL::setupTexSpaceMat( Vector<ShaderComponent*> &, // componentList
                                                    Var **texSpaceMat )
                                                    Var **texSpaceMat )
@@ -2795,4 +2796,68 @@ void ImposterVertFeatureGLSL::determineFeature( Material *material,
 {      
 {      
    if ( features.hasFeature( MFT_ImposterVert ) )
    if ( features.hasFeature( MFT_ImposterVert ) )
       outFeatureData->features.addFeature( MFT_ImposterVert );
       outFeatureData->features.addFeature( MFT_ImposterVert );
-}
+}
+
+//****************************************************************************
+// HardwareSkinningFeatureGLSL
+//****************************************************************************
+
+void HardwareSkinningFeatureGLSL::processVert(Vector<ShaderComponent*> &componentList,
+   const MaterialFeatureData &fd)
+{
+   MultiLine *meta = new MultiLine;
+
+   Var *inPosition = (Var*)LangElement::find("inPosition");
+   Var *inNormal = (Var*)LangElement::find("inNormal");
+
+   if (!inPosition)
+      inPosition = (Var*)LangElement::find("position");
+
+   if (!inNormal)
+      inNormal = (Var*)LangElement::find("normal");
+
+   Var* posePos = new Var("posePos", "vec3");
+   Var* poseNormal = new Var("poseNormal", "vec3");
+   Var* poseMat = new Var("poseMat", "mat4x3");
+   Var* poseRotMat = new Var("poseRotMat", "mat3x3");
+   Var* nodeTransforms = (Var*)LangElement::find("nodeTransforms");
+
+   if (!nodeTransforms)
+   {
+      nodeTransforms = new Var("nodeTransforms", "mat4x3");
+      nodeTransforms->uniform = true;
+      nodeTransforms->arraySize = TSShape::smMaxSkinBones;
+      nodeTransforms->constSortPos = cspPrimitive;
+   }
+
+   U32 numIndices = mVertexFormat->getNumBlendIndices();
+   meta->addStatement(new GenOp("   @ = vec3(0.0);\r\n", new DecOp(posePos)));
+   meta->addStatement(new GenOp("   @ = vec3(0.0);\r\n", new DecOp(poseNormal)));
+   meta->addStatement(new GenOp("   @;\r\n", new DecOp(poseMat)));
+   meta->addStatement(new GenOp("   @;\r\n   int i;\r\n", new DecOp(poseRotMat)));
+
+   for (U32 i = 0; i<numIndices; i++)
+   {
+      // NOTE: To keep things simple, we assume all 4 bone indices are used in each element chunk.
+      LangElement* inIndices = (Var*)LangElement::find(String::ToString("vBlendIndex%d", i));
+      LangElement* inWeights = (Var*)LangElement::find(String::ToString("vBlendWeight%d", i));
+
+      AssertFatal(inIndices && inWeights, "Something went wrong here");
+      AssertFatal(poseMat && nodeTransforms && posePos && inPosition && inWeights && poseNormal && inNormal && poseRotMat, "Something went REALLY wrong here");
+
+      meta->addStatement(new GenOp("   for (i=0; i<4; i++) {\r\n"));
+      meta->addStatement(new GenOp("      int poseIdx = int(@[i]);\r\n", inIndices));
+      meta->addStatement(new GenOp("      float poseWeight = @[i];\r\n", inWeights));
+      meta->addStatement(new GenOp("      @ = @[poseIdx];\r\n", poseMat, nodeTransforms));
+      meta->addStatement(new GenOp("      @ = mat3x3(@);\r\n", poseRotMat, poseMat));
+      meta->addStatement(new GenOp("      @ += (@ * vec4(@, 1)).xyz * poseWeight;\r\n", posePos, poseMat, inPosition));
+      meta->addStatement(new GenOp("      @ += ((@ * @) * poseWeight);\r\n", poseNormal, poseRotMat, inNormal));
+      meta->addStatement(new GenOp("   }\r\n"));
+   }
+
+   // Assign new position and normal
+   meta->addStatement(new GenOp("   @ = @;\r\n", inPosition, posePos));
+   meta->addStatement(new GenOp("   @ = normalize(@);\r\n", inNormal, poseNormal));
+
+   output = meta;
+}

+ 13 - 0
Engine/source/shaderGen/GLSL/shaderFeatureGLSL.h

@@ -659,4 +659,17 @@ public:
 											MaterialFeatureData *outFeatureData );
 											MaterialFeatureData *outFeatureData );
 };
 };
 
 
+/// Hardware Skinning
+class HardwareSkinningFeatureGLSL : public ShaderFeatureGLSL
+{
+protected:
+
+public:
+
+   virtual void processVert(Vector<ShaderComponent*> &componentList,
+      const MaterialFeatureData &fd);
+
+   virtual String getName() { return "Hardware Skinning"; }
+};
+
 #endif // _SHADERGEN_GLSL_SHADERFEATUREGLSL_H_
 #endif // _SHADERGEN_GLSL_SHADERFEATUREGLSL_H_

+ 13 - 0
Engine/source/shaderGen/GLSL/shaderGenGLSL.cpp

@@ -113,6 +113,9 @@ const char* ShaderGenComponentFactoryGLSL::typeToString( GFXDeclType type )
       case GFXDeclType_Float3:
       case GFXDeclType_Float3:
          return "vec3";
          return "vec3";
 
 
+      case GFXDeclType_UByte4:
+         return "vec4";
+
       case GFXDeclType_Float4:
       case GFXDeclType_Float4:
       case GFXDeclType_Color:
       case GFXDeclType_Color:
          return "vec4";
          return "vec4";
@@ -160,6 +163,16 @@ ShaderComponent* ShaderGenComponentFactoryGLSL::createVertexInputConnector( cons
          var = vertComp->getElement( RT_COLOR );
          var = vertComp->getElement( RT_COLOR );
          var->setName( "diffuse" );
          var->setName( "diffuse" );
       }
       }
+      else if (element.isSemantic(GFXSemantic::BLENDINDICES))
+      {
+         var = vertComp->getElement(RT_BLENDINDICES);
+         var->setName(String::ToString("vBlendIndex%d", element.getSemanticIndex()));
+      }
+      else if (element.isSemantic(GFXSemantic::BLENDWEIGHT))
+      {
+         var = vertComp->getElement(RT_BLENDWEIGHT);
+         var->setName(String::ToString("vBlendWeight%d", element.getSemanticIndex()));
+      }
       else if ( element.isSemantic( GFXSemantic::TEXCOORD ) )
       else if ( element.isSemantic( GFXSemantic::TEXCOORD ) )
       {
       {
          var = vertComp->getElement( RT_TEXCOORD );
          var = vertComp->getElement( RT_TEXCOORD );

+ 1 - 0
Engine/source/shaderGen/GLSL/shaderGenGLSLInit.cpp

@@ -105,6 +105,7 @@ void _initShaderGenGLSL( ShaderGen *shaderGen )
    FEATUREMGR->registerFeature( MFT_DeferredMatInfoFlags, new DeferredMatInfoFlagsGLSL );
    FEATUREMGR->registerFeature( MFT_DeferredMatInfoFlags, new DeferredMatInfoFlagsGLSL );
    FEATUREMGR->registerFeature( MFT_DeferredEmptySpec, new DeferredEmptySpecGLSL );
    FEATUREMGR->registerFeature( MFT_DeferredEmptySpec, new DeferredEmptySpecGLSL );
    FEATUREMGR->registerFeature( MFT_SkyBox, new NamedFeatureGLSL( "skybox" ) );
    FEATUREMGR->registerFeature( MFT_SkyBox, new NamedFeatureGLSL( "skybox" ) );
+   FEATUREMGR->registerFeature( MFT_HardwareSkinning, new HardwareSkinningFeatureGLSL );
 }
 }
 
 
 MODULE_BEGIN( ShaderGenGLSL )
 MODULE_BEGIN( ShaderGenGLSL )

+ 84 - 4
Engine/source/shaderGen/HLSL/shaderCompHLSL.cpp

@@ -32,7 +32,20 @@ Var * ShaderConnectorHLSL::getElement( RegisterType type,
                                        U32 numElements, 
                                        U32 numElements, 
                                        U32 numRegisters )
                                        U32 numRegisters )
 {
 {
-   Var *ret = getIndexedElement( mCurTexElem, type, numElements, numRegisters );
+   Var *ret = NULL;
+   
+   if ( type == RT_BLENDINDICES )
+   {
+      ret = getIndexedElement( mCurBlendIndicesElem, type, numElements, numRegisters );
+   }
+   else if ( type == RT_BLENDWEIGHT )
+   {
+      ret = getIndexedElement( mCurBlendWeightsElem, type, numElements, numRegisters );
+   }
+   else
+   {
+      ret = getIndexedElement( mCurTexElem, type, numElements, numRegisters );
+   }
 
 
    // Adjust texture offset if this is a texcoord type
    // Adjust texture offset if this is a texcoord type
    if( type == RT_TEXCOORD )
    if( type == RT_TEXCOORD )
@@ -42,6 +55,20 @@ Var * ShaderConnectorHLSL::getElement( RegisterType type,
       else
       else
          mCurTexElem += numElements;
          mCurTexElem += numElements;
    }
    }
+   else if ( type == RT_BLENDINDICES )
+   {
+      if ( numRegisters != -1 )
+         mCurBlendIndicesElem += numRegisters;
+      else
+         mCurBlendIndicesElem += numElements;
+   }
+   else if ( type == RT_BLENDWEIGHT )
+   {
+      if ( numRegisters != -1 )
+         mCurBlendWeightsElem += numRegisters;
+      else
+         mCurBlendWeightsElem += numElements;
+   }
 
 
    return ret;
    return ret;
 }
 }
@@ -133,6 +160,46 @@ Var * ShaderConnectorHLSL::getIndexedElement( U32 index, RegisterType type, U32
          return newVar;
          return newVar;
       }
       }
 
 
+   case RT_BLENDINDICES:
+      {
+         Var *newVar = new Var;
+         mElementList.push_back( newVar );
+
+         // This was needed for hardware instancing, but
+         // i don't really remember why right now.
+         if ( index > mCurBlendIndicesElem )
+            mCurBlendIndicesElem = index + 1;
+
+         char out[32];
+         dSprintf( (char*)out, sizeof(out), "BLENDINDICES%d", index );
+         newVar->setConnectName( out );
+         newVar->constNum = index;
+         newVar->arraySize = numElements;
+
+         return newVar;
+      }
+
+   case RT_BLENDWEIGHT:
+      {
+         Var *newVar = new Var;
+         mElementList.push_back( newVar );
+
+         // This was needed for hardware instancing, but
+         // i don't really remember why right now.
+         if ( index > mCurBlendWeightsElem )
+            mCurBlendWeightsElem = index + 1;
+
+         char out[32];
+         dSprintf( (char*)out, sizeof(out), "BLENDWEIGHT%d", index );
+         newVar->setConnectName( out );
+         newVar->constNum = index;
+         newVar->arraySize = numElements;
+
+         return newVar;
+      }
+
+
+
    default:
    default:
       break;
       break;
    }
    }
@@ -177,6 +244,8 @@ void ShaderConnectorHLSL::reset()
 
 
    mElementList.setSize( 0 );
    mElementList.setSize( 0 );
    mCurTexElem = 0;
    mCurTexElem = 0;
+   mCurBlendIndicesElem = 0;
+   mCurBlendWeightsElem = 0;
 }
 }
 
 
 void ShaderConnectorHLSL::print( Stream &stream, bool isVertexShader )
 void ShaderConnectorHLSL::print( Stream &stream, bool isVertexShader )
@@ -231,12 +300,23 @@ void ParamsDefHLSL::assignConstantNumbers()
                if (dStrcmp((const char*)var->type, "float4x4") == 0)
                if (dStrcmp((const char*)var->type, "float4x4") == 0)
                {
                {
                   mCurrConst += (4 * var->arraySize);
                   mCurrConst += (4 * var->arraySize);
-               } else {
+               }
+               else
+               {
                   if (dStrcmp((const char*)var->type, "float3x3") == 0)
                   if (dStrcmp((const char*)var->type, "float3x3") == 0)
                   {
                   {
                      mCurrConst += (3 * var->arraySize);
                      mCurrConst += (3 * var->arraySize);
-                  } else {
-                     mCurrConst += var->arraySize;
+                  }
+                  else
+                  {
+                     if (dStrcmp((const char*)var->type, "float4x3") == 0)
+                     {
+                        mCurrConst += (3 * var->arraySize);
+                     }
+                     else
+                     {
+                        mCurrConst += var->arraySize;
+                     }
                   }
                   }
                }
                }
             }
             }

+ 64 - 0
Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp

@@ -33,6 +33,7 @@
 #include "core/util/autoPtr.h"
 #include "core/util/autoPtr.h"
 
 
 #include "lighting/advanced/advancedLightBinManager.h"
 #include "lighting/advanced/advancedLightBinManager.h"
+#include "ts/tsShape.h"
 
 
 LangElement * ShaderFeatureHLSL::setupTexSpaceMat( Vector<ShaderComponent*> &, // componentList
 LangElement * ShaderFeatureHLSL::setupTexSpaceMat( Vector<ShaderComponent*> &, // componentList
                                                    Var **texSpaceMat )
                                                    Var **texSpaceMat )
@@ -2991,3 +2992,66 @@ void ImposterVertFeatureHLSL::determineFeature( Material *material,
       outFeatureData->features.addFeature( MFT_ImposterVert );
       outFeatureData->features.addFeature( MFT_ImposterVert );
 }
 }
 
 
+//****************************************************************************
+// HardwareSkinningFeatureHLSL
+//****************************************************************************
+
+void HardwareSkinningFeatureHLSL::processVert(   Vector<ShaderComponent*> &componentList, 
+                                             const MaterialFeatureData &fd )
+{      
+   MultiLine *meta = new MultiLine;
+
+   Var *inPosition = (Var*)LangElement::find( "inPosition" );
+   Var *inNormal = (Var*)LangElement::find( "inNormal" );
+
+   if ( !inPosition )
+      inPosition = (Var*)LangElement::find( "position" );
+
+   if ( !inNormal )
+      inNormal = (Var*)LangElement::find( "normal" );
+
+   Var* posePos = new Var("posePos", "float3");
+   Var* poseNormal = new Var("poseNormal", "float3");
+   Var* poseMat = new Var("poseMat", "float4x3");
+   Var* poseRotMat = new Var("poseRotMat", "float3x3");
+   Var* nodeTransforms = (Var*)LangElement::find("nodeTransforms");
+
+   if (!nodeTransforms)
+   {
+      nodeTransforms = new Var("nodeTransforms", "float4x3");
+      nodeTransforms->uniform = true;
+      nodeTransforms->arraySize = TSShape::smMaxSkinBones;
+      nodeTransforms->constSortPos = cspPotentialPrimitive;
+   }
+   
+   U32 numIndices = mVertexFormat->getNumBlendIndices();
+   meta->addStatement( new GenOp( "   @ = 0.0;\r\n", new DecOp( posePos ) ) );  
+   meta->addStatement( new GenOp( "   @ = 0.0;\r\n", new DecOp( poseNormal ) ) );
+   meta->addStatement( new GenOp( "   @;\r\n", new DecOp( poseMat ) ) );
+   meta->addStatement(new GenOp("   @;\r\n   int i;\r\n", new DecOp(poseRotMat)));
+
+   for (U32 i=0; i<numIndices; i++)
+   {
+      // NOTE: To keep things simple, we assume all 4 bone indices are used in each element chunk.
+      LangElement* inIndices = (Var*)LangElement::find(String::ToString( "blendIndices%d", i ));
+      LangElement* inWeights = (Var*)LangElement::find(String::ToString( "blendWeight%d", i ));
+       
+      AssertFatal(inIndices && inWeights, "Something went wrong here");
+      AssertFatal(poseMat && nodeTransforms && posePos && inPosition && inWeights && poseNormal && inNormal && poseRotMat, "Something went REALLY wrong here");
+      
+      meta->addStatement( new GenOp( "   for (i=0; i<4; i++) {\r\n" ) );
+         meta->addStatement( new GenOp( "      int poseIdx = int(@[i]);\r\n", inIndices ) );
+         meta->addStatement( new GenOp( "      float poseWeight = @[i];\r\n", inWeights) );
+         meta->addStatement( new GenOp( "      @ = @[poseIdx];\r\n", poseMat, nodeTransforms) );
+         meta->addStatement( new GenOp( "      @ = (float3x3)@;\r\n", poseRotMat, poseMat) );
+         meta->addStatement( new GenOp( "      @ += (mul(float4(@, 1), @)).xyz * poseWeight;\r\n", posePos, inPosition, poseMat) );
+         meta->addStatement( new GenOp( "      @ += (mul(@,@) * poseWeight);\r\n", poseNormal, inNormal, poseRotMat) );
+      meta->addStatement( new GenOp( "   }\r\n" ) );
+   }
+   
+   // Assign new position and normal
+   meta->addStatement( new GenOp( "   @ = @;\r\n", inPosition, posePos ) );
+   meta->addStatement( new GenOp( "   @ = normalize(@);\r\n", inNormal, poseNormal ) );
+
+   output = meta;
+}

+ 13 - 0
Engine/source/shaderGen/HLSL/shaderFeatureHLSL.h

@@ -663,4 +663,17 @@ public:
                                   MaterialFeatureData *outFeatureData );
                                   MaterialFeatureData *outFeatureData );
 };
 };
 
 
+/// Hardware Skinning
+class HardwareSkinningFeatureHLSL : public ShaderFeatureHLSL
+{
+protected:
+
+public:
+
+   virtual void processVert(  Vector<ShaderComponent*> &componentList,
+                              const MaterialFeatureData &fd );
+
+   virtual String getName() { return "Hardware Skinning"; }
+};
+
 #endif // _SHADERGEN_HLSL_SHADERFEATUREHLSL_H_
 #endif // _SHADERGEN_HLSL_SHADERFEATUREHLSL_H_

+ 19 - 0
Engine/source/shaderGen/HLSL/shaderGenHLSL.cpp

@@ -121,6 +121,9 @@ const char* ShaderGenComponentFactoryHLSL::typeToString( GFXDeclType type )
       case GFXDeclType_Float4:
       case GFXDeclType_Float4:
       case GFXDeclType_Color:
       case GFXDeclType_Color:
          return "float4";
          return "float4";
+      
+	  case GFXDeclType_UByte4:
+         return "uint4";
    }
    }
 }
 }
 
 
@@ -174,6 +177,22 @@ ShaderComponent* ShaderGenComponentFactoryHLSL::createVertexInputConnector( cons
          else
          else
             var->setName( String::ToString( "texCoord%d", element.getSemanticIndex() + 1 ) );
             var->setName( String::ToString( "texCoord%d", element.getSemanticIndex() + 1 ) );
       }
       }
+      else if ( element.isSemantic( GFXSemantic::BLENDINDICES ) )
+      {
+         var = vertComp->getIndexedElement( element.getSemanticIndex(), RT_BLENDINDICES );
+         var->setName( String::ToString( "blendIndices%d", element.getSemanticIndex() ) );
+      }
+      else if ( element.isSemantic( GFXSemantic::BLENDWEIGHT ) )
+      {
+         var = vertComp->getIndexedElement( element.getSemanticIndex(), RT_BLENDWEIGHT );
+         var->setName( String::ToString( "blendWeight%d", element.getSemanticIndex() ) );
+      }
+      else if ( element.isSemantic( GFXSemantic::PADDING ) )
+      {
+         var = NULL;
+         //var = vertComp->getIndexedElement( vertComp->getCurTexElem() + element.getSemanticIndex(), RT_TEXCOORD );
+         //var->setName( String::ToString( "pad%d", element.getSemanticIndex() + 1 ) );
+      }
       else
       else
       {
       {
          // Everything else is a texcoord!
          // Everything else is a texcoord!

+ 1 - 1
Engine/source/shaderGen/HLSL/shaderGenHLSLInit.cpp

@@ -100,13 +100,13 @@ void _initShaderGenHLSL( ShaderGen *shaderGen )
 
 
    FEATUREMGR->registerFeature( MFT_ImposterVert, new ImposterVertFeatureHLSL );
    FEATUREMGR->registerFeature( MFT_ImposterVert, new ImposterVertFeatureHLSL );
 
 
-   // Deferred Shading
    FEATUREMGR->registerFeature( MFT_isDeferred, new NamedFeatureHLSL( "Deferred Material" ) );
    FEATUREMGR->registerFeature( MFT_isDeferred, new NamedFeatureHLSL( "Deferred Material" ) );
    FEATUREMGR->registerFeature( MFT_DeferredSpecMap, new DeferredSpecMapHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredSpecMap, new DeferredSpecMapHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredSpecVars, new DeferredSpecVarsHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredSpecVars, new DeferredSpecVarsHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredMatInfoFlags, new DeferredMatInfoFlagsHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredMatInfoFlags, new DeferredMatInfoFlagsHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredEmptySpec, new DeferredEmptySpecHLSL );
    FEATUREMGR->registerFeature( MFT_DeferredEmptySpec, new DeferredEmptySpecHLSL );
    FEATUREMGR->registerFeature( MFT_SkyBox,  new NamedFeatureHLSL( "skybox" ) );
    FEATUREMGR->registerFeature( MFT_SkyBox,  new NamedFeatureHLSL( "skybox" ) );
+   FEATUREMGR->registerFeature( MFT_HardwareSkinning, new HardwareSkinningFeatureHLSL );
 }
 }
 
 
 MODULE_BEGIN( ShaderGenHLSL )
 MODULE_BEGIN( ShaderGenHLSL )

+ 2 - 0
Engine/source/shaderGen/shaderComp.cpp

@@ -32,6 +32,8 @@ ShaderConnector::ShaderConnector()
 {
 {
    mCurTexElem = 0;
    mCurTexElem = 0;
    mName[0] = '\0';
    mName[0] = '\0';
+   mCurBlendIndicesElem = 0;
+   mCurBlendWeightsElem = 0;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------

+ 4 - 0
Engine/source/shaderGen/shaderComp.h

@@ -71,6 +71,8 @@ protected:
    Vector <Var*> mElementList;
    Vector <Var*> mElementList;
 
 
    U32 mCurTexElem;
    U32 mCurTexElem;
+   U32 mCurBlendIndicesElem;
+   U32 mCurBlendWeightsElem;
    U8 mName[32];
    U8 mName[32];
 
 
 public:
 public:
@@ -78,6 +80,8 @@ public:
    ShaderConnector();
    ShaderConnector();
    virtual ~ShaderConnector();
    virtual ~ShaderConnector();
 
 
+   U32 getCurTexElem() { return mCurTexElem; }
+
    ///
    ///
    virtual Var* getElement(   RegisterType type, 
    virtual Var* getElement(   RegisterType type, 
                               U32 numElements = 1, 
                               U32 numElements = 1, 

+ 9 - 2
Engine/source/shaderGen/shaderFeature.h

@@ -99,6 +99,12 @@ protected:
    ///
    ///
    S32 mProcessIndex;
    S32 mProcessIndex;
 
 
+public:
+
+   // TODO: Make this protected and give it a proper API.
+   const GFXVertexFormat *mVertexFormat;
+
+   // TODO: Make this protected and give it a proper API.
    GFXVertexFormat *mInstancingFormat;
    GFXVertexFormat *mInstancingFormat;
 
 
 public:   
 public:   
@@ -139,7 +145,8 @@ public:
    ShaderFeature()
    ShaderFeature()
       :  output( NULL ),
       :  output( NULL ),
          mProcessIndex( 0 ),
          mProcessIndex( 0 ),
-         mInstancingFormat( NULL )
+         mInstancingFormat( NULL ),
+         mVertexFormat( NULL )
    {
    {
    }
    }
 
 
@@ -285,7 +292,7 @@ public:
 
 
    /// Called after processing the vertex and processing the pixel 
    /// Called after processing the vertex and processing the pixel 
    /// to cleanup any temporary structures stored in the feature.
    /// to cleanup any temporary structures stored in the feature.
-   virtual void reset() { output = NULL; mProcessIndex = 0; mInstancingFormat = NULL; }
+   virtual void reset() { output = NULL; mProcessIndex = 0; mInstancingFormat = NULL; mVertexFormat = NULL; }
 
 
    /// A simpler helper function which either finds
    /// A simpler helper function which either finds
    /// the existing local var or creates one.
    /// the existing local var or creates one.

+ 3 - 0
Engine/source/shaderGen/shaderGen.cpp

@@ -265,6 +265,9 @@ void ShaderGen::_processVertFeatures( Vector<GFXShaderMacro> &macros, bool macro
             continue;
             continue;
 
 
          feature->setInstancingFormat( &mInstancingFormat );
          feature->setInstancingFormat( &mInstancingFormat );
+
+         feature->mVertexFormat = mVertexFormat;
+
          feature->processVert( mComponents, mFeatureData );
          feature->processVert( mComponents, mFeatureData );
 
 
          String line;
          String line;

+ 0 - 6
Engine/source/ts/arch/tsMeshIntrinsics.arch.h

@@ -26,19 +26,13 @@
 #if defined(TORQUE_CPU_X86)
 #if defined(TORQUE_CPU_X86)
 # // x86 CPU family implementations
 # // x86 CPU family implementations
 extern void zero_vert_normal_bulk_SSE(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride);
 extern void zero_vert_normal_bulk_SSE(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride);
-extern void m_matF_x_BatchedVertWeightList_SSE(const MatrixF &mat, const dsize_t count, const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch, U8 * const __restrict outPtr, const dsize_t outStride);
-#if (_MSC_VER >= 1500)
-extern void m_matF_x_BatchedVertWeightList_SSE4(const MatrixF &mat, const dsize_t count, const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch, U8 * const __restrict outPtr, const dsize_t outStride);
-#endif
 #
 #
 #elif defined(TORQUE_CPU_PPC)
 #elif defined(TORQUE_CPU_PPC)
 # // PPC CPU family implementations
 # // PPC CPU family implementations
 #  if defined(TORQUE_OS_XENON)
 #  if defined(TORQUE_OS_XENON)
 extern void zero_vert_normal_bulk_X360(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride);
 extern void zero_vert_normal_bulk_X360(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride);
-extern void m_matF_x_BatchedVertWeightList_X360(const MatrixF &mat, const dsize_t count, const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch, U8 * const __restrict outPtr, const dsize_t outStride);
 #  else
 #  else
 extern void zero_vert_normal_bulk_gccvec(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride);
 extern void zero_vert_normal_bulk_gccvec(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride);
-extern void m_matF_x_BatchedVertWeightList_gccvec(const MatrixF &mat, const dsize_t count, const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch, U8 * const __restrict outPtr, const dsize_t outStride);
 #  endif
 #  endif
 #
 #
 #else
 #else

+ 0 - 113
Engine/source/ts/arch/tsMeshIntrinsics.sse.cpp

@@ -67,117 +67,4 @@ void zero_vert_normal_bulk_SSE(const dsize_t count, U8 * __restrict const outPtr
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-void m_matF_x_BatchedVertWeightList_SSE(const MatrixF &mat, 
-                                    const dsize_t count,
-                                    const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch,
-                                    U8 * const __restrict outPtr,
-                                    const dsize_t outStride)
-{
-   const char * __restrict iPtr = reinterpret_cast<const char *>(batch);
-   const dsize_t inStride = sizeof(TSSkinMesh::BatchData::BatchedVertWeight);
-
-   // SSE intrinsic version
-   // Based on: http://www.cortstratton.org/articles/HugiCode.html
-
-   // Load matrix, transposed, into registers
-   MatrixF transMat;
-   mat.transposeTo(transMat);
-   register __m128 sseMat[4];
-
-   sseMat[0] = _mm_loadu_ps(&transMat[0]);
-   sseMat[1] = _mm_loadu_ps(&transMat[4]);
-   sseMat[2] = _mm_loadu_ps(&transMat[8]);
-   sseMat[3] = _mm_loadu_ps(&transMat[12]);
-
-   // mask
-   const __m128 _w_mask = { 1.0f, 1.0f, 1.0f, 0.0f };
-
-   // temp registers
-   register __m128 tempPos;
-   register __m128 tempNrm;
-   register __m128 scratch0;
-   register __m128 scratch1;
-   register __m128 inPos;
-   register __m128 inNrm;
-
-   // pre-populate cache
-   const TSSkinMesh::BatchData::BatchedVertWeight &firstElem = batch[0];
-   for(S32 i = 0; i < 8; i++)
-   {
-      _mm_prefetch(reinterpret_cast<const char *>(iPtr +  inStride * i), _MM_HINT_T0);
-      _mm_prefetch(reinterpret_cast<const char *>(outPtr +  outStride * (i + firstElem.vidx)), _MM_HINT_T0);
-   }
-
-   for(register S32 i = 0; i < count; i++)
-   {
-      const TSSkinMesh::BatchData::BatchedVertWeight &inElem = batch[i];
-      TSMesh::__TSMeshVertexBase *outElem = reinterpret_cast<TSMesh::__TSMeshVertexBase *>(outPtr + inElem.vidx * outStride);
-
-      // process x (hiding the prefetches in the delays)
-      inPos = _mm_load_ps(inElem.vert);
-      inNrm = _mm_load_ps(inElem.normal);
-
-      // prefetch input 
-#define INPUT_PREFETCH_LOOKAHEAD 64
-      const char *prefetchInput = reinterpret_cast<const char *>(batch) + inStride * (i + INPUT_PREFETCH_LOOKAHEAD);
-      _mm_prefetch(prefetchInput, _MM_HINT_T0);
-
-      // propagate the .x elements across the vectors
-      tempPos = _mm_shuffle_ps(inPos, inPos, _MM_SHUFFLE(0, 0, 0, 0));
-      tempNrm = _mm_shuffle_ps(inNrm, inNrm, _MM_SHUFFLE(0, 0, 0, 0));
-
-      // prefetch ouput with half the lookahead distance of the input
-#define OUTPUT_PREFETCH_LOOKAHEAD (INPUT_PREFETCH_LOOKAHEAD >> 1)
-      const char *outPrefetch = reinterpret_cast<const char*>(outPtr) + outStride * (inElem.vidx + OUTPUT_PREFETCH_LOOKAHEAD);
-      _mm_prefetch(outPrefetch, _MM_HINT_T0);
-
-      // mul by column 0
-      tempPos = _mm_mul_ps(tempPos, sseMat[0]);
-      tempNrm = _mm_mul_ps(tempNrm, sseMat[0]);
-
-      // process y
-      scratch0 = _mm_shuffle_ps(inPos, inPos, _MM_SHUFFLE(1, 1, 1, 1));
-      scratch1 = _mm_shuffle_ps(inNrm, inNrm, _MM_SHUFFLE(1, 1, 1, 1));
-
-      scratch0 = _mm_mul_ps(scratch0, sseMat[1]);
-      scratch1 = _mm_mul_ps(scratch1, sseMat[1]);
-
-      tempPos = _mm_add_ps(tempPos, scratch0);
-      tempNrm = _mm_add_ps(tempNrm, scratch1);
-
-
-      // process z
-      scratch0 = _mm_shuffle_ps(inPos, inPos, _MM_SHUFFLE(2, 2, 2, 2));
-      scratch1 = _mm_shuffle_ps(inNrm, inNrm, _MM_SHUFFLE(2, 2, 2, 2));
-
-      scratch0 = _mm_mul_ps(scratch0, sseMat[2]);
-      scratch1 = _mm_mul_ps(scratch1, sseMat[2]);
-
-      tempPos = _mm_add_ps(tempPos, scratch0);
-
-      inNrm = _mm_load_ps(outElem->_normal); //< load normal for accumulation
-      scratch0 = _mm_shuffle_ps(inPos, inPos, _MM_SHUFFLE(3, 3, 3, 3));//< load bone weight across all elements of scratch0
-
-      tempNrm = _mm_add_ps(tempNrm, scratch1);
-
-      scratch0 = _mm_mul_ps(scratch0, _w_mask); //< mask off last
-
-      // Translate the position by adding the 4th column of the matrix to it
-      tempPos = _mm_add_ps(tempPos, sseMat[3]);
-
-      // now multiply by the blend weight, and mask out the W component of both vectors
-      tempPos = _mm_mul_ps(tempPos, scratch0);
-      tempNrm = _mm_mul_ps(tempNrm, scratch0);
-
-      inPos = _mm_load_ps(outElem->_vert);   //< load position for accumulation
-
-      // accumulate with previous values
-      tempNrm = _mm_add_ps(tempNrm, inNrm);
-      tempPos = _mm_add_ps(tempPos, inPos);
-
-      _mm_store_ps(outElem->_vert, tempPos);   //< output position
-      _mm_store_ps(outElem->_normal, tempNrm); //< output normal
-   }
-}
-
 #endif // TORQUE_CPU_X86
 #endif // TORQUE_CPU_X86

+ 0 - 80
Engine/source/ts/arch/tsMeshIntrinsics.sse4.cpp

@@ -25,84 +25,4 @@
 #include "ts/tsMeshIntrinsics.h"
 #include "ts/tsMeshIntrinsics.h"
 #include <smmintrin.h>
 #include <smmintrin.h>
 
 
-void m_matF_x_BatchedVertWeightList_SSE4(const MatrixF &mat, 
-                                    const dsize_t count,
-                                    const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch,
-                                    U8 * const __restrict outPtr,
-                                    const dsize_t outStride)
-{
-   const char * __restrict iPtr = reinterpret_cast<const char *>(batch);
-   const dsize_t inStride = sizeof(TSSkinMesh::BatchData::BatchedVertWeight);
-
-   __m128 sseMat[3];
-   sseMat[0] = _mm_loadu_ps(&mat[0]);
-   sseMat[1] = _mm_loadu_ps(&mat[4]);
-   sseMat[2] = _mm_loadu_ps(&mat[8]);
-
-   // temp registers
-   __m128 inPos, tempPos;
-   __m128 inNrm, tempNrm;
-   __m128 temp0, temp1, temp2, temp3;
-
-   // pre-populate cache
-   const TSSkinMesh::BatchData::BatchedVertWeight &firstElem = batch[0];
-   for(S32 i = 0; i < 8; i++)
-   {
-      _mm_prefetch(reinterpret_cast<const char *>(iPtr +  inStride * i), _MM_HINT_T0);
-      _mm_prefetch(reinterpret_cast<const char *>(outPtr +  outStride * (i + firstElem.vidx)), _MM_HINT_T0);
-   }
-
-   for(S32 i = 0; i < count; i++)
-   {
-      const TSSkinMesh::BatchData::BatchedVertWeight &inElem = batch[i];
-      TSMesh::__TSMeshVertexBase *outElem = reinterpret_cast<TSMesh::__TSMeshVertexBase *>(outPtr + inElem.vidx * outStride);
-
-      // process x (hiding the prefetches in the delays)
-      inPos = _mm_load_ps(inElem.vert);
-      inNrm = _mm_load_ps(inElem.normal);
-
-      // prefetch input 
-#define INPUT_PREFETCH_LOOKAHEAD 64
-      const char *prefetchInput = reinterpret_cast<const char *>(batch) + inStride * (i + INPUT_PREFETCH_LOOKAHEAD);
-      _mm_prefetch(prefetchInput, _MM_HINT_T0);
-
-      // prefetch ouput with half the lookahead distance of the input
-#define OUTPUT_PREFETCH_LOOKAHEAD (INPUT_PREFETCH_LOOKAHEAD >> 1)
-      const char *outPrefetch = reinterpret_cast<const char*>(outPtr) + outStride * (inElem.vidx + OUTPUT_PREFETCH_LOOKAHEAD);
-      _mm_prefetch(outPrefetch, _MM_HINT_T0);
-
-      // Multiply position
-      tempPos = _mm_dp_ps(inPos, sseMat[0], 0xF1);
-      temp0 = _mm_dp_ps(inPos, sseMat[1], 0xF2);
-      temp1 = _mm_dp_ps(inPos, sseMat[2], 0xF4);
-      
-      temp0 = _mm_or_ps(temp0, temp1);
-      tempPos = _mm_or_ps(tempPos, temp0);
-
-      // Multiply normal
-      tempNrm = _mm_dp_ps(inNrm, sseMat[0], 0x71);
-      temp2 = _mm_dp_ps(inNrm, sseMat[1], 0x72);
-      temp3 = _mm_dp_ps(inNrm, sseMat[2], 0x74);
-
-      temp2 = _mm_or_ps(temp2, temp3);
-      tempNrm = _mm_or_ps(tempNrm, temp2);
-
-      // Load bone weight and multiply
-      temp3 = _mm_shuffle_ps(inPos, inPos, _MM_SHUFFLE(3, 3, 3, 3));
-
-      tempPos = _mm_mul_ps(tempPos, temp3);
-      tempNrm = _mm_mul_ps(tempNrm, temp3);
-
-      inPos = _mm_load_ps(outElem->_vert);   //< load position for accumulation
-      inNrm = _mm_load_ps(outElem->_normal); //< load normal for accumulation
-
-      // accumulate with previous values
-      tempNrm = _mm_add_ps(tempNrm, inNrm);
-      tempPos = _mm_add_ps(tempPos, inPos);
-
-      _mm_store_ps(outElem->_vert, tempPos);   //< output position
-      _mm_store_ps(outElem->_normal, tempNrm); //< output normal
-   }
-}
-
 #endif // TORQUE_CPU_X86
 #endif // TORQUE_CPU_X86

+ 1 - 0
Engine/source/ts/loader/appMesh.cpp

@@ -157,6 +157,7 @@ TSMesh* AppMesh::constructTSMesh()
 
 
    // Finish initializing the shape
    // Finish initializing the shape
    tsmesh->setFlags(flags);
    tsmesh->setFlags(flags);
+   tsmesh->updateMeshFlags();
    tsmesh->computeBounds();
    tsmesh->computeBounds();
    tsmesh->numFrames = numFrames;
    tsmesh->numFrames = numFrames;
    tsmesh->numMatFrames = numMatFrames;
    tsmesh->numMatFrames = numMatFrames;

+ 1 - 0
Engine/source/ts/loader/tsShapeLoader.cpp

@@ -1229,6 +1229,7 @@ void TSShapeLoader::install()
    shape->tubeRadius = shape->radius;
    shape->tubeRadius = shape->radius;
 
 
    shape->init();
    shape->init();
+   shape->finalizeEditable();
 }
 }
 
 
 void TSShapeLoader::computeBounds(Box3F& bounds)
 void TSShapeLoader::computeBounds(Box3F& bounds)

+ 8 - 1
Engine/source/ts/tsCollision.cpp

@@ -1459,10 +1459,17 @@ void TSMesh::prepOpcodeCollision()
    AssertFatal( (curIts - its) == mi->GetNbTriangles(), "Triangle count mismatch!" );
    AssertFatal( (curIts - its) == mi->GetNbTriangles(), "Triangle count mismatch!" );
 
 
    for( S32 i = 0; i < mi->GetNbVertices(); i++ )
    for( S32 i = 0; i < mi->GetNbVertices(); i++ )
+   {
       if( mVertexData.isReady() )
       if( mVertexData.isReady() )
-         pts[i].Set( mVertexData[i].vert().x, mVertexData[i].vert().y, mVertexData[i].vert().z );
+      {
+         const __TSMeshVertexBase &vertData = mVertexData.getBase(i);
+         pts[i].Set( vertData.vert().x, vertData.vert().y, vertData.vert().z );
+      }
       else
       else
+      {
          pts[i].Set( verts[i].x, verts[i].y, verts[i].z );
          pts[i].Set( verts[i].x, verts[i].y, verts[i].z );
+      }
+   }
 
 
    mi->SetPointers( its, pts );
    mi->SetPointers( its, pts );
 
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 340 - 370
Engine/source/ts/tsMesh.cpp


+ 238 - 141
Engine/source/ts/tsMesh.h

@@ -96,65 +96,53 @@ typedef GFX360MemVertexBufferHandle<__NullVertexStruct> TSVertexBufferHandle;
 typedef GFXVertexBufferDataHandle TSVertexBufferHandle;
 typedef GFXVertexBufferDataHandle TSVertexBufferHandle;
 #endif
 #endif
 
 
+class TSMesh;
+class TSShapeAlloc;
 
 
-///
-class TSMesh
+/// @name Vertex format serialization
+/// {
+struct TSBasicVertexFormat
 {
 {
-   friend class TSShape;
-  public:
-   struct TSMeshVertexArray;
-  protected:
-
-   U32 meshType;
-   Box3F mBounds;
-   Point3F mCenter;
-   F32 mRadius;
-   F32 mVisibility;
-   bool mDynamic;
-
-   const GFXVertexFormat *mVertexFormat;
+   S16 texCoordOffset;
+   S16 boneOffset;
+   S16 colorOffset;
+   S16 numBones;
+   S16 vertexSize;
 
 
-   U32 mVertSize;
+   TSBasicVertexFormat();
+   TSBasicVertexFormat(TSMesh *mesh);
+   void getFormat(GFXVertexFormat &fmt);
+   void calculateSize();
 
 
-   TSVertexBufferHandle mVB;
-   GFXPrimitiveBufferHandle mPB;
+   void writeAlloc(TSShapeAlloc* alloc);
+   void readAlloc(TSShapeAlloc* alloc);
 
 
-   void _convertToAlignedMeshData( TSMeshVertexArray &vertexData, const Vector<Point3F> &_verts, const Vector<Point3F> &_norms );
-   void _createVBIB( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
+   void addMeshRequirements(TSMesh *mesh);
+};
+/// }
 
 
-  public:
+///
+class TSMesh
+{
+   friend class TSShape;
+public:
 
 
-   enum
+   /// Helper class for a freeable vector
+   template<class T>
+   class FreeableVector : public Vector<T>
    {
    {
-      /// types...
-      StandardMeshType = 0,
-      SkinMeshType     = 1,
-      DecalMeshType    = 2,
-      SortedMeshType   = 3,
-      NullMeshType     = 4,
-      TypeMask = StandardMeshType|SkinMeshType|DecalMeshType|SortedMeshType|NullMeshType,
+   public:
+      bool free_memory() { return Vector<T>::resize(0); }
 
 
-      /// flags (stored with meshType)...
-      Billboard = BIT(31), HasDetailTexture = BIT(30),
-      BillboardZAxis = BIT(29), UseEncodedNormals = BIT(28),
-      FlagMask = Billboard|BillboardZAxis|HasDetailTexture|UseEncodedNormals
+      FreeableVector<T>& operator=(const Vector<T>& p) { Vector<T>::operator=(p); return *this; }
+      FreeableVector<T>& operator=(const FreeableVector<T>& p) { Vector<T>::operator=(p); return *this; }
    };
    };
 
 
-   U32 getMeshType() const { return meshType & TypeMask; }
-   void setFlags(U32 flag) { meshType |= flag; }
-   void clearFlags(U32 flag) { meshType &= ~flag; }
-   U32 getFlags( U32 flag = 0xFFFFFFFF ) const { return meshType & flag; }
-
-   const Point3F* getNormals( S32 firstVert );
+   /// @name Aligned Vertex Data 
+   /// {
 
 
-   S32 parentMesh; ///< index into shapes mesh list
-   S32 numFrames;
-   S32 numMatFrames;
-   S32 vertsPerFrame;
+#pragma pack(1)
 
 
-   /// @name Aligned Vertex Data 
-   /// @{
-   #pragma pack(1)
    struct __TSMeshVertexBase
    struct __TSMeshVertexBase
    {
    {
       Point3F _vert;
       Point3F _vert;
@@ -173,23 +161,40 @@ class TSMesh
       void tangent(const Point4F &t) { _tangent = t.asPoint3F(); _tangentW = t.w; }
       void tangent(const Point4F &t) { _tangent = t.asPoint3F(); _tangentW = t.w; }
 
 
       const Point2F &tvert() const { return _tvert; }
       const Point2F &tvert() const { return _tvert; }
-      void tvert(const Point2F &tv) { _tvert = tv;}
-
-      // Don't call these unless it's actually a __TSMeshVertex_3xUVColor, for real.
-      // We don't want a vftable for virtual methods.
-      Point2F &tvert2() const { return *reinterpret_cast<Point2F *>(reinterpret_cast<U8 *>(const_cast<__TSMeshVertexBase *>(this)) + 0x30); }
-      void tvert2(const Point2F &tv) { (*reinterpret_cast<Point2F *>(reinterpret_cast<U8 *>(this) + 0x30)) = tv; }
-
-      GFXVertexColor &color() const { return *reinterpret_cast<GFXVertexColor *>(reinterpret_cast<U8 *>(const_cast<__TSMeshVertexBase *>(this)) + 0x38); }
-      void color(const GFXVertexColor &c) { (*reinterpret_cast<GFXVertexColor *>(reinterpret_cast<U8 *>(this) + 0x38)) = c; }
+      void tvert(const Point2F &tv) { _tvert = tv; }
    };
    };
 
 
-   struct __TSMeshVertex_3xUVColor : public __TSMeshVertexBase
+   struct __TSMeshVertex_3xUVColor
    {
    {
       Point2F _tvert2;
       Point2F _tvert2;
       GFXVertexColor _color;
       GFXVertexColor _color;
-      F32 _tvert3;  // Unused, but needed for alignment purposes
+
+      const Point2F &tvert2() const { return _tvert2; }
+      void tvert2(const Point2F& c) { _tvert2 = c; }
+
+      const GFXVertexColor &color() const { return _color; }
+      void color(const GFXVertexColor &c) { _color = c; }
    };
    };
+
+   struct __TSMeshIndex_List {
+      U8 x;
+      U8 y;
+      U8 z;
+      U8 w;
+   };
+
+   struct __TSMeshVertex_BoneData
+   {
+      __TSMeshIndex_List _indexes;
+      Point4F _weights;
+
+      const __TSMeshIndex_List &index() const { return _indexes; }
+      void index(const __TSMeshIndex_List& c) { _indexes = c; }
+
+      const Point4F &weight() const { return _weights; }
+      void weight(const Point4F &w) { _weights = w; }
+   };
+
 #pragma pack()
 #pragma pack()
 
 
    struct TSMeshVertexArray
    struct TSMeshVertexArray
@@ -197,53 +202,136 @@ class TSMesh
    protected:
    protected:
       U8 *base;
       U8 *base;
       dsize_t vertSz;
       dsize_t vertSz;
-      bool vertexDataReady;
       U32 numElements;
       U32 numElements;
 
 
+      U32 colorOffset;
+      U32 boneOffset;
+
+      bool vertexDataReady;
+      bool ownsData;
+
    public:
    public:
-      TSMeshVertexArray() : base(NULL), vertexDataReady(false), numElements(0) {}
-      virtual ~TSMeshVertexArray() { set(NULL, 0, 0); }
+      TSMeshVertexArray() : base(NULL), numElements(0), colorOffset(0), boneOffset(0), vertexDataReady(false), ownsData(false) {}
+      virtual ~TSMeshVertexArray() { set(NULL, 0, 0, 0, 0); }
+
+      virtual void set(void *b, dsize_t s, U32 n, S32 inColorOffset, S32 inBoneOffset, bool nowOwnsData = true)
+      {
+         if (base && ownsData)
+            dFree_aligned(base);
+         base = reinterpret_cast<U8 *>(b);
+         vertSz = s;
+         numElements = n;
+         colorOffset = inColorOffset >= 0 ? inColorOffset : 0;
+         boneOffset = inBoneOffset >= 0 ? inBoneOffset : 0;
+         ownsData = nowOwnsData;
+      }
+
+      /// Gets pointer to __TSMeshVertexBase for vertex idx
+      __TSMeshVertexBase &getBase(int idx) const
+      {
+         AssertFatal(idx < numElements, "Out of bounds access!"); return *reinterpret_cast<__TSMeshVertexBase *>(base + (idx * vertSz));
+      }
+
+      /// Gets pointer to __TSMeshVertex_3xUVColor for vertex idx
+      __TSMeshVertex_3xUVColor &getColor(int idx) const
+      {
+         AssertFatal(idx < numElements, "Out of bounds access!"); return *reinterpret_cast<__TSMeshVertex_3xUVColor *>(base + (idx * vertSz) + colorOffset);
+      }
+
+      /// Gets pointer to __TSMeshVertex_BoneData for vertex idx, additionally offsetted by subBoneList 
+      __TSMeshVertex_BoneData &getBone(int idx, int subBoneList) const
+      {
+         AssertFatal(idx < numElements, "Out of bounds access!"); return *reinterpret_cast<__TSMeshVertex_BoneData *>(base + (idx * vertSz) + boneOffset + (sizeof(__TSMeshVertex_BoneData) * subBoneList));
+      }
 
 
-      virtual void set(void *b, dsize_t s, U32 n, bool autoFree = true ) 
+      /// Returns base address of vertex data
+      __TSMeshVertexBase *address() const
       {
       {
-         if(base && autoFree) 
-            dFree_aligned(base); 
-         base = reinterpret_cast<U8 *>(b); 
-         vertSz = s; 
-         numElements = n; 
+         return reinterpret_cast<__TSMeshVertexBase *>(base);
       }
       }
 
 
-      // Vector-like interface
-      __TSMeshVertexBase &operator[](S32 idx) const { AssertFatal(idx < numElements, "Out of bounds access!"); return *reinterpret_cast<__TSMeshVertexBase *>(base + idx * vertSz); }
-      __TSMeshVertexBase *address() const { return reinterpret_cast<__TSMeshVertexBase *>(base); }
       U32 size() const { return numElements; }
       U32 size() const { return numElements; }
       dsize_t mem_size() const { return numElements * vertSz; }
       dsize_t mem_size() const { return numElements * vertSz; }
       dsize_t vertSize() const { return vertSz; }
       dsize_t vertSize() const { return vertSz; }
       bool isReady() const { return vertexDataReady; }
       bool isReady() const { return vertexDataReady; }
       void setReady(bool r) { vertexDataReady = r; }
       void setReady(bool r) { vertexDataReady = r; }
+
+      U8* getPtr() { return base; }
+
+      inline U32 getColorOffset() const { return colorOffset; }
+      inline U32 getBoneOffset() const { return boneOffset; }
    };
    };
 
 
-   bool mHasColor;
-   bool mHasTVert2;
+protected:
 
 
-   TSMeshVertexArray mVertexData;
-   dsize_t mNumVerts;
-   virtual void convertToAlignedMeshData();
-   /// @}
+   U32 meshType;
+   Box3F mBounds;
+   Point3F mCenter;
+   F32 mRadius;
+   F32 mVisibility;
 
 
-   /// @name Vertex data
-   /// @{
+   const GFXVertexFormat *mVertexFormat;
 
 
-   template<class T>
-   class FreeableVector : public Vector<T>
+   TSMesh *parentMeshObject; ///< Current parent object instance
+
+   U32 mPrimBufferOffset;
+
+   GFXVertexBufferDataHandle mVB;
+   GFXPrimitiveBufferHandle mPB;
+
+public:
+
+   S32 parentMesh; ///< index into shapes mesh list
+   S32 numFrames;
+   S32 numMatFrames;
+   S32 vertsPerFrame;
+
+   U32 mVertOffset;
+   U32 mVertSize;
+
+protected:
+
+   void _convertToVertexData(TSMeshVertexArray &outArray, const Vector<Point3F> &_verts, const Vector<Point3F> &_norms);
+
+  public:
+
+   enum
    {
    {
-   public:
-      bool free_memory() { return Vector<T>::resize(0); }
+      /// types...
+      StandardMeshType = 0,
+      SkinMeshType     = 1,
+      DecalMeshType    = 2,
+      SortedMeshType   = 3,
+      NullMeshType     = 4,
+      TypeMask = StandardMeshType|SkinMeshType|DecalMeshType|SortedMeshType|NullMeshType,
 
 
-      FreeableVector<T>& operator=(const Vector<T>& p) { Vector<T>::operator=(p); return *this; }
-      FreeableVector<T>& operator=(const FreeableVector<T>& p) { Vector<T>::operator=(p); return *this; }
+      /// flags (stored with meshType)...
+      Billboard = BIT(31), HasDetailTexture = BIT(30),
+      BillboardZAxis = BIT(29), UseEncodedNormals = BIT(28),
+      HasColor = BIT(27), HasTVert2 = BIT(26),
+      FlagMask = Billboard|BillboardZAxis|HasDetailTexture|UseEncodedNormals|HasColor|HasTVert2
    };
    };
 
 
+   U32 getMeshType() const { return meshType & TypeMask; }
+   U32 getHasColor() const { return colors.size() > 0 || meshType & HasColor; }
+   U32 getHasTVert2() const { return tverts2.size() > 0 || meshType & HasTVert2; }
+   void setFlags(U32 flag) { meshType |= flag; }
+   void clearFlags(U32 flag) { meshType &= ~flag; }
+   U32 getFlags( U32 flag = 0xFFFFFFFF ) const { return meshType & flag; }
+
+   const Point3F* getNormals( S32 firstVert );
+
+   TSMeshVertexArray mVertexData;
+   U32 mNumVerts; ///< Number of verts allocated in main vertex buffer
+
+   virtual void convertToVertexData();
+
+   virtual void copySourceVertexDataFrom(const TSMesh* srcMesh);
+   /// @}
+
+   /// @name Vertex data
+   /// @{
+
    FreeableVector<Point3F> verts;
    FreeableVector<Point3F> verts;
    FreeableVector<Point3F> norms;
    FreeableVector<Point3F> norms;
    FreeableVector<Point2F> tverts;
    FreeableVector<Point2F> tverts;
@@ -279,16 +367,16 @@ class TSMesh
 
 
    /// This is used by sgShadowProjector to render the 
    /// This is used by sgShadowProjector to render the 
    /// mesh directly, skipping the render manager.
    /// mesh directly, skipping the render manager.
-   virtual void render( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
+   virtual void render( TSVertexBufferHandle &vb );
    void innerRender( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
    void innerRender( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
    virtual void render( TSMaterialList *, 
    virtual void render( TSMaterialList *, 
                         const TSRenderState &data,
                         const TSRenderState &data,
                         bool isSkinDirty,
                         bool isSkinDirty,
                         const Vector<MatrixF> &transforms, 
                         const Vector<MatrixF> &transforms, 
                         TSVertexBufferHandle &vertexBuffer,
                         TSVertexBufferHandle &vertexBuffer,
-                        GFXPrimitiveBufferHandle &primitiveBuffer );
+                        const char *meshName);
 
 
-   void innerRender( TSMaterialList *, const TSRenderState &data, TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
+   void innerRender( TSMaterialList *, const TSRenderState &data, TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb, const char *meshName );
 
 
    /// @}
    /// @}
 
 
@@ -326,12 +414,13 @@ class TSMesh
    static const Point3F& decodeNormal( U8 ncode ) { return smU8ToNormalTable[ncode]; }
    static const Point3F& decodeNormal( U8 ncode ) { return smU8ToNormalTable[ncode]; }
    /// @}
    /// @}
 
 
+   virtual U32 getMaxBonesPerVert() { return 0; }
+
    /// persist methods...
    /// persist methods...
    virtual void assemble( bool skip );
    virtual void assemble( bool skip );
    static TSMesh* assembleMesh( U32 meshType, bool skip );
    static TSMesh* assembleMesh( U32 meshType, bool skip );
    virtual void disassemble();
    virtual void disassemble();
 
 
-   void createVBIB();
    void createTangents(const Vector<Point3F> &_verts, const Vector<Point3F> &_norms);
    void createTangents(const Vector<Point3F> &_verts, const Vector<Point3F> &_norms);
    void findTangent( U32 index1, 
    void findTangent( U32 index1, 
                      U32 index2, 
                      U32 index2, 
@@ -350,6 +439,9 @@ class TSMesh
    /// have less that this count of verts.
    /// have less that this count of verts.
    static S32 smMaxInstancingVerts;
    static S32 smMaxInstancingVerts;
 
 
+   /// Default node transform for standard meshes which have blend indices
+   static MatrixF smDummyNodeTransform;
+
    /// convert primitives on load...
    /// convert primitives on load...
    void convertToTris(const TSDrawPrimitive *primitivesIn, const S32 *indicesIn,
    void convertToTris(const TSDrawPrimitive *primitivesIn, const S32 *indicesIn,
                       S32 numPrimIn, S32 & numPrimOut, S32 & numIndicesOut,
                       S32 numPrimIn, S32 & numPrimOut, S32 & numIndicesOut,
@@ -361,6 +453,14 @@ class TSMesh
                               S32 numPrimIn, S32 &numPrimOut, S32 &numIndicesOut,
                               S32 numPrimIn, S32 &numPrimOut, S32 &numIndicesOut,
                               TSDrawPrimitive *primitivesOut, S32 *indicesOut) const;
                               TSDrawPrimitive *primitivesOut, S32 *indicesOut) const;
 
 
+   /// Moves vertices from the vertex buffer back into the split vert lists, unless verts already exist
+   virtual void makeEditable();
+
+   /// Clears split vertex lists
+   virtual void clearEditable();
+
+   void updateMeshFlags();
+
    /// methods used during assembly to share vertexand other info
    /// methods used during assembly to share vertexand other info
    /// between meshes (and for skipping detail levels on load)
    /// between meshes (and for skipping detail levels on load)
    S32* getSharedData32( S32 parentMesh, S32 size, S32 **source, bool skip );
    S32* getSharedData32( S32 parentMesh, S32 size, S32 **source, bool skip );
@@ -402,6 +502,9 @@ class TSMesh
    bool buildPolyListOpcode( const S32 od, AbstractPolyList *polyList, const Box3F &nodeBox, TSMaterialList *materials );
    bool buildPolyListOpcode( const S32 od, AbstractPolyList *polyList, const Box3F &nodeBox, TSMaterialList *materials );
    bool castRayOpcode( const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials );
    bool castRayOpcode( const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials );
 
 
+   void dumpPrimitives(U32 startVertex, U32 startIndex, GFXPrimitive *piArray, U16* ibIndices);
+   virtual U32 getNumVerts();
+
    static const F32 VISIBILITY_EPSILON; 
    static const F32 VISIBILITY_EPSILON; 
 };
 };
 
 
@@ -413,7 +516,7 @@ public:
    {
    {
       enum Constants
       enum Constants
       {
       {
-         maxBonePerVert = 16,  // Abitrarily chosen
+         maxBonePerVert = 16,  // Assumes a maximum of 4 blocks of bone indices for HW skinning
       };
       };
 
 
       /// @name Batch by vertex
       /// @name Batch by vertex
@@ -441,48 +544,6 @@ public:
       Vector<BatchedVertex> vertexBatchOperations;
       Vector<BatchedVertex> vertexBatchOperations;
       /// @}
       /// @}
 
 
-      /// @name Batch by Bone Transform
-      /// These are used for batches where each element is a bone transform,
-      /// and verts/normals are batch transformed against each element
-      /// @{
-
-
-      #pragma pack(1)
-
-      dALIGN(
-
-      struct BatchedVertWeight
-      {
-         Point3F vert;   // Do not change the ordering of these members
-         F32 weight;
-         Point3F normal;
-         S32 vidx;
-      }
-
-      ); // dALIGN
-
-      #pragma pack()
-
-      struct BatchedTransform
-      {
-      public:
-         BatchedVertWeight *alignedMem;
-         dsize_t numElements;
-         Vector<BatchedVertWeight> *_tmpVec;
-
-         BatchedTransform() : alignedMem(NULL), numElements(0), _tmpVec(NULL) {}
-         virtual ~BatchedTransform() 
-         { 
-            if(alignedMem) 
-               dFree_aligned(alignedMem); 
-            alignedMem = NULL; 
-            SAFE_DELETE(_tmpVec);
-         }
-      };
-      SparseArray<BatchedTransform> transformBatchOperations;
-      Vector<S32> transformKeys;
-      /// @}
-
       // # = num bones
       // # = num bones
       Vector<S32> nodeIndex;
       Vector<S32> nodeIndex;
       Vector<MatrixF> initialTransforms;
       Vector<MatrixF> initialTransforms;
@@ -490,36 +551,62 @@ public:
       // # = numverts
       // # = numverts
       Vector<Point3F> initialVerts;
       Vector<Point3F> initialVerts;
       Vector<Point3F> initialNorms;
       Vector<Point3F> initialNorms;
+
+      bool initialized;
+
+      BatchData() : initialized(false) { ; }
    };
    };
 
 
    /// This method will build the batch operations and prepare the BatchData
    /// This method will build the batch operations and prepare the BatchData
    /// for use.
    /// for use.
-   void createBatchData();
-   virtual void convertToAlignedMeshData();
+   void createSkinBatchData();
+
+   /// Inserts transform indices and weights into vertex data
+   void setupVertexTransforms();
+
+   /// Returns maximum bones used per vertex
+   virtual U32 getMaxBonesPerVert();
+
+   virtual void convertToVertexData();
+   virtual void copySourceVertexDataFrom(const TSMesh* srcMesh);
+
+   void printVerts();
+
+   void addWeightsFromVertexBuffer();
+
+   void makeEditable();
+   void clearEditable();
 
 
 public:
 public:
    typedef TSMesh Parent;
    typedef TSMesh Parent;
+   
+   /// @name Vertex tuples
+   /// {
+   FreeableVector<F32> weight;      ///< blend weight
+   FreeableVector<S32> boneIndex;   ///< Maps from mesh node to bone in shape
+   FreeableVector<S32> vertexIndex; ///< index of affected vertex
+   /// }
+
+   /// Maximum number of bones referenced by this skin mesh
+   S32 maxBones;
 
 
    /// Structure containing data needed to batch skinning
    /// Structure containing data needed to batch skinning
    BatchData batchData;
    BatchData batchData;
-   bool batchDataInitialized;
-   
-   /// vectors that define the vertex, weight, bone tuples
-   Vector<F32> weight;
-   Vector<S32> boneIndex;
-   Vector<S32> vertexIndex;
 
 
    /// set verts and normals...
    /// set verts and normals...
-   void updateSkin( const Vector<MatrixF> &transforms, TSVertexBufferHandle &instanceVB, GFXPrimitiveBufferHandle &instancePB );
+   void updateSkinBuffer( const Vector<MatrixF> &transforms, U8 *buffer );
+
+   /// update bone transforms for this mesh
+   void updateSkinBones( const Vector<MatrixF> &transforms, Vector<MatrixF>& destTransforms );
 
 
    // render methods..
    // render methods..
-   void render( TSVertexBufferHandle &instanceVB, GFXPrimitiveBufferHandle &instancePB );
+   void render( TSVertexBufferHandle &instanceVB );
    void render(   TSMaterialList *, 
    void render(   TSMaterialList *, 
                   const TSRenderState &data,
                   const TSRenderState &data,
                   bool isSkinDirty,
                   bool isSkinDirty,
                   const Vector<MatrixF> &transforms, 
                   const Vector<MatrixF> &transforms, 
                   TSVertexBufferHandle &vertexBuffer,
                   TSVertexBufferHandle &vertexBuffer,
-                  GFXPrimitiveBufferHandle &primitiveBuffer );
+                  const char *meshName );
 
 
    // collision methods...
    // collision methods...
    bool buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials );
    bool buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials );
@@ -532,6 +619,14 @@ public:
    void assemble( bool skip );
    void assemble( bool skip );
    void disassemble();
    void disassemble();
 
 
+   /// Helper method to add a blend tuple for a vertex
+   inline void addWeightForVert(U32 vi, U32 bi, F32 w)
+   {
+      weight.push_back(w);
+      boneIndex.push_back(bi);
+      vertexIndex.push_back(vi);
+   }
+
    /// variables used during assembly (for skipping mesh detail levels
    /// variables used during assembly (for skipping mesh detail levels
    /// on load and for sharing verts between meshes)
    /// on load and for sharing verts between meshes)
    static Vector<MatrixF*> smInitTransformList;
    static Vector<MatrixF*> smInitTransformList;
@@ -540,6 +635,8 @@ public:
    static Vector<F32*>     smWeightList;
    static Vector<F32*>     smWeightList;
    static Vector<S32*>     smNodeIndexList;
    static Vector<S32*>     smNodeIndexList;
 
 
+   static bool smDebugSkinVerts;
+
    TSSkinMesh();
    TSSkinMesh();
 };
 };
 
 

+ 30 - 14
Engine/source/ts/tsMeshFit.cpp

@@ -282,7 +282,7 @@ void MeshFit::addSourceMesh( const TSShape::Object& obj, const TSMesh* mesh )
    S32 count, stride;
    S32 count, stride;
    U8* pVert;
    U8* pVert;
 
 
-   if ( mesh->mVertexData.isReady() )
+   if ( mesh->mVertexData.isReady() && mesh->verts.size() == 0 )
    {
    {
       count = mesh->mVertexData.size();
       count = mesh->mVertexData.size();
       stride = mesh->mVertexData.vertSize();
       stride = mesh->mVertexData.vertSize();
@@ -327,8 +327,6 @@ TSMesh* MeshFit::createTriMesh( F32* verts, S32 numVerts, U32* indices, S32 numT
    mesh->numMatFrames = 1;
    mesh->numMatFrames = 1;
    mesh->vertsPerFrame = numVerts;
    mesh->vertsPerFrame = numVerts;
    mesh->setFlags(0);
    mesh->setFlags(0);
-   mesh->mHasColor = false;
-   mesh->mHasTVert2 = false;
    mesh->mNumVerts = numVerts;
    mesh->mNumVerts = numVerts;
 
 
    mesh->indices.reserve( numTris * 3 );
    mesh->indices.reserve( numTris * 3 );
@@ -406,12 +404,28 @@ void MeshFit::addBox( const Point3F& sides, const MatrixF& mat )
    if ( !mesh )
    if ( !mesh )
       return;
       return;
 
 
-   for ( S32 i = 0; i < mesh->mVertexData.size(); i++ )
+   if (mesh->verts.size() > 0)
+   {
+      for (S32 i = 0; i < mesh->verts.size(); i++)
+      {
+         Point3F v = mesh->verts[i];
+         v.convolve(sides);
+         mesh->verts[i] = v;
+      }
+
+      mesh->mVertexData.setReady(false);
+   }
+   else
    {
    {
-      Point3F v = mesh->mVertexData[i].vert();
-      v.convolve( sides );
-      mesh->mVertexData[i].vert( v );
+      for (S32 i = 0; i < mesh->mVertexData.size(); i++)
+      {
+         TSMesh::__TSMeshVertexBase &vdata = mesh->mVertexData.getBase(i);
+         Point3F v = vdata.vert();
+         v.convolve(sides);
+         vdata.vert(v);
+      }
    }
    }
+
    mesh->computeBounds();
    mesh->computeBounds();
 
 
    mMeshes.increment();
    mMeshes.increment();
@@ -437,8 +451,9 @@ void MeshFit::addSphere( F32 radius, const Point3F& center )
 
 
    for ( S32 i = 0; i < mesh->mVertexData.size(); i++ )
    for ( S32 i = 0; i < mesh->mVertexData.size(); i++ )
    {
    {
-      Point3F v = mesh->mVertexData[i].vert();
-      mesh->mVertexData[i].vert( v * radius );
+      TSMesh::__TSMeshVertexBase &vdata = mesh->mVertexData.getBase(i);
+      Point3F v = vdata.vert();
+      vdata.vert( v * radius );
    }
    }
    mesh->computeBounds();
    mesh->computeBounds();
 
 
@@ -470,9 +485,9 @@ void MeshFit::addCapsule( F32 radius, F32 height, const MatrixF& mat )
    F32 offset = ( height / ( 2 * radius ) ) - 0.5f;
    F32 offset = ( height / ( 2 * radius ) ) - 0.5f;
    for ( S32 i = 0; i < mesh->mVertexData.size(); i++ )
    for ( S32 i = 0; i < mesh->mVertexData.size(); i++ )
    {
    {
-      Point3F v = mesh->mVertexData[i].vert();
+      Point3F v = mesh->mVertexData.getBase(i).vert();
       v.y += ( ( v.y > 0 ) ? offset : -offset );
       v.y += ( ( v.y > 0 ) ? offset : -offset );
-      mesh->mVertexData[i].vert( v * radius );
+      mesh->mVertexData.getBase(i).vert( v * radius );
    }
    }
    mesh->computeBounds();
    mesh->computeBounds();
 
 
@@ -784,13 +799,14 @@ DefineTSShapeConstructorMethod( addPrimitive, bool, ( const char* meshName, cons
    MatrixF mat( txfm.getMatrix() );
    MatrixF mat( txfm.getMatrix() );
 
 
    // Transform the mesh vertices
    // Transform the mesh vertices
-   if ( mesh->mVertexData.isReady() )
+   if ( mesh->mVertexData.isReady() && mesh->verts.size() == 0 )
    {
    {
       for (S32 i = 0; i < mesh->mVertexData.size(); i++)
       for (S32 i = 0; i < mesh->mVertexData.size(); i++)
       {
       {
+         TSMesh::__TSMeshVertexBase &vdata = mesh->mVertexData.getBase(i);
          Point3F v;
          Point3F v;
-         mat.mulP( mesh->mVertexData[i].vert(), &v );
-         mesh->mVertexData[i].vert( v );
+         mat.mulP( vdata.vert(), &v );
+         vdata.vert( v );
       }
       }
    }
    }
    else
    else

+ 0 - 39
Engine/source/ts/tsMeshIntrinsics.cpp

@@ -26,7 +26,6 @@
 
 
 
 
 void (*zero_vert_normal_bulk)(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride) = NULL;
 void (*zero_vert_normal_bulk)(const dsize_t count, U8 * __restrict const outPtr, const dsize_t outStride) = NULL;
-void (*m_matF_x_BatchedVertWeightList)(const MatrixF &mat, const dsize_t count, const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch, U8 * const __restrict outPtr, const dsize_t outStride) = NULL;
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Default C++ Implementations (pretty slow)
 // Default C++ Implementations (pretty slow)
@@ -47,33 +46,6 @@ void zero_vert_normal_bulk_C(const dsize_t count, U8 * __restrict const outPtr,
    }
    }
 }
 }
 
 
-//------------------------------------------------------------------------------
-
-void m_matF_x_BatchedVertWeightList_C(const MatrixF &mat, 
-                                    const dsize_t count,
-                                    const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch,
-                                    U8 * const __restrict outPtr,
-                                    const dsize_t outStride)
-{
-   const register MatrixF m = mat;
-
-   register Point3F tempPt;
-   register Point3F tempNrm;
-
-   for(register S32 i = 0; i < count; i++)
-   {
-      const TSSkinMesh::BatchData::BatchedVertWeight &inElem = batch[i];
-
-      TSMesh::__TSMeshVertexBase *outElem = reinterpret_cast<TSMesh::__TSMeshVertexBase *>(outPtr + inElem.vidx * outStride);
-
-      m.mulP( inElem.vert, &tempPt );
-      m.mulV( inElem.normal, &tempNrm );
-
-      outElem->_vert += ( tempPt * inElem.weight );
-      outElem->_normal += ( tempNrm * inElem.weight );
-   }
-}
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 // Initializer.
 // Initializer.
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -86,11 +58,9 @@ MODULE_BEGIN( TSMeshIntrinsics )
    {
    {
       // Assign defaults (C++ versions)
       // Assign defaults (C++ versions)
       zero_vert_normal_bulk = zero_vert_normal_bulk_C;
       zero_vert_normal_bulk = zero_vert_normal_bulk_C;
-      m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_C;
 
 
    #if defined(TORQUE_OS_XENON)
    #if defined(TORQUE_OS_XENON)
       zero_vert_normal_bulk = zero_vert_normal_bulk_X360;
       zero_vert_normal_bulk = zero_vert_normal_bulk_X360;
-      m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_X360;
    #else
    #else
       // Find the best implementation for the current CPU
       // Find the best implementation for the current CPU
       if(Platform::SystemInfo.processor.properties & CPU_PROP_SSE)
       if(Platform::SystemInfo.processor.properties & CPU_PROP_SSE)
@@ -98,21 +68,12 @@ MODULE_BEGIN( TSMeshIntrinsics )
    #if defined(TORQUE_CPU_X86)
    #if defined(TORQUE_CPU_X86)
          
          
          zero_vert_normal_bulk = zero_vert_normal_bulk_SSE;
          zero_vert_normal_bulk = zero_vert_normal_bulk_SSE;
-         m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_SSE;
-
-         /* This code still has a bug left in it
-   #if (_MSC_VER >= 1500)
-         if(Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_1)
-            m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_SSE4;
-   #endif
-            */
    #endif
    #endif
       }
       }
       else if(Platform::SystemInfo.processor.properties & CPU_PROP_ALTIVEC)
       else if(Platform::SystemInfo.processor.properties & CPU_PROP_ALTIVEC)
       {
       {
    #if !defined(TORQUE_OS_XENON) && defined(TORQUE_CPU_PPC)
    #if !defined(TORQUE_OS_XENON) && defined(TORQUE_CPU_PPC)
          zero_vert_normal_bulk = zero_vert_normal_bulk_gccvec;
          zero_vert_normal_bulk = zero_vert_normal_bulk_gccvec;
-         m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_gccvec;
    #endif
    #endif
       }
       }
    #endif
    #endif

+ 0 - 14
Engine/source/ts/tsMeshIntrinsics.h

@@ -23,20 +23,6 @@
 #ifndef _TSMESHINTRINSICS_H_
 #ifndef _TSMESHINTRINSICS_H_
 #define _TSMESHINTRINSICS_H_
 #define _TSMESHINTRINSICS_H_
 
 
-/// This is the batch-by-transform skin loop
-///
-/// @param mat       Bone transform
-/// @param count     Number of input elements in the batch
-/// @param batch     Pointer to the first element in an aligned array of input elements
-/// @param outPtr    Pointer to index 0 of a TSMesh aligned vertex buffer
-/// @param outStride Size, in bytes, of one entry in the vertex buffer
-extern void (*m_matF_x_BatchedVertWeightList)
-                                   (const MatrixF &mat, 
-                                    const dsize_t count,
-                                    const TSSkinMesh::BatchData::BatchedVertWeight * __restrict batch,
-                                    U8 * const __restrict outPtr,
-                                    const dsize_t outStride);
-
 /// Set the vertex position and normal to (0, 0, 0)
 /// Set the vertex position and normal to (0, 0, 0)
 ///
 ///
 /// @param count     Number of elements
 /// @param count     Number of elements

+ 5 - 1
Engine/source/ts/tsPartInstance.cpp

@@ -206,7 +206,11 @@ void TSPartInstance::render(S32 od, const TSRenderState &rdata)
 
 
    // render mesh objects
    // render mesh objects
    for (i=0; i<mMeshObjects.size(); i++)
    for (i=0; i<mMeshObjects.size(); i++)
-      mMeshObjects[i]->render(od,mSourceShape->getMaterialList(),rdata,1.0);
+   {
+      TSRenderState objState = rdata;
+      const char *meshName = mSourceShape->mShape->names[mMeshObjects[i]->object->nameIndex];
+      mMeshObjects[i]->render(od,mSourceShape->mShape->mShapeVertexBuffer,mSourceShape->getMaterialList(),objState,1.0, meshName);
+   }
 }
 }
 
 
 //-------------------------------------------------------------------------------------
 //-------------------------------------------------------------------------------------

+ 7 - 2
Engine/source/ts/tsRenderState.cpp

@@ -34,7 +34,9 @@ TSRenderState::TSRenderState()
       mCuller( NULL ),
       mCuller( NULL ),
       mLightQuery( NULL ),
       mLightQuery( NULL ),
       mUseOriginSort( false ),
       mUseOriginSort( false ),
-      mAccuTex( NULL )
+      mAccuTex( NULL ),
+      mNodeTransforms( NULL ),
+      mNodeTransformCount( 0 )
 {
 {
 }
 }
 
 
@@ -48,6 +50,9 @@ TSRenderState::TSRenderState( const TSRenderState &state )
       mCuller( state.mCuller ),
       mCuller( state.mCuller ),
       mUseOriginSort( state.mUseOriginSort ),
       mUseOriginSort( state.mUseOriginSort ),
       mLightQuery( state.mLightQuery ),
       mLightQuery( state.mLightQuery ),
-      mAccuTex( state.mAccuTex )
+      mAccuTex( state.mAccuTex ),
+      mUseOriginSort( state.mUseOriginSort ),
+      mNodeTransforms( state.mNodeTransforms ),
+      mNodeTransformCount( state.mNodeTransformCount )
 {
 {
 }
 }

+ 11 - 1
Engine/source/ts/tsRenderState.h

@@ -35,7 +35,7 @@ class SceneRenderState;
 class GFXCubemap;
 class GFXCubemap;
 class Frustum;
 class Frustum;
 class LightQuery;
 class LightQuery;
-
+class TSShape;
 
 
 /// A simple class for passing render state through the pre-render pipeline.
 /// A simple class for passing render state through the pre-render pipeline.
 ///
 ///
@@ -109,6 +109,12 @@ protected:
    // volume. This is passed down per-object.
    // volume. This is passed down per-object.
    GFXTextureObject* mAccuTex;
    GFXTextureObject* mAccuTex;
 
 
+   /// List of matrices to use for hardware skinning
+   MatrixF *mNodeTransforms;
+
+   /// Count of matrices in the mNodeTransforms list
+   U32 mNodeTransformCount;
+
 public:
 public:
 
 
    
    
@@ -159,6 +165,10 @@ public:
    void setAccuTex( GFXTextureObject* query ) { mAccuTex = query; }
    void setAccuTex( GFXTextureObject* query ) { mAccuTex = query; }
    GFXTextureObject* getAccuTex() const { return mAccuTex; }
    GFXTextureObject* getAccuTex() const { return mAccuTex; }
 
 
+   ///@ see mNodeTransforms, mNodeTransformCount
+   void setNodeTransforms(MatrixF *list, U32 count) { mNodeTransforms = list; mNodeTransformCount = count; }
+   void getNodeTransforms(MatrixF **list, U32 *count) const { *list = mNodeTransforms; *count = mNodeTransformCount; }
+
    /// @}
    /// @}
 };
 };
 
 

+ 405 - 263
Engine/source/ts/tsShape.cpp

@@ -42,7 +42,7 @@ extern TSShape* loadColladaShape(const Torque::Path &path);
 #endif
 #endif
 
 
 /// most recent version -- this is the version we write
 /// most recent version -- this is the version we write
-S32 TSShape::smVersion = 26;
+S32 TSShape::smVersion = 28;
 /// the version currently being read...valid only during a read
 /// the version currently being read...valid only during a read
 S32 TSShape::smReadVersion = -1;
 S32 TSShape::smReadVersion = -1;
 const U32 TSShape::smMostRecentExporterVersion = DTS_EXPORTER_CURRENT_VERSION;
 const U32 TSShape::smMostRecentExporterVersion = DTS_EXPORTER_CURRENT_VERSION;
@@ -58,13 +58,14 @@ F32 TSShape::smAlphaOutDefault = -1.0f;
 S32 TSShape::smNumSkipLoadDetails = 0;
 S32 TSShape::smNumSkipLoadDetails = 0;
 
 
 bool TSShape::smInitOnRead = true;
 bool TSShape::smInitOnRead = true;
+bool TSShape::smUseHardwareSkinning = true;
+U32 TSShape::smMaxSkinBones = 70;
 
 
 
 
 TSShape::TSShape()
 TSShape::TSShape()
 {
 {
    materialList = NULL;
    materialList = NULL;
    mReadVersion = -1; // -1 means constructed from scratch (e.g., in exporter or no read yet)
    mReadVersion = -1; // -1 means constructed from scratch (e.g., in exporter or no read yet)
-   mHasSkinMesh = false;
    mSequencesConstructed = false;
    mSequencesConstructed = false;
    mShapeData = NULL;
    mShapeData = NULL;
    mShapeDataSize = 0;
    mShapeDataSize = 0;
@@ -286,6 +287,29 @@ bool TSShape::findMeshIndex(const String& meshName, S32& objIndex, S32& meshInde
    return false;
    return false;
 }
 }
 
 
+bool TSShape::needsBufferUpdate()
+{
+   // No buffer? definitely need an update!
+   if (mVertexSize == 0 || mShapeVertexData.size == 0)
+      return true;
+
+   // Check if we have modified vertex data
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
+   {
+      TSMesh *mesh = *iter;
+      if (!mesh ||
+         (mesh->getMeshType() != TSMesh::StandardMeshType &&
+            mesh->getMeshType() != TSMesh::SkinMeshType))
+         continue;
+
+      // NOTE: cant use mVertexData.isReady since that might not be init'd at this stage
+      if (mesh->mVertSize == 0)
+         return true;
+   }
+
+   return false;
+}
+
 TSMesh* TSShape::findMesh(const String& meshName)
 TSMesh* TSShape::findMesh(const String& meshName)
 {
 {
    S32 objIndex, meshIndex;
    S32 objIndex, meshIndex;
@@ -545,75 +569,356 @@ void TSShape::init()
          detailCollisionAccelerators[dca] = NULL;
          detailCollisionAccelerators[dca] = NULL;
    }
    }
 
 
+   // Assign mesh parents & format
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
+   {
+      TSMesh *mesh = *iter;
+      if (!mesh)
+         continue;
+
+      if (mesh->parentMesh >= 0)
+      {
+         mesh->parentMeshObject = meshes[mesh->parentMesh];
+      }
+      else
+      {
+         mesh->parentMeshObject = NULL;
+      }
+
+      mesh->mVertexFormat = &mVertexFormat;
+   }
+
    initVertexFeatures();
    initVertexFeatures();
    initMaterialList();
    initMaterialList();
 }
 }
 
 
+void TSShape::initVertexBuffers()
+{
+   // Assumes mVertexData is valid
+   if (!mShapeVertexData.vertexDataReady)
+   {
+      AssertFatal(false, "WTF");
+   }
+
+   U32 destIndices = 0;
+   U32 destPrims = 0;
+
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
+   {
+      TSMesh *mesh = *iter;
+      if (!mesh ||
+         (mesh->getMeshType() != TSMesh::StandardMeshType &&
+            mesh->getMeshType() != TSMesh::SkinMeshType))
+         continue;
+
+      destIndices += mesh->indices.size();
+      destPrims += mesh->primitives.size();
+   }
+
+   // For HW skinning we can just use the static buffer
+   if (TSShape::smUseHardwareSkinning)
+   {
+      getVertexBuffer(mShapeVertexBuffer, GFXBufferTypeStatic);
+   }
+
+   // Also the IBO
+   mShapeVertexIndices.set(GFX, destIndices, destPrims, GFXBufferTypeStatic);
+   U16 *indicesStart = NULL;
+   mShapeVertexIndices.lock(&indicesStart, NULL);
+   U16 *ibIndices = indicesStart;
+   GFXPrimitive *piInput = mShapeVertexIndices->mPrimitiveArray;
+   U32 vertStart = 0;
+   U32 primStart = 0;
+   U32 indStart = 0;
+
+   // Create VBO
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
+   {
+      TSMesh *mesh = *iter;
+      if (!mesh ||
+         (mesh->getMeshType() != TSMesh::StandardMeshType &&
+            mesh->getMeshType() != TSMesh::SkinMeshType))
+         continue;
+
+      // Make the offset vbo
+      mesh->mPrimBufferOffset = primStart;
+
+      // Dump primitives to locked buffer
+      mesh->dumpPrimitives(vertStart, indStart, piInput, ibIndices);
+
+      AssertFatal(mesh->mVertOffset / mVertexSize == vertStart, "offset mismatch");
+
+      vertStart += mesh->mNumVerts;
+      primStart += mesh->primitives.size();
+      indStart += mesh->indices.size();
+
+      mesh->mVB = mShapeVertexBuffer;
+      mesh->mPB = mShapeVertexIndices;
+
+      // Advance
+      piInput += mesh->primitives.size();
+      ibIndices += mesh->indices.size();
+
+      if (TSSkinMesh::smDebugSkinVerts && mesh->getMeshType() == TSMesh::SkinMeshType)
+      {
+         static_cast<TSSkinMesh*>(mesh)->printVerts();
+      }
+   }
+
+#ifdef TORQUE_DEBUG
+   // Verify prims
+   if (TSSkinMesh::smDebugSkinVerts)
+   {
+      U32 vertsInBuffer = mShapeVertexData.size / mVertexSize;
+      U32 primsInBuffer = piInput - mShapeVertexIndices->mPrimitiveArray;
+      U32 indsInBuffer = ibIndices - indicesStart;
+
+      for (U32 i = 0; i < primStart; i++)
+      {
+         GFXPrimitive &prim = mShapeVertexIndices->mPrimitiveArray[i];
+
+         if (prim.type != GFXTriangleList && prim.type != GFXTriangleStrip)
+         {
+            AssertFatal(false, "Unexpected triangle list");
+         }
+
+         if (prim.type == GFXTriangleStrip)
+            continue;
+
+         AssertFatal(prim.startVertex < vertsInBuffer, "wrong start vertex");
+         AssertFatal((prim.startVertex + prim.numVertices) <= vertsInBuffer, "too many verts");
+         AssertFatal(prim.startIndex + (prim.numPrimitives * 3) <= indsInBuffer, "too many inds");
+
+         for (U32 i = prim.startIndex; i < prim.startIndex + (prim.numPrimitives * 3); i++)
+         {
+            if (indicesStart[i] >= vertsInBuffer)
+            {
+               AssertFatal(false, "vert not in buffer");
+            }
+            U16 idx = indicesStart[i];
+            if (idx < prim.minIndex)
+            {
+               AssertFatal(false, "index out of minIndex range");
+            }
+         }
+      }
+   }
+#endif
+
+   mShapeVertexIndices.unlock();
+}
+
+void TSShape::getVertexBuffer(TSVertexBufferHandle &vb, GFXBufferType bufferType)
+{
+   vb.set(GFX, mVertexSize, &mVertexFormat, mShapeVertexData.size / mVertexSize, bufferType);
+
+   U8 *vertexData = mShapeVertexData.base;
+   U8 *vertPtr = vb.lock();
+   dMemcpy(vertPtr, mShapeVertexData.base, mShapeVertexData.size);
+   vb.unlock();
+}
+
+void TSShape::initVertexBufferPointers()
+{
+   if (mBasicVertexFormat.vertexSize == -1)
+      return;
+   AssertFatal(mVertexSize == mBasicVertexFormat.vertexSize, "vertex size mismatch");
+
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
+   {
+      TSMesh *mesh = *iter;
+      if (mesh &&
+         (mesh->getMeshType() == TSMesh::StandardMeshType ||
+            mesh->getMeshType() == TSMesh::SkinMeshType))
+      {
+         // Set buffer
+         AssertFatal(mesh->mNumVerts >= mesh->vertsPerFrame, "invalid verts per frame");
+         if (mesh->mVertSize > 0 && !mesh->mVertexData.isReady())
+         {
+            U32 boneOffset = 0;
+            U32 colorOffset = 0;
+            AssertFatal(mesh->mVertSize == mVertexFormat.getSizeInBytes(), "mismatch in format size");
+
+            if (mBasicVertexFormat.boneOffset >= 0)
+            {
+               boneOffset = mBasicVertexFormat.boneOffset;
+            }
+
+            if (mBasicVertexFormat.colorOffset >= 0)
+            {
+               colorOffset = mBasicVertexFormat.colorOffset;
+            }
+
+            // Initialize the vertex data
+            mesh->mVertexData.set(mShapeVertexData.base + mesh->mVertOffset, mesh->mVertSize, mesh->mNumVerts, colorOffset, boneOffset, false);
+            mesh->mVertexData.setReady(true);
+         }
+      }
+   }
+}
+
 void TSShape::initVertexFeatures()
 void TSShape::initVertexFeatures()
 {
 {
    bool hasColors = false;
    bool hasColors = false;
    bool hasTexcoord2 = false;
    bool hasTexcoord2 = false;
+   bool hasSkin = false;
+   U32 vertStart = 0;
+   U32 primStart = 0;
+   U32 indStart = 0;
 
 
-   Vector<TSMesh*>::iterator iter = meshes.begin();
-   for ( ; iter != meshes.end(); iter++ )
+   if (!needsBufferUpdate())
    {
    {
-      TSMesh *mesh = *iter;
-      if (  mesh &&
-            (  mesh->getMeshType() == TSMesh::StandardMeshType ||
-               mesh->getMeshType() == TSMesh::SkinMeshType ) )
+      // Init format from basic format
+      mVertexFormat.clear();
+      mBasicVertexFormat.getFormat(mVertexFormat);
+      mVertexSize = mVertexFormat.getSizeInBytes();
+
+      initVertexBufferPointers();
+
+      for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
       {
       {
-         if ( mesh->mVertexData.isReady() )
+         TSMesh *mesh = *iter;
+         if (mesh &&
+            (mesh->getMeshType() == TSMesh::SkinMeshType))
          {
          {
-            hasColors |= mesh->mHasColor;
-            hasTexcoord2 |= mesh->mHasTVert2;
+            static_cast<TSSkinMesh*>(mesh)->createSkinBatchData();
          }
          }
-         else
+      }
+
+      // Make sure VBO is init'd
+      initVertexBuffers();
+      return;
+   }
+
+   // Cleanout VBO
+   mShapeVertexBuffer = NULL;
+
+   // Make sure mesh has verts stored in mesh data, we're recreating the buffer
+   TSBasicVertexFormat basicFormat;
+   
+   initVertexBufferPointers();
+
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
+   {
+      TSMesh *mesh = *iter;
+      if (mesh &&
+         (mesh->getMeshType() == TSMesh::StandardMeshType ||
+            mesh->getMeshType() == TSMesh::SkinMeshType))
+      {
+         // Make sure we have everything in the vert lists
+         mesh->makeEditable();
+
+         // We need the skin batching data here to determine bone counts
+         if (mesh->getMeshType() == TSMesh::SkinMeshType)
          {
          {
-            hasColors |= !mesh->colors.empty();
-            hasTexcoord2 |= !mesh->tverts2.empty();
+            static_cast<TSSkinMesh*>(mesh)->createSkinBatchData();
          }
          }
+
+         basicFormat.addMeshRequirements(mesh);
       }
       }
    }
    }
 
 
-   mVertSize = ( hasTexcoord2 || hasColors ) ? sizeof(TSMesh::__TSMeshVertex_3xUVColor) : sizeof(TSMesh::__TSMeshVertexBase);
    mVertexFormat.clear();
    mVertexFormat.clear();
-  
-   mVertexFormat.addElement( GFXSemantic::POSITION, GFXDeclType_Float3 );
-   mVertexFormat.addElement( GFXSemantic::TANGENTW, GFXDeclType_Float, 3 );
-   mVertexFormat.addElement( GFXSemantic::NORMAL, GFXDeclType_Float3 );
-   mVertexFormat.addElement( GFXSemantic::TANGENT, GFXDeclType_Float3 );
+   mBasicVertexFormat = basicFormat;
+   mBasicVertexFormat.getFormat(mVertexFormat);
+   mBasicVertexFormat.vertexSize = mVertexFormat.getSizeInBytes();
+   mVertexSize = mBasicVertexFormat.vertexSize;
 
 
-   mVertexFormat.addElement( GFXSemantic::TEXCOORD, GFXDeclType_Float2, 0 );
+   U32 destVertex = 0;
+   U32 destIndices = 0;
 
 
-   if(hasTexcoord2 || hasColors)
+   // Go fix up meshes to include defaults for optional features
+   // and initialize them if they're not a skin mesh.
+   U32 count = 0;
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
    {
    {
-      mVertexFormat.addElement( GFXSemantic::TEXCOORD, GFXDeclType_Float2, 1 );
-      mVertexFormat.addElement( GFXSemantic::COLOR, GFXDeclType_Color );
-      mVertexFormat.addElement( GFXSemantic::TEXCOORD, GFXDeclType_Float, 2 );
+      TSMesh *mesh = *iter;
+      if (!mesh ||
+         (mesh->getMeshType() != TSMesh::StandardMeshType &&
+            mesh->getMeshType() != TSMesh::SkinMeshType))
+         continue;
+
+      mesh->mVertSize = mVertexSize;
+      mesh->mVertOffset = destVertex;
+
+      destVertex += mesh->mVertSize * mesh->getNumVerts();
+      destIndices += mesh->indices.size();
+
+      count += 1;
    }
    }
 
 
-   // Go fix up meshes to include defaults for optional features
-   // and initialize them if they're not a skin mesh.
-   iter = meshes.begin();
-   for ( ; iter != meshes.end(); iter++ )
+   // Don't set up if we have no meshes
+   if (count == 0)
+   {
+      mShapeVertexData.set(NULL, 0);
+      mShapeVertexData.vertexDataReady = false;
+      return;
+   }
+
+   // Now we can create the VBO
+   U8 *vertexData = (U8*)dMalloc_aligned(destVertex, 16);
+   U8 *vertexDataPtr = vertexData;
+   mShapeVertexData.set(vertexData, destVertex);
+
+   // Create VBO
+   for (Vector<TSMesh*>::iterator iter = meshes.begin(); iter != meshes.end(); iter++)
    {
    {
       TSMesh *mesh = *iter;
       TSMesh *mesh = *iter;
-      if (  !mesh ||
-            (  mesh->getMeshType() != TSMesh::StandardMeshType &&
-               mesh->getMeshType() != TSMesh::SkinMeshType ) )
+      U32 idx = iter - meshes.begin();
+
+      if (!mesh ||
+         (mesh->getMeshType() != TSMesh::StandardMeshType &&
+            mesh->getMeshType() != TSMesh::SkinMeshType))
          continue;
          continue;
 
 
-      // Set the flags.
-      mesh->mVertexFormat = &mVertexFormat;
-      mesh->mVertSize = mVertSize;
+      U32 boneOffset = 0;
+      U32 colorOffset = 0;
+      AssertFatal(mesh->mVertSize == mVertexFormat.getSizeInBytes(), "mismatch in format size");
 
 
-      // Create and fill aligned data structure
-      mesh->convertToAlignedMeshData();
+      if (mBasicVertexFormat.boneOffset >= 0)
+      {
+         boneOffset = mBasicVertexFormat.boneOffset;
+      }
 
 
-      // Init the vertex buffer.
-      if ( mesh->getMeshType() == TSMesh::StandardMeshType )
-         mesh->createVBIB();
+      if (mBasicVertexFormat.colorOffset >= 0)
+      {
+         colorOffset = mBasicVertexFormat.colorOffset;
+      }
+
+      // Dump everything
+      mesh->mVertexData.setReady(false);
+      mesh->mVertSize = mVertexSize;
+      AssertFatal(mesh->mVertOffset == vertexDataPtr - vertexData, "vertex offset mismatch");
+      mesh->mNumVerts = mesh->getNumVerts();
+
+      mesh->mVertexData.set(mShapeVertexData.base + mesh->mVertOffset, mesh->mVertSize, mesh->mNumVerts, colorOffset, boneOffset, false);
+      mesh->convertToVertexData();
+      mesh->mVertexData.setReady(true);
+
+#ifdef TORQUE_DEBUG
+      AssertFatal(mesh->mNumVerts == mesh->verts.size(), "vert mismatch");
+      for (U32 i = 0; i < mesh->mNumVerts; i++)
+      {
+         Point3F v1 = mesh->verts[i];
+         Point3F v2 = mesh->mVertexData.getBase(i).vert();
+         AssertFatal(mesh->verts[i] == mesh->mVertexData.getBase(i).vert(), "vert data mismatch");
+      }
+
+      if (mesh->getMeshType() == TSMesh::SkinMeshType)
+      {
+         AssertFatal(mesh->getMaxBonesPerVert() != 0, "Skin mesh has no bones used, very strange!");
+      }
+#endif
+
+      // Advance
+      vertexDataPtr += mesh->mVertSize * mesh->mNumVerts;
+
+      AssertFatal(vertexDataPtr - vertexData <= destVertex, "Vertex data overflow");
    }
    }
+
+   mShapeVertexData.vertexDataReady = true;
+
+   initVertexBuffers();
 }
 }
 
 
 void TSShape::setupBillboardDetails( const String &cachePath )
 void TSShape::setupBillboardDetails( const String &cachePath )
@@ -654,8 +959,6 @@ void TSShape::initMaterialList()
    subShapeFirstTranslucentObject.setSize(numSubShapes);
    subShapeFirstTranslucentObject.setSize(numSubShapes);
    #endif
    #endif
 
 
-   mHasSkinMesh = false;
-
    S32 i,j,k;
    S32 i,j,k;
    // for each subshape, find the first translucent object
    // for each subshape, find the first translucent object
    // also, while we're at it, set mHasTranslucency
    // also, while we're at it, set mHasTranslucency
@@ -674,8 +977,6 @@ void TSShape::initMaterialList()
             if (!mesh)
             if (!mesh)
                continue;
                continue;
 
 
-            mHasSkinMesh |= mesh->getMeshType() == TSMesh::SkinMeshType;
-
             for (k=0; k<mesh->primitives.size(); k++)
             for (k=0; k<mesh->primitives.size(); k++)
             {
             {
                if (mesh->primitives[k].matIndex & TSDrawPrimitive::NoMaterial)
                if (mesh->primitives[k].matIndex & TSDrawPrimitive::NoMaterial)
@@ -1118,6 +1419,40 @@ void TSShape::assembleShape()
 
 
    tsalloc.checkGuard();
    tsalloc.checkGuard();
 
 
+   if (TSShape::smReadVersion >= 27)
+   {
+      // Vertex format is set here
+      S8 *vboData = NULL;
+      S32 vboSize = 0;
+
+      mBasicVertexFormat.readAlloc(&tsalloc);
+      mVertexFormat.clear();
+      mBasicVertexFormat.getFormat(mVertexFormat);
+      mVertexSize = mVertexFormat.getSizeInBytes();
+
+      AssertFatal(mVertexSize == mBasicVertexFormat.vertexSize, "vertex size mismatch");
+
+      vboSize = tsalloc.get32();
+      vboData = tsalloc.getPointer8(vboSize);
+
+      if (tsalloc.getBuffer() && vboSize > 0)
+      {
+         U8 *vertexData = (U8*)dMalloc_aligned(vboSize, 16);
+         U8 *vertexDataPtr = vertexData;
+         dMemcpy(vertexData, vboData, vboSize);
+         mShapeVertexData.set(vertexData, vboSize);
+         mShapeVertexData.vertexDataReady = true;
+      }
+      else
+      {
+         mShapeVertexData.set(NULL, 0);
+      }
+   }
+   else
+   {
+      mShapeVertexData.set(NULL, 0);
+   }
+
    // about to read in the meshes...first must allocate some scratch space
    // about to read in the meshes...first must allocate some scratch space
    S32 scratchSize = getMax(numSkins,numMeshes);
    S32 scratchSize = getMax(numSkins,numMeshes);
    TSMesh::smVertsList.setSize(scratchSize);
    TSMesh::smVertsList.setSize(scratchSize);
@@ -1401,6 +1736,19 @@ void TSShape::disassembleShape()
    }
    }
    tsalloc.setGuard();
    tsalloc.setGuard();
 
 
+   if (TSShape::smVersion >= 27)
+   {
+      // Vertex format now included with mesh data. Note this doesn't include index data which
+      // is constructed directly in the buffer from the meshes
+      S8 *vboData = NULL;
+      S32 vboSize = 0;
+
+      mBasicVertexFormat.writeAlloc(&tsalloc);
+
+      tsalloc.set32(mShapeVertexData.size);
+      tsalloc.copyToBuffer8((S8*)mShapeVertexData.base, mShapeVertexData.size);
+   }
+
    // read in the meshes (sans skins)...
    // read in the meshes (sans skins)...
    bool * isMesh = new bool[numMeshes]; // funny business because decals are pretend meshes (legacy issue)
    bool * isMesh = new bool[numMeshes]; // funny business because decals are pretend meshes (legacy issue)
    for (i=0;i<numMeshes;i++)
    for (i=0;i<numMeshes;i++)
@@ -1618,226 +1966,9 @@ bool TSShape::read(Stream * s)
    delete [] memBuffer32;
    delete [] memBuffer32;
 
 
    if (smInitOnRead)
    if (smInitOnRead)
+   {
       init();
       init();
-
-   //if (names.size() == 3 && dStricmp(names[2], "Box") == 0)
-   //{
-   //   Con::errorf("\nnodes.set(dMalloc(%d * sizeof(Node)), %d);", nodes.size(), nodes.size());
-   //   for (U32 i = 0; i < nodes.size(); i++)
-   //   {
-   //      Node& obj = nodes[i];
-
-   //      Con::errorf("   nodes[%d].nameIndex = %d;", i, obj.nameIndex);
-   //      Con::errorf("   nodes[%d].parentIndex = %d;", i, obj.parentIndex);
-   //      Con::errorf("   nodes[%d].firstObject = %d;", i, obj.firstObject);
-   //      Con::errorf("   nodes[%d].firstChild = %d;", i, obj.firstChild);
-   //      Con::errorf("   nodes[%d].nextSibling = %d;", i, obj.nextSibling);
-   //   }
-
-   //   Con::errorf("\nobjects.set(dMalloc(%d * sizeof(Object)), %d);", objects.size(), objects.size());
-   //   for (U32 i = 0; i < objects.size(); i++)
-   //   {
-   //      Object& obj = objects[i];
-
-   //      Con::errorf("   objects[%d].nameIndex = %d;", i, obj.nameIndex);
-   //      Con::errorf("   objects[%d].numMeshes = %d;", i, obj.numMeshes);
-   //      Con::errorf("   objects[%d].startMeshIndex = %d;", i, obj.startMeshIndex);
-   //      Con::errorf("   objects[%d].nodeIndex = %d;", i, obj.nodeIndex);
-   //      Con::errorf("   objects[%d].nextSibling = %d;", i, obj.nextSibling);
-   //      Con::errorf("   objects[%d].firstDecal = %d;", i, obj.firstDecal);
-   //   }
-
-   //   Con::errorf("\nobjectStates.set(dMalloc(%d * sizeof(ObjectState)), %d);", objectStates.size(), objectStates.size());
-   //   for (U32 i = 0; i < objectStates.size(); i++)
-   //   {
-   //      ObjectState& obj = objectStates[i];
-
-   //      Con::errorf("   objectStates[%d].vis = %g;", i, obj.vis);
-   //      Con::errorf("   objectStates[%d].frameIndex = %d;", i, obj.frameIndex);
-   //      Con::errorf("   objectStates[%d].matFrameIndex = %d;", i, obj.matFrameIndex);
-   //   }
-   //   Con::errorf("\nsubShapeFirstNode.set(dMalloc(%d * sizeof(S32)), %d);", subShapeFirstNode.size(), subShapeFirstNode.size());
-   //   for (U32 i = 0; i < subShapeFirstNode.size(); i++)
-   //      Con::errorf("   subShapeFirstNode[%d] = %d;", i, subShapeFirstNode[i]);
-
-   //   Con::errorf("\nsubShapeFirstObject.set(dMalloc(%d * sizeof(S32)), %d);", subShapeFirstObject.size(), subShapeFirstObject.size());
-   //   for (U32 i = 0; i < subShapeFirstObject.size(); i++)
-   //      Con::errorf("   subShapeFirstObject[%d] = %d;", i, subShapeFirstObject[i]);
-
-   //   //Con::errorf("numDetailFirstSkins = %d", detailFirstSkin.size());
-   //   Con::errorf("\nsubShapeNumNodes.set(dMalloc(%d * sizeof(S32)), %d);", subShapeNumNodes.size(), subShapeNumNodes.size());
-   //   for (U32 i = 0; i < subShapeNumNodes.size(); i++)
-   //      Con::errorf("   subShapeNumNodes[%d] = %d;", i, subShapeNumNodes[i]);
-
-   //   Con::errorf("\nsubShapeNumObjects.set(dMalloc(%d * sizeof(S32)), %d);", subShapeNumObjects.size(), subShapeNumObjects.size());
-   //   for (U32 i = 0; i < subShapeNumObjects.size(); i++)
-   //      Con::errorf("   subShapeNumObjects[%d] = %d;", i, subShapeNumObjects[i]);
-
-   //   Con::errorf("\ndetails.set(dMalloc(%d * sizeof(Detail)), %d);", details.size(), details.size());
-   //   for (U32 i = 0; i < details.size(); i++)
-   //   {
-   //      Detail& obj = details[i];
-
-   //      Con::errorf("   details[%d].nameIndex = %d;", i, obj.nameIndex);
-   //      Con::errorf("   details[%d].subShapeNum = %d;", i, obj.subShapeNum);
-   //      Con::errorf("   details[%d].objectDetailNum = %d;", i, obj.objectDetailNum);
-   //      Con::errorf("   details[%d].size = %g;", i, obj.size);
-   //      Con::errorf("   details[%d].averageError = %g;", i, obj.averageError);
-   //      Con::errorf("   details[%d].maxError = %g;", i, obj.maxError);
-   //      Con::errorf("   details[%d].polyCount = %d;", i, obj.polyCount);
-   //   }
-
-   //   Con::errorf("\ndefaultRotations.set(dMalloc(%d * sizeof(Quat16)), %d);", defaultRotations.size(), defaultRotations.size());
-   //   for (U32 i = 0; i < defaultRotations.size(); i++)
-   //   {
-   //      Con::errorf("   defaultRotations[%d].x = %g;", i, defaultRotations[i].x);
-   //      Con::errorf("   defaultRotations[%d].y = %g;", i, defaultRotations[i].y);
-   //      Con::errorf("   defaultRotations[%d].z = %g;", i, defaultRotations[i].z);
-   //      Con::errorf("   defaultRotations[%d].w = %g;", i, defaultRotations[i].w);
-   //   }
-
-   //   Con::errorf("\ndefaultTranslations.set(dMalloc(%d * sizeof(Point3F)), %d);", defaultTranslations.size(), defaultTranslations.size());
-   //   for (U32 i = 0; i < defaultTranslations.size(); i++)
-   //      Con::errorf("   defaultTranslations[%d].set(%g, %g, %g);", i, defaultTranslations[i].x, defaultTranslations[i].y, defaultTranslations[i].z);
-
-   //   Con::errorf("\nsubShapeFirstTranslucentObject.set(dMalloc(%d * sizeof(S32)), %d);", subShapeFirstTranslucentObject.size(), subShapeFirstTranslucentObject.size());
-   //   for (U32 i = 0; i < subShapeFirstTranslucentObject.size(); i++)
-   //      Con::errorf("   subShapeFirstTranslucentObject[%d] = %d;", i, subShapeFirstTranslucentObject[i]);
-
-   //   Con::errorf("\nmeshes.set(dMalloc(%d * sizeof(TSMesh)), %d);", meshes.size(), meshes.size());
-   //   for (U32 i = 0; i < meshes.size(); i++)
-   //   {
-   //      TSMesh* obj = meshes[i];
-
-   //      if (obj)
-   //      {
-   //         Con::errorf("   meshes[%d]->meshType = %d;", i, obj->meshType);
-   //         Con::errorf("   meshes[%d]->mBounds.minExtents.set(%g, %g, %g);", i, obj->mBounds.minExtents.x, obj->mBounds.minExtents.y, obj->mBounds.minExtents.z);
-   //         Con::errorf("   meshes[%d]->mBounds.maxExtents.set(%g, %g, %g);", i, obj->mBounds.maxExtents.x, obj->mBounds.maxExtents.y, obj->mBounds.maxExtents.z);
-   //         Con::errorf("   meshes[%d]->mCenter.set(%g, %g, %g);", i, obj->mCenter.x, obj->mCenter.y, obj->mCenter.z);
-   //         Con::errorf("   meshes[%d]->mRadius = %g;", i, obj->mRadius);
-   //         Con::errorf("   meshes[%d]->mVisibility = %g;", i, obj->mVisibility);
-   //         Con::errorf("   meshes[%d]->mDynamic = %d;", i, obj->mDynamic);
-   //         Con::errorf("   meshes[%d]->parentMesh = %d;", i, obj->parentMesh);
-   //         Con::errorf("   meshes[%d]->numFrames = %d;", i, obj->numFrames);
-   //         Con::errorf("   meshes[%d]->numMatFrames = %d;", i, obj->numMatFrames);
-   //         Con::errorf("   meshes[%d]->vertsPerFrame = %d;", i, obj->vertsPerFrame);
-
-   //         Con::errorf("\n   meshes[%d]->verts.set(dMalloc(%d * sizeof(Point3F)), %d);", obj->verts.size(), obj->verts.size());
-   //         for (U32 j = 0; j < obj->verts.size(); j++)
-   //            Con::errorf("   meshes[%d]->verts[%d].set(%g, %g, %g);", i, j, obj->verts[j].x, obj->verts[j].y, obj->verts[j].z);
-
-   //         Con::errorf("\n   meshes[%d]->norms.set(dMalloc(%d * sizeof(Point3F)), %d);", obj->norms.size(), obj->norms.size());
-   //         for (U32 j = 0; j < obj->norms.size(); j++)
-   //            Con::errorf("   meshes[%d]->norms[%d].set(%g, %g, %g);", i, j, obj->norms[j].x, obj->norms[j].y, obj->norms[j].z);
-
-   //         Con::errorf("\n   meshes[%d]->tverts.set(dMalloc(%d * sizeof(Point2F)), %d);", obj->tverts.size(), obj->tverts.size());
-   //         for (U32 j = 0; j < obj->tverts.size(); j++)
-   //            Con::errorf("   meshes[%d]->tverts[%d].set(%g, %g);", i, j, obj->tverts[j].x, obj->tverts[j].y);
-
-   //         Con::errorf("\n   meshes[%d]->primitives.set(dMalloc(%d * sizeof(TSDrawPrimitive)), %d);", obj->primitives.size(), obj->primitives.size());
-   //         for (U32 j = 0; j < obj->primitives.size(); j++)
-   //         {
-   //            TSDrawPrimitive& prim = obj->primitives[j];
-
-   //            Con::errorf("   meshes[%d]->primitives[%d].start = %d;", i, j, prim.start);
-   //            Con::errorf("   meshes[%d]->primitives[%d].numElements = %d;", i, j, prim.numElements);
-   //            Con::errorf("   meshes[%d]->primitives[%d].matIndex = %d;", i, j, prim.matIndex);
-   //         }
-
-   //         Con::errorf("\n   meshes[%d]->encodedNorms.set(dMalloc(%d * sizeof(U8)), %d);", obj->encodedNorms.size(), obj->encodedNorms.size());
-   //         for (U32 j = 0; j < obj->encodedNorms.size(); j++)
-   //            Con::errorf("   meshes[%d]->encodedNorms[%d] = %c;", i, j, obj->encodedNorms[j]);
-
-   //         Con::errorf("\n   meshes[%d]->indices.set(dMalloc(%d * sizeof(U16)), %d);", obj->indices.size(), obj->indices.size());
-   //         for (U32 j = 0; j < obj->indices.size(); j++)
-   //            Con::errorf("   meshes[%d]->indices[%d] = %d;", i, j, obj->indices[j]);
-
-   //         Con::errorf("\n   meshes[%d]->initialTangents.set(dMalloc(%d * sizeof(Point3F)), %d);", obj->initialTangents.size(), obj->initialTangents.size());
-   //         for (U32 j = 0; j < obj->initialTangents.size(); j++)
-   //            Con::errorf("   meshes[%d]->initialTangents[%d].set(%g, %g, %g);", i, j, obj->initialTangents[j].x, obj->initialTangents[j].y, obj->initialTangents[j].z);
-
-   //         Con::errorf("\n   meshes[%d]->tangents.set(dMalloc(%d * sizeof(Point4F)), %d);", obj->tangents.size(), obj->tangents.size());
-   //         for (U32 j = 0; j < obj->tangents.size(); j++)
-   //            Con::errorf("   meshes[%d]->tangents[%d].set(%g, %g, %g, %g);", i, j, obj->tangents[j].x, obj->tangents[j].y, obj->tangents[j].z, obj->tangents[j].w);
-
-   //         Con::errorf("   meshes[%d]->billboardAxis.set(%g, %g, %g);", i, obj->billboardAxis.x, obj->billboardAxis.y, obj->billboardAxis.z);
-
-   //         Con::errorf("\n   meshes[%d]->planeNormals.set(dMalloc(%d * sizeof(Point3F)), %d);", obj->planeNormals.size(), obj->planeNormals.size());
-   //         for (U32 j = 0; j < obj->planeNormals.size(); j++)
-   //            Con::errorf("   meshes[%d]->planeNormals[%d].set(%g, %g, %g);", i, j, obj->planeNormals[j].x, obj->planeNormals[j].y, obj->planeNormals[j].z);
-
-   //         Con::errorf("\n   meshes[%d]->planeConstants.set(dMalloc(%d * sizeof(F32)), %d);", obj->planeConstants.size(), obj->planeConstants.size());
-   //         for (U32 j = 0; j < obj->planeConstants.size(); j++)
-   //            Con::errorf("   meshes[%d]->planeConstants[%d] = %g;", i, j, obj->planeConstants[j]);
-
-   //         Con::errorf("\n   meshes[%d]->planeMaterials.set(dMalloc(%d * sizeof(U32)), %d);", obj->planeMaterials.size(), obj->planeMaterials.size());
-   //         for (U32 j = 0; j < obj->planeMaterials.size(); j++)
-   //            Con::errorf("   meshes[%d]->planeMaterials[%d] = %d;", i, j, obj->planeMaterials[j]);
-
-   //         Con::errorf("   meshes[%d]->planesPerFrame = %d;", i, obj->planesPerFrame);
-   //         Con::errorf("   meshes[%d]->mergeBufferStart = %d;", i, obj->mergeBufferStart);
-   //      }
-   //   }
-
-   //   Con::errorf("\nalphaIn.set(dMalloc(%d * sizeof(F32)), %d);", alphaIn.size(), alphaIn.size());
-   //   for (U32 i = 0; i < alphaIn.size(); i++)
-   //      Con::errorf("   alphaIn[%d] = %g;", i, alphaIn[i]);
-
-   //   Con::errorf("\nalphaOut.set(dMalloc(%d * sizeof(F32)), %d);", alphaOut.size(), alphaOut.size());
-   //   for (U32 i = 0; i < alphaOut.size(); i++)
-   //      Con::errorf("   alphaOut[%d] = %g;", i, alphaOut[i]);
-
-   //   //Con::errorf("numSequences = %d", sequences.size());
-   //   //Con::errorf("numNodeRotations = %d", nodeRotations.size());
-   //   //Con::errorf("numNodeTranslations = %d", nodeTranslations.size());
-   //   //Con::errorf("numNodeUniformScales = %d", nodeUniformScales.size());
-   //   //Con::errorf("numNodeAlignedScales = %d", nodeAlignedScales.size());
-   //   //Con::errorf("numNodeArbitraryScaleRots = %d", nodeArbitraryScaleRots.size());
-   //   //Con::errorf("numNodeArbitraryScaleFactors = %d", nodeArbitraryScaleFactors.size());
-   //   //Con::errorf("numGroundRotations = %d", groundRotations.size());
-   //   //Con::errorf("numGroundTranslations = %d", groundTranslations.size());
-   //   //Con::errorf("numTriggers = %d", triggers.size());
-   //   //Con::errorf("numBillboardDetails = %d", billboardDetails.size());
-
-   //   //Con::errorf("\nnumDetailCollisionAccelerators = %d", detailCollisionAccelerators.size());
-   //   //for (U32 i = 0; i < detailCollisionAccelerators.size(); i++)
-   //   //{
-   //   //   ConvexHullAccelerator* obj = detailCollisionAccelerators[i];
-
-   //   //   if (obj)
-   //   //   {
-   //   //      Con::errorf("   detailCollisionAccelerators[%d].numVerts = %d", i, obj->numVerts);
-
-   //   //      for (U32 j = 0; j < obj->numVerts; j++)
-   //   //      {
-   //   //         Con::errorf("      verts[%d](%g, %g, %g)", j, obj->vertexList[j].x, obj->vertexList[j].y, obj->vertexList[j].z);
-   //   //         Con::errorf("      norms[%d](%g, %g, %g)", j, obj->normalList[j].x, obj->normalList[j].y, obj->normalList[j].z);
-   //   //         //U8**     emitStrings;
-   //   //      }
-   //   //   }
-   //   //}
-
-   //   Con::errorf("\nnames.setSize(%d);", names.size());
-   //   for (U32 i = 0; i < names.size(); i++)
-   //      Con::errorf("   names[%d] = StringTable->insert(\"%s\");", i, names[i]);
-
-   //   //TSMaterialList * materialList;
-
-   //   Con::errorf("\nradius = %g;", radius);
-   //   Con::errorf("tubeRadius = %g;", tubeRadius);
-   //   Con::errorf("center.set(%g, %g, %g);", center.x, center.y, center.z);
-   //   Con::errorf("bounds.minExtents.set(%g, %g, %g);", bounds.minExtents.x, bounds.minExtents.y, bounds.minExtents.z);
-   //   Con::errorf("bounds.maxExtents.set(%g, %g, %g);", bounds.maxExtents.x, bounds.maxExtents.y, bounds.maxExtents.z);
-
-   //   Con::errorf("\nmExporterVersion = %d;", mExporterVersion);
-   //   Con::errorf("mSmallestVisibleSize = %g;", mSmallestVisibleSize);
-   //   Con::errorf("mSmallestVisibleDL = %d;", mSmallestVisibleDL);
-   //   Con::errorf("mReadVersion = %d;", mReadVersion);
-   //   Con::errorf("mFlags = %d;", mFlags);
-   //   //Con::errorf("data = %d", data);
-   //   Con::errorf("mSequencesConstructed = %d;", mSequencesConstructed);
-   //}
+   }
 
 
    return true;
    return true;
 }
 }
@@ -2294,3 +2425,14 @@ void TSShape::computeAccelerator(S32 dl)
       AssertFatal(currPos == emitStringLen, "Error, over/underflowed the emission string!");
       AssertFatal(currPos == emitStringLen, "Error, over/underflowed the emission string!");
    }
    }
 }
 }
+
+void TSShape::finalizeEditable()
+{
+   for (U32 i = 0; i < meshes.size(); i++)
+   {
+      if (meshes[i])
+      {
+         meshes[i]->clearEditable();
+      }
+   }
+}

+ 45 - 8
Engine/source/ts/tsShape.h

@@ -50,6 +50,25 @@ struct CollisionShapeInfo
    PhysicsCollision *colShape;
    PhysicsCollision *colShape;
 };
 };
 
 
+/// Data storage helper for main shape buffer
+struct TSShapeVertexArray
+{
+   U8 *base;
+   U32 size;
+   bool vertexDataReady;
+
+   TSShapeVertexArray() : base(NULL), size(0), vertexDataReady(false) {}
+   virtual ~TSShapeVertexArray() { set(NULL, 0); }
+
+   virtual void set(void *b, U32 s, bool autoFree = true)
+   {
+      if (base && autoFree)
+         dFree_aligned(base);
+      base = reinterpret_cast<U8 *>(b);
+      size = s;
+   }
+};
+
 /// TSShape stores generic data for a 3space model.
 /// TSShape stores generic data for a 3space model.
 ///
 ///
 /// TSShape and TSShapeInstance act in conjunction to allow the rendering and
 /// TSShape and TSShapeInstance act in conjunction to allow the rendering and
@@ -381,18 +400,20 @@ class TSShape
    /// The GFX vertex format for all detail meshes in the shape.
    /// The GFX vertex format for all detail meshes in the shape.
    /// @see initVertexFeatures()
    /// @see initVertexFeatures()
    GFXVertexFormat mVertexFormat;
    GFXVertexFormat mVertexFormat;
+   TSBasicVertexFormat mBasicVertexFormat;
+   U32 mVertexSize;
 
 
-   /// The GFX vertex size in bytes for all detail meshes in the shape.
-   /// @see initVertexFeatures()
-   U32 mVertSize;
+   S8* mShapeData;
+   U32 mShapeDataSize;
 
 
-   /// Is true if this shape contains skin meshes.
-   bool mHasSkinMesh;
+
+   // Processed vertex data
+   TSShapeVertexArray mShapeVertexData;
+   TSVertexBufferHandle mShapeVertexBuffer;
+   GFXPrimitiveBufferHandle mShapeVertexIndices;
 
 
    bool mSequencesConstructed;
    bool mSequencesConstructed;
 
 
-   S8* mShapeData;
-   U32 mShapeDataSize;
 
 
    // shape class has few methods --
    // shape class has few methods --
    // just constructor/destructor, io, and lookup methods
    // just constructor/destructor, io, and lookup methods
@@ -402,14 +423,24 @@ class TSShape
    ~TSShape();
    ~TSShape();
    void init();
    void init();
    void initMaterialList();    ///< you can swap in a new material list, but call this if you do
    void initMaterialList();    ///< you can swap in a new material list, but call this if you do
+   void finalizeEditable();
    bool preloadMaterialList(const Torque::Path &path); ///< called to preload and validate the materials in the mat list
    bool preloadMaterialList(const Torque::Path &path); ///< called to preload and validate the materials in the mat list
 
 
    void setupBillboardDetails( const String &cachePath );
    void setupBillboardDetails( const String &cachePath );
+   
+   /// Initializes the main vertex buffer
+   void initVertexBuffers();
+
+   /// Loads shape vertex data into specified buffer
+   void getVertexBuffer(TSVertexBufferHandle &vb, GFXBufferType bufferType);
 
 
    /// Called from init() to calcuate the GFX vertex features for
    /// Called from init() to calcuate the GFX vertex features for
    /// all detail meshes in the shape.
    /// all detail meshes in the shape.
    void initVertexFeatures();
    void initVertexFeatures();
 
 
+   /// Inits basic buffer pointers on load
+   void initVertexBufferPointers();
+
    bool getSequencesConstructed() const { return mSequencesConstructed; }
    bool getSequencesConstructed() const { return mSequencesConstructed; }
    void setSequencesConstructed(const bool c) { mSequencesConstructed = c; }
    void setSequencesConstructed(const bool c) { mSequencesConstructed = c; }
 
 
@@ -526,7 +557,7 @@ class TSShape
 
 
    const GFXVertexFormat* getVertexFormat() const { return &mVertexFormat; }
    const GFXVertexFormat* getVertexFormat() const { return &mVertexFormat; }
 
 
-   U32 getVertexSize() const { return mVertSize; }
+   bool needsBufferUpdate();
 
 
    /// @}
    /// @}
 
 
@@ -548,6 +579,12 @@ class TSShape
    /// by default we initialize shape when we read...
    /// by default we initialize shape when we read...
    static bool smInitOnRead;
    static bool smInitOnRead;
 
 
+   /// Enables hardware skinning features
+   static bool smUseHardwareSkinning;
+
+   /// Determines maximum number of bones to use in hardware skinning shaders
+   static U32 smMaxSkinBones;
+
    /// @name Version Info
    /// @name Version Info
    /// @{
    /// @{
 
 

+ 4 - 45
Engine/source/ts/tsShapeEdit.cpp

@@ -892,10 +892,6 @@ TSMesh* TSShape::copyMesh( const TSMesh* srcMesh ) const
       mesh = new TSMesh;
       mesh = new TSMesh;
    }
    }
 
 
-   // Set vertex format (all meshes in this shape must share the same format)
-   mesh->mVertSize = mVertSize;
-   mesh->mVertexFormat = &mVertexFormat;
-
    if ( !srcMesh )
    if ( !srcMesh )
       return mesh;      // return an empty mesh
       return mesh;      // return an empty mesh
 
 
@@ -906,53 +902,16 @@ TSMesh* TSShape::copyMesh( const TSMesh* srcMesh ) const
    mesh->numMatFrames = srcMesh->numMatFrames;
    mesh->numMatFrames = srcMesh->numMatFrames;
    mesh->vertsPerFrame = srcMesh->vertsPerFrame;
    mesh->vertsPerFrame = srcMesh->vertsPerFrame;
    mesh->setFlags(srcMesh->getFlags());
    mesh->setFlags(srcMesh->getFlags());
-   mesh->mHasColor = srcMesh->mHasColor;
-   mesh->mHasTVert2 = srcMesh->mHasTVert2;
    mesh->mNumVerts = srcMesh->mNumVerts;
    mesh->mNumVerts = srcMesh->mNumVerts;
 
 
-   if ( srcMesh->mVertexData.isReady() )
-   {
-      mesh->mVertexData.set( NULL, 0, 0, false );
-      void *aligned_mem = dMalloc_aligned( mVertSize * srcMesh->mVertexData.size(), 16 );
-
-      // Copy the source data (note that the destination shape may have different vertex size)
-      if ( mVertSize == srcMesh->mVertexData.size() )
-      {
-         dMemcpy( aligned_mem, srcMesh->mVertexData.address(), srcMesh->mVertexData.mem_size() );
-      }
-      else
-      {
-         U8* src = (U8*)srcMesh->mVertexData.address();
-         U8* dest = (U8*)aligned_mem;
-         for ( S32 i = 0; i < srcMesh->mVertexData.size(); i++ )
-         {
-            dMemcpy( dest, src, srcMesh->mVertexData.vertSize() );
-            src += srcMesh->mVertexData.vertSize();
-            dest += mVertSize;
-         }
-      }
-      mesh->mVertexData.set( aligned_mem, mVertSize, srcMesh->mVertexData.size() );
-      mesh->mVertexData.setReady( true );
-   }
-   else
-   {
-      mesh->verts = srcMesh->verts;
-      mesh->tverts = srcMesh->tverts;
-      mesh->tverts2 = srcMesh->tverts2;
-      mesh->colors = srcMesh->colors;
-      mesh->norms = srcMesh->norms;
-
-      mesh->createTangents(mesh->verts, mesh->norms);
-      mesh->encodedNorms.set(NULL,0);
+   // Copy vertex data in an *unpacked* form
+   mesh->copySourceVertexDataFrom(srcMesh);
 
 
-      mesh->convertToAlignedMeshData();
-   }
+   mesh->createTangents(mesh->verts, mesh->norms);
+   mesh->encodedNorms.set(NULL, 0);
 
 
    mesh->computeBounds();
    mesh->computeBounds();
 
 
-   if ( mesh->getMeshType() != TSMesh::SkinMeshType )
-      mesh->createVBIB();
-
    return mesh;
    return mesh;
 }
 }
 
 

+ 109 - 11
Engine/source/ts/tsShapeInstance.cpp

@@ -368,8 +368,9 @@ void TSShapeInstance::renderDebugNormals( F32 normalScalar, S32 dl )
          PrimBuild::begin( GFXLineList, 2 * numNrms );
          PrimBuild::begin( GFXLineList, 2 * numNrms );
          for ( U32 n = 0; n < numNrms; n++ )
          for ( U32 n = 0; n < numNrms; n++ )
          {
          {
-            Point3F norm = mesh->mVertexData[n].normal();
-            Point3F vert = mesh->mVertexData[n].vert();
+            const TSMesh::__TSMeshVertexBase &v = mesh->mVertexData.getBase(n);
+            Point3F norm = v.normal();
+            Point3F vert = v.vert();
 
 
             meshMat.mulP( vert );
             meshMat.mulP( vert );
             meshMat.mulV( norm );
             meshMat.mulV( norm );
@@ -527,17 +528,65 @@ void TSShapeInstance::render( const TSRenderState &rdata, S32 dl, F32 intraDL )
       return;
       return;
    }
    }
 
 
-   // run through the meshes   
    S32 start = rdata.isNoRenderNonTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss];
    S32 start = rdata.isNoRenderNonTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss];
-   S32 end   = rdata.isNoRenderTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss] + mShape->subShapeNumObjects[ss];
+   S32 end = rdata.isNoRenderTranslucent() ? mShape->subShapeFirstTranslucentObject[ss] : mShape->subShapeFirstObject[ss] + mShape->subShapeNumObjects[ss];
+   TSVertexBufferHandle *realBuffer;
+
+   if (TSShape::smUseHardwareSkinning)
+   {
+      // For hardware skinning, just using the buffer associated with the shape will work fine
+      realBuffer = &mShape->mShapeVertexBuffer;
+   }
+   else
+   {
+      // For software skinning, we need to update our own buffer each frame
+      realBuffer = &mSoftwareVertexBuffer;
+      if (realBuffer->getPointer() == NULL)
+      {
+         mShape->getVertexBuffer(*realBuffer, GFXBufferTypeDynamic);
+      }
+
+      if (bufferNeedsUpdate(od, start, end))
+      {
+         U8 *buffer = realBuffer->lock();
+         if (!buffer)
+            return;
+
+         // Base vertex data
+         dMemcpy(buffer, mShape->mShapeVertexData.base, mShape->mShapeVertexData.size);
+
+         // Apply skinned verts (where applicable)
+         for (i = start; i < end; i++)
+         {
+            mMeshObjects[i].updateVertexBuffer(od, buffer);
+         }
+
+         realBuffer->unlock();
+      }
+   }
+
+   // run through the meshes
    for (i=start; i<end; i++)
    for (i=start; i<end; i++)
    {
    {
+      TSRenderState objState = rdata;
       // following line is handy for debugging, to see what part of the shape that it is rendering
       // following line is handy for debugging, to see what part of the shape that it is rendering
-      // const char *name = mShape->names[ mMeshObjects[i].object->nameIndex ];
-      mMeshObjects[i].render( od, mMaterialList, rdata, mAlphaAlways ? mAlphaAlwaysValue : 1.0f );
+      const char *name = mShape->names[ mMeshObjects[i].object->nameIndex ];
+      mMeshObjects[i].render( od, *realBuffer, mMaterialList, objState, mAlphaAlways ? mAlphaAlwaysValue : 1.0f, name );
    }
    }
 }
 }
 
 
+bool TSShapeInstance::bufferNeedsUpdate(S32 objectDetail, S32 start, S32 end)
+{
+   // run through the meshes
+   for (U32 i = start; i<end; i++)
+   {
+      if (mMeshObjects[i].bufferNeedsUpdate(objectDetail))
+         return true;
+   }
+
+   return false;
+}
+
 void TSShapeInstance::setCurrentDetail( S32 dl, F32 intraDL )
 void TSShapeInstance::setCurrentDetail( S32 dl, F32 intraDL )
 {
 {
    PROFILE_SCOPE( TSShapeInstance_setCurrentDetail );
    PROFILE_SCOPE( TSShapeInstance_setCurrentDetail );
@@ -711,15 +760,27 @@ S32 TSShapeInstance::setDetailFromScreenError( F32 errorTolerance )
 // Object (MeshObjectInstance & PluginObjectInstance) render methods
 // Object (MeshObjectInstance & PluginObjectInstance) render methods
 //-------------------------------------------------------------------------------------
 //-------------------------------------------------------------------------------------
 
 
-void TSShapeInstance::ObjectInstance::render( S32, TSMaterialList *, const TSRenderState &rdata, F32 alpha )
+void TSShapeInstance::ObjectInstance::render( S32, TSVertexBufferHandle &vb, TSMaterialList *, TSRenderState &rdata, F32 alpha, const char *meshName )
 {
 {
    AssertFatal(0,"TSShapeInstance::ObjectInstance::render:  no default render method.");
    AssertFatal(0,"TSShapeInstance::ObjectInstance::render:  no default render method.");
 }
 }
 
 
+void TSShapeInstance::ObjectInstance::updateVertexBuffer( S32 objectDetail, U8 *buffer )
+{
+   AssertFatal(0, "TSShapeInstance::ObjectInstance::updateVertexBuffer:  no default vertex buffer update method.");
+}
+
+bool TSShapeInstance::ObjectInstance::bufferNeedsUpdate( S32 objectDetai )
+{
+   return false;
+}
+
 void TSShapeInstance::MeshObjectInstance::render(  S32 objectDetail, 
 void TSShapeInstance::MeshObjectInstance::render(  S32 objectDetail, 
+                                                   TSVertexBufferHandle &vb,
                                                    TSMaterialList *materials, 
                                                    TSMaterialList *materials, 
-                                                   const TSRenderState &rdata, 
-                                                   F32 alpha )
+                                                   TSRenderState &rdata, 
+                                                   F32 alpha,
+                                                   const char *meshName )
 {
 {
    PROFILE_SCOPE( TSShapeInstance_MeshObjectInstance_render );
    PROFILE_SCOPE( TSShapeInstance_MeshObjectInstance_render );
 
 
@@ -751,12 +812,22 @@ void TSShapeInstance::MeshObjectInstance::render(  S32 objectDetail,
    const U32 currTime = Sim::getCurrentTime();
    const U32 currTime = Sim::getCurrentTime();
    bool isSkinDirty = currTime != mLastTime;
    bool isSkinDirty = currTime != mLastTime;
 
 
+   // Update active transform list for bones for GPU skinning
+   if ( mesh->getMeshType() == TSMesh::SkinMeshType )
+   {
+      if (isSkinDirty)
+      {
+         static_cast<TSSkinMesh*>(mesh)->updateSkinBones(*mTransforms, mActiveTransforms);
+      }
+      rdata.setNodeTransforms(mActiveTransforms.address(), mActiveTransforms.size());
+   }
+
    mesh->render(  materials, 
    mesh->render(  materials, 
                   rdata, 
                   rdata, 
                   isSkinDirty,
                   isSkinDirty,
                   *mTransforms, 
                   *mTransforms, 
-                  mVertexBuffer,
-                  mPrimitiveBuffer );
+                  vb,
+                  meshName );
 
 
    // Update the last render time.
    // Update the last render time.
    mLastTime = currTime;
    mLastTime = currTime;
@@ -764,6 +835,33 @@ void TSShapeInstance::MeshObjectInstance::render(  S32 objectDetail,
    GFX->popWorldMatrix();
    GFX->popWorldMatrix();
 }
 }
 
 
+void TSShapeInstance::MeshObjectInstance::updateVertexBuffer(S32 objectDetail, U8 *buffer)
+{
+   PROFILE_SCOPE(TSShapeInstance_MeshObjectInstance_updateVertexBuffer);
+
+   if (forceHidden || ((visible) <= 0.01f))
+      return;
+
+   TSMesh *mesh = getMesh(objectDetail);
+   if (!mesh)
+      return;
+
+   // Update the buffer here
+   if (mesh->getMeshType() == TSMesh::SkinMeshType)
+   {
+      static_cast<TSSkinMesh*>(mesh)->updateSkinBuffer(*mTransforms, buffer);
+   }
+
+   mLastTime = Sim::getCurrentTime();
+}
+
+bool TSShapeInstance::MeshObjectInstance::bufferNeedsUpdate( S32 objectDetail )
+{
+   TSMesh *mesh = getMesh(objectDetail);
+   const U32 currTime = Sim::getCurrentTime();
+   return mesh && mesh->getMeshType() == TSMesh::SkinMeshType && currTime != mLastTime;
+}
+
 TSShapeInstance::MeshObjectInstance::MeshObjectInstance() 
 TSShapeInstance::MeshObjectInstance::MeshObjectInstance() 
    : meshList(0), object(0), frame(0), matFrame(0),
    : meshList(0), object(0), frame(0), matFrame(0),
      visible(1.0f), forceHidden(false), mLastTime( 0 )
      visible(1.0f), forceHidden(false), mLastTime( 0 )

+ 17 - 6
Engine/source/ts/tsShapeInstance.h

@@ -126,7 +126,11 @@ class TSShapeInstance
      /// @{
      /// @{
 
 
      /// Render!  This draws the base-textured object.
      /// Render!  This draws the base-textured object.
-      virtual void render( S32 objectDetail, TSMaterialList *, const TSRenderState &rdata, F32 alpha );      
+      virtual void render( S32 objectDetail, TSVertexBufferHandle &vb, TSMaterialList *, TSRenderState &rdata, F32 alpha, const char *meshName );
+
+     /// Updates the vertex buffer data for this mesh (used for software skinning)
+      virtual void updateVertexBuffer( S32 objectDetail, U8 *buffer );
+      virtual bool bufferNeedsUpdate( S32 objectDetail );
      /// @}
      /// @}
 
 
      /// @name Collision Routines
      /// @name Collision Routines
@@ -157,18 +161,21 @@ class TSShapeInstance
       /// If true this mesh is forced to be hidden
       /// If true this mesh is forced to be hidden
       /// regardless of the animation state.
       /// regardless of the animation state.
       bool forceHidden;
       bool forceHidden;
-
-      TSVertexBufferHandle mVertexBuffer;
-      GFXPrimitiveBufferHandle mPrimitiveBuffer;
       
       
       /// The time at which this mesh 
       /// The time at which this mesh 
       /// was last rendered.
       /// was last rendered.
       U32 mLastTime;
       U32 mLastTime;
 
 
+      Vector<MatrixF> mActiveTransforms;
+
       MeshObjectInstance();
       MeshObjectInstance();
       virtual ~MeshObjectInstance() {}
       virtual ~MeshObjectInstance() {}
 
 
-      void render( S32 objectDetail, TSMaterialList *, const TSRenderState &rdata, F32 alpha );
+      void render( S32 objectDetail, TSVertexBufferHandle &vb, TSMaterialList *, TSRenderState &rdata, F32 alpha, const char *meshName );
+
+      void updateVertexBuffer( S32 objectDetail, U8 *buffer );
+
+      bool bufferNeedsUpdate(S32 objectDetail);
 
 
       /// Gets the mesh with specified detail level
       /// Gets the mesh with specified detail level
       TSMesh * getMesh(S32 num) const { return num<object->numMeshes ? *(meshList+num) : NULL; }
       TSMesh * getMesh(S32 num) const { return num<object->numMeshes ? *(meshList+num) : NULL; }
@@ -268,7 +275,9 @@ protected:
    /// equal mShapeResource if it was created from a resource.
    /// equal mShapeResource if it was created from a resource.
    TSShape *mShape;
    TSShape *mShape;
 
 
-   
+   /// Vertex buffer used for software skinning this instance
+   TSVertexBufferHandle mSoftwareVertexBuffer;
+
    bool            mOwnMaterialList; ///< Does this own the material list pointer?
    bool            mOwnMaterialList; ///< Does this own the material list pointer?
 
 
    bool           mAlphaAlways;
    bool           mAlphaAlways;
@@ -488,6 +497,8 @@ protected:
    void render( const TSRenderState &rdata );
    void render( const TSRenderState &rdata );
    void render( const TSRenderState &rdata, S32 dl, F32 intraDL = 0.0f );
    void render( const TSRenderState &rdata, S32 dl, F32 intraDL = 0.0f );
 
 
+   bool bufferNeedsUpdate(S32 objectDetail, S32 start, S32 end);
+
    void animate() { animate( mCurrentDetailLevel ); }
    void animate() { animate( mCurrentDetailLevel ); }
    void animate(S32 dl);
    void animate(S32 dl);
    void animateNodes(S32 ss);
    void animateNodes(S32 ss);

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно