| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: W3DModelDraw.cpp ///////////////////////////////////////////////////////////////////////
- // Author: Colin Day, November 2001
- // Desc: Default w3d draw module
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #define DEFINE_W3DANIMMODE_NAMES
- #define DEFINE_WEAPONSLOTTYPE_NAMES
- #define NO_DEBUG_CRC
- #include "Common/CRC.h"
- #include "Common/CRCDebug.h"
- #include "Common/GameState.h"
- #include "Common/GlobalData.h"
- #include "Common/PerfTimer.h"
- #include "Common/RandomValue.h"
- #include "Common/ThingTemplate.h"
- #include "Common/GameLOD.h"
- #include "Common/Xfer.h"
- #include "Common/GameState.h"
- #include "Common/QuickTrig.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/FXList.h"
- #include "GameClient/Shadow.h"
- #include "GameLogic/GameLogic.h" // for real-time frame
- #include "GameLogic/Object.h"
- #include "GameLogic/WeaponSet.h"
- #include "GameLogic/FPUControl.h"
- #include "GameLogic/Module/AIUpdate.h"
- #include "GameLogic/Module/PhysicsUpdate.h"
- #include "W3DDevice/GameClient/Module/W3DModelDraw.h"
- #include "W3DDevice/GameClient/W3DAssetManager.h"
- #include "W3DDevice/GameClient/W3DDisplay.h"
- #include "W3DDevice/GameClient/W3DScene.h"
- #include "W3DDevice/GameClient/W3DShadow.h"
- #include "W3DDevice/GameClient/W3DTerrainTracks.h"
- #include "W3DDevice/GameClient/WorldHeightMap.h"
- #include "WW3D2/HAnim.h"
- #include "WW3D2/HLod.h"
- #include "WW3D2/RendObj.h"
- #include "WW3D2/Mesh.h"
- #include "WW3D2/MeshMdl.h"
- #include "Common/BitFlagsIO.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //-------------------------------------------------------------------------------------------------
- static inline Bool isValidTimeToCalcLogicStuff()
- {
- return (TheGameLogic && TheGameLogic->isInGameLogicUpdate()) ||
- (TheGameState && TheGameState->isInLoadGame());
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- #if defined(DEBUG_CRC) && (defined(_DEBUG) || defined(_INTERNAL))
- #include <cstdarg>
- class LogClass
- {
- public:
- LogClass(const char *fname);
- ~LogClass();
- void log(const char *fmt, ...);
- void dumpMatrix3D(const Matrix3D *m, AsciiString name, AsciiString fname, Int line);
- void dumpReal(Real r, AsciiString name, AsciiString fname, Int line);
- protected:
- FILE *m_fp;
- };
- LogClass::LogClass(const char *fname)
- {
- char buffer[ _MAX_PATH ];
- GetModuleFileName( NULL, buffer, sizeof( buffer ) );
- char *pEnd = buffer + strlen( buffer );
- while( pEnd != buffer )
- {
- if( *pEnd == '\\' )
- {
- *pEnd = 0;
- break;
- }
- pEnd--;
- }
- AsciiString fullPath;
- fullPath.format("%s\\%s", buffer, fname);
- m_fp = fopen(fullPath.str(), "wt");
- }
- LogClass::~LogClass()
- {
- if (m_fp)
- {
- fclose(m_fp);
- }
- }
- void LogClass::log(const char *fmt, ...)
- {
- DEBUG_ASSERTCRASH(isValidTimeToCalcLogicStuff(), ("Calc'ing logic bone pos in client!!!"));
- if (!m_fp /*|| !isValidTimeToCalcLogicStuff()*/)
- return;
- static char buf[1024];
- static Int lastFrame = 0;
- static Int lastIndex = 0;
- if (lastFrame != TheGameLogic->getFrame())
- {
- lastFrame = TheGameLogic->getFrame();
- lastIndex = 0;
- }
- va_list va;
- va_start( va, fmt );
- _vsnprintf(buf, 1024, fmt, va );
- buf[1023] = 0;
- va_end( va );
- char *tmp = buf;
- while (tmp && *tmp)
- {
- if (*tmp == '\r' || *tmp == '\n')
- {
- *tmp = ' ';
- }
- ++tmp;
- }
- fprintf(m_fp, "%d:%d %s\n", lastFrame, lastIndex++, buf);
- fflush(m_fp);
- }
- void LogClass::dumpMatrix3D(const Matrix3D *m, AsciiString name, AsciiString fname, Int line)
- {
- fname.toLower();
- fname = fname.reverseFind('\\') + 1;
- const Real *matrix = (const Real *)m;
- log("dumpMatrix3D() %s:%d %s\n",
- fname.str(), line, name.str());
- for (Int i=0; i<3; ++i)
- log(" 0x%08X 0x%08X 0x%08X 0x%08X\n",
- AS_INT(matrix[(i<<2)+0]), AS_INT(matrix[(i<<2)+1]), AS_INT(matrix[(i<<2)+2]), AS_INT(matrix[(i<<2)+3]));
- }
- void LogClass::dumpReal(Real r, AsciiString name, AsciiString fname, Int line)
- {
- if (!m_fp || !isValidTimeToCalcLogicStuff())
- return;
- fname.toLower();
- fname = fname.reverseFind('\\') + 1;
- log("dumpReal() %s:%d %s %8.8X (%f)\n",
- fname.str(), line, name.str(), AS_INT(r), r);
- }
- LogClass BonePosLog("bonePositions.txt");
- #define BONEPOS_LOG(x) BonePosLog.log x
- #define BONEPOS_DUMPMATRIX3D(x) BONEPOS_DUMPMATRIX3DNAMED(x, #x)
- #define BONEPOS_DUMPMATRIX3DNAMED(x, y) BonePosLog.dumpMatrix3D(x, y, __FILE__, __LINE__)
- #define BONEPOS_DUMPREAL(x) BONEPOS_DUMPREALNAMED(x, #x)
- #define BONEPOS_DUMPREALNAMED(x, y) BonePosLog.dumpReal(x, y, __FILE__, __LINE__)
- #else // DEBUG_CRC
- #define BONEPOS_LOG(x) {}
- #define BONEPOS_DUMPMATRIX3D(x) {}
- #define BONEPOS_DUMPMATRIX3DNAMED(x, y) {}
- #define BONEPOS_DUMPREAL(x) {}
- #define BONEPOS_DUMPREALNAMED(x, y) {}
- #endif // DEBUG_CRC
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- extern AsciiString TheThingTemplateBeingParsedName;
- extern Real TheSkateDistOverride;
- #endif
- // flags that aren't read directly from INI, but set in response to various other situations
- enum INIReadFlagsType
- {
- ANIMS_COPIED_FROM_DEFAULT_STATE = 0,
- GOT_NONIDLE_ANIMS,
- GOT_IDLE_ANIMS,
- };
- enum ACBits
- {
- RANDOMIZE_START_FRAME = 0,
- START_FRAME_FIRST,
- START_FRAME_LAST,
- ADJUST_HEIGHT_BY_CONSTRUCTION_PERCENT,
- PRISTINE_BONE_POS_IN_FINAL_FRAME,
- MAINTAIN_FRAME_ACROSS_STATES,
- RESTART_ANIM_WHEN_COMPLETE,
- MAINTAIN_FRAME_ACROSS_STATES2,
- MAINTAIN_FRAME_ACROSS_STATES3,
- MAINTAIN_FRAME_ACROSS_STATES4,
- };
- static const char *ACBitsNames[] =
- {
- "RANDOMSTART",
- "START_FRAME_FIRST",
- "START_FRAME_LAST",
- "ADJUST_HEIGHT_BY_CONSTRUCTION_PERCENT",
- "PRISTINE_BONE_POS_IN_FINAL_FRAME",
- "MAINTAIN_FRAME_ACROSS_STATES",
- "RESTART_ANIM_WHEN_COMPLETE",
- "MAINTAIN_FRAME_ACROSS_STATES2",
- "MAINTAIN_FRAME_ACROSS_STATES3",
- "MAINTAIN_FRAME_ACROSS_STATES4",
-
- NULL
- };
- static const Int ALL_MAINTAIN_FRAME_FLAGS =
- (1<<MAINTAIN_FRAME_ACROSS_STATES) |
- (1<<MAINTAIN_FRAME_ACROSS_STATES2) |
- (1<<MAINTAIN_FRAME_ACROSS_STATES3) |
- (1<<MAINTAIN_FRAME_ACROSS_STATES4);
- inline Bool isAnyMaintainFrameFlagSet(Int flags)
- {
- return (flags & ALL_MAINTAIN_FRAME_FLAGS) != 0;
- }
- inline Bool isCommonMaintainFrameFlagSet(Int a, Int b)
- {
- a &= ALL_MAINTAIN_FRAME_FLAGS;
- b &= ALL_MAINTAIN_FRAME_FLAGS;
- return (a & b) != 0;
- }
- /** @todo: Move this to some kind of INI file*/
- //
- // Note: these values are saved in save files, so you MUST NOT REMOVE OR CHANGE
- // existing values!
- //
- static char *TerrainDecalTextureName[TERRAIN_DECAL_MAX]=
- {
- #ifdef ALLOW_DEMORALIZE
- "DM_RING",//demoralized
- #else
- "TERRAIN_DECAL_DEMORALIZED_OBSOLETE",
- #endif
- "EXHorde",//enthusiastic
- "EXHorde_UP", //enthusiastic with nationalism
- "EXHordeB",//enthusiastic vehicle
- "EXHordeB_UP", //enthusiastic vehicle with nationalism
- "EXJunkCrate",//Marks a crate as special
- "EXHordeC_UP", //enthusiastic with fanaticism
- "EXChemSuit", //Marks a unit as having chemical suit on
- "", //dummy entry for TERRAIN_DECAL_NONE
- "" //dummy entry for TERRAIN_DECAL_SHADOW_TEXTURE
- };
- const UnsignedInt NO_NEXT_DURATION = 0xffffffff;
- //-------------------------------------------------------------------------------------------------
- W3DAnimationInfo::W3DAnimationInfo(const AsciiString& name, Bool isIdle, Real distanceCovered) :
- #ifdef RETAIN_ANIM_HANDLES
- m_handle(NULL),
- m_naturalDurationInMsec(0),
- #else
- m_naturalDurationInMsec(-1),
- #endif
- m_name(name),
- m_isIdleAnim(isIdle),
- m_distanceCovered(distanceCovered)
- {
- }
- //-------------------------------------------------------------------------------------------------
- W3DAnimationInfo::W3DAnimationInfo( const W3DAnimationInfo &r ) :
- m_name(r.m_name),
- #ifdef RETAIN_ANIM_HANDLES
- m_handle(r.m_handle),
- #endif
- m_distanceCovered(r.m_distanceCovered),
- m_isIdleAnim(r.m_isIdleAnim),
- m_naturalDurationInMsec(r.m_naturalDurationInMsec)
- {
- #ifdef RETAIN_ANIM_HANDLES
- if (m_handle)
- m_handle->Add_Ref();
- #endif
- }
- //-------------------------------------------------------------------------------------------------
- W3DAnimationInfo& W3DAnimationInfo::operator=(const W3DAnimationInfo &r)
- {
- m_name = r.m_name;
- m_distanceCovered = r.m_distanceCovered;
- m_naturalDurationInMsec = r.m_naturalDurationInMsec;
- m_isIdleAnim = r.m_isIdleAnim;
- #ifdef RETAIN_ANIM_HANDLES
- REF_PTR_RELEASE(m_handle);
- m_handle = r.m_handle;
- if (m_handle)
- m_handle->Add_Ref();
- #endif
- return (*this);
- }
- //-------------------------------------------------------------------------------------------------
- // note that this now returns an ADDREFED handle, which must be released by the caller!
- HAnimClass* W3DAnimationInfo::getAnimHandle() const
- {
- #ifdef RETAIN_ANIM_HANDLES
- if (m_handle == NULL)
- {
- // Get_HAnim addrefs it, so we'll have to release it in our dtor.
- m_handle = W3DDisplay::m_assetManager->Get_HAnim(m_name.str());
- DEBUG_ASSERTCRASH(m_handle, ("*** ASSET ERROR: animation %s not found\n",m_name.str()));
- if (m_handle)
- {
- m_naturalDurationInMsec = m_handle->Get_Num_Frames() * 1000.0f / m_handle->Get_Frame_Rate();
- }
- }
- // since we have it locally, must addref.
- if (m_handle)
- m_handle->Add_Ref();
- return m_handle;
- #else
- HAnimClass* handle = W3DDisplay::m_assetManager->Get_HAnim(m_name.str());
- DEBUG_ASSERTCRASH(handle, ("*** ASSET ERROR: animation %s not found\n",m_name.str()));
- if (handle != NULL && m_naturalDurationInMsec < 0)
- {
- m_naturalDurationInMsec = handle->Get_Num_Frames() * 1000.0f / handle->Get_Frame_Rate();
- }
- // since Get_HAnim() returns an addrefed handle, we must NOT addref here.
- //if (handle)
- // handle->Add_Ref();
- return handle;
- #endif
- }
- //-------------------------------------------------------------------------------------------------
- W3DAnimationInfo::~W3DAnimationInfo()
- {
- #ifdef RETAIN_ANIM_HANDLES
- REF_PTR_RELEASE(m_handle);
- m_handle = NULL;
- #endif
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::preloadAssets( TimeOfDay timeOfDay, Real scale )
- {
- // load this asset
- if( m_modelName.isEmpty() == FALSE )
- {
- TheDisplay->preloadModelAssets( m_modelName );
- }
-
- // this can be called from the client, which is problematic
- // validateStuff(NULL, getDrawable()->getScale());
- //validateCachedBones(NULL, scale);
- //validateTurretInfo();
- //validateWeaponBarrelInfo();
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::addPublicBone(const AsciiString& boneName) const
- {
- if (boneName.isEmpty() || boneName.isNone())
- return;
- AsciiString tmp = boneName;
- tmp.toLower();
- if (std::find(m_publicBones.begin(), m_publicBones.end(), tmp) == m_publicBones.end())
- {
- m_publicBones.push_back(tmp);
- }
- }
- //-------------------------------------------------------------------------------------------------
- Bool ModelConditionInfo::matchesMode(Bool night, Bool snowy) const
- {
- for (std::vector<ModelConditionFlags>::const_iterator it = m_conditionsYesVec.begin();
- it != m_conditionsYesVec.end();
- ++it)
- {
- if (it->test(MODELCONDITION_NIGHT) == (night) &&
- it->test(MODELCONDITION_SNOW) == (snowy))
- {
- return true;
- }
- }
- return false;
- }
- //-------------------------------------------------------------------------------------------------
- inline Bool testFlagBit(Int flags, Int bit)
- {
- return (flags & (1<<bit)) != 0;
- }
- //-------------------------------------------------------------------------------------------------
- static Bool findSingleBone(RenderObjClass* robj, const AsciiString& boneName, Matrix3D& mtx, Int& boneIndex)
- {
- if (boneName.isNone() || boneName.isEmpty())
- return false;
- boneIndex = robj->Get_Bone_Index(boneName.str());
- if (boneIndex != 0)
- {
- mtx = robj->Get_Bone_Transform(boneIndex);
- return true;
- }
- else
- {
- return false;
- }
- }
- //-------------------------------------------------------------------------------------------------
- static Bool findSingleSubObj(RenderObjClass* robj, const AsciiString& boneName, Matrix3D& mtx, Int& boneIndex)
- {
- if (boneName.isNone() || boneName.isEmpty())
- return false;
- RenderObjClass* childObject = robj->Get_Sub_Object_By_Name(boneName.str());
- if (childObject)
- {
- mtx = childObject->Get_Transform();
- // you'd think this would work, but, it does not. do it the hard way.
- // boneIndex = childObject->Get_Sub_Object_Bone_Index(childObject);
- for (Int subObj = 0; subObj < robj->Get_Num_Sub_Objects(); subObj++)
- {
- RenderObjClass* test = robj->Get_Sub_Object(subObj);
- if (test == childObject)
- {
- boneIndex = robj->Get_Sub_Object_Bone_Index(0, subObj);
- #if defined(_DEBUG) || defined(_INTERNAL)
- test->Release_Ref();
- test = robj->Get_Sub_Object_On_Bone(0, boneIndex);
- DEBUG_ASSERTCRASH(test != NULL && test == childObject, ("*** ASSET ERROR: Hmm, bone problem"));
- #endif
- }
- if (test) test->Release_Ref();
- }
- childObject->Release_Ref();
- return true;
- }
- else
- {
- return false;
- }
- }
- //-------------------------------------------------------------------------------------------------
- static Bool doSingleBoneName(RenderObjClass* robj, const AsciiString& boneName, PristineBoneInfoMap& map)
- {
- Bool foundAsBone = false;
- Bool foundAsSubObj = false;
- PristineBoneInfo info;
- AsciiString tmp;
- AsciiString boneNameTmp = boneName;
- boneNameTmp.toLower(); // convert to all-lowercase to avoid case sens issues later
- setFPMode();
- if (findSingleBone(robj, boneNameTmp, info.mtx, info.boneIndex))
- {
- //DEBUG_LOG(("added bone %s\n",boneNameTmp.str()));
- BONEPOS_LOG(("Caching bone %s (index %d)\n", boneNameTmp.str(), info.boneIndex));
- BONEPOS_DUMPMATRIX3D(&(info.mtx));
- map[NAMEKEY(boneNameTmp)] = info;
- foundAsBone = true;
- }
- for (Int i = 1; i <= 99; ++i)
- {
- tmp.format("%s%02d", boneNameTmp.str(), i);
- if (findSingleBone(robj, tmp, info.mtx, info.boneIndex))
- {
- //DEBUG_LOG(("added bone %s\n",tmp.str()));
- BONEPOS_LOG(("Caching bone %s (index %d)\n", tmp.str(), info.boneIndex));
- BONEPOS_DUMPMATRIX3D(&(info.mtx));
- map[NAMEKEY(tmp)] = info;
- foundAsBone = true;
- }
- else
- {
- break;
- }
- }
- if (!foundAsBone)
- {
- if (findSingleSubObj(robj, boneNameTmp, info.mtx, info.boneIndex))
- {
- //DEBUG_LOG(("added subobj %s\n",boneNameTmp.str()));
- BONEPOS_LOG(("Caching bone from subobject %s (index %d)\n", boneNameTmp.str(), info.boneIndex));
- BONEPOS_DUMPMATRIX3D(&(info.mtx));
- map[NAMEKEY(boneNameTmp)] = info;
- foundAsSubObj = true;
- }
- for (Int i = 1; i <= 99; ++i)
- {
- tmp.format("%s%02d", boneNameTmp.str(), i);
- if (findSingleSubObj(robj, tmp, info.mtx, info.boneIndex))
- {
- //DEBUG_LOG(("added subobj %s\n",tmp.str()));
- BONEPOS_LOG(("Caching bone from subobject %s (index %d)\n", tmp.str(), info.boneIndex));
- BONEPOS_DUMPMATRIX3D(&(info.mtx));
- map[NAMEKEY(tmp)] = info;
- foundAsSubObj = true;
- }
- else
- {
- break;
- }
- }
- }
- return foundAsBone || foundAsSubObj;
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::validateStuff(RenderObjClass* robj, Real scale, const std::vector<AsciiString>& extraPublicBones) const
- {
- // srj sez: hm, this doesn't make sense; I think we really do need to validate transition states.
- // if (m_transition != NO_TRANSITION)
- // return;
-
- loadAnimations();
- if (!(m_validStuff & PUBLIC_BONES_VALID) && isValidTimeToCalcLogicStuff())
- {
- for (std::vector<AsciiString>::const_iterator bone_it = extraPublicBones.begin(); bone_it != extraPublicBones.end(); ++bone_it)
- {
- addPublicBone(*bone_it);
- }
- m_validStuff |= PUBLIC_BONES_VALID;
- }
- validateCachedBones(robj, scale);
- validateTurretInfo();
- validateWeaponBarrelInfo();
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::validateCachedBones(RenderObjClass* robj, Real scale) const
- {
- //DEBUG_ASSERTCRASH(isValidTimeToCalcLogicStuff(), ("calling validateCachedBones() from in GameClient!"));
- if (m_validStuff & PRISTINE_BONES_VALID)
- return;
- if (!isValidTimeToCalcLogicStuff())
- {
- m_pristineBones.clear();
- m_validStuff &= ~PRISTINE_BONES_VALID;
- return;
- }
- setFPMode();
- BONEPOS_LOG(("Validating bones for %s: %s", m_modelName.str(), getDescription().str()));
- //BONEPOS_LOG(("Passing in valid render obj: %d\n", (robj != 0)));
- BONEPOS_DUMPREAL(scale);
- m_pristineBones.clear();
- // go ahead and set this here, in case we return early.
- m_validStuff |= PRISTINE_BONES_VALID;
- Bool tossRobj = false;
- if (robj == NULL)
- {
- if (m_modelName.isEmpty())
- {
- //BONEPOS_LOG(("Bailing: model name is empty\n"));
- return;
- }
- robj = W3DDisplay::m_assetManager->Create_Render_Obj(m_modelName.str(), scale, 0);
- DEBUG_ASSERTCRASH(robj, ("*** ASSET ERROR: Model %s not found!\n",m_modelName.str()));
- if (!robj)
- {
- //BONEPOS_LOG(("Bailing: could not load render object\n"));
- return;
- }
- tossRobj = true;
- }
- Matrix3D originalTransform = robj->Get_Transform(); // save the transform
- HLodClass* hlod = NULL;
- HAnimClass* curAnim = NULL;
- int numFrames = 0;
- float frame = 0.0f;
- int mode = 0;
- float mult = 1.0f;
- if (robj->Class_ID() == RenderObjClass::CLASSID_HLOD)
- {
- hlod = (HLodClass*)robj;
- curAnim = hlod->Peek_Animation_And_Info(frame, numFrames, mode, mult);
- }
- // if we have any animations in this state, always choose the first, since the animations
- // vary on a per-client basis.
- HAnimClass* animToUse;
- if (m_animations.size() > 0)
- {
- animToUse = m_animations.front().getAnimHandle(); // return an AddRef'ed handle
- }
- else
- {
- animToUse = curAnim; // Peek_Animation_And_Info does not addref, so we must do so here
- if (animToUse)
- animToUse->Add_Ref();
- }
- if (animToUse != NULL)
- {
- // make sure we're in frame zero.
- Int whichFrame = testFlagBit(m_flags, PRISTINE_BONE_POS_IN_FINAL_FRAME) ? animToUse->Get_Num_Frames()-1 : 0;
- robj->Set_Animation(animToUse, whichFrame, RenderObjClass::ANIM_MODE_MANUAL);
- // must balance the addref, above
- REF_PTR_RELEASE(animToUse);
- animToUse = NULL;
- }
- Matrix3D tmp(true);
- tmp.Scale(scale);
- robj->Set_Transform(tmp); // set to identity transform
- if (TheGlobalData)
- {
- for (std::vector<AsciiString>::const_iterator it = TheGlobalData->m_standardPublicBones.begin(); it != TheGlobalData->m_standardPublicBones.end(); ++it)
- {
- if (!doSingleBoneName(robj, *it, m_pristineBones))
- {
- // don't crash here, since these are catch-all global bones and won't be present in most models.
- //DEBUG_CRASH(("public bone %s (and variations thereof) not found in model %s!\n",it->str(),m_modelName.str()));
- }
- //else
- //{
- // DEBUG_LOG(("global bone %s (or variations thereof) found in model %s\n",it->str(),m_modelName.str()));
- //}
- }
- }
- for (std::vector<AsciiString>::const_iterator it = m_publicBones.begin(); it != m_publicBones.end(); ++it)
- {
- if (!doSingleBoneName(robj, *it, m_pristineBones))
- {
- // DO crash here, since we specifically requested this bone for this model
- DEBUG_CRASH(("*** ASSET ERROR: public bone '%s' (and variations thereof) not found in model %s!\n",it->str(),m_modelName.str()));
- }
- //else
- //{
- // DEBUG_LOG(("extra bone %s (or variations thereof) found in model %s\n",it->str(),m_modelName.str()));
- //}
- }
- robj->Set_Transform(originalTransform); // restore previous transform
- if (curAnim != NULL)
- {
- robj->Set_Animation(curAnim, frame, mode);
- hlod->Set_Animation_Frame_Rate_Multiplier(mult);
- }
- if (tossRobj)
- {
- REF_PTR_RELEASE(robj);
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::validateWeaponBarrelInfo() const
- {
- //DEBUG_ASSERTCRASH(isValidTimeToCalcLogicStuff(), ("calling validateWeaponBarrelInfo() from in GameClient!"));
- if (m_validStuff & BARRELS_VALID)
- return;
- if (!isValidTimeToCalcLogicStuff())
- {
- return;
- }
- setFPMode();
- for (int wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot)
- {
- m_weaponBarrelInfoVec[wslot].clear();
- m_hasRecoilBonesOrMuzzleFlashes[wslot] = false;
- const AsciiString& fxBoneName = m_weaponFireFXBoneName[wslot];
- const AsciiString& recoilBoneName = m_weaponRecoilBoneName[wslot];
- const AsciiString& mfName = m_weaponMuzzleFlashName[wslot];
- const AsciiString& plbName = m_weaponProjectileLaunchBoneName[wslot];
-
- // a useful tool for finding missing INI entries in the weapon-bone block
- // since this class has no idea which object it refers to, it must assume that the projectilelaunchbonename
- // is required if the fxBoneName is specified
- // this is not always true, since some weapons have no launched projectiles, hence the caveat in the assert message
- //#if defined(_DEBUG) || defined(_INTERNAL)
- // if (
- // ( m_modelName.startsWith("UV") || m_modelName.startsWith("NV") || m_modelName.startsWith("AV") ||
- // m_modelName.startsWith("uv") || m_modelName.startsWith("nv") || m_modelName.startsWith("av")
- // )
- //
- // && fxBoneName.isNotEmpty()
- //
- // )
- // DEBUG_ASSERTCRASH( plbName.isNotEmpty(), ("You appear to have a missing projectilelaunchbonename. \n Promptly ignore this assert if this model is used by a non-projectile-weapon-bearing unit\nModel name = %s.", m_modelName.str()) );
- //#endif
- if (fxBoneName.isNotEmpty() || recoilBoneName.isNotEmpty() || mfName.isNotEmpty() || plbName.isNotEmpty())
- {
- Int prevFxBone = 0;
- char buffer[256];
- for (Int i = 1; i <= 99; ++i)
- {
- WeaponBarrelInfo info;
- info.m_projectileOffsetMtx.Make_Identity();
- if (!recoilBoneName.isEmpty())
- {
- sprintf(buffer, "%s%02d", recoilBoneName.str(), i);
- findPristineBone(NAMEKEY(buffer), &info.m_recoilBone);
- }
- if (!mfName.isEmpty())
- {
- sprintf(buffer, "%s%02d", mfName.str(), i);
- findPristineBone(NAMEKEY(buffer), &info.m_muzzleFlashBone);
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (info.m_muzzleFlashBone)
- info.m_muzzleFlashBoneName = buffer;
- #endif
- }
- if (!fxBoneName.isEmpty())
- {
- sprintf(buffer, "%s%02d", fxBoneName.str(), i);
- findPristineBone(NAMEKEY(buffer), &info.m_fxBone);
- // special case: if we have multiple muzzleflashes, but only one fxbone, use that fxbone for everything.
- if (info.m_fxBone == 0 && info.m_muzzleFlashBone != 0)
- info.m_fxBone = prevFxBone;
- }
- Int plbBoneIndex = 0;
- if (!plbName.isEmpty())
- {
- sprintf(buffer, "%s%02d", plbName.str(), i);
- const Matrix3D* mtx = findPristineBone(NAMEKEY(buffer), &plbBoneIndex);
- if (mtx != NULL)
- info.m_projectileOffsetMtx = *mtx;
- }
- if (info.m_fxBone == 0 && info.m_recoilBone == 0 && info.m_muzzleFlashBone == 0 && plbBoneIndex == 0)
- break;
- CRCDEBUG_LOG(("validateWeaponBarrelInfo() - model name %s wslot %d\n", m_modelName.str(), wslot));
- DUMPMATRIX3D(&(info.m_projectileOffsetMtx));
- BONEPOS_LOG(("validateWeaponBarrelInfo() - model name %s wslot %d\n", m_modelName.str(), wslot));
- BONEPOS_DUMPMATRIX3D(&(info.m_projectileOffsetMtx));
- m_weaponBarrelInfoVec[wslot].push_back(info);
- if (info.m_recoilBone != 0 || info.m_muzzleFlashBone != 0)
- m_hasRecoilBonesOrMuzzleFlashes[wslot] = true;
- prevFxBone = info.m_fxBone;
- }
-
- if (m_weaponBarrelInfoVec[wslot].empty())
- {
- // try the unadorned names
- WeaponBarrelInfo info;
- if (!recoilBoneName.isEmpty())
- findPristineBone(NAMEKEY(recoilBoneName), &info.m_recoilBone);
- if (!mfName.isEmpty())
- findPristineBone(NAMEKEY(mfName), &info.m_muzzleFlashBone);
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (info.m_muzzleFlashBone)
- info.m_muzzleFlashBoneName = mfName;
- #endif
- const Matrix3D* plbMtx = plbName.isEmpty() ? NULL : findPristineBone(NAMEKEY(plbName), NULL);
- if (plbMtx != NULL)
- info.m_projectileOffsetMtx = *plbMtx;
- else
- info.m_projectileOffsetMtx.Make_Identity();
- if (!fxBoneName.isEmpty())
- findPristineBone(NAMEKEY(fxBoneName), &info.m_fxBone);
-
- if (info.m_fxBone != 0 || info.m_recoilBone != 0 || info.m_muzzleFlashBone != 0 || plbMtx != NULL)
- {
- CRCDEBUG_LOG(("validateWeaponBarrelInfo() - model name %s (unadorned) wslot %d\n", m_modelName.str(), wslot));
- DUMPMATRIX3D(&(info.m_projectileOffsetMtx));
- BONEPOS_LOG(("validateWeaponBarrelInfo() - model name %s (unadorned) wslot %d\n", m_modelName.str(), wslot));
- BONEPOS_DUMPMATRIX3D(&(info.m_projectileOffsetMtx));
- m_weaponBarrelInfoVec[wslot].push_back(info);
- if (info.m_recoilBone != 0 || info.m_muzzleFlashBone != 0)
- m_hasRecoilBonesOrMuzzleFlashes[wslot] = true;
- }
- else
- {
- CRCDEBUG_LOG(("validateWeaponBarrelInfo() - model name %s (unadorned) found nothing\n", m_modelName.str()));
- BONEPOS_LOG(("validateWeaponBarrelInfo() - model name %s (unadorned) found nothing\n", m_modelName.str()));
- }
- } // if empty
- DEBUG_ASSERTCRASH(!(m_modelName.isNotEmpty() && m_weaponBarrelInfoVec[wslot].empty()), ("*** ASSET ERROR: No fx bone named '%s' found in model %s!\n",fxBoneName.str(),m_modelName.str()));
- }
- }
- m_validStuff |= BARRELS_VALID;
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::validateTurretInfo() const
- {
- //DEBUG_ASSERTCRASH(isValidTimeToCalcLogicStuff(), ("calling validateTurretInfo() from in GameClient!"));
- if (m_validStuff & TURRETS_VALID)
- return;
- setFPMode();
- for (int tslot = 0; tslot < MAX_TURRETS; ++tslot)
- {
- TurretInfo& tur = m_turrets[tslot];
- if (!isValidTimeToCalcLogicStuff() || m_modelName.isEmpty())
- {
- tur.m_turretAngleBone = 0;
- tur.m_turretPitchBone = 0;
- continue;
- }
- if (tur.m_turretAngleNameKey != NAMEKEY_INVALID)
- {
- if (findPristineBone(tur.m_turretAngleNameKey, &tur.m_turretAngleBone) == NULL)
- {
- DEBUG_CRASH(("*** ASSET ERROR: TurretBone %s not found! (%s)\n",KEYNAME(tur.m_turretAngleNameKey).str(),m_modelName.str()));
- tur.m_turretAngleBone = 0;
- }
- }
- else
- {
- tur.m_turretAngleBone = 0;
- }
- if (tur.m_turretPitchNameKey != NAMEKEY_INVALID)
- {
- if (findPristineBone(tur.m_turretPitchNameKey, &tur.m_turretPitchBone) == NULL)
- {
- DEBUG_CRASH(("*** ASSET ERROR: TurretBone %s not found! (%s)\n",KEYNAME(tur.m_turretPitchNameKey).str(),m_modelName.str()));
- tur.m_turretPitchBone = 0;
- }
- }
- else
- {
- tur.m_turretPitchBone = 0;
- }
- }
- if (isValidTimeToCalcLogicStuff())
- {
- m_validStuff |= TURRETS_VALID;
- }
- }
- //-------------------------------------------------------------------------------------------------
- const Matrix3D* ModelConditionInfo::findPristineBone(NameKeyType boneName, Int* boneIndex) const
- {
- DEBUG_ASSERTCRASH((m_validStuff & PRISTINE_BONES_VALID), ("*** ASSET ERROR: bones are not valid"));
- if (!(m_validStuff & PRISTINE_BONES_VALID))
- {
- // set it to zero, some callers rely on this
- if (boneIndex)
- *boneIndex = 0;
- return NULL;
- }
- if (boneName == NAMEKEY_INVALID)
- {
- // set it to zero, some callers rely on this
- if (boneIndex)
- *boneIndex = 0;
- return NULL;
- }
- PristineBoneInfoMap::const_iterator it = m_pristineBones.find(boneName);
- if (it != m_pristineBones.end())
- {
- if (boneIndex)
- *boneIndex = it->second.boneIndex;
- return &it->second.mtx;
- }
- else
- {
- // set it to zero -- some callers rely on this!
- if (boneIndex)
- *boneIndex = 0;
- return NULL;
- }
- }
- //-------------------------------------------------------------------------------------------------
- Bool ModelConditionInfo::findPristineBonePos(NameKeyType boneName, Coord3D& pos) const
- {
- const Matrix3D* mtx = findPristineBone(boneName, NULL);
- if (mtx)
- {
- Vector3 v = mtx->Get_Translation();
- pos.x = v.X;
- pos.y = v.Y;
- pos.z = v.Z;
- return true;
- }
- else
- {
- pos.zero();
- return false;
- }
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::loadAnimations() const
- {
- #ifdef RETAIN_ANIM_HANDLES
- for (W3DAnimationVector::const_iterator it2 = m_animations.begin(); it2 != m_animations.end(); ++it2)
- {
- HAnimClass* h = it2->getAnimHandle(); // just force it to get loaded
- REF_PTR_RELEASE(h);
- h = NULL;
- }
- #else
- // srj sez: I think there is no real reason to preload these all anymore. things that need the anims
- // (for bones) will force an implicit load anyway, but there's no point in forcibly loading the anims
- // that don't contain interesting logical bones.
- #endif
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::clear()
- {
- int i;
- #if defined(_DEBUG) || defined(_INTERNAL)
- m_description.clear();
- #endif
- m_conditionsYesVec.clear();
- m_modelName.clear();
- for (i = 0; i < MAX_TURRETS; ++i)
- {
- m_turrets[i].clear();
- }
- m_hideShowVec.clear();
- for (i = 0; i < WEAPONSLOT_COUNT; ++i)
- {
- m_weaponFireFXBoneName[i].clear();
- m_weaponRecoilBoneName[i].clear();
- m_weaponMuzzleFlashName[i].clear();
- m_weaponProjectileLaunchBoneName[i].clear();
- m_weaponBarrelInfoVec[i].clear();
- m_hasRecoilBonesOrMuzzleFlashes[i] = false;
- }
- m_particleSysBones.clear();
- m_animations.clear();
- m_flags = 0;
- m_transitionKey = NAMEKEY_INVALID;
- m_allowToFinishKey = NAMEKEY_INVALID;
- m_iniReadFlags = 0;
- m_mode = RenderObjClass::ANIM_MODE_ONCE;
- m_transitionSig = NO_TRANSITION;
- m_animMinSpeedFactor = 1.0f;
- m_animMaxSpeedFactor = 1.0f;
- m_pristineBones.clear();
- m_validStuff = 0;
- }
- //-------------------------------------------------------------------------------------------------
- W3DModelDrawModuleData::W3DModelDrawModuleData() :
- m_validated(0),
- m_okToChangeModelColor(false),
- m_particlesAttachedToAnimatedBones(false),
- m_animationsRequirePower(true),
- #ifdef CACHE_ATTACH_BONE
- m_attachToDrawableBoneOffsetValid(false),
- #endif
- m_minLODRequired(STATIC_GAME_LOD_LOW),
- m_defaultState(-1)
- {
- const Real MAX_SHIFT = 3.0f;
- const Real INITIAL_RECOIL_RATE = 2.0f;
- const Real RECOIL_DAMPING = 0.4f;
- const Real SETTLE_RATE = 0.065f;
- m_projectileBoneFeedbackEnabledSlots = 0;
- m_initialRecoil = INITIAL_RECOIL_RATE;
- m_maxRecoil = MAX_SHIFT;
- m_recoilDamping = RECOIL_DAMPING;
- m_recoilSettle = SETTLE_RATE;
- m_receivesDynamicLights = TRUE;
- // m_ignoreConditionStates defaults to all zero, which is what we want
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::validateStuffForTimeAndWeather(const Drawable* draw, Bool night, Bool snowy) const
- {
- if (!isValidTimeToCalcLogicStuff())
- return;
- enum
- {
- NORMAL = 0x0001,
- NIGHT = 0x0002,
- SNOWY = 0x0004,
- NIGHT_SNOWY = 0x0008
- };
- Int mode;
- if (night)
- {
- mode = (snowy) ? NIGHT_SNOWY : NIGHT;
- }
- else
- {
- mode = (snowy) ? SNOWY : NORMAL;
- }
- if (m_validated & mode)
- return;
- m_validated |= mode;
- for (ModelConditionVector::iterator c_it = m_conditionStates.begin(); c_it != m_conditionStates.end(); ++c_it)
- {
- if (!c_it->matchesMode(false, false) && !c_it->matchesMode(night, snowy))
- continue;
- c_it->validateStuff(NULL, draw->getScale(), m_extraPublicBones);
- }
- for (TransitionMap::iterator t_it = m_transitionMap.begin(); t_it != m_transitionMap.end(); ++t_it)
- {
- // here's the tricky part: only want to load the anims for this one if there is at least one
- // source AND at least one dest state that matches the current mode
- NameKeyType src = recoverSrcState(t_it->first);
- NameKeyType dst = recoverDstState(t_it->first);
- Bool a = false;
- Bool b = false;
- for (c_it = m_conditionStates.begin(); c_it != m_conditionStates.end(); ++c_it)
- {
- if (!a && c_it->m_transitionKey == src && c_it->matchesMode(night, snowy))
- a = true;
- if (!b && c_it->m_transitionKey == dst && c_it->matchesMode(night, snowy))
- b = true;
- }
- if (a && b)
- {
- t_it->second.loadAnimations();
- // nope -- transition states don't get public bones.
- //it->addPublicBone(m_extraPublicBones);
- // srj sez: hm, this doesn't make sense; I think we really do need to validate transition states.
- t_it->second.validateStuff(NULL, draw->getScale(), m_extraPublicBones);
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- W3DModelDrawModuleData::~W3DModelDrawModuleData()
- {
- m_conditionStateMap.clear();
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::preloadAssets( TimeOfDay timeOfDay, Real scale ) const
- {
- for( ModelConditionVector::iterator it = m_conditionStates.begin();
- it != m_conditionStates.end();
- ++it )
- {
- it->preloadAssets( timeOfDay, scale );
- }
- }
- //-------------------------------------------------------------------------------------------------
- AsciiString W3DModelDrawModuleData::getBestModelNameForWB(const ModelConditionFlags& c) const
- {
- const ModelConditionInfo* info = findBestInfo(c);
- if (info)
- return info->m_modelName;
- return AsciiString::TheEmptyString;
- }
- #ifdef CACHE_ATTACH_BONE
- //-------------------------------------------------------------------------------------------------
- const Vector3* W3DModelDrawModuleData::getAttachToDrawableBoneOffset(const Drawable* draw) const
- {
- if (m_attachToDrawableBone.isEmpty())
- {
- return NULL;
- }
- else
- {
- if (!m_attachToDrawableBoneOffsetValid)
- {
- // must use pristine bone here since the result is used by logic
- Matrix3D boneMtx;
- if (draw->getPristineBonePositions(m_attachToDrawableBone.str(), 0, NULL, &boneMtx, 1) == 1)
- {
- m_attachToDrawableBoneOffset = boneMtx.Get_Translation();
- }
- else
- {
- m_attachToDrawableBoneOffset.X = 0;
- m_attachToDrawableBoneOffset.Y = 0;
- m_attachToDrawableBoneOffset.Z = 0;
- }
- m_attachToDrawableBoneOffsetValid = true;
- }
- return &m_attachToDrawableBoneOffset;
- }
- }
- #endif
- //-------------------------------------------------------------------------------------------------
- enum ParseCondStateType
- {
- PARSE_NORMAL,
- PARSE_DEFAULT,
- PARSE_TRANSITION,
- PARSE_ALIAS
- };
- //-------------------------------------------------------------------------------------------------
- static void parseAsciiStringLC( INI* ini, void * /*instance*/, void *store, const void* /*userData*/ )
- {
- AsciiString* asciiString = (AsciiString *)store;
- *asciiString = ini->getNextAsciiString();
- asciiString->toLower();
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::buildFieldParse(MultiIniFieldParse& p)
- {
- ModuleData::buildFieldParse(p);
- static const FieldParse dataFieldParse[] =
- {
- { "InitialRecoilSpeed", INI::parseVelocityReal, NULL, offsetof(W3DModelDrawModuleData, m_initialRecoil) },
- { "MaxRecoilDistance", INI::parseReal, NULL, offsetof(W3DModelDrawModuleData, m_maxRecoil) },
- { "RecoilDamping", INI::parseReal, NULL, offsetof(W3DModelDrawModuleData, m_recoilDamping) },
- { "RecoilSettleSpeed", INI::parseVelocityReal, NULL, offsetof(W3DModelDrawModuleData, m_recoilSettle) },
- { "OkToChangeModelColor", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_okToChangeModelColor) },
- { "AnimationsRequirePower", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_animationsRequirePower) },
- { "ParticlesAttachedToAnimatedBones", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_particlesAttachedToAnimatedBones) },
- { "MinLODRequired", INI::parseStaticGameLODLevel, NULL, offsetof(W3DModelDrawModuleData, m_minLODRequired) },
- { "ProjectileBoneFeedbackEnabledSlots", INI::parseBitString32, TheWeaponSlotTypeNames, offsetof(W3DModelDrawModuleData, m_projectileBoneFeedbackEnabledSlots) },
- { "DefaultConditionState", W3DModelDrawModuleData::parseConditionState, (void*)PARSE_DEFAULT, 0 },
- { "ConditionState", W3DModelDrawModuleData::parseConditionState, (void*)PARSE_NORMAL, 0 },
- { "AliasConditionState", W3DModelDrawModuleData::parseConditionState, (void*)PARSE_ALIAS, 0 },
- { "TransitionState", W3DModelDrawModuleData::parseConditionState, (void*)PARSE_TRANSITION, 0 },
- { "TrackMarks", parseAsciiStringLC, NULL, offsetof(W3DModelDrawModuleData, m_trackFile) },
- { "ExtraPublicBone", INI::parseAsciiStringVectorAppend, NULL, offsetof(W3DModelDrawModuleData, m_extraPublicBones) },
- { "AttachToBoneInAnotherModule", parseAsciiStringLC, NULL, offsetof(W3DModelDrawModuleData, m_attachToDrawableBone) },
- { "IgnoreConditionStates", ModelConditionFlags::parseFromINI, NULL, offsetof(W3DModelDrawModuleData, m_ignoreConditionStates) },
- { "ReceivesDynamicLights", INI::parseBool, NULL, offsetof(W3DModelDrawModuleData, m_receivesDynamicLights) },
- { 0, 0, 0, 0 }
- };
- p.add(dataFieldParse);
- }
- //-------------------------------------------------------------------------------------------------
- enum AnimParseType
- {
- ANIM_NORMAL,
- ANIM_IDLE
- };
- //-------------------------------------------------------------------------------------------------
- static void parseAnimation(INI* ini, void *instance, void * /*store*/, const void* userData)
- {
- AnimParseType animType = (AnimParseType)(UnsignedInt)userData;
- AsciiString animName = ini->getNextAsciiString();
- animName.toLower();
- const char* distanceCoveredToken = ini->getNextTokenOrNull();
- Real distanceCovered = distanceCoveredToken ? INI::scanReal(distanceCoveredToken) : 0;
- DEBUG_ASSERTCRASH(!(animType == ANIM_IDLE && distanceCovered != 0), ("You should not specify nonzero DistanceCovered values for Idle Anims"));
- const char* timesToRepeatToken = ini->getNextTokenOrNull();
- Int timesToRepeat = timesToRepeatToken ? INI::scanInt(timesToRepeatToken) : 1;
- if (timesToRepeat < 1) timesToRepeat = 1;
- W3DAnimationInfo animInfo(animName, (animType == ANIM_IDLE), distanceCovered);
- ModelConditionInfo* self = (ModelConditionInfo*)instance;
- if (self->m_iniReadFlags & (1<<ANIMS_COPIED_FROM_DEFAULT_STATE))
- {
- self->m_iniReadFlags &= ~((1<<ANIMS_COPIED_FROM_DEFAULT_STATE)|(1<<GOT_IDLE_ANIMS)|(1<<GOT_NONIDLE_ANIMS));
- self->m_animations.clear();
- }
- if (animInfo.isIdleAnim())
- self->m_iniReadFlags |= (1<<GOT_IDLE_ANIMS);
- else
- self->m_iniReadFlags |= (1<<GOT_NONIDLE_ANIMS);
- if (!animName.isEmpty() && !animName.isNone())
- {
- while (timesToRepeat--)
- self->m_animations.push_back(animInfo);
- }
- }
- //-------------------------------------------------------------------------------------------------
- static void parseShowHideSubObject(INI* ini, void *instance, void *store, const void* userData)
- {
- std::vector<ModelConditionInfo::HideShowSubObjInfo>* vec = (std::vector<ModelConditionInfo::HideShowSubObjInfo>*)store;
- AsciiString subObjName = ini->getNextAsciiString();
- subObjName.toLower();
- // handle "None"
- if (subObjName.isNone())
- {
- vec->clear();
- return;
- }
- while (subObjName.isNotEmpty())
- {
- Bool found = false;
- for (std::vector<ModelConditionInfo::HideShowSubObjInfo>::iterator it = vec->begin(); it != vec->end(); ++it)
- {
- if (stricmp(it->subObjName.str(), subObjName.str()) == 0)
- {
- it->hide = (userData != NULL);
- found = true;
- }
- }
-
- if (!found)
- {
- ModelConditionInfo::HideShowSubObjInfo info;
- info.subObjName = subObjName;
- info.hide = (userData != NULL);
- vec->push_back(info);
- }
- subObjName = ini->getNextAsciiString();
- subObjName.toLower();
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::showSubObject( const AsciiString& name, Bool show )
- {
- if( name.isNotEmpty() )
- {
- Bool found = false;
- for( std::vector<ModelConditionInfo::HideShowSubObjInfo>::iterator it = m_subObjectVec.begin(); it != m_subObjectVec.end(); ++it )
- {
- if( stricmp( it->subObjName.str(), name.str() ) == 0 )
- {
- it->hide = !show;
- found = true;
- }
- }
- if( !found )
- {
- ModelConditionInfo::HideShowSubObjInfo info;
- info.subObjName = name;
- info.hide = !show;
- m_subObjectVec.push_back( info );
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- static void parseWeaponBoneName(INI* ini, void *instance, void * store, const void* /*userData*/)
- {
- ModelConditionInfo* self = (ModelConditionInfo*)instance;
- AsciiString* arr = (AsciiString*)store;
-
- WeaponSlotType wslot = (WeaponSlotType)INI::scanIndexList(ini->getNextToken(), TheWeaponSlotTypeNames);
- arr[wslot] = ini->getNextAsciiString();
- arr[wslot].toLower();
- if (arr[wslot].isNone())
- arr[wslot].clear();
- if (self)
- self->addPublicBone(arr[wslot]);
- }
- //-------------------------------------------------------------------------------------------------
- static void parseParticleSysBone(INI* ini, void *instance, void * store, const void * /*userData*/)
- {
- ParticleSysBoneInfo info;
- info.boneName = ini->getNextAsciiString();
- info.boneName.toLower();
- ini->parseParticleSystemTemplate(ini, instance, &(info.particleSystemTemplate), NULL);
- ModelConditionInfo *self = (ModelConditionInfo *)instance;
- self->m_particleSysBones.push_back(info);
- }
- //-------------------------------------------------------------------------------------------------
- static void parseRealRange( INI *ini, void *instance, void *store, const void* /*userData*/ )
- {
- ModelConditionInfo *self = (ModelConditionInfo *)instance;
- const char *token = ini->getNextToken();
- self->m_animMinSpeedFactor = ini->scanReal( token );
- token = ini->getNextToken();
- self->m_animMaxSpeedFactor = ini->scanReal( token );
- }
- //-------------------------------------------------------------------------------------------------
- static void parseLowercaseNameKey(INI* ini, void *instance, void * store, const void * /*userData*/)
- {
- NameKeyType* key = (NameKeyType*)store;
- AsciiString tmp = ini->getNextToken();
- tmp.toLower();
- *key = NAMEKEY(tmp.str());
- }
- //-------------------------------------------------------------------------------------------------
- static void parseBoneNameKey(INI* ini, void *instance, void * store, const void * /*userData*/)
- {
- ModelConditionInfo* self = (ModelConditionInfo*)instance;
- NameKeyType* key = (NameKeyType*)store;
- AsciiString tmp = ini->getNextToken();
- tmp.toLower();
- if (self)
- self->addPublicBone(tmp);
- if (tmp.isEmpty() || tmp.isNone())
- *key = NAMEKEY_INVALID;
- else
- *key = NAMEKEY(tmp.str());
- }
- //-------------------------------------------------------------------------------------------------
- static Bool doesStateExist(const ModelConditionVector& v, const ModelConditionFlags& f)
- {
- for (ModelConditionVector::const_iterator it = v.begin(); it != v.end(); ++it)
- {
- for (Int i = it->getConditionsYesCount()-1; i >= 0; --i)
- {
- if (f == it->getNthConditionsYes(i))
- return true;
- }
- }
- return false;
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::parseConditionState(INI* ini, void *instance, void * /*store*/, const void* userData)
- {
- static const FieldParse myFieldParse[] =
- {
- { "Model", parseAsciiStringLC, NULL, offsetof(ModelConditionInfo, m_modelName) },
- { "Turret", parseBoneNameKey, NULL, offsetof(ModelConditionInfo, m_turrets[0].m_turretAngleNameKey) },
- { "TurretArtAngle", INI::parseAngleReal, NULL, offsetof(ModelConditionInfo, m_turrets[0].m_turretArtAngle) },
- { "TurretPitch", parseBoneNameKey, NULL, offsetof(ModelConditionInfo, m_turrets[0].m_turretPitchNameKey) },
- { "TurretArtPitch", INI::parseAngleReal, NULL, offsetof(ModelConditionInfo, m_turrets[0].m_turretArtPitch) },
- { "AltTurret", parseBoneNameKey, NULL, offsetof(ModelConditionInfo, m_turrets[1].m_turretAngleNameKey) },
- { "AltTurretArtAngle", INI::parseAngleReal, NULL, offsetof(ModelConditionInfo, m_turrets[1].m_turretArtAngle) },
- { "AltTurretPitch", parseBoneNameKey, NULL, offsetof(ModelConditionInfo, m_turrets[1].m_turretPitchNameKey) },
- { "AltTurretArtPitch", INI::parseAngleReal, NULL, offsetof(ModelConditionInfo, m_turrets[1].m_turretArtPitch) },
- { "ShowSubObject", parseShowHideSubObject, (void*)0, offsetof(ModelConditionInfo, m_hideShowVec) },
- { "HideSubObject", parseShowHideSubObject, (void*)1, offsetof(ModelConditionInfo, m_hideShowVec) },
- { "WeaponFireFXBone", parseWeaponBoneName, NULL, offsetof(ModelConditionInfo, m_weaponFireFXBoneName[0]) },
- { "WeaponRecoilBone", parseWeaponBoneName, NULL, offsetof(ModelConditionInfo, m_weaponRecoilBoneName[0]) },
- { "WeaponMuzzleFlash", parseWeaponBoneName, NULL, offsetof(ModelConditionInfo, m_weaponMuzzleFlashName[0]) },
- { "WeaponLaunchBone", parseWeaponBoneName, NULL, offsetof(ModelConditionInfo, m_weaponProjectileLaunchBoneName[0]) },
- { "WeaponHideShowBone", parseWeaponBoneName, NULL, offsetof(ModelConditionInfo, m_weaponProjectileHideShowName[0]) },
- { "Animation", parseAnimation, (void*)ANIM_NORMAL, offsetof(ModelConditionInfo, m_animations) },
- { "IdleAnimation", parseAnimation, (void*)ANIM_IDLE, offsetof(ModelConditionInfo, m_animations) },
- { "AnimationMode", INI::parseIndexList, TheAnimModeNames, offsetof(ModelConditionInfo, m_mode) },
- { "TransitionKey", parseLowercaseNameKey, NULL, offsetof(ModelConditionInfo, m_transitionKey) },
- { "WaitForStateToFinishIfPossible", parseLowercaseNameKey, NULL, offsetof(ModelConditionInfo, m_allowToFinishKey) },
- { "Flags", INI::parseBitString32, ACBitsNames, offsetof(ModelConditionInfo, m_flags) },
- { "ParticleSysBone", parseParticleSysBone, NULL, 0 },
- { "AnimationSpeedFactorRange", parseRealRange, NULL, 0 },
- { 0, 0, 0, 0 }
- };
- ModelConditionInfo info;
- W3DModelDrawModuleData* self = (W3DModelDrawModuleData*)instance;
- ParseCondStateType cst = (ParseCondStateType)(UnsignedInt)userData;
- switch (cst)
- {
- case PARSE_DEFAULT:
- {
- if (self->m_defaultState >= 0)
- {
- DEBUG_CRASH(("*** ASSET ERROR: you may have only one default state!\n"));
- throw INI_INVALID_DATA;
- }
- else if (ini->getNextTokenOrNull())
- {
- DEBUG_CRASH(("*** ASSET ERROR: unknown keyword\n"));
- throw INI_INVALID_DATA;
- }
- else
- {
- if (!self->m_conditionStates.empty())
- {
- DEBUG_CRASH(("*** ASSET ERROR: when using DefaultConditionState, it must be the first state listed (%s)\n",TheThingTemplateBeingParsedName.str()));
- throw INI_INVALID_DATA;
- }
- // note, this is size(), not size()-1, since we haven't actually modified the list yet
- self->m_defaultState = self->m_conditionStates.size();
- //DEBUG_LOG(("set default state to %d\n",self->m_defaultState));
- // add an empty conditionstateflag set
- ModelConditionFlags blankConditions;
- info.m_conditionsYesVec.clear();
- info.m_conditionsYesVec.push_back(blankConditions);
- #if defined(_DEBUG) || defined(_INTERNAL)
- info.m_description.clear();
- info.m_description.concat(TheThingTemplateBeingParsedName);
- info.m_description.concat(" DEFAULT");
- #endif
- }
- }
- break;
- case PARSE_TRANSITION:
- {
- AsciiString firstNm = ini->getNextToken(); firstNm.toLower();
- AsciiString secondNm = ini->getNextToken(); secondNm.toLower();
- NameKeyType firstKey = NAMEKEY(firstNm);
- NameKeyType secondKey = NAMEKEY(secondNm);
- if (firstKey == secondKey)
- {
- DEBUG_CRASH(("*** ASSET ERROR: You may not declare a transition between two identical states\n"));
- throw INI_INVALID_DATA;
- }
- if (self->m_defaultState >= 0)
- {
- info = self->m_conditionStates.at(self->m_defaultState);
- info.m_iniReadFlags |= (1<<ANIMS_COPIED_FROM_DEFAULT_STATE);
- info.m_transitionKey = NAMEKEY_INVALID;
- info.m_allowToFinishKey = NAMEKEY_INVALID;
- }
- info.m_transitionSig = buildTransitionSig(firstKey, secondKey);
- #if defined(_DEBUG) || defined(_INTERNAL)
- info.m_description.clear();
- info.m_description.concat(TheThingTemplateBeingParsedName);
- info.m_description.concat(" TRANSITION: ");
- info.m_description.concat(firstNm);
- info.m_description.concat(" ");
- info.m_description.concat(secondNm);
- #endif
- }
- break;
- case PARSE_ALIAS:
- {
- if (self->m_conditionStates.empty())
- {
- DEBUG_CRASH(("*** ASSET ERROR: AliasConditionState must refer to the previous state!\n"));
- throw INI_INVALID_DATA;
- }
-
- ModelConditionInfo& prevState = self->m_conditionStates.at(self->m_conditionStates.size()-1);
-
- ModelConditionFlags conditionsYes;
- #if defined(_DEBUG) || defined(_INTERNAL)
- AsciiString description;
- conditionsYes.parse(ini, &description);
- prevState.m_description.concat("\nAKA: ");
- prevState.m_description.concat(description);
- #else
- conditionsYes.parse(ini, NULL);
- #endif
-
- if (conditionsYes.anyIntersectionWith(self->m_ignoreConditionStates))
- {
- DEBUG_CRASH(("You should not specify bits in a state once they are used in IgnoreConditionStates (%s)\n", TheThingTemplateBeingParsedName.str()));
- throw INI_INVALID_DATA;
- }
- if (doesStateExist(self->m_conditionStates, conditionsYes))
- {
- DEBUG_CRASH(("*** ASSET ERROR: duplicate condition states are not currently allowed"));
- throw INI_INVALID_DATA;
- }
- if (!conditionsYes.any() && self->m_defaultState >= 0)
- {
- DEBUG_CRASH(("*** ASSET ERROR: you may not specify both a Default state and a Conditions=None state"));
- throw INI_INVALID_DATA;
- }
- prevState.m_conditionsYesVec.push_back(conditionsYes);
-
- // yes, return, NOT break!
- return;
- }
- case PARSE_NORMAL:
- {
- if (self->m_defaultState >= 0 && cst != PARSE_ALIAS)
- {
- info = self->m_conditionStates.at(self->m_defaultState);
- info.m_iniReadFlags |= (1<<ANIMS_COPIED_FROM_DEFAULT_STATE);
- info.m_conditionsYesVec.clear();
- }
- // no, we do not currently require a default state, cuz it would break the exiting INI
- // files too badly. maybe someday.
- // else
- // {
- // DEBUG_CRASH(("*** ASSET ERROR: you must specify a default state\n"));
- // throw INI_INVALID_DATA;
- // }
-
- ModelConditionFlags conditionsYes;
- #if defined(_DEBUG) || defined(_INTERNAL)
- AsciiString description;
- conditionsYes.parse(ini, &description);
- info.m_description.clear();
- info.m_description.concat(TheThingTemplateBeingParsedName);
- info.m_description.concat("\n ");
- info.m_description.concat(description);
- #else
- conditionsYes.parse(ini, NULL);
- #endif
- if (conditionsYes.anyIntersectionWith(self->m_ignoreConditionStates))
- {
- DEBUG_CRASH(("You should not specify bits in a state once they are used in IgnoreConditionStates (%s)\n", TheThingTemplateBeingParsedName.str()));
- throw INI_INVALID_DATA;
- }
- if (self->m_defaultState < 0 && self->m_conditionStates.empty() && conditionsYes.any())
- {
- // it doesn't actually NEED to be first, but it does need to be present, and this is the simplest way to enforce...
- DEBUG_CRASH(("*** ASSET ERROR: when not using DefaultConditionState, the first ConditionState must be for NONE (%s)\n",TheThingTemplateBeingParsedName.str()));
- throw INI_INVALID_DATA;
- }
- if (!conditionsYes.any() && self->m_defaultState >= 0)
- {
- DEBUG_CRASH(("*** ASSET ERROR: you may not specify both a Default state and a Conditions=None state"));
- throw INI_INVALID_DATA;
- }
- if (doesStateExist(self->m_conditionStates, conditionsYes))
- {
- DEBUG_CRASH(("*** ASSET ERROR: duplicate condition states are not currently allowed (%s)",info.m_description.str()));
- throw INI_INVALID_DATA;
- }
-
- DEBUG_ASSERTCRASH(info.m_conditionsYesVec.size() == 0, ("*** ASSET ERROR: nonempty m_conditionsYesVec.size(), see srj"));
- info.m_conditionsYesVec.clear();
- info.m_conditionsYesVec.push_back(conditionsYes);
- }
- break;
- }
- ini->initFromINI(&info, myFieldParse);
- if (info.m_modelName.isEmpty())
- {
- DEBUG_CRASH(("*** ASSET ERROR: you must specify a model name"));
- throw INI_INVALID_DATA;
- }
- else if (info.m_modelName.isNone())
- {
- info.m_modelName.clear();
- }
- if ((info.m_iniReadFlags & (1<<GOT_IDLE_ANIMS)) && (info.m_iniReadFlags & (1<<GOT_NONIDLE_ANIMS)))
- {
- DEBUG_CRASH(("*** ASSET ERROR: you should not specify both Animations and IdleAnimations for the same state"));
- throw INI_INVALID_DATA;
- }
- if ((info.m_iniReadFlags & (1<<GOT_IDLE_ANIMS)) && (info.m_mode != RenderObjClass::ANIM_MODE_ONCE && info.m_mode != RenderObjClass::ANIM_MODE_ONCE_BACKWARDS))
- {
- DEBUG_CRASH(("*** ASSET ERROR: Idle Anims should always use ONCE or ONCE_BACKWARDS (%s)\n",TheThingTemplateBeingParsedName.str()));
- throw INI_INVALID_DATA;
- }
- info.m_validStuff &= ~ModelConditionInfo::HAS_PROJECTILE_BONES;
- for (int wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot)
- {
- if (info.m_weaponProjectileLaunchBoneName[wslot].isNotEmpty())
- {
- info.m_validStuff |= ModelConditionInfo::HAS_PROJECTILE_BONES;
- break;
- }
- }
- if (cst == PARSE_TRANSITION)
- {
- if (info.m_iniReadFlags & (1<<GOT_IDLE_ANIMS))
- {
- DEBUG_CRASH(("*** ASSET ERROR: Transition States should not specify Idle anims"));
- throw INI_INVALID_DATA;
- }
- if (info.m_mode != RenderObjClass::ANIM_MODE_ONCE && info.m_mode != RenderObjClass::ANIM_MODE_ONCE_BACKWARDS)
- {
- DEBUG_CRASH(("*** ASSET ERROR: Transition States should always use ONCE or ONCE_BACKWARDS"));
- throw INI_INVALID_DATA;
- }
- if (info.m_transitionKey != NAMEKEY_INVALID || info.m_allowToFinishKey != NAMEKEY_INVALID)
- {
- DEBUG_CRASH(("*** ASSET ERROR: Transition States must not have transition keys or m_allowToFinishKey"));
- throw INI_INVALID_DATA;
- }
- self->m_transitionMap[info.m_transitionSig] = info;
- }
- else
- {
- self->m_conditionStates.push_back(info);
- }
- }
- //-------------------------------------------------------------------------------------------------
- static Int countOnBits(UnsignedInt val)
- {
- Int count = 0;
- for (Int i = 0; i < 32; ++i)
- {
- if (val & 1)
- ++count;
- val >>= 1;
- }
- return count;
- }
- //-------------------------------------------------------------------------------------------------
- const ModelConditionInfo* W3DModelDrawModuleData::findBestInfo(const ModelConditionFlags& c) const
- {
- ModelConditionFlags bits = c;
- bits.clear(m_ignoreConditionStates);
- return m_conditionStateMap.findBestInfo(m_conditionStates, bits);
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- W3DModelDraw::W3DModelDraw(Thing *thing, const ModuleData* moduleData) : DrawModule(thing, moduleData)
- {
- int i;
- m_animationMode = RenderObjClass::ANIM_MODE_LOOP;
- m_hideHeadlights = true;
- m_pauseAnimation = false;
- m_curState = NULL;
- m_hexColor = 0;
- m_renderObject = NULL;
- m_shadow = NULL;
- m_shadowEnabled = TRUE;
- m_terrainDecal = NULL;
- m_trackRenderObject = NULL;
- m_whichAnimInCurState = -1;
- m_nextState = NULL;
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- for (i = 0; i < WEAPONSLOT_COUNT; ++i)
- {
- m_weaponRecoilInfoVec[i].clear();
- }
- m_needRecalcBoneParticleSystems = false;
- m_fullyObscuredByShroud = false;
- // only validate the current time-of-day and weather conditions by default.
- getW3DModelDrawModuleData()->validateStuffForTimeAndWeather(getDrawable(),
- TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT,
- TheGlobalData->m_weather == WEATHER_SNOWY);
- ModelConditionFlags emptyFlags;
- const ModelConditionInfo* info = findBestInfo(emptyFlags);
- if (!info)
- {
- DEBUG_CRASH(("*** ASSET ERROR: all draw modules must have an IDLE state\n"));
- throw INI_INVALID_DATA;
- }
- Drawable* draw = getDrawable();
- if ( draw )
- {
- Object* obj = draw->getObject();
- if (obj)
- {
- if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT)
- m_hexColor = obj->getNightIndicatorColor();
- else
- m_hexColor = obj->getIndicatorColor();
- }
- // THE VAST MAJORITY OF THESE SHOULD BE TRUE
- if ( ! getW3DModelDrawModuleData()->m_receivesDynamicLights)
- {
- draw->setReceivesDynamicLights( FALSE );
- DEBUG_LOG(("setReceivesDynamicLights = FALSE: %s\n", draw->getTemplate()->getName().str()));
- }
- }
- setModelState(info);
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::onDrawableBoundToObject(void)
- {
- getW3DModelDrawModuleData()->validateStuffForTimeAndWeather(getDrawable(),
- TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT,
- TheGlobalData->m_weather == WEATHER_SNOWY);
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- W3DModelDraw::~W3DModelDraw(void)
- {
- if (m_trackRenderObject && TheTerrainTracksRenderObjClassSystem)
- {
- TheTerrainTracksRenderObjClassSystem->unbindTrack(m_trackRenderObject);
- m_trackRenderObject = NULL;
- }
- nukeCurrentRender(NULL);
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::doStartOrStopParticleSys()
- {
- Bool hidden = getDrawable()->isDrawableEffectivelyHidden() || m_fullyObscuredByShroud;
- for (std::vector<ParticleSysTrackerType>::const_iterator it = m_particleSystemIDs.begin(); it != m_particleSystemIDs.end(); ++it)
- //for (std::vector<ParticleSystemID>::const_iterator it = m_particleSystemIDs.begin(); it != m_particleSystemIDs.end(); ++it)
- {
- ParticleSystem *sys = TheParticleSystemManager->findParticleSystem((*it).id);
- if (sys != NULL) {
- // this can be NULL
- if (hidden) {
- sys->stop();
- } else {
- sys->start();
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setHidden(Bool hidden)
- {
- if (m_renderObject)
- m_renderObject->Set_Hidden(hidden);
- if (m_shadow)
- m_shadow->enableShadowRender(!hidden);
- m_shadowEnabled = hidden;
- if (m_terrainDecal)
- m_terrainDecal->enableShadowRender(!hidden);
-
- if (m_trackRenderObject && hidden)
- { const Coord3D* pos = getDrawable()->getPosition();
- m_trackRenderObject->addCapEdgeToTrack(pos->x,pos->y);
- }
-
- doStartOrStopParticleSys();
- }
- /**Free all data used by this model's shadow. This is used to dynamically enable/disable shadows by the options screen*/
- void W3DModelDraw::releaseShadows(void) ///< frees all shadow resources used by this module - used by Options screen.
- {
- if (m_shadow)
- m_shadow->release();
- m_shadow = NULL;
- }
- /** Create shadow resources if not already present. This is used to dynamically enable/disable shadows by the options screen*/
- void W3DModelDraw::allocateShadows(void)
- {
- const ThingTemplate *tmplate=getDrawable()->getTemplate();
- //Check if we don't already have a shadow but need one for this type of model.
- if (m_shadow == NULL && m_renderObject && TheW3DShadowManager && tmplate->getShadowType() != SHADOW_NONE)
- {
- Shadow::ShadowTypeInfo shadowInfo;
- strcpy(shadowInfo.m_ShadowName, tmplate->getShadowTextureName().str());
- DEBUG_ASSERTCRASH(shadowInfo.m_ShadowName[0] != '\0', ("this should be validated in ThingTemplate now"));
- shadowInfo.allowUpdates = FALSE; //shadow image will never update
- shadowInfo.allowWorldAlign = TRUE; //shadow image will wrap around world objects
- shadowInfo.m_type = (ShadowType)tmplate->getShadowType();
- shadowInfo.m_sizeX = tmplate->getShadowSizeX();
- shadowInfo.m_sizeY = tmplate->getShadowSizeY();
- shadowInfo.m_offsetX = tmplate->getShadowOffsetX();
- shadowInfo.m_offsetY = tmplate->getShadowOffsetY();
- m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo);
- if (m_shadow)
- { m_shadow->enableShadowInvisible(m_fullyObscuredByShroud);
- if (m_renderObject->Is_Hidden() || !m_shadowEnabled)
- m_shadow->enableShadowRender(FALSE);
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setShadowsEnabled(Bool enable)
- {
- if (m_shadow)
- m_shadow->enableShadowRender(enable);
- m_shadowEnabled = enable;
- }
- /**collect some stats about the rendering cost of this draw module */
- #if defined(_DEBUG) || defined(_INTERNAL)
- void W3DModelDraw::getRenderCost(RenderCost & rc) const
- {
- getRenderCostRecursive(rc,m_renderObject);
- if (m_shadow)
- m_shadow->getRenderCost(rc);
- }
- #endif //_DEBUG || _INTERNAL
- /**recurse through sub-objs to collect stats about the rendering cost of this draw module */
- #if defined(_DEBUG) || defined(_INTERNAL)
- void W3DModelDraw::getRenderCostRecursive(RenderCost & rc,RenderObjClass * robj) const
- {
- if (robj == NULL) return;
- // recurse through sub-objects
- for (int i=0; i<robj->Get_Num_Sub_Objects(); i++) {
- RenderObjClass * sub_obj = robj->Get_Sub_Object(i);
- getRenderCostRecursive(rc,sub_obj);
- REF_PTR_RELEASE(sub_obj);
- }
- // Only consider visible sub-objects. Some vehicles have hidden headlight cones for example
- // that are not normally rendered.
- if (robj->Is_Not_Hidden_At_All()) {
-
- // collect stats from meshes
- if (robj->Class_ID() == RenderObjClass::CLASSID_MESH) {
- MeshClass * mesh = (MeshClass*)robj;
- MeshModelClass * model = mesh->Peek_Model();
- if (model != NULL)
- { if (model->Get_Flag(MeshGeometryClass::SORT))
- rc.addSortedMeshes(1);
- if (model->Get_Flag(MeshGeometryClass::SKIN))
- rc.addSkinMeshes(1);
- }
- rc.addDrawCalls(mesh->Get_Draw_Call_Count());
- }
-
- // collect bone stats.
- const HTreeClass * htree = robj->Get_HTree();
- if (htree != NULL) {
- rc.addBones(htree->Num_Pivots());
- }
- }
- }
- #endif //_DEBUG || _INTERNAL
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setFullyObscuredByShroud(Bool fullyObscured)
- {
- if (m_fullyObscuredByShroud != fullyObscured)
- {
- m_fullyObscuredByShroud = fullyObscured;
- if (m_shadow)
- m_shadow->enableShadowInvisible(m_fullyObscuredByShroud);
- if (m_terrainDecal)
- m_terrainDecal->enableShadowInvisible(m_fullyObscuredByShroud);
- doStartOrStopParticleSys();
- }
- }
- //-------------------------------------------------------------------------------------------------
- static Bool isAnimationComplete(RenderObjClass* r)
- {
- if (r && r->Class_ID() == RenderObjClass::CLASSID_HLOD)
- {
- HLodClass *hlod = (HLodClass*)r;
- return hlod->Is_Animation_Complete();
- }
- return true;
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::adjustAnimSpeedToMovementSpeed()
- {
- // if the cur animation has a "distance covered" number, try to throttle
- // the animation rate to match our actual speed.
- Real dist = getCurAnimDistanceCovered();
- if (dist > 0.0f)
- {
- const Object *obj = getDrawable()->getObject();
- if (obj)
- {
- const PhysicsBehavior* physics = obj->getPhysics();
- if (physics)
- {
- Real speed = physics->getVelocityMagnitude(); // in dist/frame
- if (speed > 0.0f)
- {
- // if distance-covered is specified for this anim, adjust the frame rate
- // so it appears to sync with our unit speed
- Real desiredDurationInMsec = dist / speed * MSEC_PER_LOGICFRAME_REAL;
- setCurAnimDurationInMsec(desiredDurationInMsec);
- }
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::adjustTransformMtx(Matrix3D& mtx) const
- {
- const W3DModelDrawModuleData* d = getW3DModelDrawModuleData();
- #ifdef CACHE_ATTACH_BONE
- const Vector3* offset = d->getAttachToDrawableBoneOffset(getDrawable());
- if (offset)
- {
- Vector3 tmp = mtx.Rotate_Vector(*offset);
- mtx.Adjust_X_Translation(tmp.X);
- mtx.Adjust_Y_Translation(tmp.Y);
- mtx.Adjust_Z_Translation(tmp.Z);
- }
- #else
- if (d->m_attachToDrawableBone.isNotEmpty())
- {
- // override the mtx in this case. yes, call drawable, since the bone in question is
- // likely to be in another module!
- Matrix3D boneMtx;
- if (getDrawable()->getCurrentWorldspaceClientBonePositions(d->m_attachToDrawableBone.str(), boneMtx))
- {
- mtx = boneMtx;
- }
- else
- {
- DEBUG_LOG(("m_attachToDrawableBone %s not found\n",getW3DModelDrawModuleData()->m_attachToDrawableBone.str()));
- }
- }
- #endif
- if (m_curState->m_flags & (1<<ADJUST_HEIGHT_BY_CONSTRUCTION_PERCENT))
- {
- const Object *obj = getDrawable()->getObject();
- if (obj)
- {
- Real pct = obj->getConstructionPercent();
- if (pct >= 0.0f)
- {
- Real height = obj->getGeometryInfo().getMaxHeightAbovePosition();
- mtx.Translate_Z(-height + (height * pct / 100.0f));
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::doDrawModule(const Matrix3D* transformMtx)
- {
- // update whether or not we should be animating.
- setPauseAnimation( !getDrawable()->getShouldAnimate(getW3DModelDrawModuleData()->m_animationsRequirePower) );
- Matrix3D scaledTransform;
- if (getDrawable()->getInstanceScale() != 1.0f)
- {
- // do custom scaling of the W3D model.
- scaledTransform = *transformMtx;
- scaledTransform.Scale(getDrawable()->getInstanceScale());
- transformMtx = &scaledTransform;
- if (m_renderObject)
- m_renderObject->Set_ObjectScale(getDrawable()->getInstanceScale());
- }
- if (isAnimationComplete(m_renderObject))
- {
- if (m_curState != NULL && m_nextState != NULL)
- {
- //DEBUG_LOG(("transition %s is complete\n",m_curState->m_description.str()));
- const ModelConditionInfo* nextState = m_nextState;
- UnsignedInt nextDuration = m_nextStateAnimLoopDuration;
- m_nextState = NULL;
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- setModelState(nextState);
- if (nextDuration != NO_NEXT_DURATION)
- {
- //DEBUG_LOG(("restoring pending duration of %d frames\n",nextDuration));
- setAnimationLoopDuration(nextDuration);
- }
- }
-
- if (m_renderObject &&
- m_curState != NULL &&
- m_whichAnimInCurState != -1)
- {
- if (m_curState->m_animations[m_whichAnimInCurState].isIdleAnim())
- {
- //DEBUG_LOG(("randomly switching to new idle state!\n"));
- // state hasn't changed, if it's been awhile, switch the idle anim
- // (yes, that's right: pass curState for prevState)
- adjustAnimation(m_curState, -1.0);
- }
- else if (testFlagBit(m_curState->m_flags, RESTART_ANIM_WHEN_COMPLETE))
- {
- adjustAnimation(m_curState, -1.0);
- }
- }
- }
- adjustAnimSpeedToMovementSpeed();
- // set our position in the render object to our position of the drawable
- if (m_renderObject)
- {
- Matrix3D mtx = *transformMtx;
- adjustTransformMtx(mtx);
- m_renderObject->Set_Transform(mtx);
- }
- handleClientTurretPositioning();
- recalcBonesForClientParticleSystems();
-
- const W3DModelDrawModuleData *modData = getW3DModelDrawModuleData();
- if ( modData->m_particlesAttachedToAnimatedBones )
- updateBonesForClientParticleSystems();// LORENZEN ADDED THIS
- // IT REPOSITIONS PARTICLESYSTEMS TO TSTAY IN SYNC WITH ANIMATED BONES
-
- handleClientRecoil();
- }
- //-------------------------------------------------------------------------------------------------
- const ModelConditionInfo* W3DModelDraw::findTransitionForSig(TransitionSig sig) const
- {
- const TransitionMap& transitionMap = getW3DModelDrawModuleData()->m_transitionMap;
- TransitionMap::const_iterator it = transitionMap.find(sig);
- if (it != transitionMap.end())
- {
- return &(*it).second;
- }
- return NULL;
- }
- //-------------------------------------------------------------------------------------------------
- Real W3DModelDraw::getCurrentAnimFraction() const
- {
- if (m_curState != NULL
- && isAnyMaintainFrameFlagSet(m_curState->m_flags)
- && m_renderObject != NULL
- && m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD)
- {
- float framenum, dummy;
- int mode, numFrames;
- HLodClass* hlod = (HLodClass*)m_renderObject;
- /*HAnimClass* anim =*/ hlod->Peek_Animation_And_Info(framenum, numFrames, mode, dummy);
- if (framenum < 0.0)
- return 0.0;
- else if (framenum >= numFrames)
- return 1.0;
- else
- return (Real)framenum / ((Real)numFrames - 1);
- }
- else
- {
- return -1.0;
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::adjustAnimation(const ModelConditionInfo* prevState, Real prevAnimFraction)
- {
- if (!m_curState)
- return;
- // if the current state has m_animations associated, do the right thing
- Int numAnims = m_curState->m_animations.size();
- if (numAnims > 0)
- {
- if (numAnims == 1)
- {
- m_whichAnimInCurState = 0;
- }
- else if (prevState == m_curState)
- {
- // select an idle anim different than the currently playing one
- Int animToAvoid = m_whichAnimInCurState;
- while (m_whichAnimInCurState == animToAvoid)
- m_whichAnimInCurState = GameClientRandomValue(0, numAnims-1);
- }
- else
- {
- m_whichAnimInCurState = GameClientRandomValue(0, numAnims-1);
- }
-
- const W3DAnimationInfo& animInfo = m_curState->m_animations[m_whichAnimInCurState];
-
- HAnimClass* animHandle = animInfo.getAnimHandle(); // note that this now returns an ADDREFED handle, which must be released by the caller!
- if (m_renderObject && animHandle)
- {
- Int startFrame = 0;
- if (m_curState->m_mode == RenderObjClass::ANIM_MODE_ONCE_BACKWARDS ||
- m_curState->m_mode == RenderObjClass::ANIM_MODE_LOOP_BACKWARDS)
- {
- startFrame = animHandle->Get_Num_Frames()-1;
- }
- if (testFlagBit(m_curState->m_flags, RANDOMIZE_START_FRAME))
- {
- startFrame = GameClientRandomValue(0, animHandle->Get_Num_Frames()-1);
- }
- else if (testFlagBit(m_curState->m_flags, START_FRAME_FIRST))
- {
- startFrame = 0;
- }
- else if (testFlagBit(m_curState->m_flags, START_FRAME_LAST))
- {
- startFrame = animHandle->Get_Num_Frames()-1;
- }
- // order is important here: MAINTAIN_FRAME_ACROSS_STATES is overridden by the other bits, above.
- else if (isAnyMaintainFrameFlagSet(m_curState->m_flags) &&
- prevState &&
- prevState != m_curState &&
- isAnyMaintainFrameFlagSet(prevState->m_flags) &&
- isCommonMaintainFrameFlagSet(m_curState->m_flags, prevState->m_flags) &&
- prevAnimFraction >= 0.0)
- {
- startFrame = REAL_TO_INT(prevAnimFraction * animHandle->Get_Num_Frames()-1);
- }
- m_renderObject->Set_Animation(animHandle, startFrame, m_curState->m_mode);
- REF_PTR_RELEASE(animHandle);
- animHandle = NULL;
- if (m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD)
- {
- HLodClass *hlod = (HLodClass*)m_renderObject;
- Real factor = GameClientRandomValueReal( m_curState->m_animMinSpeedFactor, m_curState->m_animMaxSpeedFactor );
- hlod->Set_Animation_Frame_Rate_Multiplier( factor );
- }
- }
- }
- else
- {
- m_whichAnimInCurState = -1;
- }
- }
- //-------------------------------------------------------------------------------------------------
- Bool W3DModelDraw::setCurAnimDurationInMsec(Real desiredDurationInMsec)
- {
- if (m_renderObject && m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD)
- {
- HLodClass* hlod = (HLodClass*)m_renderObject;
- HAnimClass* anim = hlod->Peek_Animation();
- if (anim)
- {
- Real naturalDurationInMsec = anim->Get_Num_Frames() * 1000.0f / anim->Get_Frame_Rate();
- if (naturalDurationInMsec > 0.0f && desiredDurationInMsec > 0.0f)
- {
- Real multiplier = naturalDurationInMsec / desiredDurationInMsec;
- hlod->Set_Animation_Frame_Rate_Multiplier(multiplier);
- return true;
- }
- }
- }
- return false;
- }
- //-------------------------------------------------------------------------------------------------
- Real W3DModelDraw::getCurAnimDistanceCovered() const
- {
- if (m_curState != NULL && m_whichAnimInCurState >= 0)
- {
- const W3DAnimationInfo& animInfo = m_curState->m_animations[m_whichAnimInCurState];
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheSkateDistOverride != 0.0f)
- return TheSkateDistOverride;
- #endif
- return animInfo.getDistanceCovered();
- }
- return 0.0f;
- }
- //-------------------------------------------------------------------------------------------------
- /**
- Utility function to make it easier to recursively hide all objects connected to a certain bone.
- We will hide all objects connected to bones which are children of boneIdx
- */
- static void doHideShowBoneSubObjs(Bool state, Int numSubObjects, Int boneIdx, RenderObjClass *fullObject, const HTreeClass *htree)
- {
- #if 1 //(gth) fixed and tested this version
- for (Int i=0; i < numSubObjects; i++)
- {
- bool is_child = false;
- Int parentBoneIndex = fullObject->Get_Sub_Object_Bone_Index(0, i);
-
- while (parentBoneIndex != 0)
- {
- parentBoneIndex = htree->Get_Parent_Index(parentBoneIndex);
- if (parentBoneIndex == boneIdx)
- {
- is_child = true;
- break;
- }
- }
- if (is_child)
- {
- RenderObjClass* childObject = fullObject->Get_Sub_Object(i);
- childObject->Set_Hidden(state);
- childObject->Release_Ref();
- }
- }
- #endif
- #if 0 //old slow version
-
- for (Int i=0; i < numSubObjects; i++)
- {
- Int childBoneIndex = fullObject->Get_Sub_Object_Bone_Index(0, i);
- Int parentIndex = htree->Get_Parent_Index(childBoneIndex);
- if (childBoneIndex == parentIndex)
- continue;
- if (parentIndex == boneIdx) // this object has our subobject as parent so copy hide state
- {
- RenderObjClass* childObject = fullObject->Get_Sub_Object(i);
- // recurse down the hierarchy to hide all sub-children
- doHideShowBoneSubObjs(state, numSubObjects, childBoneIndex, fullObject, htree);
- childObject->Set_Hidden(state);
- childObject->Release_Ref();
- }
- }
- #endif
- }
- //-------------------------------------------------------------------------------------------------
- void ModelConditionInfo::WeaponBarrelInfo::setMuzzleFlashHidden(RenderObjClass *fullObject, Bool hide) const
- {
- if (fullObject)
- {
- RenderObjClass* childObject = fullObject->Get_Sub_Object_On_Bone(0, m_muzzleFlashBone);
- if (childObject)
- {
- childObject->Set_Hidden(hide);
- childObject->Release_Ref();
- }
- else
- {
- DEBUG_CRASH(("*** ASSET ERROR: childObject %s not found in setMuzzleFlashHidden()\n",m_muzzleFlashBoneName.str()));
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::doHideShowSubObjs(const std::vector<ModelConditionInfo::HideShowSubObjInfo>* vec)
- {
- if (!m_renderObject)
- return;
- if (!vec->empty())
- {
- for (std::vector<ModelConditionInfo::HideShowSubObjInfo>::const_iterator it = vec->begin(); it != vec->end(); ++it)
- {
- Int objIndex;
- RenderObjClass* subObj;
- if ((subObj = m_renderObject->Get_Sub_Object_By_Name(it->subObjName.str(), &objIndex)) != NULL)
- {
- subObj->Set_Hidden(it->hide);
- const HTreeClass *htree = m_renderObject->Get_HTree();
- if (htree)
- {
- //get the bone of this subobject so we can hide all other child objects that use this bone
- //as a parent.
- Int boneIdx = m_renderObject->Get_Sub_Object_Bone_Index(0, objIndex);
- doHideShowBoneSubObjs(it->hide, m_renderObject->Get_Num_Sub_Objects(), boneIdx, m_renderObject, htree);
- }
- subObj->Release_Ref();
- }
- else
- {
- DEBUG_CRASH(("*** ASSET ERROR: SubObject %s not found (%s)!\n",it->subObjName.str(),getDrawable()->getTemplate()->getName().str()));
- }
- }
- }
- //Kris (added Aug 2002)
- //This is really important as it allows a person to override modelcondition show/hide objects. Used by the A10 strike
- //September 2002 -- now used by the UpgradeSubObject system.
- if( !m_subObjectVec.empty() )
- {
- updateSubObjects();
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::stopClientParticleSystems()
- {
- for (std::vector<ParticleSysTrackerType>::const_iterator it = m_particleSystemIDs.begin(); it != m_particleSystemIDs.end(); ++it)
- //for (std::vector<ParticleSystemID>::const_iterator it = m_particleSystemIDs.begin(); it != m_particleSystemIDs.end(); ++it)
- {
- ParticleSystem *sys = TheParticleSystemManager->findParticleSystem((*it).id);
- if (sys != NULL)
- {
- // this can be NULL
- sys->destroy();
- }
- }
- m_particleSystemIDs.clear();
- }
- //-------------------------------------------------------------------------------------------------
- /*
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- This function must not EVER do ANYTHING which can in any way, shape, or form
- affect GameLogic in any way; if it does, net desyncs will occur and we
- will all lose our jobs. This must remain pure-client-only, and ensure
- that nothing it does can be detected, even in read-only form, by GameLogic!
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- */
- void W3DModelDraw::handleClientTurretPositioning()
- {
- if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID))
- return;
- for (int tslot = 0; tslot < MAX_TURRETS; ++tslot)
- {
- const ModelConditionInfo::TurretInfo& tur = m_curState->m_turrets[tslot];
- Real turretAngle = 0;
- Real turretPitch = 0;
- if (tur.m_turretAngleBone || tur.m_turretPitchBone)
- {
- const Object *obj = getDrawable()->getObject();
- if (obj)
- {
- const AIUpdateInterface* ai = obj->getAIUpdateInterface();
- if (ai)
- ai->getTurretRotAndPitch((WhichTurretType)tslot, &turretAngle, &turretPitch);
- }
- // do turret, if any
- if (tur.m_turretAngleBone != 0)
- {
- if (m_curState)
- turretAngle += tur.m_turretArtAngle;
- Matrix3D turretXfrm(1);
- turretXfrm.Rotate_Z(turretAngle);
- if (m_renderObject)
- {
- m_renderObject->Capture_Bone( tur.m_turretAngleBone );
- m_renderObject->Control_Bone( tur.m_turretAngleBone, turretXfrm );
- }
- }
- // do turret pitch, if any
- if (tur.m_turretPitchBone != 0)
- {
- if (m_curState)
- turretPitch += tur.m_turretArtPitch;
- Matrix3D turretPitchXfrm(1);
- turretPitchXfrm.Rotate_Y(-turretPitch);
- if (m_renderObject)
- {
- m_renderObject->Capture_Bone( tur.m_turretPitchBone );
- m_renderObject->Control_Bone( tur.m_turretPitchBone, turretPitchXfrm );
- }
- }
- }
- } // next tslot
- }
- //void W3DModelDraw::handleClientFlagPositioning()
- //{
- // const ModelConditionInfo::TurretInfo& tur = m_curState->m_turrets[tslot];
- // Real turretAngle = TheGlobalData->m_downwindAngle;
- // if (tur.m_flagAngleBone )
- // {
- // Matrix3D turretXfrm(1);
- // turretXfrm.Rotate_Z(turretAngle);
- // if (m_renderObject)
- // {
- // m_renderObject->Capture_Bone( tur.m_turretAngleBone );
- // m_renderObject->Control_Bone( tur.m_turretAngleBone, turretXfrm );
- // }
- // }
- //}
- //-------------------------------------------------------------------------------------------------
- /*
- Note that, strictly speaking this code is WRONG, since it assumes it will get called every frame,
- but in fact, will only get called every frame that it is visible. In practice, this isn't a big problem,
- but...
- @todo fix me someday (srj)
- */
- void W3DModelDraw::handleClientRecoil()
- {
- const W3DModelDrawModuleData* d = getW3DModelDrawModuleData();
- if (!(m_curState->m_validStuff & ModelConditionInfo::BARRELS_VALID))
- {
- return;
- }
- // do recoil, if any
- for (int wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot)
- {
- if (!m_curState->m_hasRecoilBonesOrMuzzleFlashes[wslot])
- continue;
- const ModelConditionInfo::WeaponBarrelInfoVec& barrels = m_curState->m_weaponBarrelInfoVec[wslot];
- WeaponRecoilInfoVec& recoils = m_weaponRecoilInfoVec[wslot];
- Int count = barrels.size();
- Int recoilCount = recoils.size();
- DEBUG_ASSERTCRASH(count == recoilCount, ("Barrel count != recoil count!"));
- count = (count>recoilCount)?recoilCount:count;
- for (Int i = 0; i < count; ++i)
- {
- if (barrels[i].m_muzzleFlashBone != 0)
- {
- Bool hidden = recoils[i].m_state != WeaponRecoilInfo::RECOIL_START;
- //DEBUG_LOG(("adjust muzzleflash %08lx for Draw %08lx state %s to %d at frame %d\n",subObjToHide,this,m_curState->m_description.str(),hidden?1:0,TheGameLogic->getFrame()));
- barrels[i].setMuzzleFlashHidden(m_renderObject, hidden);
- }
- const Real TINY_RECOIL = 0.01f;
- if (barrels[i].m_recoilBone != 0)
- {
- switch (recoils[i].m_state )
- {
- case WeaponRecoilInfo::IDLE:
- // nothing
- break;
- case WeaponRecoilInfo::RECOIL_START:
- case WeaponRecoilInfo::RECOIL:
- recoils[i].m_shift += recoils[i].m_recoilRate;
- recoils[i].m_recoilRate *= d->m_recoilDamping; // recoil decelerates
- if (recoils[i].m_shift >= d->m_maxRecoil)
- {
- recoils[i].m_shift = d->m_maxRecoil;
- recoils[i].m_state = WeaponRecoilInfo::SETTLE;
- }
- else if (fabs(recoils[i].m_recoilRate) < TINY_RECOIL)
- {
- recoils[i].m_state = WeaponRecoilInfo::SETTLE;
- }
- break;
- case WeaponRecoilInfo::SETTLE:
- recoils[i].m_shift -= d->m_recoilSettle;
- if (recoils[i].m_shift <= 0.0f)
- {
- recoils[i].m_shift = 0.0f;
- recoils[i].m_state = WeaponRecoilInfo::IDLE;
- }
- break;
- }
- Matrix3D gunXfrm;
- gunXfrm.Make_Identity();
- gunXfrm.Translate_X( -recoils[i].m_shift );
- //DEBUG_ASSERTLOG(recoils[i].m_shift==0.0f,("adjust bone %d by %f\n",recoils[i].m_recoilBone,recoils[i].m_shift));
- if (m_renderObject)
- {
- m_renderObject->Capture_Bone( barrels[i].m_recoilBone );
- m_renderObject->Control_Bone( barrels[i].m_recoilBone, gunXfrm );
- }
- }
- else
- {
- recoils[i].m_state = WeaponRecoilInfo::IDLE;
- //DEBUG_LOG(("reset Draw %08lx state %08lx\n",this,m_curState));
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- /*
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- This function must not EVER do ANYTHING which can in any way, shape, or form
- affect GameLogic in any way; if it does, net desyncs will occur and we
- will all lose our jobs. This must remain pure-client-only, and ensure
- that nothing it does can be detected, even in read-only form, by GameLogic!
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- */
- void W3DModelDraw::recalcBonesForClientParticleSystems()
- {
- if (m_needRecalcBoneParticleSystems)
- {
- const Drawable* drawable = getDrawable();
- if (drawable != NULL )
- {
-
- if( m_curState != NULL && drawable->testDrawableStatus( DRAWABLE_STATUS_NO_STATE_PARTICLES ) == FALSE )
- {
- for (std::vector<ParticleSysBoneInfo>::const_iterator it = m_curState->m_particleSysBones.begin(); it != m_curState->m_particleSysBones.end(); ++it)
- {
- ParticleSystem *sys = TheParticleSystemManager->createParticleSystem(it->particleSystemTemplate);
- if (sys != NULL)
- {
- Coord3D pos;
- pos.zero();
- Real rotation = 0.0f;
- Int boneIndex = m_renderObject ? m_renderObject->Get_Bone_Index(it->boneName.str()) : 0;
- if (boneIndex != 0)
- {
- // ugh... kill the mtx so we get it in modelspace, not world space
- Matrix3D originalTransform = m_renderObject->Get_Transform(); // save the transform
- Matrix3D tmp(true);
- tmp.Scale(getDrawable()->getScale());
- m_renderObject->Set_Transform(tmp); // set to identity transform
- const Matrix3D boneTransform = m_renderObject->Get_Bone_Transform(boneIndex);
- Vector3 vpos = boneTransform.Get_Translation();
- rotation = boneTransform.Get_Z_Rotation();
- m_renderObject->Set_Transform(originalTransform); // restore it
- pos.x = vpos.X;
- pos.y = vpos.Y;
- pos.z = vpos.Z;
- }
- // got the bone position...
- sys->setPosition(&pos);
- // and the direction, so that the system is oriented like the bone is
- sys->rotateLocalTransformZ(rotation);
- // Attatch it to the object...
- sys->attachToDrawable(drawable);
- // important: mark it as do-not-save, since we'll just re-create it when we reload.
- sys->setSaveable(FALSE);
- if (drawable->isDrawableEffectivelyHidden() || m_fullyObscuredByShroud)
- {
- sys->stop(); // don't start the systems for drawables that are hidden.
- }
- // store the particle system id so we can kill it later.
- ParticleSysTrackerType tracker;
- tracker.id = sys->getSystemID();
- tracker.boneIndex = boneIndex;
- m_particleSystemIDs.push_back( tracker );
- }
- }
- }
- }
- m_needRecalcBoneParticleSystems = false;
- }
- }
- //-------------------------------------------------------------------------------------------------
- /*
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- This function must not EVER do ANYTHING which can in any way, shape, or form
- affect GameLogic in any way; if it does, net desyncs will occur and we
- will all lose our jobs. This must remain pure-client-only, and ensure
- that nothing it does can be detected, even in read-only form, by GameLogic!
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- DANGER WARNING READ ME
- */
- Bool W3DModelDraw::updateBonesForClientParticleSystems()
- {
- const Drawable* drawable = getDrawable();
- if (drawable != NULL && m_curState != NULL && m_renderObject != NULL )
- {
- // Matrix3D originalTransform = m_renderObject->Get_Transform();
- // Matrix3D tmp = originalTransform;
- // Vector3 zeroTranslation(0,0,0);
- // tmp.Set_Translation( zeroTranslation );
- // tmp.Scale(drawable->getScale());
- // m_renderObject->Set_Transform(tmp);
-
-
- for (std::vector<ParticleSysTrackerType>::const_iterator it = m_particleSystemIDs.begin(); it != m_particleSystemIDs.end(); ++it)
- {
- ParticleSystem *sys = TheParticleSystemManager->findParticleSystem((*it).id);
- Int boneIndex = (*it).boneIndex;
- if ( (sys != NULL) && (boneIndex != 0) )
- {
- const Matrix3D boneTransform = m_renderObject->Get_Bone_Transform(boneIndex);// just a little worried about state changes
-
- Vector3 vpos = boneTransform.Get_Translation();
- Coord3D pos;
- pos.x = vpos.X;
- pos.y = vpos.Y;
- pos.z = vpos.Z;
- sys->setPosition(&pos);
- Real orientation = boneTransform.Get_Z_Rotation();
- sys->rotateLocalTransformZ(orientation);
-
- sys->setLocalTransform(&boneTransform);
- sys->setSkipParentXfrm(true);
- }
- }// next praticle system
- // m_renderObject->Set_Transform(originalTransform);
- }// end if Drawable
- return TRUE;
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setTerrainDecal(TerrainDecalType type)
- {
- if (m_terrainDecal)
- m_terrainDecal->release();
- m_terrainDecal = NULL;
- if (type == TERRAIN_DECAL_NONE || type >= TERRAIN_DECAL_MAX)
- //turning off decals on this object. (or bad value.)
- return;
- const ThingTemplate *tmplate=getDrawable()->getTemplate();
- //create a new terrain decal
- Shadow::ShadowTypeInfo decalInfo;
- decalInfo.allowUpdates = FALSE; //shadow image will never update
- decalInfo.allowWorldAlign = TRUE; //shadow image will wrap around world objects
- decalInfo.m_type = SHADOW_ALPHA_DECAL;
- //decalInfo.m_type = SHADOW_ADDITIVE_DECAL;//temporary kluge to test graphics
- if (type == TERRAIN_DECAL_SHADOW_TEXTURE)
- strcpy(decalInfo.m_ShadowName,tmplate->getShadowTextureName().str());
- else
- strcpy(decalInfo.m_ShadowName,TerrainDecalTextureName[type]);
- decalInfo.m_sizeX = tmplate->getShadowSizeX();
- decalInfo.m_sizeY = tmplate->getShadowSizeY();
- decalInfo.m_offsetX = tmplate->getShadowOffsetX();
- decalInfo.m_offsetY = tmplate->getShadowOffsetY();
- if (TheProjectedShadowManager)
- m_terrainDecal = TheProjectedShadowManager->addDecal(m_renderObject,&decalInfo);
- if (m_terrainDecal)
- { m_terrainDecal->enableShadowInvisible(m_fullyObscuredByShroud);
- m_terrainDecal->enableShadowRender(m_shadowEnabled);
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setTerrainDecalSize(Real x, Real y)
- {
- if (m_terrainDecal)
- {
- m_terrainDecal->setSize(x,y);
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setTerrainDecalOpacity(Real o)
- {
- if (m_terrainDecal)
- {
- m_terrainDecal->setOpacity((Int)(255.0f * o));
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::nukeCurrentRender(Matrix3D* xform)
- {
- // this needs to be "dirtied" so that the new pausing of the animation will be triggered.
- m_pauseAnimation = false;
- // changing geometry, so we need to remove shadow if present
- if (m_shadow)
- m_shadow->release();
- m_shadow = NULL;
- if(m_terrainDecal)
- m_terrainDecal->release();
- m_terrainDecal = NULL;
- // remove existing render object from the scene
- if (m_renderObject)
- {
- // save the transform for the new model
- if (xform)
- *xform = m_renderObject->Get_Transform();
- W3DDisplay::m_3DScene->Remove_Render_Object(m_renderObject);
- REF_PTR_RELEASE(m_renderObject);
- m_renderObject = NULL;
- }
- else
- {
- if (xform)
- {
- *xform = *getDrawable()->getTransformMatrix();
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL) //art wants to see buildings without flags as a test.
- void W3DModelDraw::hideGarrisonFlags(Bool hide)
- {
- if (!m_renderObject)
- return;
- Int objIndex;
- RenderObjClass* subObj;
- if ((subObj = m_renderObject->Get_Sub_Object_By_Name("POLE", &objIndex)) != NULL)
- {
- subObj->Set_Hidden(hide);
- const HTreeClass *htree = m_renderObject->Get_HTree();
- if (htree)
- {
- //get the bone of this subobject so we can hide all other child objects that use this bone
- //as a parent.
- Int boneIdx = m_renderObject->Get_Sub_Object_Bone_Index(0, objIndex);
- doHideShowBoneSubObjs(hide, m_renderObject->Get_Num_Sub_Objects(), boneIdx, m_renderObject, htree);
- }
- subObj->Release_Ref();
- }
- }
- #endif
- //-------------------------------------------------------------------------------------------------
- /** Hides all subobjects which are headlights. Used to disable lights on models during the day.*/
- void W3DModelDraw::hideAllHeadlights(Bool hide)
- {
- if (m_renderObject)
- {
- for (Int subObj = 0; subObj < m_renderObject->Get_Num_Sub_Objects(); subObj++)
- {
- RenderObjClass* test = m_renderObject->Get_Sub_Object(subObj);
- if (strstr(test->Get_Name(),"HEADLIGHT"))
- {
- test->Set_Hidden(hide);
- }
- test->Release_Ref();
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::hideAllMuzzleFlashes(const ModelConditionInfo* state, RenderObjClass* renderObject)
- {
- if (!state || !renderObject)
- return;
- if (!(state->m_validStuff & ModelConditionInfo::BARRELS_VALID))
- {
- return;
- }
- for (int wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot)
- {
- if (!state->m_hasRecoilBonesOrMuzzleFlashes[wslot])
- continue;
- const ModelConditionInfo::WeaponBarrelInfoVec& barrels = state->m_weaponBarrelInfoVec[wslot];
- for (ModelConditionInfo::WeaponBarrelInfoVec::const_iterator it = barrels.begin(); it != barrels.end(); ++it)
- {
- if (it->m_muzzleFlashBone != 0)
- {
- it->setMuzzleFlashHidden(renderObject, true);
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- static Bool turretNamesDiffer(const ModelConditionInfo* a, const ModelConditionInfo* b)
- {
- if (!(a->m_validStuff & ModelConditionInfo::TURRETS_VALID) || !(b->m_validStuff & ModelConditionInfo::TURRETS_VALID))
- {
- return true;
- }
- for (int i = 0; i < MAX_TURRETS; ++i)
- if (a->m_turrets[i].m_turretAngleNameKey != b->m_turrets[i].m_turretAngleNameKey ||
- a->m_turrets[i].m_turretPitchNameKey != b->m_turrets[i].m_turretPitchNameKey)
- return true;
- return false;
- }
- //-------------------------------------------------------------------------------------------------
- /** Change the model for this drawable. If color is non-zero, it will also apply team color to the
- model */
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setModelState(const ModelConditionInfo* newState)
- {
- DEBUG_ASSERTCRASH(newState, ("invalid state in W3DModelDraw::setModelState\n"));
- #ifdef DEBUG_OBJECT_ID_EXISTS
- if (getDrawable() && getDrawable()->getObject() && getDrawable()->getObject()->getID() == TheObjectIDToDebug)
- {
- DEBUG_LOG(("REQUEST switching to state %s for obj %s %d\n",newState->m_description.str(),getDrawable()->getObject()->getTemplate()->getName().str(),getDrawable()->getObject()->getID()));
- }
- #endif
- const ModelConditionInfo* nextState = NULL;
- if (m_curState != NULL && newState != NULL)
- {
- // if the requested state is the current state (and nothing is pending),
- // or if the requested state is pending, just punt.
- //
- // note that if the requested state matches the current state AND
- // we also have a pending state, then we nuke both of 'em. This sounds
- // weird, but is deliberate: nextState and newState will always be "real" states (or null),
- // leaving us these possibilities:
- //
- // -- curState is a transition state
- // --in this case, new state should take precedence (unless there's a wait-to-finish marking,
- // which would be handled by the else clause)
- //
- // -- curState is a real state, nextState is a real state with a wait-to-finish clause
- // -- if curState == newState, presume that we should restart curState, thus punting thepending nextState
- // -- if curState != newState, presume we should switch to it, thus punting curState and nextState
- //
- // -- curState is a real state, nextState is a real state without a wait-to-finish clause
- // -- should be impossible!
- if ((m_curState == newState && m_nextState == NULL) ||
- (m_curState != NULL && m_nextState == newState))
- {
- #ifdef DEBUG_OBJECT_ID_EXISTS
- if (getDrawable() && getDrawable()->getObject() && getDrawable()->getObject()->getID() == TheObjectIDToDebug)
- {
- DEBUG_LOG(("IGNORE duplicate state %s for obj %s %d\n",newState->m_description.str(),getDrawable()->getObject()->getTemplate()->getName().str(),getDrawable()->getObject()->getID()));
- }
- #endif
- // I don't think he'll be interested...
- // he's already got one, you see
- return;
- }
- // check for allow-to-finish implicit transitions
- else if (newState != m_curState &&
- newState->m_allowToFinishKey != NAMEKEY_INVALID &&
- newState->m_allowToFinishKey == m_curState->m_transitionKey &&
- m_renderObject &&
- !isAnimationComplete(m_renderObject))
- {
- #ifdef DEBUG_OBJECT_ID_EXISTS
- if (getDrawable() && getDrawable()->getObject() && getDrawable()->getObject()->getID() == TheObjectIDToDebug)
- {
- DEBUG_LOG(("ALLOW_TO_FINISH state %s for obj %s %d\n",newState->m_description.str(),getDrawable()->getObject()->getTemplate()->getName().str(),getDrawable()->getObject()->getID()));
- }
- #endif
- m_nextState = newState;
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- return;
- }
- // check for a normal->normal state transition
- else if (newState != m_curState &&
- m_curState->m_transitionKey != NAMEKEY_INVALID &&
- newState->m_transitionKey != NAMEKEY_INVALID)
- {
- TransitionSig sig = buildTransitionSig(m_curState->m_transitionKey, newState->m_transitionKey);
- const ModelConditionInfo* transState = findTransitionForSig(sig);
- if (transState != NULL)
- {
- #ifdef DEBUG_OBJECT_ID_EXISTS
- if (getDrawable() && getDrawable()->getObject() && getDrawable()->getObject()->getID() == TheObjectIDToDebug)
- {
- DEBUG_LOG(("using TRANSITION state %s before requested state %s for obj %s %d\n",transState->m_description.str(),newState->m_description.str(),getDrawable()->getObject()->getTemplate()->getName().str(),getDrawable()->getObject()->getID()));
- }
- #endif
- nextState = newState;
- newState = transState;
- }
- }
- }
-
- // get this here, before we change anything... we'll need it to pass to adjustAnimation (srj)
- Real prevAnimFraction = getCurrentAnimFraction();
- //
- // Set up any particle effects for the new model. Also stop the old ones, note that we
- // will never allow the placement of new ones if the status bit is set that tells us
- // we should not automatically create particle systems for the model condition states
- //
- if( getDrawable()->testDrawableStatus( DRAWABLE_STATUS_NO_STATE_PARTICLES ) == FALSE )
- m_needRecalcBoneParticleSystems = true;
- // always stop particle systems now
- stopClientParticleSystems();
- // and always hide muzzle flashes, in case modelstate and model have crossed at the same time
- hideAllMuzzleFlashes(newState, m_renderObject);
- // note that different states might use the same model; for these, don't go thru the
- // expense of creating a new render-object. (exception: if color is changing, or subobjs are changing,
- // or a few other things...)
- if (m_curState == NULL ||
- newState->m_modelName != m_curState->m_modelName ||
- turretNamesDiffer(newState, m_curState)
- // srj sez: I'm not sure why we want to do the "hard stuff" if we have projectile bones; I think
- // it is a holdover from days gone by when bones were handled quite differently, rather than being cached.
- // but doing this hard stuff is a lot more work, and I think it's unnecessary, so let's remove this.
- //|| (newState->m_validStuff & ModelConditionInfo::HAS_PROJECTILE_BONES)
- )
- {
- Matrix3D transform;
- nukeCurrentRender(&transform);
- Drawable* draw = getDrawable();
- // create a new render object and set into drawable
- if (newState->m_modelName.isEmpty())
- {
- m_renderObject = NULL;
- }
- else
- {
- m_renderObject = W3DDisplay::m_assetManager->Create_Render_Obj(newState->m_modelName.str(), draw->getScale(), m_hexColor);
- DEBUG_ASSERTCRASH(m_renderObject, ("*** ASSET ERROR: Model %s not found!\n",newState->m_modelName.str()));
- }
- //BONEPOS_LOG(("validateStuff() from within W3DModelDraw::setModelState()\n"));
- //BONEPOS_DUMPREAL(draw->getScale());
- newState->validateStuff(m_renderObject, draw->getScale(), getW3DModelDrawModuleData()->m_extraPublicBones);
- // ensure that any muzzle flashes from the *new* state, start out hidden...
- // hideAllMuzzleFlashes(newState, m_renderObject);//moved to above
- rebuildWeaponRecoilInfo(newState);
- doHideShowSubObjs(&newState->m_hideShowVec);
- #if defined(_DEBUG) || defined(_INTERNAL) //art wants to see buildings without flags as a test.
- if (TheGlobalData->m_hideGarrisonFlags && draw->isKindOf(KINDOF_STRUCTURE))
- hideGarrisonFlags(TRUE);
- #endif
- const ThingTemplate *tmplate = draw->getTemplate();
- // set up tracks, if not already set.
- if (m_renderObject &&
- TheGlobalData->m_makeTrackMarks &&
- !m_trackRenderObject &&
- TheTerrainTracksRenderObjClassSystem != NULL &&
- !getW3DModelDrawModuleData()->m_trackFile.isEmpty())
- {
- m_trackRenderObject = TheTerrainTracksRenderObjClassSystem->bindTrack(m_renderObject, 1.0f*MAP_XY_FACTOR, getW3DModelDrawModuleData()->m_trackFile.str());
- if (draw && m_trackRenderObject)
- m_trackRenderObject->setOwnerDrawable(draw);
- }
- // set up shadows
- if (m_renderObject && TheW3DShadowManager && tmplate->getShadowType() != SHADOW_NONE)
- {
- Shadow::ShadowTypeInfo shadowInfo;
- strcpy(shadowInfo.m_ShadowName, tmplate->getShadowTextureName().str());
- DEBUG_ASSERTCRASH(shadowInfo.m_ShadowName[0] != '\0', ("this should be validated in ThingTemplate now"));
- shadowInfo.allowUpdates = FALSE; //shadow image will never update
- shadowInfo.allowWorldAlign = TRUE; //shadow image will wrap around world objects
- shadowInfo.m_type = (ShadowType)tmplate->getShadowType();
- shadowInfo.m_sizeX = tmplate->getShadowSizeX();
- shadowInfo.m_sizeY = tmplate->getShadowSizeY();
- shadowInfo.m_offsetX = tmplate->getShadowOffsetX();
- shadowInfo.m_offsetY = tmplate->getShadowOffsetY();
- m_shadow = TheW3DShadowManager->addShadow(m_renderObject, &shadowInfo, draw);
- if (m_shadow)
- { m_shadow->enableShadowInvisible(m_fullyObscuredByShroud);
- m_shadow->enableShadowRender(m_shadowEnabled);
- }
- }
- if( m_renderObject )
- {
- // set collision type for render object. Used by WW3D2 collision code.
- if (tmplate->isKindOf(KINDOF_SELECTABLE))
- {
- m_renderObject->Set_Collision_Type( PICK_TYPE_SELECTABLE );
- }
- if( tmplate->isKindOf( KINDOF_SHRUBBERY ))
- {
- m_renderObject->Set_Collision_Type( PICK_TYPE_SHRUBBERY );
- }
- if( tmplate->isKindOf( KINDOF_MINE ))
- {
- m_renderObject->Set_Collision_Type( PICK_TYPE_MINES );
- }
- if( tmplate->isKindOf( KINDOF_FORCEATTACKABLE ))
- {
- m_renderObject->Set_Collision_Type( PICK_TYPE_FORCEATTACKABLE );
- }
- if( tmplate->isKindOf( KINDOF_CLICK_THROUGH ))
- {
- m_renderObject->Set_Collision_Type( 0 );
- }
-
- Object *obj = draw->getObject();
- if( obj )
- {
- // for non bridge objects we adjust some collision types
- if( obj->isKindOf( KINDOF_BRIDGE ) == FALSE &&
- obj->isKindOf( KINDOF_BRIDGE_TOWER ) == FALSE )
- {
- if( obj->isKindOf( KINDOF_STRUCTURE ) && draw->getModelConditionFlags().test( MODELCONDITION_RUBBLE ) )
- {
- //A dead building, -- don't allow the user to click on rubble! Treat it as a location instead.
- m_renderObject->Set_Collision_Type( 0 );
- }
- else if( obj->isEffectivelyDead() )
- {
- //A dead object, -- don't allow the user to click on rubble/hulks! Treat it as a location instead.
- m_renderObject->Set_Collision_Type( 0 );
- }
- }
- }
- // add render object to our scene
- W3DDisplay::m_3DScene->Add_Render_Object(m_renderObject);
- // tie in our drawable as the user data pointer in the render object
- m_renderObject->Set_User_Data(draw->getDrawableInfo());
-
- setTerrainDecal(draw->getTerrainDecalType());
- //We created a new render object so we need to preserve the visibility state
- //of the previous render object.
- if (draw->isDrawableEffectivelyHidden())
- {
- m_renderObject->Set_Hidden(TRUE);
- if (m_shadow)
- m_shadow->enableShadowRender(FALSE);
- m_shadowEnabled = FALSE;
- }
-
- //
- // set the transform for the new model to that we saved before, we do this so that the
- // model transition is smooth and will immediately appear at the same orientation and location
- // as the previous one
- //
- m_renderObject->Set_Transform(transform);
- onRenderObjRecreated();
- }
- }
- else
- {
- //BONEPOS_LOG(("validateStuff() from within W3DModelDraw::setModelState()\n"));
- //BONEPOS_DUMPREAL(getDrawable()->getScale());
- newState->validateStuff(m_renderObject, getDrawable()->getScale(), getW3DModelDrawModuleData()->m_extraPublicBones);
- rebuildWeaponRecoilInfo(newState);
- // ensure that any muzzle flashes from the *previous* state, are hidden...
- // hideAllMuzzleFlashes(m_curState, m_renderObject);// moved to above
-
- doHideShowSubObjs(&newState->m_hideShowVec);
- }
- hideAllHeadlights(m_hideHeadlights);
- const ModelConditionInfo* prevState = m_curState; // save, to pass to adjustAnimation (could be null)
- m_curState = newState;
- m_nextState = nextState;
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- adjustAnimation(prevState, prevAnimFraction);
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::replaceModelConditionState(const ModelConditionFlags& c)
- {
- m_hideHeadlights = c.test(MODELCONDITION_NIGHT) ? false : true;
- const ModelConditionInfo* info = findBestInfo(c);
- if (info)
- setModelState(info);
- hideAllHeadlights(m_hideHeadlights);
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setSelectable(Bool selectable)
- {
- // set collision type for render object. Used by WW3D2 collision code.
- if( m_renderObject )
- {
- int current = m_renderObject->Get_Collision_Type();
- if (selectable) {
- current |= PICK_TYPE_SELECTABLE;
- } else {
- current &= ~PICK_TYPE_SELECTABLE;
- }
- m_renderObject->Set_Collision_Type(current);
- } // end if
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::replaceIndicatorColor(Color color)
- {
- if (!getW3DModelDrawModuleData()->m_okToChangeModelColor)
- return;
- if (getRenderObject())
- {
- Int newColor = (color == 0) ? 0 : (color | 0xFF000000);
- if (newColor != m_hexColor)
- {
- m_hexColor = newColor;
- // set these to NULL to force a regen of everything in setModelState.
- const ModelConditionInfo* tmp = m_curState;
- m_curState = NULL;
- m_nextState = NULL;
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- setModelState(tmp);
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- // this method must ONLY be called from the client, NEVER From the logic, not even indirectly.
- Bool W3DModelDraw::clientOnly_getRenderObjInfo(Coord3D* pos, Real* boundingSphereRadius, Matrix3D* transform) const
- {
- if (!m_renderObject)
- return false;
- Vector3 objPos = m_renderObject->Get_Position(); //get position of object
- pos->x = objPos.X;
- pos->y = objPos.Y;
- pos->z = objPos.Z;
- *transform = m_renderObject->Get_Transform();
- *boundingSphereRadius = m_renderObject->Get_Bounding_Sphere().Radius;
- return true;
- }
- //-------------------------------------------------------------------------------------------------
- Bool W3DModelDraw::getProjectileLaunchOffset(
- const ModelConditionFlags& condition,
- WeaponSlotType wslot,
- Int specificBarrelToUse,
- Matrix3D* launchPos,
- WhichTurretType tur,
- Coord3D* turretRotPos,
- Coord3D* turretPitchPos
- ) const
- {
- /*
- Note, this recalcs the state every time, rather than using m_curState,
- because m_curState could be a transition state, and we really need
- to get the pristine bone(s) for the state that logic believes to be current,
- not the one the client might currently be using...
- */
- const ModelConditionInfo* stateToUse = findBestInfo(condition);
- if (!stateToUse)
- {
- CRCDEBUG_LOG(("can't find best info\n"));
- //BONEPOS_LOG(("can't find best info\n"));
- return false;
- }
- #if defined(_DEBUG) || defined(_INTERNAL)
- CRCDEBUG_LOG(("W3DModelDraw::getProjectileLaunchOffset() for %s\n",
- stateToUse->getDescription().str()));
- #endif
- #ifdef INTENSE_DEBUG
- AsciiString flags;
- for (Int i=0; i<condition.size(); ++i)
- {
- if (condition.test(i))
- {
- if (flags.isNotEmpty())
- flags.concat(',');
- flags.concat(condition.getNameFromSingleBit(i));
- }
- }
- #endif // INTENSE_DEBUG
- const W3DModelDrawModuleData* d = getW3DModelDrawModuleData();
- //CRCDEBUG_LOG(("validateStuffs() from within W3DModelDraw::getProjectileLaunchOffset()\n"));
- //DUMPREAL(getDrawable()->getScale());
- //BONEPOS_LOG(("validateStuffs() from within W3DModelDraw::getProjectileLaunchOffset()\n"));
- //BONEPOS_DUMPREAL(getDrawable()->getScale());
- stateToUse->validateStuff(NULL, getDrawable()->getScale(), d->m_extraPublicBones);
- DEBUG_ASSERTCRASH(stateToUse->m_transitionSig == NO_TRANSITION,
- ("It is never legal to getProjectileLaunchOffset from a Transition state (they vary on a per-client basis)... however, we can fix this (see srj)\n"));
- DEBUG_ASSERTCRASH(specificBarrelToUse >= 0, ("specificBarrelToUse should now always be explicit"));
- #ifdef CACHE_ATTACH_BONE
- #else
- Coord3D techOffset;
- techOffset.zero();
- // must use pristine bone here since the result is used by logic
- Matrix3D pivot;
- if (d->m_attachToDrawableBone.isNotEmpty() &&
- getDrawable()->getPristineBonePositions( d->m_attachToDrawableBone.str(), 0, NULL, &pivot, 1 ) == 1)
- {
- pivot.Pre_Rotate_Z(getDrawable()->getOrientation());
- techOffset.x = pivot.Get_X_Translation();
- techOffset.y = pivot.Get_Y_Translation();
- techOffset.z = pivot.Get_Z_Translation();
- }
- #endif
- CRCDEBUG_LOG(("wslot = %d\n", wslot));
- const ModelConditionInfo::WeaponBarrelInfoVec& wbvec = stateToUse->m_weaponBarrelInfoVec[wslot];
- if( wbvec.empty() )
- {
- // Can't find the launch pos, but they might still want the other info they asked for
- CRCDEBUG_LOG(("empty wbvec\n"));
- //BONEPOS_LOG(("empty wbvec\n"));
- launchPos = NULL;
- }
- else
- {
- if (specificBarrelToUse < 0 || specificBarrelToUse >= wbvec.size())
- specificBarrelToUse = 0;
- if (launchPos)
- {
- CRCDEBUG_LOG(("specificBarrelToUse = %d\n", specificBarrelToUse));
- *launchPos = wbvec[specificBarrelToUse].m_projectileOffsetMtx;
- if (tur != TURRET_INVALID)
- {
- launchPos->Pre_Rotate_Z(stateToUse->m_turrets[tur].m_turretArtAngle);
- launchPos->Pre_Rotate_Y(-stateToUse->m_turrets[tur].m_turretArtPitch);
- }
- #ifdef CACHE_ATTACH_BONE
- #else
- launchPos->Adjust_Translation( Vector3( techOffset.x, techOffset.y, techOffset.z ) );
- #endif
- DUMPMATRIX3D(launchPos);
- }
- }
- if (turretRotPos)
- turretRotPos->zero();
- if (turretPitchPos)
- turretPitchPos->zero();
- if (tur != TURRET_INVALID)
- {
- #ifdef CACHE_ATTACH_BONE
- const Vector3* offset = d->getAttachToDrawableBoneOffset(getDrawable());
- #endif
- const ModelConditionInfo::TurretInfo& turInfo = stateToUse->m_turrets[tur];
- if (turretRotPos)
- {
- if (turInfo.m_turretAngleNameKey != NAMEKEY_INVALID &&
- !stateToUse->findPristineBonePos(turInfo.m_turretAngleNameKey, *turretRotPos))
- {
- DEBUG_CRASH(("*** ASSET ERROR: TurretBone %s not found!\n",KEYNAME(turInfo.m_turretAngleNameKey).str()));
- }
- #ifdef CACHE_ATTACH_BONE
- if (offset)
- {
- turretRotPos->x += offset->X;
- turretRotPos->y += offset->Y;
- turretRotPos->z += offset->Z;
- }
- #endif
- }
- if (turretPitchPos)
- {
- if (turInfo.m_turretPitchNameKey != NAMEKEY_INVALID &&
- !stateToUse->findPristineBonePos(turInfo.m_turretPitchNameKey, *turretPitchPos))
- {
- DEBUG_CRASH(("*** ASSET ERROR: TurretBone %s not found!\n",KEYNAME(turInfo.m_turretPitchNameKey).str()));
- }
- #ifdef CACHE_ATTACH_BONE
- if (offset)
- {
- turretPitchPos->x += offset->X;
- turretPitchPos->y += offset->Y;
- turretPitchPos->z += offset->Z;
- }
- #endif
- }
- }
- return launchPos != NULL;// return if LaunchPos is valid or not
- }
- //-------------------------------------------------------------------------------------------------
- Int W3DModelDraw::getPristineBonePositionsForConditionState(
- const ModelConditionFlags& condition,
- const char* boneNamePrefix,
- Int startIndex,
- Coord3D* positions,
- Matrix3D* transforms,
- Int maxBones
- ) const
- {
- /*
- Note, this recalcs the state every time, rather than using m_curState,
- because m_curState could be a transition state, and we really need
- to get the pristine bone(s) for the state that logic believes to be current,
- not the one the client might currently be using...
- */
- const ModelConditionInfo* stateToUse = findBestInfo(condition);
- if (!stateToUse)
- return 0;
- // if (isValidTimeToCalcLogicStuff())
- // {
- // CRCDEBUG_LOG(("W3DModelDraw::getPristineBonePositionsForConditionState() - state = '%s'\n",
- // stateToUse->getDescription().str()));
- // //CRCDEBUG_LOG(("renderObject == NULL: %d\n", (stateToUse==m_curState)?(m_renderObject == NULL):1));
- // }
- //BONEPOS_LOG(("validateStuff() from within W3DModelDraw::getPristineBonePositionsForConditionState()\n"));
- //BONEPOS_DUMPREAL(getDrawable()->getScale());
- // we must call this every time we set m_nextState, to ensure cached bones are happy
- stateToUse->validateStuff(
- // if the state is the current state, pass in the current render object
- // so that we don't have to re-create it!
- stateToUse == m_curState ? m_renderObject : NULL,
- getDrawable()->getScale(),
- getW3DModelDrawModuleData()->m_extraPublicBones);
- const int MAX_BONE_GET = 64;
- Matrix3D tmpMtx[MAX_BONE_GET];
- if (maxBones > MAX_BONE_GET)
- maxBones = MAX_BONE_GET;
- if (transforms == NULL)
- transforms = tmpMtx;
- Int posCount = 0;
- Int endIndex = (startIndex == 0) ? 0 : 99;
- char buffer[256];
- for (Int i = startIndex; i <= endIndex; ++i)
- {
- if (i == 0)
- strcpy(buffer, boneNamePrefix);
- else
- sprintf(buffer, "%s%02d", boneNamePrefix, i);
-
- for (char *c = buffer; c && *c; ++c)
- {
- // convert to all-lowercase since that's how we filled in the map
- *c = tolower(*c);
- }
- const Matrix3D* mtx = stateToUse->findPristineBone(NAMEKEY(buffer), NULL);
- if (mtx)
- {
- transforms[posCount] = *mtx;
- // if (isValidTimeToCalcLogicStuff())
- // {
- // DUMPMATRIX3D(mtx);
- // }
- }
- else
- {
- //DEBUG_CRASH(("*** ASSET ERROR: Bone %s not found!\n",buffer));
- const Object *obj = getDrawable()->getObject();
- if (obj)
- transforms[posCount] = *obj->getTransformMatrix();
- else
- transforms[posCount].Make_Identity();
- break;
- }
- ++posCount;
- if (posCount >= maxBones)
- break;
- }
-
- if (positions && transforms)
- {
- for (i = 0; i < posCount; ++i)
- {
- Vector3 pos = transforms[i].Get_Translation();
- positions[i].x = pos.X;
- positions[i].y = pos.Y;
- positions[i].z = pos.Z;
- // if (isValidTimeToCalcLogicStuff())
- // {
- // DUMPCOORD3D(&(positions[i]));
- // }
- }
- }
- // if (isValidTimeToCalcLogicStuff())
- // {
- // CRCDEBUG_LOG(("end of W3DModelDraw::getPristineBonePositionsForConditionState()\n"));
- // }
- return posCount;
- }
- //-------------------------------------------------------------------------------------------------
- // (gth) C&C3 Added this accessor for the bounding box of a render object in a W3DModelDraw module
- // this method must ONLY be called from the client, NEVER From the logic, not even indirectly.
- Bool W3DModelDraw::clientOnly_getRenderObjBoundBox(OBBoxClass * boundbox) const
- {
- if (!m_renderObject)
- return false;
- AABoxClass aabox;
- m_renderObject->Get_Obj_Space_Bounding_Box(aabox);
- Matrix3D tm = m_renderObject->Get_Transform();
- // build an OBB for this AAB,transform
- OBBoxClass box0(aabox.Center,aabox.Extent);
- OBBoxClass::Transform(tm,box0,boundbox);
- return true;
- }
- //-------------------------------------------------------------------------------------------------
- // (gth) C&C3 Added this accessor for a bone transform in the render object
- // this method must ONLY be called from the client, NEVER From the logic, not even indirectly.
- Bool W3DModelDraw::clientOnly_getRenderObjBoneTransform(const AsciiString & boneName,Matrix3D * set_tm) const
- {
- if (!m_renderObject) {
- return false;
- }
- int idx = m_renderObject->Get_Bone_Index(boneName.str());
- if (idx == 0) {
- set_tm->Make_Identity();
- return false;
- } else {
- *set_tm = m_renderObject->Get_Bone_Transform(idx);
- return true;
- }
- }
- //-------------------------------------------------------------------------------------------------
- Bool W3DModelDraw::getCurrentWorldspaceClientBonePositions(const char* boneName, Matrix3D& transform) const
- {
- if (!m_renderObject)
- return false;
- Int boneIndex = m_renderObject->Get_Bone_Index(boneName);
- if (boneIndex == 0)
- return false;
- transform = m_renderObject->Get_Bone_Transform(boneIndex);
- return true;
- }
- //-------------------------------------------------------------------------------------------------
- Int W3DModelDraw::getCurrentBonePositions(
- const char* boneNamePrefix,
- Int startIndex,
- Coord3D* positions,
- Matrix3D* transforms,
- Int maxBones
- ) const
- {
- const int MAX_BONE_GET = 64;
- Matrix3D tmpMtx[MAX_BONE_GET];
- if (maxBones > MAX_BONE_GET)
- maxBones = MAX_BONE_GET;
- if (transforms == NULL)
- transforms = tmpMtx;
- if( !m_renderObject )
- return 0;
- // ugh... kill the mtx so we get it in modelspace, not world space
- Matrix3D originalTransform = m_renderObject->Get_Transform(); // save the transform
- // which is faster: slamming the xform (and invalidating the objects xforms)
- // or inverting it ourself? gotta profile to see. (srj)
- #define DO_INV
- #ifdef DO_INV
- Matrix3D inverse;
- originalTransform.Get_Orthogonal_Inverse(inverse);
- inverse.Scale(getDrawable()->getScale());
- #else
- Matrix3D tmp(true);
- tmp.Scale(getDrawable()->getScale());
- m_renderObject->Set_Transform(tmp); // set to identity transform
- #endif
- Int posCount = 0;
- Int endIndex = (startIndex == 0) ? 0 : 99;
- char buffer[256];
- for (Int i = startIndex; i <= endIndex; ++i)
- {
- if (i == 0)
- strcpy(buffer, boneNamePrefix);
- else
- sprintf(buffer, "%s%02d", boneNamePrefix, i);
-
- Int boneIndex = m_renderObject->Get_Bone_Index(buffer);
- if (boneIndex == 0)
- break;
- transforms[posCount] = m_renderObject->Get_Bone_Transform(boneIndex);
- #ifdef DO_INV
- transforms[posCount].preMul(inverse);
- #endif
- //DEBUG_ASSERTCRASH(!m_renderObject->Is_Bone_Captured(boneIndex), ("bone is captured!"));
- ++posCount;
- if (posCount >= maxBones)
- break;
- }
-
- if (positions && transforms)
- {
- for (i = 0; i < posCount; ++i)
- {
- Vector3 pos = transforms[i].Get_Translation();
- positions[i].x = pos.X;
- positions[i].y = pos.Y;
- positions[i].z = pos.Z;
- }
- }
- #ifdef DO_INV
- #else
- m_renderObject->Set_Transform(originalTransform); // restore it
- #endif
- return posCount;
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::reactToTransformChange( const Matrix3D* oldMtx,
- const Coord3D* oldPos,
- Real oldAngle )
- {
- // set the position of our render object
- if( m_renderObject )
- {
- Matrix3D mtx = *getDrawable()->getTransformMatrix();
- adjustTransformMtx(mtx);
- m_renderObject->Set_Transform(mtx);
- }
- if (m_trackRenderObject)
- {
- Object *obj = getDrawable()->getObject();
- const Coord3D* pos = getDrawable()->getPosition();
- if ( m_fullyObscuredByShroud || obj->testStatus( OBJECT_STATUS_STEALTHED ) == TRUE )
- {
- m_trackRenderObject->addCapEdgeToTrack(pos->x, pos->y);
- }
- else
- {
- if (obj && obj->isSignificantlyAboveTerrain())
- {
- m_trackRenderObject->setAirborne();
- }
- m_trackRenderObject->addEdgeToTrack(pos->x, pos->y);
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- const ModelConditionInfo* W3DModelDraw::findBestInfo(const ModelConditionFlags& c) const
- {
- return getW3DModelDrawModuleData()->findBestInfo(c);
- }
- //-------------------------------------------------------------------------------------------------
- Int W3DModelDraw::getBarrelCount(WeaponSlotType wslot) const
- {
- return (m_curState && (m_curState->m_validStuff & ModelConditionInfo::BARRELS_VALID)) ?
- m_curState->m_weaponBarrelInfoVec[wslot].size() : 0;
- }
- //-------------------------------------------------------------------------------------------------
- Bool W3DModelDraw::handleWeaponFireFX(WeaponSlotType wslot, Int specificBarrelToUse, const FXList* fxl, Real weaponSpeed, const Coord3D* victimPos, Real damageRadius)
- {
- DEBUG_ASSERTCRASH(specificBarrelToUse >= 0, ("specificBarrelToUse should now always be explicit"));
- if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::BARRELS_VALID))
- return false;
- const ModelConditionInfo::WeaponBarrelInfoVec& wbvec = m_curState->m_weaponBarrelInfoVec[wslot];
- if (wbvec.empty())
- {
- // don't do this... some other module of our drawable may have handled it.
- // just return false and let the caller sort it out.
- // FXList::doFXPos(fxl, getDrawable()->getPosition(), getDrawable()->getTransformMatrix(), weaponSpeed, victimPos);
- return false;
- }
-
- Bool handled = false;
- if (specificBarrelToUse < 0 || specificBarrelToUse > wbvec.size())
- specificBarrelToUse = 0;
- const ModelConditionInfo::WeaponBarrelInfo& info = wbvec[specificBarrelToUse];
- if (fxl)
- {
- if (info.m_fxBone && m_renderObject)
- {
- const Object *logicObject = getDrawable()->getObject();// This is slow, so store it
- if( ! m_renderObject->Is_Hidden() || (logicObject == NULL) )
- {
- // I can ask the drawable's bone position if I am not hidden (if I have no object I have no choice)
- Matrix3D mtx = m_renderObject->Get_Bone_Transform(info.m_fxBone);
- Coord3D pos;
- pos.x = mtx.Get_X_Translation();
- pos.y = mtx.Get_Y_Translation();
- pos.z = mtx.Get_Z_Translation();
- FXList::doFXPos(fxl, &pos, &mtx, weaponSpeed, victimPos, damageRadius);
- }
- else
- {
- // Else, I should just use my logic position for the effect placement.
- // Things in transports regularly fire from inside (hidden), so this is not weird.
- const Matrix3D *mtx;
- Coord3D pos;
- mtx = logicObject->getTransformMatrix();
- pos = *(logicObject->getPosition());
- /** @todo Once Firepoint bones are actually implemented, this matrix will become correct.
- // Unless of course they decide to not have the tracers come out of the windows, but rather go towards the target.
- // In that case, tracers will have to be rewritten to be "point towards secondary" instead of
- // "point straight ahead" which assumes we are facing the target.
- */
- FXList::doFXPos(fxl, &pos, mtx, weaponSpeed, victimPos, damageRadius);
- }
- handled = true;
- }
- else
- {
- DEBUG_LOG(("*** no FXBone found for a non-null FXL\n"));
- }
- }
- if (info.m_recoilBone || info.m_muzzleFlashBone)
- {
- //DEBUG_LOG(("START muzzleflash %08lx for Draw %08lx state %s at frame %d\n",info.m_muzzleFlashBone,this,m_curState->m_description.str(),TheGameLogic->getFrame()));
- WeaponRecoilInfo& recoil = m_weaponRecoilInfoVec[wslot][specificBarrelToUse];
- recoil.m_state = WeaponRecoilInfo::RECOIL_START;
- recoil.m_recoilRate = getW3DModelDrawModuleData()->m_initialRecoil;
- if (info.m_muzzleFlashBone != 0)
- info.setMuzzleFlashHidden(m_renderObject, false);
- }
- return handled;
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setAnimationLoopDuration(UnsignedInt numFrames)
- {
- // this is never defined -- srj
- #ifdef NO_DURATIONS_ON_TRANSITIONS
- if (m_curState != NULL && m_curState->m_transition != NO_TRANSITION &&
- m_nextState != NULL && m_nextState->m_transition == NO_TRANSITION)
- {
- DEBUG_LOG(("deferring pending duration of %d frames\n",numFrames));
- m_nextStateAnimLoopDuration = numFrames;
- return;
- }
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- DEBUG_ASSERTCRASH(m_curState != NULL && m_curState->m_transition == NO_TRANSITION, ("Hmm, setAnimationLoopDuration on a transition state is probably not right... see srj"));
- #else
- m_nextStateAnimLoopDuration = NO_NEXT_DURATION;
- #endif
- Real desiredDurationInMsec = ceilf(numFrames * MSEC_PER_LOGICFRAME_REAL);
- setCurAnimDurationInMsec(desiredDurationInMsec);
- }
- //-------------------------------------------------------------------------------------------------
- /**
- similar to the above, but assumes that the current state is a "ONCE",
- and is smart about transition states... if there is a transition state
- "inbetween", it is included in the completion time.
- */
- void W3DModelDraw::setAnimationCompletionTime(UnsignedInt numFrames)
- {
- if (m_curState != NULL && m_curState->m_transitionSig != NO_TRANSITION && m_curState->m_animations.size() > 0 &&
- m_nextState != NULL && m_nextState->m_transitionSig == NO_TRANSITION && m_nextState->m_animations.size() > 0)
- {
- // we have a transition; split up the time suitably.
- // note that this is just a guess, and assumes that the states
- // have only one anim each (or, if multiple, that they are
- // all pretty close in natural duration)
- const Real t1 = m_curState->m_animations.front().getNaturalDurationInMsec();
- const Real t2 = m_nextState->m_animations.front().getNaturalDurationInMsec();
- UnsignedInt transTime = REAL_TO_INT_FLOOR((numFrames * t1) / (t1 + t2));
- setAnimationLoopDuration(transTime);
- m_nextStateAnimLoopDuration = numFrames - transTime;
- }
- else
- {
- setAnimationLoopDuration(numFrames);
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setAnimationFrame( int frame )
- {
- if( m_renderObject && m_whichAnimInCurState >= 0 )
- {
- const W3DAnimationInfo& animInfo = m_curState->m_animations[ m_whichAnimInCurState ];
- HAnimClass* animHandle = animInfo.getAnimHandle(); // note that this now returns an ADDREFED handle, which must be released by the caller!
- m_renderObject->Set_Animation( animHandle, frame );
- REF_PTR_RELEASE(animHandle);
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::setPauseAnimation(Bool pauseAnim)
- {
- if (m_pauseAnimation == pauseAnim)
- {
- return;
- }
- m_pauseAnimation = pauseAnim;
- if (m_renderObject && m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD)
- {
- float framenum, dummy;
- int mode, numFrames;
- HLodClass* hlod = (HLodClass*)m_renderObject;
- HAnimClass* anim = hlod->Peek_Animation_And_Info(framenum, numFrames, mode, dummy);
- if (anim)
- {
- if (m_pauseAnimation)
- {
- m_animationMode = mode;
- hlod->Set_Animation(anim, framenum, RenderObjClass::ANIM_MODE_MANUAL);
- }
- else
- {
- hlod->Set_Animation(anim, framenum, m_animationMode);
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- #ifdef ALLOW_ANIM_INQUIRIES
- // srj sez: not sure if this is a good idea, for net sync reasons...
- Real W3DModelDraw::getAnimationScrubScalar( void ) const
- {
- return getCurAnimDistanceCovered();
- }
- #endif
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::rebuildWeaponRecoilInfo(const ModelConditionInfo* state)
- {
- Int wslot;
- if (state == NULL)
- {
- for (wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot)
- {
- m_weaponRecoilInfoVec[wslot].clear();
- }
- }
- else
- {
- for (wslot = 0; wslot < WEAPONSLOT_COUNT; ++wslot)
- {
- Int ncount = state->m_weaponBarrelInfoVec[wslot].size();
- if (m_weaponRecoilInfoVec[wslot].size() != ncount)
- {
- WeaponRecoilInfo tmp;
- m_weaponRecoilInfoVec[wslot].resize(ncount, tmp);
- }
- for (WeaponRecoilInfoVec::iterator it = m_weaponRecoilInfoVec[wslot].begin(); it != m_weaponRecoilInfoVec[wslot].end(); ++it)
- {
- it->clear();
- }
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** Preload any assets for the time of day requested */
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::preloadAssets( TimeOfDay timeOfDay )
- {
- const W3DModelDrawModuleData *modData = getW3DModelDrawModuleData();
- if( modData )
- modData->preloadAssets( timeOfDay, getDrawable()->getScale() );
- }
- //-------------------------------------------------------------------------------------------------
- Bool W3DModelDraw::isVisible() const
- {
- return (m_renderObject && m_renderObject->Is_Really_Visible());
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::updateProjectileClipStatus( UnsignedInt shotsRemaining, UnsignedInt maxShots, WeaponSlotType slot )
- {
- if ((getW3DModelDrawModuleData()->m_projectileBoneFeedbackEnabledSlots & (1 << slot)) == 0)
- return; // Only if specified.
- doHideShowProjectileObjects( shotsRemaining, maxShots, slot );// Means effectively, show m of n.
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::updateDrawModuleSupplyStatus( Int , Int currentSupply )
- {
- // This level only cares if you have anything or not
- if( currentSupply > 0 )
- {
- getDrawable()->setModelConditionState( MODELCONDITION_CARRYING );
- }
- else
- {
- getDrawable()->clearModelConditionState( MODELCONDITION_CARRYING );
- }
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::doHideShowProjectileObjects( UnsignedInt showCount, UnsignedInt maxCount, WeaponSlotType slot )
- {
- // Loop through the projectile bones, and start hiding off the front. That is, 8,9 means to hide the first only.
- if (maxCount < showCount)
- {
- DEBUG_CRASH(("Someone is trying to show more projectiles than they have.") );
- return;
- }
- Int hideCount = maxCount - showCount;
- std::vector<ModelConditionInfo::HideShowSubObjInfo> showHideVector;
- ModelConditionInfo::HideShowSubObjInfo oneEntry;
- if (m_curState->m_weaponProjectileHideShowName[slot].isEmpty())
- {
- for( Int projectileIndex = 0; projectileIndex < maxCount; projectileIndex++ )
- {
- oneEntry.subObjName.format("%s%02d", m_curState->m_weaponProjectileLaunchBoneName[slot].str(), (projectileIndex + 1));
- oneEntry.hide = ((projectileIndex + 1) <= hideCount);
- showHideVector.push_back( oneEntry );
- }
- }
- else
- {
- oneEntry.subObjName = m_curState->m_weaponProjectileHideShowName[slot];
- oneEntry.hide = (0 < hideCount);
- showHideVector.push_back( oneEntry );
- }
- // Rather than duplicate recursive utility stuff, I will build a vector like those used by the main ShowHide setting
- doHideShowSubObjs(&showHideVector);
- }
- //-------------------------------------------------------------------------------------------------
- void W3DModelDraw::updateSubObjects()
- {
- if (!m_renderObject)
- return;
- if (!m_subObjectVec.empty())
- {
- for (std::vector<ModelConditionInfo::HideShowSubObjInfo>::const_iterator it = m_subObjectVec.begin(); it != m_subObjectVec.end(); ++it)
- {
- Int objIndex;
- RenderObjClass* subObj;
- if ((subObj = m_renderObject->Get_Sub_Object_By_Name(it->subObjName.str(), &objIndex)) != NULL)
- {
- subObj->Set_Hidden(it->hide);
- const HTreeClass *htree = m_renderObject->Get_HTree();
- if (htree)
- {
- //get the bone of this subobject so we can hide all other child objects that use this bone
- //as a parent.
- Int boneIdx = m_renderObject->Get_Sub_Object_Bone_Index(0, objIndex);
- doHideShowBoneSubObjs( it->hide, m_renderObject->Get_Num_Sub_Objects(), boneIdx, m_renderObject, htree);
- }
- subObj->Release_Ref();
- }
- else
- {
- DEBUG_CRASH(("*** ASSET ERROR: SubObject %s not found (%s)!\n",it->subObjName.str(),getDrawable()->getTemplate()->getName().str()));
- }
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void W3DModelDraw::crc( Xfer *xfer )
- {
- // extend base class
- DrawModule::crc( xfer );
- } // end crc
- // ------------------------------------------------------------------------------------------------
- /** Xfer method
- * Version Info:
- * 1: Initial version
- * 2: Added animation frame (CBD)
- */
- // ------------------------------------------------------------------------------------------------
- void W3DModelDraw::xfer( Xfer *xfer )
- {
- // version
- const XferVersion currentVersion = 2;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // extend base class
- DrawModule::xfer( xfer );
- // weapon recoil info vectors
- UnsignedByte recoilInfoCount;
- WeaponRecoilInfo weaponRecoilInfo;
- for( Int i = 0; i < WEAPONSLOT_COUNT; ++i )
- {
- // count of data here
- recoilInfoCount = m_weaponRecoilInfoVec[ i ].size();
- xfer->xferUnsignedByte( &recoilInfoCount );
- if( xfer->getXferMode() == XFER_SAVE )
- {
- WeaponRecoilInfoVec::const_iterator it;
- for( it = m_weaponRecoilInfoVec[ i ].begin(); it != m_weaponRecoilInfoVec[ i ].end(); ++it )
- {
- // state
- weaponRecoilInfo.m_state = (*it).m_state;
- xfer->xferUser( &weaponRecoilInfo.m_state, sizeof( WeaponRecoilInfo::RecoilState ) );
- // shift
- weaponRecoilInfo.m_shift = (*it).m_shift;
- xfer->xferReal( &weaponRecoilInfo.m_shift );
- // recoil rate
- weaponRecoilInfo.m_recoilRate = (*it).m_recoilRate;
- xfer->xferReal( &weaponRecoilInfo.m_recoilRate );
- } // end for, it
-
- } // end if, save
- else
- {
- // clear this list before loading
- m_weaponRecoilInfoVec[ i ].clear();
- // read each data item
- for( Int j = 0; j < recoilInfoCount; ++j )
- {
- // read state
- xfer->xferUser( &weaponRecoilInfo.m_state, sizeof( WeaponRecoilInfo::RecoilState ) );
- // read shift
- xfer->xferReal( &weaponRecoilInfo.m_shift );
- // read recoil rate
- xfer->xferReal( &weaponRecoilInfo.m_recoilRate );
- // stuff it in the vector
- m_weaponRecoilInfoVec[ i ].push_back( weaponRecoilInfo );
- } // end for, j
- } // end else, load
- } // end for, i
- // sub object vector
- UnsignedByte subObjectCount = m_subObjectVec.size();
- xfer->xferUnsignedByte( &subObjectCount );
- ModelConditionInfo::HideShowSubObjInfo hideShowSubObjInfo;
- if( xfer->getXferMode() == XFER_SAVE )
- {
- std::vector<ModelConditionInfo::HideShowSubObjInfo>::const_iterator it;
- for( it = m_subObjectVec.begin(); it != m_subObjectVec.end(); ++it )
- {
- // sub object name
- hideShowSubObjInfo.subObjName = (*it).subObjName;
- xfer->xferAsciiString( &hideShowSubObjInfo.subObjName );
- // hide
- hideShowSubObjInfo.hide = (*it).hide;
- xfer->xferBool( &hideShowSubObjInfo.hide );
- } // end for, it
- } // end if, save
- else
- {
- // the vector must be emtpy
- m_subObjectVec.clear();
- // read each data item
- for( UnsignedByte i = 0; i < subObjectCount; ++i )
- {
- // name
- xfer->xferAsciiString( &hideShowSubObjInfo.subObjName );
- // hide
- xfer->xferBool( &hideShowSubObjInfo.hide );
- // stuff in vector
- m_subObjectVec.push_back( hideShowSubObjInfo );
- } // end for, i
- } // end else, load
- // animation
- if( version >= 2 )
- {
-
- if( xfer->getXferMode() == XFER_SAVE )
- {
- // srj sez: don't save info for transition states, since we can't really
- // restore them effectively.
- if ( m_renderObject
- && m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD
- && m_curState
- && m_curState->m_transitionSig == NO_TRANSITION )
- {
-
- // cast to HLod
- HLodClass *hlod = (HLodClass*)m_renderObject;
- // get animation info
- Int mode, numFrames;
- Real frame, dummy;
- HAnimClass *anim = hlod->Peek_Animation_And_Info( frame, numFrames, mode, dummy );
- // animation data is present
- Bool present = anim ? TRUE : FALSE;
- xfer->xferBool( &present );
- // if animation data is present
- if( anim )
- {
- // xfer mode
- xfer->xferInt( &mode );
- //
- // xfer frame as a fraction (this will allow the animations to change
- // in future patches but will still be mostly correct)
- //
- Real percent = frame / INT_TO_REAL( anim->Get_Num_Frames()-1 );
- xfer->xferReal( &percent );
- } // end if, anim
- } // end if
- else
- {
- // animation data is *NOT* present
- Bool present = FALSE;
- xfer->xferBool( &present );
- } // end else
- } // end if, save
- else
- {
- // read animation present flag
- Bool present;
- xfer->xferBool( &present );
- if( present )
- {
-
- {
- // read mode
- Int mode;
- xfer->xferInt( &mode ); // note, this will be ignored
- }
- // read percent
- Real percent;
- xfer->xferReal( &percent );
- //
- // cast render object to HLod, if this is no longer possible we have read the
- // data already and can just ignore it
- //
- if( m_renderObject && m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD )
- {
- HLodClass *hlod = (HLodClass *)m_renderObject;
- // get anim
- HAnimClass *anim = hlod->Peek_Animation();
- // set animation data
- if( anim )
- {
- // figure out frame number given percent written in file and total frames on anim
- Real frame = percent * INT_TO_REAL( anim->Get_Num_Frames()-1 );
- float dummy1, dummy2;
- int curMode, dummy3;
- hlod->Peek_Animation_And_Info(dummy1, dummy3, curMode, dummy2);
-
- // srj sez: do not change the animation mode. it's too risky, since if you change (say) a nonlooping
- // to a looping, something might break since it could rely on that anim terminating.
- // set animation data
- hlod->Set_Animation( anim, frame, curMode );
- } // end if, anim
- } // end if
- } // end if
- } // end else, load
- } // end if, version with animation info
- // when loading, update the sub objects if we have any
- if( xfer->getXferMode() == XFER_LOAD && m_subObjectVec.empty() == FALSE )
- updateSubObjects();
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void W3DModelDraw::loadPostProcess( void )
- {
- // extend base class
- DrawModule::loadPostProcess();
- } // end loadPostProcess
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::crc( Xfer *x )
- {
- xfer(x);
- }
- // ------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::xfer( Xfer *x )
- {
- // version
- const XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- x->xferVersion( &version, currentVersion );
- for (ModelConditionVector::iterator it = m_conditionStates.begin(); it != m_conditionStates.end(); ++it)
- {
- ModelConditionInfo *info = &(*it);
- x->xferByte(&(info->m_validStuff));
- #if defined(_DEBUG) || defined(_INTERNAL)
- x->xferAsciiString(&(info->m_description));
- #endif
- if (info->m_validStuff)
- {
- for (PristineBoneInfoMap::iterator bit = info->m_pristineBones.begin(); bit != info->m_pristineBones.end(); ++bit)
- {
- PristineBoneInfo *bone = &(bit->second);
- x->xferInt(&(bone->boneIndex));
- x->xferUser(&(bone->mtx), sizeof(Matrix3D));
- }
- for (Int i=0; i<MAX_TURRETS; ++i)
- {
- x->xferInt(&(info->m_turrets[i].m_turretAngleBone));
- x->xferInt(&(info->m_turrets[i].m_turretPitchBone));
- }
- for (i=0; i<WEAPONSLOT_COUNT; ++i)
- {
- for (ModelConditionInfo::WeaponBarrelInfoVec::iterator wit = info->m_weaponBarrelInfoVec[i].begin(); wit != info->m_weaponBarrelInfoVec[i].end(); ++wit)
- {
- x->xferUser(&(wit->m_projectileOffsetMtx), sizeof(Matrix3D));
- }
- }
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- void W3DModelDrawModuleData::loadPostProcess( void )
- {
- }
|