1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
- // Copyright (C) 2015 Faust Logic, Inc.
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- #include "platform/platform.h"
- #include "environment/meshRoad.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "util/catmullRom.h"
- #include "math/util/quadTransforms.h"
- #include "scene/simPath.h"
- #include "scene/sceneRenderState.h"
- #include "scene/sceneManager.h"
- #include "scene/sgUtil.h"
- #include "renderInstance/renderPassManager.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "core/stream/bitStream.h"
- #include "gfx/gfxDrawUtil.h"
- #include "gfx/gfxTransformSaver.h"
- #include "gfx/primBuilder.h"
- #include "gfx/gfxDebugEvent.h"
- #include "materials/materialManager.h"
- #include "math/mathIO.h"
- #include "math/mathUtils.h"
- #include "math/util/frustum.h"
- #include "gui/3d/guiTSControl.h"
- #include "materials/shaderData.h"
- #include "gfx/sim/gfxStateBlockData.h"
- #include "gfx/sim/debugDraw.h"
- #include "collision/concretePolyList.h"
- #include "T3D/physics/physicsPlugin.h"
- #include "T3D/physics/physicsBody.h"
- #include "T3D/physics/physicsCollision.h"
- #include "environment/nodeListManager.h"
- #ifdef TORQUE_AFX_ENABLED
- #include "afx/ce/afxZodiacMgr.h"
- #endif
- #define MIN_METERS_PER_SEGMENT 1.0f
- #define MIN_NODE_DEPTH 0.25f
- #define MAX_NODE_DEPTH 50.0f
- #define MIN_NODE_WIDTH 0.25f
- #define MAX_NODE_WIDTH 50.0f
- static U32 gIdxArray[6][2][3] = {
- { { 0, 4, 5 }, { 0, 5, 1 }, }, // Top Face
- { { 2, 6, 4 }, { 2, 4, 0 }, }, // Left Face
- { { 1, 5, 7 }, { 1, 7, 3 }, }, // Right Face
- { { 2, 3, 7 }, { 2, 7, 6 }, }, // Bottom Face
- { { 0, 1, 3 }, { 0, 3, 2 }, }, // Front Face
- { { 4, 6, 7 }, { 4, 7, 5 }, }, // Back Face
- };
- static S32 QSORT_CALLBACK compareHitSegments(const void* a,const void* b)
- {
- const MeshRoadHitSegment *fa = (MeshRoadHitSegment*)a;
- const MeshRoadHitSegment *fb = (MeshRoadHitSegment*)b;
- F32 diff = fb->t - fa->t;
- return (diff > 0) ? 1 : (diff < 0) ? -1 : 0;
- }
- //-----------------------------------------------------------------------------
- // MeshRoadNodeList Struct
- //-----------------------------------------------------------------------------
- struct MeshRoadNodeList : public NodeListManager::NodeList
- {
- Vector<Point3F> mPositions;
- Vector<F32> mWidths;
- Vector<F32> mDepths;
- Vector<VectorF> mNormals;
- MeshRoadNodeList() { }
- virtual ~MeshRoadNodeList() { }
- };
- //-----------------------------------------------------------------------------
- // MeshRoadNodeEvent Class
- //-----------------------------------------------------------------------------
- class MeshRoadNodeEvent : public NodeListEvent
- {
- typedef NodeListEvent Parent;
- public:
- Vector<Point3F> mPositions;
- Vector<F32> mWidths;
- Vector<F32> mDepths;
- Vector<VectorF> mNormals;
- public:
- MeshRoadNodeEvent() { mNodeList = NULL; }
- virtual ~MeshRoadNodeEvent() { }
- virtual void pack(NetConnection*, BitStream*);
- virtual void unpack(NetConnection*, BitStream*);
- virtual void copyIntoList(NodeListManager::NodeList* copyInto);
- virtual void padListToSize();
- DECLARE_CONOBJECT(MeshRoadNodeEvent);
- };
- void MeshRoadNodeEvent::pack(NetConnection* conn, BitStream* stream)
- {
- Parent::pack( conn, stream );
- stream->writeInt( mPositions.size(), 16 );
- for (U32 i=0; i<mPositions.size(); ++i)
- {
- mathWrite( *stream, mPositions[i] );
- stream->write( mWidths[i] );
- stream->write( mDepths[i] );
- mathWrite( *stream, mNormals[i] );
- }
- }
- void MeshRoadNodeEvent::unpack(NetConnection* conn, BitStream* stream)
- {
- mNodeList = new MeshRoadNodeList();
- Parent::unpack( conn, stream );
- U32 count = stream->readInt( 16 );
- Point3F pos;
- F32 width, depth;
- VectorF normal;
- MeshRoadNodeList* list = static_cast<MeshRoadNodeList*>(mNodeList);
- for (U32 i=0; i<count; ++i)
- {
- mathRead( *stream, &pos );
- stream->read( &width );
- stream->read( &depth );
- mathRead( *stream, &normal );
- list->mPositions.push_back( pos );
- list->mWidths.push_back( width );
- list->mDepths.push_back( depth );
- list->mNormals.push_back( normal );
- }
- list->mTotalValidNodes = count;
- // Do we have a complete list?
- if (list->mPositions.size() >= mTotalNodes)
- list->mListComplete = true;
- }
- void MeshRoadNodeEvent::copyIntoList(NodeListManager::NodeList* copyInto)
- {
- MeshRoadNodeList* prevList = dynamic_cast<MeshRoadNodeList*>(copyInto);
- MeshRoadNodeList* list = static_cast<MeshRoadNodeList*>(mNodeList);
- // Merge our list with the old list.
- for (U32 i=mLocalListStart, index=0; i<mLocalListStart+list->mPositions.size(); ++i, ++index)
- {
- prevList->mPositions[i] = list->mPositions[index];
- prevList->mWidths[i] = list->mWidths[index];
- prevList->mDepths[i] = list->mDepths[index];
- prevList->mNormals[i] = list->mNormals[index];
- }
- }
- void MeshRoadNodeEvent::padListToSize()
- {
- MeshRoadNodeList* list = static_cast<MeshRoadNodeList*>(mNodeList);
- U32 totalValidNodes = list->mTotalValidNodes;
- // Pad our list front?
- if (mLocalListStart)
- {
- MeshRoadNodeList* newlist = new MeshRoadNodeList();
- newlist->mPositions.increment(mLocalListStart);
- newlist->mWidths.increment(mLocalListStart);
- newlist->mDepths.increment(mLocalListStart);
- newlist->mNormals.increment(mLocalListStart);
- newlist->mPositions.merge(list->mPositions);
- newlist->mWidths.merge(list->mWidths);
- newlist->mDepths.merge(list->mDepths);
- newlist->mNormals.merge(list->mNormals);
- delete list;
- mNodeList = list = newlist;
- }
- // Pad our list end?
- if (list->mPositions.size() < mTotalNodes)
- {
- U32 delta = mTotalNodes - list->mPositions.size();
- list->mPositions.increment(delta);
- list->mWidths.increment(delta);
- list->mDepths.increment(delta);
- list->mNormals.increment(delta);
- }
- list->mTotalValidNodes = totalValidNodes;
- }
- IMPLEMENT_CO_NETEVENT_V1(MeshRoadNodeEvent);
- ConsoleDocClass( MeshRoadNodeEvent,
- "@brief Sends messages to the Mesh Road Editor\n\n"
- "Editor use only.\n\n"
- "@internal"
- );
- //-----------------------------------------------------------------------------
- // MeshRoadNodeListNotify Class
- //-----------------------------------------------------------------------------
- class MeshRoadNodeListNotify : public NodeListNotify
- {
- typedef NodeListNotify Parent;
- protected:
- SimObjectPtr<MeshRoad> mRoad;
- public:
- MeshRoadNodeListNotify( MeshRoad* road, U32 listId ) { mRoad = road; mListId = listId; }
- virtual ~MeshRoadNodeListNotify() { mRoad = NULL; }
- virtual void sendNotification( NodeListManager::NodeList* list );
- };
- void MeshRoadNodeListNotify::sendNotification( NodeListManager::NodeList* list )
- {
- if (mRoad.isValid())
- {
- // Build the road's nodes
- MeshRoadNodeList* roadList = dynamic_cast<MeshRoadNodeList*>( list );
- if (roadList)
- mRoad->buildNodesFromList( roadList );
- }
- }
- //-------------------------------------------------------------------------
- // MeshRoadProfile Class
- //-------------------------------------------------------------------------
- MeshRoadProfile::MeshRoadProfile()
- {
- mRoad = NULL;
- // Set transformation matrix to identity
- mObjToSlice.identity();
- mSliceToObj.identity();
- }
- S32 MeshRoadProfile::clickOnLine(Point3F &p)
- {
- Point3F newProfilePt;
- Point3F ptOnSegment;
- F32 dist = 0.0f;
- F32 minDist = 99999.0f;
- U32 idx = 0;
- for(U32 i=0; i < mNodes.size()-1; i++)
- {
- ptOnSegment = MathUtils::mClosestPointOnSegment(mNodes[i].getPosition(), mNodes[i+1].getPosition(), p);
- dist = (p - ptOnSegment).len();
- if(dist < minDist)
- {
- minDist = dist;
- newProfilePt = ptOnSegment;
- idx = i+1;
- }
- }
- if(minDist <= 0.1f)
- {
- p.set(newProfilePt.x, newProfilePt.y, newProfilePt.z);
- return idx;
- }
- return -1;
- }
- void MeshRoadProfile::addPoint(U32 nodeId, Point3F &p)
- {
- if(nodeId < mNodes.size() && nodeId != 0)
- {
- p.z = 0.0f;
- mNodes.insert(nodeId, p);
- mSegMtrls.insert(nodeId-1, mSegMtrls[nodeId-1]);
- mRoad->setMaskBits(MeshRoad::ProfileMask | MeshRoad::RegenMask);
- generateNormals();
- }
- }
- void MeshRoadProfile::removePoint(U32 nodeId)
- {
- if(nodeId > 0 && nodeId < mNodes.size()-1)
- {
- mNodes.erase(nodeId);
- mSegMtrls.remove(nodeId-1);
- mRoad->setMaskBits(MeshRoad::ProfileMask | MeshRoad::RegenMask);
- generateNormals();
- }
- }
- void MeshRoadProfile::setNodePosition(U32 nodeId, Point3F pos)
- {
- if(nodeId < mNodes.size())
- {
- mNodes[nodeId].setPosition(pos.x, pos.y);
- mRoad->setMaskBits(MeshRoad::ProfileMask | MeshRoad::RegenMask);
- generateNormals();
- }
- }
- void MeshRoadProfile::toggleSmoothing(U32 nodeId)
- {
- if(nodeId > 0 && nodeId < mNodes.size()-1)
- {
- mNodes[nodeId].setSmoothing(!mNodes[nodeId].isSmooth());
- mRoad->setMaskBits(MeshRoad::ProfileMask | MeshRoad::RegenMask);
- generateNormals();
- }
- }
- void MeshRoadProfile::toggleSegMtrl(U32 seg)
- {
- if(seg < mSegMtrls.size())
- {
- switch(mSegMtrls[seg])
- {
- case MeshRoad::Side: mSegMtrls[seg] = MeshRoad::Top; break;
- case MeshRoad::Top: mSegMtrls[seg] = MeshRoad::Bottom; break;
- case MeshRoad::Bottom: mSegMtrls[seg] = MeshRoad::Side; break;
- }
- mRoad->setMaskBits(MeshRoad::ProfileMask | MeshRoad::RegenMask);
- }
- }
- void MeshRoadProfile::generateNormals()
- {
- VectorF t, b, n, t2, n2;
- Point3F averagePt;
- mNodeNormals.clear();
- // Loop through all profile line segments
- for(U32 i=0; i < mNodes.size()-1; i++)
- {
- // Calculate normal for each node in line segment
- for(U32 j=0; j<2; j++)
- {
- // Smoothed Node: Average the node with nodes before and after.
- // Direction between the node and the average is the smoothed normal.
- if( mNodes[i+j].isSmooth() )
- {
- b = Point3F(0.0f, 0.0f, 1.0f);
- t = mNodes[i+j-1].getPosition() - mNodes[i+j].getPosition();
- n = mCross(t, b);
- n.normalizeSafe();
- t2 = mNodes[i+j].getPosition() - mNodes[i+j+1].getPosition();
- n2 = mCross(t2, b);
- n2.normalizeSafe();
- n += n2;
- }
- // Non-smoothed Node: Normal is perpendicular to segment.
- else
- {
- b = Point3F(0.0f, 0.0f, 1.0f);
- t = mNodes[i].getPosition() - mNodes[i+1].getPosition();
- n = mCross(t, b);
- }
- n.normalizeSafe();
- mNodeNormals.push_back(n);
- }
- }
- }
- void MeshRoadProfile::generateEndCap(F32 width)
- {
- Point3F pt;
- mCap.newPoly();
- for ( U32 i = 0; i < mNodes.size(); i++ )
- {
- pt = mNodes[i].getPosition();
- mCap.addVert(pt);
- }
- for ( S32 i = mNodes.size()-1; i >= 0; i-- )
- {
- pt = mNodes[i].getPosition();
- pt.x = -pt.x - width;
- mCap.addVert(pt);
- }
- mCap.decompose();
- }
- void MeshRoadProfile::setProfileDepth(F32 depth)
- {
- Point3F curPos = mNodes[mNodes.size()-1].getPosition();
- mNodes[mNodes.size()-1].setPosition(curPos.x, -depth);
- }
- void MeshRoadProfile::setTransform(const MatrixF &mat, const Point3F &p)
- {
- mObjToSlice.identity();
- mSliceToObj.identity();
- mObjToSlice *= mat;
- mSliceToObj *= mObjToSlice.inverse();
- mSliceToObj.transpose();
- mStartPos = p;
- }
- void MeshRoadProfile::getNodeWorldPos(U32 nodeId, Point3F &p)
- {
- if(nodeId < mNodes.size())
- {
- p = mNodes[nodeId].getPosition();
- mObjToSlice.mulP(p);
- p += mStartPos;
- }
- }
- void MeshRoadProfile::getNormToSlice(U32 normId, VectorF &n)
- {
- if(normId < mNodeNormals.size())
- {
- n = mNodeNormals[normId];
- mObjToSlice.mulP(n);
- }
- }
- void MeshRoadProfile::getNormWorldPos(U32 normId, Point3F &p)
- {
- if(normId < mNodeNormals.size())
- {
- U32 nodeId = normId/2 + (U32)(mFmod(normId,2.0f));
- p = mNodes[nodeId].getPosition();
- p += 0.5f * mNodeNormals[normId]; // Length = 0.5 units
- mObjToSlice.mulP(p);
- p += mStartPos;
- }
- }
- void MeshRoadProfile::worldToObj(Point3F &p)
- {
- p -= mStartPos;
- mSliceToObj.mulP(p);
- p.z = 0.0f;
- }
- void MeshRoadProfile::objToWorld(Point3F &p)
- {
- mObjToSlice.mulP(p);
- p += mStartPos;
- }
- F32 MeshRoadProfile::getProfileLen()
- {
- F32 sum = 0.0f;
- Point3F segmentVec;
- for(U32 i=0; i < mNodes.size()-1; i++)
- {
- segmentVec = mNodes[i+1].getPosition() - mNodes[i].getPosition();
- sum += segmentVec.len();
- }
- return sum;
- }
- F32 MeshRoadProfile::getNodePosPercent(U32 nodeId)
- {
- nodeId = mFmod(nodeId, mNodes.size());
- if(nodeId == 0)
- return 0.0f;
- else if(nodeId == mNodes.size()-1)
- return 1.0f;
- F32 totLen = getProfileLen();
- F32 sum = 0.0f;
- Point3F segmentVec;
- for(U32 i=0; i < nodeId; i++)
- {
- segmentVec = mNodes[i+1].getPosition() - mNodes[i].getPosition();
- sum += segmentVec.len();
- }
- return sum/totLen;
- }
- void MeshRoadProfile::resetProfile(F32 defaultDepth)
- {
- Point3F pos(0.0f, 0.0f, 0.0f);
- mNodes.clear();
- mNodes.push_back(pos);
- pos.y = -defaultDepth;
- mNodes.push_back(pos);
- mSegMtrls.clear();
- mSegMtrls.push_back(MeshRoad::Side);
- mRoad->setMaskBits(MeshRoad::ProfileMask | MeshRoad::RegenMask);
- generateNormals();
- }
- //------------------------------------------------------------------------------
- // MeshRoadConvex Class
- //------------------------------------------------------------------------------
- const MatrixF& MeshRoadConvex::getTransform() const
- {
- return MatrixF::Identity; //mObject->getTransform();
- }
- Box3F MeshRoadConvex::getBoundingBox() const
- {
- return box;
- }
- Box3F MeshRoadConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const
- {
- Box3F newBox = box;
- newBox.minExtents.convolve(scale);
- newBox.maxExtents.convolve(scale);
- mat.mul(newBox);
- return newBox;
- }
- Point3F MeshRoadConvex::support(const VectorF& vec) const
- {
- F32 bestDot = mDot( verts[0], vec );
- const Point3F *bestP = &verts[0];
- for(S32 i=1; i<4; i++)
- {
- F32 newD = mDot(verts[i], vec);
- if(newD > bestDot)
- {
- bestDot = newD;
- bestP = &verts[i];
- }
- }
- return *bestP;
- }
- void MeshRoadConvex::getFeatures(const MatrixF& mat, const VectorF& n, ConvexFeature* cf)
- {
- cf->material = 0;
- cf->mObject = mObject;
- // For a tetrahedron this is pretty easy... first
- // convert everything into world space.
- Point3F tverts[4];
- mat.mulP(verts[0], &tverts[0]);
- mat.mulP(verts[1], &tverts[1]);
- mat.mulP(verts[2], &tverts[2]);
- mat.mulP(verts[3], &tverts[3]);
- // Points...
- S32 firstVert = cf->mVertexList.size();
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[0];
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[1];
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[2];
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[3];
- // Edges...
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert+0;
- cf->mEdgeList.last().vertex[1] = firstVert+1;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert+1;
- cf->mEdgeList.last().vertex[1] = firstVert+2;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert+2;
- cf->mEdgeList.last().vertex[1] = firstVert+0;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert+3;
- cf->mEdgeList.last().vertex[1] = firstVert+0;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert+3;
- cf->mEdgeList.last().vertex[1] = firstVert+1;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert+3;
- cf->mEdgeList.last().vertex[1] = firstVert+2;
- // Triangles...
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[0]);
- cf->mFaceList.last().vertex[0] = firstVert+2;
- cf->mFaceList.last().vertex[1] = firstVert+1;
- cf->mFaceList.last().vertex[2] = firstVert+0;
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[1], tverts[0], tverts[3]);
- cf->mFaceList.last().vertex[0] = firstVert+1;
- cf->mFaceList.last().vertex[1] = firstVert+0;
- cf->mFaceList.last().vertex[2] = firstVert+3;
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[3]);
- cf->mFaceList.last().vertex[0] = firstVert+2;
- cf->mFaceList.last().vertex[1] = firstVert+1;
- cf->mFaceList.last().vertex[2] = firstVert+3;
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[0], tverts[2], tverts[3]);
- cf->mFaceList.last().vertex[0] = firstVert+0;
- cf->mFaceList.last().vertex[1] = firstVert+2;
- cf->mFaceList.last().vertex[2] = firstVert+3;
- }
- void MeshRoadConvex::getPolyList( AbstractPolyList* list )
- {
- // Transform the list into object space and set the pointer to the object
- //MatrixF i( mObject->getTransform() );
- //Point3F iS( mObject->getScale() );
- //list->setTransform(&i, iS);
- list->setTransform( &MatrixF::Identity, Point3F::One );
- list->setObject(mObject);
- // Points...
- S32 base = list->addPoint(verts[1]);
- list->addPoint(verts[2]);
- list->addPoint(verts[0]);
- list->addPoint(verts[3]);
- // Planes...
- list->begin(0,0);
- list->vertex(base + 2);
- list->vertex(base + 1);
- list->vertex(base + 0);
- list->plane(base + 2, base + 1, base + 0);
- list->end();
- list->begin(0,0);
- list->vertex(base + 2);
- list->vertex(base + 1);
- list->vertex(base + 3);
- list->plane(base + 2, base + 1, base + 3);
- list->end();
- list->begin(0,0);
- list->vertex(base + 3);
- list->vertex(base + 1);
- list->vertex(base + 0);
- list->plane(base + 3, base + 1, base + 0);
- list->end();
- list->begin(0,0);
- list->vertex(base + 2);
- list->vertex(base + 3);
- list->vertex(base + 0);
- list->plane(base + 2, base + 3, base + 0);
- list->end();
- }
- //------------------------------------------------------------------------------
- // MeshRoadSegment Class
- //------------------------------------------------------------------------------
- MeshRoadSegment::MeshRoadSegment()
- {
- mPlaneCount = 0;
- columns = 0;
- rows = 0;
- numVerts = 0;
- numTriangles = 0;
- startVert = 0;
- endVert = 0;
- startIndex = 0;
- endIndex = 0;
- slice0 = NULL;
- slice1 = NULL;
- }
- MeshRoadSegment::MeshRoadSegment( MeshRoadSlice *rs0, MeshRoadSlice *rs1, const MatrixF &roadMat )
- {
- columns = 0;
- rows = 0;
- numVerts = 0;
- numTriangles = 0;
- startVert = 0;
- endVert = 0;
- startIndex = 0;
- endIndex = 0;
- slice0 = rs0;
- slice1 = rs1;
- // Calculate the bounding box(s)
- worldbounds.minExtents = worldbounds.maxExtents = rs0->p0;
- for(U32 i=0; i < rs0->verts.size(); i++)
- worldbounds.extend( rs0->verts[i] );
- for(U32 i=0; i < rs1->verts.size(); i++)
- worldbounds.extend( rs1->verts[i] );
- objectbounds = worldbounds;
- roadMat.mul( objectbounds );
- // Calculate the planes for this segment
- // Will be used for intersection/buoyancy tests
- mPlaneCount = 6;
- mPlanes[0].set( slice0->pb0, slice0->p0, slice1->p0 ); // left
- mPlanes[1].set( slice1->pb2, slice1->p2, slice0->p2 ); // right
- mPlanes[2].set( slice0->pb2, slice0->p2, slice0->p0 ); // near
- mPlanes[3].set( slice1->p0, slice1->p2, slice1->pb2 ); // far
- mPlanes[4].set( slice1->p2, slice1->p0, slice0->p0 ); // top
- mPlanes[5].set( slice0->pb0, slice1->pb0, slice1->pb2 ); // bottom
- }
- void MeshRoadSegment::set( MeshRoadSlice *rs0, MeshRoadSlice *rs1 )
- {
- columns = 0;
- rows = 0;
- numVerts = 0;
- numTriangles = 0;
- startVert = 0;
- endVert = 0;
- startIndex = 0;
- endIndex = 0;
- slice0 = rs0;
- slice1 = rs1;
- }
- bool MeshRoadSegment::intersectBox( const Box3F &bounds ) const
- {
- // This code copied from Frustum class.
- Point3F maxPoint;
- F32 maxDot;
- // Note the planes are ordered left, right, near,
- // far, top, bottom for getting early rejections
- // from the typical horizontal scene.
- for ( S32 i = 0; i < mPlaneCount; i++ )
- {
- // This is pretty much as optimal as you can
- // get for a plane vs AABB test...
- //
- // 4 comparisons
- // 3 multiplies
- // 2 adds
- // 1 negation
- //
- // It will early out as soon as it detects the
- // bounds is outside one of the planes.
- if ( mPlanes[i].x > 0 )
- maxPoint.x = bounds.maxExtents.x;
- else
- maxPoint.x = bounds.minExtents.x;
- if ( mPlanes[i].y > 0 )
- maxPoint.y = bounds.maxExtents.y;
- else
- maxPoint.y = bounds.minExtents.y;
- if ( mPlanes[i].z > 0 )
- maxPoint.z = bounds.maxExtents.z;
- else
- maxPoint.z = bounds.minExtents.z;
- maxDot = mDot( maxPoint, mPlanes[ i ] );
- if ( maxDot <= -mPlanes[ i ].d )
- return false;
- }
- return true;
- }
- bool MeshRoadSegment::containsPoint( const Point3F &pnt ) const
- {
- // This code from Frustum class.
- F32 maxDot;
- // Note the planes are ordered left, right, near,
- // far, top, bottom for getting early rejections
- // from the typical horizontal scene.
- for ( S32 i = 0; i < mPlaneCount; i++ )
- {
- const PlaneF &plane = mPlanes[ i ];
- // This is pretty much as optimal as you can
- // get for a plane vs point test...
- //
- // 1 comparison
- // 2 multiplies
- // 1 adds
- //
- // It will early out as soon as it detects the
- // point is outside one of the planes.
- maxDot = mDot( pnt, plane ) + plane.d;
- if ( maxDot < 0.0f )
- return false;
- }
- return true;
- }
- F32 MeshRoadSegment::distanceToSurface(const Point3F &pnt) const
- {
- return mPlanes[4].distToPlane( pnt );
- }
- //------------------------------------------------------------------------------
- // MeshRoad Class
- //------------------------------------------------------------------------------
- ConsoleDocClass( MeshRoad,
- "@brief A strip of rectangular mesh segments defined by a 3D spline "
- "for prototyping road-shaped objects in your scene.\n\n"
-
- "User may control width and depth per node, overall spline shape in three "
- "dimensions, and seperate Materials for rendering the top, bottom, and side surfaces.\n\n"
-
- "MeshRoad is not capable of handling intersections, branches, curbs, or other "
- "desirable features in a final 'road' asset and is therefore intended for "
- "prototyping and experimentation.\n\n"
- "Materials assigned to MeshRoad should tile vertically.\n\n"
- "@ingroup Terrain"
- );
- bool MeshRoad::smEditorOpen = false;
- bool MeshRoad::smShowBatches = false;
- bool MeshRoad::smShowSpline = true;
- bool MeshRoad::smShowRoad = true;
- bool MeshRoad::smShowRoadProfile = false;
- bool MeshRoad::smWireframe = true;
- SimObjectPtr<SimSet> MeshRoad::smServerMeshRoadSet = NULL;
- GFXStateBlockRef MeshRoad::smWireframeSB;
- IMPLEMENT_CO_NETOBJECT_V1(MeshRoad);
- MeshRoad::MeshRoad()
- : mTextureLength( 5.0f ),
- mBreakAngle( 3.0f ),
- mWidthSubdivisions( 0 ),
- mPhysicsRep( NULL )
- {
- mConvexList = new Convex;
- // Setup NetObject.
- mTypeMask |= StaticObjectType | StaticShapeObjectType;
- mNetFlags.set(Ghostable);
- mMatInst[Top] = NULL;
- mMatInst[Bottom] = NULL;
- mMatInst[Side] = NULL;
- mTypeMask |= TerrainLikeObjectType;
- for (U32 i = 0; i < SurfaceCount; i++)
- {
- mVertCount[i] = 0;
- mTriangleCount[i] = 0;
- }
- INIT_ASSET(TopMaterial);
- INIT_ASSET(BottomMaterial);
- INIT_ASSET(SideMaterial);
- mSideProfile.mRoad = this;
- }
- MeshRoad::~MeshRoad()
- {
- delete mConvexList;
- mConvexList = NULL;
- }
- void MeshRoad::initPersistFields()
- {
- addGroup( "MeshRoad" );
- INITPERSISTFIELD_MATERIALASSET(TopMaterial, MeshRoad, "Material for the upper surface of the road.");
- INITPERSISTFIELD_MATERIALASSET(BottomMaterial, MeshRoad, "Material for the bottom surface of the road.");
- INITPERSISTFIELD_MATERIALASSET(SideMaterial, MeshRoad, "Material for the side surface of the road.");
- addField( "textureLength", TypeF32, Offset( mTextureLength, MeshRoad ),
- "The length in meters of textures mapped to the MeshRoad." );
- addField( "breakAngle", TypeF32, Offset( mBreakAngle, MeshRoad ),
- "Angle in degrees - MeshRoad will subdivide the spline if its curve is greater than this threshold." );
- addField( "widthSubdivisions", TypeS32, Offset( mWidthSubdivisions, MeshRoad ),
- "Subdivide segments widthwise this many times when generating vertices." );
- endGroup( "MeshRoad" );
- addGroup( "Internal" );
- addProtectedField( "Node", TypeString, 0, &addNodeFromField, &emptyStringProtectedGetFn,
- "Do not modify, for internal use." );
- addProtectedField( "ProfileNode", TypeString, 0, &addProfileNodeFromField, &emptyStringProtectedGetFn,
- "Do not modify, for internal use." );
- endGroup( "Internal" );
- Parent::initPersistFields();
- }
- void MeshRoad::consoleInit()
- {
- Parent::consoleInit();
- Con::addVariable( "$MeshRoad::EditorOpen", TypeBool, &MeshRoad::smEditorOpen, "True if the MeshRoad editor is open, otherwise false.\n"
- "@ingroup Editors\n");
- Con::addVariable( "$MeshRoad::wireframe", TypeBool, &MeshRoad::smWireframe, "If true, will render the wireframe of the road.\n"
- "@ingroup Editors\n");
- Con::addVariable( "$MeshRoad::showBatches", TypeBool, &MeshRoad::smShowBatches, "Determines if the debug rendering of the batches cubes is displayed or not.\n"
- "@ingroup Editors\n");
- Con::addVariable( "$MeshRoad::showSpline", TypeBool, &MeshRoad::smShowSpline, "If true, the spline on which the curvature of this road is based will be rendered.\n"
- "@ingroup Editors\n");
- Con::addVariable( "$MeshRoad::showRoad", TypeBool, &MeshRoad::smShowRoad, "If true, the road will be rendered. When in the editor, roads are always rendered regardless of this flag.\n"
- "@ingroup Editors\n");
- Con::addVariable( "$MeshRoad::showRoadProfile", TypeBool, &MeshRoad::smShowRoadProfile, "If true, the road profile will be shown in the editor.\n"
- "@ingroup Editors\n");
- }
- bool MeshRoad::addNodeFromField( void *object, const char *index, const char *data )
- {
- MeshRoad *pObj = static_cast<MeshRoad*>(object);
- //if ( !pObj->isProperlyAdded() )
- //{
- F32 width, depth;
- Point3F pos, normal;
- U32 result = dSscanf( data, "%g %g %g %g %g %g %g %g", &pos.x, &pos.y, &pos.z, &width, &depth, &normal.x, &normal.y, &normal.z );
- if ( result == 8 )
- pObj->_addNode( pos, width, depth, normal );
- //}
- return false;
- }
- bool MeshRoad::addProfileNodeFromField( void* obj, const char *index, const char* data )
- {
- MeshRoad *pObj = static_cast<MeshRoad*>(obj);
- F32 x, y;
- U32 smooth, mtrl;
- U32 result = dSscanf( data, "%g %g %d %d", &x, &y, &smooth, &mtrl );
- if ( result == 4 )
- {
- if(!pObj->mSideProfile.mNodes.empty())
- pObj->mSideProfile.mSegMtrls.push_back(mtrl);
- MeshRoadProfileNode node;
- node.setPosition(x, y);
- node.setSmoothing(smooth != 0);
- pObj->mSideProfile.mNodes.push_back(node);
- }
- return false;
- }
- bool MeshRoad::onAdd()
- {
- if ( !Parent::onAdd() )
- return false;
- // Reset the World Box.
- //setGlobalBounds();
- resetWorldBox();
- // Set the Render Transform.
- setRenderTransform(mObjToWorld);
- // Add to ServerMeshRoadSet
- if ( isServerObject() )
- {
- getServerSet()->addObject( this );
- }
- if ( isClientObject() )
- _initMaterial();
- // If this road was not created from a file, give profile two default nodes
- if(mSideProfile.mNodes.empty())
- {
- // Initialize with two nodes in vertical line with unit length
- MeshRoadProfileNode node1(Point3F(0.0f, 0.0f, 0.0f));
- MeshRoadProfileNode node2(Point3F(0.0f, -5.0f, 0.0f));
- mSideProfile.mNodes.push_back(node1);
- mSideProfile.mNodes.push_back(node2);
- // Both node normals are straight to the right, perpendicular to the profile line
- VectorF norm(1.0f, 0.0f, 0.0f);
- mSideProfile.mNodeNormals.push_back(norm);
- mSideProfile.mNodeNormals.push_back(norm);
- mSideProfile.mSegMtrls.push_back(MeshRoad::Side);
- }
- else
- mSideProfile.generateNormals();
- // Generate the Vert/Index buffers and everything else.
- _regenerate();
- // Add to Scene.
- addToScene();
- return true;
- }
- void MeshRoad::onRemove()
- {
- SAFE_DELETE( mPhysicsRep );
- mConvexList->nukeList();
- for ( U32 i = 0; i < SurfaceCount; i++ )
- {
- SAFE_DELETE( mMatInst[i] );
- }
- removeFromScene();
- Parent::onRemove();
- }
- void MeshRoad::inspectPostApply()
- {
- // Set Parent.
- Parent::inspectPostApply();
- //if ( mMetersPerSegment < MIN_METERS_PER_SEGMENT )
- // mMetersPerSegment = MIN_METERS_PER_SEGMENT;
- setMaskBits(MeshRoadMask);
- }
- void MeshRoad::onStaticModified( const char* slotName, const char*newValue )
- {
- Parent::onStaticModified( slotName, newValue );
- if ( dStricmp( slotName, "breakAngle" ) == 0 )
- {
- setMaskBits( RegenMask );
- }
- }
- void MeshRoad::writeFields( Stream &stream, U32 tabStop )
- {
- Parent::writeFields( stream, tabStop );
- // Now write all nodes
- stream.write(2, "\r\n");
- for ( U32 i = 0; i < mNodes.size(); i++ )
- {
- const MeshRoadNode &node = mNodes[i];
- stream.writeTabs(tabStop);
- char buffer[1024];
- dMemset( buffer, 0, 1024 );
- dSprintf( buffer, 1024, "Node = \"%g %g %g %g %g %g %g %g\";", node.point.x, node.point.y, node.point.z, node.width, node.depth, node.normal.x, node.normal.y, node.normal.z );
- stream.writeLine( (const U8*)buffer );
- }
- stream.write(2, "\r\n");
- Point3F nodePos;
- U8 smooth, mtrl;
- for ( U32 i = 0; i < mSideProfile.mNodes.size(); i++ )
- {
- nodePos = mSideProfile.mNodes[i].getPosition();
- if(i)
- mtrl = mSideProfile.mSegMtrls[i-1];
- else
- mtrl = 0;
- if(mSideProfile.mNodes[i].isSmooth())
- smooth = 1;
- else
- smooth = 0;
- stream.writeTabs(tabStop);
- char buffer[1024];
- dMemset( buffer, 0, 1024 );
- dSprintf( buffer, 1024, "ProfileNode = \"%.6f %.6f %d %d\";", nodePos.x, nodePos.y, smooth, mtrl);
- stream.writeLine( (const U8*)buffer );
- }
- }
- bool MeshRoad::writeField( StringTableEntry fieldname, const char *value )
- {
- if ( fieldname == StringTable->insert("Node") )
- return false;
- if ( fieldname == StringTable->insert("ProfileNode") )
- return false;
- return Parent::writeField( fieldname, value );
- }
- void MeshRoad::onEditorEnable()
- {
- }
- void MeshRoad::onEditorDisable()
- {
- }
- SimSet* MeshRoad::getServerSet()
- {
- if ( !smServerMeshRoadSet )
- {
- smServerMeshRoadSet = new SimSet();
- smServerMeshRoadSet->registerObject( "ServerMeshRoadSet" );
- Sim::getRootGroup()->addObject( smServerMeshRoadSet );
- }
- return smServerMeshRoadSet;
- }
- void MeshRoad::prepRenderImage( SceneRenderState* state )
- {
- if ( mNodes.size() <= 1 )
- return;
- RenderPassManager *renderPass = state->getRenderPass();
-
- // Normal Road RenderInstance
- // Always rendered when the editor is not open
- // otherwise obey the smShowRoad flag
- if ( smShowRoad || !smEditorOpen )
- {
- #ifdef TORQUE_AFX_ENABLED
- afxZodiacMgr::renderMeshRoadZodiacs(state, this);
- #endif
- MeshRenderInst coreRI;
- coreRI.clear();
- coreRI.objectToWorld = &MatrixF::Identity;
- coreRI.worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
- coreRI.projection = renderPass->allocSharedXform(RenderPassManager::Projection);
- coreRI.type = RenderPassManager::RIT_Mesh;
-
- BaseMatInstance *matInst;
- for ( U32 i = 0; i < SurfaceCount; i++ )
- {
- matInst = state->getOverrideMaterial( mMatInst[i] );
- if ( !matInst )
- continue;
- // Get the lights if we haven't already.
- if ( matInst->isForwardLit() && !coreRI.lights[0] )
- {
- LightQuery query;
- query.init( getWorldSphere() );
- query.getLights( coreRI.lights, 8 );
- }
- MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
- *ri = coreRI;
- // Currently rendering whole road, fix to cull and batch
- // per segment.
- // Set the correct material for rendering.
- ri->matInst = matInst;
- ri->vertBuff = &mVB[i];
- ri->primBuff = &mPB[i];
- ri->prim = renderPass->allocPrim();
- ri->prim->type = GFXTriangleList;
- ri->prim->minIndex = 0;
- ri->prim->startIndex = 0;
- ri->prim->numPrimitives = mTriangleCount[i];
- ri->prim->startVertex = 0;
- ri->prim->numVertices = mVertCount[i];
- // We sort by the material then vertex buffer.
- ri->defaultKey = matInst->getStateHint();
- ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
- renderPass->addInst( ri );
- }
- }
- // Debug RenderInstance
- // Only when editor is open.
- if ( smEditorOpen )
- {
- ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
- ri->renderDelegate.bind( this, &MeshRoad::_debugRender );
- ri->type = RenderPassManager::RIT_Editor;
- state->getRenderPass()->addInst( ri );
- }
- }
- void MeshRoad::_initMaterial()
- {
- if (mTopMaterialAsset.notNull())
- {
- if (!mMatInst[Top] || !String(mTopMaterialAsset->getMaterialDefinitionName()).equal(mMatInst[Top]->getMaterial()->getName(), String::NoCase))
- {
- SAFE_DELETE(mMatInst[Top]);
- Material* tMat = nullptr;
- if (!Sim::findObject(mTopMaterialAsset->getMaterialDefinitionName(), tMat))
- Con::errorf("MeshRoad::_initMaterial - Material %s was not found.", mTopMaterialAsset->getMaterialDefinitionName());
- mMaterial[Top] = tMat;
- if (mMaterial[Top])
- mMatInst[Top] = mMaterial[Top]->createMatInstance();
- else
- mMatInst[Top] = MATMGR->createMatInstance("WarningMaterial");
- mMatInst[Top]->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>());
- }
- }
- if (mBottomMaterialAsset.notNull())
- {
- if (!mMatInst[Bottom] || !String(mBottomMaterialAsset->getMaterialDefinitionName()).equal(mMatInst[Bottom]->getMaterial()->getName(), String::NoCase))
- {
- SAFE_DELETE(mMatInst[Bottom]);
- Material* tMat = nullptr;
- if (!Sim::findObject(mBottomMaterialAsset->getMaterialDefinitionName(), tMat))
- Con::errorf("MeshRoad::_initMaterial - Material %s was not found.", mBottomMaterialAsset->getMaterialDefinitionName());
- mMaterial[Bottom] = tMat;
- if (mMaterial[Bottom])
- mMatInst[Bottom] = mMaterial[Bottom]->createMatInstance();
- else
- mMatInst[Bottom] = MATMGR->createMatInstance("WarningMaterial");
- mMatInst[Bottom]->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>());
- }
- }
- if (mSideMaterialAsset.notNull())
- {
- if (!mMatInst[Side] || !String(mSideMaterialAsset->getMaterialDefinitionName()).equal(mMatInst[Side]->getMaterial()->getName(), String::NoCase))
- {
- SAFE_DELETE(mMatInst[Side]);
- Material* tMat = nullptr;
- if (!Sim::findObject(mSideMaterialAsset->getMaterialDefinitionName(), tMat))
- Con::errorf("MeshRoad::_initMaterial - Material %s was not found.", mSideMaterialAsset->getMaterialDefinitionName());
- mMaterial[Side] = tMat;
- if (mMaterial[Side])
- mMatInst[Side] = mMaterial[Side]->createMatInstance();
- else
- mMatInst[Side] = MATMGR->createMatInstance("WarningMaterial");
- mMatInst[Side]->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>());
- }
- }
- }
- void MeshRoad::_debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* )
- {
- //MeshRoadConvex convex;
- //buildConvex( Box3F(true), convex );
- //convex.render();
- //GFXDrawUtil *drawer = GFX->getDrawUtil();
- //GFX->setStateBlock( smStateBlock );
- return;
- /*
- U32 convexCount = mDebugConvex.size();
- PrimBuild::begin( GFXTriangleList, convexCount * 12 );
- PrimBuild::color4i( 0, 0, 255, 155 );
- for ( U32 i = 0; i < convexCount; i++ )
- {
- MeshRoadConvex *convex = mDebugConvex[i];
- Point3F a = convex->verts[0];
- Point3F b = convex->verts[1];
- Point3F c = convex->verts[2];
- Point3F p = convex->verts[3];
- //mObjToWorld.mulP(a);
- //mObjToWorld.mulP(b);
- //mObjToWorld.mulP(c);
- //mObjToWorld.mulP(p);
-
- PrimBuild::vertex3fv( c );
- PrimBuild::vertex3fv( b );
- PrimBuild::vertex3fv( a );
- PrimBuild::vertex3fv( b );
- PrimBuild::vertex3fv( a );
- PrimBuild::vertex3fv( p );
- PrimBuild::vertex3fv( c );
- PrimBuild::vertex3fv( b );
- PrimBuild::vertex3fv( p );
- PrimBuild::vertex3fv( a );
- PrimBuild::vertex3fv( c );
- PrimBuild::vertex3fv( p );
- }
- PrimBuild::end();
- for ( U32 i = 0; i < mSegments.size(); i++ )
- {
- ///GFX->getDrawUtil()->drawWireBox( mSegments[i].worldbounds, ColorI(255,0,0,255) );
- }
- GFX->enterDebugEvent( ColorI( 255, 0, 0 ), "DecalRoad_debugRender" );
- GFXTransformSaver saver;
- GFX->setStateBlock( smStateBlock );
- Point3F size(1,1,1);
- ColorI color( 255, 0, 0, 255 );
- if ( smShowBatches )
- {
- for ( U32 i = 0; i < mBatches.size(); i++ )
- {
- const Box3F &box = mBatches[i].bounds;
- Point3F center;
- box.getCenter( ¢er );
- GFX->getDrawUtil()->drawWireCube( ( box.maxExtents - box.minExtents ) * 0.5f, center, ColorI(255,100,100,255) );
- }
- }
- GFX->leaveDebugEvent();
- */
- }
- U32 MeshRoad::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
- {
- U32 retMask = Parent::packUpdate(con, mask, stream);
- if ( stream->writeFlag( mask & MeshRoadMask ) )
- {
- // Write Object Transform.
- stream->writeAffineTransform( mObjToWorld );
- // Write Materials
- PACK_ASSET(con, TopMaterial);
- PACK_ASSET(con, BottomMaterial);
- PACK_ASSET(con, SideMaterial);
- stream->write( mTextureLength );
- stream->write( mBreakAngle );
- stream->write( mWidthSubdivisions );
- }
- if ( stream->writeFlag( mask & ProfileMask ) )
- {
- stream->writeInt( mSideProfile.mNodes.size(), 16 );
- for( U32 i = 0; i < mSideProfile.mNodes.size(); i++ )
- {
- mathWrite( *stream, mSideProfile.mNodes[i].getPosition() );
- stream->writeFlag( mSideProfile.mNodes[i].isSmooth() );
- if(i)
- stream->writeInt(mSideProfile.mSegMtrls[i-1], 3);
- else
- stream->writeInt(0, 3);
- }
- }
- if ( stream->writeFlag( mask & NodeMask ) )
- {
- const U32 nodeByteSize = 32; // Based on sending all of a node's parameters
- // Test if we can fit all of our nodes within the current stream.
- // We make sure we leave 100 bytes still free in the stream for whatever
- // may follow us.
- S32 allowedBytes = stream->getWriteByteSize() - 100;
- if ( stream->writeFlag( (nodeByteSize * mNodes.size()) < allowedBytes ) )
- {
- // All nodes should fit, so send them out now.
- stream->writeInt( mNodes.size(), 16 );
- for ( U32 i = 0; i < mNodes.size(); i++ )
- {
- mathWrite( *stream, mNodes[i].point );
- stream->write( mNodes[i].width );
- stream->write( mNodes[i].depth );
- mathWrite( *stream, mNodes[i].normal );
- }
- }
- else
- {
- // There isn't enough space left in the stream for all of the
- // nodes. Batch them up into NetEvents.
- U32 id = gServerNodeListManager->nextListId();
- U32 count = 0;
- U32 index = 0;
- while (count < mNodes.size())
- {
- count += NodeListManager::smMaximumNodesPerEvent;
- if (count > mNodes.size())
- {
- count = mNodes.size();
- }
- MeshRoadNodeEvent* event = new MeshRoadNodeEvent();
- event->mId = id;
- event->mTotalNodes = mNodes.size();
- event->mLocalListStart = index;
- for (; index<count; ++index)
- {
- event->mPositions.push_back( mNodes[index].point );
- event->mWidths.push_back( mNodes[index].width );
- event->mDepths.push_back( mNodes[index].depth );
- event->mNormals.push_back( mNodes[index].normal );
- }
- con->postNetEvent( event );
- }
- stream->write( id );
- }
- }
- stream->writeFlag( mask & RegenMask );
- // Were done ...
- return retMask;
- }
- void MeshRoad::unpackUpdate(NetConnection * con, BitStream * stream)
- {
- // Unpack Parent.
- Parent::unpackUpdate(con, stream);
- // MeshRoadMask
- if(stream->readFlag())
- {
- MatrixF ObjectMatrix;
- stream->readAffineTransform(&ObjectMatrix);
- Parent::setTransform(ObjectMatrix);
- UNPACK_ASSET(con, TopMaterial);
- UNPACK_ASSET(con, BottomMaterial);
- UNPACK_ASSET(con, SideMaterial);
- if ( isProperlyAdded() )
- _initMaterial();
- stream->read( &mTextureLength );
- stream->read( &mBreakAngle );
- stream->read( &mWidthSubdivisions );
- }
- // ProfileMask
- if(stream->readFlag())
- {
- Point3F pos;
- mSideProfile.mNodes.clear();
- mSideProfile.mSegMtrls.clear();
- U32 count = stream->readInt( 16 );
- for( U32 i = 0; i < count; i++)
- {
- mathRead( *stream, &pos );
- MeshRoadProfileNode node(pos);
- node.setSmoothing( stream->readFlag() );
- mSideProfile.mNodes.push_back(node);
- if(i)
- mSideProfile.mSegMtrls.push_back(stream->readInt(3));
- else
- stream->readInt(3);
- }
- mSideProfile.generateNormals();
- }
- // NodeMask
- if ( stream->readFlag() )
- {
- if (stream->readFlag())
- {
- // Nodes have been passed in this update
- U32 count = stream->readInt( 16 );
- mNodes.clear();
- Point3F pos, normal;
- F32 width, depth;
- for ( U32 i = 0; i < count; i++ )
- {
- mathRead( *stream, &pos );
- stream->read( &width );
- stream->read( &depth );
- mathRead( *stream, &normal );
- _addNode( pos, width, depth, normal );
- }
- }
- else
- {
- // Nodes will arrive as events
- U32 id;
- stream->read( &id );
- // Check if the road's nodes made it here before we did.
- NodeListManager::NodeList* list = NULL;
- if ( gClientNodeListManager->findListById( id, &list, true) )
- {
- // Work with the completed list
- MeshRoadNodeList* roadList = dynamic_cast<MeshRoadNodeList*>( list );
- if (roadList)
- buildNodesFromList( roadList );
- delete list;
- }
- else
- {
- // Nodes have not yet arrived, so register our interest in the list
- MeshRoadNodeListNotify* notify = new MeshRoadNodeListNotify( this, id );
- gClientNodeListManager->registerNotification( notify );
- }
- }
- }
- if ( stream->readFlag() && isProperlyAdded() )
- _regenerate();
- }
- void MeshRoad::setTransform( const MatrixF &mat )
- {
- for ( U32 i = 0; i < mNodes.size(); i++ )
- {
- mWorldToObj.mulP( mNodes[i].point );
- mat.mulP( mNodes[i].point );
- }
- Parent::setTransform( mat );
- if ( mPhysicsRep )
- mPhysicsRep->setTransform( mat );
- // Regenerate and update the client
- _regenerate();
- setMaskBits( NodeMask | RegenMask );
- }
- void MeshRoad::setScale( const VectorF &scale )
- {
- // We ignore scale requests from the editor
- // right now.
- //Parent::setScale( scale );
- }
- void MeshRoad::buildConvex(const Box3F& box, Convex* convex)
- {
- if ( mSlices.size() < 2 )
- return;
- mConvexList->collectGarbage();
- mDebugConvex.clear();
- Box3F realBox = box;
- mWorldToObj.mul(realBox);
- realBox.minExtents.convolveInverse(mObjScale);
- realBox.maxExtents.convolveInverse(mObjScale);
- if (realBox.isOverlapped(getObjBox()) == false)
- return;
- U32 segmentCount = mSegments.size();
- U32 numConvexes ;
- U32 halfConvexes;
- U32 nextSegOffset = 2*mSideProfile.mNodes.size();
- U32 leftSideOffset = nextSegOffset/2;
- U32 k2, capIdx1, capIdx2, capIdx3;
- // Create convex(s) for each segment
- for ( U32 i = 0; i < segmentCount; i++ )
- {
- const MeshRoadSegment &segment = mSegments[i];
- // Is this segment overlapped?
- if ( !segment.getWorldBounds().isOverlapped( box ) )
- continue;
- // Each segment has 6 faces
- for ( U32 j = 0; j < 6; j++ )
- {
- // Only first segment has front face
- if ( j == 4 && i != 0 )
- continue;
- // Only last segment has back face
- if ( j == 5 && i != segmentCount-1 )
- continue;
- // The top and bottom sides have 2 convex(s)
- // The left, right, front, and back sides depend on the user-defined profile
- switch(j)
- {
- case 0: numConvexes = 2; break; // Top
- case 1: // Left
- case 2: numConvexes = 2* (mSideProfile.mNodes.size()-1); break; // Right
- case 3: numConvexes = 2; break; // Bottom
- case 4: // Front
- case 5: numConvexes = mSideProfile.mCap.getNumTris(); break; // Back
- default: numConvexes = 0;
- }
- halfConvexes = numConvexes/2;
- for ( U32 k = 0; k < numConvexes; k++ )
- {
- // See if this convex exists in the working set already...
- Convex* cc = 0;
- CollisionWorkingList& wl = convex->getWorkingList();
- for ( CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext )
- {
- if ( itr->mConvex->getType() == MeshRoadConvexType )
- {
- MeshRoadConvex *pConvex = static_cast<MeshRoadConvex*>(itr->mConvex);
- if ( pConvex->pRoad == this &&
- pConvex->segmentId == i &&
- pConvex->faceId == j &&
- pConvex->triangleId == k )
- {
- cc = itr->mConvex;
- break;
- }
- }
- }
- if (cc)
- continue;
- Point3F a, b, c;
- // Top or Bottom
- if(j == 0 || j == 3)
- {
- // Get the triangle...
- U32 idx0 = gIdxArray[j][k][0];
- U32 idx1 = gIdxArray[j][k][1];
- U32 idx2 = gIdxArray[j][k][2];
- a = segment[idx0];
- b = segment[idx1];
- c = segment[idx2];
- }
- // Left Side
- else if(j == 1)
- {
- if(k >= halfConvexes)
- {
- k2 = k + leftSideOffset - halfConvexes;
- a = segment.slice1->verts[k2];
- b = segment.slice0->verts[k2];
- c = segment.slice1->verts[k2 + 1];
- }
- else
- {
- k2 = k + leftSideOffset;
- a = segment.slice0->verts[k2];
- b = segment.slice0->verts[k2 + 1];
- c = segment.slice1->verts[k2 + 1];
- }
- }
- // Right Side
- else if(j == 2)
- {
- // a.set(2*k, 2*k, 0.0f);
- // b.set(2*k, 2*k, 2.0f);
- // c.set(2*(k+1), 2*(k+1), 0.0f);
- if(k >= halfConvexes)
- {
- k2 = k - halfConvexes;
- a = segment.slice1->verts[k2];
- b = segment.slice1->verts[k2 + 1];
- c = segment.slice0->verts[k2];
- }
- else
- {
- a = segment.slice0->verts[k];
- b = segment.slice1->verts[k + 1];
- c = segment.slice0->verts[k + 1];
- }
- }
- // Front
- else if(j == 4)
- {
- k2 = nextSegOffset + leftSideOffset - 1;
- capIdx1 = mSideProfile.mCap.getTriIdx(k, 0);
- capIdx2 = mSideProfile.mCap.getTriIdx(k, 1);
- capIdx3 = mSideProfile.mCap.getTriIdx(k, 2);
- if(capIdx1 >= leftSideOffset)
- capIdx1 = k2 - capIdx1;
- if(capIdx2 >= leftSideOffset)
- capIdx2 = k2 - capIdx2;
- if(capIdx3 >= leftSideOffset)
- capIdx3 = k2 - capIdx3;
- a = segment.slice0->verts[capIdx1];
- b = segment.slice0->verts[capIdx2];
- c = segment.slice0->verts[capIdx3];
- }
- // Back
- else
- {
- k2 = nextSegOffset + leftSideOffset - 1;
- capIdx1 = mSideProfile.mCap.getTriIdx(k, 0);
- capIdx2 = mSideProfile.mCap.getTriIdx(k, 1);
- capIdx3 = mSideProfile.mCap.getTriIdx(k, 2);
- if(capIdx1 >= leftSideOffset)
- capIdx1 = k2 - capIdx1;
- if(capIdx2 >= leftSideOffset)
- capIdx2 = k2 - capIdx2;
- if(capIdx3 >= leftSideOffset)
- capIdx3 = k2 - capIdx3;
- a = segment.slice1->verts[capIdx3];
- b = segment.slice1->verts[capIdx2];
- c = segment.slice1->verts[capIdx1];
- }
-
- // Transform the result into object space!
- //mWorldToObj.mulP( a );
- //mWorldToObj.mulP( b );
- //mWorldToObj.mulP( c );
- PlaneF p( c, b, a );
- Point3F peak = ((a + b + c) / 3.0f) + (p * 0.15f);
- // Set up the convex...
- MeshRoadConvex *cp = new MeshRoadConvex();
- mConvexList->registerObject( cp );
- convex->addToWorkingList( cp );
- cp->mObject = this;
- cp->pRoad = this;
- cp->segmentId = i;
- cp->faceId = j;
- cp->triangleId = k;
- cp->normal = p;
- cp->verts[0] = c;
- cp->verts[1] = b;
- cp->verts[2] = a;
- cp->verts[3] = peak;
- // Update the bounding box.
- Box3F &bounds = cp->box;
- bounds.minExtents.set( F32_MAX, F32_MAX, F32_MAX );
- bounds.maxExtents.set( -F32_MAX, -F32_MAX, -F32_MAX );
- bounds.minExtents.setMin( a );
- bounds.minExtents.setMin( b );
- bounds.minExtents.setMin( c );
- bounds.minExtents.setMin( peak );
- bounds.maxExtents.setMax( a );
- bounds.maxExtents.setMax( b );
- bounds.maxExtents.setMax( c );
- bounds.maxExtents.setMax( peak );
- mDebugConvex.push_back(cp);
- }
- }
- }
- }
- bool MeshRoad::buildPolyList( PolyListContext, AbstractPolyList* polyList, const Box3F &box, const SphereF & )
- {
- if ( mSlices.size() < 2 )
- return false;
- polyList->setTransform( &MatrixF::Identity, Point3F::One );
- polyList->setObject(this);
- // JCF: optimize this to not always add everything.
- return buildSegmentPolyList( polyList, 0, mSegments.size() - 1, true, true );
- }
- bool MeshRoad::buildSegmentPolyList( AbstractPolyList* polyList, U32 startSegIdx, U32 endSegIdx, bool capFront, bool capEnd )
- {
- if ( mSlices.size() < 2 )
- return false;
- // Add verts
- for ( U32 i = startSegIdx; i <= endSegIdx; i++ )
- {
- const MeshRoadSegment &seg = mSegments[i];
- if ( i == startSegIdx )
- {
- for(U32 j = 0; j < seg.slice0->verts.size(); j++)
- polyList->addPoint( seg.slice0->verts[j] );
- }
- for(U32 j = 0; j < seg.slice1->verts.size(); j++)
- polyList->addPoint( seg.slice1->verts[j] );
- }
- // Temporaries to hold indices for the corner points of a quad.
- S32 p00, p01, p11, p10;
- S32 pb00, pb01, pb11, pb10;
- U32 offset = 0;
- S32 a, b, c;
- U32 mirror;
- DebugDrawer *ddraw = NULL;//DebugDrawer::get();
- ClippedPolyList *cpolyList = dynamic_cast<ClippedPolyList*>(polyList);
- MatrixF mat;
- Point3F scale;
- if ( cpolyList )
- cpolyList->getTransform( &mat, &scale );
- U32 nextSegOffset = 2*mSideProfile.mNodes.size();
- U32 leftSideOffset = nextSegOffset/2;
- for ( U32 i = startSegIdx; i <= endSegIdx; i++ )
- {
- p00 = offset + leftSideOffset;
- p10 = offset;
- pb00 = offset + nextSegOffset - 1;
- pb10 = offset + leftSideOffset - 1;
- p01 = offset + nextSegOffset + leftSideOffset;
- p11 = offset + nextSegOffset;
- pb01 = offset + 2*nextSegOffset - 1;
- pb11 = offset + nextSegOffset + leftSideOffset - 1;
- // Top Face
- polyList->begin( 0,0 );
- polyList->vertex( p00 );
- polyList->vertex( p01 );
- polyList->vertex( p11 );
- polyList->plane( p00, p01, p11 );
- polyList->end();
- if ( ddraw && cpolyList )
- {
- Point3F v0 = cpolyList->mVertexList[p00].point;
- mat.mulP( v0 );
- Point3F v1 = cpolyList->mVertexList[p01].point;
- mat.mulP( v1 );
- Point3F v2 = cpolyList->mVertexList[p11].point;
- mat.mulP( v2 );
- ddraw->drawTri( v0, v1, v2 );
- ddraw->setLastZTest( false );
- ddraw->setLastTTL( 0 );
- }
- polyList->begin( 0,0 );
- polyList->vertex( p00 );
- polyList->vertex( p11 );
- polyList->vertex( p10 );
- polyList->plane( p00, p11, p10 );
- polyList->end();
- if ( ddraw && cpolyList )
- {
- ddraw->drawTri( cpolyList->mVertexList[p00].point, cpolyList->mVertexList[p11].point, cpolyList->mVertexList[p10].point );
- ddraw->setLastTTL( 0 );
- }
- if (buildPolyList_TopSurfaceOnly)
- {
- offset += 4;
- continue;
- }
- // Left Face
- for(U32 j = leftSideOffset; j < nextSegOffset-1; j++)
- {
- a = offset + j;
- b = a + nextSegOffset + 1;
- c = b - 1;
- polyList->begin( 0,0 );
- polyList->vertex( a );
- polyList->vertex( b );
- polyList->vertex( c);
- polyList->plane( a, b, c );
- polyList->end();
- a = offset + j;
- b = a + 1;
- c = a + nextSegOffset + 1;
- polyList->begin( 0,0 );
- polyList->vertex( a );
- polyList->vertex( b );
- polyList->vertex( c );
- polyList->plane( a, b, c );
- polyList->end();
- }
- // Right Face
- for(U32 j = 0; j < leftSideOffset-1; j++)
- {
- a = offset + j;
- b = a + nextSegOffset;
- c = b + 1;
- polyList->begin( 0,0 );
- polyList->vertex( a );
- polyList->vertex( b );
- polyList->vertex( c);
- polyList->plane( a, b, c );
- polyList->end();
- a = offset + j;
- b = a + nextSegOffset + 1;
- c = a + 1;
- polyList->begin( 0,0 );
- polyList->vertex( a );
- polyList->vertex( b );
- polyList->vertex( c );
- polyList->plane( a, b, c );
- polyList->end();
- }
- // Bottom Face
- polyList->begin( 0,0 );
- polyList->vertex( pb00 );
- polyList->vertex( pb10 );
- polyList->vertex( pb11 );
- polyList->plane( pb00, pb10, pb11 );
- polyList->end();
- polyList->begin( 0,0 );
- polyList->vertex( pb00 );
- polyList->vertex( pb11 );
- polyList->vertex( pb01 );
- polyList->plane( pb00, pb11, pb01 );
- polyList->end();
- // Front Face
- if ( i == startSegIdx && capFront )
- {
- mirror = nextSegOffset + leftSideOffset - 1;
- for(U32 j = 0; j < mSideProfile.mCap.getNumTris(); j++)
- {
- a = mSideProfile.mCap.getTriIdx(j, 0);
- b = mSideProfile.mCap.getTriIdx(j, 1);
- c = mSideProfile.mCap.getTriIdx(j, 2);
- if(a >= leftSideOffset)
- a = mirror - a;
- if(b >= leftSideOffset)
- b = mirror - b;
- if(c >= leftSideOffset)
- c = mirror - c;
- polyList->begin( 0,0 );
- polyList->vertex( a );
- polyList->vertex( b );
- polyList->vertex( c );
- polyList->plane( a, b, c );
- polyList->end();
- }
- }
- // Back Face
- if ( i == endSegIdx && capEnd )
- {
- mirror = nextSegOffset + leftSideOffset - 1;
- for(U32 j = 0; j < mSideProfile.mCap.getNumTris(); j++)
- {
- a = mSideProfile.mCap.getTriIdx(j, 0);
- b = mSideProfile.mCap.getTriIdx(j, 1);
- c = mSideProfile.mCap.getTriIdx(j, 2);
- if(a >= leftSideOffset)
- a = offset + nextSegOffset + mirror - a;
- if(b >= leftSideOffset)
- b = offset + nextSegOffset + mirror - b;
- if(c >= leftSideOffset)
- c = offset + nextSegOffset + mirror - c;
- polyList->begin( 0,0 );
- polyList->vertex( c );
- polyList->vertex( b );
- polyList->vertex( a );
- polyList->plane( c, b, a );
- polyList->end();
- }
- }
- offset += nextSegOffset;
- }
- return true;
- }
- bool MeshRoad::castRay( const Point3F &s, const Point3F &e, RayInfo *info )
- {
- Point3F start = s;
- Point3F end = e;
- mObjToWorld.mulP(start);
- mObjToWorld.mulP(end);
- F32 out = 1.0f; // The output fraction/percentage along the line defined by s and e
- VectorF norm(0.0f, 0.0f, 0.0f); // The normal of the face intersected
-
- Vector<MeshRoadHitSegment> hitSegments;
- for ( U32 i = 0; i < mSegments.size(); i++ )
- {
- const MeshRoadSegment &segment = mSegments[i];
- F32 t;
- VectorF n;
- if ( segment.getWorldBounds().collideLine( start, end, &t, &n ) )
- {
- hitSegments.increment();
- hitSegments.last().t = t;
- hitSegments.last().idx = i;
- }
- }
- dQsort( hitSegments.address(), hitSegments.size(), sizeof(MeshRoadHitSegment), compareHitSegments );
- U32 idx0, idx1, idx2;
- F32 t;
- for ( U32 i = 0; i < hitSegments.size(); i++ )
- {
- U32 segIdx = hitSegments[i].idx;
- const MeshRoadSegment &segment = mSegments[segIdx];
- U32 numConvexes ;
- U32 halfConvexes;
- U32 nextSegOffset = 2*mSideProfile.mNodes.size();
- U32 leftSideOffset = nextSegOffset/2;
- U32 k2, capIdx1, capIdx2, capIdx3;
- // Each segment has 6 faces
- for ( U32 j = 0; j < 6; j++ )
- {
- if ( j == 4 && segIdx != 0 )
- continue;
- if ( j == 5 && segIdx != mSegments.size() - 1 )
- continue;
- // The top and bottom sides have 2 convex(s)
- // The left, right, front, and back sides depend on the user-defined profile
- switch(j)
- {
- case 0: numConvexes = 2; break; // Top
- case 1: // Left
- case 2: numConvexes = 2* (mSideProfile.mNodes.size()-1); break; // Right
- case 3: numConvexes = 2; break; // Bottom
- case 4: // Front
- case 5: numConvexes = mSideProfile.mCap.getNumTris(); break; // Back
- default: numConvexes = 0;
- }
- halfConvexes = numConvexes/2;
- // Each face has 2 triangles
- for ( U32 k = 0; k < numConvexes; k++ )
- {
- const Point3F *a = NULL;
- const Point3F *b = NULL;
- const Point3F *c = NULL;
- // Top or Bottom
- if(j == 0 || j == 3)
- {
- idx0 = gIdxArray[j][k][0];
- idx1 = gIdxArray[j][k][1];
- idx2 = gIdxArray[j][k][2];
- a = &segment[idx0];
- b = &segment[idx1];
- c = &segment[idx2];
- }
- // Left Side
- else if(j == 1)
- {
- if(k >= halfConvexes)
- {
- k2 = k + leftSideOffset - halfConvexes;
- a = &segment.slice1->verts[k2];
- b = &segment.slice0->verts[k2];
- c = &segment.slice1->verts[k2 + 1];
- }
- else
- {
- k2 = k + leftSideOffset;
- a = &segment.slice0->verts[k2];
- b = &segment.slice0->verts[k2 + 1];
- c = &segment.slice1->verts[k2 + 1];
- }
- }
- // Right Side
- else if(j == 2)
- {
- if(k >= halfConvexes)
- {
- k2 = k - halfConvexes;
- a = &segment.slice1->verts[k2];
- b = &segment.slice1->verts[k2 + 1];
- c = &segment.slice0->verts[k2];
- }
- else
- {
- a = &segment.slice0->verts[k];
- b = &segment.slice1->verts[k + 1];
- c = &segment.slice0->verts[k + 1];
- }
- }
- // Front
- else if(j == 4)
- {
- k2 = nextSegOffset + leftSideOffset - 1;
- capIdx1 = mSideProfile.mCap.getTriIdx(k, 0);
- capIdx2 = mSideProfile.mCap.getTriIdx(k, 1);
- capIdx3 = mSideProfile.mCap.getTriIdx(k, 2);
- if(capIdx1 >= leftSideOffset)
- capIdx1 = k2 - capIdx1;
- if(capIdx2 >= leftSideOffset)
- capIdx2 = k2 - capIdx2;
- if(capIdx3 >= leftSideOffset)
- capIdx3 = k2 - capIdx3;
- a = &segment.slice0->verts[capIdx1];
- b = &segment.slice0->verts[capIdx2];
- c = &segment.slice0->verts[capIdx3];
- }
- // Back
- else
- {
- k2 = nextSegOffset + leftSideOffset - 1;
- capIdx1 = mSideProfile.mCap.getTriIdx(k, 0);
- capIdx2 = mSideProfile.mCap.getTriIdx(k, 1);
- capIdx3 = mSideProfile.mCap.getTriIdx(k, 2);
- if(capIdx1 >= leftSideOffset)
- capIdx1 = k2 - capIdx1;
- if(capIdx2 >= leftSideOffset)
- capIdx2 = k2 - capIdx2;
- if(capIdx3 >= leftSideOffset)
- capIdx3 = k2 - capIdx3;
- a = &segment.slice1->verts[capIdx3];
- b = &segment.slice1->verts[capIdx2];
- c = &segment.slice1->verts[capIdx1];
- }
- if ( !MathUtils::mLineTriangleCollide( start, end,
- *c, *b, *a,
- NULL,
- &t ) )
- continue;
-
- if ( t >= 0.0f && t < 1.0f && t < out )
- {
- out = t;
- norm = PlaneF( *a, *b, *c );
- }
- }
- }
- if (out >= 0.0f && out < 1.0f)
- break;
- }
- if (out >= 0.0f && out < 1.0f)
- {
- info->t = out;
- info->normal = norm;
- info->point.interpolate(start, end, out);
- info->face = -1;
- info->object = this;
- info->material = this->mMatInst[0];
- return true;
- }
- return false;
- }
- bool MeshRoad::collideBox(const Point3F &start, const Point3F &end, RayInfo* info)
- {
- Con::warnf( "MeshRoad::collideBox() - not yet implemented!" );
- return Parent::collideBox( start, end, info );
- }
- void MeshRoad::_regenerate()
- {
- if ( mNodes.size() == 0 )
- return;
- if ( mSideProfile.mNodes.size() == 2 && mSideProfile.mNodes[1].getPosition().x == 0.0f)
- mSideProfile.setProfileDepth(mNodes[0].depth);
- const Point3F &nodePt = mNodes.first().point;
- MatrixF mat( true );
- mat.setPosition( nodePt );
- Parent::setTransform( mat );
- _generateSlices();
- // Make sure we are in the correct bins given our world box.
- if( getSceneManager() != NULL )
- getSceneManager()->notifyObjectDirty( this );
- }
- void MeshRoad::_generateSlices()
- {
- if ( mNodes.size() < 2 )
- return;
- // Create the spline, initialized with the MeshRoadNode(s)
- U32 nodeCount = mNodes.size();
- MeshRoadSplineNode *splineNodes = new MeshRoadSplineNode[nodeCount];
- for ( U32 i = 0; i < nodeCount; i++ )
- {
- MeshRoadSplineNode &splineNode = splineNodes[i];
- const MeshRoadNode &node = mNodes[i];
- splineNode.x = node.point.x;
- splineNode.y = node.point.y;
- splineNode.z = node.point.z;
- splineNode.width = node.width;
- splineNode.depth = node.depth;
- splineNode.normal = node.normal;
- }
- CatmullRom<MeshRoadSplineNode> spline;
- spline.initialize( nodeCount, splineNodes );
- delete [] splineNodes;
- mSlices.clear();
-
- VectorF lastBreakVector(0,0,0);
- MeshRoadSlice slice;
- MeshRoadSplineNode lastBreakNode;
- lastBreakNode = spline.evaluate(0.0f);
- for ( U32 i = 1; i < mNodes.size(); i++ )
- {
- F32 t1 = spline.getTime(i);
- F32 t0 = spline.getTime(i-1);
-
- F32 segLength = spline.arcLength( t0, t1 );
- U32 numSegments = mCeil( segLength / MIN_METERS_PER_SEGMENT );
- numSegments = getMax( numSegments, (U32)1 );
- F32 tstep = ( t1 - t0 ) / numSegments;
- U32 startIdx = 0;
- U32 endIdx = ( i == nodeCount - 1 ) ? numSegments + 1 : numSegments;
- for ( U32 j = startIdx; j < endIdx; j++ )
- {
- F32 t = t0 + tstep * j;
- MeshRoadSplineNode splineNode = spline.evaluate(t);
- VectorF toNodeVec = splineNode.getPosition() - lastBreakNode.getPosition();
- toNodeVec.normalizeSafe();
- if ( lastBreakVector.isZero() )
- lastBreakVector = toNodeVec;
- F32 angle = mRadToDeg( mAcos( mDot( toNodeVec, lastBreakVector ) ) );
- if ( j == startIdx ||
- ( j == endIdx - 1 && i == mNodes.size() - 1 ) ||
- angle > mBreakAngle )
- {
- // Push back a spline node
- slice.p1.set( splineNode.x, splineNode.y, splineNode.z );
- slice.width = splineNode.width;
- slice.depth = splineNode.depth;
- slice.normal = splineNode.normal;
- slice.normal.normalize();
- slice.parentNodeIdx = i-1;
- slice.t = t;
- mSlices.push_back( slice );
- lastBreakVector = splineNode.getPosition() - lastBreakNode.getPosition();
- lastBreakVector.normalizeSafe();
- lastBreakNode = splineNode;
- }
- }
- }
-
- MatrixF mat(true);
- Box3F box;
- U32 lastProfileNode = mSideProfile.mNodes.size() - 1;
- F32 depth = mSideProfile.mNodes[lastProfileNode].getPosition().y;
- F32 bttmOffset = mSideProfile.mNodes[lastProfileNode].getPosition().x;
- for ( U32 i = 0; i < mSlices.size(); i++ )
- {
- // Calculate uvec, fvec, and rvec for all slices
- calcSliceTransform( i, mat );
- MeshRoadSlice *slicePtr = &mSlices[i];
- mat.getColumn( 0, &slicePtr->rvec );
- mat.getColumn( 1, &slicePtr->fvec );
- mat.getColumn( 2, &slicePtr->uvec );
- // Calculate p0/p2/pb0/pb2 for all slices
- slicePtr->p0 = slicePtr->p1 - slicePtr->rvec * slicePtr->width * 0.5f;
- slicePtr->p2 = slicePtr->p1 + slicePtr->rvec * slicePtr->width * 0.5f;
- slicePtr->pb0 = slicePtr->p0 + slicePtr->uvec * depth - slicePtr->rvec * bttmOffset;
- slicePtr->pb2 = slicePtr->p2 + slicePtr->uvec * depth + slicePtr->rvec * bttmOffset;
- // Generate or extend the object/world bounds
- if ( i == 0 )
- {
- box.minExtents = slicePtr->p0;
- box.maxExtents = slicePtr->p2;
- box.extend(slicePtr->pb0 );
- box.extend(slicePtr->pb2 );
- }
- else
- {
- box.extend(slicePtr->p0 );
- box.extend(slicePtr->p2 );
- box.extend(slicePtr->pb0 );
- box.extend(slicePtr->pb2 );
- }
- // Right side
- Point3F pos;
- VectorF norm;
- MatrixF profileMat1(true);
- profileMat1.setRow(0, slicePtr->rvec);
- profileMat1.setRow(1, slicePtr->uvec);
- profileMat1.setRow(2, -slicePtr->fvec);
- // Left side
- MatrixF profileMat2(true);
- profileMat2.setRow(0, -slicePtr->rvec);
- profileMat2.setRow(1, slicePtr->uvec);
- profileMat2.setRow(2, slicePtr->fvec);
- for(U32 i = 0; i < 2; i++)
- {
- if(i)
- mSideProfile.setTransform(profileMat2, slicePtr->p0);
- else
- mSideProfile.setTransform(profileMat1, slicePtr->p2);
- // Retain original per-node depth functionality
- if(mSideProfile.mNodes.size() == 2 && mSideProfile.mNodes[1].getPosition().y == -mSlices[0].depth)
- {
- mSideProfile.getNodeWorldPos(0, pos);
- slicePtr->verts.push_back(pos);
- box.extend( pos );
- pos.z -= slicePtr->depth;
- slicePtr->verts.push_back(pos);
- box.extend( pos );
- if(i)
- slicePtr->pb0 = pos;
- else
- slicePtr->pb2 = pos;
- mSideProfile.getNormToSlice(0, norm);
- slicePtr->norms.push_back(norm);
- mSideProfile.getNormToSlice(1, norm);
- slicePtr->norms.push_back(norm);
- }
- // New profile functionality
- else
- {
- for(U32 j = 0; j < mSideProfile.mNodes.size(); j++)
- {
- mSideProfile.getNodeWorldPos(j, pos);
- slicePtr->verts.push_back(pos);
- box.extend( pos );
- }
- for(U32 j = 0; j < mSideProfile.mNodeNormals.size(); j++)
- {
- mSideProfile.getNormToSlice(j, norm);
- slicePtr->norms.push_back(norm);
- }
- }
- }
- }
- mWorldBox = box;
- resetObjectBox();
- _generateSegments();
- }
- void MeshRoad::_generateSegments()
- {
- SAFE_DELETE( mPhysicsRep );
- mSegments.clear();
- for ( U32 i = 0; i < mSlices.size() - 1; i++ )
- {
- MeshRoadSegment seg( &mSlices[i], &mSlices[i+1], getWorldTransform() );
- mSegments.push_back( seg );
- }
- //mSideProfile.generateEndCap(mSlices[0].width);
- if ( isClientObject() )
- _generateVerts();
- if ( PHYSICSMGR )
- {
- ConcretePolyList polylist;
- if ( buildPolyList( PLC_Collision, &polylist, getWorldBox(), getWorldSphere() ) )
- {
- polylist.triangulate();
- PhysicsCollision *colShape = PHYSICSMGR->createCollision();
- colShape->addTriangleMesh( polylist.mVertexList.address(),
- polylist.mVertexList.size(),
- polylist.mIndexList.address(),
- polylist.mIndexList.size() / 3,
- MatrixF::Identity );
- PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
- mPhysicsRep = PHYSICSMGR->createBody();
- mPhysicsRep->init( colShape, 0, 0, this, world );
- }
- }
- }
- void MeshRoad::_generateVerts()
- {
- const U32 widthDivisions = getMax( 0, mWidthSubdivisions );
- const F32 divisionStep = 1.0f / (F32)( widthDivisions + 1 );
- const U32 sliceCount = mSlices.size();
- const U32 segmentCount = mSegments.size();
- U32 numProfSide, numProfTop, numProfBottom;
- numProfSide = numProfTop = numProfBottom = 0;
- // Find how many profile segments are set to side, top, and bottom materials
- for ( U32 i = 0; i < mSideProfile.mSegMtrls.size(); i++)
- {
- switch(mSideProfile.mSegMtrls[i])
- {
- case Side: numProfSide++; break;
- case Top: numProfTop++; break;
- case Bottom: numProfBottom++; break;
- }
- }
- F32 profLen = mSideProfile.getProfileLen();
- mVertCount[Top] = ( 2 + widthDivisions ) * sliceCount;
- mVertCount[Top] += sliceCount * numProfTop * 4;
- mTriangleCount[Top] = segmentCount * 2 * ( widthDivisions + 1 );
- mTriangleCount[Top] += segmentCount * numProfTop * 4;
- mVertCount[Bottom] = sliceCount * 2;
- mVertCount[Bottom] += sliceCount * numProfBottom * 4;
- mTriangleCount[Bottom] = segmentCount * 2;
- mTriangleCount[Bottom] += segmentCount * numProfBottom * 4;
- mVertCount[Side] = sliceCount * numProfSide * 4; // side verts
- mVertCount[Side] += mSideProfile.mNodes.size() * 4; // end cap verts
- mTriangleCount[Side] = segmentCount * numProfSide * 4; // side tris
- mTriangleCount[Side] += mSideProfile.mCap.getNumTris() * 2; // end cap tris
-
- // Calculate TexCoords for Slices
- F32 texCoordV = 0.0f;
- mSlices[0].texCoordV = 0.0f;
- for ( U32 i = 1; i < sliceCount; i++ )
- {
- MeshRoadSlice &slice = mSlices[i];
- MeshRoadSlice &prevSlice = mSlices[i-1];
-
- // Increment the textCoordV for the next slice.
- F32 len = ( slice.p1 - prevSlice.p1 ).len();
- texCoordV += len / mTextureLength;
- slice.texCoordV = texCoordV;
- }
- // Make Vertex Buffers
- GFXVertexPNTT *pVert = NULL;
- U32 vertCounter = 0;
- // Top Buffers...
- mVB[Top].set( GFX, mVertCount[Top], GFXBufferTypeStatic );
- pVert = mVB[Top].lock();
- vertCounter = 0;
-
- for ( U32 i = 0; i < sliceCount; i++ )
- {
- MeshRoadSlice &slice = mSlices[i];
-
- pVert->point = slice.p0;
- pVert->normal = slice.uvec;
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(1,slice.texCoordV);
- pVert++;
- vertCounter++;
- for ( U32 j = 0; j < widthDivisions; j++ )
- {
- const F32 t = divisionStep * (F32)( j + 1 );
- pVert->point.interpolate( slice.p0, slice.p2, t );
- pVert->normal = slice.uvec;
- pVert->tangent = slice.fvec;
- pVert->texCoord.set( 1.0f - t, slice.texCoordV );
- pVert++;
- vertCounter++;
- }
- pVert->point = slice.p2;
- pVert->normal = slice.uvec;
- pVert->tangent = slice.fvec;
- pVert->texCoord.set( 0, slice.texCoordV );
- pVert++;
- vertCounter++;
- }
- if(numProfTop)
- {
- for ( U32 i = 0; i < sliceCount; i++ )
- {
- MeshRoadSlice &slice = mSlices[i];
- // Right Side
- for ( U32 j = 0; j < mSideProfile.mNodes.size()-1; j++)
- {
- if(mSideProfile.mSegMtrls[j] == Top)
- {
- // Vertex 1
- pVert->point = slice.verts[j];
- pVert->normal = slice.norms[2*j];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- // Vertex 2
- pVert->point = slice.verts[j+1];
- pVert->normal = slice.norms[2*j+1];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j+1)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- }
- // Left Side
- for( U32 j = mSideProfile.mNodes.size(); j < 2*mSideProfile.mNodes.size()-1; j++)
- {
- if(mSideProfile.mSegMtrls[j-mSideProfile.mNodes.size()] == Top)
- {
- // Vertex 1
- pVert->point = slice.verts[j];
- pVert->normal = slice.norms[2*j-2];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- // Vertex 2
- pVert->point = slice.verts[j+1];
- pVert->normal = slice.norms[2*j-1];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j+1)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- }
- }
- }
- AssertFatal( vertCounter == mVertCount[Top], "MeshRoad, wrote incorrect number of verts in mVB[Top]!" );
- mVB[Top].unlock();
- // Bottom Buffer...
- mVB[Bottom].set( GFX, mVertCount[Bottom], GFXBufferTypeStatic );
- pVert = mVB[Bottom].lock();
- vertCounter = 0;
- for ( U32 i = 0; i < sliceCount; i++ )
- {
- MeshRoadSlice &slice = mSlices[i];
- pVert->point = slice.pb2;
- pVert->normal = -slice.uvec;
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(0,slice.texCoordV);
- pVert++;
- vertCounter++;
- pVert->point = slice.pb0;
- pVert->normal = -slice.uvec;
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(1,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- if(numProfBottom)
- {
- for ( U32 i = 0; i < sliceCount; i++ )
- {
- MeshRoadSlice &slice = mSlices[i];
- // Right Side
- for ( U32 j = 0; j < mSideProfile.mNodes.size()-1; j++)
- {
- if(mSideProfile.mSegMtrls[j] == Bottom)
- {
- // Vertex 1
- pVert->point = slice.verts[j];
- pVert->normal = slice.norms[2*j];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- // Vertex 2
- pVert->point = slice.verts[j+1];
- pVert->normal = slice.norms[2*j+1];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j+1)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- }
- // Left Side
- for( U32 j = mSideProfile.mNodes.size(); j < 2*mSideProfile.mNodes.size()-1; j++)
- {
- if(mSideProfile.mSegMtrls[j-mSideProfile.mNodes.size()] == Bottom)
- {
- // Vertex 1
- pVert->point = slice.verts[j];
- pVert->normal = slice.norms[2*j-2];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- // Vertex 2
- pVert->point = slice.verts[j+1];
- pVert->normal = slice.norms[2*j-1];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j+1)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- }
- }
- }
- AssertFatal( vertCounter == mVertCount[Bottom], "MeshRoad, wrote incorrect number of verts in mVB[Bottom]!" );
- mVB[Bottom].unlock();
- // Side Buffers...
- mVB[Side].set( GFX, mVertCount[Side], GFXBufferTypeStatic );
- pVert = mVB[Side].lock();
- vertCounter = 0;
- if(numProfSide)
- {
- for ( U32 i = 0; i < sliceCount; i++ )
- {
- MeshRoadSlice &slice = mSlices[i];
- // Right Side
- for( U32 j = 0; j < mSideProfile.mNodes.size()-1; j++)
- {
- if(mSideProfile.mSegMtrls[j] == Side)
- {
- // Segment Vertex 1
- pVert->point = slice.verts[j];
- pVert->normal = slice.norms[2*j];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- // Segment Vertex 2
- pVert->point = slice.verts[j+1];
- pVert->normal = slice.norms[2*j+1];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j+1)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- }
- // Left Side
- for( U32 j = mSideProfile.mNodes.size(); j < 2*mSideProfile.mNodes.size()-1; j++)
- {
- if(mSideProfile.mSegMtrls[j-mSideProfile.mNodes.size()] == Side)
- {
- // Segment Vertex 1
- pVert->point = slice.verts[j];
- pVert->normal = slice.norms[2*j-2];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- // Segment Vertex 2
- pVert->point = slice.verts[j+1];
- pVert->normal = slice.norms[2*j-1];
- pVert->tangent = slice.fvec;
- pVert->texCoord.set(mSideProfile.getNodePosPercent(j+1)*profLen/mTextureLength,slice.texCoordV);
- pVert++;
- vertCounter++;
- }
- }
- }
- }
- // Cap verts
- Point3F pos;
- VectorF norm;
- VectorF tang;
- for( U32 i = 0; i < mSlices.size(); i += mSlices.size()-1)
- {
- MeshRoadSlice &slice = mSlices[i];
- // Back cap
- if(i)
- {
- norm = slice.fvec;
- tang = -slice.rvec;
- }
- // Front cap
- else
- {
- norm = -slice.fvec;
- tang = slice.rvec;
- }
- // Right side
- for( U32 j = 0; j < mSideProfile.mNodes.size(); j++)
- {
- pVert->point = slice.verts[j];
- pVert->normal = norm;
- pVert->tangent = tang;
- pos = mSideProfile.mNodes[j].getPosition();
- pVert->texCoord.set(pos.x/mTextureLength, pos.y/mTextureLength);
- pVert++;
- vertCounter++;
- }
- // Left side
- for( U32 j = 2*mSideProfile.mNodes.size()-1; j >= mSideProfile.mNodes.size(); j--)
- {
- pVert->point = slice.verts[j];
- pVert->normal = norm;
- pVert->tangent = tang;
- pos = mSideProfile.mNodes[j-mSideProfile.mNodes.size()].getPosition();
- pos.x = -pos.x - slice.width;
- pVert->texCoord.set(pos.x/mTextureLength, pos.y/mTextureLength);
- pVert++;
- vertCounter++;
- }
- }
- AssertFatal( vertCounter == mVertCount[Side], "MeshRoad, wrote incorrect number of verts in mVB[Side]!" );
- mVB[Side].unlock();
- // Make Primitive Buffers
- U32 p00, p01, p11, p10;
- U32 offset = 0;
- U16 *pIdx = NULL;
- U32 curIdx = 0;
- // Top Primitive Buffer
- mPB[Top].set( GFX, mTriangleCount[Top] * 3, mTriangleCount[Top], GFXBufferTypeStatic );
- mPB[Top].lock(&pIdx);
- curIdx = 0;
- offset = 0;
- const U32 rowStride = 2 + widthDivisions;
-
- for ( U32 i = 0; i < mSegments.size(); i++ )
- {
- for ( U32 j = 0; j < widthDivisions + 1; j++ )
- {
- p00 = offset;
- p10 = offset + 1;
- p01 = offset + rowStride;
- p11 = offset + rowStride + 1;
- pIdx[curIdx] = p00;
- curIdx++;
- pIdx[curIdx] = p01;
- curIdx++;
- pIdx[curIdx] = p11;
- curIdx++;
- pIdx[curIdx] = p00;
- curIdx++;
- pIdx[curIdx] = p11;
- curIdx++;
- pIdx[curIdx] = p10;
- curIdx++;
- offset += 1;
- }
- offset += 1;
- }
- offset += 2;
- if(numProfTop)
- {
- U32 nextSegOffset = 4 * numProfTop;
- for ( U32 i = 0; i < segmentCount; i++ )
- {
- // Loop through profile segments on right side
- for( U32 j = 0; j < numProfTop; j++)
- {
- // Profile Segment Face 1
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + 1 + offset;
- curIdx++;
- // Profile Segment Face 2
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- }
- // Loop through profile segments on left side
- for( U32 j = numProfTop; j < 2*numProfTop; j++)
- {
- // Profile Segment Face 1
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + 1 + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- // Profile Segment Face 2
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + offset;
- curIdx++;
- }
- }
- }
- AssertFatal( curIdx == mTriangleCount[Top] * 3, "MeshRoad, wrote incorrect number of indices in mPB[Top]!" );
- mPB[Top].unlock();
- // Bottom Primitive Buffer
- mPB[Bottom].set( GFX, mTriangleCount[Bottom] * 3, mTriangleCount[Bottom], GFXBufferTypeStatic );
- mPB[Bottom].lock(&pIdx);
- curIdx = 0;
- offset = 0;
- for ( U32 i = 0; i < mSegments.size(); i++ )
- {
- p00 = offset;
- p10 = offset + 1;
- p01 = offset + 2;
- p11 = offset + 3;
- pIdx[curIdx] = p00;
- curIdx++;
- pIdx[curIdx] = p01;
- curIdx++;
- pIdx[curIdx] = p11;
- curIdx++;
- pIdx[curIdx] = p00;
- curIdx++;
- pIdx[curIdx] = p11;
- curIdx++;
- pIdx[curIdx] = p10;
- curIdx++;
- offset += 2;
- }
- offset += 2;
- if(numProfBottom)
- {
- U32 nextSegOffset = 4 * numProfBottom;
- for ( U32 i = 0; i < segmentCount; i++ )
- {
- // Loop through profile segments on right side
- for( U32 j = 0; j < numProfBottom; j++)
- {
- // Profile Segment Face 1
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + 1 + offset;
- curIdx++;
- // Profile Segment Face 2
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- }
- // Loop through profile segments on left side
- for( U32 j = numProfBottom; j < 2*numProfBottom; j++)
- {
- // Profile Segment Face 1
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + 1 + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- // Profile Segment Face 2
- pIdx[curIdx] = nextSegOffset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + 1 + offset;
- curIdx++;
- pIdx[curIdx] = nextSegOffset*i + 2*j + nextSegOffset + offset;
- curIdx++;
- }
- }
- }
- AssertFatal( curIdx == mTriangleCount[Bottom] * 3, "MeshRoad, wrote incorrect number of indices in mPB[Bottom]!" );
- mPB[Bottom].unlock();
- // Side Primitive Buffer
- mPB[Side].set( GFX, mTriangleCount[Side] * 3, mTriangleCount[Side], GFXBufferTypeStatic );
- mPB[Side].lock(&pIdx);
- curIdx = 0;
- offset = 4 * numProfSide;
- if(numProfSide)
- {
- for ( U32 i = 0; i < mSegments.size(); i++ )
- {
- // Loop through profile segments on right side
- for( U32 j = 0; j < numProfSide; j++)
- {
- // Profile Segment Face 1
- pIdx[curIdx] = offset*i + 2*j;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + offset + 1;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + 1;
- curIdx++;
- // Profile Segment Face 2
- pIdx[curIdx] = offset*i + 2*j;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + offset;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + offset + 1;
- curIdx++;
- }
- // Loop through profile segments on left side
- for( U32 j = numProfSide; j < 2*numProfSide; j++)
- {
- // Profile Segment Face 1
- pIdx[curIdx] = offset*i + 2*j;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + 1;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + offset + 1;
- curIdx++;
- // Profile Segment Face 2
- pIdx[curIdx] = offset*i + 2*j;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + offset + 1;
- curIdx++;
- pIdx[curIdx] = offset*i + 2*j + offset;
- curIdx++;
- }
- }
- }
- // Cap the front
- offset = sliceCount * numProfSide * 4;
- for ( U32 i = 0; i < mSideProfile.mCap.getNumTris(); i++ )
- {
- pIdx[curIdx] = mSideProfile.mCap.getTriIdx(i, 0) + offset;
- curIdx++;
- pIdx[curIdx] = mSideProfile.mCap.getTriIdx(i, 1) + offset;
- curIdx++;
- pIdx[curIdx] = mSideProfile.mCap.getTriIdx(i, 2) + offset;
- curIdx++;
- }
- // Cap the back
- offset += mSideProfile.mNodes.size() * 2;
- for ( U32 i = 0; i < mSideProfile.mCap.getNumTris(); i++ )
- {
- pIdx[curIdx] = mSideProfile.mCap.getTriIdx(i, 2) + offset;
- curIdx++;
- pIdx[curIdx] = mSideProfile.mCap.getTriIdx(i, 1) + offset;
- curIdx++;
- pIdx[curIdx] = mSideProfile.mCap.getTriIdx(i, 0) + offset;
- curIdx++;
- }
- AssertFatal( curIdx == mTriangleCount[Side] * 3, "MeshRoad, wrote incorrect number of indices in mPB[Side]!" );
- mPB[Side].unlock();
- }
- const MeshRoadNode& MeshRoad::getNode( U32 idx )
- {
- return mNodes[idx];
- }
- VectorF MeshRoad::getNodeNormal( U32 idx )
- {
- if ( mNodes.size() - 1 < idx )
- return VectorF::Zero;
- return mNodes[idx].normal;
- }
- void MeshRoad::setNodeNormal( U32 idx, const VectorF &normal )
- {
- if ( mNodes.size() - 1 < idx )
- return;
- mNodes[idx].normal = normal;
- regenerate();
- setMaskBits( NodeMask | RegenMask );
- }
- Point3F MeshRoad::getNodePosition( U32 idx )
- {
- if ( mNodes.size() - 1 < idx )
- return Point3F::Zero;
- return mNodes[idx].point;
- }
- void MeshRoad::setNodePosition( U32 idx, const Point3F &pos )
- {
- if ( mNodes.size() - 1 < idx )
- return;
- mNodes[idx].point = pos;
- regenerate();
- setMaskBits( NodeMask | RegenMask );
- }
- U32 MeshRoad::addNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal )
- {
- U32 idx = _addNode( pos, width, depth, normal );
- regenerate();
- setMaskBits( NodeMask | RegenMask );
- return idx;
- }
- void MeshRoad::buildNodesFromList( MeshRoadNodeList* list )
- {
- mNodes.clear();
- for (U32 i=0; i<list->mPositions.size(); ++i)
- {
- _addNode( list->mPositions[i], list->mWidths[i], list->mDepths[i], list->mNormals[i] );
- }
- _regenerate();
- }
- U32 MeshRoad::insertNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal, const U32 &idx )
- {
- U32 ret = _insertNode( pos, width, depth, normal, idx );
- regenerate();
- setMaskBits( NodeMask | RegenMask );
- return ret;
- }
- void MeshRoad::setNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal, const U32 &idx )
- {
- if ( mNodes.size() - 1 < idx )
- return;
- MeshRoadNode &node = mNodes[idx];
- node.point = pos;
- node.width = width;
- node.depth = depth;
- node.normal = normal;
- regenerate();
- setMaskBits( NodeMask | RegenMask );
- }
- void MeshRoad::setNodeWidth( U32 idx, F32 meters )
- {
- meters = mClampF( meters, MIN_NODE_WIDTH, MAX_NODE_WIDTH );
- if ( mNodes.size() - 1 < idx )
- return;
- mNodes[idx].width = meters;
- _regenerate();
- setMaskBits( RegenMask | NodeMask );
- }
- F32 MeshRoad::getNodeWidth( U32 idx )
- {
- if ( mNodes.size() - 1 < idx )
- return -1.0f;
- return mNodes[idx].width;
- }
- void MeshRoad::setNodeDepth( U32 idx, F32 meters )
- {
- meters = mClampF( meters, MIN_NODE_DEPTH, MAX_NODE_DEPTH );
- if ( mNodes.size() - 1 < idx )
- return;
- mNodes[idx].depth = meters;
- _regenerate();
- setMaskBits( MeshRoadMask | RegenMask | NodeMask );
- }
- F32 MeshRoad::getNodeDepth( U32 idx )
- {
- if ( mNodes.size() - 1 < idx )
- return -1.0f;
- return mNodes[idx].depth;
- }
- MatrixF MeshRoad::getNodeTransform( U32 idx )
- {
- MatrixF mat(true);
- if ( mNodes.size() - 1 < idx )
- return mat;
- bool hasNext = idx + 1 < mNodes.size();
- bool hasPrev = (S32)idx - 1 > 0;
- const MeshRoadNode &node = mNodes[idx];
- VectorF fvec( 0, 1, 0 );
- if ( hasNext )
- {
- fvec = mNodes[idx+1].point - node.point;
- fvec.normalizeSafe();
- }
- else if ( hasPrev )
- {
- fvec = node.point - mNodes[idx-1].point;
- fvec.normalizeSafe();
- }
- else
- fvec = mPerp( node.normal );
- if ( fvec.isZero() )
- fvec = mPerp( node.normal );
- F32 dot = mDot( fvec, node.normal );
- if ( dot < -0.9f || dot > 0.9f )
- fvec = mPerp( node.normal );
- VectorF rvec = mCross( fvec, node.normal );
- if ( rvec.isZero() )
- rvec = mPerp( fvec );
- rvec.normalize();
- fvec = mCross( node.normal, rvec );
- fvec.normalize();
- mat.setColumn( 0, rvec );
- mat.setColumn( 1, fvec );
- mat.setColumn( 2, node.normal );
- mat.setColumn( 3, node.point );
- AssertFatal( m_matF_determinant( mat ) != 0.0f, "no inverse!");
- return mat;
- }
- void MeshRoad::calcSliceTransform( U32 idx, MatrixF &mat )
- {
- if ( mSlices.size() - 1 < idx )
- return;
- bool hasNext = idx + 1 < mSlices.size();
- bool hasPrev = (S32)idx - 1 >= 0;
- const MeshRoadSlice &slice = mSlices[idx];
- VectorF fvec( 0, 1, 0 );
- if ( hasNext )
- {
- fvec = mSlices[idx+1].p1 - slice.p1;
- fvec.normalizeSafe();
- }
- else if ( hasPrev )
- {
- fvec = slice.p1 - mSlices[idx-1].p1;
- fvec.normalizeSafe();
- }
- else
- fvec = mPerp( slice.normal );
- if ( fvec.isZero() )
- fvec = mPerp( slice.normal );
- F32 dot = mDot( fvec, slice.normal );
- if ( dot < -0.9f || dot > 0.9f )
- fvec = mPerp( slice.normal );
- VectorF rvec = mCross( fvec, slice.normal );
- if ( rvec.isZero() )
- rvec = mPerp( fvec );
- rvec.normalize();
- fvec = mCross( slice.normal, rvec );
- fvec.normalize();
- mat.setColumn( 0, rvec );
- mat.setColumn( 1, fvec );
- mat.setColumn( 2, slice.normal );
- mat.setColumn( 3, slice.p1 );
- AssertFatal( m_matF_determinant( mat ) != 0.0f, "no inverse!");
- }
- F32 MeshRoad::getRoadLength() const
- {
- F32 length = 0.0f;
- for ( U32 i = 0; i < mSegments.size(); i++ )
- {
- length += mSegments[i].length();
- }
- return length;
- }
- void MeshRoad::deleteNode( U32 idx )
- {
- if ( mNodes.size() - 1 < idx )
- return;
- mNodes.erase(idx);
- _regenerate();
- setMaskBits( RegenMask | NodeMask );
- }
- U32 MeshRoad::_addNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal )
- {
- mNodes.increment();
- MeshRoadNode &node = mNodes.last();
- node.point = pos;
- node.width = width;
- node.depth = depth;
- node.normal = normal;
- setMaskBits( NodeMask | RegenMask );
- return mNodes.size() - 1;
- }
- U32 MeshRoad::_insertNode( const Point3F &pos, const F32 &width, const F32 &depth, const VectorF &normal, const U32 &idx )
- {
- U32 ret;
- MeshRoadNode *node;
- if ( idx == U32_MAX )
- {
- mNodes.increment();
- node = &mNodes.last();
- ret = mNodes.size() - 1;
- }
- else
- {
- mNodes.insert( idx );
- node = &mNodes[idx];
- ret = idx;
- }
- node->point = pos;
- node->depth = depth;
- node->width = width;
- node->normal = normal;
- return ret;
- }
- bool MeshRoad::collideRay( const Point3F &origin, const Point3F &direction, U32 *nodeIdx, Point3F *collisionPnt )
- {
- Point3F p0 = origin;
- Point3F p1 = origin + direction * 2000.0f;
- // If the line segment does not collide with the MeshRoad's world box,
- // it definitely does not collide with any part of the river.
- if ( !getWorldBox().collideLine( p0, p1 ) )
- return false;
- if ( mSlices.size() < 2 )
- return false;
- MathUtils::Quad quad;
- MathUtils::Ray ray;
- F32 t;
- // Check each road segment (formed by a pair of slices) for collision
- // with the line segment.
- for ( U32 i = 0; i < mSlices.size() - 1; i++ )
- {
- const MeshRoadSlice &slice0 = mSlices[i];
- const MeshRoadSlice &slice1 = mSlices[i+1];
- // For simplicities sake we will only test for collision between the
- // line segment and the Top face of the river segment.
- // Clockwise starting with the leftmost/closest point.
- quad.p00 = slice0.p0;
- quad.p01 = slice1.p0;
- quad.p11 = slice1.p2;
- quad.p10 = slice0.p2;
- ray.origin = origin;
- ray.direction = direction;
- if ( MathUtils::mRayQuadCollide( quad, ray, NULL, &t ) )
- {
- if ( nodeIdx )
- *nodeIdx = slice0.parentNodeIdx;
- if ( collisionPnt )
- *collisionPnt = ray.origin + ray.direction * t;
- return true;
- }
- }
- return false;
- }
- void MeshRoad::regenerate()
- {
- _regenerate();
- setMaskBits( RegenMask );
- }
- //-------------------------------------------------------------------------
- // Console Methods
- //-------------------------------------------------------------------------
- DefineEngineMethod( MeshRoad, setNodeDepth, void, ( S32 idx, F32 meters ),,
- "Intended as a helper to developers and editor scripts.\n"
- "Sets the depth in meters of a particular node."
- )
- {
- object->setNodeDepth( idx, meters );
- }
- DefineEngineMethod( MeshRoad, regenerate, void, (),,
- "Intended as a helper to developers and editor scripts.\n"
- "Force MeshRoad to recreate its geometry."
- )
- {
- object->regenerate();
- }
- DefineEngineMethod( MeshRoad, postApply, void, (),,
- "Intended as a helper to developers and editor scripts.\n"
- "Force trigger an inspectPostApply. This will transmit "
- "material and other fields ( not including nodes ) to client objects."
- )
- {
- object->inspectPostApply();
- }
- bool MeshRoad::buildPolyList_TopSurfaceOnly = false;
- bool MeshRoad::buildTopPolyList(PolyListContext plc, AbstractPolyList* polyList)
- {
- static Box3F box_prox; static SphereF ball_prox;
- buildPolyList_TopSurfaceOnly = true;
- bool result = buildPolyList(plc, polyList, box_prox, ball_prox);
- buildPolyList_TopSurfaceOnly = false;
- return result;
- }
|