tsMesh.cpp
Public Defines
define
getDrawType(a) ([])
define
tsalloc()
Public Variables
Public Functions
Detailed Description
Public Defines
getDrawType(a) ([])
tsalloc()
Public Variables
GFXPrimitiveType drawTypes []
Vector< Point3F > gNormalStore
Public Functions
tsForceFaceCamera(MatrixF * mat, const Point3F * objScale)
unwindStrip(const S32 * indices, S32 numElements, Vector< S32 > & triIndices)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "ts/tsMesh.h" 26 27#include "ts/tsMeshIntrinsics.h" 28#include "ts/tsDecal.h" 29#include "ts/tsSortedMesh.h" 30#include "ts/tsShape.h" 31#include "ts/tsShapeInstance.h" 32#include "ts/tsRenderState.h" 33#include "ts/tsMaterialList.h" 34#include "ts/instancingMatHook.h" 35#include "math/mMath.h" 36#include "math/mathIO.h" 37#include "math/mathUtils.h" 38#include "console/console.h" 39#include "scene/sceneObject.h" 40#include "core/bitRender.h" 41#include "collision/convex.h" 42#include "collision/optimizedPolyList.h" 43#include "core/frameAllocator.h" 44#include "platform/profiler.h" 45#include "materials/sceneData.h" 46#include "materials/materialManager.h" 47#include "scene/sceneManager.h" 48#include "scene/sceneRenderState.h" 49#include "materials/matInstance.h" 50#include "materials/materialFeatureTypes.h" 51#include "renderInstance/renderPassManager.h" 52#include "materials/customMaterialDefinition.h" 53#include "gfx/util/triListOpt.h" 54#include "util/triRayCheck.h" 55 56#include "opcode/Opcode.h" 57 58GFXPrimitiveType drawTypes[] = { GFXTriangleList, GFXTriangleStrip }; 59#define getDrawType(a) (drawTypes[a]) 60 61 62// structures used to share data between detail levels... 63// used (and valid) during load only 64Vector<Point3F*> TSMesh::smVertsList; 65Vector<Point3F*> TSMesh::smNormsList; 66Vector<U8*> TSMesh::smEncodedNormsList; 67Vector<Point2F*> TSMesh::smTVertsList; 68Vector<Point2F*> TSMesh::smTVerts2List; 69Vector<ColorI*> TSMesh::smColorsList; 70 71Vector<bool> TSMesh::smDataCopied; 72 73Vector<MatrixF*> TSSkinMesh::smInitTransformList; 74Vector<S32*> TSSkinMesh::smVertexIndexList; 75Vector<S32*> TSSkinMesh::smBoneIndexList; 76Vector<F32*> TSSkinMesh::smWeightList; 77Vector<S32*> TSSkinMesh::smNodeIndexList; 78 79bool TSSkinMesh::smDebugSkinVerts = false; 80 81Vector<Point3F> gNormalStore; 82 83bool TSMesh::smUseTriangles = false; // convert all primitives to triangle lists on load 84bool TSMesh::smUseOneStrip = true; // join triangle strips into one long strip on load 85S32 TSMesh::smMinStripSize = 1; // smallest number of _faces_ allowed per strip (all else put in tri list) 86bool TSMesh::smUseEncodedNormals = false; 87 88const F32 TSMesh::VISIBILITY_EPSILON = 0.0001f; 89 90S32 TSMesh::smMaxInstancingVerts = 200; 91MatrixF TSMesh::smDummyNodeTransform(1); 92 93// quick function to force object to face camera -- currently throws out roll :( 94void tsForceFaceCamera( MatrixF *mat, const Point3F *objScale ) 95{ 96 Point4F p; 97 mat->getColumn( 3, &p ); 98 mat->identity(); 99 mat->setColumn( 3, p ); 100 101 if ( objScale ) 102 { 103 MatrixF scale( true ); 104 scale.scale( *objScale ); 105 mat->mul( scale ); 106 } 107} 108 109//----------------------------------------------------- 110// TSMesh render methods 111//----------------------------------------------------- 112 113void TSMesh::render( TSVertexBufferHandle &instanceVB ) 114{ 115 innerRender(instanceVB, mPB); 116} 117 118void TSMesh::innerRender( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb ) 119{ 120 if ( !vb.isValid() || !pb.isValid() ) 121 return; 122 123 GFX->setVertexBuffer( vb ); 124 GFX->setPrimitiveBuffer( pb ); 125 126 for( U32 p = 0; p < mPrimitives.size(); p++ ) 127 GFX->drawPrimitive( p ); 128} 129 130 131void TSMesh::render( TSMaterialList *materials, 132 const TSRenderState &rdata, 133 bool isSkinDirty, 134 const Vector<MatrixF> &transforms, 135 TSVertexBufferHandle &vertexBuffer, 136 const char *meshName) 137{ 138 // These are only used by TSSkinMesh. 139 TORQUE_UNUSED( isSkinDirty ); 140 TORQUE_UNUSED( transforms ); 141 142 // Pass our shared VB. 143 innerRender(materials, rdata, vertexBuffer, mPB, meshName); 144} 145 146void TSMesh::innerRender( TSMaterialList *materials, const TSRenderState &rdata, TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb, const char *meshName ) 147{ 148 PROFILE_SCOPE( TSMesh_InnerRender ); 149 150 if( vertsPerFrame <= 0 ) 151 return; 152 153 F32 meshVisibility = rdata.getFadeOverride() * mVisibility; 154 if ( meshVisibility < VISIBILITY_EPSILON ) 155 return; 156 157 const SceneRenderState *state = rdata.getSceneState(); 158 RenderPassManager *renderPass = state->getRenderPass(); 159 160 MeshRenderInst *coreRI = renderPass->allocInst<MeshRenderInst>(); 161 coreRI->type = RenderPassManager::RIT_Mesh; 162#ifdef TORQUE_ENABLE_GFXDEBUGEVENTS 163 coreRI->meshName = meshName; 164#endif 165 166 // Pass accumulation texture along. 167 coreRI->accuTex = rdata.getAccuTex(); 168 169 const MatrixF &objToWorld = GFX->getWorldMatrix(); 170 171 // Sort by the center point or the bounds. 172 if ( rdata.useOriginSort() ) 173 coreRI->sortDistSq = ( objToWorld.getPosition() - state->getCameraPosition() ).lenSquared(); 174 else 175 { 176 Box3F rBox = mBounds; 177 objToWorld.mul( rBox ); 178 coreRI->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() ); 179 } 180 181 if (getFlags(Billboard)) 182 { 183 Point3F camPos = state->getDiffuseCameraPosition(); 184 Point3F objPos; 185 objToWorld.getColumn(3, &objPos); 186 Point3F targetVector = camPos - objPos; 187 if(getFlags(BillboardZAxis)) 188 targetVector.z = 0.0f; 189 targetVector.normalize(); 190 MatrixF orient = MathUtils::createOrientFromDir(targetVector); 191 orient.setPosition(objPos); 192 orient.scale(objToWorld.getScale()); 193 194 coreRI->objectToWorld = renderPass->allocUniqueXform( orient ); 195 } 196 else 197 coreRI->objectToWorld = renderPass->allocUniqueXform( objToWorld ); 198 199 coreRI->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); 200 coreRI->projection = renderPass->allocSharedXform(RenderPassManager::Projection); 201 202 AssertFatal( vb.isValid(), "TSMesh::innerRender() - Got invalid vertex buffer!" ); 203 AssertFatal( pb.isValid(), "TSMesh::innerRender() - Got invalid primitive buffer!" ); 204 205 coreRI->vertBuff = &vb; 206 coreRI->primBuff = &pb; 207 coreRI->defaultKey2 = (uintptr_t) coreRI->vertBuff; 208 209 coreRI->materialHint = rdata.getMaterialHint(); 210 211 coreRI->mCustomShaderData = rdata.getCustomShaderBinding(); 212 213 coreRI->visibility = meshVisibility; 214 coreRI->cubemap = rdata.getCubemap(); 215 216 if ( getMeshType() == TSMesh::SkinMeshType ) 217 { 218 rdata.getNodeTransforms(&coreRI->mNodeTransforms, &coreRI->mNodeTransformCount); 219 } 220 else 221 { 222 coreRI->mNodeTransforms = &TSMesh::smDummyNodeTransform; 223 coreRI->mNodeTransformCount = 1; 224 } 225 226 // NOTICE: SFXBB is removed and refraction is disabled! 227 //coreRI->backBuffTex = GFX->getSfxBackBuffer(); 228 229 for ( S32 i = 0; i < mPrimitives.size(); i++ ) 230 { 231 const TSDrawPrimitive &draw = mPrimitives[i]; 232 233 // We need to have a material. 234 if ( draw.matIndex & TSDrawPrimitive::NoMaterial ) 235 continue; 236 237#ifdef TORQUE_DEBUG_BREAK_INSPECT 238 // for inspection if you happen to be running in a debugger and can't do bit 239 // operations in your head. 240 S32 triangles = draw.matIndex & TSDrawPrimitive::Triangles; 241 S32 strip = draw.matIndex & TSDrawPrimitive::Strip; 242 S32 fan = draw.matIndex & TSDrawPrimitive::Fan; 243 S32 indexed = draw.matIndex & TSDrawPrimitive::Indexed; 244 S32 type = draw.matIndex & TSDrawPrimitive::TypeMask; 245 TORQUE_UNUSED(triangles); 246 TORQUE_UNUSED(strip); 247 TORQUE_UNUSED(fan); 248 TORQUE_UNUSED(indexed); 249 TORQUE_UNUSED(type); 250 //define TORQUE_DEBUG_BREAK_INSPECT, and insert debug break here to inspect the above elements at runtime 251#endif 252 253 const U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask; 254 BaseMatInstance *matInst = materials->getMaterialInst( matIndex ); 255 256#ifndef TORQUE_OS_MAC 257 258 // Get the instancing material if this mesh qualifies. 259 if (mMeshType != SkinMeshType && pb->mPrimitiveArray[i].numVertices < smMaxInstancingVerts ) 260 if (matInst && !matInst->getFeatures().hasFeature(MFT_HardwareSkinning)) 261 matInst = InstancingMaterialHook::getInstancingMat( matInst ); 262 263#endif 264 265 // If we don't have a material instance after the overload then 266 // there is nothing to render... skip this primitive. 267 matInst = state->getOverrideMaterial( matInst ); 268 if ( !matInst || !matInst->isValid()) 269 continue; 270 271 // If the material needs lights then gather them 272 // here once and set them on the core render inst. 273 if ( matInst->isForwardLit() && !coreRI->lights[0] && rdata.getLightQuery() ) 274 rdata.getLightQuery()->getLights( coreRI->lights, 8 ); 275 276 MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>(); 277 *ri = *coreRI; 278 279 ri->matInst = matInst; 280 ri->defaultKey = matInst->getStateHint(); 281 ri->primBuffIndex = mPrimBufferOffset + i; 282 283 // Translucent materials need the translucent type. 284 if ( matInst->getMaterial()->isTranslucent() && (!(matInst->getMaterial()->isAlphatest() && state->isShadowPass()))) 285 { 286 ri->type = RenderPassManager::RIT_Translucent; 287 ri->translucentSort = true; 288 } 289 290 renderPass->addInst( ri ); 291 } 292} 293 294const Point3F * TSMesh::getNormals( S32 firstVert ) 295{ 296 if ( getFlags( UseEncodedNormals ) ) 297 { 298 gNormalStore.setSize( vertsPerFrame ); 299 for ( S32 i = 0; i < mEncodedNorms.size(); i++ ) 300 gNormalStore[i] = decodeNormal(mEncodedNorms[ i + firstVert ] ); 301 302 return gNormalStore.address(); 303 } 304 305 return &mNorms[firstVert]; 306} 307 308//----------------------------------------------------- 309// TSMesh collision methods 310//----------------------------------------------------- 311 312bool TSMesh::buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials ) 313{ 314 S32 firstVert = vertsPerFrame * frame, i, base = 0; 315 bool hasTVert2 = getHasTVert2(); 316 317 // add the verts... 318 if ( vertsPerFrame ) 319 { 320 if ( mVertexData.isReady() ) 321 { 322 OptimizedPolyList* opList = dynamic_cast<OptimizedPolyList*>(polyList); 323 if ( opList ) 324 { 325 base = opList->mVertexList.size(); 326 for ( i = 0; i < vertsPerFrame; i++ ) 327 { 328 // Don't use vertex() method as we want to retain the original indices 329 OptimizedPolyList::VertIndex vert; 330 vert.vertIdx = opList->insertPoint( mVertexData.getBase( i + firstVert ).vert() ); 331 vert.normalIdx = opList->insertNormal( mVertexData.getBase( i + firstVert ).normal() ); 332 vert.uv0Idx = opList->insertUV0( mVertexData.getBase( i + firstVert ).tvert() ); 333 if ( hasTVert2 ) 334 vert.uv1Idx = opList->insertUV1( mVertexData.getColor( i + firstVert ).tvert2() ); 335 336 opList->mVertexList.push_back( vert ); 337 } 338 } 339 else 340 { 341 base = polyList->addPointAndNormal( mVertexData.getBase( firstVert ).vert(), mVertexData.getBase( firstVert ).normal() ); 342 for ( i = 1; i < vertsPerFrame; i++ ) 343 { 344 polyList->addPointAndNormal( mVertexData.getBase( i + firstVert ).vert(), mVertexData.getBase( i + firstVert ).normal() ); 345 } 346 } 347 } 348 else 349 { 350 OptimizedPolyList* opList = dynamic_cast<OptimizedPolyList*>(polyList); 351 if ( opList ) 352 { 353 base = opList->mVertexList.size(); 354 for ( i = 0; i < vertsPerFrame; i++ ) 355 { 356 // Don't use vertex() method as we want to retain the original indices 357 OptimizedPolyList::VertIndex vert; 358 vert.vertIdx = opList->insertPoint( mVerts[ i + firstVert ] ); 359 vert.normalIdx = opList->insertNormal( mNorms[ i + firstVert ] ); 360 vert.uv0Idx = opList->insertUV0( mTverts[ i + firstVert ] ); 361 if ( hasTVert2 ) 362 vert.uv1Idx = opList->insertUV1(mTverts[ i + firstVert ] ); 363 364 opList->mVertexList.push_back( vert ); 365 } 366 } 367 else 368 { 369 base = polyList->addPointAndNormal( mVerts[firstVert], mNorms[firstVert] ); 370 for ( i = 1; i < vertsPerFrame; i++ ) 371 polyList->addPointAndNormal(mVerts[ i + firstVert ], mNorms[ i + firstVert ] ); 372 } 373 } 374 } 375 376 // add the polys... 377 for ( i = 0; i < mPrimitives.size(); i++ ) 378 { 379 TSDrawPrimitive & draw = mPrimitives[i]; 380 U32 start = draw.start; 381 382 AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" ); 383 384 U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask; 385 BaseMatInstance* material = ( materials ? materials->getMaterialInst( matIndex ) : 0 ); 386 387 // gonna depend on what kind of primitive it is... 388 if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles ) 389 { 390 for ( S32 j = 0; j < draw.numElements; ) 391 { 392 U32 idx0 = base + mIndices[start + j + 0]; 393 U32 idx1 = base + mIndices[start + j + 1]; 394 U32 idx2 = base + mIndices[start + j + 2]; 395 polyList->begin(material,surfaceKey++); 396 polyList->vertex( idx0 ); 397 polyList->vertex( idx1 ); 398 polyList->vertex( idx2 ); 399 polyList->plane( idx0, idx1, idx2 ); 400 polyList->end(); 401 j += 3; 402 } 403 } 404 else 405 { 406 AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::buildPolyList (2)" ); 407 408 U32 idx0 = base + mIndices[start + 0]; 409 U32 idx1; 410 U32 idx2 = base + mIndices[start + 1]; 411 U32 * nextIdx = &idx1; 412 for ( S32 j = 2; j < draw.numElements; j++ ) 413 { 414 *nextIdx = idx2; 415 // nextIdx = (j%2)==0 ? &idx0 : &idx1; 416 nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1); 417 idx2 = base + mIndices[start + j]; 418 if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 ) 419 continue; 420 421 polyList->begin( material, surfaceKey++ ); 422 polyList->vertex( idx0 ); 423 polyList->vertex( idx1 ); 424 polyList->vertex( idx2 ); 425 polyList->plane( idx0, idx1, idx2 ); 426 polyList->end(); 427 } 428 } 429 } 430 return true; 431} 432 433bool TSMesh::getFeatures( S32 frame, const MatrixF& mat, const VectorF&, ConvexFeature* cf, U32& ) 434{ 435 S32 firstVert = vertsPerFrame * frame; 436 S32 i; 437 S32 base = cf->mVertexList.size(); 438 439 for ( i = 0; i < vertsPerFrame; i++ ) 440 { 441 cf->mVertexList.increment(); 442 mat.mulP( mVertexData.getBase(firstVert + i).vert(), &cf->mVertexList.last() ); 443 } 444 445 // add the polys... 446 for ( i = 0; i < mPrimitives.size(); i++ ) 447 { 448 TSDrawPrimitive & draw = mPrimitives[i]; 449 U32 start = draw.start; 450 451 AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" ); 452 453 // gonna depend on what kind of primitive it is... 454 if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles) 455 { 456 for ( S32 j = 0; j < draw.numElements; j += 3 ) 457 { 458 PlaneF plane( cf->mVertexList[base + mIndices[start + j + 0]], 459 cf->mVertexList[base + mIndices[start + j + 1]], 460 cf->mVertexList[base + mIndices[start + j + 2]]); 461 462 cf->mFaceList.increment(); 463 464 ConvexFeature::Face& lastFace = cf->mFaceList.last(); 465 lastFace.normal = plane; 466 467 lastFace.vertex[0] = base + mIndices[start + j + 0]; 468 lastFace.vertex[1] = base + mIndices[start + j + 1]; 469 lastFace.vertex[2] = base + mIndices[start + j + 2]; 470 471 for ( U32 l = 0; l < 3; l++ ) 472 { 473 U32 newEdge0, newEdge1; 474 U32 zero = base + mIndices[start + j + l]; 475 U32 one = base + mIndices[start + j + ((l+1)%3)]; 476 newEdge0 = getMin( zero, one ); 477 newEdge1 = getMax( zero, one ); 478 bool found = false; 479 for ( S32 k = 0; k < cf->mEdgeList.size(); k++ ) 480 { 481 if ( cf->mEdgeList[k].vertex[0] == newEdge0 && 482 cf->mEdgeList[k].vertex[1] == newEdge1) 483 { 484 found = true; 485 break; 486 } 487 } 488 489 if ( !found ) 490 { 491 cf->mEdgeList.increment(); 492 cf->mEdgeList.last().vertex[0] = newEdge0; 493 cf->mEdgeList.last().vertex[1] = newEdge1; 494 } 495 } 496 } 497 } 498 else 499 { 500 AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::buildPolyList (2)" ); 501 502 U32 idx0 = base + mIndices[start + 0]; 503 U32 idx1; 504 U32 idx2 = base + mIndices[start + 1]; 505 U32 * nextIdx = &idx1; 506 for ( S32 j = 2; j < draw.numElements; j++ ) 507 { 508 *nextIdx = idx2; 509 nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1); 510 idx2 = base + mIndices[start + j]; 511 if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 ) 512 continue; 513 514 PlaneF plane( cf->mVertexList[idx0], 515 cf->mVertexList[idx1], 516 cf->mVertexList[idx2] ); 517 518 cf->mFaceList.increment(); 519 cf->mFaceList.last().normal = plane; 520 521 cf->mFaceList.last().vertex[0] = idx0; 522 cf->mFaceList.last().vertex[1] = idx1; 523 cf->mFaceList.last().vertex[2] = idx2; 524 525 U32 newEdge0, newEdge1; 526 newEdge0 = getMin( idx0, idx1 ); 527 newEdge1 = getMax( idx0, idx1 ); 528 bool found = false; 529 S32 k; 530 for ( k = 0; k < cf->mEdgeList.size(); k++ ) 531 { 532 ConvexFeature::Edge currentEdge = cf->mEdgeList[k]; 533 if (currentEdge.vertex[0] == newEdge0 && 534 currentEdge.vertex[1] == newEdge1) 535 { 536 found = true; 537 break; 538 } 539 } 540 541 if ( !found ) 542 { 543 cf->mEdgeList.increment(); 544 cf->mEdgeList.last().vertex[0] = newEdge0; 545 cf->mEdgeList.last().vertex[1] = newEdge1; 546 } 547 548 newEdge0 = getMin( idx1, idx2 ); 549 newEdge1 = getMax( idx1, idx2 ); 550 found = false; 551 for ( k = 0; k < cf->mEdgeList.size(); k++ ) 552 { 553 if ( cf->mEdgeList[k].vertex[0] == newEdge0 && 554 cf->mEdgeList[k].vertex[1] == newEdge1 ) 555 { 556 found = true; 557 break; 558 } 559 } 560 561 if ( !found ) 562 { 563 cf->mEdgeList.increment(); 564 cf->mEdgeList.last().vertex[0] = newEdge0; 565 cf->mEdgeList.last().vertex[1] = newEdge1; 566 } 567 568 newEdge0 = getMin(idx0, idx2); 569 newEdge1 = getMax(idx0, idx2); 570 found = false; 571 for ( k = 0; k < cf->mEdgeList.size(); k++ ) 572 { 573 if ( cf->mEdgeList[k].vertex[0] == newEdge0 && 574 cf->mEdgeList[k].vertex[1] == newEdge1 ) 575 { 576 found = true; 577 break; 578 } 579 } 580 581 if ( !found ) 582 { 583 cf->mEdgeList.increment(); 584 cf->mEdgeList.last().vertex[0] = newEdge0; 585 cf->mEdgeList.last().vertex[1] = newEdge1; 586 } 587 } 588 } 589 } 590 591 return false; 592} 593 594 595void TSMesh::support( S32 frame, const Point3F &v, F32 *currMaxDP, Point3F *currSupport ) 596{ 597 if ( vertsPerFrame == 0 ) 598 return; 599 600 U32 waterMark = FrameAllocator::getWaterMark(); 601 F32* pDots = (F32*)FrameAllocator::alloc( sizeof(F32) * vertsPerFrame ); 602 603 S32 firstVert = vertsPerFrame * frame; 604 m_point3F_bulk_dot( &v.x, 605 &mVertexData.getBase(firstVert).vert().x, 606 vertsPerFrame, 607 mVertexData.vertSize(), 608 pDots ); 609 610 F32 localdp = *currMaxDP; 611 S32 index = -1; 612 613 for ( S32 i = 0; i < vertsPerFrame; i++ ) 614 { 615 if ( pDots[i] > localdp ) 616 { 617 localdp = pDots[i]; 618 index = i; 619 } 620 } 621 622 FrameAllocator::setWaterMark(waterMark); 623 624 if ( index != -1 ) 625 { 626 *currMaxDP = localdp; 627 *currSupport = mVertexData.getBase(index + firstVert).vert(); 628 } 629} 630 631bool TSMesh::castRay( S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials ) 632{ 633 if ( mPlaneNormals.empty() ) 634 buildConvexHull(); // if haven't done it yet... 635 636 // Keep track of startTime and endTime. They start out at just under 0 and just over 1, respectively. 637 // As we check against each plane, prune start and end times back to represent current intersection of 638 // line with all the planes (or rather with all the half-spaces defined by the planes). 639 // But, instead of explicitly keeping track of startTime and endTime, keep track as numerator and denominator 640 // so that we can avoid as many divisions as possible. 641 642 // F32 startTime = -0.01f; 643 F32 startNum = -0.01f; 644 F32 startDen = 1.00f; 645 // F32 endTime = 1.01f; 646 F32 endNum = 1.01f; 647 F32 endDen = 1.00f; 648 649 S32 curPlane = 0; 650 U32 curMaterial = 0; 651 bool found = false; 652 653 // the following block of code is an optimization... 654 // it isn't necessary if the longer version of the main loop is used 655 bool tmpFound; 656 S32 tmpPlane; 657 F32 sgn = -1.0f; 658 F32 * pnum = &startNum; 659 F32 * pden = &startDen; 660 S32 * pplane = &curPlane; 661 bool * pfound = &found; 662 663 S32 startPlane = frame * mPlanesPerFrame; 664 for ( S32 i = startPlane; i < startPlane + mPlanesPerFrame; i++ ) 665 { 666 // if start & end outside, no collision 667 // if start & end inside, continue 668 // if start outside, end inside, or visa versa, find intersection of line with plane 669 // then update intersection of line with hull (using startTime and endTime) 670 F32 dot1 = mDot(mPlaneNormals[i], start ) - mPlaneConstants[i]; 671 F32 dot2 = mDot(mPlaneNormals[i], end) - mPlaneConstants[i]; 672 if ( dot1 * dot2 > 0.0f ) 673 { 674 // same side of the plane...which side -- dot==0 considered inside 675 if ( dot1 > 0.0f ) 676 return false; // start and end outside of this plane, no collision 677 678 // start and end inside plane, continue 679 continue; 680 } 681 682 //AssertFatal( dot1 / ( dot1 - dot2 ) >= 0.0f && dot1 / ( dot1 - dot2 ) <= 1.0f,"TSMesh::castRay (1)" ); 683 684 // find intersection (time) with this plane... 685 // F32 time = dot1 / (dot1-dot2); 686 F32 num = mFabs( dot1 ); 687 F32 den = mFabs( dot1 - dot2 ); 688 689 // the following block of code is an optimized version... 690 // this can be commented out and the following block of code used instead 691 // if debugging a problem in this code, that should probably be done 692 // if you want to see how this works, look at the following block of code, 693 // not this one... 694 // Note that this does not get optimized appropriately...it is included this way 695 // as an idea for future optimization. 696 if ( sgn * dot1 >= 0 ) 697 { 698 sgn *= -1.0f; 699 pnum = (F32*) ((dsize_t)pnum ^ (dsize_t)&endNum ^ (dsize_t)&startNum); 700 pden = (F32*) ((dsize_t)pden ^ (dsize_t)&endDen ^ (dsize_t)&startDen); 701 pplane = (S32*) ((dsize_t)pplane ^ (dsize_t)&tmpPlane ^ (dsize_t)&curPlane); 702 pfound = (bool*) ((dsize_t)pfound ^ (dsize_t)&tmpFound ^ (dsize_t)&found); 703 } 704 705 bool noCollision = num * endDen * sgn < endNum * den * sgn && num * startDen * sgn < startNum * den * sgn; 706 if (num * *pden * sgn < *pnum * den * sgn && !noCollision) 707 { 708 *pnum = num; 709 *pden = den; 710 *pplane = i; 711 *pfound = true; 712 } 713 else if ( noCollision ) 714 return false; 715 716// if (dot1<=0.0f) 717// { 718// // start is inside plane, end is outside...chop off end 719// if (num*endDen<endNum*den) // if (time<endTime) 720// { 721// if (num*startDen<startNum*den) //if (time<startTime) 722// // no intersection of line and hull 723// return false; 724// // endTime = time; 725// endNum = num; 726// endDen = den; 727// } 728// // else, no need to do anything, just continue (we've been more inside than this) 729// } 730// else // dot2<=0.0f 731// { 732// // end is inside poly, start is outside...chop off start 733// AssertFatal(dot2<=0.0f,"TSMesh::castRay (2)"); 734// if (num*startDen>startNum*den) // if (time>startTime) 735// { 736// if (num*endDen>endNum*den) //if (time>endTime) 737// // no intersection of line and hull 738// return false; 739// // startTime = time; 740// startNum = num; 741// startDen = den; 742// curPlane = i; 743// curMaterial = planeMaterials[i-startPlane]; 744// found = true; 745// } 746// // else, no need to do anything, just continue (we've been more inside than this) 747// } 748 } 749 750 // setup rayInfo 751 if ( found && rayInfo ) 752 { 753 curMaterial = mPlaneMaterials[ curPlane - startPlane ]; 754 755 rayInfo->t = (F32)startNum/(F32)startDen; // finally divide... 756 rayInfo->normal = mPlaneNormals[curPlane]; 757 758 if (materials && materials->size() > 0) 759 rayInfo->material = materials->getMaterialInst( curMaterial ); 760 else 761 rayInfo->material = NULL; 762 763 rayInfo->setContactPoint( start, end ); 764 765 return true; 766 } 767 else if ( found ) 768 return true; 769 770 // only way to get here is if start is inside hull... 771 // we could return null and just plug in garbage for the material and normal... 772 return false; 773} 774 775bool TSMesh::castRayRendered( S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials ) 776{ 777 if( vertsPerFrame <= 0 ) 778 return false; 779 780 if( mNumVerts == 0 ) 781 return false; 782 783 S32 firstVert = vertsPerFrame * frame; 784 785 bool found = false; 786 F32 best_t = F32_MAX; 787 U32 bestIdx0 = 0, bestIdx1 = 0, bestIdx2 = 0; 788 BaseMatInstance* bestMaterial = NULL; 789 Point3F dir = end - start; 790 791 for ( S32 i = 0; i < mPrimitives.size(); i++ ) 792 { 793 TSDrawPrimitive & draw = mPrimitives[i]; 794 U32 drawStart = draw.start; 795 796 AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::castRayRendered (1)" ); 797 798 U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask; 799 BaseMatInstance* material = ( materials ? materials->getMaterialInst( matIndex ) : 0 ); 800 801 U32 idx0, idx1, idx2; 802 803 // gonna depend on what kind of primitive it is... 804 if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles ) 805 { 806 for ( S32 j = 0; j < draw.numElements-2; j += 3 ) 807 { 808 idx0 = mIndices[drawStart + j + 0]; 809 idx1 = mIndices[drawStart + j + 1]; 810 idx2 = mIndices[drawStart + j + 2]; 811 812 F32 cur_t = 0; 813 Point2F b; 814 815 if(castRayTriangle(start, dir, mVertexData.getBase(firstVert + idx0).vert(), 816 mVertexData.getBase(firstVert + idx1).vert(), mVertexData.getBase(firstVert + idx2).vert(), cur_t, b)) 817 { 818 if(cur_t < best_t) 819 { 820 best_t = cur_t; 821 bestIdx0 = idx0; 822 bestIdx1 = idx1; 823 bestIdx2 = idx2; 824 bestMaterial = material; 825 found = true; 826 } 827 } 828 } 829 } 830 else 831 { 832 AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::castRayRendered (2)" ); 833 834 idx0 = mIndices[drawStart + 0]; 835 idx2 = mIndices[drawStart + 1]; 836 U32 * nextIdx = &idx1; 837 for ( S32 j = 2; j < draw.numElements; j++ ) 838 { 839 *nextIdx = idx2; 840 // nextIdx = (j%2)==0 ? &idx0 : &idx1; 841 nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1); 842 idx2 = mIndices[drawStart + j]; 843 if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 ) 844 continue; 845 846 F32 cur_t = 0; 847 Point2F b; 848 849 if(castRayTriangle(start, dir, mVertexData.getBase(firstVert + idx0).vert(), 850 mVertexData.getBase(firstVert + idx1).vert(), mVertexData.getBase(firstVert + idx2).vert(), cur_t, b)) 851 { 852 if(cur_t < best_t) 853 { 854 best_t = cur_t; 855 bestIdx0 = firstVert + idx0; 856 bestIdx1 = firstVert + idx1; 857 bestIdx2 = firstVert + idx2; 858 bestMaterial = material; 859 found = true; 860 } 861 } 862 } 863 } 864 } 865 866 // setup rayInfo 867 if ( found && rayInfo ) 868 { 869 rayInfo->t = best_t; 870 871 Point3F normal; 872 mCross(mVertexData.getBase(bestIdx2).vert()-mVertexData.getBase(bestIdx0).vert(),mVertexData.getBase(bestIdx1).vert()-mVertexData.getBase(bestIdx0).vert(),&normal); 873 if ( mDot( normal, normal ) < 0.001f ) 874 { 875 mCross( mVertexData.getBase(bestIdx0).vert() - mVertexData.getBase(bestIdx1).vert(), mVertexData.getBase(bestIdx2).vert() - mVertexData.getBase(bestIdx1).vert(), &normal ); 876 if ( mDot( normal, normal ) < 0.001f ) 877 { 878 mCross( mVertexData.getBase(bestIdx1).vert() - mVertexData.getBase(bestIdx2).vert(), mVertexData.getBase(bestIdx0).vert() - mVertexData.getBase(bestIdx2).vert(), &normal ); 879 } 880 } 881 normal.normalize(); 882 rayInfo->normal = normal; 883 884 rayInfo->material = bestMaterial; 885 886 rayInfo->setContactPoint( start, end ); 887 888 return true; 889 } 890 else if ( found ) 891 return true; 892 893 return false; 894} 895 896bool TSMesh::addToHull( U32 idx0, U32 idx1, U32 idx2 ) 897{ 898 // calculate the normal of this triangle... remember, we lose precision 899 // when we subtract two large numbers that are very close to each other, 900 // so depending on how we calculate the normal, we could get a 901 // different result. so, we will calculate the normal three different 902 // ways and take the one that gives us the largest vector before we 903 // normalize. 904 Point3F normal1, normal2, normal3; 905 906 const Point3F& vertex0Data = mVertexData.getBase(idx0).vert(); 907 const Point3F& vertex1Data = mVertexData.getBase(idx1).vert(); 908 const Point3F& vertex2Data = mVertexData.getBase(idx2).vert(); 909 910 mCross(vertex2Data-vertex0Data,vertex1Data-vertex0Data,&normal1); 911 mCross(vertex0Data-vertex1Data,vertex2Data-vertex1Data,&normal2); 912 mCross(vertex1Data-vertex2Data,vertex0Data-vertex2Data,&normal3); 913 914 Point3F normal = normal1; 915 F32 greatestMagSquared = mDot(normal1, normal1); 916 F32 magSquared = mDot(normal2, normal2); 917 if (magSquared > greatestMagSquared) 918 { 919 normal = normal2; 920 greatestMagSquared = magSquared; 921 } 922 magSquared = mDot(normal3, normal3); 923 if (magSquared > greatestMagSquared) 924 { 925 normal = normal3; 926 greatestMagSquared = magSquared; 927 } 928 if (mDot(normal, normal) < 0.00000001f) 929 return false; 930 931 normal.normalize(); 932 F32 k = mDot( normal, mVertexData.getBase(idx0).vert() ); 933 for ( S32 i = 0; i < mPlaneNormals.size(); i++ ) 934 { 935 if ( mDot(mPlaneNormals[i], normal ) > 0.99f && mFabs( k- mPlaneConstants[i] ) < 0.01f ) 936 return false; // this is a repeat... 937 } 938 // new plane, add it to the list... 939 mPlaneNormals.push_back( normal ); 940 mPlaneConstants.push_back( k ); 941 return true; 942} 943 944bool TSMesh::buildConvexHull() 945{ 946 // already done, return without error 947 if (mPlaneNormals.size() ) 948 return true; 949 950 bool error = false; 951 952 // should probably only have 1 frame, but just in case... 953 mPlanesPerFrame = 0; 954 S32 frame, i, j; 955 for ( frame = 0; frame < numFrames; frame++ ) 956 { 957 S32 firstVert = vertsPerFrame * frame; 958 S32 firstPlane = mPlaneNormals.size(); 959 for ( i = 0; i < mPrimitives.size(); i++ ) 960 { 961 TSDrawPrimitive & draw = mPrimitives[i]; 962 U32 start = draw.start; 963 964 AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildConvexHull (1)" ); 965 966 // gonna depend on what kind of primitive it is... 967 if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles ) 968 { 969 for ( j = 0; j < draw.numElements; j += 3 ) 970 if ( addToHull( mIndices[start + j + 0] + firstVert, 971 mIndices[start + j + 1] + firstVert, 972 mIndices[start + j + 2] + firstVert ) && frame == 0 ) 973 mPlaneMaterials.push_back( draw.matIndex & TSDrawPrimitive::MaterialMask ); 974 } 975 else 976 { 977 AssertFatal( (draw.matIndex&TSDrawPrimitive::Strip) == TSDrawPrimitive::Strip,"TSMesh::buildConvexHull (2)" ); 978 979 U32 idx0 = mIndices[start + 0] + firstVert; 980 U32 idx1; 981 U32 idx2 = mIndices[start + 1] + firstVert; 982 U32 * nextIdx = &idx1; 983 for ( j = 2; j < draw.numElements; j++ ) 984 { 985 *nextIdx = idx2; 986// nextIdx = (j%2)==0 ? &idx0 : &idx1; 987 nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1 ); 988 idx2 = mIndices[start + j] + firstVert; 989 if ( addToHull( idx0, idx1, idx2 ) && frame == 0 ) 990 mPlaneMaterials.push_back( draw.matIndex & TSDrawPrimitive::MaterialMask ); 991 } 992 } 993 } 994 // make sure all the verts on this frame are inside all the planes 995 for ( i = 0; i < vertsPerFrame; i++ ) 996 for ( j = firstPlane; j < mPlaneNormals.size(); j++ ) 997 if ( mDot( mVertexData.getBase(firstVert + i).vert(), mPlaneNormals[j] ) - mPlaneConstants[j] < 0.01 ) // .01 == a little slack 998 error = true; 999 1000 if ( frame == 0 ) 1001 mPlanesPerFrame = mPlaneNormals.size(); 1002 1003 if ( (frame + 1) * mPlanesPerFrame != mPlaneNormals.size() ) 1004 { 1005 // eek, not all frames have same number of planes... 1006 while ( (frame + 1) * mPlanesPerFrame > mPlaneNormals.size() ) 1007 { 1008 // we're short, duplicate last plane till we match 1009 U32 sz = mPlaneNormals.size(); 1010 mPlaneNormals.increment(); 1011 mPlaneNormals.last() = mPlaneNormals[sz-1]; 1012 mPlaneConstants.increment(); 1013 mPlaneConstants.last() = mPlaneConstants[sz-1]; 1014 } 1015 while ( (frame + 1) * mPlanesPerFrame < mPlaneNormals.size() ) 1016 { 1017 // harsh -- last frame has more than other frames 1018 // duplicate last plane in each frame 1019 for ( S32 k = frame - 1; k >= 0; k-- ) 1020 { 1021 mPlaneNormals.insert( k * mPlanesPerFrame + mPlanesPerFrame ); 1022 mPlaneNormals[k * mPlanesPerFrame + mPlanesPerFrame] = mPlaneNormals[k * mPlanesPerFrame + mPlanesPerFrame - 1]; 1023 mPlaneConstants.insert( k * mPlanesPerFrame + mPlanesPerFrame ); 1024 mPlaneConstants[k * mPlanesPerFrame + mPlanesPerFrame] = mPlaneConstants[k * mPlanesPerFrame + mPlanesPerFrame - 1]; 1025 if ( k == 0 ) 1026 { 1027 mPlaneMaterials.increment(); 1028 mPlaneMaterials.last() = mPlaneMaterials[mPlaneMaterials.size() - 2]; 1029 } 1030 } 1031 mPlanesPerFrame++; 1032 } 1033 } 1034 AssertFatal( (frame + 1) * mPlanesPerFrame == mPlaneNormals.size(),"TSMesh::buildConvexHull (3)" ); 1035 } 1036 return !error; 1037} 1038 1039//----------------------------------------------------- 1040// TSMesh bounds methods 1041//----------------------------------------------------- 1042 1043void TSMesh::computeBounds() 1044{ 1045 MatrixF mat(true); 1046 computeBounds( mat, mBounds, -1, &mCenter, &mRadius ); 1047} 1048 1049void TSMesh::computeBounds( const MatrixF &transform, Box3F &bounds, S32 frame, Point3F *center, F32 *radius ) 1050{ 1051 const Point3F *baseVert = NULL; 1052 S32 stride = 0; 1053 S32 numVerts = 0; 1054 1055 AssertFatal(!mVertexData.isReady() || (mVertexData.isReady() && mNumVerts == mVertexData.size() && mNumVerts == vertsPerFrame), "vertex number mismatch"); 1056 1057 if(mVerts.size() == 0 && mVertexData.isReady() && mVertexData.size() > 0) 1058 { 1059 baseVert = &mVertexData.getBase(0).vert(); 1060 stride = mVertexData.vertSize(); 1061 1062 if ( frame < 0 ) 1063 numVerts = mNumVerts; 1064 else 1065 { 1066 baseVert = &mVertexData.getBase(frame * vertsPerFrame).vert(); 1067 numVerts = vertsPerFrame; 1068 } 1069 } 1070 else 1071 { 1072 baseVert = mVerts.address(); 1073 stride = sizeof(Point3F); 1074 1075 if ( frame < 0 ) 1076 numVerts = mVerts.size(); 1077 else 1078 { 1079 baseVert += frame * vertsPerFrame; 1080 numVerts = vertsPerFrame; 1081 } 1082 } 1083 computeBounds( baseVert, numVerts, stride, transform, bounds, center, radius ); 1084} 1085 1086void TSMesh::computeBounds( const Point3F *v, S32 numVerts, S32 stride, const MatrixF &transform, Box3F &bounds, Point3F *center, F32 *radius ) 1087{ 1088 const U8 *_vb = reinterpret_cast<const U8 *>(v); 1089 1090 if ( !numVerts ) 1091 { 1092 bounds.minExtents = Point3F::Zero; 1093 bounds.maxExtents = Point3F::Zero; 1094 if ( center ) 1095 *center = Point3F::Zero; 1096 if ( radius ) 1097 *radius = 0; 1098 return; 1099 } 1100 1101 S32 i; 1102 Point3F p; 1103 transform.mulP( *v, &bounds.minExtents ); 1104 bounds.maxExtents = bounds.minExtents; 1105 for ( i = 0; i < numVerts; i++ ) 1106 { 1107 const Point3F &curVert = *reinterpret_cast<const Point3F *>(_vb + i * stride); 1108 transform.mulP( curVert, &p ); 1109 bounds.maxExtents.setMax( p ); 1110 bounds.minExtents.setMin( p ); 1111 } 1112 Point3F c; 1113 if ( !center ) 1114 center = &c; 1115 center->x = 0.5f * (bounds.minExtents.x + bounds.maxExtents.x); 1116 center->y = 0.5f * (bounds.minExtents.y + bounds.maxExtents.y); 1117 center->z = 0.5f * (bounds.minExtents.z + bounds.maxExtents.z); 1118 if ( radius ) 1119 { 1120 *radius = 0.0f; 1121 for ( i = 0; i < numVerts; i++ ) 1122 { 1123 const Point3F &curVert = *reinterpret_cast<const Point3F *>(_vb + i * stride); 1124 transform.mulP( curVert, &p ); 1125 p -= *center; 1126 *radius = getMax( *radius, mDot( p, p ) ); 1127 } 1128 *radius = mSqrt( *radius ); 1129 } 1130} 1131 1132//----------------------------------------------------- 1133 1134S32 TSMesh::getNumPolys() const 1135{ 1136 S32 count = 0; 1137 for ( S32 i = 0; i < mPrimitives.size(); i++ ) 1138 { 1139 switch (mPrimitives[i].matIndex & TSDrawPrimitive::TypeMask) 1140 { 1141 case TSDrawPrimitive::Triangles: 1142 count += mPrimitives[i].numElements / 3; 1143 break; 1144 1145 case TSDrawPrimitive::Fan: 1146 count += mPrimitives[i].numElements - 2; 1147 break; 1148 1149 case TSDrawPrimitive::Strip: 1150 // Don't count degenerate triangles 1151 for ( S32 j = mPrimitives[i].start; 1152 j < mPrimitives[i].start+ mPrimitives[i].numElements-2; 1153 j++ ) 1154 { 1155 if ((mIndices[j] != mIndices[j+1]) && 1156 (mIndices[j] != mIndices[j+2]) && 1157 (mIndices[j+1] != mIndices[j+2])) 1158 count++; 1159 } 1160 break; 1161 } 1162 } 1163 return count; 1164} 1165 1166//----------------------------------------------------- 1167 1168TSMesh::TSMesh() : mMeshType( StandardMeshType ) 1169{ 1170 VECTOR_SET_ASSOCIATION(mPlaneNormals ); 1171 VECTOR_SET_ASSOCIATION(mPlaneConstants ); 1172 VECTOR_SET_ASSOCIATION(mPlaneMaterials ); 1173 mParentMesh = -1; 1174 1175 mOptTree = NULL; 1176 mOpMeshInterface = NULL; 1177 mOpTris = NULL; 1178 mOpPoints = NULL; 1179 1180 mVisibility = 1.0f; 1181 1182 1183 mNumVerts = 0; 1184 mVertSize = 0; 1185 mVertOffset = 0; 1186 mRadius = 0.0f; 1187 mVertexFormat = NULL; 1188 mPrimBufferOffset = 0; 1189 numFrames = 0; 1190 numMatFrames = 0; 1191 vertsPerFrame = 0; 1192 mPlanesPerFrame = 0; 1193 mMergeBufferStart = 0; 1194 mParentMeshObject = NULL; 1195} 1196 1197//----------------------------------------------------- 1198// TSMesh destructor 1199//----------------------------------------------------- 1200 1201TSMesh::~TSMesh() 1202{ 1203 SAFE_DELETE( mOptTree ); 1204 SAFE_DELETE( mOpMeshInterface ); 1205 SAFE_DELETE_ARRAY( mOpTris ); 1206 SAFE_DELETE_ARRAY( mOpPoints ); 1207 1208 mNumVerts = 0; 1209} 1210 1211//----------------------------------------------------- 1212// TSSkinMesh methods 1213//----------------------------------------------------- 1214 1215void TSSkinMesh::updateSkinBuffer( const Vector<MatrixF> &transforms, U8* buffer ) 1216{ 1217 PROFILE_SCOPE(TSSkinMesh_UpdateSkinBuffer); 1218 1219 AssertFatal(batchData.initialized, "Batch data not initialized. Call createSkinBatchData() before any skin update is called."); 1220 1221 if (TSShape::smUseHardwareSkinning || mNumVerts == 0) 1222 return; 1223 1224 const MatrixF *matrices = NULL; 1225 1226 static Vector<MatrixF> sBoneTransforms; 1227 sBoneTransforms.setSize(batchData.nodeIndex.size()); 1228 1229 // set up bone transforms 1230 PROFILE_START(TSSkinMesh_UpdateTransforms); 1231 for (S32 i = 0; i < batchData.nodeIndex.size(); i++) 1232 { 1233 S32 node = batchData.nodeIndex[i]; 1234 sBoneTransforms[i].mul(transforms[node], batchData.initialTransforms[i]); 1235 } 1236 1237 matrices = &sBoneTransforms[0]; 1238 PROFILE_END(); 1239 1240 const Point3F *inVerts = batchData.initialVerts.address(); 1241 const Point3F *inNorms = batchData.initialNorms.address(); 1242 1243 AssertFatal(inVerts, "Something went wrong, verts should be valid"); 1244 1245 U8 *dest = buffer + mVertOffset; 1246 if (!dest) 1247 return; 1248 1249 Point3F srcVtx, srcNrm; 1250 1251 AssertFatal(batchData.vertexBatchOperations.size() == batchData.initialVerts.size(), "Assumption failed!"); 1252 1253 Point3F skinnedVert; 1254 Point3F skinnedNorm; 1255 1256 for (Vector<BatchData::BatchedVertex>::const_iterator itr = batchData.vertexBatchOperations.begin(); 1257 itr != batchData.vertexBatchOperations.end(); itr++) 1258 { 1259 const BatchData::BatchedVertex &curVert = *itr; 1260 1261 skinnedVert.zero(); 1262 skinnedNorm.zero(); 1263 1264 for (S32 tOp = 0; tOp < curVert.transformCount; tOp++) 1265 { 1266 const BatchData::TransformOp &transformOp = curVert.transform[tOp]; 1267 1268 const MatrixF& deltaTransform = matrices[transformOp.transformIndex]; 1269 1270 deltaTransform.mulP(inVerts[curVert.vertexIndex], &srcVtx); 1271 skinnedVert += (srcVtx * transformOp.weight); 1272 1273 deltaTransform.mulV(inNorms[curVert.vertexIndex], &srcNrm); 1274 skinnedNorm += srcNrm * transformOp.weight; 1275 } 1276 1277 // Assign results 1278 __TSMeshVertexBase *dvert = (__TSMeshVertexBase*)(dest + (mVertSize * curVert.vertexIndex)); 1279 dvert->vert(skinnedVert); 1280 dvert->normal(skinnedNorm); 1281 } 1282} 1283 1284void TSSkinMesh::updateSkinBones( const Vector<MatrixF> &transforms, Vector<MatrixF>& destTransforms ) 1285{ 1286 // Update transforms for current mesh 1287 destTransforms.setSize(batchData.nodeIndex.size()); 1288 1289 for (int i = 0; i<batchData.nodeIndex.size(); i++) 1290 { 1291 S32 node = batchData.nodeIndex[i]; 1292 1293 if (node >= transforms.size()) 1294 continue; // jamesu - ignore obviously invalid data 1295 destTransforms[i].mul(transforms[node], batchData.initialTransforms[i]); 1296 } 1297} 1298 1299void TSSkinMesh::createSkinBatchData() 1300{ 1301 if(batchData.initialized) 1302 return; 1303 1304 batchData.initialized = true; 1305 S32 * curVtx = vertexIndex.begin(); 1306 S32 * curBone = boneIndex.begin(); 1307 F32 * curWeight = weight.begin(); 1308 const S32 * endVtx = vertexIndex.end(); 1309 1310 AssertFatal(batchData.nodeIndex.size() <= TSShape::smMaxSkinBones, "Too many bones are here!!!"); 1311 1312 // Temp vector to build batch operations 1313 Vector<BatchData::BatchedVertex> batchOperations; 1314 1315 bool issuedWeightWarning = false; 1316 1317 if (mVertexData.isReady()) 1318 { 1319 batchData.initialVerts.setSize(mNumVerts); 1320 batchData.initialNorms.setSize(mNumVerts); 1321 1322 // Fill arrays 1323 for (U32 i = 0; i < mNumVerts; i++) 1324 { 1325 const __TSMeshVertexBase &cv = mVertexData.getBase(i); 1326 batchData.initialVerts[i] = cv.vert(); 1327 batchData.initialNorms[i] = cv.normal(); 1328 } 1329 1330 addWeightsFromVertexBuffer(); 1331 1332 curVtx = vertexIndex.begin(); 1333 curBone = boneIndex.begin(); 1334 curWeight = weight.begin(); 1335 endVtx = vertexIndex.end(); 1336 } 1337 else 1338 { 1339 batchData.initialNorms = mNorms; 1340 batchData.initialVerts = mVerts; 1341 } 1342 1343 // Build the batch operations 1344 while( curVtx != endVtx ) 1345 { 1346 const S32 vidx = *curVtx; 1347 ++curVtx; 1348 1349 const S32 midx = *curBone; 1350 ++curBone; 1351 1352 const F32 w = *curWeight; 1353 ++curWeight; 1354 1355 // Ignore empty weights 1356 if ( vidx < 0 || midx < 0 || w == 0 ) 1357 continue; 1358 1359 if( !batchOperations.empty() && 1360 batchOperations.last().vertexIndex == vidx ) 1361 { 1362 AssertFatal( batchOperations.last().transformCount > 0, "Not sure how this happened!" ); 1363 1364 S32 opIdx = batchOperations.last().transformCount++; 1365 1366 // Limit the number of weights per bone (keep the N largest influences) 1367 if ( opIdx >= TSSkinMesh::BatchData::maxBonePerVert ) 1368 { 1369 if ( !issuedWeightWarning ) 1370 { 1371 issuedWeightWarning = true; 1372 Con::warnf( "At least one vertex has too many bone weights - limiting " 1373 "to the largest %d influences (see maxBonePerVert in tsMesh.h).", 1374 TSSkinMesh::BatchData::maxBonePerVert ); 1375 } 1376 1377 // Too many weights => find and replace the smallest one 1378 S32 minIndex = 0; 1379 F32 minWeight = batchOperations.last().transform[0].weight; 1380 for ( S32 i = 1; i < batchOperations.last().transformCount; i++ ) 1381 { 1382 if ( batchOperations.last().transform[i].weight < minWeight ) 1383 { 1384 minWeight = batchOperations.last().transform[i].weight; 1385 minIndex = i; 1386 } 1387 } 1388 1389 opIdx = minIndex; 1390 batchOperations.last().transformCount = TSSkinMesh::BatchData::maxBonePerVert; 1391 } 1392 1393 batchOperations.last().transform[opIdx].transformIndex = midx; 1394 batchOperations.last().transform[opIdx].weight = w; 1395 } 1396 else 1397 { 1398 batchOperations.increment(); 1399 batchOperations.last().vertexIndex = vidx; 1400 batchOperations.last().transformCount = 1; 1401 1402 batchOperations.last().transform[0].transformIndex = midx; 1403 batchOperations.last().transform[0].weight = w; 1404 } 1405 //Con::printf( "[%d] transform idx %d, weight %1.5f", vidx, midx, w ); 1406 } 1407 //Con::printf("End skin update"); 1408 1409 // Normalize vertex weights (force weights for each vert to sum to 1) 1410 if ( issuedWeightWarning ) 1411 { 1412 for ( S32 i = 0; i < batchOperations.size(); i++ ) 1413 { 1414 BatchData::BatchedVertex& batchOp = batchOperations[i]; 1415 1416 // Sum weights for this vertex 1417 F32 invTotalWeight = 0; 1418 for ( S32 j = 0; j < batchOp.transformCount; j++ ) 1419 invTotalWeight += batchOp.transform[j].weight; 1420 1421 // Then normalize the vertex weights 1422 invTotalWeight = 1.0f / invTotalWeight; 1423 for ( S32 j = 0; j < batchOp.transformCount; j++ ) 1424 batchOp.transform[j].weight *= invTotalWeight; 1425 } 1426 } 1427 1428 batchData.vertexBatchOperations.set(batchOperations.address(), batchOperations.size()); 1429 1430 U32 maxValue = 0; 1431 for (U32 i = 0; i<batchData.vertexBatchOperations.size(); i++) 1432 { 1433 maxValue = batchData.vertexBatchOperations[i].transformCount > maxValue ? batchData.vertexBatchOperations[i].transformCount : maxValue; 1434 } 1435 maxBones = maxValue; 1436} 1437 1438void TSSkinMesh::setupVertexTransforms() 1439{ 1440 AssertFatal(mVertexData.vertSize() == mVertSize, "vert size mismatch"); 1441 1442 // Generate the bone transforms for the verts 1443 for( Vector<BatchData::BatchedVertex>::const_iterator itr = batchData.vertexBatchOperations.begin(); 1444 itr != batchData.vertexBatchOperations.end(); itr++ ) 1445 { 1446 const BatchData::BatchedVertex &curTransform = *itr; 1447 S32 i=0; 1448 S32 j=0; 1449 S32 transformsLeft = curTransform.transformCount; 1450 1451 // Set weights and indices in batches of 4 1452 for( i = 0, j = 0; i < curTransform.transformCount; i += 4, j += 1 ) 1453 { 1454 __TSMeshVertex_BoneData &v = mVertexData.getBone(curTransform.vertexIndex, j); 1455 S32 vertsSet = transformsLeft > 4 ? 4 : transformsLeft; 1456 1457 __TSMeshIndex_List indices; 1458 Point4F weights; 1459 dMemset(&indices, '\0', sizeof(indices)); 1460 dMemset(&weights, '\0', sizeof(weights)); 1461 1462 switch (vertsSet) 1463 { 1464 case 1: 1465 indices.x = curTransform.transform[i+0].transformIndex; 1466 weights.x = curTransform.transform[i+0].weight; 1467 break; 1468 case 2: 1469 indices.x = curTransform.transform[i+0].transformIndex; 1470 weights.x = curTransform.transform[i+0].weight; 1471 indices.y = curTransform.transform[i+1].transformIndex; 1472 weights.y = curTransform.transform[i+1].weight; 1473 break; 1474 case 3: 1475 indices.x = curTransform.transform[i+0].transformIndex; 1476 weights.x = curTransform.transform[i+0].weight; 1477 indices.y = curTransform.transform[i+1].transformIndex; 1478 weights.y = curTransform.transform[i+1].weight; 1479 indices.z = curTransform.transform[i+2].transformIndex; 1480 weights.z = curTransform.transform[i+2].weight; 1481 break; 1482 case 4: 1483 indices.x = curTransform.transform[i+0].transformIndex; 1484 weights.x = curTransform.transform[i+0].weight; 1485 indices.y = curTransform.transform[i+1].transformIndex; 1486 weights.y = curTransform.transform[i+1].weight; 1487 indices.z = curTransform.transform[i+2].transformIndex; 1488 weights.z = curTransform.transform[i+2].weight; 1489 indices.w = curTransform.transform[i+3].transformIndex; 1490 weights.w = curTransform.transform[i+3].weight; 1491 break; 1492 case 0: 1493 default: 1494 break; 1495 } 1496 1497 v.index(indices); 1498 v.weight(weights); 1499 transformsLeft -= 4; 1500 } 1501 } 1502} 1503 1504U32 TSSkinMesh::getMaxBonesPerVert() 1505{ 1506 return maxBones >= 0 ? maxBones : 0; 1507} 1508 1509void TSSkinMesh::render( TSVertexBufferHandle &instanceVB ) 1510{ 1511 innerRender(instanceVB, mPB); 1512} 1513 1514void TSSkinMesh::render( TSMaterialList *materials, 1515 const TSRenderState &rdata, 1516 bool isSkinDirty, 1517 const Vector<MatrixF> &transforms, 1518 TSVertexBufferHandle &vertexBuffer, 1519 const char *meshName ) 1520{ 1521 PROFILE_SCOPE(TSSkinMesh_render); 1522 1523 if (mNumVerts == 0) 1524 return; 1525 1526 // verify stuff first 1527 AssertFatal(mVertexData.size() == mNumVerts, "Vert # mismatch"); 1528 AssertFatal((TSShape::smUseHardwareSkinning && vertexBuffer == mVB) || (!TSShape::smUseHardwareSkinning), "Vertex buffer mismatch"); 1529 1530 // render... 1531 innerRender(materials, rdata, vertexBuffer, mPB, meshName); 1532} 1533 1534bool TSSkinMesh::buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials ) 1535{ 1536 return false; 1537} 1538 1539bool TSSkinMesh::castRay( S32 frame, const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials ) 1540{ 1541 TORQUE_UNUSED(frame); 1542 TORQUE_UNUSED(start); 1543 TORQUE_UNUSED(end); 1544 TORQUE_UNUSED(rayInfo); 1545 TORQUE_UNUSED(materials); 1546 1547 return false; 1548} 1549 1550bool TSSkinMesh::buildConvexHull() 1551{ 1552 return false; // no error, but we don't do anything either... 1553} 1554 1555void TSSkinMesh::computeBounds( const MatrixF &transform, Box3F &bounds, S32 frame, Point3F *center, F32 *radius ) 1556{ 1557 TORQUE_UNUSED(frame); 1558 1559 if (mVerts.size() != 0) 1560 { 1561 // Use unskinned verts 1562 TSMesh::computeBounds(mVerts.address(), mVerts.size(), sizeof(Point3F), transform, bounds, center, radius ); 1563 } 1564 else if (frame <= 0 && batchData.initialVerts.size() > 0) 1565 { 1566 // Use unskinned verts 1567 TSMesh::computeBounds(batchData.initialVerts.address(), batchData.initialVerts.size(), sizeof(Point3F), transform, bounds, center, radius); 1568 } 1569 else 1570 { 1571 Point3F *vertStart = reinterpret_cast<Point3F *>(mVertexData.address()); 1572 TSMesh::computeBounds( vertStart, mVertexData.size(), mVertexData.vertSize(), transform, bounds, center, radius ); 1573 } 1574} 1575 1576//----------------------------------------------------- 1577// encoded normals 1578//----------------------------------------------------- 1579 1580const Point3F TSMesh::smU8ToNormalTable[] = 1581{ 1582 Point3F( 0.565061f, -0.270644f, -0.779396f ), 1583 Point3F( -0.309804f, -0.731114f, 0.607860f ), 1584 Point3F( -0.867412f, 0.472957f, 0.154619f ), 1585 Point3F( -0.757488f, 0.498188f, -0.421925f ), 1586 Point3F( 0.306834f, -0.915340f, 0.260778f ), 1587 Point3F( 0.098754f, 0.639153f, -0.762713f ), 1588 Point3F( 0.713706f, -0.558862f, -0.422252f ), 1589 Point3F( -0.890431f, -0.407603f, -0.202466f ), 1590 Point3F( 0.848050f, -0.487612f, -0.207475f ), 1591 Point3F( -0.232226f, 0.776855f, 0.585293f ), 1592 Point3F( -0.940195f, 0.304490f, -0.152706f ), 1593 Point3F( 0.602019f, -0.491878f, -0.628991f ), 1594 Point3F( -0.096835f, -0.494354f, -0.863850f ), 1595 Point3F( 0.026630f, -0.323659f, -0.945799f ), 1596 Point3F( 0.019208f, 0.909386f, 0.415510f ), 1597 Point3F( 0.854440f, 0.491730f, 0.167731f ), 1598 Point3F( -0.418835f, 0.866521f, -0.271512f ), 1599 Point3F( 0.465024f, 0.409667f, 0.784809f ), 1600 Point3F( -0.674391f, -0.691087f, -0.259992f ), 1601 Point3F( 0.303858f, -0.869270f, -0.389922f ), 1602 Point3F( 0.991333f, 0.090061f, -0.095640f ), 1603 Point3F( -0.275924f, -0.369550f, 0.887298f ), 1604 Point3F( 0.426545f, -0.465962f, 0.775202f ), 1605 Point3F( -0.482741f, -0.873278f, -0.065920f ), 1606 Point3F( 0.063616f, 0.932012f, -0.356800f ), 1607 Point3F( 0.624786f, -0.061315f, 0.778385f ), 1608 Point3F( -0.530300f, 0.416850f, 0.738253f ), 1609 Point3F( 0.312144f, -0.757028f, -0.573999f ), 1610 Point3F( 0.399288f, -0.587091f, -0.704197f ), 1611 Point3F( -0.132698f, 0.482877f, 0.865576f ), 1612 Point3F( 0.950966f, 0.306530f, 0.041268f ), 1613 Point3F( -0.015923f, -0.144300f, 0.989406f ), 1614 Point3F( -0.407522f, -0.854193f, 0.322925f ), 1615 Point3F( -0.932398f, 0.220464f, 0.286408f ), 1616 Point3F( 0.477509f, 0.876580f, 0.059936f ), 1617 Point3F( 0.337133f, 0.932606f, -0.128796f ), 1618 Point3F( -0.638117f, 0.199338f, 0.743687f ), 1619 Point3F( -0.677454f, 0.445349f, 0.585423f ), 1620 Point3F( -0.446715f, 0.889059f, -0.100099f ), 1621 Point3F( -0.410024f, 0.909168f, 0.072759f ), 1622 Point3F( 0.708462f, 0.702103f, -0.071641f ), 1623 Point3F( -0.048801f, -0.903683f, -0.425411f ), 1624 Point3F( -0.513681f, -0.646901f, 0.563606f ), 1625 Point3F( -0.080022f, 0.000676f, -0.996793f ), 1626 Point3F( 0.066966f, -0.991150f, -0.114615f ), 1627 Point3F( -0.245220f, 0.639318f, -0.728793f ), 1628 Point3F( 0.250978f, 0.855979f, 0.452006f ), 1629 Point3F( -0.123547f, 0.982443f, -0.139791f ), 1630 Point3F( -0.794825f, 0.030254f, -0.606084f ), 1631 Point3F( -0.772905f, 0.547941f, 0.319967f ), 1632 Point3F( 0.916347f, 0.369614f, -0.153928f ), 1633 Point3F( -0.388203f, 0.105395f, 0.915527f ), 1634 Point3F( -0.700468f, -0.709334f, 0.078677f ), 1635 Point3F( -0.816193f, 0.390455f, 0.425880f ), 1636 Point3F( -0.043007f, 0.769222f, -0.637533f ), 1637 Point3F( 0.911444f, 0.113150f, 0.395560f ), 1638 Point3F( 0.845801f, 0.156091f, -0.510153f ), 1639 Point3F( 0.829801f, -0.029340f, 0.557287f ), 1640 Point3F( 0.259529f, 0.416263f, 0.871418f ), 1641 Point3F( 0.231128f, -0.845982f, 0.480515f ), 1642 Point3F( -0.626203f, -0.646168f, 0.436277f ), 1643 Point3F( -0.197047f, -0.065791f, 0.978184f ), 1644 Point3F( -0.255692f, -0.637488f, -0.726794f ), 1645 Point3F( 0.530662f, -0.844385f, -0.073567f ), 1646 Point3F( -0.779887f, 0.617067f, -0.104899f ), 1647 Point3F( 0.739908f, 0.113984f, 0.662982f ), 1648 Point3F( -0.218801f, 0.930194f, -0.294729f ), 1649 Point3F( -0.374231f, 0.818666f, 0.435589f ), 1650 Point3F( -0.720250f, -0.028285f, 0.693137f ), 1651 Point3F( 0.075389f, 0.415049f, 0.906670f ), 1652 Point3F( -0.539724f, -0.106620f, 0.835063f ), 1653 Point3F( -0.452612f, -0.754669f, -0.474991f ), 1654 Point3F( 0.682822f, 0.581234f, -0.442629f ), 1655 Point3F( 0.002435f, -0.618462f, -0.785811f ), 1656 Point3F( -0.397631f, 0.110766f, -0.910835f ), 1657 Point3F( 0.133935f, -0.985438f, 0.104754f ), 1658 Point3F( 0.759098f, -0.608004f, 0.232595f ), 1659 Point3F( -0.825239f, -0.256087f, 0.503388f ), 1660 Point3F( 0.101693f, -0.565568f, 0.818408f ), 1661 Point3F( 0.386377f, 0.793546f, -0.470104f ), 1662 Point3F( -0.520516f, -0.840690f, 0.149346f ), 1663 Point3F( -0.784549f, -0.479672f, 0.392935f ), 1664 Point3F( -0.325322f, -0.927581f, -0.183735f ), 1665 Point3F( -0.069294f, -0.428541f, 0.900861f ), 1666 Point3F( 0.993354f, -0.115023f, -0.004288f ), 1667 Point3F( -0.123896f, -0.700568f, 0.702747f ), 1668 Point3F( -0.438031f, -0.120880f, -0.890795f ), 1669 Point3F( 0.063314f, 0.813233f, 0.578484f ), 1670 Point3F( 0.322045f, 0.889086f, -0.325289f ), 1671 Point3F( -0.133521f, 0.875063f, -0.465228f ), 1672 Point3F( 0.637155f, 0.564814f, 0.524422f ), 1673 Point3F( 0.260092f, -0.669353f, 0.695930f ), 1674 Point3F( 0.953195f, 0.040485f, -0.299634f ), 1675 Point3F( -0.840665f, -0.076509f, 0.536124f ), 1676 Point3F( -0.971350f, 0.202093f, 0.125047f ), 1677 Point3F( -0.804307f, -0.396312f, -0.442749f ), 1678 Point3F( -0.936746f, 0.069572f, 0.343027f ), 1679 Point3F( 0.426545f, -0.465962f, 0.775202f ), 1680 Point3F( 0.794542f, -0.227450f, 0.563000f ), 1681 Point3F( -0.892172f, 0.091169f, -0.442399f ), 1682 Point3F( -0.312654f, 0.541264f, 0.780564f ), 1683 Point3F( 0.590603f, -0.735618f, -0.331743f ), 1684 Point3F( -0.098040f, -0.986713f, 0.129558f ), 1685 Point3F( 0.569646f, 0.283078f, -0.771603f ), 1686 Point3F( 0.431051f, -0.407385f, -0.805129f ), 1687 Point3F( -0.162087f, -0.938749f, -0.304104f ), 1688 Point3F( 0.241533f, -0.359509f, 0.901341f ), 1689 Point3F( -0.576191f, 0.614939f, 0.538380f ), 1690 Point3F( -0.025110f, 0.085740f, 0.996001f ), 1691 Point3F( -0.352693f, -0.198168f, 0.914515f ), 1692 Point3F( -0.604577f, 0.700711f, 0.378802f ), 1693 Point3F( 0.465024f, 0.409667f, 0.784809f ), 1694 Point3F( -0.254684f, -0.030474f, -0.966544f ), 1695 Point3F( -0.604789f, 0.791809f, 0.085259f ), 1696 Point3F( -0.705147f, -0.399298f, 0.585943f ), 1697 Point3F( 0.185691f, 0.017236f, -0.982457f ), 1698 Point3F( 0.044588f, 0.973094f, 0.226052f ), 1699 Point3F( -0.405463f, 0.642367f, 0.650357f ), 1700 Point3F( -0.563959f, 0.599136f, -0.568319f ), 1701 Point3F( 0.367162f, -0.072253f, -0.927347f ), 1702 Point3F( 0.960429f, -0.213570f, -0.178783f ), 1703 Point3F( -0.192629f, 0.906005f, 0.376893f ), 1704 Point3F( -0.199718f, -0.359865f, -0.911378f ), 1705 Point3F( 0.485072f, 0.121233f, -0.866030f ), 1706 Point3F( 0.467163f, -0.874294f, 0.131792f ), 1707 Point3F( -0.638953f, -0.716603f, 0.279677f ), 1708 Point3F( -0.622710f, 0.047813f, -0.780990f ), 1709 Point3F( 0.828724f, -0.054433f, -0.557004f ), 1710 Point3F( 0.130241f, 0.991080f, 0.028245f ), 1711 Point3F( 0.310995f, -0.950076f, -0.025242f ), 1712 Point3F( 0.818118f, 0.275336f, 0.504850f ), 1713 Point3F( 0.676328f, 0.387023f, 0.626733f ), 1714 Point3F( -0.100433f, 0.495114f, -0.863004f ), 1715 Point3F( -0.949609f, -0.240681f, -0.200786f ), 1716 Point3F( -0.102610f, 0.261831f, -0.959644f ), 1717 Point3F( -0.845732f, -0.493136f, 0.203850f ), 1718 Point3F( 0.672617f, -0.738838f, 0.041290f ), 1719 Point3F( 0.380465f, 0.875938f, 0.296613f ), 1720 Point3F( -0.811223f, 0.262027f, -0.522742f ), 1721 Point3F( -0.074423f, -0.775670f, -0.626736f ), 1722 Point3F( -0.286499f, 0.755850f, -0.588735f ), 1723 Point3F( 0.291182f, -0.276189f, -0.915933f ), 1724 Point3F( -0.638117f, 0.199338f, 0.743687f ), 1725 Point3F( 0.439922f, -0.864433f, -0.243359f ), 1726 Point3F( 0.177649f, 0.206919f, 0.962094f ), 1727 Point3F( 0.277107f, 0.948521f, 0.153361f ), 1728 Point3F( 0.507629f, 0.661918f, -0.551523f ), 1729 Point3F( -0.503110f, -0.579308f, -0.641313f ), 1730 Point3F( 0.600522f, 0.736495f, -0.311364f ), 1731 Point3F( -0.691096f, -0.715301f, -0.103592f ), 1732 Point3F( -0.041083f, -0.858497f, 0.511171f ), 1733 Point3F( 0.207773f, -0.480062f, -0.852274f ), 1734 Point3F( 0.795719f, 0.464614f, 0.388543f ), 1735 Point3F( -0.100433f, 0.495114f, -0.863004f ), 1736 Point3F( 0.703249f, 0.065157f, -0.707951f ), 1737 Point3F( -0.324171f, -0.941112f, 0.096024f ), 1738 Point3F( -0.134933f, -0.940212f, 0.312722f ), 1739 Point3F( -0.438240f, 0.752088f, -0.492249f ), 1740 Point3F( 0.964762f, -0.198855f, 0.172311f ), 1741 Point3F( -0.831799f, 0.196807f, 0.519015f ), 1742 Point3F( -0.508008f, 0.819902f, 0.263986f ), 1743 Point3F( 0.471075f, -0.001146f, 0.882092f ), 1744 Point3F( 0.919512f, 0.246162f, -0.306435f ), 1745 Point3F( -0.960050f, 0.279828f, -0.001187f ), 1746 Point3F( 0.110232f, -0.847535f, -0.519165f ), 1747 Point3F( 0.208229f, 0.697360f, 0.685806f ), 1748 Point3F( -0.199680f, -0.560621f, 0.803637f ), 1749 Point3F( 0.170135f, -0.679985f, -0.713214f ), 1750 Point3F( 0.758371f, -0.494907f, 0.424195f ), 1751 Point3F( 0.077734f, -0.755978f, 0.649965f ), 1752 Point3F( 0.612831f, -0.672475f, 0.414987f ), 1753 Point3F( 0.142776f, 0.836698f, -0.528726f ), 1754 Point3F( -0.765185f, 0.635778f, 0.101382f ), 1755 Point3F( 0.669873f, -0.419737f, 0.612447f ), 1756 Point3F( 0.593549f, 0.194879f, 0.780847f ), 1757 Point3F( 0.646930f, 0.752173f, 0.125368f ), 1758 Point3F( 0.837721f, 0.545266f, -0.030127f ), 1759 Point3F( 0.541505f, 0.768070f, 0.341820f ), 1760 Point3F( 0.760679f, -0.365715f, -0.536301f ), 1761 Point3F( 0.381516f, 0.640377f, 0.666605f ), 1762 Point3F( 0.565794f, -0.072415f, -0.821361f ), 1763 Point3F( -0.466072f, -0.401588f, 0.788356f ), 1764 Point3F( 0.987146f, 0.096290f, 0.127560f ), 1765 Point3F( 0.509709f, -0.688886f, -0.515396f ), 1766 Point3F( -0.135132f, -0.988046f, -0.074192f ), 1767 Point3F( 0.600499f, 0.476471f, -0.642166f ), 1768 Point3F( -0.732326f, -0.275320f, -0.622815f ), 1769 Point3F( -0.881141f, -0.470404f, 0.048078f ), 1770 Point3F( 0.051548f, 0.601042f, 0.797553f ), 1771 Point3F( 0.402027f, -0.763183f, 0.505891f ), 1772 Point3F( 0.404233f, -0.208288f, 0.890624f ), 1773 Point3F( -0.311793f, 0.343843f, 0.885752f ), 1774 Point3F( 0.098132f, -0.937014f, 0.335223f ), 1775 Point3F( 0.537158f, 0.830585f, -0.146936f ), 1776 Point3F( 0.725277f, 0.298172f, -0.620538f ), 1777 Point3F( -0.882025f, 0.342976f, -0.323110f ), 1778 Point3F( -0.668829f, 0.424296f, -0.610443f ), 1779 Point3F( -0.408835f, -0.476442f, -0.778368f ), 1780 Point3F( 0.809472f, 0.397249f, -0.432375f ), 1781 Point3F( -0.909184f, -0.205938f, -0.361903f ), 1782 Point3F( 0.866930f, -0.347934f, -0.356895f ), 1783 Point3F( 0.911660f, -0.141281f, -0.385897f ), 1784 Point3F( -0.431404f, -0.844074f, -0.318480f ), 1785 Point3F( -0.950593f, -0.073496f, 0.301614f ), 1786 Point3F( -0.719716f, 0.626915f, -0.298305f ), 1787 Point3F( -0.779887f, 0.617067f, -0.104899f ), 1788 Point3F( -0.475899f, -0.542630f, 0.692151f ), 1789 Point3F( 0.081952f, -0.157248f, -0.984153f ), 1790 Point3F( 0.923990f, -0.381662f, -0.024025f ), 1791 Point3F( -0.957998f, 0.120979f, -0.260008f ), 1792 Point3F( 0.306601f, 0.227975f, -0.924134f ), 1793 Point3F( -0.141244f, 0.989182f, 0.039601f ), 1794 Point3F( 0.077097f, 0.186288f, -0.979466f ), 1795 Point3F( -0.630407f, -0.259801f, 0.731499f ), 1796 Point3F( 0.718150f, 0.637408f, 0.279233f ), 1797 Point3F( 0.340946f, 0.110494f, 0.933567f ), 1798 Point3F( -0.396671f, 0.503020f, -0.767869f ), 1799 Point3F( 0.636943f, -0.245005f, 0.730942f ), 1800 Point3F( -0.849605f, -0.518660f, -0.095724f ), 1801 Point3F( -0.388203f, 0.105395f, 0.915527f ), 1802 Point3F( -0.280671f, -0.776541f, -0.564099f ), 1803 Point3F( -0.601680f, 0.215451f, -0.769131f ), 1804 Point3F( -0.660112f, -0.632371f, -0.405412f ), 1805 Point3F( 0.921096f, 0.284072f, 0.266242f ), 1806 Point3F( 0.074850f, -0.300846f, 0.950731f ), 1807 Point3F( 0.943952f, -0.067062f, 0.323198f ), 1808 Point3F( -0.917838f, -0.254589f, 0.304561f ), 1809 Point3F( 0.889843f, -0.409008f, 0.202219f ), 1810 Point3F( -0.565849f, 0.753721f, -0.334246f ), 1811 Point3F( 0.791460f, 0.555918f, -0.254060f ), 1812 Point3F( 0.261936f, 0.703590f, -0.660568f ), 1813 Point3F( -0.234406f, 0.952084f, 0.196444f ), 1814 Point3F( 0.111205f, 0.979492f, -0.168014f ), 1815 Point3F( -0.869844f, -0.109095f, -0.481113f ), 1816 Point3F( -0.337728f, -0.269701f, -0.901777f ), 1817 Point3F( 0.366793f, 0.408875f, -0.835634f ), 1818 Point3F( -0.098749f, 0.261316f, 0.960189f ), 1819 Point3F( -0.272379f, -0.847100f, 0.456324f ), 1820 Point3F( -0.319506f, 0.287444f, -0.902935f ), 1821 Point3F( 0.873383f, -0.294109f, 0.388203f ), 1822 Point3F( -0.088950f, 0.710450f, 0.698104f ), 1823 Point3F( 0.551238f, -0.786552f, 0.278340f ), 1824 Point3F( 0.724436f, -0.663575f, -0.186712f ), 1825 Point3F( 0.529741f, -0.606539f, 0.592861f ), 1826 Point3F( -0.949743f, -0.282514f, 0.134809f ), 1827 Point3F( 0.155047f, 0.419442f, -0.894443f ), 1828 Point3F( -0.562653f, -0.329139f, -0.758346f ), 1829 Point3F( 0.816407f, -0.576953f, 0.024576f ), 1830 Point3F( 0.178550f, -0.950242f, -0.255266f ), 1831 Point3F( 0.479571f, 0.706691f, 0.520192f ), 1832 Point3F( 0.391687f, 0.559884f, -0.730145f ), 1833 Point3F( 0.724872f, -0.205570f, -0.657496f ), 1834 Point3F( -0.663196f, -0.517587f, -0.540624f ), 1835 Point3F( -0.660054f, -0.122486f, -0.741165f ), 1836 Point3F( -0.531989f, 0.374711f, -0.759328f ), 1837 Point3F( 0.194979f, -0.059120f, 0.979024f ) 1838}; 1839 1840U8 TSMesh::encodeNormal( const Point3F &normal ) 1841{ 1842 U8 bestIndex = 0; 1843 F32 bestDot = -10E30f; 1844 for ( U32 i = 0; i < 256; i++ ) 1845 { 1846 F32 dot = mDot( normal, smU8ToNormalTable[i] ); 1847 if ( dot > bestDot ) 1848 { 1849 bestIndex = i; 1850 bestDot = dot; 1851 } 1852 } 1853 return bestIndex; 1854} 1855 1856//----------------------------------------------------- 1857// TSMesh assemble from/ dissemble to memory buffer 1858//----------------------------------------------------- 1859 1860#define tsalloc TSShape::smTSAlloc 1861 1862TSMesh* TSMesh::assembleMesh( U32 meshType, bool skip ) 1863{ 1864 static TSMesh tempStandardMesh; 1865 static TSSkinMesh tempSkinMesh; 1866 static TSDecalMesh tempDecalMesh; 1867 static TSSortedMesh tempSortedMesh; 1868 1869 bool justSize = skip || !tsalloc.allocShape32(0); // if this returns NULL, we're just sizing memory block 1870 1871 // a little funny business because we pretend decals are derived from meshes 1872 S32 * ret = NULL; 1873 TSMesh * mesh = NULL; 1874 TSDecalMesh * decal = NULL; 1875 1876 if ( justSize ) 1877 { 1878 switch ( meshType ) 1879 { 1880 case StandardMeshType : 1881 { 1882 ret = (S32*)&tempStandardMesh; 1883 mesh = &tempStandardMesh; 1884 tsalloc.allocShape32( sizeof(TSMesh) >> 2 ); 1885 break; 1886 } 1887 case SkinMeshType : 1888 { 1889 ret = (S32*)&tempSkinMesh; 1890 mesh = &tempSkinMesh; 1891 tsalloc.allocShape32( sizeof(TSSkinMesh) >> 2 ); 1892 break; 1893 } 1894 case DecalMeshType : 1895 { 1896 ret = (S32*)&tempDecalMesh; 1897 decal = &tempDecalMesh; 1898 tsalloc.allocShape32( sizeof(TSDecalMesh) >> 2 ); 1899 break; 1900 } 1901 case SortedMeshType : 1902 { 1903 ret = (S32*)&tempSortedMesh; 1904 mesh = &tempSortedMesh; 1905 tsalloc.allocShape32( sizeof(TSSortedMesh) >> 2 ); 1906 break; 1907 } 1908 } 1909 } 1910 else 1911 { 1912 switch ( meshType ) 1913 { 1914 case StandardMeshType : 1915 { 1916 ret = tsalloc.allocShape32( sizeof(TSMesh) >> 2 ); 1917 constructInPlace( (TSMesh*)ret ); 1918 mesh = (TSMesh*)ret; 1919 break; 1920 } 1921 case SkinMeshType : 1922 { 1923 ret = tsalloc.allocShape32( sizeof(TSSkinMesh) >> 2 ); 1924 constructInPlace( (TSSkinMesh*)ret ); 1925 mesh = (TSSkinMesh*)ret; 1926 break; 1927 } 1928 case DecalMeshType : 1929 { 1930 ret = tsalloc.allocShape32( sizeof(TSDecalMesh) >> 2 ); 1931 constructInPlace((TSDecalMesh*)ret); 1932 decal = (TSDecalMesh*)ret; 1933 break; 1934 } 1935 case SortedMeshType : 1936 { 1937 ret = tsalloc.allocShape32( sizeof(TSSortedMesh) >> 2 ); 1938 constructInPlace( (TSSortedMesh*)ret ); 1939 mesh = (TSSortedMesh*)ret; 1940 break; 1941 } 1942 } 1943 } 1944 1945 tsalloc.setSkipMode( skip ); 1946 1947 if ( mesh ) 1948 mesh->assemble( skip ); 1949 1950 if ( decal ) 1951 decal->assemble( skip ); 1952 1953 tsalloc.setSkipMode( false ); 1954 1955 return (TSMesh*)ret; 1956} 1957 1958void TSMesh::convertToTris( const TSDrawPrimitive *primitivesIn, 1959 const S32 *indicesIn, 1960 S32 numPrimIn, 1961 S32 &numPrimOut, 1962 S32 &numIndicesOut, 1963 TSDrawPrimitive *primitivesOut, 1964 S32 *indicesOut ) const 1965{ 1966 S32 prevMaterial = -99999; 1967 TSDrawPrimitive * newDraw = NULL; 1968 numPrimOut = 0; 1969 numIndicesOut = 0; 1970 for ( S32 i = 0; i < numPrimIn; i++ ) 1971 { 1972 S32 newMat = primitivesIn[i].matIndex; 1973 newMat &= ~<a href="/coding/class/structtsdrawprimitive/">TSDrawPrimitive</a>::TypeMask; 1974 1975 U32 start = primitivesIn[i].start; 1976 U32 prevStart = (i > 0) ? primitivesIn[i-1].start : start; 1977 U32 numElements = primitivesIn[i].numElements; 1978 1979 // Add a new primitive if changing materials, or if this primitive 1980 // indexes vertices in a different 16-bit range 1981 if ( ( newMat != prevMaterial ) || 1982 ((indicesIn[prevStart] ^ indicesIn[start]) & 0xFFFF0000) ) 1983 { 1984 if ( primitivesOut ) 1985 { 1986 newDraw = &primitivesOut[numPrimOut]; 1987 newDraw->start = numIndicesOut; 1988 newDraw->numElements = 0; 1989 newDraw->matIndex = newMat | TSDrawPrimitive::Triangles; 1990 } 1991 numPrimOut++; 1992 prevMaterial = newMat; 1993 } 1994 1995 // gonna depend on what kind of primitive it is... 1996 if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles) 1997 { 1998 for ( S32 j = 0; j < numElements; j += 3 ) 1999 { 2000 if ( indicesOut ) 2001 { 2002 indicesOut[numIndicesOut + 0] = indicesIn[start + j + 0]; 2003 indicesOut[numIndicesOut + 1] = indicesIn[start + j + 1]; 2004 indicesOut[numIndicesOut + 2] = indicesIn[start + j + 2]; 2005 } 2006 if ( newDraw ) 2007 newDraw->numElements += 3; 2008 2009 numIndicesOut += 3; 2010 } 2011 } 2012 else 2013 { 2014 U32 idx0 = indicesIn[start + 0]; 2015 U32 idx1; 2016 U32 idx2 = indicesIn[start + 1]; 2017 U32 * nextIdx = &idx1; 2018 for ( S32 j = 2; j < numElements; j++ ) 2019 { 2020 *nextIdx = idx2; 2021 nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1); 2022 idx2 = indicesIn[start + j]; 2023 if ( idx0 == idx1 || idx1 == idx2 || idx2 == idx0 ) 2024 continue; 2025 2026 if ( indicesOut ) 2027 { 2028 indicesOut[numIndicesOut+0] = idx0; 2029 indicesOut[numIndicesOut+1] = idx1; 2030 indicesOut[numIndicesOut+2] = idx2; 2031 } 2032 2033 if ( newDraw ) 2034 newDraw->numElements += 3; 2035 numIndicesOut += 3; 2036 } 2037 } 2038 } 2039} 2040 2041void unwindStrip( const S32 * indices, S32 numElements, Vector<S32> &triIndices ) 2042{ 2043 U32 idx0 = indices[0]; 2044 U32 idx1; 2045 U32 idx2 = indices[1]; 2046 U32 * nextIdx = &idx1; 2047 for ( S32 j = 2; j < numElements; j++ ) 2048 { 2049 *nextIdx = idx2; 2050 nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1); 2051 idx2 = indices[j]; 2052 if ( idx0 == idx1 || idx1 == idx2 || idx2 == idx0 ) 2053 continue; 2054 2055 triIndices.push_back( idx0 ); 2056 triIndices.push_back( idx1 ); 2057 triIndices.push_back( idx2 ); 2058 } 2059} 2060 2061void TSMesh::convertToSingleStrip( const TSDrawPrimitive *primitivesIn, 2062 const S32 *indicesIn, 2063 S32 numPrimIn, 2064 S32 &numPrimOut, 2065 S32 &numIndicesOut, 2066 TSDrawPrimitive *primitivesOut, 2067 S32 *indicesOut ) const 2068{ 2069 S32 prevMaterial = -99999; 2070 TSDrawPrimitive * newDraw = NULL; 2071 TSDrawPrimitive * newTris = NULL; 2072 Vector<S32> triIndices; 2073 S32 curDrawOut = 0; 2074 numPrimOut = 0; 2075 numIndicesOut = 0; 2076 for ( S32 i = 0; i < numPrimIn; i++ ) 2077 { 2078 S32 newMat = primitivesIn[i].matIndex; 2079 2080 U32 start = primitivesIn[i].start; 2081 U32 prevStart = (i > 0) ? primitivesIn[i-1].start : start; 2082 U32 numElements = primitivesIn[i].numElements; 2083 2084 // Add a new primitive if changing materials, or if this primitive 2085 // indexes vertices in a different 16-bit range 2086 if ( ( newMat != prevMaterial ) || 2087 ((indicesIn[prevStart] ^ indicesIn[start]) & 0xFFFF0000) ) 2088 { 2089 // before adding the new primitive, transfer triangle indices 2090 if ( triIndices.size() ) 2091 { 2092 if ( newTris && indicesOut ) 2093 { 2094 newTris->start = numIndicesOut; 2095 newTris->numElements = triIndices.size(); 2096 dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32)); 2097 } 2098 numIndicesOut += triIndices.size(); 2099 triIndices.clear(); 2100 newTris = NULL; 2101 } 2102 2103 if ( primitivesOut ) 2104 { 2105 newDraw = &primitivesOut[numPrimOut]; 2106 newDraw->start = numIndicesOut; 2107 newDraw->numElements = 0; 2108 newDraw->matIndex = newMat; 2109 } 2110 2111 numPrimOut++; 2112 curDrawOut = 0; 2113 prevMaterial = newMat; 2114 } 2115 2116 // gonna depend on what kind of primitive it is... 2117 // from above we know it's the same kind as the one we're building... 2118 if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles) 2119 { 2120 // triangles primitive...add to it 2121 for ( S32 j = 0; j < numElements; j += 3 ) 2122 { 2123 if ( indicesOut ) 2124 { 2125 indicesOut[numIndicesOut + 0] = indicesIn[start + j + 0]; 2126 indicesOut[numIndicesOut + 1] = indicesIn[start + j + 1]; 2127 indicesOut[numIndicesOut + 2] = indicesIn[start + j + 2]; 2128 } 2129 2130 if ( newDraw ) 2131 newDraw->numElements += 3; 2132 2133 numIndicesOut += 3; 2134 } 2135 } 2136 else 2137 { 2138 // strip primitive... 2139 // if numElements less than smSmallestStripSize, add to triangles... 2140 if ( numElements < smMinStripSize + 2 ) 2141 { 2142 // put triangle indices aside until material changes... 2143 if ( triIndices.empty() ) 2144 { 2145 // set up for new triangle primitive and add it if we are copying data right now 2146 if ( primitivesOut ) 2147 { 2148 newTris = &primitivesOut[numPrimOut]; 2149 newTris->matIndex = newMat; 2150 newTris->matIndex &= ~(TSDrawPrimitive::Triangles</a>|<a href="/coding/class/structtsdrawprimitive/#structtsdrawprimitive_1ac9813717d47f33a65a1a751a1713507dab4690780bfa05758bdbe8e9e39bb64bf">TSDrawPrimitive::Strip); 2151 newTris->matIndex |= TSDrawPrimitive::Triangles; 2152 } 2153 2154 numPrimOut++; 2155 } 2156 unwindStrip( indicesIn + start, numElements, triIndices ); 2157 } 2158 else 2159 { 2160 // strip primitive...add to it 2161 if ( indicesOut ) 2162 { 2163 if ( curDrawOut & 1 ) 2164 { 2165 indicesOut[numIndicesOut + 0] = indicesOut[numIndicesOut - 1]; 2166 indicesOut[numIndicesOut + 1] = indicesOut[numIndicesOut - 1]; 2167 indicesOut[numIndicesOut + 2] = indicesIn[start]; 2168 dMemcpy(indicesOut+numIndicesOut+3,indicesIn+start,numElements*sizeof(U32)); 2169 } 2170 else if ( curDrawOut ) 2171 { 2172 indicesOut[numIndicesOut + 0] = indicesOut[numIndicesOut - 1]; 2173 indicesOut[numIndicesOut + 1] = indicesIn[start]; 2174 dMemcpy(indicesOut+numIndicesOut+2,indicesIn+start,numElements*sizeof(U32)); 2175 } 2176 else 2177 dMemcpy(indicesOut+numIndicesOut,indicesIn+start,numElements*sizeof(U32)); 2178 } 2179 S32 added = numElements; 2180 added += curDrawOut ? (curDrawOut&1 ? 3 : 2) : 0; 2181 if ( newDraw ) 2182 newDraw->numElements += added; 2183 2184 numIndicesOut += added; 2185 curDrawOut += added; 2186 } 2187 } 2188 } 2189 // spit out tris before leaving 2190 // before adding the new primitive, transfer triangle indices 2191 if ( triIndices.size() ) 2192 { 2193 if ( newTris && indicesOut ) 2194 { 2195 newTris->start = numIndicesOut; 2196 newTris->numElements = triIndices.size(); 2197 dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32)); 2198 } 2199 2200 numIndicesOut += triIndices.size(); 2201 triIndices.clear(); 2202 newTris = NULL; 2203 } 2204} 2205 2206// this method does none of the converting that the above methods do, except that small strips are converted 2207// to triangle lists... 2208void TSMesh::leaveAsMultipleStrips( const TSDrawPrimitive *primitivesIn, 2209 const S32 *indicesIn, 2210 S32 numPrimIn, 2211 S32 &numPrimOut, 2212 S32 &numIndicesOut, 2213 TSDrawPrimitive *primitivesOut, 2214 S32 *indicesOut ) const 2215{ 2216 S32 prevMaterial = -99999; 2217 TSDrawPrimitive * newDraw = NULL; 2218 Vector<S32> triIndices; 2219 numPrimOut = 0; 2220 numIndicesOut = 0; 2221 for ( S32 i = 0; i < numPrimIn; i++ ) 2222 { 2223 S32 newMat = primitivesIn[i].matIndex; 2224 2225 U32 start = primitivesIn[i].start; 2226 U32 prevStart = (i > 0) ? primitivesIn[i-1].start : start; 2227 U32 numElements = primitivesIn[i].numElements; 2228 2229 // Add a new primitive if changing materials, or if this primitive 2230 // indexes vertices in a different 16-bit range 2231 if ( triIndices.size() && 2232 (( newMat != prevMaterial ) || 2233 ((indicesIn[prevStart] ^ indicesIn[start]) & 0xFFFF0000) )) 2234 { 2235 // material just changed and we have triangles lying around 2236 // add primitive and indices for triangles and clear triIndices 2237 if ( indicesOut ) 2238 { 2239 TSDrawPrimitive * newTris = &primitivesOut[numPrimOut]; 2240 newTris->matIndex = prevMaterial; 2241 newTris->matIndex &= ~(TSDrawPrimitive::Triangles</a>|<a href="/coding/class/structtsdrawprimitive/#structtsdrawprimitive_1ac9813717d47f33a65a1a751a1713507dab4690780bfa05758bdbe8e9e39bb64bf">TSDrawPrimitive::Strip); 2242 newTris->matIndex |= TSDrawPrimitive::Triangles; 2243 newTris->start = numIndicesOut; 2244 newTris->numElements = triIndices.size(); 2245 dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32)); 2246 } 2247 numPrimOut++; 2248 numIndicesOut += triIndices.size(); 2249 triIndices.clear(); 2250 } 2251 2252 // this is a little convoluted because this code was adapted from convertToSingleStrip 2253 // but we will need a new primitive only if it is a triangle primitive coming in 2254 // or we have more elements than the min strip size... 2255 if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles || numElements>=<a href="/coding/class/classtsmesh/#classtsmesh_1a30775157e7f49fdd31b0458872e3a413">smMinStripSize</a>+2) 2256 { 2257 if ( primitivesOut ) 2258 { 2259 newDraw = &primitivesOut[numPrimOut]; 2260 newDraw->start = numIndicesOut; 2261 newDraw->numElements = 0; 2262 newDraw->matIndex = newMat; 2263 } 2264 numPrimOut++; 2265 } 2266 prevMaterial = newMat; 2267 2268 // gonna depend on what kind of primitive it is... 2269 // from above we know it's the same kind as the one we're building... 2270 if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles) 2271 { 2272 // triangles primitive...add to it 2273 for ( S32 j = 0; j < numElements; j += 3 ) 2274 { 2275 if ( indicesOut ) 2276 { 2277 indicesOut[numIndicesOut + 0] = indicesIn[start + j + 0]; 2278 indicesOut[numIndicesOut + 1] = indicesIn[start + j + 1]; 2279 indicesOut[numIndicesOut + 2] = indicesIn[start + j + 2]; 2280 } 2281 if ( newDraw ) 2282 newDraw->numElements += 3; 2283 2284 numIndicesOut += 3; 2285 } 2286 } 2287 else 2288 { 2289 // strip primitive... 2290 // if numElements less than smSmallestStripSize, add to triangles... 2291 if ( numElements < smMinStripSize + 2 ) 2292 // put triangle indices aside until material changes... 2293 unwindStrip( indicesIn + start, numElements, triIndices ); 2294 else 2295 { 2296 // strip primitive...add to it 2297 if ( indicesOut ) 2298 dMemcpy(indicesOut+numIndicesOut,indicesIn+start,numElements*sizeof(U32)); 2299 if ( newDraw ) 2300 newDraw->numElements = numElements; 2301 2302 numIndicesOut += numElements; 2303 } 2304 } 2305 } 2306 // spit out tris before leaving 2307 if ( triIndices.size() ) 2308 { 2309 // material just changed and we have triangles lying around 2310 // add primitive and indices for triangles and clear triIndices 2311 if ( indicesOut ) 2312 { 2313 TSDrawPrimitive *newTris = &primitivesOut[numPrimOut]; 2314 newTris->matIndex = prevMaterial; 2315 newTris->matIndex &= ~(TSDrawPrimitive::Triangles</a>|<a href="/coding/class/structtsdrawprimitive/#structtsdrawprimitive_1ac9813717d47f33a65a1a751a1713507dab4690780bfa05758bdbe8e9e39bb64bf">TSDrawPrimitive::Strip); 2316 newTris->matIndex |= TSDrawPrimitive::Triangles; 2317 newTris->start = numIndicesOut; 2318 newTris->numElements = triIndices.size(); 2319 dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32)); 2320 } 2321 numPrimOut++; 2322 numIndicesOut += triIndices.size(); 2323 triIndices.clear(); 2324 } 2325} 2326 2327// This method retrieves data that is shared (or possibly shared) between different meshes. 2328// This adds an extra step to the copying of data from the memory buffer to the shape data buffer. 2329// If we have no parentMesh, then we either return a pointer to the data in the memory buffer 2330// (in the case that we skip this mesh) or copy the data into the shape data buffer and return 2331// that pointer (in the case that we don't skip this mesh). 2332// If we do have a parent mesh, then we return a pointer to the data in the shape buffer, 2333// copying the data in there ourselves if our parent didn't already do it (i.e., if it was skipped). 2334S32 * TSMesh::getSharedData32( S32 parentMesh, S32 size, S32 **source, bool skip ) 2335{ 2336 S32 * ptr; 2337 if( parentMesh < 0 ) 2338 ptr = skip ? tsalloc.getPointer32( size ) : tsalloc.copyToShape32( size ); 2339 else 2340 { 2341 ptr = source[parentMesh]; 2342 // if we skipped the previous mesh (and we're not skipping this one) then 2343 // we still need to copy points into the shape... 2344 if ( !smDataCopied[parentMesh] && !skip ) 2345 { 2346 S32 * tmp = ptr; 2347 ptr = tsalloc.allocShape32( size ); 2348 if ( ptr && tmp ) 2349 dMemcpy(ptr, tmp, size * sizeof(S32) ); 2350 } 2351 } 2352 return ptr; 2353} 2354 2355S8 * TSMesh::getSharedData8( S32 parentMesh, S32 size, S8 **source, bool skip ) 2356{ 2357 S8 * ptr; 2358 if( parentMesh < 0 ) 2359 ptr = skip ? tsalloc.getPointer8( size ) : tsalloc.copyToShape8( size ); 2360 else 2361 { 2362 ptr = source[parentMesh]; 2363 // if we skipped the previous mesh (and we're not skipping this one) then 2364 // we still need to copy points into the shape... 2365 if ( !smDataCopied[parentMesh] && !skip ) 2366 { 2367 S8 * tmp = ptr; 2368 ptr = tsalloc.allocShape8( size ); 2369 if ( ptr && tmp ) 2370 dMemcpy( ptr, tmp, size * sizeof(S32) ); 2371 } 2372 } 2373 return ptr; 2374} 2375 2376void TSMesh::dumpPrimitives(U32 startVertex, U32 startIndex, GFXPrimitive *piArray, U16* ibIndices) 2377{ 2378 // go through and create PrimitiveInfo array 2379 GFXPrimitive pInfo; 2380 2381 U32 primitivesSize = mPrimitives.size(); 2382 for (U32 i = 0; i < primitivesSize; i++) 2383 { 2384 const TSDrawPrimitive & draw = mPrimitives[i]; 2385 2386 GFXPrimitiveType drawType = getDrawType(draw.matIndex >> 30); 2387 2388 switch (drawType) 2389 { 2390 case GFXTriangleList: 2391 pInfo.type = drawType; 2392 pInfo.numPrimitives = draw.numElements / 3; 2393 pInfo.startIndex = startIndex + draw.start; 2394 // Use the first index to determine which 16-bit address space we are operating in 2395 pInfo.startVertex = (mIndices[draw.start] & 0xFFFF0000); // TODO: figure out a good solution for this 2396 pInfo.minIndex = 0; // minIndex are zero based index relative to startVertex. See @GFXDevice 2397 pInfo.numVertices = getMin((U32)0x10000, mNumVerts - pInfo.startVertex); 2398 pInfo.startVertex += startVertex; 2399 break; 2400 2401 case GFXTriangleStrip: 2402 pInfo.type = drawType; 2403 pInfo.numPrimitives = draw.numElements - 2; 2404 pInfo.startIndex = startIndex + draw.start; 2405 // Use the first index to determine which 16-bit address space we are operating in 2406 pInfo.startVertex = (mIndices[draw.start] & 0xFFFF0000); // TODO: figure out a good solution for this 2407 pInfo.minIndex = 0; // minIndex are zero based index relative to startVertex. See @GFXDevice 2408 pInfo.numVertices = getMin((U32)0x10000, mNumVerts - pInfo.startVertex); 2409 pInfo.startVertex += startVertex; 2410 break; 2411 2412 default: 2413 AssertFatal(false, "WTF?!"); 2414 } 2415 2416 *piArray++ = pInfo; 2417 } 2418 2419 dCopyArray(ibIndices, mIndices.address(), mIndices.size()); 2420} 2421 2422void TSMesh::assemble( bool skip ) 2423{ 2424 tsalloc.checkGuard(); 2425 2426 numFrames = tsalloc.get32(); 2427 numMatFrames = tsalloc.get32(); 2428 mParentMesh = tsalloc.get32(); 2429 tsalloc.get32( (S32*)&mBounds, 6 ); 2430 tsalloc.get32( (S32*)&mCenter, 3 ); 2431 mRadius = (F32)tsalloc.get32(); 2432 2433 if (TSShape::smReadVersion >= 27) 2434 { 2435 // Offsetted 2436 mVertOffset = tsalloc.get32(); 2437 mNumVerts = tsalloc.get32(); 2438 mVertSize = tsalloc.get32(); 2439 } 2440 else 2441 { 2442 mVertOffset = 0; 2443 mNumVerts = 0; 2444 mVertSize = 0; 2445 } 2446 2447 S32 numVerts = tsalloc.get32(); 2448 S32 *ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smVertsList.address(), skip ); 2449 mVerts.set( (Point3F*)ptr32, numVerts ); 2450 2451 S32 numTVerts = tsalloc.get32(); 2452 ptr32 = getSharedData32(mParentMesh, 2 * numTVerts, (S32**)smTVertsList.address(), skip ); 2453 mTverts.set( (Point2F*)ptr32, numTVerts ); 2454 2455 if ( TSShape::smReadVersion > 25 ) 2456 { 2457 numTVerts = tsalloc.get32(); 2458 ptr32 = getSharedData32(mParentMesh, 2 * numTVerts, (S32**)smTVerts2List.address(), skip ); 2459 mTverts2.set( (Point2F*)ptr32, numTVerts ); 2460 2461 S32 numVColors = tsalloc.get32(); 2462 ptr32 = getSharedData32(mParentMesh, numVColors, (S32**)smColorsList.address(), skip ); 2463 mColors.set( (ColorI*)ptr32, numVColors ); 2464 } 2465 2466 S8 *ptr8; 2467 if ( TSShape::smReadVersion > 21 && TSMesh::smUseEncodedNormals) 2468 { 2469 // we have encoded normals and we want to use them... 2470 if (mParentMesh < 0 ) 2471 tsalloc.getPointer32( numVerts * 3 ); // adva nce past norms, don't use 2472 mNorms.set( NULL, 0 ); 2473 2474 ptr8 = getSharedData8(mParentMesh, numVerts, (S8**)smEncodedNormsList.address(), skip ); 2475 mEncodedNorms.set( ptr8, numVerts ); 2476 } 2477 else if ( TSShape::smReadVersion > 21 ) 2478 { 2479 // we have encoded normals but we don't want to use them... 2480 ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip ); 2481 mNorms.set( (Point3F*)ptr32, numVerts ); 2482 2483 if (mParentMesh < 0 ) 2484 tsalloc.getPointer8( numVerts ); // advance past encoded normls, don't use 2485 mEncodedNorms.set( NULL, 0 ); 2486 } 2487 else 2488 { 2489 // no encoded normals... 2490 ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip ); 2491 mNorms.set( (Point3F*)ptr32, numVerts ); 2492 mEncodedNorms.set( NULL, 0 ); 2493 } 2494 2495 // copy the primitives and indices...how we do this depends on what 2496 // form we want them in when copied...just get pointers to data for now 2497 S32 szPrimIn, szIndIn; 2498 TSDrawPrimitive *primIn; 2499 S32 *indIn; 2500 bool deleteInputArrays = false; 2501 2502 if (TSShape::smReadVersion > 25) 2503 { 2504 // mesh primitives (start, numElements) and indices are stored as 32 bit values 2505 szPrimIn = tsalloc.get32(); 2506 primIn = (TSDrawPrimitive*)tsalloc.getPointer32(szPrimIn*3); 2507 szIndIn = tsalloc.get32(); 2508 indIn = tsalloc.getPointer32(szIndIn); 2509 } 2510 else 2511 { 2512 // mesh primitives (start, numElements) indices are stored as 16 bit values 2513 szPrimIn = tsalloc.get32(); 2514 S16 *prim16 = tsalloc.getPointer16(szPrimIn*2); // primitive: start, numElements 2515 S32 *prim32 = tsalloc.getPointer32(szPrimIn); // primitive: matIndex 2516 szIndIn = tsalloc.get32(); 2517 2518 // warn about non-addressable indices 2519 if ( !skip && szIndIn >= 0x10000 ) 2520 { 2521 Con::warnf("Mesh contains non-addressable indices, and may not render " 2522 "correctly. Either split this mesh into pieces of no more than 65k " 2523 "unique verts prior to export, or use COLLADA."); 2524 } 2525 2526 S16 *ind16 = tsalloc.getPointer16(szIndIn); 2527 2528 // need to copy to temporary arrays 2529 deleteInputArrays = true; 2530 primIn = new TSDrawPrimitive[szPrimIn]; 2531 for (S32 i = 0; i < szPrimIn; i++) 2532 { 2533 primIn[i].start = prim16[i*2]; 2534 primIn[i].numElements = prim16[i*2+1]; 2535 primIn[i].matIndex = prim32[i]; 2536 } 2537 2538 indIn = new S32[szIndIn]; 2539 dCopyArray(indIn, ind16, szIndIn); 2540 } 2541 2542 // count the number of output primitives and indices 2543 S32 szPrimOut = szPrimIn, szIndOut = szIndIn; 2544 if (smUseTriangles) 2545 convertToTris(primIn, indIn, szPrimIn, szPrimOut, szIndOut, NULL, NULL); 2546 else if (smUseOneStrip) 2547 convertToSingleStrip(primIn, indIn, szPrimIn, szPrimOut, szIndOut, NULL, NULL); 2548 else 2549 leaveAsMultipleStrips(primIn, indIn, szPrimIn, szPrimOut, szIndOut, NULL, NULL); 2550 2551 // allocate enough space for the new primitives and indices (all 32 bits) 2552 TSDrawPrimitive *primOut = (TSDrawPrimitive*)tsalloc.allocShape32(3*szPrimOut); 2553 S32 *indOut = tsalloc.allocShape32(szIndOut); 2554 2555 // copy output primitives and indices 2556 S32 chkPrim = szPrimOut, chkInd = szIndOut; 2557 if (smUseTriangles) 2558 convertToTris(primIn, indIn, szPrimIn, chkPrim, chkInd, primOut, indOut); 2559 else if (smUseOneStrip) 2560 convertToSingleStrip(primIn, indIn, szPrimIn, chkPrim, chkInd, primOut, indOut); 2561 else 2562 leaveAsMultipleStrips(primIn, indIn, szPrimIn, chkPrim, chkInd, primOut, indOut); 2563 AssertFatal(chkPrim==szPrimOut && chkInd==szIndOut,"TSMesh::primitive conversion"); 2564 2565 // store output 2566 mPrimitives.set(primOut, szPrimOut); 2567 mIndices.set(indOut, szIndOut); 2568 2569 // delete temporary arrays if necessary 2570 if (deleteInputArrays) 2571 { 2572 delete [] primIn; 2573 delete [] indIn; 2574 } 2575 2576 S32 sz = tsalloc.get32(); 2577 tsalloc.getPointer16( sz ); // skip deprecated merge indices 2578 tsalloc.align32(); 2579 2580 vertsPerFrame = tsalloc.get32(); 2581 U32 flags = (U32)tsalloc.get32(); 2582 if ( mEncodedNorms.size() ) 2583 flags |= UseEncodedNormals; 2584 2585 setFlags( flags ); 2586 2587 // Set color & tvert2 flags if we have an old version 2588 if (TSShape::smReadVersion < 27) 2589 { 2590 if (mColors.size() > 0) setFlags(HasColor); 2591 if (mTverts2.size() > 0) setFlags(HasTVert2); 2592 mNumVerts = mVerts.size(); 2593 } 2594 2595 tsalloc.checkGuard(); 2596 2597 if ( tsalloc.allocShape32( 0 ) && TSShape::smReadVersion < 19 ) 2598 computeBounds(); // only do this if we copied the data... 2599 2600 createTangents(mVerts, mNorms); 2601} 2602 2603void TSMesh::disassemble() 2604{ 2605 tsalloc.setGuard(); 2606 2607 tsalloc.set32( numFrames ); 2608 tsalloc.set32( numMatFrames ); 2609 tsalloc.set32(mParentMesh); 2610 tsalloc.copyToBuffer32( (S32*)&mBounds, 6 ); 2611 tsalloc.copyToBuffer32( (S32*)&mCenter, 3 ); 2612 tsalloc.set32( (S32)mRadius ); 2613 2614 bool shouldMakeEditable = TSShape::smVersion < 27 || mVertSize == 0; 2615 2616 // Re-create the vectors 2617 if (shouldMakeEditable) 2618 { 2619 makeEditable(); 2620 2621 // No Offset 2622 if (TSShape::smVersion >= 27) 2623 { 2624 tsalloc.set32(0); 2625 tsalloc.set32(0); 2626 tsalloc.set32(0); 2627 } 2628 } 2629 else 2630 { 2631 // Offsetted 2632 tsalloc.set32(mVertOffset); 2633 tsalloc.set32(mNumVerts); 2634 tsalloc.set32(mVertSize); 2635 AssertFatal(mNumVerts >= vertsPerFrame, "invalid mNumVerts"); 2636 } 2637 2638 if (TSShape::smVersion >= 27 && mVertexData.isReady()) 2639 { 2640 // If not editable all arrays are effectively 0. 2641 tsalloc.set32(0); // verts 2642 tsalloc.set32(0); // tverts 2643 tsalloc.set32(0); // tverts2 2644 tsalloc.set32(0); // colors 2645 } 2646 else 2647 { 2648 // verts... 2649 tsalloc.set32(mVerts.size()); 2650 if (mParentMesh < 0) 2651 tsalloc.copyToBuffer32((S32*)mVerts.address(), 3 * mVerts.size()); // if no parent mesh, then save off our verts 2652 2653 // tverts... 2654 tsalloc.set32(mTverts.size()); 2655 if (mParentMesh < 0) 2656 tsalloc.copyToBuffer32((S32*)mTverts.address(), 2 * mTverts.size()); // if no parent mesh, then save off our tverts 2657 2658 if (TSShape::smVersion > 25) 2659 { 2660 // tverts2... 2661 tsalloc.set32(mTverts2.size()); 2662 if (mParentMesh < 0) 2663 tsalloc.copyToBuffer32((S32*)mTverts2.address(), 2 * mTverts2.size()); // if no parent mesh, then save off our tverts 2664 2665 // colors 2666 tsalloc.set32(mColors.size()); 2667 if (mParentMesh < 0) 2668 tsalloc.copyToBuffer32((S32*)mColors.address(), mColors.size()); // if no parent mesh, then save off our tverts 2669 } 2670 2671 // norms... 2672 if (mParentMesh < 0) // if no parent mesh, then save off our norms 2673 tsalloc.copyToBuffer32((S32*)mNorms.address(), 3 * mNorms.size()); // norms.size()==verts.size() or error... 2674 2675 // encoded norms... 2676 if (mParentMesh < 0) 2677 { 2678 // if no parent mesh, compute encoded normals and copy over 2679 for (S32 i = 0; i < mNorms.size(); i++) 2680 { 2681 U8 normIdx = mEncodedNorms.size() ? mEncodedNorms[i] : encodeNormal(mNorms[i]); 2682 tsalloc.copyToBuffer8((S8*)&normIdx, 1); 2683 } 2684 } 2685 } 2686 2687 // optimize triangle draw order during disassemble 2688 { 2689 FrameTemp<TriListOpt::IndexType> tmpIdxs(mIndices.size()); 2690 for ( S32 i = 0; i < mPrimitives.size(); i++ ) 2691 { 2692 const TSDrawPrimitive& prim = mPrimitives[i]; 2693 2694 // only optimize triangle lists (strips and fans are assumed to be already optimized) 2695 if ( (prim.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles ) 2696 { 2697 TriListOpt::OptimizeTriangleOrdering(mVerts.size(), prim.numElements, 2698 mIndices.address() + prim.start, tmpIdxs.address()); 2699 dCopyArray(mIndices.address() + prim.start, tmpIdxs.address(), 2700 prim.numElements); 2701 } 2702 } 2703 } 2704 2705 if (TSShape::smVersion > 25) 2706 { 2707 // primitives... 2708 tsalloc.set32(mPrimitives.size() ); 2709 tsalloc.copyToBuffer32((S32*)mPrimitives.address(),3* mPrimitives.size()); 2710 2711 // indices... 2712 tsalloc.set32(mIndices.size()); 2713 tsalloc.copyToBuffer32((S32*)mIndices.address(),mIndices.size()); 2714 } 2715 else 2716 { 2717 // primitives 2718 tsalloc.set32(mPrimitives.size() ); 2719 for (S32 i=0; i<mPrimitives.size(); i++) 2720 { 2721 S16 start = (S16)mPrimitives[i].start; 2722 S16 numElements = (S16)mPrimitives[i].numElements; 2723 2724 tsalloc.copyToBuffer16(&start, 1); 2725 tsalloc.copyToBuffer16(&numElements, 1); 2726 tsalloc.copyToBuffer32(&(mPrimitives[i].matIndex), 1); 2727 } 2728 2729 // indices 2730 tsalloc.set32(mIndices.size()); 2731 Vector<S16> s16_indices(mIndices.size()); 2732 for (S32 i=0; i<mIndices.size(); i++) 2733 s16_indices.push_back((S16)mIndices[i]); 2734 tsalloc.copyToBuffer16(s16_indices.address(), s16_indices.size()); 2735 } 2736 2737 // merge indices...DEPRECATED 2738 tsalloc.set32( 0 ); 2739 2740 // small stuff... 2741 tsalloc.set32( vertsPerFrame ); 2742 tsalloc.set32( getFlags() ); 2743 2744 tsalloc.setGuard(); 2745} 2746 2747//----------------------------------------------------------------------------- 2748// TSSkinMesh assemble from/ dissemble to memory buffer 2749//----------------------------------------------------------------------------- 2750void TSSkinMesh::assemble( bool skip ) 2751{ 2752 // avoid a crash on computeBounds... 2753 batchData.initialVerts.set( NULL, 0 ); 2754 2755 TSMesh::assemble( skip ); 2756 2757 if (TSShape::smReadVersion >= 27) 2758 { 2759 maxBones = tsalloc.get32(); 2760 } 2761 else 2762 { 2763 maxBones = -1; 2764 } 2765 2766 S32 sz; 2767 S32 * ptr32; 2768 2769 if (TSShape::smReadVersion < 27) 2770 { 2771 sz = tsalloc.get32(); 2772 S32 numVerts = sz; 2773 ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smVertsList.address(), skip); 2774 batchData.initialVerts.set((Point3F*)ptr32, sz); 2775 2776 S8 * ptr8; 2777 if (TSShape::smReadVersion > 21 && TSMesh::smUseEncodedNormals) 2778 { 2779 // we have encoded normals and we want to use them... 2780 if (mParentMesh < 0) 2781 tsalloc.getPointer32(numVerts * 3); // advance past norms, don't use 2782 batchData.initialNorms.set(NULL, 0); 2783 2784 ptr8 = getSharedData8(mParentMesh, numVerts, (S8**)smEncodedNormsList.address(), skip); 2785 mEncodedNorms.set(ptr8, numVerts); 2786 // Note: we don't set the encoded normals flag because we handle them in updateSkin and 2787 // hide the fact that we are using them from base class (TSMesh) 2788 } 2789 else if (TSShape::smReadVersion > 21) 2790 { 2791 // we have encoded normals but we don't want to use them... 2792 ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip); 2793 batchData.initialNorms.set((Point3F*)ptr32, numVerts); 2794 2795 if (mParentMesh < 0) 2796 tsalloc.getPointer8(numVerts); // advance past encoded normls, don't use 2797 2798 mEncodedNorms.set(NULL, 0); 2799 } 2800 else 2801 { 2802 // no encoded normals... 2803 ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip); 2804 batchData.initialNorms.set((Point3F*)ptr32, numVerts); 2805 mEncodedNorms.set(NULL, 0); 2806 } 2807 2808 // Sometimes we'll have a mesh with 0 verts but initialVerts is set, 2809 // so set these accordingly 2810 if (mVerts.size() == 0) 2811 { 2812 mVerts = batchData.initialVerts; 2813 } 2814 2815 if (mNorms.size() == 0) 2816 { 2817 mNorms = batchData.initialNorms; 2818 } 2819 } 2820 else 2821 { 2822 // Set from the mesh data 2823 batchData.initialVerts = mVerts; 2824 batchData.initialNorms = mNorms; 2825 } 2826 2827 sz = tsalloc.get32(); 2828 ptr32 = getSharedData32(mParentMesh, 16 * sz, (S32**)smInitTransformList.address(), skip ); 2829 batchData.initialTransforms.set( ptr32, sz ); 2830 2831 sz = tsalloc.get32(); 2832 ptr32 = getSharedData32(mParentMesh, sz, (S32**)smVertexIndexList.address(), skip ); 2833 vertexIndex.set( ptr32, sz ); 2834 2835 ptr32 = getSharedData32(mParentMesh, sz, (S32**)smBoneIndexList.address(), skip ); 2836 boneIndex.set( ptr32, sz ); 2837 2838 ptr32 = getSharedData32(mParentMesh, sz, (S32**)smWeightList.address(), skip ); 2839 weight.set( (F32*)ptr32, sz ); 2840 2841 sz = tsalloc.get32(); 2842 ptr32 = getSharedData32(mParentMesh, sz, (S32**)smNodeIndexList.address(), skip ); 2843 batchData.nodeIndex.set( ptr32, sz ); 2844 2845 tsalloc.checkGuard(); 2846 2847 if (smDebugSkinVerts && ptr32 != NULL) 2848 { 2849 Con::printf("Loaded skin verts..."); 2850 for (U32 i = 0; i < vertexIndex.size(); i++) 2851 { 2852 Con::printf("vi[%i] == %i", i, vertexIndex[i]); 2853 } 2854 for (U32 i = 0; i < boneIndex.size(); i++) 2855 { 2856 Con::printf("bi[%i] == %i", i, boneIndex[i]); 2857 } 2858 for (U32 i = 0; i < batchData.nodeIndex.size(); i++) 2859 { 2860 Con::printf("ni[%i] == %i", i, batchData.nodeIndex[i]); 2861 } 2862 for (U32 i = 0; i < boneIndex.size(); i++) 2863 { 2864 Con::printf("we[%i] == %f", i, weight[i]); 2865 } 2866 2867 if (mNumVerts != 0) 2868 { 2869 AssertFatal(batchData.initialVerts.size() == mNumVerts, "err WTF"); 2870 } 2871 2872 Con::printf("---"); 2873 } 2874 2875 if ( tsalloc.allocShape32( 0 ) && TSShape::smReadVersion < 19 ) 2876 TSMesh::computeBounds(); // only do this if we copied the data...c 2877} 2878 2879//----------------------------------------------------------------------------- 2880// disassemble 2881//----------------------------------------------------------------------------- 2882void TSSkinMesh::disassemble() 2883{ 2884 TSMesh::disassemble(); 2885 2886 if (TSShape::smVersion >= 27) 2887 { 2888 AssertFatal(maxBones != 0, "Skin mesh with no bones? No way!"); 2889 tsalloc.set32(maxBones); 2890 } 2891 2892 if (TSShape::smVersion < 27) 2893 { 2894 tsalloc.set32(batchData.initialVerts.size()); 2895 // if we have no parent mesh, then save off our verts & norms 2896 if (mParentMesh < 0) 2897 { 2898 tsalloc.copyToBuffer32((S32*)mVerts.address(), 3 * mVerts.size()); 2899 2900 // no longer do this here...let tsmesh handle this 2901 tsalloc.copyToBuffer32((S32*)mNorms.address(), 3 * mNorms.size()); 2902 2903 // if no parent mesh, compute encoded normals and copy over 2904 for (S32 i = 0; i < mNorms.size(); i++) 2905 { 2906 U8 normIdx = mEncodedNorms.size() ? mEncodedNorms[i] : encodeNormal(mNorms[i]); 2907 tsalloc.copyToBuffer8((S8*)&normIdx, 1); 2908 } 2909 } 2910 } 2911 2912 tsalloc.set32( batchData.initialTransforms.size() ); 2913 if (mParentMesh < 0 ) 2914 tsalloc.copyToBuffer32( (S32*)batchData.initialTransforms.address(), batchData.initialTransforms.size() * 16 ); 2915 2916 if (!mVertexData.isReady()) 2917 { 2918 tsalloc.set32(vertexIndex.size()); 2919 2920 tsalloc.copyToBuffer32((S32*)vertexIndex.address(), vertexIndex.size()); 2921 2922 tsalloc.copyToBuffer32((S32*)boneIndex.address(), boneIndex.size()); 2923 2924 tsalloc.copyToBuffer32((S32*)weight.address(), weight.size()); 2925 } 2926 else 2927 { 2928 tsalloc.set32(0); 2929 } 2930 2931 if (TSShape::smVersion < 27) 2932 { 2933 if (mParentMesh < 0) 2934 { 2935 tsalloc.copyToBuffer32((S32*)vertexIndex.address(), vertexIndex.size()); 2936 2937 tsalloc.copyToBuffer32((S32*)boneIndex.address(), boneIndex.size()); 2938 2939 tsalloc.copyToBuffer32((S32*)weight.address(), weight.size()); 2940 } 2941 } 2942 2943 tsalloc.set32( batchData.nodeIndex.size() ); 2944 if (mParentMesh < 0 ) 2945 tsalloc.copyToBuffer32( (S32*)batchData.nodeIndex.address(), batchData.nodeIndex.size() ); 2946 2947 tsalloc.setGuard(); 2948} 2949 2950TSSkinMesh::TSSkinMesh() 2951{ 2952 mMeshType = SkinMeshType; 2953 batchData.initialized = false; 2954 maxBones = -1; 2955} 2956 2957//----------------------------------------------------------------------------- 2958// find tangent vector 2959//----------------------------------------------------------------------------- 2960inline void TSMesh::findTangent( U32 index1, 2961 U32 index2, 2962 U32 index3, 2963 Point3F *tan0, 2964 Point3F *tan1, 2965 const Vector<Point3F> &_verts) 2966{ 2967 const Point3F &v1 = _verts[index1]; 2968 const Point3F &v2 = _verts[index2]; 2969 const Point3F &v3 = _verts[index3]; 2970 2971 const Point2F &w1 = mTverts[index1]; 2972 const Point2F &w2 = mTverts[index2]; 2973 const Point2F &w3 = mTverts[index3]; 2974 2975 F32 x1 = v2.x - v1.x; 2976 F32 x2 = v3.x - v1.x; 2977 F32 y1 = v2.y - v1.y; 2978 F32 y2 = v3.y - v1.y; 2979 F32 z1 = v2.z - v1.z; 2980 F32 z2 = v3.z - v1.z; 2981 2982 F32 s1 = w2.x - w1.x; 2983 F32 s2 = w3.x - w1.x; 2984 F32 t1 = w2.y - w1.y; 2985 F32 t2 = w3.y - w1.y; 2986 2987 F32 denom = (s1 * t2 - s2 * t1); 2988 2989 if( mFabs( denom ) < 0.0001f ) 2990 { 2991 // handle degenerate triangles from strips 2992 if (denom<0) denom = -0.0001f; 2993 else denom = 0.0001f; 2994 } 2995 F32 r = 1.0f / denom; 2996 2997 Point3F sdir( (t2 * x1 - t1 * x2) * r, 2998 (t2 * y1 - t1 * y2) * r, 2999 (t2 * z1 - t1 * z2) * r ); 3000 3001 Point3F tdir( (s1 * x2 - s2 * x1) * r, 3002 (s1 * y2 - s2 * y1) * r, 3003 (s1 * z2 - s2 * z1) * r ); 3004 3005 3006 tan0[index1] += sdir; 3007 tan1[index1] += tdir; 3008 3009 tan0[index2] += sdir; 3010 tan1[index2] += tdir; 3011 3012 tan0[index3] += sdir; 3013 tan1[index3] += tdir; 3014} 3015 3016//----------------------------------------------------------------------------- 3017// create array of tangent vectors 3018//----------------------------------------------------------------------------- 3019void TSMesh::createTangents(const Vector<Point3F> &_verts, const Vector<Point3F> &_norms) 3020{ 3021 if (_verts.size() == 0) // can only be done in editable mode 3022 return; 3023 3024 U32 numVerts = _verts.size(); 3025 U32 numNorms = _norms.size(); 3026 if ( numVerts <= 0 || numNorms <= 0 ) 3027 return; 3028 3029 if( numVerts != numNorms) 3030 return; 3031 3032 Vector<Point3F> tan0; 3033 tan0.setSize( numVerts * 2 ); 3034 3035 Point3F *tan1 = tan0.address() + numVerts; 3036 dMemset( tan0.address(), 0, sizeof(Point3F) * 2 * numVerts ); 3037 3038 U32 numPrimatives = mPrimitives.size(); 3039 3040 for (S32 i = 0; i < numPrimatives; i++ ) 3041 { 3042 const TSDrawPrimitive & draw = mPrimitives[i]; 3043 GFXPrimitiveType drawType = getDrawType( draw.matIndex >> 30 ); 3044 3045 U32 p1Index = 0; 3046 U32 p2Index = 0; 3047 3048 U32 *baseIdx = &mIndices[draw.start]; 3049 3050 const U32 numElements = (U32)draw.numElements; 3051 3052 switch( drawType ) 3053 { 3054 case GFXTriangleList: 3055 { 3056 for( U32 j = 0; j < numElements; j += 3 ) 3057 findTangent( baseIdx[j], baseIdx[j + 1], baseIdx[j + 2], tan0.address(), tan1, _verts ); 3058 break; 3059 } 3060 3061 case GFXTriangleStrip: 3062 { 3063 p1Index = baseIdx[0]; 3064 p2Index = baseIdx[1]; 3065 for( U32 j = 2; j < numElements; j++ ) 3066 { 3067 findTangent( p1Index, p2Index, baseIdx[j], tan0.address(), tan1, _verts ); 3068 p1Index = p2Index; 3069 p2Index = baseIdx[j]; 3070 } 3071 break; 3072 } 3073 3074 default: 3075 AssertFatal( false, "TSMesh::createTangents: unknown primitive type!" ); 3076 } 3077 } 3078 3079 mTangents.setSize( numVerts ); 3080 3081 // fill out final info from accumulated basis data 3082 for( U32 i = 0; i < numVerts; i++ ) 3083 { 3084 const Point3F &n = _norms[i]; 3085 const Point3F &t = tan0[i]; 3086 const Point3F &b = tan1[i]; 3087 3088 Point3F tempPt = t - n * mDot( n, t ); 3089 tempPt.normalize(); 3090 mTangents[i] = tempPt; 3091 3092 Point3F cp; 3093 mCross( n, t, &cp ); 3094 3095 mTangents[i].w = (mDot( cp, b ) < 0.0f) ? -1.0f : 1.0f; 3096 } 3097} 3098 3099void TSMesh::convertToVertexData() 3100{ 3101 if (!mVertexData.isReady()) 3102 { 3103 _convertToVertexData(mVertexData, mVerts, mNorms); 3104 } 3105} 3106 3107void TSSkinMesh::convertToVertexData() 3108{ 3109 if (!mVertexData.isReady()) 3110 { 3111 // Batch data required here 3112 createSkinBatchData(); 3113 3114 // Dump verts to buffer 3115 _convertToVertexData(mVertexData, batchData.initialVerts, batchData.initialNorms); 3116 3117 // Setup bones too 3118 setupVertexTransforms(); 3119 } 3120} 3121 3122void TSMesh::copySourceVertexDataFrom(const TSMesh* srcMesh) 3123{ 3124 mVerts = srcMesh->mVerts; 3125 mTverts = srcMesh->mTverts; 3126 mNorms = srcMesh->mNorms; 3127 mColors = srcMesh->mColors; 3128 mTverts2 = srcMesh->mTverts2; 3129 3130 if (mVerts.size() == 0) 3131 { 3132 bool hasTVert2 = srcMesh->getHasTVert2(); 3133 bool hasColor = srcMesh->getHasColor(); 3134 3135 mVerts.setSize(srcMesh->mNumVerts); 3136 mTverts.setSize(srcMesh->mNumVerts); 3137 mNorms.setSize(srcMesh->mNumVerts); 3138 3139 if (hasColor) 3140 mColors.setSize(mNumVerts); 3141 if (hasTVert2) 3142 mTverts2.setSize(mNumVerts); 3143 3144 // Fill arrays 3145 for (U32 i = 0; i < mNumVerts; i++) 3146 { 3147 const __TSMeshVertexBase &cv = srcMesh->mVertexData.getBase(i); 3148 const __TSMeshVertex_3xUVColor &cvc = srcMesh->mVertexData.getColor(i); 3149 mVerts[i] = cv.vert(); 3150 mTverts[i] = cv.tvert(); 3151 mNorms[i] = cv.normal(); 3152 3153 if (hasColor) 3154 cvc.color().getColor(&mColors[i]); 3155 if (hasTVert2) 3156 mTverts2[i] = cvc.tvert2(); 3157 } 3158 } 3159} 3160 3161void TSSkinMesh::copySourceVertexDataFrom(const TSMesh* srcMesh) 3162{ 3163 TSMesh::copySourceVertexDataFrom(srcMesh); 3164 3165 if (srcMesh->getMeshType() == TSMesh::SkinMeshType) 3166 { 3167 const TSSkinMesh* srcSkinMesh = static_cast<const TSSkinMesh*>(srcMesh); 3168 3169 weight = srcSkinMesh->weight; 3170 boneIndex = srcSkinMesh->boneIndex; 3171 vertexIndex = srcSkinMesh->vertexIndex; 3172 maxBones = srcSkinMesh->maxBones; 3173 3174 // Extract from vertex data 3175 if (srcSkinMesh->vertexIndex.size() == 0) 3176 { 3177 mVertexData = srcMesh->mVertexData; 3178 addWeightsFromVertexBuffer(); 3179 mVertexData.setReady(false); 3180 } 3181 } 3182} 3183 3184U32 TSMesh::getNumVerts() 3185{ 3186 return mVertexData.isReady() ? mNumVerts : mVerts.size(); 3187} 3188 3189void TSMesh::_convertToVertexData(TSMeshVertexArray &outArray, const Vector<Point3F> &_verts, const Vector<Point3F> &_norms) 3190{ 3191 // Update tangents list 3192 createTangents(mVerts, mNorms); 3193 3194 AssertFatal(_verts.size() == mNumVerts, "vert count mismatch"); 3195 AssertFatal(!getHasColor() || mColors.size() == _verts.size(), "Vector of color elements should be the same size as other vectors"); 3196 AssertFatal(!getHasTVert2() || mTverts2.size() == _verts.size(), "Vector of tvert2 elements should be the same size as other vectors"); 3197 3198 AssertFatal(!outArray.isReady(), "Mesh already converted to aligned data! Re-check code!"); 3199 AssertFatal(_verts.size() == _norms.size() && 3200 _verts.size() == mTangents.size(), 3201 "Vectors: verts, norms, tangents must all be the same size"); 3202 AssertFatal(mVertSize == outArray.vertSize(), "Size inconsistency"); 3203 3204 if (mNumVerts == 0) 3205 return; 3206 3207 bool needWeightSet = outArray.getBoneOffset() != 0; 3208 3209 bool hasColor = getHasColor(); 3210 bool hasTVert2 = getHasTVert2(); 3211 3212 dMemset(&outArray.getBase(0), '\0', mVertSize * mNumVerts); 3213 3214 for (U32 i = 0; i < mNumVerts; i++) 3215 { 3216 __TSMeshVertexBase &v = outArray.getBase(i); 3217 v.vert(_verts[i]); 3218 v.normal(_norms[i]); 3219 v.tangent(mTangents[i]); 3220 3221 if (i < mTverts.size()) 3222 v.tvert(mTverts[i]); 3223 3224 if (hasTVert2 || hasColor) 3225 { 3226 __TSMeshVertex_3xUVColor &vc = outArray.getColor(i); 3227 if (hasTVert2 && i < mTverts2.size()) 3228 vc.tvert2(mTverts2[i]); 3229 if (hasColor && i < mColors.size()) 3230 vc.color(mColors[i]); 3231 } 3232 3233 // NOTE: skin verts are set later on for the skinned mesh, otherwise we'll set the default (i.e. 0) if we need one for a rigid mesh 3234 if (needWeightSet) 3235 { 3236 const Point4F wt(1.0f, 0.0f, 0.0f, 0.0f); 3237 outArray.getBone(i, 0).weight(wt); 3238 } 3239 } 3240} 3241 3242void TSMesh::makeEditable() 3243{ 3244 bool hasVerts = mVerts.size() != 0; 3245 3246 if(mVertexData.isReady() && !hasVerts) 3247 { 3248 copySourceVertexDataFrom(this); 3249 } 3250 3251 mVertexData.setReady(false); 3252 3253 mVertSize = 0; 3254 mNumVerts = 0; 3255 mVertOffset = 0; 3256 3257 updateMeshFlags(); 3258} 3259 3260void TSSkinMesh::addWeightsFromVertexBuffer() 3261{ 3262 weight.setSize(0); 3263 boneIndex.setSize(0); 3264 vertexIndex.setSize(0); 3265 3266 U32 numBoneBlocks = maxBones >= 0 ? (maxBones + 3) / 4 : 0; 3267 for (U32 i = 0; i < mNumVerts; i++) 3268 { 3269 for (U32 j = 0; j < numBoneBlocks; j++) 3270 { 3271 const __TSMeshVertex_BoneData &cv = mVertexData.getBone(i, j); 3272 3273 if (cv._weights.x != 0.0f) 3274 { 3275 addWeightForVert(i, cv._indexes.x, cv._weights.x); 3276 } 3277 if (cv._weights.y != 0.0f) 3278 { 3279 addWeightForVert(i, cv._indexes.y, cv._weights.y); 3280 } 3281 if (cv._weights.z != 0.0f) 3282 { 3283 addWeightForVert(i, cv._indexes.z, cv._weights.z); 3284 } 3285 if (cv._weights.w != 0.0f) 3286 { 3287 addWeightForVert(i, cv._indexes.w, cv._weights.w); 3288 } 3289 } 3290 } 3291} 3292 3293void TSSkinMesh::makeEditable() 3294{ 3295 bool hasVerts = mVerts.size() != 0; 3296 3297 // Reconstruct bone mapping 3298 if (mVertexData.isReady() && !hasVerts) 3299 { 3300 copySourceVertexDataFrom(this); 3301 3302 weight.setSize(0); 3303 boneIndex.setSize(0); 3304 vertexIndex.setSize(0); 3305 3306 addWeightsFromVertexBuffer(); 3307 } 3308 3309 mVertexData.setReady(false); 3310 3311 mVertSize = 0; 3312 mNumVerts = 0; 3313 3314 updateMeshFlags(); 3315 batchData.initialized = false; 3316} 3317 3318void TSMesh::clearEditable() 3319{ 3320 if (mVerts.size() == 0) 3321 return; 3322 3323 if (mColors.empty()) 3324 clearFlags(HasColor); 3325 else 3326 setFlags(HasColor); 3327 3328 if (mTverts2.empty()) 3329 clearFlags(HasTVert2); 3330 else 3331 setFlags(HasTVert2); 3332 3333 mVerts.free_memory(); 3334 mNorms.free_memory(); 3335 mTangents.free_memory(); 3336 mTverts.free_memory(); 3337 mTverts2.free_memory(); 3338 mColors.free_memory(); 3339} 3340 3341void TSMesh::updateMeshFlags() 3342{ 3343 // Make sure flags are correct 3344 if (mColors.empty()) 3345 clearFlags(HasColor); 3346 else 3347 setFlags(HasColor); 3348 3349 if (mTverts2.empty()) 3350 clearFlags(HasTVert2); 3351 else 3352 setFlags(HasTVert2); 3353} 3354 3355void TSSkinMesh::clearEditable() 3356{ 3357 TSMesh::clearEditable(); 3358 3359 weight.free_memory(); 3360 boneIndex.free_memory(); 3361 vertexIndex.free_memory(); 3362} 3363 3364TSBasicVertexFormat::TSBasicVertexFormat() : 3365 texCoordOffset(-1), 3366 boneOffset(-1), 3367 colorOffset(-1), 3368 numBones(0), 3369 vertexSize(-1) 3370{ 3371} 3372 3373TSBasicVertexFormat::TSBasicVertexFormat(TSMesh *mesh) 3374{ 3375 texCoordOffset = -1; 3376 boneOffset = -1; 3377 colorOffset = -1; 3378 numBones = 0; 3379 vertexSize = -1; 3380 3381 addMeshRequirements(mesh); 3382} 3383 3384void TSBasicVertexFormat::getFormat(GFXVertexFormat &fmt) 3385{ 3386 // NOTE: previously the vertex data was padded to allow for verts to be skinned via SSE. 3387 // since we now prefer to skin on the GPU and use a basic non-SSE fallback for software 3388 // skinning, adding in padding via GFXSemantic::PADDING or dummy fields is no longer required. 3389 fmt.addElement(GFXSemantic::POSITION, GFXDeclType_Float3); 3390 fmt.addElement(GFXSemantic::TANGENTW, GFXDeclType_Float, 3); 3391 fmt.addElement(GFXSemantic::NORMAL, GFXDeclType_Float3); 3392 fmt.addElement(GFXSemantic::TANGENT, GFXDeclType_Float3); 3393 3394 fmt.addElement(GFXSemantic::TEXCOORD, GFXDeclType_Float2, 0); 3395 3396 if (texCoordOffset >= 0 || colorOffset >= 0) 3397 { 3398 fmt.addElement(GFXSemantic::TEXCOORD, GFXDeclType_Float2, 1); 3399 fmt.addElement(GFXSemantic::COLOR, GFXDeclType_Color); 3400 } 3401 3402 for (U32 i=0; i<numBones; i++) 3403 { 3404 fmt.addElement(GFXSemantic::BLENDINDICES, GFXDeclType_UByte4, i); 3405 fmt.addElement(GFXSemantic::BLENDWEIGHT, GFXDeclType_Float4, i); 3406 } 3407} 3408 3409void TSBasicVertexFormat::calculateSize() 3410{ 3411 GFXVertexFormat fmt; 3412 vertexSize = 0; 3413 getFormat(fmt); 3414 vertexSize = fmt.getSizeInBytes(); 3415} 3416 3417void TSBasicVertexFormat::writeAlloc(TSShapeAlloc* alloc) 3418{ 3419 alloc->set16(texCoordOffset); 3420 alloc->set16(boneOffset); 3421 alloc->set16(colorOffset); 3422 alloc->set16(numBones); 3423 alloc->set16(vertexSize); 3424} 3425 3426void TSBasicVertexFormat::readAlloc(TSShapeAlloc* alloc) 3427{ 3428 texCoordOffset = alloc->get16(); 3429 boneOffset = alloc->get16(); 3430 colorOffset = alloc->get16(); 3431 numBones = alloc->get16(); 3432 vertexSize = alloc->get16(); 3433} 3434 3435void TSBasicVertexFormat::addMeshRequirements(TSMesh *mesh) 3436{ 3437 bool hasColors = false; 3438 bool hasTexcoord2 = false; 3439 bool hasSkin = false; 3440 3441 hasColors = mesh->getHasColor() || (colorOffset != -1); 3442 hasTexcoord2 = mesh->getHasTVert2() || (texCoordOffset != -1); 3443 hasSkin = (mesh->getMeshType() == TSMesh::SkinMeshType) || (boneOffset != -1); 3444 3445 S32 offset = sizeof(TSMesh::__TSMeshVertexBase); 3446 3447 if ((hasTexcoord2 || hasColors)) 3448 { 3449 if (texCoordOffset == -1 || colorOffset == -1) 3450 { 3451 texCoordOffset = offset; 3452 colorOffset = offset + (sizeof(float) * 2); 3453 } 3454 3455 offset += sizeof(TSMesh::__TSMeshVertex_3xUVColor); 3456 } 3457 3458 if (hasSkin) 3459 { 3460 boneOffset = offset; 3461 3462 U32 numMeshBones = mesh->getMaxBonesPerVert(); 3463 U32 boneBlocks = numMeshBones / 4; 3464 U32 extraBlocks = numMeshBones % 4 != 0 ? 1 : 0; 3465 U32 neededBones = boneBlocks + extraBlocks; 3466 numBones = MAX(neededBones, numBones); 3467 } 3468} 3469 3470void TSSkinMesh::printVerts() 3471{ 3472 for (U32 i = 0; i < mNumVerts; i++) 3473 { 3474 TSMesh::__TSMeshVertexBase &vb = mVertexData.getBase(i); 3475 TSMesh::__TSMeshVertex_BoneData &bw = mVertexData.getBone(i, 0); 3476 3477 Point3F vert = batchData.initialVerts[i]; 3478 Con::printf("v[%i] == %f,%f,%f; iv == %f,%f,%f. bo=%i,%i,%i,%i bw=%f,%f,%f,%f", 3479 i, vb._vert.x, vb._vert.y, vb._vert.z, 3480 vert.x, vert.y, vert.z, 3481 bw._indexes.x, bw._indexes.y, bw._indexes.z, bw._indexes.w, 3482 bw._weights.x, bw._weights.y, bw._weights.z, bw._weights.w); 3483 } 3484} 3485