//----------------------------------------------------------------------------- // 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. //----------------------------------------------------------------------------- #include "ts/loader/appMesh.h" #include "ts/loader/tsShapeLoader.h" Vector AppMesh::appMaterials; AppMesh::AppMesh() : flags(0), vertsPerFrame(0),numFrames(0), numMatFrames(0), detailSize(1) { } AppMesh::~AppMesh() { } void AppMesh::computeBounds(Box3F& bounds) { bounds = Box3F::Invalid; if ( isSkin() ) { // Need to skin the mesh before we can compute the bounds // Setup bone transforms Vector boneTransforms; boneTransforms.setSize( nodeIndex.size() ); for (S32 iBone = 0; iBone < boneTransforms.size(); iBone++) { MatrixF nodeMat = bones[iBone]->getNodeTransform( TSShapeLoader::DefaultTime ); TSShapeLoader::zapScale(nodeMat); boneTransforms[iBone].mul( nodeMat, initialTransforms[iBone] ); } // Multiply verts by weighted bone transforms for (S32 iVert = 0; iVert < initialVerts.size(); iVert++) points[iVert].set( Point3F::Zero ); for (S32 iWeight = 0; iWeight < vertexIndex.size(); iWeight++) { const S32& vertIndex = vertexIndex[iWeight]; const MatrixF& deltaTransform = boneTransforms[ boneIndex[iWeight] ]; Point3F v; deltaTransform.mulP( initialVerts[vertIndex], &v ); v *= weight[iWeight]; points[vertIndex] += v; } // compute bounds for the skinned mesh for (S32 iVert = 0; iVert < initialVerts.size(); iVert++) bounds.extend( points[iVert] ); } else { MatrixF transform = getMeshTransform(TSShapeLoader::DefaultTime); TSShapeLoader::zapScale(transform); for (S32 iVert = 0; iVert < points.size(); iVert++) { Point3F p; transform.mulP(points[iVert], &p); bounds.extend(p); } } } void AppMesh::computeNormals() { // Clear normals normals.setSize( points.size() ); for (S32 iNorm = 0; iNorm < normals.size(); iNorm++) normals[iNorm] = Point3F::Zero; // Sum triangle normals for each vertex for (S32 iPrim = 0; iPrim < primitives.size(); iPrim++) { const TSDrawPrimitive& prim = primitives[iPrim]; for (S32 iInd = 0; iInd < prim.numElements; iInd += 3) { // Compute the normal for this triangle S32 idx0 = indices[prim.start + iInd + 0]; S32 idx1 = indices[prim.start + iInd + 1]; S32 idx2 = indices[prim.start + iInd + 2]; const Point3F& v0 = points[idx0]; const Point3F& v1 = points[idx1]; const Point3F& v2 = points[idx2]; Point3F n; mCross(v2 - v0, v1 - v0, &n); n.normalize(); // remove this to use 'weighted' normals (large triangles will have more effect) normals[idx0] += n; normals[idx1] += n; normals[idx2] += n; } } // Normalize the vertex normals (this takes care of averaging the triangle normals) for (S32 iNorm = 0; iNorm < normals.size(); iNorm++) normals[iNorm].normalize(); } TSMesh* AppMesh::constructTSMesh() { TSMesh* tsmesh; if (isSkin()) { TSSkinMesh* tsskin = new TSSkinMesh(); tsmesh = tsskin; // Copy skin elements tsskin->weight = weight; tsskin->boneIndex = boneIndex; tsskin->vertexIndex = vertexIndex; tsskin->batchData.nodeIndex = nodeIndex; tsskin->batchData.initialTransforms = initialTransforms; tsskin->batchData.initialVerts = initialVerts; tsskin->batchData.initialNorms = initialNorms; } else { tsmesh = new TSMesh(); } // Copy mesh elements tsmesh->mVerts = points; tsmesh->mNorms = normals; tsmesh->mTverts = uvs; tsmesh->mPrimitives = primitives; tsmesh->mIndices = indices; tsmesh->mColors = colors; tsmesh->mTverts2 = uv2s; // Finish initializing the shape tsmesh->setFlags(flags); tsmesh->updateMeshFlags(); tsmesh->computeBounds(); tsmesh->numFrames = numFrames; tsmesh->numMatFrames = numMatFrames; tsmesh->vertsPerFrame = vertsPerFrame; tsmesh->createTangents(tsmesh->mVerts, tsmesh->mNorms); tsmesh->mEncodedNorms.set(NULL,0); return tsmesh; } bool AppMesh::isBillboard() { return !dStrnicmp(getName(),"BB::",4) || !dStrnicmp(getName(),"BB_",3) || isBillboardZAxis(); } bool AppMesh::isBillboardZAxis() { return !dStrnicmp(getName(),"BBZ::",5) || !dStrnicmp(getName(),"BBZ_",4); }