| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483 | //-----------------------------------------------------------------------------// Copyright (c) 2012 GarageGames, LLC//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS// IN THE SOFTWARE.//-----------------------------------------------------------------------------#include "platform/platform.h"#include "ts/tsMesh.h"#include "ts/tsMeshIntrinsics.h"#include "ts/tsDecal.h"#include "ts/tsSortedMesh.h"#include "ts/tsShape.h"#include "ts/tsShapeInstance.h"#include "ts/tsRenderState.h"#include "ts/tsMaterialList.h"#include "ts/instancingMatHook.h"#include "math/mMath.h"#include "math/mathIO.h"#include "math/mathUtils.h"#include "console/console.h"#include "scene/sceneObject.h"#include "core/bitRender.h"#include "collision/convex.h"#include "collision/optimizedPolyList.h"#include "core/frameAllocator.h"#include "platform/profiler.h"#include "materials/sceneData.h"#include "materials/materialManager.h"#include "scene/sceneManager.h"#include "scene/sceneRenderState.h"#include "materials/matInstance.h"#include "materials/materialFeatureTypes.h"#include "renderInstance/renderPassManager.h"#include "materials/customMaterialDefinition.h"#include "gfx/util/triListOpt.h"#include "util/triRayCheck.h"#include "opcode/Opcode.h"GFXPrimitiveType drawTypes[] = { GFXTriangleList, GFXTriangleStrip };#define getDrawType(a) (drawTypes[a])// structures used to share data between detail levels...// used (and valid) during load onlyVector<Point3F*> TSMesh::smVertsList;Vector<Point3F*> TSMesh::smNormsList;Vector<U8*>      TSMesh::smEncodedNormsList;Vector<Point2F*> TSMesh::smTVertsList;Vector<Point2F*> TSMesh::smTVerts2List;Vector<ColorI*> TSMesh::smColorsList;Vector<bool>     TSMesh::smDataCopied;Vector<MatrixF*> TSSkinMesh::smInitTransformList;Vector<S32*>     TSSkinMesh::smVertexIndexList;Vector<S32*>     TSSkinMesh::smBoneIndexList;Vector<F32*>     TSSkinMesh::smWeightList;Vector<S32*>     TSSkinMesh::smNodeIndexList;bool TSSkinMesh::smDebugSkinVerts = false;Vector<Point3F> gNormalStore;bool TSMesh::smUseTriangles = false; // convert all primitives to triangle lists on loadbool TSMesh::smUseOneStrip  = true; // join triangle strips into one long strip on loadS32  TSMesh::smMinStripSize = 1;     // smallest number of _faces_ allowed per strip (all else put in tri list)bool TSMesh::smUseEncodedNormals = false;const F32 TSMesh::VISIBILITY_EPSILON = 0.0001f;S32 TSMesh::smMaxInstancingVerts = 200;MatrixF TSMesh::smDummyNodeTransform(1);// quick function to force object to face camera -- currently throws out roll :(void tsForceFaceCamera( MatrixF *mat, const Point3F *objScale ){   Point4F p;   mat->getColumn( 3, &p );   mat->identity();   mat->setColumn( 3, p );   if ( objScale )   {      MatrixF scale( true );      scale.scale( *objScale );      mat->mul( scale );   }}//-----------------------------------------------------// TSMesh render methods//-----------------------------------------------------void TSMesh::render( TSVertexBufferHandle &instanceVB ){   innerRender(instanceVB, mPB);}void TSMesh::innerRender( TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb ){   if ( !vb.isValid() || !pb.isValid() )      return;   GFX->setVertexBuffer( vb );   GFX->setPrimitiveBuffer( pb );      for( U32 p = 0; p < mPrimitives.size(); p++ )      GFX->drawPrimitive( p );}void TSMesh::render( TSMaterialList *materials,                      const TSRenderState &rdata,                      bool isSkinDirty,                     const Vector<MatrixF> &transforms,                      TSVertexBufferHandle &vertexBuffer,                     const char *meshName){   // These are only used by TSSkinMesh.   TORQUE_UNUSED( isSkinDirty );      TORQUE_UNUSED( transforms );   // Pass our shared VB.   innerRender(materials, rdata, vertexBuffer, mPB, meshName);}void TSMesh::innerRender( TSMaterialList *materials, const TSRenderState &rdata, TSVertexBufferHandle &vb, GFXPrimitiveBufferHandle &pb, const char *meshName ){   PROFILE_SCOPE( TSMesh_InnerRender );   if( vertsPerFrame <= 0 )       return;   F32 meshVisibility = rdata.getFadeOverride() * mVisibility;   if ( meshVisibility < VISIBILITY_EPSILON )      return;   const SceneRenderState *state = rdata.getSceneState();   RenderPassManager *renderPass = state->getRenderPass();   MeshRenderInst *coreRI = renderPass->allocInst<MeshRenderInst>();   coreRI->type = RenderPassManager::RIT_Mesh;#ifdef TORQUE_ENABLE_GFXDEBUGEVENTS   coreRI->meshName = meshName;#endif   // Pass accumulation texture along.   coreRI->accuTex = rdata.getAccuTex();   const MatrixF &objToWorld = GFX->getWorldMatrix();   // Sort by the center point or the bounds.   if ( rdata.useOriginSort() )      coreRI->sortDistSq = ( objToWorld.getPosition() - state->getCameraPosition() ).lenSquared();   else   {      Box3F rBox = mBounds;      objToWorld.mul( rBox );      coreRI->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() );         }   if (getFlags(Billboard))   {      Point3F camPos = state->getDiffuseCameraPosition();      Point3F objPos;      objToWorld.getColumn(3, &objPos);      Point3F targetVector = camPos - objPos;      if(getFlags(BillboardZAxis))         targetVector.z = 0.0f;      targetVector.normalize();      MatrixF orient = MathUtils::createOrientFromDir(targetVector);      orient.setPosition(objPos);      orient.scale(objToWorld.getScale());      coreRI->objectToWorld = renderPass->allocUniqueXform( orient );   }   else      coreRI->objectToWorld = renderPass->allocUniqueXform( objToWorld );   coreRI->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);   coreRI->projection = renderPass->allocSharedXform(RenderPassManager::Projection);   AssertFatal( vb.isValid(), "TSMesh::innerRender() - Got invalid vertex buffer!" );   AssertFatal( pb.isValid(), "TSMesh::innerRender() - Got invalid primitive buffer!" );   coreRI->vertBuff = &vb;   coreRI->primBuff = &pb;   coreRI->defaultKey2 = (uintptr_t) coreRI->vertBuff;   coreRI->materialHint = rdata.getMaterialHint();   coreRI->mCustomShaderData = rdata.getCustomShaderBinding();   coreRI->visibility = meshVisibility;     coreRI->cubemap = rdata.getCubemap();   if ( getMeshType() == TSMesh::SkinMeshType )   {      rdata.getNodeTransforms(&coreRI->mNodeTransforms, &coreRI->mNodeTransformCount);   }   else   {      coreRI->mNodeTransforms = &TSMesh::smDummyNodeTransform;      coreRI->mNodeTransformCount = 1;   }   // NOTICE: SFXBB is removed and refraction is disabled!   //coreRI->backBuffTex = GFX->getSfxBackBuffer();   for ( S32 i = 0; i < mPrimitives.size(); i++ )   {      const TSDrawPrimitive &draw = mPrimitives[i];      // We need to have a material.      if ( draw.matIndex & TSDrawPrimitive::NoMaterial )         continue;#ifdef TORQUE_DEBUG_BREAK_INSPECT      // for inspection if you happen to be running in a debugger and can't do bit       // operations in your head.      S32 triangles = draw.matIndex & TSDrawPrimitive::Triangles;      S32 strip = draw.matIndex & TSDrawPrimitive::Strip;      S32 fan = draw.matIndex & TSDrawPrimitive::Fan;      S32 indexed = draw.matIndex & TSDrawPrimitive::Indexed;      S32 type = draw.matIndex & TSDrawPrimitive::TypeMask;      TORQUE_UNUSED(triangles);      TORQUE_UNUSED(strip);      TORQUE_UNUSED(fan);      TORQUE_UNUSED(indexed);      TORQUE_UNUSED(type);      //define TORQUE_DEBUG_BREAK_INSPECT, and insert debug break here to inspect the above elements at runtime#endif      const U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask;      BaseMatInstance *matInst = materials->getMaterialInst( matIndex );#ifndef TORQUE_OS_MAC      // Get the instancing material if this mesh qualifies.      if (mMeshType != SkinMeshType && pb->mPrimitiveArray[i].numVertices < smMaxInstancingVerts )         if (matInst && !matInst->getFeatures().hasFeature(MFT_HardwareSkinning))            matInst = InstancingMaterialHook::getInstancingMat( matInst );#endif      // If we don't have a material instance after the overload then      // there is nothing to render... skip this primitive.      matInst = state->getOverrideMaterial( matInst );      if ( !matInst || !matInst->isValid() || !matInst->getMaterial())         continue;      // If the material needs lights then gather them      // here once and set them on the core render inst.      if ( matInst->isForwardLit() && !coreRI->lights[0] && rdata.getLightQuery() )         rdata.getLightQuery()->getLights( coreRI->lights, 8 );      MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();      *ri = *coreRI;      ri->matInst = matInst;      ri->defaultKey = matInst->getStateHint();      ri->primBuffIndex = mPrimBufferOffset + i;      // Translucent materials need the translucent type.      if ( matInst->getMaterial()->isTranslucent() && (!(matInst->getMaterial()->isAlphatest() && state->isShadowPass())))      {         ri->type = RenderPassManager::RIT_Translucent;         ri->translucentSort = true;      }      renderPass->addInst( ri );   }}const Point3F * TSMesh::getNormals( S32 firstVert ){   if ( getFlags( UseEncodedNormals ) )   {      gNormalStore.setSize( vertsPerFrame );      for ( S32 i = 0; i < mEncodedNorms.size(); i++ )         gNormalStore[i] = decodeNormal(mEncodedNorms[ i + firstVert ] );      return gNormalStore.address();   }   return &mNorms[firstVert];}//-----------------------------------------------------// TSMesh collision methods//-----------------------------------------------------bool TSMesh::buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials ){   S32 firstVert  = vertsPerFrame * frame, i, base = 0;   bool hasTVert2 = getHasTVert2();   // add the verts...   if ( vertsPerFrame )   {      if ( mVertexData.isReady() )      {         OptimizedPolyList* opList = dynamic_cast<OptimizedPolyList*>(polyList);         if ( opList )         {            base = opList->mVertexList.size();            for ( i = 0; i < vertsPerFrame; i++ )            {               // Don't use vertex() method as we want to retain the original indices               OptimizedPolyList::VertIndex vert;               vert.vertIdx   = opList->insertPoint( mVertexData.getBase( i + firstVert ).vert() );               vert.normalIdx = opList->insertNormal( mVertexData.getBase( i + firstVert ).normal() );               vert.uv0Idx    = opList->insertUV0( mVertexData.getBase( i + firstVert ).tvert() );               if ( hasTVert2 )                  vert.uv1Idx = opList->insertUV1( mVertexData.getColor( i + firstVert ).tvert2() );               opList->mVertexList.push_back( vert );            }         }         else         {            base = polyList->addPointAndNormal( mVertexData.getBase( firstVert ).vert(), mVertexData.getBase( firstVert ).normal() );            for ( i = 1; i < vertsPerFrame; i++ )            {               polyList->addPointAndNormal( mVertexData.getBase( i + firstVert ).vert(), mVertexData.getBase( i + firstVert ).normal() );            }         }      }      else      {         OptimizedPolyList* opList = dynamic_cast<OptimizedPolyList*>(polyList);         if ( opList )         {            base = opList->mVertexList.size();            for ( i = 0; i < vertsPerFrame; i++ )            {               // Don't use vertex() method as we want to retain the original indices               OptimizedPolyList::VertIndex vert;               vert.vertIdx   = opList->insertPoint( mVerts[ i + firstVert ] );               vert.normalIdx = opList->insertNormal( mNorms[ i + firstVert ] );               vert.uv0Idx    = opList->insertUV0( mTverts[ i + firstVert ] );               if ( hasTVert2 )                  vert.uv1Idx = opList->insertUV1(mTverts[ i + firstVert ] );               opList->mVertexList.push_back( vert );            }         }         else         {            base = polyList->addPointAndNormal( mVerts[firstVert], mNorms[firstVert] );            for ( i = 1; i < vertsPerFrame; i++ )               polyList->addPointAndNormal(mVerts[ i + firstVert ], mNorms[ i + firstVert ] );         }      }   }   // add the polys...   for ( i = 0; i < mPrimitives.size(); i++ )   {      TSDrawPrimitive & draw = mPrimitives[i];      U32 start = draw.start;      AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" );      U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask;      BaseMatInstance* material = ( materials ? materials->getMaterialInst( matIndex ) : 0 );      // gonna depend on what kind of primitive it is...      if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )      {         for ( S32 j = 0; j < draw.numElements; )         {            U32 idx0 = base + mIndices[start + j + 0];            U32 idx1 = base + mIndices[start + j + 1];            U32 idx2 = base + mIndices[start + j + 2];            polyList->begin(material,surfaceKey++);            polyList->vertex( idx0 );            polyList->vertex( idx1 );            polyList->vertex( idx2 );            polyList->plane( idx0, idx1, idx2 );            polyList->end();            j += 3;         }      }      else      {         AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::buildPolyList (2)" );         U32 idx0 = base + mIndices[start + 0];         U32 idx1;         U32 idx2 = base + mIndices[start + 1];         U32 * nextIdx = &idx1;         for ( S32 j = 2; j < draw.numElements; j++ )         {            *nextIdx = idx2;            // nextIdx = (j%2)==0 ? &idx0 : &idx1;            nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);            idx2 = base + mIndices[start + j];            if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )               continue;            polyList->begin( material, surfaceKey++ );            polyList->vertex( idx0 );            polyList->vertex( idx1 );            polyList->vertex( idx2 );            polyList->plane( idx0, idx1, idx2 );            polyList->end();         }      }   }   return true;}bool TSMesh::getFeatures( S32 frame, const MatrixF& mat, const VectorF&, ConvexFeature* cf, U32& ){   S32 firstVert = vertsPerFrame * frame;   S32 i;   S32 base = cf->mVertexList.size();   for ( i = 0; i < vertsPerFrame; i++ )    {      cf->mVertexList.increment();      mat.mulP( mVertexData.getBase(firstVert + i).vert(), &cf->mVertexList.last() );   }   // add the polys...   for ( i = 0; i < mPrimitives.size(); i++ )   {      TSDrawPrimitive & draw = mPrimitives[i];      U32 start = draw.start;      AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildPolyList (1)" );      // gonna depend on what kind of primitive it is...      if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)      {         for ( S32 j = 0; j < draw.numElements; j += 3 )         {            PlaneF plane( cf->mVertexList[base + mIndices[start + j + 0]],                          cf->mVertexList[base + mIndices[start + j + 1]],                          cf->mVertexList[base + mIndices[start + j + 2]]);            cf->mFaceList.increment();            ConvexFeature::Face& lastFace = cf->mFaceList.last();            lastFace.normal = plane;            lastFace.vertex[0] = base + mIndices[start + j + 0];            lastFace.vertex[1] = base + mIndices[start + j + 1];            lastFace.vertex[2] = base + mIndices[start + j + 2];            for ( U32 l = 0; l < 3; l++ )             {               U32 newEdge0, newEdge1;               U32 zero = base + mIndices[start + j + l];               U32 one  = base + mIndices[start + j + ((l+1)%3)];               newEdge0 = getMin( zero, one );               newEdge1 = getMax( zero, one );               bool found = false;               for ( S32 k = 0; k < cf->mEdgeList.size(); k++ )                {                  if ( cf->mEdgeList[k].vertex[0] == newEdge0 &&                       cf->mEdgeList[k].vertex[1] == newEdge1)                   {                     found = true;                     break;                  }               }               if ( !found )                {                  cf->mEdgeList.increment();                  cf->mEdgeList.last().vertex[0] = newEdge0;                  cf->mEdgeList.last().vertex[1] = newEdge1;               }            }         }      }      else      {         AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::buildPolyList (2)" );         U32 idx0 = base + mIndices[start + 0];         U32 idx1;         U32 idx2 = base + mIndices[start + 1];         U32 * nextIdx = &idx1;         for ( S32 j = 2; j < draw.numElements; j++ )         {            *nextIdx = idx2;            nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);            idx2 = base + mIndices[start + j];            if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )               continue;            PlaneF plane( cf->mVertexList[idx0],                          cf->mVertexList[idx1],                          cf->mVertexList[idx2] );            cf->mFaceList.increment();            cf->mFaceList.last().normal = plane;            cf->mFaceList.last().vertex[0] = idx0;            cf->mFaceList.last().vertex[1] = idx1;            cf->mFaceList.last().vertex[2] = idx2;            U32 newEdge0, newEdge1;            newEdge0 = getMin( idx0, idx1 );            newEdge1 = getMax( idx0, idx1 );            bool found = false;            S32 k;            for ( k = 0; k < cf->mEdgeList.size(); k++ )             {               ConvexFeature::Edge currentEdge = cf->mEdgeList[k];               if (currentEdge.vertex[0] == newEdge0 &&                  currentEdge.vertex[1] == newEdge1)               {                  found = true;                  break;               }            }            if ( !found )             {               cf->mEdgeList.increment();               cf->mEdgeList.last().vertex[0] = newEdge0;               cf->mEdgeList.last().vertex[1] = newEdge1;            }            newEdge0 = getMin( idx1, idx2 );            newEdge1 = getMax( idx1, idx2 );            found = false;            for ( k = 0; k < cf->mEdgeList.size(); k++ )             {               if ( cf->mEdgeList[k].vertex[0] == newEdge0 &&                    cf->mEdgeList[k].vertex[1] == newEdge1 )                {                  found = true;                  break;               }            }            if ( !found )             {               cf->mEdgeList.increment();               cf->mEdgeList.last().vertex[0] = newEdge0;               cf->mEdgeList.last().vertex[1] = newEdge1;            }            newEdge0 = getMin(idx0, idx2);            newEdge1 = getMax(idx0, idx2);            found = false;            for ( k = 0; k < cf->mEdgeList.size(); k++ )             {               if ( cf->mEdgeList[k].vertex[0] == newEdge0 &&                    cf->mEdgeList[k].vertex[1] == newEdge1 )                {                  found = true;                  break;               }            }            if ( !found )             {               cf->mEdgeList.increment();               cf->mEdgeList.last().vertex[0] = newEdge0;               cf->mEdgeList.last().vertex[1] = newEdge1;            }         }      }   }   return false;}void TSMesh::support( S32 frame, const Point3F &v, F32 *currMaxDP, Point3F *currSupport ){   if ( vertsPerFrame == 0 )      return;   U32 waterMark = FrameAllocator::getWaterMark();   F32* pDots = (F32*)FrameAllocator::alloc( sizeof(F32) * vertsPerFrame );   S32 firstVert = vertsPerFrame * frame;   m_point3F_bulk_dot( &v.x,                       &mVertexData.getBase(firstVert).vert().x,                       vertsPerFrame,                       mVertexData.vertSize(),                       pDots );   F32 localdp = *currMaxDP;   S32 index   = -1;   for ( S32 i = 0; i < vertsPerFrame; i++ )   {      if ( pDots[i] > localdp )      {         localdp = pDots[i];         index   = i;      }   }   FrameAllocator::setWaterMark(waterMark);   if ( index != -1 )   {      *currMaxDP   = localdp;      *currSupport = mVertexData.getBase(index + firstVert).vert();   }}bool TSMesh::castRay( S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials ){   if ( mPlaneNormals.empty() )      buildConvexHull(); // if haven't done it yet...   // Keep track of startTime and endTime.  They start out at just under 0 and just over 1, respectively.   // As we check against each plane, prune start and end times back to represent current intersection of   // line with all the planes (or rather with all the half-spaces defined by the planes).   // But, instead of explicitly keeping track of startTime and endTime, keep track as numerator and denominator   // so that we can avoid as many divisions as possible.   //   F32 startTime = -0.01f;   F32 startNum = -0.01f;   F32 startDen =  1.00f;   //   F32 endTime   = 1.01f;   F32 endNum = 1.01f;   F32 endDen = 1.00f;   S32 curPlane = 0;   U32 curMaterial = 0;   bool found = false;   // the following block of code is an optimization...   // it isn't necessary if the longer version of the main loop is used   bool tmpFound;   S32 tmpPlane;   F32 sgn = -1.0f;   F32 * pnum = &startNum;   F32 * pden = &startDen;   S32 * pplane = &curPlane;   bool * pfound = &found;   S32 startPlane = frame * mPlanesPerFrame;   for ( S32  i = startPlane; i < startPlane + mPlanesPerFrame; i++ )   {      // if start & end outside, no collision      // if start & end inside, continue      // if start outside, end inside, or visa versa, find intersection of line with plane      //    then update intersection of line with hull (using startTime and endTime)      F32 dot1 = mDot(mPlaneNormals[i], start ) - mPlaneConstants[i];      F32 dot2 = mDot(mPlaneNormals[i], end) - mPlaneConstants[i];      if ( dot1 * dot2 > 0.0f )      {         // same side of the plane...which side -- dot==0 considered inside         if ( dot1 > 0.0f )            return false; // start and end outside of this plane, no collision                  // start and end inside plane, continue         continue;      }      //AssertFatal( dot1 / ( dot1 - dot2 ) >= 0.0f && dot1 / ( dot1 - dot2 ) <= 1.0f,"TSMesh::castRay (1)" );      // find intersection (time) with this plane...      // F32 time = dot1 / (dot1-dot2);      F32 num = mFabs( dot1 );      F32 den = mFabs( dot1 - dot2 );      // the following block of code is an optimized version...      // this can be commented out and the following block of code used instead      // if debugging a problem in this code, that should probably be done      // if you want to see how this works, look at the following block of code,      // not this one...      // Note that this does not get optimized appropriately...it is included this way      // as an idea for future optimization.      if ( sgn * dot1 >= 0 )      {         sgn *= -1.0f;         pnum = (F32*) ((dsize_t)pnum ^ (dsize_t)&endNum ^ (dsize_t)&startNum);         pden = (F32*) ((dsize_t)pden ^ (dsize_t)&endDen ^ (dsize_t)&startDen);         pplane = (S32*) ((dsize_t)pplane ^ (dsize_t)&tmpPlane ^ (dsize_t)&curPlane);         pfound = (bool*) ((dsize_t)pfound ^ (dsize_t)&tmpFound ^ (dsize_t)&found);      }      bool noCollision = num * endDen * sgn < endNum * den * sgn && num * startDen * sgn < startNum * den * sgn;      if (num * *pden * sgn < *pnum * den * sgn && !noCollision)      {         *pnum = num;         *pden = den;         *pplane = i;         *pfound = true;      }      else if ( noCollision )         return false;//      if (dot1<=0.0f)//      {//         // start is inside plane, end is outside...chop off end//         if (num*endDen<endNum*den) // if (time<endTime)//         {//            if (num*startDen<startNum*den) //if (time<startTime)//               // no intersection of line and hull//               return false;//            // endTime = time;//            endNum = num;//            endDen = den;//         }//         // else, no need to do anything, just continue (we've been more inside than this)//      }//      else // dot2<=0.0f//      {//         // end is inside poly, start is outside...chop off start//         AssertFatal(dot2<=0.0f,"TSMesh::castRay (2)");//         if (num*startDen>startNum*den) // if (time>startTime)//        {//            if (num*endDen>endNum*den) //if (time>endTime)//               // no intersection of line and hull//               return false;//            // startTime   = time;//            startNum = num;//            startDen = den;//            curPlane    = i;//            curMaterial = planeMaterials[i-startPlane];//            found = true;//         }//         // else, no need to do anything, just continue (we've been more inside than this)//      }   }   // setup rayInfo   if ( found && rayInfo )   {      curMaterial       = mPlaneMaterials[ curPlane - startPlane ];      rayInfo->t        = (F32)startNum/(F32)startDen; // finally divide...      rayInfo->normal   = mPlaneNormals[curPlane];      if (materials && materials->size() > 0)         rayInfo->material = materials->getMaterialInst( curMaterial );      else         rayInfo->material = NULL;      rayInfo->setContactPoint( start, end );      return true;   }   else if ( found )      return true;   // only way to get here is if start is inside hull...   // we could return null and just plug in garbage for the material and normal...   return false;}bool TSMesh::castRayRendered( S32 frame, const Point3F & start, const Point3F & end, RayInfo * rayInfo, TSMaterialList* materials ){   if( vertsPerFrame <= 0 )       return false;   if( mNumVerts == 0 )      return false;   S32 firstVert  = vertsPerFrame * frame;	bool found = false;	F32 best_t = F32_MAX;   U32 bestIdx0 = 0, bestIdx1 = 0, bestIdx2 = 0;   BaseMatInstance* bestMaterial = NULL;	Point3F dir = end - start;   for ( S32 i = 0; i < mPrimitives.size(); i++ )   {      TSDrawPrimitive & draw = mPrimitives[i];      U32 drawStart = draw.start;      AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::castRayRendered (1)" );      U32 matIndex = draw.matIndex & TSDrawPrimitive::MaterialMask;      BaseMatInstance* material = ( materials ? materials->getMaterialInst( matIndex ) : 0 );      U32 idx0, idx1, idx2;      // gonna depend on what kind of primitive it is...      if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )      {         for ( S32 j = 0; j < draw.numElements-2; j += 3 )         {            idx0 = mIndices[drawStart + j + 0];            idx1 = mIndices[drawStart + j + 1];            idx2 = mIndices[drawStart + j + 2];			   F32 cur_t = 0;			   Point2F b;			   if(castRayTriangle(start, dir, mVertexData.getBase(firstVert + idx0).vert(),               mVertexData.getBase(firstVert + idx1).vert(), mVertexData.getBase(firstVert + idx2).vert(), cur_t, b))			   {				   if(cur_t < best_t)				   {					   best_t = cur_t;                  bestIdx0 = idx0;                  bestIdx1 = idx1;                  bestIdx2 = idx2;                  bestMaterial = material;					   found = true;				   }			   }         }      }      else      {         AssertFatal( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Strip,"TSMesh::castRayRendered (2)" );         idx0 = mIndices[drawStart + 0];         idx2 = mIndices[drawStart + 1];         U32 * nextIdx = &idx1;         for ( S32 j = 2; j < draw.numElements; j++ )         {            *nextIdx = idx2;            // nextIdx = (j%2)==0 ? &idx0 : &idx1;            nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);            idx2 = mIndices[drawStart + j];            if ( idx0 == idx1 || idx0 == idx2 || idx1 == idx2 )               continue;			   F32 cur_t = 0;			   Point2F b;			   if(castRayTriangle(start, dir, mVertexData.getBase(firstVert + idx0).vert(),                mVertexData.getBase(firstVert + idx1).vert(), mVertexData.getBase(firstVert + idx2).vert(), cur_t, b))			   {				   if(cur_t < best_t)				   {					   best_t = cur_t;                  bestIdx0 = firstVert + idx0;                  bestIdx1 = firstVert + idx1;                  bestIdx2 = firstVert + idx2;                  bestMaterial = material;					   found = true;				   }			   }         }      }   }   // setup rayInfo   if ( found && rayInfo )   {      rayInfo->t = best_t;      Point3F normal;      mCross(mVertexData.getBase(bestIdx2).vert()-mVertexData.getBase(bestIdx0).vert(),mVertexData.getBase(bestIdx1).vert()-mVertexData.getBase(bestIdx0).vert(),&normal);      if ( mDot( normal, normal ) < 0.001f )      {         mCross( mVertexData.getBase(bestIdx0).vert() - mVertexData.getBase(bestIdx1).vert(), mVertexData.getBase(bestIdx2).vert() - mVertexData.getBase(bestIdx1).vert(), &normal );         if ( mDot( normal, normal ) < 0.001f )         {            mCross( mVertexData.getBase(bestIdx1).vert() - mVertexData.getBase(bestIdx2).vert(), mVertexData.getBase(bestIdx0).vert() - mVertexData.getBase(bestIdx2).vert(), &normal );         }      }      normal.normalize();      rayInfo->normal = normal;      rayInfo->material = bestMaterial;      rayInfo->setContactPoint( start, end );      return true;   }   else if ( found )      return true;   return false;}bool TSMesh::addToHull( U32 idx0, U32 idx1, U32 idx2 ){   // calculate the normal of this triangle... remember, we lose precision   // when we subtract two large numbers that are very close to each other,   // so depending on how we calculate the normal, we could get a    // different result. so, we will calculate the normal three different   // ways and take the one that gives us the largest vector before we   // normalize.   Point3F normal1, normal2, normal3;   const Point3F& vertex0Data = mVertexData.getBase(idx0).vert();   const Point3F& vertex1Data = mVertexData.getBase(idx1).vert();   const Point3F& vertex2Data = mVertexData.getBase(idx2).vert();   mCross(vertex2Data-vertex0Data,vertex1Data-vertex0Data,&normal1);   mCross(vertex0Data-vertex1Data,vertex2Data-vertex1Data,&normal2);   mCross(vertex1Data-vertex2Data,vertex0Data-vertex2Data,&normal3);   Point3F normal = normal1;   F32 greatestMagSquared = mDot(normal1, normal1);   F32 magSquared = mDot(normal2, normal2);   if (magSquared > greatestMagSquared)   {      normal = normal2;      greatestMagSquared = magSquared;   }   magSquared = mDot(normal3, normal3);   if (magSquared > greatestMagSquared)   {      normal = normal3;      greatestMagSquared = magSquared;   }   if (mDot(normal, normal) < 0.00000001f)       return false;   normal.normalize();   F32 k = mDot( normal, mVertexData.getBase(idx0).vert() );   for ( S32 i = 0; i < mPlaneNormals.size(); i++ )   {      if ( mDot(mPlaneNormals[i], normal ) > 0.99f && mFabs( k- mPlaneConstants[i] ) < 0.01f )         return false;          // this is a repeat...   }   // new plane, add it to the list...   mPlaneNormals.push_back( normal );   mPlaneConstants.push_back( k );   return true;}bool TSMesh::buildConvexHull(){   // already done, return without error   if (mPlaneNormals.size() )      return true;   bool error = false;   // should probably only have 1 frame, but just in case...   mPlanesPerFrame = 0;   S32 frame, i, j;   for ( frame = 0; frame < numFrames; frame++ )   {      S32 firstVert  = vertsPerFrame * frame;      S32 firstPlane = mPlaneNormals.size();      for ( i = 0; i < mPrimitives.size(); i++ )      {         TSDrawPrimitive & draw = mPrimitives[i];         U32 start = draw.start;         AssertFatal( draw.matIndex & TSDrawPrimitive::Indexed,"TSMesh::buildConvexHull (1)" );         // gonna depend on what kind of primitive it is...         if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )         {            for ( j = 0;  j < draw.numElements; j += 3 )               if ( addToHull(   mIndices[start + j + 0] + firstVert,                                  mIndices[start + j + 1] + firstVert,                                  mIndices[start + j + 2] + firstVert ) && frame == 0 )				   mPlaneMaterials.push_back( draw.matIndex & TSDrawPrimitive::MaterialMask );         }         else         {            AssertFatal( (draw.matIndex&TSDrawPrimitive::Strip) == TSDrawPrimitive::Strip,"TSMesh::buildConvexHull (2)" );            U32 idx0 = mIndices[start + 0] + firstVert;            U32 idx1;            U32 idx2 = mIndices[start + 1] + firstVert;            U32 * nextIdx = &idx1;            for ( j = 2; j < draw.numElements; j++ )            {               *nextIdx = idx2;//               nextIdx = (j%2)==0 ? &idx0 : &idx1;               nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1 );               idx2 = mIndices[start + j] + firstVert;               if ( addToHull( idx0, idx1, idx2 ) && frame == 0 )				   mPlaneMaterials.push_back( draw.matIndex & TSDrawPrimitive::MaterialMask );            }         }      }      // make sure all the verts on this frame are inside all the planes      for ( i = 0; i < vertsPerFrame; i++ )         for ( j = firstPlane; j < mPlaneNormals.size(); j++ )            if ( mDot( mVertexData.getBase(firstVert + i).vert(), mPlaneNormals[j] ) - mPlaneConstants[j] < 0.01 ) // .01 == a little slack               error = true;      if ( frame == 0 )		  mPlanesPerFrame = mPlaneNormals.size();      if ( (frame + 1) * mPlanesPerFrame != mPlaneNormals.size() )      {         // eek, not all frames have same number of planes...         while ( (frame + 1) * mPlanesPerFrame > mPlaneNormals.size() )         {            // we're short, duplicate last plane till we match            U32 sz = mPlaneNormals.size();			mPlaneNormals.increment();			mPlaneNormals.last() = mPlaneNormals[sz-1];			mPlaneConstants.increment();			mPlaneConstants.last() = mPlaneConstants[sz-1];         }         while ( (frame + 1) * mPlanesPerFrame < mPlaneNormals.size() )         {            // harsh -- last frame has more than other frames            // duplicate last plane in each frame            for ( S32 k = frame - 1; k >= 0; k-- )            {				mPlaneNormals.insert( k * mPlanesPerFrame + mPlanesPerFrame );				mPlaneNormals[k * mPlanesPerFrame + mPlanesPerFrame] = mPlaneNormals[k * mPlanesPerFrame + mPlanesPerFrame - 1];				mPlaneConstants.insert( k * mPlanesPerFrame + mPlanesPerFrame );				mPlaneConstants[k * mPlanesPerFrame + mPlanesPerFrame] = mPlaneConstants[k * mPlanesPerFrame + mPlanesPerFrame - 1];               if ( k == 0 )               {				   mPlaneMaterials.increment();				   mPlaneMaterials.last() = mPlaneMaterials[mPlaneMaterials.size() - 2];               }            }			mPlanesPerFrame++;         }      }      AssertFatal( (frame + 1) * mPlanesPerFrame == mPlaneNormals.size(),"TSMesh::buildConvexHull (3)" );   }   return !error;}//-----------------------------------------------------// TSMesh bounds methods//-----------------------------------------------------void TSMesh::computeBounds(){   MatrixF mat(true);   computeBounds( mat, mBounds, -1, &mCenter, &mRadius );}void TSMesh::computeBounds( const MatrixF &transform, Box3F &bounds, S32 frame, Point3F *center, F32 *radius ){   const Point3F *baseVert = NULL;   S32 stride = 0;   S32 numVerts = 0;   AssertFatal(!mVertexData.isReady()  || (mVertexData.isReady() && mNumVerts == mVertexData.size() && mNumVerts == vertsPerFrame), "vertex number mismatch");   if(mVerts.size() == 0 && mVertexData.isReady() && mVertexData.size() > 0)   {      baseVert = &mVertexData.getBase(0).vert();      stride = mVertexData.vertSize();      if ( frame < 0 )         numVerts = mNumVerts;      else      {         baseVert = &mVertexData.getBase(frame * vertsPerFrame).vert();         numVerts = vertsPerFrame;      }   }   else   {      baseVert = mVerts.address();      stride = sizeof(Point3F);      if ( frame < 0 )         numVerts = mVerts.size();      else      {         baseVert += frame * vertsPerFrame;         numVerts = vertsPerFrame;      }   }   computeBounds( baseVert, numVerts, stride, transform, bounds, center, radius );}void TSMesh::computeBounds( const Point3F *v, S32 numVerts, S32 stride, const MatrixF &transform, Box3F &bounds, Point3F *center, F32 *radius ){   const U8 *_vb = reinterpret_cast<const U8 *>(v);   if ( !numVerts )   {      bounds.minExtents = Point3F::Zero;      bounds.maxExtents = Point3F::Zero;      if ( center )         *center = Point3F::Zero;      if ( radius )         *radius = 0;      return;   }   S32 i;   Point3F p;   transform.mulP( *v, &bounds.minExtents );   bounds.maxExtents = bounds.minExtents;   for ( i = 0; i < numVerts; i++ )   {      const Point3F &curVert = *reinterpret_cast<const Point3F *>(_vb + i * stride);      transform.mulP( curVert, &p );      bounds.maxExtents.setMax( p );      bounds.minExtents.setMin( p );   }   Point3F c;   if ( !center )      center = &c;   center->x = 0.5f * (bounds.minExtents.x + bounds.maxExtents.x);   center->y = 0.5f * (bounds.minExtents.y + bounds.maxExtents.y);   center->z = 0.5f * (bounds.minExtents.z + bounds.maxExtents.z);   if ( radius )   {      *radius = 0.0f;      for ( i = 0; i < numVerts; i++ )      {         const Point3F &curVert = *reinterpret_cast<const Point3F *>(_vb + i * stride);         transform.mulP( curVert, &p );         p -= *center;         *radius = getMax( *radius, mDot( p, p ) );      }      *radius = mSqrt( *radius );   }}//-----------------------------------------------------S32 TSMesh::getNumPolys() const{   S32 count = 0;   for ( S32 i = 0; i < mPrimitives.size(); i++ )   {      switch (mPrimitives[i].matIndex & TSDrawPrimitive::TypeMask)      {         case TSDrawPrimitive::Triangles:            count += mPrimitives[i].numElements / 3;            break;         case TSDrawPrimitive::Fan:            count += mPrimitives[i].numElements - 2;            break;         case TSDrawPrimitive::Strip:            // Don't count degenerate triangles            for ( S32 j = mPrimitives[i].start;                  j < mPrimitives[i].start+ mPrimitives[i].numElements-2;                  j++ )            {               if ((mIndices[j] != mIndices[j+1]) &&                   (mIndices[j] != mIndices[j+2]) &&                   (mIndices[j+1] != mIndices[j+2]))                  count++;            }            break;      }   }   return count;}//-----------------------------------------------------TSMesh::TSMesh() : mMeshType( StandardMeshType ){   VECTOR_SET_ASSOCIATION(mPlaneNormals );   VECTOR_SET_ASSOCIATION(mPlaneConstants );   VECTOR_SET_ASSOCIATION(mPlaneMaterials );   mParentMesh = -1;   mOptTree = NULL;   mOpMeshInterface = NULL;   mOpTris = NULL;   mOpPoints = NULL;   mVisibility = 1.0f;   mNumVerts = 0;   mVertSize = 0;   mVertOffset = 0;   mRadius = 0.0f;   mVertexFormat = NULL;   mPrimBufferOffset = 0;   numFrames = 0;   numMatFrames = 0;   vertsPerFrame = 0;   mPlanesPerFrame = 0;   mMergeBufferStart = 0;   mParentMeshObject = NULL;}//-----------------------------------------------------// TSMesh destructor//-----------------------------------------------------TSMesh::~TSMesh(){   SAFE_DELETE( mOptTree );   SAFE_DELETE( mOpMeshInterface );   SAFE_DELETE_ARRAY( mOpTris );   SAFE_DELETE_ARRAY( mOpPoints );   mNumVerts = 0;}//-----------------------------------------------------// TSSkinMesh methods//-----------------------------------------------------void TSSkinMesh::updateSkinBuffer( const Vector<MatrixF> &transforms, U8* buffer ){   PROFILE_SCOPE(TSSkinMesh_UpdateSkinBuffer);   AssertFatal(batchData.initialized, "Batch data not initialized. Call createSkinBatchData() before any skin update is called.");   if (TSShape::smUseHardwareSkinning || mNumVerts == 0)      return;   const MatrixF *matrices = NULL;   static Vector<MatrixF> sBoneTransforms;   sBoneTransforms.setSize(batchData.nodeIndex.size());   // set up bone transforms   PROFILE_START(TSSkinMesh_UpdateTransforms);   for (S32 i = 0; i < batchData.nodeIndex.size(); i++)   {      S32 node = batchData.nodeIndex[i];      sBoneTransforms[i].mul(transforms[node], batchData.initialTransforms[i]);   }   matrices = &sBoneTransforms[0];   PROFILE_END();   const Point3F *inVerts = batchData.initialVerts.address();   const Point3F *inNorms = batchData.initialNorms.address();   AssertFatal(inVerts, "Something went wrong, verts should be valid");   U8 *dest = buffer + mVertOffset;   if (!dest)      return;   Point3F srcVtx, srcNrm;   AssertFatal(batchData.vertexBatchOperations.size() == batchData.initialVerts.size(), "Assumption failed!");   Point3F skinnedVert;   Point3F skinnedNorm;   for (Vector<BatchData::BatchedVertex>::const_iterator itr = batchData.vertexBatchOperations.begin();      itr != batchData.vertexBatchOperations.end(); itr++)   {      const BatchData::BatchedVertex &curVert = *itr;      skinnedVert.zero();      skinnedNorm.zero();      for (S32 tOp = 0; tOp < curVert.transformCount; tOp++)      {         const BatchData::TransformOp &transformOp = curVert.transform[tOp];         const MatrixF& deltaTransform = matrices[transformOp.transformIndex];         deltaTransform.mulP(inVerts[curVert.vertexIndex], &srcVtx);         skinnedVert += (srcVtx * transformOp.weight);         deltaTransform.mulV(inNorms[curVert.vertexIndex], &srcNrm);         skinnedNorm += srcNrm * transformOp.weight;      }      // Assign results       __TSMeshVertexBase *dvert = (__TSMeshVertexBase*)(dest + (mVertSize * curVert.vertexIndex));      dvert->vert(skinnedVert);      dvert->normal(skinnedNorm);   }}void TSSkinMesh::updateSkinBones( const Vector<MatrixF> &transforms, Vector<MatrixF>& destTransforms ){   // Update transforms for current mesh   destTransforms.setSize(batchData.nodeIndex.size());   for (int i = 0; i<batchData.nodeIndex.size(); i++)   {      S32 node = batchData.nodeIndex[i];      if (node >= transforms.size())         continue; // jamesu - ignore obviously invalid data      destTransforms[i].mul(transforms[node], batchData.initialTransforms[i]);   }}void TSSkinMesh::createSkinBatchData(){   if(batchData.initialized)      return;   batchData.initialized = true;   S32 * curVtx = vertexIndex.begin();   S32 * curBone = boneIndex.begin();   F32 * curWeight = weight.begin();   const S32 * endVtx = vertexIndex.end();   AssertFatal(batchData.nodeIndex.size() <= TSShape::smMaxSkinBones, "Too many bones are here!!!");   // Temp vector to build batch operations   Vector<BatchData::BatchedVertex> batchOperations;   bool issuedWeightWarning = false;   if (mVertexData.isReady())   {      batchData.initialVerts.setSize(mNumVerts);      batchData.initialNorms.setSize(mNumVerts);      // Fill arrays      for (U32 i = 0; i < mNumVerts; i++)      {         const __TSMeshVertexBase &cv = mVertexData.getBase(i);         batchData.initialVerts[i] = cv.vert();         batchData.initialNorms[i] = cv.normal();      }      addWeightsFromVertexBuffer();      curVtx = vertexIndex.begin();      curBone = boneIndex.begin();      curWeight = weight.begin();      endVtx = vertexIndex.end();   }   else   {      batchData.initialNorms = mNorms;      batchData.initialVerts = mVerts;   }   // Build the batch operations   while( curVtx != endVtx )   {      const S32 vidx = *curVtx;      ++curVtx;      const S32 midx = *curBone;      ++curBone;      const F32 w = *curWeight;      ++curWeight;      // Ignore empty weights      if ( vidx < 0 || midx < 0 || w == 0 )         continue;      if( !batchOperations.empty() &&         batchOperations.last().vertexIndex == vidx )      {         AssertFatal( batchOperations.last().transformCount > 0, "Not sure how this happened!" );         S32 opIdx = batchOperations.last().transformCount++;         // Limit the number of weights per bone (keep the N largest influences)         if ( opIdx >= TSSkinMesh::BatchData::maxBonePerVert )         {            if ( !issuedWeightWarning )            {               issuedWeightWarning = true;               Con::warnf( "At least one vertex has too many bone weights - limiting "                  "to the largest %d influences (see maxBonePerVert in tsMesh.h).",                  TSSkinMesh::BatchData::maxBonePerVert );            }            // Too many weights => find and replace the smallest one            S32 minIndex = 0;            F32 minWeight = batchOperations.last().transform[0].weight;            for ( S32 i = 1; i < batchOperations.last().transformCount; i++ )            {               if ( batchOperations.last().transform[i].weight < minWeight )               {                  minWeight = batchOperations.last().transform[i].weight;                  minIndex = i;               }            }            opIdx = minIndex;            batchOperations.last().transformCount = TSSkinMesh::BatchData::maxBonePerVert;         }         batchOperations.last().transform[opIdx].transformIndex = midx;         batchOperations.last().transform[opIdx].weight = w;      }      else      {         batchOperations.increment();         batchOperations.last().vertexIndex = vidx;         batchOperations.last().transformCount = 1;         batchOperations.last().transform[0].transformIndex = midx;         batchOperations.last().transform[0].weight = w;      }      //Con::printf( "[%d] transform idx %d, weight %1.5f", vidx, midx, w );   }   //Con::printf("End skin update");   // Normalize vertex weights (force weights for each vert to sum to 1)   if ( issuedWeightWarning )   {      for ( S32 i = 0; i < batchOperations.size(); i++ )      {         BatchData::BatchedVertex& batchOp = batchOperations[i];         // Sum weights for this vertex         F32 invTotalWeight = 0;         for ( S32 j = 0; j < batchOp.transformCount; j++ )            invTotalWeight += batchOp.transform[j].weight;         // Then normalize the vertex weights         invTotalWeight = 1.0f / invTotalWeight;         for ( S32 j = 0; j < batchOp.transformCount; j++ )            batchOp.transform[j].weight *= invTotalWeight;      }   }   batchData.vertexBatchOperations.set(batchOperations.address(), batchOperations.size());   U32 maxValue = 0;   for (U32 i = 0; i<batchData.vertexBatchOperations.size(); i++)   {      maxValue = batchData.vertexBatchOperations[i].transformCount > maxValue ? batchData.vertexBatchOperations[i].transformCount : maxValue;   }   maxBones = maxValue;}void TSSkinMesh::setupVertexTransforms(){   AssertFatal(mVertexData.vertSize() == mVertSize, "vert size mismatch");   // Generate the bone transforms for the verts   for( Vector<BatchData::BatchedVertex>::const_iterator itr = batchData.vertexBatchOperations.begin();      itr != batchData.vertexBatchOperations.end(); itr++ )   {      const BatchData::BatchedVertex &curTransform = *itr;      S32 i=0;      S32 j=0;      S32 transformsLeft = curTransform.transformCount;      // Set weights and indices in batches of 4      for( i = 0, j = 0; i < curTransform.transformCount; i += 4, j += 1 )      {         __TSMeshVertex_BoneData &v = mVertexData.getBone(curTransform.vertexIndex, j);         S32 vertsSet = transformsLeft > 4 ? 4 : transformsLeft;         __TSMeshIndex_List indices;         Point4F weights;         dMemset(&indices, '\0', sizeof(indices));         dMemset(&weights, '\0', sizeof(weights));         switch (vertsSet)         {         case 1:            indices.x = curTransform.transform[i+0].transformIndex;            weights.x = curTransform.transform[i+0].weight;            break;         case 2:            indices.x = curTransform.transform[i+0].transformIndex;            weights.x = curTransform.transform[i+0].weight;            indices.y = curTransform.transform[i+1].transformIndex;            weights.y = curTransform.transform[i+1].weight;            break;         case 3:            indices.x = curTransform.transform[i+0].transformIndex;            weights.x = curTransform.transform[i+0].weight;            indices.y = curTransform.transform[i+1].transformIndex;            weights.y = curTransform.transform[i+1].weight;            indices.z = curTransform.transform[i+2].transformIndex;            weights.z = curTransform.transform[i+2].weight;            break;         case 4:            indices.x = curTransform.transform[i+0].transformIndex;            weights.x = curTransform.transform[i+0].weight;            indices.y = curTransform.transform[i+1].transformIndex;            weights.y = curTransform.transform[i+1].weight;            indices.z = curTransform.transform[i+2].transformIndex;            weights.z = curTransform.transform[i+2].weight;            indices.w = curTransform.transform[i+3].transformIndex;            weights.w = curTransform.transform[i+3].weight;            break;         case 0:         default:            break;         }         v.index(indices);         v.weight(weights);         transformsLeft -= 4;      }   }}U32 TSSkinMesh::getMaxBonesPerVert(){   return maxBones >= 0 ? maxBones : 0;}void TSSkinMesh::render( TSVertexBufferHandle &instanceVB ){   innerRender(instanceVB, mPB);}void TSSkinMesh::render(   TSMaterialList *materials,                            const TSRenderState &rdata,                           bool isSkinDirty,                           const Vector<MatrixF> &transforms,                            TSVertexBufferHandle &vertexBuffer,                           const char *meshName ){   PROFILE_SCOPE(TSSkinMesh_render);   if (mNumVerts == 0)      return;   // verify stuff first   AssertFatal(mVertexData.size() == mNumVerts, "Vert # mismatch");   AssertFatal((TSShape::smUseHardwareSkinning && vertexBuffer == mVB) || (!TSShape::smUseHardwareSkinning), "Vertex buffer mismatch");   // render...   innerRender(materials, rdata, vertexBuffer, mPB, meshName);}bool TSSkinMesh::buildPolyList( S32 frame, AbstractPolyList *polyList, U32 &surfaceKey, TSMaterialList *materials ){   return false;}bool TSSkinMesh::castRay( S32 frame, const Point3F &start, const Point3F &end, RayInfo *rayInfo, TSMaterialList *materials ){   TORQUE_UNUSED(frame);   TORQUE_UNUSED(start);   TORQUE_UNUSED(end);   TORQUE_UNUSED(rayInfo);   TORQUE_UNUSED(materials);   return false;}bool TSSkinMesh::buildConvexHull(){   return false; // no error, but we don't do anything either...}void TSSkinMesh::computeBounds( const MatrixF &transform, Box3F &bounds, S32 frame, Point3F *center, F32 *radius ){   TORQUE_UNUSED(frame);   if (mVerts.size() != 0)   {      // Use unskinned verts      TSMesh::computeBounds(mVerts.address(), mVerts.size(), sizeof(Point3F), transform, bounds, center, radius );   }   else if (frame <= 0 && batchData.initialVerts.size() > 0)   {      // Use unskinned verts      TSMesh::computeBounds(batchData.initialVerts.address(), batchData.initialVerts.size(), sizeof(Point3F), transform, bounds, center, radius);   }   else   {      Point3F *vertStart = reinterpret_cast<Point3F *>(mVertexData.address());      TSMesh::computeBounds( vertStart, mVertexData.size(), mVertexData.vertSize(), transform, bounds, center, radius );   }}//-----------------------------------------------------// encoded normals//-----------------------------------------------------const Point3F TSMesh::smU8ToNormalTable[] ={      Point3F( 0.565061f, -0.270644f, -0.779396f ),      Point3F( -0.309804f, -0.731114f, 0.607860f ),      Point3F( -0.867412f, 0.472957f, 0.154619f ),      Point3F( -0.757488f, 0.498188f, -0.421925f ),      Point3F( 0.306834f, -0.915340f, 0.260778f ),      Point3F( 0.098754f, 0.639153f, -0.762713f ),      Point3F( 0.713706f, -0.558862f, -0.422252f ),      Point3F( -0.890431f, -0.407603f, -0.202466f ),      Point3F( 0.848050f, -0.487612f, -0.207475f ),      Point3F( -0.232226f, 0.776855f, 0.585293f ),      Point3F( -0.940195f, 0.304490f, -0.152706f ),      Point3F( 0.602019f, -0.491878f, -0.628991f ),      Point3F( -0.096835f, -0.494354f, -0.863850f ),      Point3F( 0.026630f, -0.323659f, -0.945799f ),      Point3F( 0.019208f, 0.909386f, 0.415510f ),      Point3F( 0.854440f, 0.491730f, 0.167731f ),      Point3F( -0.418835f, 0.866521f, -0.271512f ),      Point3F( 0.465024f, 0.409667f, 0.784809f ),      Point3F( -0.674391f, -0.691087f, -0.259992f ),      Point3F( 0.303858f, -0.869270f, -0.389922f ),      Point3F( 0.991333f, 0.090061f, -0.095640f ),      Point3F( -0.275924f, -0.369550f, 0.887298f ),      Point3F( 0.426545f, -0.465962f, 0.775202f ),      Point3F( -0.482741f, -0.873278f, -0.065920f ),      Point3F( 0.063616f, 0.932012f, -0.356800f ),      Point3F( 0.624786f, -0.061315f, 0.778385f ),      Point3F( -0.530300f, 0.416850f, 0.738253f ),      Point3F( 0.312144f, -0.757028f, -0.573999f ),      Point3F( 0.399288f, -0.587091f, -0.704197f ),      Point3F( -0.132698f, 0.482877f, 0.865576f ),      Point3F( 0.950966f, 0.306530f, 0.041268f ),      Point3F( -0.015923f, -0.144300f, 0.989406f ),      Point3F( -0.407522f, -0.854193f, 0.322925f ),      Point3F( -0.932398f, 0.220464f, 0.286408f ),      Point3F( 0.477509f, 0.876580f, 0.059936f ),      Point3F( 0.337133f, 0.932606f, -0.128796f ),      Point3F( -0.638117f, 0.199338f, 0.743687f ),      Point3F( -0.677454f, 0.445349f, 0.585423f ),      Point3F( -0.446715f, 0.889059f, -0.100099f ),      Point3F( -0.410024f, 0.909168f, 0.072759f ),      Point3F( 0.708462f, 0.702103f, -0.071641f ),      Point3F( -0.048801f, -0.903683f, -0.425411f ),      Point3F( -0.513681f, -0.646901f, 0.563606f ),      Point3F( -0.080022f, 0.000676f, -0.996793f ),      Point3F( 0.066966f, -0.991150f, -0.114615f ),      Point3F( -0.245220f, 0.639318f, -0.728793f ),      Point3F( 0.250978f, 0.855979f, 0.452006f ),      Point3F( -0.123547f, 0.982443f, -0.139791f ),      Point3F( -0.794825f, 0.030254f, -0.606084f ),      Point3F( -0.772905f, 0.547941f, 0.319967f ),      Point3F( 0.916347f, 0.369614f, -0.153928f ),      Point3F( -0.388203f, 0.105395f, 0.915527f ),      Point3F( -0.700468f, -0.709334f, 0.078677f ),      Point3F( -0.816193f, 0.390455f, 0.425880f ),      Point3F( -0.043007f, 0.769222f, -0.637533f ),      Point3F( 0.911444f, 0.113150f, 0.395560f ),      Point3F( 0.845801f, 0.156091f, -0.510153f ),      Point3F( 0.829801f, -0.029340f, 0.557287f ),      Point3F( 0.259529f, 0.416263f, 0.871418f ),      Point3F( 0.231128f, -0.845982f, 0.480515f ),      Point3F( -0.626203f, -0.646168f, 0.436277f ),      Point3F( -0.197047f, -0.065791f, 0.978184f ),      Point3F( -0.255692f, -0.637488f, -0.726794f ),      Point3F( 0.530662f, -0.844385f, -0.073567f ),      Point3F( -0.779887f, 0.617067f, -0.104899f ),      Point3F( 0.739908f, 0.113984f, 0.662982f ),      Point3F( -0.218801f, 0.930194f, -0.294729f ),      Point3F( -0.374231f, 0.818666f, 0.435589f ),      Point3F( -0.720250f, -0.028285f, 0.693137f ),      Point3F( 0.075389f, 0.415049f, 0.906670f ),      Point3F( -0.539724f, -0.106620f, 0.835063f ),      Point3F( -0.452612f, -0.754669f, -0.474991f ),      Point3F( 0.682822f, 0.581234f, -0.442629f ),      Point3F( 0.002435f, -0.618462f, -0.785811f ),      Point3F( -0.397631f, 0.110766f, -0.910835f ),      Point3F( 0.133935f, -0.985438f, 0.104754f ),      Point3F( 0.759098f, -0.608004f, 0.232595f ),      Point3F( -0.825239f, -0.256087f, 0.503388f ),      Point3F( 0.101693f, -0.565568f, 0.818408f ),      Point3F( 0.386377f, 0.793546f, -0.470104f ),      Point3F( -0.520516f, -0.840690f, 0.149346f ),      Point3F( -0.784549f, -0.479672f, 0.392935f ),      Point3F( -0.325322f, -0.927581f, -0.183735f ),      Point3F( -0.069294f, -0.428541f, 0.900861f ),      Point3F( 0.993354f, -0.115023f, -0.004288f ),      Point3F( -0.123896f, -0.700568f, 0.702747f ),      Point3F( -0.438031f, -0.120880f, -0.890795f ),      Point3F( 0.063314f, 0.813233f, 0.578484f ),      Point3F( 0.322045f, 0.889086f, -0.325289f ),      Point3F( -0.133521f, 0.875063f, -0.465228f ),      Point3F( 0.637155f, 0.564814f, 0.524422f ),      Point3F( 0.260092f, -0.669353f, 0.695930f ),      Point3F( 0.953195f, 0.040485f, -0.299634f ),      Point3F( -0.840665f, -0.076509f, 0.536124f ),      Point3F( -0.971350f, 0.202093f, 0.125047f ),      Point3F( -0.804307f, -0.396312f, -0.442749f ),      Point3F( -0.936746f, 0.069572f, 0.343027f ),      Point3F( 0.426545f, -0.465962f, 0.775202f ),      Point3F( 0.794542f, -0.227450f, 0.563000f ),      Point3F( -0.892172f, 0.091169f, -0.442399f ),      Point3F( -0.312654f, 0.541264f, 0.780564f ),      Point3F( 0.590603f, -0.735618f, -0.331743f ),      Point3F( -0.098040f, -0.986713f, 0.129558f ),      Point3F( 0.569646f, 0.283078f, -0.771603f ),      Point3F( 0.431051f, -0.407385f, -0.805129f ),      Point3F( -0.162087f, -0.938749f, -0.304104f ),      Point3F( 0.241533f, -0.359509f, 0.901341f ),      Point3F( -0.576191f, 0.614939f, 0.538380f ),      Point3F( -0.025110f, 0.085740f, 0.996001f ),      Point3F( -0.352693f, -0.198168f, 0.914515f ),      Point3F( -0.604577f, 0.700711f, 0.378802f ),      Point3F( 0.465024f, 0.409667f, 0.784809f ),      Point3F( -0.254684f, -0.030474f, -0.966544f ),      Point3F( -0.604789f, 0.791809f, 0.085259f ),      Point3F( -0.705147f, -0.399298f, 0.585943f ),      Point3F( 0.185691f, 0.017236f, -0.982457f ),      Point3F( 0.044588f, 0.973094f, 0.226052f ),      Point3F( -0.405463f, 0.642367f, 0.650357f ),      Point3F( -0.563959f, 0.599136f, -0.568319f ),      Point3F( 0.367162f, -0.072253f, -0.927347f ),      Point3F( 0.960429f, -0.213570f, -0.178783f ),      Point3F( -0.192629f, 0.906005f, 0.376893f ),      Point3F( -0.199718f, -0.359865f, -0.911378f ),      Point3F( 0.485072f, 0.121233f, -0.866030f ),      Point3F( 0.467163f, -0.874294f, 0.131792f ),      Point3F( -0.638953f, -0.716603f, 0.279677f ),      Point3F( -0.622710f, 0.047813f, -0.780990f ),      Point3F( 0.828724f, -0.054433f, -0.557004f ),      Point3F( 0.130241f, 0.991080f, 0.028245f ),      Point3F( 0.310995f, -0.950076f, -0.025242f ),      Point3F( 0.818118f, 0.275336f, 0.504850f ),      Point3F( 0.676328f, 0.387023f, 0.626733f ),      Point3F( -0.100433f, 0.495114f, -0.863004f ),      Point3F( -0.949609f, -0.240681f, -0.200786f ),      Point3F( -0.102610f, 0.261831f, -0.959644f ),      Point3F( -0.845732f, -0.493136f, 0.203850f ),      Point3F( 0.672617f, -0.738838f, 0.041290f ),      Point3F( 0.380465f, 0.875938f, 0.296613f ),      Point3F( -0.811223f, 0.262027f, -0.522742f ),      Point3F( -0.074423f, -0.775670f, -0.626736f ),      Point3F( -0.286499f, 0.755850f, -0.588735f ),      Point3F( 0.291182f, -0.276189f, -0.915933f ),      Point3F( -0.638117f, 0.199338f, 0.743687f ),      Point3F( 0.439922f, -0.864433f, -0.243359f ),      Point3F( 0.177649f, 0.206919f, 0.962094f ),      Point3F( 0.277107f, 0.948521f, 0.153361f ),      Point3F( 0.507629f, 0.661918f, -0.551523f ),      Point3F( -0.503110f, -0.579308f, -0.641313f ),      Point3F( 0.600522f, 0.736495f, -0.311364f ),      Point3F( -0.691096f, -0.715301f, -0.103592f ),      Point3F( -0.041083f, -0.858497f, 0.511171f ),      Point3F( 0.207773f, -0.480062f, -0.852274f ),      Point3F( 0.795719f, 0.464614f, 0.388543f ),      Point3F( -0.100433f, 0.495114f, -0.863004f ),      Point3F( 0.703249f, 0.065157f, -0.707951f ),      Point3F( -0.324171f, -0.941112f, 0.096024f ),      Point3F( -0.134933f, -0.940212f, 0.312722f ),      Point3F( -0.438240f, 0.752088f, -0.492249f ),      Point3F( 0.964762f, -0.198855f, 0.172311f ),      Point3F( -0.831799f, 0.196807f, 0.519015f ),      Point3F( -0.508008f, 0.819902f, 0.263986f ),      Point3F( 0.471075f, -0.001146f, 0.882092f ),      Point3F( 0.919512f, 0.246162f, -0.306435f ),      Point3F( -0.960050f, 0.279828f, -0.001187f ),      Point3F( 0.110232f, -0.847535f, -0.519165f ),      Point3F( 0.208229f, 0.697360f, 0.685806f ),      Point3F( -0.199680f, -0.560621f, 0.803637f ),      Point3F( 0.170135f, -0.679985f, -0.713214f ),      Point3F( 0.758371f, -0.494907f, 0.424195f ),      Point3F( 0.077734f, -0.755978f, 0.649965f ),      Point3F( 0.612831f, -0.672475f, 0.414987f ),      Point3F( 0.142776f, 0.836698f, -0.528726f ),      Point3F( -0.765185f, 0.635778f, 0.101382f ),      Point3F( 0.669873f, -0.419737f, 0.612447f ),      Point3F( 0.593549f, 0.194879f, 0.780847f ),      Point3F( 0.646930f, 0.752173f, 0.125368f ),      Point3F( 0.837721f, 0.545266f, -0.030127f ),      Point3F( 0.541505f, 0.768070f, 0.341820f ),      Point3F( 0.760679f, -0.365715f, -0.536301f ),      Point3F( 0.381516f, 0.640377f, 0.666605f ),      Point3F( 0.565794f, -0.072415f, -0.821361f ),      Point3F( -0.466072f, -0.401588f, 0.788356f ),      Point3F( 0.987146f, 0.096290f, 0.127560f ),      Point3F( 0.509709f, -0.688886f, -0.515396f ),      Point3F( -0.135132f, -0.988046f, -0.074192f ),      Point3F( 0.600499f, 0.476471f, -0.642166f ),      Point3F( -0.732326f, -0.275320f, -0.622815f ),      Point3F( -0.881141f, -0.470404f, 0.048078f ),      Point3F( 0.051548f, 0.601042f, 0.797553f ),      Point3F( 0.402027f, -0.763183f, 0.505891f ),      Point3F( 0.404233f, -0.208288f, 0.890624f ),      Point3F( -0.311793f, 0.343843f, 0.885752f ),      Point3F( 0.098132f, -0.937014f, 0.335223f ),      Point3F( 0.537158f, 0.830585f, -0.146936f ),      Point3F( 0.725277f, 0.298172f, -0.620538f ),      Point3F( -0.882025f, 0.342976f, -0.323110f ),      Point3F( -0.668829f, 0.424296f, -0.610443f ),      Point3F( -0.408835f, -0.476442f, -0.778368f ),      Point3F( 0.809472f, 0.397249f, -0.432375f ),      Point3F( -0.909184f, -0.205938f, -0.361903f ),      Point3F( 0.866930f, -0.347934f, -0.356895f ),      Point3F( 0.911660f, -0.141281f, -0.385897f ),      Point3F( -0.431404f, -0.844074f, -0.318480f ),      Point3F( -0.950593f, -0.073496f, 0.301614f ),      Point3F( -0.719716f, 0.626915f, -0.298305f ),      Point3F( -0.779887f, 0.617067f, -0.104899f ),      Point3F( -0.475899f, -0.542630f, 0.692151f ),      Point3F( 0.081952f, -0.157248f, -0.984153f ),      Point3F( 0.923990f, -0.381662f, -0.024025f ),      Point3F( -0.957998f, 0.120979f, -0.260008f ),      Point3F( 0.306601f, 0.227975f, -0.924134f ),      Point3F( -0.141244f, 0.989182f, 0.039601f ),      Point3F( 0.077097f, 0.186288f, -0.979466f ),      Point3F( -0.630407f, -0.259801f, 0.731499f ),      Point3F( 0.718150f, 0.637408f, 0.279233f ),      Point3F( 0.340946f, 0.110494f, 0.933567f ),      Point3F( -0.396671f, 0.503020f, -0.767869f ),      Point3F( 0.636943f, -0.245005f, 0.730942f ),      Point3F( -0.849605f, -0.518660f, -0.095724f ),      Point3F( -0.388203f, 0.105395f, 0.915527f ),      Point3F( -0.280671f, -0.776541f, -0.564099f ),      Point3F( -0.601680f, 0.215451f, -0.769131f ),      Point3F( -0.660112f, -0.632371f, -0.405412f ),      Point3F( 0.921096f, 0.284072f, 0.266242f ),      Point3F( 0.074850f, -0.300846f, 0.950731f ),      Point3F( 0.943952f, -0.067062f, 0.323198f ),      Point3F( -0.917838f, -0.254589f, 0.304561f ),      Point3F( 0.889843f, -0.409008f, 0.202219f ),      Point3F( -0.565849f, 0.753721f, -0.334246f ),      Point3F( 0.791460f, 0.555918f, -0.254060f ),      Point3F( 0.261936f, 0.703590f, -0.660568f ),      Point3F( -0.234406f, 0.952084f, 0.196444f ),      Point3F( 0.111205f, 0.979492f, -0.168014f ),      Point3F( -0.869844f, -0.109095f, -0.481113f ),      Point3F( -0.337728f, -0.269701f, -0.901777f ),      Point3F( 0.366793f, 0.408875f, -0.835634f ),      Point3F( -0.098749f, 0.261316f, 0.960189f ),      Point3F( -0.272379f, -0.847100f, 0.456324f ),      Point3F( -0.319506f, 0.287444f, -0.902935f ),      Point3F( 0.873383f, -0.294109f, 0.388203f ),      Point3F( -0.088950f, 0.710450f, 0.698104f ),      Point3F( 0.551238f, -0.786552f, 0.278340f ),      Point3F( 0.724436f, -0.663575f, -0.186712f ),      Point3F( 0.529741f, -0.606539f, 0.592861f ),      Point3F( -0.949743f, -0.282514f, 0.134809f ),      Point3F( 0.155047f, 0.419442f, -0.894443f ),      Point3F( -0.562653f, -0.329139f, -0.758346f ),      Point3F( 0.816407f, -0.576953f, 0.024576f ),      Point3F( 0.178550f, -0.950242f, -0.255266f ),      Point3F( 0.479571f, 0.706691f, 0.520192f ),      Point3F( 0.391687f, 0.559884f, -0.730145f ),      Point3F( 0.724872f, -0.205570f, -0.657496f ),      Point3F( -0.663196f, -0.517587f, -0.540624f ),      Point3F( -0.660054f, -0.122486f, -0.741165f ),      Point3F( -0.531989f, 0.374711f, -0.759328f ),      Point3F( 0.194979f, -0.059120f, 0.979024f )};U8 TSMesh::encodeNormal( const Point3F &normal ){   U8 bestIndex = 0;   F32 bestDot = -10E30f;   for ( U32 i = 0; i < 256; i++ )   {      F32 dot = mDot( normal, smU8ToNormalTable[i] );      if ( dot > bestDot )      {         bestIndex = i;         bestDot = dot;      }   }   return bestIndex;}//-----------------------------------------------------// TSMesh assemble from/ dissemble to memory buffer//-----------------------------------------------------#define tsalloc TSShape::smTSAllocTSMesh* TSMesh::assembleMesh( U32 meshType, bool skip ){   static TSMesh tempStandardMesh;   static TSSkinMesh tempSkinMesh;   static TSDecalMesh tempDecalMesh;   static TSSortedMesh tempSortedMesh;   bool justSize = skip || !tsalloc.allocShape32(0); // if this returns NULL, we're just sizing memory block   // a little funny business because we pretend decals are derived from meshes   S32 * ret = NULL;   TSMesh * mesh = NULL;   TSDecalMesh * decal = NULL;   if ( justSize )   {      switch ( meshType )      {         case StandardMeshType :         {            ret = (S32*)&tempStandardMesh;            mesh = &tempStandardMesh;            tsalloc.allocShape32( sizeof(TSMesh) >> 2 );            break;         }         case SkinMeshType     :         {            ret = (S32*)&tempSkinMesh;            mesh = &tempSkinMesh;            tsalloc.allocShape32( sizeof(TSSkinMesh) >> 2 );            break;         }         case DecalMeshType    :         {            ret = (S32*)&tempDecalMesh;            decal = &tempDecalMesh;            tsalloc.allocShape32( sizeof(TSDecalMesh) >> 2 );            break;         }         case SortedMeshType   :         {            ret = (S32*)&tempSortedMesh;            mesh = &tempSortedMesh;            tsalloc.allocShape32( sizeof(TSSortedMesh) >> 2 );            break;         }      }   }   else   {      switch ( meshType )      {         case StandardMeshType :         {            ret = tsalloc.allocShape32( sizeof(TSMesh) >> 2 );            constructInPlace( (TSMesh*)ret );            mesh = (TSMesh*)ret;            break;         }         case SkinMeshType     :         {            ret = tsalloc.allocShape32( sizeof(TSSkinMesh) >> 2 );            constructInPlace( (TSSkinMesh*)ret );            mesh = (TSSkinMesh*)ret;            break;         }         case DecalMeshType    :         {            ret = tsalloc.allocShape32( sizeof(TSDecalMesh) >> 2 );            constructInPlace((TSDecalMesh*)ret);            decal = (TSDecalMesh*)ret;            break;         }         case SortedMeshType   :         {            ret = tsalloc.allocShape32( sizeof(TSSortedMesh) >> 2 );            constructInPlace( (TSSortedMesh*)ret );            mesh = (TSSortedMesh*)ret;            break;         }      }   }   tsalloc.setSkipMode( skip );   if ( mesh )      mesh->assemble( skip );   if ( decal )      decal->assemble( skip );   tsalloc.setSkipMode( false );   return (TSMesh*)ret;}void TSMesh::convertToTris(	const TSDrawPrimitive *primitivesIn,							         const S32 *indicesIn,                           	S32 numPrimIn,         							S32 &numPrimOut,          							S32 &numIndicesOut,                           	TSDrawPrimitive *primitivesOut, 							         S32 *indicesOut ) const{   S32 prevMaterial = -99999;   TSDrawPrimitive * newDraw = NULL;   numPrimOut = 0;   numIndicesOut = 0;   for ( S32 i = 0; i < numPrimIn; i++ )   {      S32 newMat = primitivesIn[i].matIndex;      newMat &= ~TSDrawPrimitive::TypeMask;      U32 start = primitivesIn[i].start;      U32 prevStart = (i > 0) ? primitivesIn[i-1].start : start;      U32 numElements = primitivesIn[i].numElements;      // Add a new primitive if changing materials, or if this primitive      // indexes vertices in a different 16-bit range      if ( ( newMat != prevMaterial ) ||           ((indicesIn[prevStart] ^ indicesIn[start]) & 0xFFFF0000) )      {         if ( primitivesOut )         {            newDraw = &primitivesOut[numPrimOut];            newDraw->start = numIndicesOut;            newDraw->numElements = 0;            newDraw->matIndex = newMat | TSDrawPrimitive::Triangles;         }         numPrimOut++;         prevMaterial = newMat;      }      // gonna depend on what kind of primitive it is...      if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)      {         for ( S32 j = 0; j < numElements; j += 3 )         {            if ( indicesOut )            {               indicesOut[numIndicesOut + 0] = indicesIn[start + j + 0];               indicesOut[numIndicesOut + 1] = indicesIn[start + j + 1];               indicesOut[numIndicesOut + 2] = indicesIn[start + j + 2];            }            if ( newDraw )               newDraw->numElements += 3;            numIndicesOut += 3;         }      }      else      {         U32 idx0 = indicesIn[start + 0];         U32 idx1;         U32 idx2 = indicesIn[start + 1];         U32 * nextIdx = &idx1;         for ( S32 j = 2; j < numElements; j++ )         {            *nextIdx = idx2;            nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);            idx2 = indicesIn[start + j];            if ( idx0 == idx1 || idx1 == idx2 || idx2 == idx0 )               continue;            if ( indicesOut )            {               indicesOut[numIndicesOut+0] = idx0;               indicesOut[numIndicesOut+1] = idx1;               indicesOut[numIndicesOut+2] = idx2;            }            if ( newDraw )               newDraw->numElements += 3;            numIndicesOut += 3;         }      }   }}void unwindStrip( const S32 * indices, S32 numElements, Vector<S32> &triIndices ){   U32 idx0 = indices[0];   U32 idx1;   U32 idx2 = indices[1];   U32 * nextIdx = &idx1;   for ( S32 j = 2; j < numElements; j++ )   {      *nextIdx = idx2;      nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);      idx2 = indices[j];      if ( idx0 == idx1 || idx1 == idx2 || idx2 == idx0 )         continue;      triIndices.push_back( idx0 );      triIndices.push_back( idx1 );      triIndices.push_back( idx2 );   }}void TSMesh::convertToSingleStrip(	const TSDrawPrimitive *primitivesIn, 									         const S32 *indicesIn,                                  	S32 numPrimIn,          									S32 &numPrimOut,          									S32 &numIndicesOut,         									TSDrawPrimitive *primitivesOut,         									S32 *indicesOut ) const{   S32 prevMaterial = -99999;   TSDrawPrimitive * newDraw = NULL;   TSDrawPrimitive * newTris = NULL;   Vector<S32> triIndices;   S32 curDrawOut = 0;   numPrimOut = 0;   numIndicesOut = 0;   for ( S32 i = 0; i < numPrimIn; i++ )   {      S32 newMat = primitivesIn[i].matIndex;      U32 start = primitivesIn[i].start;      U32 prevStart = (i > 0) ? primitivesIn[i-1].start : start;      U32 numElements = primitivesIn[i].numElements;      // Add a new primitive if changing materials, or if this primitive      // indexes vertices in a different 16-bit range      if ( ( newMat != prevMaterial ) ||           ((indicesIn[prevStart] ^ indicesIn[start]) & 0xFFFF0000) )      {         // before adding the new primitive, transfer triangle indices         if ( triIndices.size() )         {            if ( newTris && indicesOut )            {               newTris->start = numIndicesOut;               newTris->numElements = triIndices.size();               dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32));            }            numIndicesOut += triIndices.size();            triIndices.clear();            newTris = NULL;         }         if ( primitivesOut )         {            newDraw = &primitivesOut[numPrimOut];            newDraw->start = numIndicesOut;            newDraw->numElements = 0;            newDraw->matIndex = newMat;         }         numPrimOut++;         curDrawOut = 0;         prevMaterial = newMat;      }      // gonna depend on what kind of primitive it is...      // from above we know it's the same kind as the one we're building...      if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)      {         // triangles primitive...add to it         for ( S32 j = 0; j < numElements; j += 3 )         {            if ( indicesOut )            {               indicesOut[numIndicesOut + 0] = indicesIn[start + j + 0];               indicesOut[numIndicesOut + 1] = indicesIn[start + j + 1];               indicesOut[numIndicesOut + 2] = indicesIn[start + j + 2];            }            if ( newDraw )               newDraw->numElements += 3;                        numIndicesOut += 3;         }      }      else      {         // strip primitive...         // if numElements less than smSmallestStripSize, add to triangles...         if ( numElements < smMinStripSize + 2 )         {            // put triangle indices aside until material changes...            if ( triIndices.empty() )            {               // set up for new triangle primitive and add it if we are copying data right now               if ( primitivesOut )               {                  newTris = &primitivesOut[numPrimOut];                  newTris->matIndex  = newMat;                  newTris->matIndex &= ~(TSDrawPrimitive::Triangles|TSDrawPrimitive::Strip);                  newTris->matIndex |= TSDrawPrimitive::Triangles;               }               numPrimOut++;            }            unwindStrip( indicesIn + start, numElements, triIndices );         }         else         {            // strip primitive...add to it            if ( indicesOut )            {               if ( curDrawOut & 1 )               {                  indicesOut[numIndicesOut + 0] = indicesOut[numIndicesOut - 1];                  indicesOut[numIndicesOut + 1] = indicesOut[numIndicesOut - 1];                  indicesOut[numIndicesOut + 2] = indicesIn[start];                  dMemcpy(indicesOut+numIndicesOut+3,indicesIn+start,numElements*sizeof(U32));               }               else if ( curDrawOut )               {                  indicesOut[numIndicesOut + 0] = indicesOut[numIndicesOut - 1];                  indicesOut[numIndicesOut + 1] = indicesIn[start];                  dMemcpy(indicesOut+numIndicesOut+2,indicesIn+start,numElements*sizeof(U32));               }               else                  dMemcpy(indicesOut+numIndicesOut,indicesIn+start,numElements*sizeof(U32));            }            S32 added = numElements;            added += curDrawOut ? (curDrawOut&1 ? 3 : 2) : 0;            if ( newDraw )               newDraw->numElements += added;                        numIndicesOut += added;            curDrawOut += added;         }      }   }   // spit out tris before leaving   // before adding the new primitive, transfer triangle indices   if ( triIndices.size() )   {      if ( newTris && indicesOut )      {         newTris->start = numIndicesOut;         newTris->numElements = triIndices.size();         dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32));      }      numIndicesOut += triIndices.size();      triIndices.clear();      newTris = NULL;   }}// this method does none of the converting that the above methods do, except that small strips are converted// to triangle lists...void TSMesh::leaveAsMultipleStrips(	const TSDrawPrimitive *primitivesIn, 									         const S32 *indicesIn,                                   	S32 numPrimIn,          									S32 &numPrimOut,          									S32 &numIndicesOut,                                   	TSDrawPrimitive *primitivesOut, 									         S32 *indicesOut ) const{   S32 prevMaterial = -99999;   TSDrawPrimitive * newDraw = NULL;   Vector<S32> triIndices;   numPrimOut = 0;   numIndicesOut = 0;   for ( S32 i = 0; i < numPrimIn; i++ )   {      S32 newMat = primitivesIn[i].matIndex;      U32 start = primitivesIn[i].start;      U32 prevStart = (i > 0) ? primitivesIn[i-1].start : start;      U32 numElements = primitivesIn[i].numElements;      // Add a new primitive if changing materials, or if this primitive      // indexes vertices in a different 16-bit range      if ( triIndices.size() &&           (( newMat != prevMaterial ) ||           ((indicesIn[prevStart] ^ indicesIn[start]) & 0xFFFF0000) ))      {         // material just changed and we have triangles lying around         // add primitive and indices for triangles and clear triIndices         if ( indicesOut )         {            TSDrawPrimitive * newTris = &primitivesOut[numPrimOut];            newTris->matIndex = prevMaterial;            newTris->matIndex &= ~(TSDrawPrimitive::Triangles|TSDrawPrimitive::Strip);            newTris->matIndex |= TSDrawPrimitive::Triangles;            newTris->start = numIndicesOut;            newTris->numElements = triIndices.size();            dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32));         }         numPrimOut++;         numIndicesOut += triIndices.size();         triIndices.clear();      }      // this is a little convoluted because this code was adapted from convertToSingleStrip      // but we will need a new primitive only if it is a triangle primitive coming in      // or we have more elements than the min strip size...      if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles || numElements>=smMinStripSize+2)      {         if ( primitivesOut )         {            newDraw = &primitivesOut[numPrimOut];            newDraw->start = numIndicesOut;            newDraw->numElements = 0;            newDraw->matIndex = newMat;         }         numPrimOut++;      }      prevMaterial = newMat;      // gonna depend on what kind of primitive it is...      // from above we know it's the same kind as the one we're building...      if ( (primitivesIn[i].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)      {         // triangles primitive...add to it         for ( S32 j = 0; j < numElements; j += 3 )         {            if ( indicesOut )            {               indicesOut[numIndicesOut + 0] = indicesIn[start + j + 0];               indicesOut[numIndicesOut + 1] = indicesIn[start + j + 1];               indicesOut[numIndicesOut + 2] = indicesIn[start + j + 2];            }            if ( newDraw )               newDraw->numElements += 3;                        numIndicesOut += 3;         }      }      else      {         // strip primitive...         // if numElements less than smSmallestStripSize, add to triangles...         if ( numElements < smMinStripSize + 2 )            // put triangle indices aside until material changes...            unwindStrip( indicesIn + start, numElements, triIndices );         else         {            // strip primitive...add to it            if ( indicesOut )               dMemcpy(indicesOut+numIndicesOut,indicesIn+start,numElements*sizeof(U32));            if ( newDraw )               newDraw->numElements = numElements;                        numIndicesOut += numElements;         }      }   }   // spit out tris before leaving   if ( triIndices.size() )   {      // material just changed and we have triangles lying around      // add primitive and indices for triangles and clear triIndices      if ( indicesOut )      {         TSDrawPrimitive *newTris = &primitivesOut[numPrimOut];         newTris->matIndex = prevMaterial;         newTris->matIndex &= ~(TSDrawPrimitive::Triangles|TSDrawPrimitive::Strip);         newTris->matIndex |= TSDrawPrimitive::Triangles;         newTris->start = numIndicesOut;         newTris->numElements = triIndices.size();         dMemcpy(&indicesOut[numIndicesOut],triIndices.address(),triIndices.size()*sizeof(U32));      }      numPrimOut++;      numIndicesOut += triIndices.size();      triIndices.clear();   }}// This method retrieves data that is shared (or possibly shared) between different meshes.// This adds an extra step to the copying of data from the memory buffer to the shape data buffer.// If we have no parentMesh, then we either return a pointer to the data in the memory buffer// (in the case that we skip this mesh) or copy the data into the shape data buffer and return// that pointer (in the case that we don't skip this mesh).// If we do have a parent mesh, then we return a pointer to the data in the shape buffer,// copying the data in there ourselves if our parent didn't already do it (i.e., if it was skipped).S32 * TSMesh::getSharedData32( S32 parentMesh, S32 size, S32 **source, bool skip ){   S32 * ptr;   if( parentMesh < 0 )      ptr = skip ? tsalloc.getPointer32( size ) : tsalloc.copyToShape32( size );   else   {      ptr = source[parentMesh];      // if we skipped the previous mesh (and we're not skipping this one) then      // we still need to copy points into the shape...      if ( !smDataCopied[parentMesh] && !skip )      {         S32 * tmp = ptr;         ptr = tsalloc.allocShape32( size );         if ( ptr && tmp )            dMemcpy(ptr, tmp, size * sizeof(S32) );      }    }   return ptr;}S8 * TSMesh::getSharedData8( S32 parentMesh, S32 size, S8 **source, bool skip ){   S8 * ptr;   if( parentMesh < 0 )      ptr = skip ? tsalloc.getPointer8( size ) : tsalloc.copyToShape8( size );   else   {      ptr = source[parentMesh];      // if we skipped the previous mesh (and we're not skipping this one) then      // we still need to copy points into the shape...      if ( !smDataCopied[parentMesh] && !skip )      {         S8 * tmp = ptr;         ptr = tsalloc.allocShape8( size );         if ( ptr && tmp )            dMemcpy( ptr, tmp, size * sizeof(S32) );      }   }   return ptr;}void TSMesh::dumpPrimitives(U32 startVertex, U32 startIndex, GFXPrimitive *piArray, U16* ibIndices){   // go through and create PrimitiveInfo array   GFXPrimitive pInfo;   U32 primitivesSize = mPrimitives.size();   for (U32 i = 0; i < primitivesSize; i++)   {      const TSDrawPrimitive & draw = mPrimitives[i];      GFXPrimitiveType drawType = getDrawType(draw.matIndex >> 30);      switch (drawType)      {      case GFXTriangleList:         pInfo.type = drawType;         pInfo.numPrimitives = draw.numElements / 3;         pInfo.startIndex = startIndex + draw.start;         // Use the first index to determine which 16-bit address space we are operating in         pInfo.startVertex = (mIndices[draw.start] & 0xFFFF0000); // TODO: figure out a good solution for this         pInfo.minIndex = 0; // minIndex are zero based index relative to startVertex. See @GFXDevice         pInfo.numVertices = getMin((U32)0x10000, mNumVerts - pInfo.startVertex);         pInfo.startVertex += startVertex;         break;      case GFXTriangleStrip:         pInfo.type = drawType;         pInfo.numPrimitives = draw.numElements - 2;         pInfo.startIndex = startIndex + draw.start;         // Use the first index to determine which 16-bit address space we are operating in         pInfo.startVertex = (mIndices[draw.start] & 0xFFFF0000); // TODO: figure out a good solution for this         pInfo.minIndex = 0; // minIndex are zero based index relative to startVertex. See @GFXDevice         pInfo.numVertices = getMin((U32)0x10000, mNumVerts - pInfo.startVertex);         pInfo.startVertex += startVertex;         break;      default:         AssertFatal(false, "WTF?!");      }      *piArray++ = pInfo;   }   dCopyArray(ibIndices, mIndices.address(), mIndices.size());}void TSMesh::assemble( bool skip ){   tsalloc.checkGuard();   numFrames = tsalloc.get32();   numMatFrames = tsalloc.get32();   mParentMesh = tsalloc.get32();   tsalloc.get32( (S32*)&mBounds, 6 );   tsalloc.get32( (S32*)&mCenter, 3 );   mRadius = (F32)tsalloc.get32();   if (TSShape::smReadVersion >= 27)   {      // Offsetted      mVertOffset = tsalloc.get32();      mNumVerts = tsalloc.get32();      mVertSize = tsalloc.get32();   }   else   {      mVertOffset = 0;      mNumVerts = 0;      mVertSize = 0;   }   S32 numVerts = tsalloc.get32();   S32 *ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smVertsList.address(), skip );   mVerts.set( (Point3F*)ptr32, numVerts );   S32 numTVerts = tsalloc.get32();   ptr32 = getSharedData32(mParentMesh, 2 * numTVerts, (S32**)smTVertsList.address(), skip );   mTverts.set( (Point2F*)ptr32, numTVerts );   if ( TSShape::smReadVersion > 25 )   {      numTVerts = tsalloc.get32();      ptr32 = getSharedData32(mParentMesh, 2 * numTVerts, (S32**)smTVerts2List.address(), skip );      mTverts2.set( (Point2F*)ptr32, numTVerts );      S32 numVColors = tsalloc.get32();      ptr32 = getSharedData32(mParentMesh, numVColors, (S32**)smColorsList.address(), skip );      mColors.set( (ColorI*)ptr32, numVColors );   }   S8 *ptr8;   if ( TSShape::smReadVersion > 21 && TSMesh::smUseEncodedNormals)   {      // we have encoded normals and we want to use them...      if (mParentMesh < 0 )         tsalloc.getPointer32( numVerts * 3 ); // adva  nce past norms, don't use      mNorms.set( NULL, 0 );      ptr8 = getSharedData8(mParentMesh, numVerts, (S8**)smEncodedNormsList.address(), skip );      mEncodedNorms.set( ptr8, numVerts );   }   else if ( TSShape::smReadVersion > 21 )   {      // we have encoded normals but we don't want to use them...      ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip );      mNorms.set( (Point3F*)ptr32, numVerts );      if (mParentMesh < 0 )         tsalloc.getPointer8( numVerts ); // advance past encoded normls, don't use      mEncodedNorms.set( NULL, 0 );   }   else   {      // no encoded normals...      ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip );      mNorms.set( (Point3F*)ptr32, numVerts );      mEncodedNorms.set( NULL, 0 );   }   // copy the primitives and indices...how we do this depends on what   // form we want them in when copied...just get pointers to data for now   S32 szPrimIn, szIndIn;   TSDrawPrimitive *primIn;   S32 *indIn;   bool deleteInputArrays = false;   if (TSShape::smReadVersion > 25)   {      // mesh primitives (start, numElements) and indices are stored as 32 bit values      szPrimIn = tsalloc.get32();      primIn = (TSDrawPrimitive*)tsalloc.getPointer32(szPrimIn*3);      szIndIn = tsalloc.get32();      indIn = tsalloc.getPointer32(szIndIn);   }   else   {      // mesh primitives (start, numElements) indices are stored as 16 bit values      szPrimIn = tsalloc.get32();      S16 *prim16 = tsalloc.getPointer16(szPrimIn*2);   // primitive: start, numElements      S32 *prim32 = tsalloc.getPointer32(szPrimIn);     // primitive: matIndex      szIndIn = tsalloc.get32();      // warn about non-addressable indices      if ( !skip && szIndIn >= 0x10000 )      {         Con::warnf("Mesh contains non-addressable indices, and may not render "            "correctly. Either split this mesh into pieces of no more than 65k "            "unique verts prior to export, or use COLLADA.");      }      S16 *ind16 = tsalloc.getPointer16(szIndIn);      // need to copy to temporary arrays      deleteInputArrays = true;      primIn = new TSDrawPrimitive[szPrimIn];      for (S32 i = 0; i < szPrimIn; i++)      {         primIn[i].start = prim16[i*2];         primIn[i].numElements = prim16[i*2+1];         primIn[i].matIndex = prim32[i];      }      indIn = new S32[szIndIn];      dCopyArray(indIn, ind16, szIndIn);   }   // count the number of output primitives and indices   S32 szPrimOut = szPrimIn, szIndOut = szIndIn;   if (smUseTriangles)      convertToTris(primIn, indIn, szPrimIn, szPrimOut, szIndOut, NULL, NULL);   else if (smUseOneStrip)      convertToSingleStrip(primIn, indIn, szPrimIn, szPrimOut, szIndOut, NULL, NULL);   else      leaveAsMultipleStrips(primIn, indIn, szPrimIn, szPrimOut, szIndOut, NULL, NULL);   // allocate enough space for the new primitives and indices (all 32 bits)   TSDrawPrimitive *primOut = (TSDrawPrimitive*)tsalloc.allocShape32(3*szPrimOut);   S32 *indOut = tsalloc.allocShape32(szIndOut);   // copy output primitives and indices   S32 chkPrim = szPrimOut, chkInd = szIndOut;   if (smUseTriangles)      convertToTris(primIn, indIn, szPrimIn, chkPrim, chkInd, primOut, indOut);   else if (smUseOneStrip)      convertToSingleStrip(primIn, indIn, szPrimIn, chkPrim, chkInd, primOut, indOut);   else      leaveAsMultipleStrips(primIn, indIn, szPrimIn, chkPrim, chkInd, primOut, indOut);   AssertFatal(chkPrim==szPrimOut && chkInd==szIndOut,"TSMesh::primitive conversion");   // store output   mPrimitives.set(primOut, szPrimOut);   mIndices.set(indOut, szIndOut);   // delete temporary arrays if necessary   if (deleteInputArrays)   {      delete [] primIn;      delete [] indIn;   }   S32 sz = tsalloc.get32();   tsalloc.getPointer16( sz ); // skip deprecated merge indices   tsalloc.align32();   vertsPerFrame = tsalloc.get32();   U32 flags = (U32)tsalloc.get32();   if ( mEncodedNorms.size() )      flags |= UseEncodedNormals;      setFlags( flags );   // Set color & tvert2 flags if we have an old version   if (TSShape::smReadVersion < 27)   {      if (mColors.size() > 0) setFlags(HasColor);      if (mTverts2.size() > 0) setFlags(HasTVert2);      mNumVerts = mVerts.size();   }   tsalloc.checkGuard();   if ( tsalloc.allocShape32( 0 ) && TSShape::smReadVersion < 19 )      computeBounds(); // only do this if we copied the data...   createTangents(mVerts, mNorms);}void TSMesh::disassemble(){   tsalloc.setGuard();   tsalloc.set32( numFrames );   tsalloc.set32( numMatFrames );   tsalloc.set32(mParentMesh);   tsalloc.copyToBuffer32( (S32*)&mBounds, 6 );   tsalloc.copyToBuffer32( (S32*)&mCenter, 3 );   tsalloc.set32( (S32)mRadius );   bool shouldMakeEditable = TSShape::smVersion < 27 || mVertSize == 0;   // Re-create the vectors   if (shouldMakeEditable)   {      makeEditable();      // No Offset      if (TSShape::smVersion >= 27)      {         tsalloc.set32(0);         tsalloc.set32(0);         tsalloc.set32(0);      }   }   else   {      // Offsetted      tsalloc.set32(mVertOffset);      tsalloc.set32(mNumVerts);      tsalloc.set32(mVertSize);      AssertFatal(mNumVerts >= vertsPerFrame, "invalid mNumVerts");   }   if (TSShape::smVersion >= 27 && mVertexData.isReady())   {      // If not editable  all arrays are effectively 0.      tsalloc.set32(0); // verts      tsalloc.set32(0); // tverts      tsalloc.set32(0); // tverts2      tsalloc.set32(0); // colors   }   else   {      // verts...      tsalloc.set32(mVerts.size());      if (mParentMesh < 0)         tsalloc.copyToBuffer32((S32*)mVerts.address(), 3 * mVerts.size()); // if no parent mesh, then save off our verts      // tverts...      tsalloc.set32(mTverts.size());      if (mParentMesh < 0)         tsalloc.copyToBuffer32((S32*)mTverts.address(), 2 * mTverts.size()); // if no parent mesh, then save off our tverts      if (TSShape::smVersion > 25)      {         // tverts2...         tsalloc.set32(mTverts2.size());         if (mParentMesh < 0)            tsalloc.copyToBuffer32((S32*)mTverts2.address(), 2 * mTverts2.size()); // if no parent mesh, then save off our tverts                                                                                 // colors         tsalloc.set32(mColors.size());         if (mParentMesh < 0)            tsalloc.copyToBuffer32((S32*)mColors.address(), mColors.size()); // if no parent mesh, then save off our tverts      }      // norms...      if (mParentMesh < 0) // if no parent mesh, then save off our norms         tsalloc.copyToBuffer32((S32*)mNorms.address(), 3 * mNorms.size()); // norms.size()==verts.size() or error...                                                                          // encoded norms...      if (mParentMesh < 0)      {         // if no parent mesh, compute encoded normals and copy over         for (S32 i = 0; i < mNorms.size(); i++)         {            U8 normIdx = mEncodedNorms.size() ? mEncodedNorms[i] : encodeNormal(mNorms[i]);            tsalloc.copyToBuffer8((S8*)&normIdx, 1);         }      }   }   // optimize triangle draw order during disassemble   {      FrameTemp<TriListOpt::IndexType> tmpIdxs(mIndices.size());      for ( S32 i = 0; i < mPrimitives.size(); i++ )      {         const TSDrawPrimitive& prim = mPrimitives[i];         // only optimize triangle lists (strips and fans are assumed to be already optimized)         if ( (prim.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles )         {            TriListOpt::OptimizeTriangleOrdering(mVerts.size(), prim.numElements,				mIndices.address() + prim.start, tmpIdxs.address());            dCopyArray(mIndices.address() + prim.start, tmpIdxs.address(),               prim.numElements);         }      }   }   if (TSShape::smVersion > 25)   {      // primitives...      tsalloc.set32(mPrimitives.size() );      tsalloc.copyToBuffer32((S32*)mPrimitives.address(),3* mPrimitives.size());      // indices...      tsalloc.set32(mIndices.size());      tsalloc.copyToBuffer32((S32*)mIndices.address(),mIndices.size());   }   else   {      // primitives      tsalloc.set32(mPrimitives.size() );      for (S32 i=0; i<mPrimitives.size(); i++)      {         S16 start = (S16)mPrimitives[i].start;         S16 numElements = (S16)mPrimitives[i].numElements;         tsalloc.copyToBuffer16(&start, 1);         tsalloc.copyToBuffer16(&numElements, 1);         tsalloc.copyToBuffer32(&(mPrimitives[i].matIndex), 1);      }      // indices      tsalloc.set32(mIndices.size());      Vector<S16> s16_indices(mIndices.size());      for (S32 i=0; i<mIndices.size(); i++)         s16_indices.push_back((S16)mIndices[i]);      tsalloc.copyToBuffer16(s16_indices.address(), s16_indices.size());   }   // merge indices...DEPRECATED   tsalloc.set32( 0 );   // small stuff...   tsalloc.set32( vertsPerFrame );   tsalloc.set32( getFlags() );   tsalloc.setGuard();}//-----------------------------------------------------------------------------// TSSkinMesh assemble from/ dissemble to memory buffer//-----------------------------------------------------------------------------void TSSkinMesh::assemble( bool skip ){   // avoid a crash on computeBounds...   batchData.initialVerts.set( NULL, 0 );   TSMesh::assemble( skip );   if (TSShape::smReadVersion >= 27)   {      maxBones = tsalloc.get32();   }   else   {      maxBones = -1;   }   S32 sz;   S32 * ptr32;   if (TSShape::smReadVersion < 27)   {      sz = tsalloc.get32();      S32 numVerts = sz;      ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smVertsList.address(), skip);      batchData.initialVerts.set((Point3F*)ptr32, sz);      S8 * ptr8;      if (TSShape::smReadVersion > 21 && TSMesh::smUseEncodedNormals)      {         // we have encoded normals and we want to use them...         if (mParentMesh < 0)            tsalloc.getPointer32(numVerts * 3); // advance past norms, don't use         batchData.initialNorms.set(NULL, 0);         ptr8 = getSharedData8(mParentMesh, numVerts, (S8**)smEncodedNormsList.address(), skip);         mEncodedNorms.set(ptr8, numVerts);         // Note: we don't set the encoded normals flag because we handle them in updateSkin and         //       hide the fact that we are using them from base class (TSMesh)      }      else if (TSShape::smReadVersion > 21)      {         // we have encoded normals but we don't want to use them...         ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip);         batchData.initialNorms.set((Point3F*)ptr32, numVerts);         if (mParentMesh < 0)            tsalloc.getPointer8(numVerts); // advance past encoded normls, don't use		 mEncodedNorms.set(NULL, 0);      }      else      {         // no encoded normals...         ptr32 = getSharedData32(mParentMesh, 3 * numVerts, (S32**)smNormsList.address(), skip);         batchData.initialNorms.set((Point3F*)ptr32, numVerts);		 mEncodedNorms.set(NULL, 0);      }      // Sometimes we'll have a mesh with 0 verts but initialVerts is set,      // so set these accordingly      if (mVerts.size() == 0)      {		  mVerts = batchData.initialVerts;      }      if (mNorms.size() == 0)      {		  mNorms = batchData.initialNorms;      }   }   else   {      // Set from the mesh data      batchData.initialVerts = mVerts;      batchData.initialNorms = mNorms;   }   sz = tsalloc.get32();   ptr32 = getSharedData32(mParentMesh, 16 * sz, (S32**)smInitTransformList.address(), skip );   batchData.initialTransforms.set( ptr32, sz );   sz = tsalloc.get32();   ptr32 = getSharedData32(mParentMesh, sz, (S32**)smVertexIndexList.address(), skip );   vertexIndex.set( ptr32, sz );   ptr32 = getSharedData32(mParentMesh, sz, (S32**)smBoneIndexList.address(), skip );   boneIndex.set( ptr32, sz );   ptr32 = getSharedData32(mParentMesh, sz, (S32**)smWeightList.address(), skip );   weight.set( (F32*)ptr32, sz );   sz = tsalloc.get32();   ptr32 = getSharedData32(mParentMesh, sz, (S32**)smNodeIndexList.address(), skip );   batchData.nodeIndex.set( ptr32, sz );   tsalloc.checkGuard();   if (smDebugSkinVerts && ptr32 != NULL)   {      Con::printf("Loaded skin verts...");      for (U32 i = 0; i < vertexIndex.size(); i++)      {         Con::printf("vi[%i] == %i", i, vertexIndex[i]);      }      for (U32 i = 0; i < boneIndex.size(); i++)      {         Con::printf("bi[%i] == %i", i, boneIndex[i]);      }      for (U32 i = 0; i < batchData.nodeIndex.size(); i++)      {         Con::printf("ni[%i] == %i", i, batchData.nodeIndex[i]);      }      for (U32 i = 0; i < boneIndex.size(); i++)      {         Con::printf("we[%i] == %f", i, weight[i]);      }      if (mNumVerts != 0)      {         AssertFatal(batchData.initialVerts.size() == mNumVerts, "err WTF");      }      Con::printf("---");   }   if ( tsalloc.allocShape32( 0 ) && TSShape::smReadVersion < 19 )      TSMesh::computeBounds(); // only do this if we copied the data...c}//-----------------------------------------------------------------------------// disassemble//-----------------------------------------------------------------------------void TSSkinMesh::disassemble(){   TSMesh::disassemble();   if (TSShape::smVersion >= 27)   {      AssertFatal(maxBones != 0, "Skin mesh with no bones? No way!");      tsalloc.set32(maxBones);   }   if (TSShape::smVersion < 27)   {      tsalloc.set32(batchData.initialVerts.size());      // if we have no parent mesh, then save off our verts & norms      if (mParentMesh < 0)      {         tsalloc.copyToBuffer32((S32*)mVerts.address(), 3 * mVerts.size());         // no longer do this here...let tsmesh handle this         tsalloc.copyToBuffer32((S32*)mNorms.address(), 3 * mNorms.size());         // if no parent mesh, compute encoded normals and copy over         for (S32 i = 0; i < mNorms.size(); i++)         {            U8 normIdx = mEncodedNorms.size() ? mEncodedNorms[i] : encodeNormal(mNorms[i]);            tsalloc.copyToBuffer8((S8*)&normIdx, 1);         }      }   }   tsalloc.set32( batchData.initialTransforms.size() );   if (mParentMesh < 0 )      tsalloc.copyToBuffer32( (S32*)batchData.initialTransforms.address(), batchData.initialTransforms.size() * 16 );   if (!mVertexData.isReady())   {      tsalloc.set32(vertexIndex.size());      tsalloc.copyToBuffer32((S32*)vertexIndex.address(), vertexIndex.size());      tsalloc.copyToBuffer32((S32*)boneIndex.address(), boneIndex.size());      tsalloc.copyToBuffer32((S32*)weight.address(), weight.size());   }   else   {      tsalloc.set32(0);   }   if (TSShape::smVersion < 27)   {      if (mParentMesh < 0)      {         tsalloc.copyToBuffer32((S32*)vertexIndex.address(), vertexIndex.size());         tsalloc.copyToBuffer32((S32*)boneIndex.address(), boneIndex.size());         tsalloc.copyToBuffer32((S32*)weight.address(), weight.size());      }   }   tsalloc.set32( batchData.nodeIndex.size() );   if (mParentMesh < 0 )      tsalloc.copyToBuffer32( (S32*)batchData.nodeIndex.address(), batchData.nodeIndex.size() );   tsalloc.setGuard();}TSSkinMesh::TSSkinMesh(){   mMeshType = SkinMeshType;   batchData.initialized = false;   maxBones = -1;}//-----------------------------------------------------------------------------// find tangent vector//-----------------------------------------------------------------------------inline void TSMesh::findTangent( U32 index1,                                  U32 index2,                                  U32 index3,                                  Point3F *tan0,                                  Point3F *tan1,                                 const Vector<Point3F> &_verts){   const Point3F &v1 = _verts[index1];   const Point3F &v2 = _verts[index2];   const Point3F &v3 = _verts[index3];   const Point2F &w1 = mTverts[index1];   const Point2F &w2 = mTverts[index2];   const Point2F &w3 = mTverts[index3];   F32 x1 = v2.x - v1.x;   F32 x2 = v3.x - v1.x;   F32 y1 = v2.y - v1.y;   F32 y2 = v3.y - v1.y;   F32 z1 = v2.z - v1.z;   F32 z2 = v3.z - v1.z;   F32 s1 = w2.x - w1.x;   F32 s2 = w3.x - w1.x;   F32 t1 = w2.y - w1.y;   F32 t2 = w3.y - w1.y;   F32 denom = (s1 * t2 - s2 * t1);   if( mFabs( denom ) < 0.0001f )   {	   // handle degenerate triangles from strips	   if (denom<0) denom = -0.0001f;	   else denom = 0.0001f;   }   F32 r = 1.0f / denom;   Point3F sdir(  (t2 * x1 - t1 * x2) * r,                   (t2 * y1 - t1 * y2) * r,                   (t2 * z1 - t1 * z2) * r );   Point3F tdir(  (s1 * x2 - s2 * x1) * r,                   (s1 * y2 - s2 * y1) * r,                   (s1 * z2 - s2 * z1) * r );   tan0[index1]  += sdir;   tan1[index1]  += tdir;   tan0[index2]  += sdir;   tan1[index2]  += tdir;   tan0[index3]  += sdir;   tan1[index3]  += tdir;}//-----------------------------------------------------------------------------// create array of tangent vectors//-----------------------------------------------------------------------------void TSMesh::createTangents(const Vector<Point3F> &_verts, const Vector<Point3F> &_norms){   if (_verts.size() == 0) // can only be done in editable mode      return;   U32 numVerts = _verts.size();   U32 numNorms = _norms.size();   if ( numVerts <= 0 || numNorms <= 0 )      return;   if( numVerts != numNorms)      return;   Vector<Point3F> tan0;   tan0.setSize( numVerts * 2 );   Point3F *tan1 = tan0.address() + numVerts;   dMemset( tan0.address(), 0, sizeof(Point3F) * 2 * numVerts );      U32   numPrimatives = mPrimitives.size();   for (S32 i = 0; i < numPrimatives; i++ )   {      const TSDrawPrimitive & draw = mPrimitives[i];      GFXPrimitiveType drawType = getDrawType( draw.matIndex >> 30 );      U32 p1Index = 0;      U32 p2Index = 0;      U32 *baseIdx = &mIndices[draw.start];      const U32 numElements = (U32)draw.numElements;      switch( drawType )      {      case GFXTriangleList:         {            for( U32 j = 0; j < numElements; j += 3 )               findTangent( baseIdx[j], baseIdx[j + 1], baseIdx[j + 2], tan0.address(), tan1, _verts );            break;         }      case GFXTriangleStrip:         {            p1Index = baseIdx[0];            p2Index = baseIdx[1];            for( U32 j = 2; j < numElements; j++ )            {               findTangent( p1Index, p2Index, baseIdx[j], tan0.address(), tan1, _verts );               p1Index = p2Index;               p2Index = baseIdx[j];            }            break;         }      default:         AssertFatal( false, "TSMesh::createTangents: unknown primitive type!" );      }   }   mTangents.setSize( numVerts );   // fill out final info from accumulated basis data   for( U32 i = 0; i < numVerts; i++ )   {      const Point3F &n = _norms[i];      const Point3F &t = tan0[i];      const Point3F &b = tan1[i];      Point3F tempPt = t - n * mDot( n, t );      tempPt.normalize();	  mTangents[i] = tempPt;      Point3F cp;      mCross( n, t, &cp );      	  mTangents[i].w = (mDot( cp, b ) < 0.0f) ? -1.0f : 1.0f;   }}void TSMesh::convertToVertexData(){   if (!mVertexData.isReady())   {      _convertToVertexData(mVertexData, mVerts, mNorms);   }}void TSSkinMesh::convertToVertexData(){   if (!mVertexData.isReady())   {      // Batch data required here      createSkinBatchData();      // Dump verts to buffer      _convertToVertexData(mVertexData, batchData.initialVerts, batchData.initialNorms);      // Setup bones too      setupVertexTransforms();   }}void TSMesh::copySourceVertexDataFrom(const TSMesh* srcMesh){   mVerts = srcMesh->mVerts;   mTverts = srcMesh->mTverts;   mNorms = srcMesh->mNorms;   mColors = srcMesh->mColors;   mTverts2 = srcMesh->mTverts2;   if (mVerts.size() == 0)   {      bool hasTVert2 = srcMesh->getHasTVert2();      bool hasColor = srcMesh->getHasColor();	  mVerts.setSize(srcMesh->mNumVerts);      mTverts.setSize(srcMesh->mNumVerts);      mNorms.setSize(srcMesh->mNumVerts);      if (hasColor)         mColors.setSize(mNumVerts);      if (hasTVert2)         mTverts2.setSize(mNumVerts);      // Fill arrays      for (U32 i = 0; i < mNumVerts; i++)      {         const __TSMeshVertexBase &cv = srcMesh->mVertexData.getBase(i);         const __TSMeshVertex_3xUVColor &cvc = srcMesh->mVertexData.getColor(i);         mVerts[i] = cv.vert();         mTverts[i] = cv.tvert();         mNorms[i] = cv.normal();         if (hasColor)            cvc.color().getColor(&mColors[i]);         if (hasTVert2)            mTverts2[i] = cvc.tvert2();      }   }}void TSSkinMesh::copySourceVertexDataFrom(const TSMesh* srcMesh){   TSMesh::copySourceVertexDataFrom(srcMesh);   if (srcMesh->getMeshType() == TSMesh::SkinMeshType)   {      const TSSkinMesh* srcSkinMesh = static_cast<const TSSkinMesh*>(srcMesh);      weight = srcSkinMesh->weight;      boneIndex = srcSkinMesh->boneIndex;      vertexIndex = srcSkinMesh->vertexIndex;      maxBones = srcSkinMesh->maxBones;      // Extract from vertex data      if (srcSkinMesh->vertexIndex.size() == 0)      {         mVertexData = srcMesh->mVertexData;         addWeightsFromVertexBuffer();         mVertexData.setReady(false);      }   }}U32 TSMesh::getNumVerts(){   return mVertexData.isReady() ? mNumVerts : mVerts.size();}void TSMesh::_convertToVertexData(TSMeshVertexArray &outArray, const Vector<Point3F> &_verts, const Vector<Point3F> &_norms){   // Update tangents list   createTangents(mVerts, mNorms);   AssertFatal(_verts.size() == mNumVerts, "vert count mismatch");   AssertFatal(!getHasColor() || mColors.size() == _verts.size(), "Vector of color elements should be the same size as other vectors");   AssertFatal(!getHasTVert2() || mTverts2.size() == _verts.size(), "Vector of tvert2 elements should be the same size as other vectors");   AssertFatal(!outArray.isReady(), "Mesh already converted to aligned data! Re-check code!");   AssertFatal(_verts.size() == _norms.size() &&      _verts.size() == mTangents.size(),      "Vectors: verts, norms, tangents must all be the same size");   AssertFatal(mVertSize == outArray.vertSize(), "Size inconsistency");   if (mNumVerts == 0)      return;   bool needWeightSet = outArray.getBoneOffset() != 0;   bool hasColor = getHasColor();   bool hasTVert2 = getHasTVert2();   dMemset(&outArray.getBase(0), '\0', mVertSize * mNumVerts);   for (U32 i = 0; i < mNumVerts; i++)   {      __TSMeshVertexBase &v = outArray.getBase(i);      v.vert(_verts[i]);      v.normal(_norms[i]);      v.tangent(mTangents[i]);      if (i < mTverts.size())         v.tvert(mTverts[i]);      if (hasTVert2 || hasColor)      {         __TSMeshVertex_3xUVColor &vc = outArray.getColor(i);         if (hasTVert2 && i < mTverts2.size())            vc.tvert2(mTverts2[i]);         if (hasColor && i < mColors.size())            vc.color(mColors[i]);      }      // 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      if (needWeightSet)      {         const Point4F wt(1.0f, 0.0f, 0.0f, 0.0f);         outArray.getBone(i, 0).weight(wt);      }   }}void TSMesh::makeEditable(){   bool hasVerts = mVerts.size() != 0;   if(mVertexData.isReady() && !hasVerts)   {      copySourceVertexDataFrom(this);   }   mVertexData.setReady(false);   mVertSize = 0;   mNumVerts = 0;   mVertOffset = 0;   updateMeshFlags();}void TSSkinMesh::addWeightsFromVertexBuffer(){   weight.setSize(0);   boneIndex.setSize(0);   vertexIndex.setSize(0);   U32 numBoneBlocks = maxBones >= 0 ? (maxBones + 3) / 4 : 0;   for (U32 i = 0; i < mNumVerts; i++)   {      for (U32 j = 0; j < numBoneBlocks; j++)      {         const __TSMeshVertex_BoneData &cv = mVertexData.getBone(i, j);         if (cv._weights.x != 0.0f)         {            addWeightForVert(i, cv._indexes.x, cv._weights.x);         }         if (cv._weights.y != 0.0f)         {            addWeightForVert(i, cv._indexes.y, cv._weights.y);         }         if (cv._weights.z != 0.0f)         {            addWeightForVert(i, cv._indexes.z, cv._weights.z);         }         if (cv._weights.w != 0.0f)         {            addWeightForVert(i, cv._indexes.w, cv._weights.w);         }      }   }}void TSSkinMesh::makeEditable(){   bool hasVerts = mVerts.size() != 0;   // Reconstruct bone mapping   if (mVertexData.isReady() && !hasVerts)   {      copySourceVertexDataFrom(this);      weight.setSize(0);      boneIndex.setSize(0);      vertexIndex.setSize(0);      addWeightsFromVertexBuffer();   }   mVertexData.setReady(false);   mVertSize = 0;   mNumVerts = 0;   updateMeshFlags();   batchData.initialized = false;}void TSMesh::clearEditable(){   if (mVerts.size() == 0)      return;   if (mColors.empty())      clearFlags(HasColor);   else      setFlags(HasColor);   if (mTverts2.empty())      clearFlags(HasTVert2);   else      setFlags(HasTVert2);   mVerts.free_memory();   mNorms.free_memory();   mTangents.free_memory();   mTverts.free_memory();   mTverts2.free_memory();   mColors.free_memory();}void TSMesh::updateMeshFlags(){   // Make sure flags are correct   if (mColors.empty())      clearFlags(HasColor);   else      setFlags(HasColor);   if (mTverts2.empty())      clearFlags(HasTVert2);   else      setFlags(HasTVert2);}void TSSkinMesh::clearEditable(){   TSMesh::clearEditable();   weight.free_memory();   boneIndex.free_memory();   vertexIndex.free_memory();}TSBasicVertexFormat::TSBasicVertexFormat() :   texCoordOffset(-1),   boneOffset(-1),   colorOffset(-1),   numBones(0),   vertexSize(-1){}TSBasicVertexFormat::TSBasicVertexFormat(TSMesh *mesh){   texCoordOffset = -1;   boneOffset = -1;   colorOffset = -1;   numBones = 0;   vertexSize = -1;   addMeshRequirements(mesh);}void TSBasicVertexFormat::getFormat(GFXVertexFormat &fmt){   // NOTE: previously the vertex data was padded to allow for verts to be skinned via SSE.    //       since we now prefer to skin on the GPU and use a basic non-SSE fallback for software    //       skinning, adding in padding via GFXSemantic::PADDING or dummy fields is no longer required.   fmt.addElement(GFXSemantic::POSITION, GFXDeclType_Float3);   fmt.addElement(GFXSemantic::TANGENTW, GFXDeclType_Float, 3);   fmt.addElement(GFXSemantic::NORMAL, GFXDeclType_Float3);   fmt.addElement(GFXSemantic::TANGENT, GFXDeclType_Float3);   fmt.addElement(GFXSemantic::TEXCOORD, GFXDeclType_Float2, 0);   if (texCoordOffset >= 0 || colorOffset >= 0)   {      fmt.addElement(GFXSemantic::TEXCOORD, GFXDeclType_Float2, 1);      fmt.addElement(GFXSemantic::COLOR, GFXDeclType_Color);   }   for (U32 i=0; i<numBones; i++)   {      fmt.addElement(GFXSemantic::BLENDINDICES, GFXDeclType_UByte4, i);      fmt.addElement(GFXSemantic::BLENDWEIGHT, GFXDeclType_Float4, i);   }}void TSBasicVertexFormat::calculateSize(){   GFXVertexFormat fmt;   vertexSize = 0;   getFormat(fmt);   vertexSize = fmt.getSizeInBytes();}void TSBasicVertexFormat::writeAlloc(TSShapeAlloc* alloc){   alloc->set16(texCoordOffset);   alloc->set16(boneOffset);   alloc->set16(colorOffset);   alloc->set16(numBones);   alloc->set16(vertexSize);}void TSBasicVertexFormat::readAlloc(TSShapeAlloc* alloc){   texCoordOffset = alloc->get16();   boneOffset = alloc->get16();   colorOffset = alloc->get16();   numBones = alloc->get16();   vertexSize = alloc->get16();}void TSBasicVertexFormat::addMeshRequirements(TSMesh *mesh){   bool hasColors = false;   bool hasTexcoord2 = false;   bool hasSkin = false;   hasColors = mesh->getHasColor() || (colorOffset != -1);   hasTexcoord2 = mesh->getHasTVert2() || (texCoordOffset != -1);   hasSkin = (mesh->getMeshType() == TSMesh::SkinMeshType) || (boneOffset != -1);   S32 offset = sizeof(TSMesh::__TSMeshVertexBase);   if ((hasTexcoord2 || hasColors))   {      if (texCoordOffset == -1 || colorOffset == -1)      {         texCoordOffset = offset;         colorOffset = offset + (sizeof(float) * 2);      }            offset += sizeof(TSMesh::__TSMeshVertex_3xUVColor);   }   if (hasSkin)   {      boneOffset = offset;      U32 numMeshBones = mesh->getMaxBonesPerVert();      U32 boneBlocks = numMeshBones / 4;      U32 extraBlocks = numMeshBones % 4 != 0 ? 1 : 0;      U32 neededBones = boneBlocks + extraBlocks;      numBones = MAX(neededBones, numBones);   }}void TSSkinMesh::printVerts(){   for (U32 i = 0; i < mNumVerts; i++)   {      TSMesh::__TSMeshVertexBase &vb = mVertexData.getBase(i);      TSMesh::__TSMeshVertex_BoneData &bw = mVertexData.getBone(i, 0);      Point3F vert = batchData.initialVerts[i];      Con::printf("v[%i] == %f,%f,%f; iv == %f,%f,%f. bo=%i,%i,%i,%i bw=%f,%f,%f,%f",         i, vb._vert.x, vb._vert.y, vb._vert.z,         vert.x, vert.y, vert.z,         bw._indexes.x, bw._indexes.y, bw._indexes.z, bw._indexes.w,         bw._weights.x, bw._weights.y, bw._weights.z, bw._weights.w);   }}
 |