Torque3D/Engine/source/ts/tsMesh.h
2012-09-19 11:15:01 -04:00

548 lines
18 KiB
C++
Raw Blame History

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _TSMESH_H_
#define _TSMESH_H_
#ifndef _STREAM_H_
#include "core/stream/stream.h"
#endif
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _ABSTRACTPOLYLIST_H_
#include "collision/abstractPolyList.h"
#endif
#ifndef _GFXDEVICE_H_
#include "gfx/gfxDevice.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _TSPARSEARRAY_H_
#include "core/tSparseArray.h"
#endif
#include "core/util/safeDelete.h"
#if defined(TORQUE_OS_XENON)
//# define USE_MEM_VERTEX_BUFFERS
#endif
#if defined(USE_MEM_VERTEX_BUFFERS)
# include "gfx/D3D9/360/gfx360MemVertexBuffer.h"
#endif
namespace Opcode { class Model; class MeshInterface; }
namespace IceMaths { class IndexedTriangle; class Point; }
class Convex;
class SceneRenderState;
class SceneObject;
struct MeshRenderInst;
class TSRenderState;
class RenderPassManager;
class TSMaterialList;
class TSShapeInstance;
struct RayInfo;
class ConvexFeature;
class ShapeBase;
struct TSDrawPrimitive
{
enum
{
Triangles = 0 << 30, ///< bits 30 and 31 index element type
Strip = 1 << 30, ///< bits 30 and 31 index element type
Fan = 2 << 30, ///< bits 30 and 31 index element type
Indexed = BIT(29), ///< use glDrawElements if indexed, glDrawArrays o.w.
NoMaterial = BIT(28), ///< set if no material (i.e., texture missing)
MaterialMask = ~(Strip|Fan|Triangles|Indexed|NoMaterial),
TypeMask = Strip|Fan|Triangles
};
S32 start;
S32 numElements;
S32 matIndex; ///< holds material index & element type (see above enum)
};
#if defined(USE_MEM_VERTEX_BUFFERS)
struct __NullVertexStruct {};
typedef GFX360MemVertexBufferHandle<__NullVertexStruct> TSVertexBufferHandle;
#else
typedef GFXVertexBufferDataHandle TSVertexBufferHandle;
#endif
///
class TSMesh
{
friend class TSShape;
public:
struct TSMeshVertexArray;
protected:
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
{
/// 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),
FlagMask = Billboard|BillboardZAxis|HasDetailTexture|UseEncodedNormals
};
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)
struct __TSMeshVertexBase
{
Point3F _vert;
F32 _tangentW;
Point3F _normal;
Point3F _tangent;
Point2F _tvert;
const Point3F &vert() const { return _vert; }
void vert(const Point3F &v) { _vert = v; }
const Point3F &normal() const { return _normal; }
void normal(const Point3F &n) { _normal = n; }
Point4F tangent() const { return Point4F(_tangent.x, _tangent.y, _tangent.z, _tangentW); }
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; }
};
struct __TSMeshVertex_3xUVColor : public __TSMeshVertexBase
{
Point2F _tvert2;
GFXVertexColor _color;
F32 _tvert3; // Unused, but needed for alignment purposes
};
#pragma pack()
struct TSMeshVertexArray
{
protected:
U8 *base;
dsize_t vertSz;
bool vertexDataReady;
U32 numElements;
public:
TSMeshVertexArray() : base(NULL), vertexDataReady(false), numElements(0) {}
virtual ~TSMeshVertexArray() { set(NULL, 0, 0); }
virtual void set(void *b, dsize_t s, U32 n, bool autoFree = true )
{
if(base && autoFree)
dFree_aligned(base);
base = reinterpret_cast<U8 *>(b);
vertSz = s;
numElements = n;
}
// Vector-like interface
__TSMeshVertexBase &operator[](int 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; }
};
bool mHasColor;
bool mHasTVert2;
TSMeshVertexArray mVertexData;
dsize_t mNumVerts;
virtual void convertToAlignedMeshData();
/// @}
/// @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;
FreeableVector<Point4F> tangents;
// Optional second texture uvs.
FreeableVector<Point2F> tverts2;
// Optional vertex colors data.
FreeableVector<ColorI> colors;
/// @}
Vector<TSDrawPrimitive> primitives;
Vector<U8> encodedNorms;
Vector<U32> indices;
/// billboard data
Point3F billboardAxis;
/// @name Convex Hull Data
/// Convex hulls are convex (no angles >= 180<38>) meshes used for collision
/// @{
Vector<Point3F> planeNormals;
Vector<F32> planeConstants;
Vector<U32> planeMaterials;
S32 planesPerFrame;
U32 mergeBufferStart;
/// @}
/// @name Render Methods
/// @{
/// This is used by sgShadowProjector to render the
/// mesh directly, skipping the render manager.
virtual void render( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
void innerRender( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
virtual void render( TSMaterialList *,
const TSRenderState &data,
bool isSkinDirty,
const Vector<MatrixF> &transforms,
TSVertexBufferHandle &vertexBuffer,
GFXPrimitiveBufferHandle &primitiveBuffer );
void innerRender( TSMaterialList *, const TSRenderState &data, TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb );
/// @}
/// @name Material Methods
/// @{
void setFade( F32 fade ) { mVisibility = fade; }
void clearFade() { setFade( 1.0f ); }
/// @}
/// @name Collision Methods
/// @{
virtual bool buildPolyList( S32 frame, AbstractPolyList * polyList, U32 & surfaceKey, TSMaterialList* materials );
virtual bool getFeatures( S32 frame, const MatrixF&, const VectorF&, ConvexFeature*, U32 &surfaceKey );
virtual void support( S32 frame, const Point3F &v, F32 *currMaxDP, Point3F *currSupport );
virtual bool castRay( S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials );
virtual bool castRayRendered( S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials );
virtual bool buildConvexHull(); ///< returns false if not convex (still builds planes)
bool addToHull( U32 idx0, U32 idx1, U32 idx2 );
/// @}
/// @name Bounding Methods
/// calculate and get bounding information
/// @{
void computeBounds();
virtual void computeBounds( const MatrixF &transform, Box3F &bounds, S32 frame = 0, Point3F *center = NULL, F32 *radius = NULL );
void computeBounds( const Point3F *, S32 numVerts, S32 stride, const MatrixF &transform, Box3F &bounds, Point3F *center, F32 *radius );
const Box3F& getBounds() const { return mBounds; }
const Point3F& getCenter() const { return mCenter; }
F32 getRadius() const { return mRadius; }
virtual S32 getNumPolys() const;
static U8 encodeNormal( const Point3F &normal );
static const Point3F& decodeNormal( U8 ncode ) { return smU8ToNormalTable[ncode]; }
/// @}
/// 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,
U32 index3,
Point3F *tan0,
Point3F *tan1,
const Vector<Point3F> &_verts);
/// on load...optionally convert primitives to other form
static bool smUseTriangles;
static bool smUseOneStrip;
static S32 smMinStripSize;
static bool smUseEncodedNormals;
/// Enables mesh instancing on non-skin meshes that
/// have less that this count of verts.
static S32 smMaxInstancingVerts;
/// convert primitives on load...
void convertToTris(const TSDrawPrimitive *primitivesIn, const S32 *indicesIn,
S32 numPrimIn, S32 & numPrimOut, S32 & numIndicesOut,
TSDrawPrimitive *primitivesOut, S32 *indicesOut) const;
void convertToSingleStrip(const TSDrawPrimitive *primitivesIn, const S32 *indicesIn,
S32 numPrimIn, S32 &numPrimOut, S32 &numIndicesOut,
TSDrawPrimitive *primitivesOut, S32 *indicesOut) const;
void leaveAsMultipleStrips(const TSDrawPrimitive *primitivesIn, const S32 *indicesIn,
S32 numPrimIn, S32 &numPrimOut, S32 &numIndicesOut,
TSDrawPrimitive *primitivesOut, S32 *indicesOut) const;
/// 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 );
S8* getSharedData8( S32 parentMesh, S32 size, S8 **source, bool skip );
/// @name Assembly Variables
/// variables used during assembly (for skipping mesh detail levels
/// on load and for sharing verts between meshes)
/// @{
static Vector<Point3F*> smVertsList;
static Vector<Point3F*> smNormsList;
static Vector<U8*> smEncodedNormsList;
static Vector<Point2F*> smTVertsList;
// Optional second texture uvs.
static Vector<Point2F*> smTVerts2List;
// Optional vertex colors.
static Vector<ColorI*> smColorsList;
static Vector<bool> smDataCopied;
static const Point3F smU8ToNormalTable[];
/// @}
TSMesh();
virtual ~TSMesh();
Opcode::Model *mOptTree;
Opcode::MeshInterface* mOpMeshInterface;
IceMaths::IndexedTriangle* mOpTris;
IceMaths::Point* mOpPoints;
void prepOpcodeCollision();
bool buildConvexOpcode( const MatrixF &mat, const Box3F &bounds, Convex *c, Convex *list );
bool buildPolyListOpcode( const S32 od, AbstractPolyList *polyList, const Box3F &nodeBox, TSMaterialList *materials );
bool castRayOpcode( const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials );
static const F32 VISIBILITY_EPSILON;
};
class TSSkinMesh : public TSMesh
{
public:
struct BatchData
{
enum Constants
{
maxBonePerVert = 16, // Abitrarily chosen
};
/// @name Batch by vertex
/// These are used for batches where each element is a vertex, built by
/// iterating over 0..maxBonePerVert bone transforms
/// @{
struct TransformOp
{
S32 transformIndex;
F32 weight;
TransformOp() : transformIndex( -1 ), weight( -1.0f ) {}
TransformOp( const S32 tIdx, const F32 w ) : transformIndex( tIdx ), weight( w ) {};
};
struct BatchedVertex
{
S32 vertexIndex;
S32 transformCount;
TransformOp transform[maxBonePerVert];
BatchedVertex() : vertexIndex( -1 ), transformCount( -1 ) {}
};
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;
// # = numverts
Vector<Point3F> initialVerts;
Vector<Point3F> initialNorms;
};
/// This method will build the batch operations and prepare the BatchData
/// for use.
void createBatchData();
virtual void convertToAlignedMeshData();
public:
typedef TSMesh Parent;
/// 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 );
// render methods..
void render( TSVertexBufferHandle &instanceVB, GFXPrimitiveBufferHandle &instancePB );
void render( TSMaterialList *,
const TSRenderState &data,
bool isSkinDirty,
const Vector<MatrixF> &transforms,
TSVertexBufferHandle &vertexBuffer,
GFXPrimitiveBufferHandle &primitiveBuffer );
// collision methods...
bool buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials );
bool castRay( S32 frame, const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials );
bool buildConvexHull(); // does nothing, skins don't use this
void computeBounds( const MatrixF &transform, Box3F &bounds, S32 frame, Point3F *center, F32 *radius );
/// persist methods...
void assemble( bool skip );
void disassemble();
/// variables used during assembly (for skipping mesh detail levels
/// on load and for sharing verts between meshes)
static Vector<MatrixF*> smInitTransformList;
static Vector<S32*> smVertexIndexList;
static Vector<S32*> smBoneIndexList;
static Vector<F32*> smWeightList;
static Vector<S32*> smNodeIndexList;
TSSkinMesh();
};
#endif // _TSMESH_H_