mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-21 20:35:35 +00:00
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:
parent
507c239a87
commit
3496c549b5
72 changed files with 2533 additions and 1327 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -157,6 +157,7 @@ TSMesh* AppMesh::constructTSMesh()
|
|||
|
||||
// Finish initializing the shape
|
||||
tsmesh->setFlags(flags);
|
||||
tsmesh->updateMeshFlags();
|
||||
tsmesh->computeBounds();
|
||||
tsmesh->numFrames = numFrames;
|
||||
tsmesh->numMatFrames = numMatFrames;
|
||||
|
|
|
|||
|
|
@ -1229,6 +1229,7 @@ void TSShapeLoader::install()
|
|||
shape->tubeRadius = shape->radius;
|
||||
|
||||
shape->init();
|
||||
shape->finalizeEditable();
|
||||
}
|
||||
|
||||
void TSShapeLoader::computeBounds(Box3F& bounds)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// @{
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue