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
This commit is contained in:
James Urquhart 2015-01-10 19:41:25 +00:00
parent 507c239a87
commit 3496c549b5
72 changed files with 2533 additions and 1327 deletions

View file

@ -406,9 +406,10 @@ bool VolumetricFog::LoadShape()
mIsVBDirty = true;
for (U32 k = 0; k < numNrms; k++)
{
Point3F norm = mesh->mVertexData[k].normal();
Point3F vert = mesh->mVertexData[k].vert();
Point2F uv = mesh->mVertexData[k].tvert();
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].texCoord = uv;
tmpVerts[k].normal = norm;

View file

@ -1426,6 +1426,8 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
StringBuilder mainBodyData;
//make shader
mainBodyData.append("VertOut main(VertIn IN){VertOut OUT;");
bool addedPadding = false;
for (U32 i = 0; i < elemCount; i++)
{
const GFXVertexElement &element = vertexFormat->getElement(i);
@ -1433,6 +1435,8 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
String semanticOut = semantic;
String type;
AssertFatal(!(addedPadding && !element.isSemantic(GFXSemantic::PADDING)), "Padding added before data");
if (element.isSemantic(GFXSemantic::POSITION))
{
semantic = "POSITION";
@ -1458,6 +1462,21 @@ String GFXD3D11Device::_createTempShaderInternal(const GFXVertexFormat *vertexFo
semantic = "BINORMAL";
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
{
//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:
type = "float4";
break;
case DXGI_FORMAT_R8G8B8A8_UINT:
type = "uint4";
break;
}
StringBuilder in;
@ -1570,16 +1592,17 @@ GFXVertexDecl* GFXD3D11Device::allocVertexDecl( const GFXVertexFormat *vertexFor
U32 stream;
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();
vd[i].InputSlot = stream;
vd[i].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
vd[i].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
vd[i].Format = GFXD3D11DeclType[element.getType()];
// If instancing is enabled, the per instance data is only used on 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.
vd[i].SemanticIndex = 0;
if ( element.isSemantic( GFXSemantic::POSITION ) )
if (element.isSemantic(GFXSemantic::POSITION))
vd[i].SemanticName = "POSITION";
else if ( element.isSemantic( GFXSemantic::NORMAL ) )
else if (element.isSemantic(GFXSemantic::NORMAL))
vd[i].SemanticName = "NORMAL";
else if ( element.isSemantic( GFXSemantic::COLOR ) )
else if (element.isSemantic(GFXSemantic::COLOR))
vd[i].SemanticName = "COLOR";
else if ( element.isSemantic( GFXSemantic::TANGENT ) )
else if (element.isSemantic(GFXSemantic::TANGENT))
vd[i].SemanticName = "TANGENT";
else if ( element.isSemantic( GFXSemantic::BINORMAL ) )
else if (element.isSemantic(GFXSemantic::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
{
//Anything that falls thru to here will be a texture coord.

View file

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

View file

@ -150,9 +150,11 @@ bool GFXD3D11ConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstTyp
(
(pd.constType == GFXSCT_Float2x2 ||
pd.constType == GFXSCT_Float3x3 ||
pd.constType == GFXSCT_Float4x3 ||
pd.constType == GFXSCT_Float4x4) &&
(constType == GFXSCT_Float2x2 ||
constType == GFXSCT_Float3x3 ||
constType == GFXSCT_Float4x3 ||
constType == GFXSCT_Float4x4)
), "Mismatched const type!");
@ -161,6 +163,7 @@ bool GFXD3D11ConstBufferLayout::set(const ParamDesc& pd, const GFXShaderConstTyp
{
case GFXSCT_Float2x2:
case GFXSCT_Float3x3:
case GFXSCT_Float4x3:
case GFXSCT_Float4x4:
return setMatrix(pd, constType, size, data, basePointer);
break;
@ -201,6 +204,40 @@ bool GFXD3D11ConstBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
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
{
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->mShader == mShader, "Mismatched shaders!");
MatrixF transposed;
mat.transposeTo(transposed);
MatrixF transposed;
if (matrixType == GFXSCT_Float4x3)
{
transposed = mat;
}
else
{
mat.transposeTo(transposed);
}
if (h->mInstancingConstant)
{
@ -510,9 +554,17 @@ void GFXD3D11ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF*
static Vector<MatrixF> transposed;
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?
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_COLUMNS:
{
switch (typeDesc.Columns)
switch (typeDesc.Rows)
{
case 3:
if (typeDesc.Rows == 3)
{
desc.constType = GFXSCT_Float3x3;
}
desc.constType = typeDesc.Columns == 4 ? GFXSCT_Float3x4 : GFXSCT_Float3x3;
break;
case 4:
if (typeDesc.Rows == 4)
{
desc.constType = GFXSCT_Float4x4;
}
desc.constType = typeDesc.Columns == 3 ? GFXSCT_Float4x3 : GFXSCT_Float4x4;
break;
}
}
@ -1513,6 +1559,9 @@ U32 GFXD3D11Shader::getAlignmentValue(const GFXShaderConstType constType) const
case GFXSCT_Float3x3 :
return mRowSizeF * 3;
break;
case GFXSCT_Float4x3:
return mRowSizeF * 3;
break;
case GFXSCT_Float4x4 :
return mRowSizeF * 4;
break;

View file

@ -629,6 +629,8 @@ void GFXD3D9Device::setVertexStream( U32 stream, GFXVertexBuffer *buffer )
mVolatileVB = NULL;
}
U32 offset = d3dBuffer && stream != 0 ? d3dBuffer->mVolatileStart * d3dBuffer->mVertexSize : 0;
// NOTE: We do not use the stream offset here for stream 0
// as that feature is *supposedly* not as well supported as
// using the start index in drawPrimitive.
@ -638,7 +640,7 @@ void GFXD3D9Device::setVertexStream( U32 stream, GFXVertexBuffer *buffer )
D3D9Assert( mD3DDevice->SetStreamSource( stream,
d3dBuffer ? d3dBuffer->vb : NULL,
d3dBuffer && stream != 0 ? d3dBuffer->mVolatileStart * d3dBuffer->mVertexSize : 0,
offset,
d3dBuffer ? d3dBuffer->mVertexSize : 0 ),
"GFXD3D9Device::setVertexStream - Failed to set stream source." );
}
@ -929,10 +931,12 @@ GFXVertexDecl* GFXD3D9Device::allocVertexDecl( const GFXVertexFormat *vertexForm
U32 elemCount = vertexFormat->getElementCount();
U32 offsets[4] = { 0 };
U32 stream;
S32 i = 0;
S32 elemIdx = 0;
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();
@ -955,6 +959,18 @@ GFXVertexDecl* GFXD3D9Device::allocVertexDecl( const GFXVertexFormat *vertexForm
vd[i].Usage = D3DDECLUSAGE_TANGENT;
else if ( element.isSemantic( GFXSemantic::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
{
// 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();
vd[elemCount] = declEnd;
vd[i] = declEnd;
decl = new D3D9VertexDecl();
D3D9Assert( mD3DDevice->CreateVertexDeclaration( vd, &decl->decl ),

View file

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

View file

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

View file

@ -35,6 +35,8 @@
#include "core/stream/fileStream.h"
#include "core/util/safeDelete.h"
#include "console/console.h"
#include "math/mMathFn.h"
using namespace Torque;
@ -172,6 +174,40 @@ bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
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
{
PROFILE_SCOPE(GFXD3D9ShaderBufferLayout_setMatrix_not4x4);
@ -186,6 +222,9 @@ bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
case GFXSCT_Float3x3 :
csize = 48;
break;
case GFXSCT_Float3x4 :
csize = 64;
break;
default:
AssertFatal(false, "Unhandled case!");
return false;
@ -204,6 +243,10 @@ bool GFXD3D9ShaderBufferLayout::setMatrix(const ParamDesc& pd, const GFXShaderCo
dMemcpy(currDestPointer, currSourcePointer, csize);
ret = true;
}
else if (pd.constType == GFXSCT_Float4x3)
{
ret = true;
}
currDestPointer += csize;
currSourcePointer += sizeof(MatrixF);
@ -390,8 +433,15 @@ void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF&
AssertFatal(!h->isSampler(), "Handle is sampler constant!" );
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)
{
@ -420,9 +470,17 @@ void GFXD3D9ShaderConstBuffer::set(GFXShaderConstHandle* handle, const MatrixF*
static Vector<MatrixF> transposed;
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?
if (h->mInstancingConstant)
@ -1069,13 +1127,13 @@ void GFXD3D9Shader::_getShaderConstants( ID3DXConstantTable *table,
case D3DXPC_MATRIX_ROWS :
case D3DXPC_MATRIX_COLUMNS :
{
switch (constantDesc.RegisterCount)
switch (constantDesc.Rows)
{
case 3 :
desc.constType = GFXSCT_Float3x3;
desc.constType = constantDesc.Columns == 4 ? GFXSCT_Float3x4 : GFXSCT_Float3x3;
break;
case 4 :
desc.constType = GFXSCT_Float4x4;
desc.constType = constantDesc.Columns == 3 ? GFXSCT_Float4x3 : GFXSCT_Float4x4;
break;
}
}
@ -1436,9 +1494,15 @@ U32 GFXD3D9Shader::getAlignmentValue(const GFXShaderConstType constType) const
case GFXSCT_Float3x3 :
return mRowSizeF * 3;
break;
case GFXSCT_Float3x4 :
return mRowSizeF * 4;
break;
case GFXSCT_Float4x4 :
return mRowSizeF * 4;
break;
case GFXSCT_Float4x3 :
return mRowSizeF * 3;
break;
//// Scalar
case GFXSCT_Int :
case GFXSCT_Int2 :

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -43,7 +43,9 @@ public: //protected:
U32 mPrimitiveCount;
GFXBufferType mBufferType;
GFXPrimitive *mPrimitiveArray;
GFXDevice *mDevice;
GFXDevice *mDevice;
U32 mVolatileStart;
#ifdef TORQUE_DEBUG
// In debug builds we provide a TOC leak tracking system.
@ -59,7 +61,8 @@ public: //protected:
GFXPrimitiveBuffer( GFXDevice *device,
U32 indexCount,
U32 primitiveCount,
GFXBufferType bufferType )
GFXBufferType bufferType ) :
mVolatileStart(0)
{
mDevice = device;
mIndexCount = indexCount;
@ -122,7 +125,7 @@ public: //protected:
// GFXResource interface
/// 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>

View file

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

View file

@ -37,6 +37,9 @@ namespace GFXSemantic
const String TANGENTW = String( "TANGENTW" ).intern();
const String COLOR = String( "COLOR" ).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:
return 4;
case GFXDeclType_UByte4:
return 4;
default:
return 0;
};
@ -85,6 +91,7 @@ void GFXVertexFormat::copy( const GFXVertexFormat &format )
mHasTangent = format.mHasTangent;
mHasColor = format.mHasColor;
mHasInstancing = format.mHasInstancing;
mHasBlendIndices = format.mHasBlendIndices;
mTexCoordCount = format.mTexCoordCount;
mSizeInBytes = format.mSizeInBytes;
mDescription = format.mDescription;
@ -171,6 +178,35 @@ bool GFXVertexFormat::hasInstancing() const
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
{
if ( mDirty )
@ -199,6 +235,7 @@ void GFXVertexFormat::_updateDirty()
mTexCoordCount = 0;
mHasColor = false;
mHasBlendIndices = false;
mHasNormal = false;
mHasTangent = false;
mSizeInBytes = 0;
@ -222,6 +259,8 @@ void GFXVertexFormat::_updateDirty()
mHasColor = true;
else if ( element.isSemantic( GFXSemantic::TEXCOORD ) )
++mTexCoordCount;
else if ( element.isSemantic( GFXSemantic::BLENDINDICES ) )
mHasBlendIndices = true;
mSizeInBytes += element.getSizeInBytes();
}

View file

@ -45,6 +45,9 @@ namespace GFXSemantic
extern const String TANGENTW;
extern const String COLOR;
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.
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.
bool hasInstancing() const;
/// Returns number of blend indices
U32 getNumBlendIndices() const;
/// Returns the texture coordinate count by
/// counting the number of TEXCOORD semantics.
U32 getTexCoordCount() const;
@ -230,6 +239,9 @@ protected:
/// Is true if there is a COLOR semantic in this vertex format.
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.
bool mHasInstancing;

View file

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

View file

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

View file

@ -608,13 +608,11 @@ void GFXGLDevice::drawIndexedPrimitive( GFXPrimitiveType primType,
U32 startIndex,
U32 primitiveCount )
{
AssertFatal( startVertex == 0, "GFXGLDevice::drawIndexedPrimitive() - Non-zero startVertex unsupported!" );
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)
glDrawElementsInstancedBaseVertex(GFXGLPrimType[primType], primCountToIndexCount(primType, primitiveCount), GL_UNSIGNED_SHORT, buf, mDrawInstancesCount, baseVertex);

View file

@ -92,6 +92,8 @@ static U32 shaderConstTypeSize(GFXShaderConstType type)
return 16;
case GFXSCT_Float3x3:
return 36;
case GFXSCT_Float4x3:
return 48;
case GFXSCT_Float4x4:
return 64;
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)[8] = mat[10];
break;
case GFXSCT_Float4x3:
dMemcpy(mBuffer + _glHandle->mOffset, (const F32*)mat, (sizeof(F32) * 12));// matrix with end row chopped off
break;
case GFXSCT_Float4x4:
{
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");
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:
dMemcpy(mBuffer + _glHandle->mOffset, (F32*)mat, _glHandle->getSize());
break;
@ -443,6 +455,14 @@ bool GFXGLShader::_init()
glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_Tangent, "vTangent");
glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TangentW, "vTangentW");
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_TexCoord1, "vTexCoord1");
glBindAttribLocation(mProgram, Torque::GL_VertexAttrib_TexCoord2, "vTexCoord2");
@ -572,6 +592,9 @@ void GFXGLShader::initConstantDescs()
case GL_FLOAT_MAT4:
desc.constType = GFXSCT_Float4x4;
break;
case GL_FLOAT_MAT4x3: // jamesu - columns, rows
desc.constType = GFXSCT_Float4x3;
break;
case GL_SAMPLER_1D:
case GL_SAMPLER_2D:
case GL_SAMPLER_3D:
@ -805,6 +828,11 @@ void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer)
case GFXSCT_Float3x3:
glUniformMatrix3fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
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:
glUniformMatrix4fv(handle->mLocation, handle->mDesc.arraySize, true, (GLfloat*)(mConstBuffer + handle->mOffset));
break;

View file

@ -11,6 +11,14 @@ namespace Torque
GL_VertexAttrib_Tangent,
GL_VertexAttrib_TangentW,
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_TexCoord1,
GL_VertexAttrib_TexCoord2,

View file

@ -187,6 +187,28 @@ void GFXGLVertexDecl::_initVerticesFormat(U32 stream)
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.
{
String name = element.getSemantic();

View file

@ -80,6 +80,9 @@ protected:
/// This is set by initialization and used by the prepass.
bool mHasNormalMaps;
/// This material makes use of bone transforms
bool mUsesHardwareSkinning;
public:
virtual ~BaseMatInstance();
@ -149,6 +152,9 @@ public:
/// @see setupPass
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
/// should be called after setupPass() within the pass loop.
/// @see setupPass
@ -214,6 +220,8 @@ public:
/// Fast test for use of normal maps in this material.
bool hasNormalMap() const { return mHasNormalMaps; }
bool usesHardwareSkinning() const { return mUsesHardwareSkinning; }
///
MatFeaturesDelegate& getFeaturesDelegate() { return mFeaturesDelegate; }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -53,6 +53,7 @@ public:
virtual MaterialParameters* getDefaultMaterialParameters();
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);

View file

@ -142,6 +142,9 @@ public:
/// Sets the transformation matrix, i.e. Model * View * Projection
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.
virtual void setSceneInfo(SceneRenderState *, const SceneData& sgData, U32 pass) = 0;

View file

@ -44,6 +44,9 @@
// We need to include customMaterialDefinition for ShaderConstHandles::init
#include "materials/customMaterialDefinition.h"
#include "ts/tsShape.h"
///
/// ShaderConstHandles
///
@ -99,6 +102,9 @@ void ShaderConstHandles::init( GFXShader *shader, CustomMaterial* mat /*=NULL*/
for (S32 i = 0; i < TEXTURE_STAGE_COUNT; ++i)
mRTParamsSC[i] = shader->getShaderConstHandle( String::ToString( "$rtParams%d", i ) );
// MFT_HardwareSkinning
mNodeTransforms = shader->getShaderConstHandle( "$nodeTransforms" );
// Clear any existing texture handles.
dMemset( mTexHandlesSC, 0, sizeof( mTexHandlesSC ) );
if(mat)
@ -491,6 +497,12 @@ void ProcessedShaderMaterial::_determineFeatures( U32 stageNum,
&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
// not part of the input feature handle.
fd.features.filter( features );
@ -1217,6 +1229,20 @@ void ProcessedShaderMaterial::setTransforms(const MatrixSet &matrixSet, SceneRen
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)
{
PROFILE_SCOPE( ProcessedShaderMaterial_setSceneInfo );

View file

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

View file

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

View file

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

View file

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

View file

@ -430,6 +430,12 @@ void RenderPrePassMgr::render( SceneRenderState *state )
matrixSet.setProjection(*passRI->projection);
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 ( mat->isInstanced() )
{

View file

@ -243,6 +243,12 @@ void RenderTranslucentMgr::render( SceneRenderState *state )
matrixSet.setProjection(*passRI->projection);
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 ( mat->isInstanced() )
{

View file

@ -101,6 +101,30 @@ Var * AppVertConnectorGLSL::getElement( RegisterType type,
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:
break;
}

View file

@ -33,6 +33,7 @@
#include "core/util/autoPtr.h"
#include "lighting/advanced/advancedLightBinManager.h"
#include "ts/tsShape.h"
LangElement * ShaderFeatureGLSL::setupTexSpaceMat( Vector<ShaderComponent*> &, // componentList
Var **texSpaceMat )
@ -2795,4 +2796,68 @@ void ImposterVertFeatureGLSL::determineFeature( Material *material,
{
if ( features.hasFeature( 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;
}

View file

@ -659,4 +659,17 @@ public:
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_

View file

@ -113,6 +113,9 @@ const char* ShaderGenComponentFactoryGLSL::typeToString( GFXDeclType type )
case GFXDeclType_Float3:
return "vec3";
case GFXDeclType_UByte4:
return "vec4";
case GFXDeclType_Float4:
case GFXDeclType_Color:
return "vec4";
@ -160,6 +163,16 @@ ShaderComponent* ShaderGenComponentFactoryGLSL::createVertexInputConnector( cons
var = vertComp->getElement( RT_COLOR );
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 ) )
{
var = vertComp->getElement( RT_TEXCOORD );

View file

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

View file

@ -32,7 +32,20 @@ Var * ShaderConnectorHLSL::getElement( RegisterType type,
U32 numElements,
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
if( type == RT_TEXCOORD )
@ -42,6 +55,20 @@ Var * ShaderConnectorHLSL::getElement( RegisterType type,
else
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;
}
@ -133,6 +160,46 @@ Var * ShaderConnectorHLSL::getIndexedElement( U32 index, RegisterType type, U32
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:
break;
}
@ -177,6 +244,8 @@ void ShaderConnectorHLSL::reset()
mElementList.setSize( 0 );
mCurTexElem = 0;
mCurBlendIndicesElem = 0;
mCurBlendWeightsElem = 0;
}
void ShaderConnectorHLSL::print( Stream &stream, bool isVertexShader )
@ -231,12 +300,23 @@ void ParamsDefHLSL::assignConstantNumbers()
if (dStrcmp((const char*)var->type, "float4x4") == 0)
{
mCurrConst += (4 * var->arraySize);
} else {
}
else
{
if (dStrcmp((const char*)var->type, "float3x3") == 0)
{
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;
}
}
}
}

View file

@ -33,6 +33,7 @@
#include "core/util/autoPtr.h"
#include "lighting/advanced/advancedLightBinManager.h"
#include "ts/tsShape.h"
LangElement * ShaderFeatureHLSL::setupTexSpaceMat( Vector<ShaderComponent*> &, // componentList
Var **texSpaceMat )
@ -2991,3 +2992,66 @@ void ImposterVertFeatureHLSL::determineFeature( Material *material,
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;
}

View file

@ -663,4 +663,17 @@ public:
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_

View file

@ -121,6 +121,9 @@ const char* ShaderGenComponentFactoryHLSL::typeToString( GFXDeclType type )
case GFXDeclType_Float4:
case GFXDeclType_Color:
return "float4";
case GFXDeclType_UByte4:
return "uint4";
}
}
@ -174,6 +177,22 @@ ShaderComponent* ShaderGenComponentFactoryHLSL::createVertexInputConnector( cons
else
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
{
// Everything else is a texcoord!

View file

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

View file

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

View file

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

View file

@ -99,6 +99,12 @@ protected:
///
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;
public:
@ -139,7 +145,8 @@ public:
ShaderFeature()
: output( NULL ),
mProcessIndex( 0 ),
mInstancingFormat( NULL )
mInstancingFormat( NULL ),
mVertexFormat( NULL )
{
}
@ -285,7 +292,7 @@ public:
/// Called after processing the vertex and processing the pixel
/// 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
/// the existing local var or creates one.

View file

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

View file

@ -26,19 +26,13 @@
#if defined(TORQUE_CPU_X86)
# // 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 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)
# // PPC CPU family implementations
# 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 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
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
#
#else

View file

@ -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

View file

@ -25,84 +25,4 @@
#include "ts/tsMeshIntrinsics.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

View file

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

View file

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

View file

@ -1459,10 +1459,17 @@ void TSMesh::prepOpcodeCollision()
AssertFatal( (curIts - its) == mi->GetNbTriangles(), "Triangle count mismatch!" );
for( S32 i = 0; i < mi->GetNbVertices(); i++ )
{
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
{
pts[i].Set( verts[i].x, verts[i].y, verts[i].z );
}
}
mi->SetPointers( its, pts );

File diff suppressed because it is too large Load diff

View file

@ -96,65 +96,53 @@ typedef GFX360MemVertexBufferHandle<__NullVertexStruct> TSVertexBufferHandle;
typedef GFXVertexBufferDataHandle TSVertexBufferHandle;
#endif
class TSMesh;
class TSShapeAlloc;
/// @name Vertex format serialization
/// {
struct TSBasicVertexFormat
{
S16 texCoordOffset;
S16 boneOffset;
S16 colorOffset;
S16 numBones;
S16 vertexSize;
TSBasicVertexFormat();
TSBasicVertexFormat(TSMesh *mesh);
void getFormat(GFXVertexFormat &fmt);
void calculateSize();
void writeAlloc(TSShapeAlloc* alloc);
void readAlloc(TSShapeAlloc* alloc);
void addMeshRequirements(TSMesh *mesh);
};
/// }
///
class TSMesh
{
friend class TSShape;
public:
struct TSMeshVertexArray;
protected:
public:
U32 meshType;
Box3F mBounds;
Point3F mCenter;
F32 mRadius;
F32 mVisibility;
bool mDynamic;
const GFXVertexFormat *mVertexFormat;
U32 mVertSize;
TSVertexBufferHandle mVB;
GFXPrimitiveBufferHandle mPB;
void _convertToAlignedMeshData( TSMeshVertexArray &vertexData, const Vector<Point3F> &_verts, const Vector<Point3F> &_norms );
void _createVBIB( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
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 );
S32 parentMesh; ///< index into shapes mesh list
S32 numFrames;
S32 numMatFrames;
S32 vertsPerFrame;
/// @name Aligned Vertex Data
/// @{
#pragma pack(1)
/// {
#pragma pack(1)
struct __TSMeshVertexBase
{
Point3F _vert;
@ -173,23 +161,40 @@ class TSMesh
void tangent(const Point4F &t) { _tangent = t.asPoint3F(); _tangentW = t.w; }
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;
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()
struct TSMeshVertexArray
@ -197,53 +202,136 @@ class TSMesh
protected:
U8 *base;
dsize_t vertSz;
bool vertexDataReady;
U32 numElements;
public:
TSMeshVertexArray() : base(NULL), vertexDataReady(false), numElements(0) {}
virtual ~TSMeshVertexArray() { set(NULL, 0, 0); }
U32 colorOffset;
U32 boneOffset;
virtual void set(void *b, dsize_t s, U32 n, bool autoFree = true )
bool vertexDataReady;
bool ownsData;
public:
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 && autoFree)
dFree_aligned(base);
base = reinterpret_cast<U8 *>(b);
vertSz = s;
numElements = n;
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));
}
/// Returns base address of vertex data
__TSMeshVertexBase *address() const
{
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; }
dsize_t mem_size() const { return numElements * vertSz; }
dsize_t vertSize() const { return vertSz; }
bool isReady() const { return vertexDataReady; }
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:
U32 meshType;
Box3F mBounds;
Point3F mCenter;
F32 mRadius;
F32 mVisibility;
const GFXVertexFormat *mVertexFormat;
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
{
/// types...
StandardMeshType = 0,
SkinMeshType = 1,
DecalMeshType = 2,
SortedMeshType = 3,
NullMeshType = 4,
TypeMask = StandardMeshType|SkinMeshType|DecalMeshType|SortedMeshType|NullMeshType,
/// 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;
dsize_t mNumVerts;
virtual void convertToAlignedMeshData();
U32 mNumVerts; ///< Number of verts allocated in main vertex buffer
virtual void convertToVertexData();
virtual void copySourceVertexDataFrom(const TSMesh* srcMesh);
/// @}
/// @name Vertex data
/// @{
template<class T>
class FreeableVector : public Vector<T>
{
public:
bool free_memory() { return Vector<T>::resize(0); }
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; }
};
FreeableVector<Point3F> verts;
FreeableVector<Point3F> norms;
FreeableVector<Point2F> tverts;
@ -279,16 +367,16 @@ class TSMesh
/// This is used by sgShadowProjector to render the
/// mesh directly, skipping the render manager.
virtual void render( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
virtual void render( TSVertexBufferHandle &vb );
void innerRender( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
virtual void render( TSMaterialList *,
const TSRenderState &data,
bool isSkinDirty,
const Vector<MatrixF> &transforms,
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]; }
/// @}
virtual U32 getMaxBonesPerVert() { return 0; }
/// persist methods...
virtual void assemble( bool skip );
static TSMesh* assembleMesh( U32 meshType, bool skip );
virtual void disassemble();
void createVBIB();
void createTangents(const Vector<Point3F> &_verts, const Vector<Point3F> &_norms);
void findTangent( U32 index1,
U32 index2,
@ -350,6 +439,9 @@ class TSMesh
/// have less that this count of verts.
static S32 smMaxInstancingVerts;
/// Default node transform for standard meshes which have blend indices
static MatrixF smDummyNodeTransform;
/// convert primitives on load...
void convertToTris(const TSDrawPrimitive *primitivesIn, const S32 *indicesIn,
S32 numPrimIn, S32 & numPrimOut, S32 & numIndicesOut,
@ -361,6 +453,14 @@ class TSMesh
S32 numPrimIn, S32 &numPrimOut, S32 &numIndicesOut,
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
/// between meshes (and for skipping detail levels on load)
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 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;
};
@ -413,7 +516,7 @@ public:
{
enum Constants
{
maxBonePerVert = 16, // Abitrarily chosen
maxBonePerVert = 16, // Assumes a maximum of 4 blocks of bone indices for HW skinning
};
/// @name Batch by vertex
@ -441,48 +544,6 @@ public:
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
Vector<S32> nodeIndex;
Vector<MatrixF> initialTransforms;
@ -490,36 +551,62 @@ public:
// # = numverts
Vector<Point3F> initialVerts;
Vector<Point3F> initialNorms;
bool initialized;
BatchData() : initialized(false) { ; }
};
/// This method will build the batch operations and prepare the BatchData
/// 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:
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
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...
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..
void render( TSVertexBufferHandle &instanceVB, GFXPrimitiveBufferHandle &instancePB );
void render( TSVertexBufferHandle &instanceVB );
void render( TSMaterialList *,
const TSRenderState &data,
bool isSkinDirty,
const Vector<MatrixF> &transforms,
TSVertexBufferHandle &vertexBuffer,
GFXPrimitiveBufferHandle &primitiveBuffer );
const char *meshName );
// collision methods...
bool buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials );
@ -532,6 +619,14 @@ public:
void assemble( bool skip );
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
/// on load and for sharing verts between meshes)
static Vector<MatrixF*> smInitTransformList;
@ -540,6 +635,8 @@ public:
static Vector<F32*> smWeightList;
static Vector<S32*> smNodeIndexList;
static bool smDebugSkinVerts;
TSSkinMesh();
};

View file

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

View file

@ -26,7 +26,6 @@
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)
@ -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.
//------------------------------------------------------------------------------
@ -86,11 +58,9 @@ MODULE_BEGIN( TSMeshIntrinsics )
{
// Assign defaults (C++ versions)
zero_vert_normal_bulk = zero_vert_normal_bulk_C;
m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_C;
#if defined(TORQUE_OS_XENON)
zero_vert_normal_bulk = zero_vert_normal_bulk_X360;
m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_X360;
#else
// Find the best implementation for the current CPU
if(Platform::SystemInfo.processor.properties & CPU_PROP_SSE)
@ -98,21 +68,12 @@ MODULE_BEGIN( TSMeshIntrinsics )
#if defined(TORQUE_CPU_X86)
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
}
else if(Platform::SystemInfo.processor.properties & CPU_PROP_ALTIVEC)
{
#if !defined(TORQUE_OS_XENON) && defined(TORQUE_CPU_PPC)
zero_vert_normal_bulk = zero_vert_normal_bulk_gccvec;
m_matF_x_BatchedVertWeightList = m_matF_x_BatchedVertWeightList_gccvec;
#endif
}
#endif

View file

@ -23,20 +23,6 @@
#ifndef _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)
///
/// @param count Number of elements

View file

@ -206,7 +206,11 @@ void TSPartInstance::render(S32 od, const TSRenderState &rdata)
// render mesh objects
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);
}
}
//-------------------------------------------------------------------------------------

View file

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

View file

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

View file

@ -42,7 +42,7 @@ extern TSShape* loadColladaShape(const Torque::Path &path);
#endif
/// 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
S32 TSShape::smReadVersion = -1;
const U32 TSShape::smMostRecentExporterVersion = DTS_EXPORTER_CURRENT_VERSION;
@ -58,13 +58,14 @@ F32 TSShape::smAlphaOutDefault = -1.0f;
S32 TSShape::smNumSkipLoadDetails = 0;
bool TSShape::smInitOnRead = true;
bool TSShape::smUseHardwareSkinning = true;
U32 TSShape::smMaxSkinBones = 70;
TSShape::TSShape()
{
materialList = NULL;
mReadVersion = -1; // -1 means constructed from scratch (e.g., in exporter or no read yet)
mHasSkinMesh = false;
mSequencesConstructed = false;
mShapeData = NULL;
mShapeDataSize = 0;
@ -286,6 +287,29 @@ bool TSShape::findMeshIndex(const String& meshName, S32& objIndex, S32& meshInde
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)
{
S32 objIndex, meshIndex;
@ -545,75 +569,356 @@ void TSShape::init()
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();
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()
{
bool hasColors = 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())
{
// 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++)
{
TSMesh *mesh = *iter;
if (mesh &&
(mesh->getMeshType() == TSMesh::SkinMeshType))
{
static_cast<TSSkinMesh*>(mesh)->createSkinBatchData();
}
}
// 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 ) )
if (mesh &&
(mesh->getMeshType() == TSMesh::StandardMeshType ||
mesh->getMeshType() == TSMesh::SkinMeshType))
{
if ( mesh->mVertexData.isReady() )
// 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->mHasColor;
hasTexcoord2 |= mesh->mHasTVert2;
}
else
{
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.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 );
if(hasTexcoord2 || hasColors)
{
mVertexFormat.addElement( GFXSemantic::TEXCOORD, GFXDeclType_Float2, 1 );
mVertexFormat.addElement( GFXSemantic::COLOR, GFXDeclType_Color );
mVertexFormat.addElement( GFXSemantic::TEXCOORD, GFXDeclType_Float, 2 );
}
U32 destVertex = 0;
U32 destIndices = 0;
// 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++ )
U32 count = 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 ) )
if (!mesh ||
(mesh->getMeshType() != TSMesh::StandardMeshType &&
mesh->getMeshType() != TSMesh::SkinMeshType))
continue;
// Set the flags.
mesh->mVertexFormat = &mVertexFormat;
mesh->mVertSize = mVertSize;
mesh->mVertSize = mVertexSize;
mesh->mVertOffset = destVertex;
// Create and fill aligned data structure
mesh->convertToAlignedMeshData();
destVertex += mesh->mVertSize * mesh->getNumVerts();
destIndices += mesh->indices.size();
// Init the vertex buffer.
if ( mesh->getMeshType() == TSMesh::StandardMeshType )
mesh->createVBIB();
count += 1;
}
// 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;
U32 idx = iter - meshes.begin();
if (!mesh ||
(mesh->getMeshType() != TSMesh::StandardMeshType &&
mesh->getMeshType() != TSMesh::SkinMeshType))
continue;
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;
}
// 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 )
@ -654,8 +959,6 @@ void TSShape::initMaterialList()
subShapeFirstTranslucentObject.setSize(numSubShapes);
#endif
mHasSkinMesh = false;
S32 i,j,k;
// for each subshape, find the first translucent object
// also, while we're at it, set mHasTranslucency
@ -674,8 +977,6 @@ void TSShape::initMaterialList()
if (!mesh)
continue;
mHasSkinMesh |= mesh->getMeshType() == TSMesh::SkinMeshType;
for (k=0; k<mesh->primitives.size(); k++)
{
if (mesh->primitives[k].matIndex & TSDrawPrimitive::NoMaterial)
@ -1118,6 +1419,40 @@ void TSShape::assembleShape()
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
S32 scratchSize = getMax(numSkins,numMeshes);
TSMesh::smVertsList.setSize(scratchSize);
@ -1401,6 +1736,19 @@ void TSShape::disassembleShape()
}
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)...
bool * isMesh = new bool[numMeshes]; // funny business because decals are pretend meshes (legacy issue)
for (i=0;i<numMeshes;i++)
@ -1618,226 +1966,9 @@ bool TSShape::read(Stream * s)
delete [] memBuffer32;
if (smInitOnRead)
{
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;
}
@ -2294,3 +2425,14 @@ void TSShape::computeAccelerator(S32 dl)
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();
}
}
}

View file

@ -50,6 +50,25 @@ struct CollisionShapeInfo
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 and TSShapeInstance act in conjunction to allow the rendering and
@ -381,19 +400,21 @@ class TSShape
/// The GFX vertex format for all detail meshes in the shape.
/// @see initVertexFeatures()
GFXVertexFormat mVertexFormat;
/// The GFX vertex size in bytes for all detail meshes in the shape.
/// @see initVertexFeatures()
U32 mVertSize;
/// Is true if this shape contains skin meshes.
bool mHasSkinMesh;
bool mSequencesConstructed;
TSBasicVertexFormat mBasicVertexFormat;
U32 mVertexSize;
S8* mShapeData;
U32 mShapeDataSize;
// Processed vertex data
TSShapeVertexArray mShapeVertexData;
TSVertexBufferHandle mShapeVertexBuffer;
GFXPrimitiveBufferHandle mShapeVertexIndices;
bool mSequencesConstructed;
// shape class has few methods --
// just constructor/destructor, io, and lookup methods
@ -402,14 +423,24 @@ class TSShape
~TSShape();
void init();
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
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
/// all detail meshes in the shape.
void initVertexFeatures();
/// Inits basic buffer pointers on load
void initVertexBufferPointers();
bool getSequencesConstructed() const { return mSequencesConstructed; }
void setSequencesConstructed(const bool c) { mSequencesConstructed = c; }
@ -526,7 +557,7 @@ class TSShape
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...
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
/// @{

View file

@ -892,10 +892,6 @@ TSMesh* TSShape::copyMesh( const TSMesh* srcMesh ) const
mesh = new TSMesh;
}
// Set vertex format (all meshes in this shape must share the same format)
mesh->mVertSize = mVertSize;
mesh->mVertexFormat = &mVertexFormat;
if ( !srcMesh )
return mesh; // return an empty mesh
@ -906,53 +902,16 @@ TSMesh* TSShape::copyMesh( const TSMesh* srcMesh ) const
mesh->numMatFrames = srcMesh->numMatFrames;
mesh->vertsPerFrame = srcMesh->vertsPerFrame;
mesh->setFlags(srcMesh->getFlags());
mesh->mHasColor = srcMesh->mHasColor;
mesh->mHasTVert2 = srcMesh->mHasTVert2;
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 vertex data in an *unpacked* form
mesh->copySourceVertexDataFrom(srcMesh);
// 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);
mesh->convertToAlignedMeshData();
}
mesh->createTangents(mesh->verts, mesh->norms);
mesh->encodedNorms.set(NULL, 0);
mesh->computeBounds();
if ( mesh->getMeshType() != TSMesh::SkinMeshType )
mesh->createVBIB();
return mesh;
}

View file

@ -368,8 +368,9 @@ void TSShapeInstance::renderDebugNormals( F32 normalScalar, S32 dl )
PrimBuild::begin( GFXLineList, 2 * numNrms );
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.mulV( norm );
@ -527,17 +528,65 @@ void TSShapeInstance::render( const TSRenderState &rdata, S32 dl, F32 intraDL )
return;
}
// run through the meshes
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++)
{
TSRenderState objState = rdata;
// 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 )
{
PROFILE_SCOPE( TSShapeInstance_setCurrentDetail );
@ -711,15 +760,27 @@ S32 TSShapeInstance::setDetailFromScreenError( F32 errorTolerance )
// 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.");
}
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,
TSVertexBufferHandle &vb,
TSMaterialList *materials,
const TSRenderState &rdata,
F32 alpha )
TSRenderState &rdata,
F32 alpha,
const char *meshName )
{
PROFILE_SCOPE( TSShapeInstance_MeshObjectInstance_render );
@ -751,12 +812,22 @@ void TSShapeInstance::MeshObjectInstance::render( S32 objectDetail,
const U32 currTime = Sim::getCurrentTime();
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,
rdata,
isSkinDirty,
*mTransforms,
mVertexBuffer,
mPrimitiveBuffer );
vb,
meshName );
// Update the last render time.
mLastTime = currTime;
@ -764,6 +835,33 @@ void TSShapeInstance::MeshObjectInstance::render( S32 objectDetail,
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()
: meshList(0), object(0), frame(0), matFrame(0),
visible(1.0f), forceHidden(false), mLastTime( 0 )

View file

@ -126,7 +126,11 @@ class TSShapeInstance
/// @{
/// 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
@ -157,18 +161,21 @@ class TSShapeInstance
/// If true this mesh is forced to be hidden
/// regardless of the animation state.
bool forceHidden;
TSVertexBufferHandle mVertexBuffer;
GFXPrimitiveBufferHandle mPrimitiveBuffer;
/// The time at which this mesh
/// was last rendered.
U32 mLastTime;
Vector<MatrixF> mActiveTransforms;
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
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.
TSShape *mShape;
/// Vertex buffer used for software skinning this instance
TSVertexBufferHandle mSoftwareVertexBuffer;
bool mOwnMaterialList; ///< Does this own the material list pointer?
bool mAlphaAlways;
@ -488,6 +497,8 @@ protected:
void render( const TSRenderState &rdata );
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(S32 dl);
void animateNodes(S32 ss);