CollisionModel_load.cpp 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. /*
  21. ===============================================================================
  22. Trace model vs. polygonal model collision detection.
  23. It is more important to minimize the number of collision polygons
  24. than it is to minimize the number of edges used for collision
  25. detection (total edges - internal edges).
  26. Stitching the world tends to minimize the number of edges used
  27. for collision detection (more internal edges). However stitching
  28. also results in more collision polygons which usually makes a
  29. stitched world slower.
  30. In an average map over 30% of all edges is internal.
  31. ===============================================================================
  32. */
  33. #pragma hdrstop
  34. #include "../idlib/precompiled.h"
  35. #include "CollisionModel_local.h"
  36. #define CMODEL_BINARYFILE_EXT "bcmodel"
  37. idCollisionModelManagerLocal collisionModelManagerLocal;
  38. idCollisionModelManager * collisionModelManager = &collisionModelManagerLocal;
  39. cm_windingList_t * cm_windingList;
  40. cm_windingList_t * cm_outList;
  41. cm_windingList_t * cm_tmpList;
  42. idHashIndex * cm_vertexHash;
  43. idHashIndex * cm_edgeHash;
  44. idBounds cm_modelBounds;
  45. int cm_vertexShift;
  46. idCVar preLoad_Collision( "preLoad_Collision", "1", CVAR_SYSTEM | CVAR_BOOL, "preload collision beginlevelload" );
  47. /*
  48. ===============================================================================
  49. Proc BSP tree for data pruning
  50. ===============================================================================
  51. */
  52. /*
  53. ================
  54. idCollisionModelManagerLocal::ParseProcNodes
  55. ================
  56. */
  57. void idCollisionModelManagerLocal::ParseProcNodes( idLexer *src ) {
  58. int i;
  59. src->ExpectTokenString( "{" );
  60. numProcNodes = src->ParseInt();
  61. if ( numProcNodes < 0 ) {
  62. src->Error( "ParseProcNodes: bad numProcNodes" );
  63. }
  64. procNodes = (cm_procNode_t *)Mem_ClearedAlloc( numProcNodes * sizeof( cm_procNode_t ), TAG_COLLISION );
  65. for ( i = 0; i < numProcNodes; i++ ) {
  66. cm_procNode_t *node;
  67. node = &procNodes[i];
  68. src->Parse1DMatrix( 4, node->plane.ToFloatPtr() );
  69. node->children[0] = src->ParseInt();
  70. node->children[1] = src->ParseInt();
  71. }
  72. src->ExpectTokenString( "}" );
  73. }
  74. /*
  75. ================
  76. idCollisionModelManagerLocal::LoadProcBSP
  77. FIXME: if the nodes would be at the start of the .proc file it would speed things up considerably
  78. ================
  79. */
  80. void idCollisionModelManagerLocal::LoadProcBSP( const char *name ) {
  81. idStr filename;
  82. idToken token;
  83. idLexer *src;
  84. // load it
  85. filename = name;
  86. filename.SetFileExtension( PROC_FILE_EXT );
  87. src = new (TAG_COLLISION) idLexer( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
  88. if ( !src->IsLoaded() ) {
  89. common->Warning( "idCollisionModelManagerLocal::LoadProcBSP: couldn't load %s", filename.c_str() );
  90. delete src;
  91. return;
  92. }
  93. if ( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) ) {
  94. common->Warning( "idCollisionModelManagerLocal::LoadProcBSP: bad id '%s' instead of '%s'", token.c_str(), PROC_FILE_ID );
  95. delete src;
  96. return;
  97. }
  98. // parse the file
  99. while ( 1 ) {
  100. if ( !src->ReadToken( &token ) ) {
  101. break;
  102. }
  103. if ( token == "model" ) {
  104. src->SkipBracedSection();
  105. continue;
  106. }
  107. if ( token == "shadowModel" ) {
  108. src->SkipBracedSection();
  109. continue;
  110. }
  111. if ( token == "interAreaPortals" ) {
  112. src->SkipBracedSection();
  113. continue;
  114. }
  115. if ( token == "nodes" ) {
  116. ParseProcNodes( src );
  117. break;
  118. }
  119. src->Error( "idCollisionModelManagerLocal::LoadProcBSP: bad token \"%s\"", token.c_str() );
  120. }
  121. delete src;
  122. }
  123. /*
  124. ===============================================================================
  125. Free map
  126. ===============================================================================
  127. */
  128. /*
  129. ================
  130. idCollisionModelManagerLocal::Clear
  131. ================
  132. */
  133. void idCollisionModelManagerLocal::Clear() {
  134. mapName.Clear();
  135. mapFileTime = 0;
  136. loaded = 0;
  137. checkCount = 0;
  138. maxModels = 0;
  139. numModels = 0;
  140. models = NULL;
  141. memset( trmPolygons, 0, sizeof( trmPolygons ) );
  142. trmBrushes[0] = NULL;
  143. trmMaterial = NULL;
  144. numProcNodes = 0;
  145. procNodes = NULL;
  146. getContacts = false;
  147. contacts = NULL;
  148. maxContacts = 0;
  149. numContacts = 0;
  150. }
  151. /*
  152. ================
  153. idCollisionModelManagerLocal::RemovePolygonReferences_r
  154. ================
  155. */
  156. void idCollisionModelManagerLocal::RemovePolygonReferences_r( cm_node_t *node, cm_polygon_t *p ) {
  157. cm_polygonRef_t *pref;
  158. while( node ) {
  159. for ( pref = node->polygons; pref; pref = pref->next ) {
  160. if ( pref->p == p ) {
  161. pref->p = NULL;
  162. // cannot return here because we can have links down the tree due to polygon merging
  163. //return;
  164. }
  165. }
  166. // if leaf node
  167. if ( node->planeType == -1 ) {
  168. break;
  169. }
  170. if ( p->bounds[0][node->planeType] > node->planeDist ) {
  171. node = node->children[0];
  172. }
  173. else if ( p->bounds[1][node->planeType] < node->planeDist ) {
  174. node = node->children[1];
  175. }
  176. else {
  177. RemovePolygonReferences_r( node->children[1], p );
  178. node = node->children[0];
  179. }
  180. }
  181. }
  182. /*
  183. ================
  184. idCollisionModelManagerLocal::RemoveBrushReferences_r
  185. ================
  186. */
  187. void idCollisionModelManagerLocal::RemoveBrushReferences_r( cm_node_t *node, cm_brush_t *b ) {
  188. cm_brushRef_t *bref;
  189. while( node ) {
  190. for ( bref = node->brushes; bref; bref = bref->next ) {
  191. if ( bref->b == b ) {
  192. bref->b = NULL;
  193. return;
  194. }
  195. }
  196. // if leaf node
  197. if ( node->planeType == -1 ) {
  198. break;
  199. }
  200. if ( b->bounds[0][node->planeType] > node->planeDist ) {
  201. node = node->children[0];
  202. }
  203. else if ( b->bounds[1][node->planeType] < node->planeDist ) {
  204. node = node->children[1];
  205. }
  206. else {
  207. RemoveBrushReferences_r( node->children[1], b );
  208. node = node->children[0];
  209. }
  210. }
  211. }
  212. /*
  213. ================
  214. idCollisionModelManagerLocal::FreeNode
  215. ================
  216. */
  217. void idCollisionModelManagerLocal::FreeNode( cm_node_t *node ) {
  218. // don't free the node here
  219. // the nodes are allocated in blocks which are freed when the model is freed
  220. }
  221. /*
  222. ================
  223. idCollisionModelManagerLocal::FreePolygonReference
  224. ================
  225. */
  226. void idCollisionModelManagerLocal::FreePolygonReference( cm_polygonRef_t *pref ) {
  227. // don't free the polygon reference here
  228. // the polygon references are allocated in blocks which are freed when the model is freed
  229. }
  230. /*
  231. ================
  232. idCollisionModelManagerLocal::FreeBrushReference
  233. ================
  234. */
  235. void idCollisionModelManagerLocal::FreeBrushReference( cm_brushRef_t *bref ) {
  236. // don't free the brush reference here
  237. // the brush references are allocated in blocks which are freed when the model is freed
  238. }
  239. /*
  240. ================
  241. idCollisionModelManagerLocal::FreePolygon
  242. ================
  243. */
  244. void idCollisionModelManagerLocal::FreePolygon( cm_model_t *model, cm_polygon_t *poly ) {
  245. model->numPolygons--;
  246. model->polygonMemory -= sizeof( cm_polygon_t ) + ( poly->numEdges - 1 ) * sizeof( poly->edges[0] );
  247. if ( model->polygonBlock == NULL ) {
  248. Mem_Free( poly );
  249. }
  250. }
  251. /*
  252. ================
  253. idCollisionModelManagerLocal::FreeBrush
  254. ================
  255. */
  256. void idCollisionModelManagerLocal::FreeBrush( cm_model_t *model, cm_brush_t *brush ) {
  257. model->numBrushes--;
  258. model->brushMemory -= sizeof( cm_brush_t ) + ( brush->numPlanes - 1 ) * sizeof( brush->planes[0] );
  259. if ( model->brushBlock == NULL ) {
  260. Mem_Free( brush );
  261. }
  262. }
  263. /*
  264. ================
  265. idCollisionModelManagerLocal::FreeTree_r
  266. ================
  267. */
  268. void idCollisionModelManagerLocal::FreeTree_r( cm_model_t *model, cm_node_t *headNode, cm_node_t *node ) {
  269. cm_polygonRef_t *pref;
  270. cm_polygon_t *p;
  271. cm_brushRef_t *bref;
  272. cm_brush_t *b;
  273. // free all polygons at this node
  274. for ( pref = node->polygons; pref; pref = node->polygons ) {
  275. p = pref->p;
  276. if ( p ) {
  277. // remove all other references to this polygon
  278. RemovePolygonReferences_r( headNode, p );
  279. FreePolygon( model, p );
  280. }
  281. node->polygons = pref->next;
  282. FreePolygonReference( pref );
  283. }
  284. // free all brushes at this node
  285. for ( bref = node->brushes; bref; bref = node->brushes ) {
  286. b = bref->b;
  287. if ( b ) {
  288. // remove all other references to this brush
  289. RemoveBrushReferences_r( headNode, b );
  290. FreeBrush( model, b );
  291. }
  292. node->brushes = bref->next;
  293. FreeBrushReference( bref );
  294. }
  295. // recurse down the tree
  296. if ( node->planeType != -1 ) {
  297. FreeTree_r( model, headNode, node->children[0] );
  298. node->children[0] = NULL;
  299. FreeTree_r( model, headNode, node->children[1] );
  300. node->children[1] = NULL;
  301. }
  302. FreeNode( node );
  303. }
  304. /*
  305. ================
  306. idCollisionModelManagerLocal::FreeModel
  307. ================
  308. */
  309. void idCollisionModelManagerLocal::FreeModel( cm_model_t *model ) {
  310. cm_polygonRefBlock_t *polygonRefBlock, *nextPolygonRefBlock;
  311. cm_brushRefBlock_t *brushRefBlock, *nextBrushRefBlock;
  312. cm_nodeBlock_t *nodeBlock, *nextNodeBlock;
  313. // free the tree structure
  314. if ( model->node ) {
  315. FreeTree_r( model, model->node, model->node );
  316. }
  317. // free blocks with polygon references
  318. for ( polygonRefBlock = model->polygonRefBlocks; polygonRefBlock; polygonRefBlock = nextPolygonRefBlock ) {
  319. nextPolygonRefBlock = polygonRefBlock->next;
  320. Mem_Free( polygonRefBlock );
  321. }
  322. // free blocks with brush references
  323. for ( brushRefBlock = model->brushRefBlocks; brushRefBlock; brushRefBlock = nextBrushRefBlock ) {
  324. nextBrushRefBlock = brushRefBlock->next;
  325. Mem_Free( brushRefBlock );
  326. }
  327. // free blocks with nodes
  328. for ( nodeBlock = model->nodeBlocks; nodeBlock; nodeBlock = nextNodeBlock ) {
  329. nextNodeBlock = nodeBlock->next;
  330. Mem_Free( nodeBlock );
  331. }
  332. // free block allocated polygons
  333. Mem_Free( model->polygonBlock );
  334. // free block allocated brushes
  335. Mem_Free( model->brushBlock );
  336. // free edges
  337. Mem_Free( model->edges );
  338. // free vertices
  339. Mem_Free( model->vertices );
  340. // free the model
  341. delete model;
  342. }
  343. /*
  344. ================
  345. idCollisionModelManagerLocal::FreeMap
  346. ================
  347. */
  348. void idCollisionModelManagerLocal::FreeMap() {
  349. int i;
  350. if ( !loaded ) {
  351. Clear();
  352. return;
  353. }
  354. for ( i = 0; i < maxModels; i++ ) {
  355. if ( !models[i] ) {
  356. continue;
  357. }
  358. FreeModel( models[i] );
  359. }
  360. FreeTrmModelStructure();
  361. Mem_Free( models );
  362. Clear();
  363. ShutdownHash();
  364. }
  365. /*
  366. ================
  367. idCollisionModelManagerLocal::FreeTrmModelStructure
  368. ================
  369. */
  370. void idCollisionModelManagerLocal::FreeTrmModelStructure() {
  371. int i;
  372. assert( models );
  373. if ( !models[MAX_SUBMODELS] ) {
  374. return;
  375. }
  376. for ( i = 0; i < MAX_TRACEMODEL_POLYS; i++ ) {
  377. FreePolygon( models[MAX_SUBMODELS], trmPolygons[i]->p );
  378. }
  379. FreeBrush( models[MAX_SUBMODELS], trmBrushes[0]->b );
  380. models[MAX_SUBMODELS]->node->polygons = NULL;
  381. models[MAX_SUBMODELS]->node->brushes = NULL;
  382. FreeModel( models[MAX_SUBMODELS] );
  383. }
  384. /*
  385. ===============================================================================
  386. Edge normals
  387. ===============================================================================
  388. */
  389. /*
  390. ================
  391. idCollisionModelManagerLocal::CalculateEdgeNormals
  392. ================
  393. */
  394. #define SHARP_EDGE_DOT -0.7f
  395. void idCollisionModelManagerLocal::CalculateEdgeNormals( cm_model_t *model, cm_node_t *node ) {
  396. cm_polygonRef_t *pref;
  397. cm_polygon_t *p;
  398. cm_edge_t *edge;
  399. float dot, s;
  400. int i, edgeNum;
  401. idVec3 dir;
  402. while( 1 ) {
  403. for ( pref = node->polygons; pref; pref = pref->next ) {
  404. p = pref->p;
  405. // if we checked this polygon already
  406. if ( p->checkcount == checkCount ) {
  407. continue;
  408. }
  409. p->checkcount = checkCount;
  410. for ( i = 0; i < p->numEdges; i++ ) {
  411. edgeNum = p->edges[i];
  412. edge = model->edges + abs( edgeNum );
  413. if ( edge->normal[0] == 0.0f && edge->normal[1] == 0.0f && edge->normal[2] == 0.0f ) {
  414. // if the edge is only used by this polygon
  415. if ( edge->numUsers == 1 ) {
  416. dir = model->vertices[ edge->vertexNum[edgeNum < 0]].p - model->vertices[ edge->vertexNum[edgeNum > 0]].p;
  417. edge->normal = p->plane.Normal().Cross( dir );
  418. edge->normal.Normalize();
  419. } else {
  420. // the edge is used by more than one polygon
  421. edge->normal = p->plane.Normal();
  422. }
  423. } else {
  424. dot = edge->normal * p->plane.Normal();
  425. // if the two planes make a very sharp edge
  426. if ( dot < SHARP_EDGE_DOT ) {
  427. // max length normal pointing outside both polygons
  428. dir = model->vertices[ edge->vertexNum[edgeNum > 0]].p - model->vertices[ edge->vertexNum[edgeNum < 0]].p;
  429. edge->normal = edge->normal.Cross( dir ) + p->plane.Normal().Cross( -dir );
  430. edge->normal *= ( 0.5f / ( 0.5f + 0.5f * SHARP_EDGE_DOT ) ) / edge->normal.Length();
  431. model->numSharpEdges++;
  432. } else {
  433. s = 0.5f / ( 0.5f + 0.5f * dot );
  434. edge->normal = s * ( edge->normal + p->plane.Normal() );
  435. }
  436. }
  437. }
  438. }
  439. // if leaf node
  440. if ( node->planeType == -1 ) {
  441. break;
  442. }
  443. CalculateEdgeNormals( model, node->children[1] );
  444. node = node->children[0];
  445. }
  446. }
  447. /*
  448. ===============================================================================
  449. Trace model to general collision model
  450. ===============================================================================
  451. */
  452. /*
  453. ================
  454. idCollisionModelManagerLocal::AllocModel
  455. ================
  456. */
  457. cm_model_t *idCollisionModelManagerLocal::AllocModel() {
  458. cm_model_t *model;
  459. model = new (TAG_COLLISION) cm_model_t;
  460. model->contents = 0;
  461. model->isConvex = false;
  462. model->maxVertices = 0;
  463. model->numVertices = 0;
  464. model->vertices = NULL;
  465. model->maxEdges = 0;
  466. model->numEdges = 0;
  467. model->edges= NULL;
  468. model->node = NULL;
  469. model->nodeBlocks = NULL;
  470. model->polygonRefBlocks = NULL;
  471. model->brushRefBlocks = NULL;
  472. model->polygonBlock = NULL;
  473. model->brushBlock = NULL;
  474. model->numPolygons = model->polygonMemory =
  475. model->numBrushes = model->brushMemory =
  476. model->numNodes = model->numBrushRefs =
  477. model->numPolygonRefs = model->numInternalEdges =
  478. model->numSharpEdges = model->numRemovedPolys =
  479. model->numMergedPolys = model->usedMemory = 0;
  480. return model;
  481. }
  482. /*
  483. ================
  484. idCollisionModelManagerLocal::AllocNode
  485. ================
  486. */
  487. cm_node_t *idCollisionModelManagerLocal::AllocNode( cm_model_t *model, int blockSize ) {
  488. int i;
  489. cm_node_t *node;
  490. cm_nodeBlock_t *nodeBlock;
  491. if ( !model->nodeBlocks || !model->nodeBlocks->nextNode ) {
  492. nodeBlock = (cm_nodeBlock_t *) Mem_ClearedAlloc( sizeof( cm_nodeBlock_t ) + blockSize * sizeof(cm_node_t), TAG_COLLISION );
  493. nodeBlock->nextNode = (cm_node_t *) ( ( (byte *) nodeBlock ) + sizeof( cm_nodeBlock_t ) );
  494. nodeBlock->next = model->nodeBlocks;
  495. model->nodeBlocks = nodeBlock;
  496. node = nodeBlock->nextNode;
  497. for ( i = 0; i < blockSize - 1; i++ ) {
  498. node->parent = node + 1;
  499. node = node->parent;
  500. }
  501. node->parent = NULL;
  502. }
  503. node = model->nodeBlocks->nextNode;
  504. model->nodeBlocks->nextNode = node->parent;
  505. node->parent = NULL;
  506. return node;
  507. }
  508. /*
  509. ================
  510. idCollisionModelManagerLocal::AllocPolygonReference
  511. ================
  512. */
  513. cm_polygonRef_t *idCollisionModelManagerLocal::AllocPolygonReference( cm_model_t *model, int blockSize ) {
  514. int i;
  515. cm_polygonRef_t *pref;
  516. cm_polygonRefBlock_t *prefBlock;
  517. if ( !model->polygonRefBlocks || !model->polygonRefBlocks->nextRef ) {
  518. prefBlock = (cm_polygonRefBlock_t *) Mem_ClearedAlloc( sizeof( cm_polygonRefBlock_t ) + blockSize * sizeof(cm_polygonRef_t), TAG_COLLISION );
  519. prefBlock->nextRef = (cm_polygonRef_t *) ( ( (byte *) prefBlock ) + sizeof( cm_polygonRefBlock_t ) );
  520. prefBlock->next = model->polygonRefBlocks;
  521. model->polygonRefBlocks = prefBlock;
  522. pref = prefBlock->nextRef;
  523. for ( i = 0; i < blockSize - 1; i++ ) {
  524. pref->next = pref + 1;
  525. pref = pref->next;
  526. }
  527. pref->next = NULL;
  528. }
  529. pref = model->polygonRefBlocks->nextRef;
  530. model->polygonRefBlocks->nextRef = pref->next;
  531. return pref;
  532. }
  533. /*
  534. ================
  535. idCollisionModelManagerLocal::AllocBrushReference
  536. ================
  537. */
  538. cm_brushRef_t *idCollisionModelManagerLocal::AllocBrushReference( cm_model_t *model, int blockSize ) {
  539. int i;
  540. cm_brushRef_t *bref;
  541. cm_brushRefBlock_t *brefBlock;
  542. if ( !model->brushRefBlocks || !model->brushRefBlocks->nextRef ) {
  543. brefBlock = (cm_brushRefBlock_t *) Mem_ClearedAlloc( sizeof(cm_brushRefBlock_t) + blockSize * sizeof(cm_brushRef_t), TAG_COLLISION );
  544. brefBlock->nextRef = (cm_brushRef_t *) ( ( (byte *) brefBlock ) + sizeof(cm_brushRefBlock_t) );
  545. brefBlock->next = model->brushRefBlocks;
  546. model->brushRefBlocks = brefBlock;
  547. bref = brefBlock->nextRef;
  548. for ( i = 0; i < blockSize - 1; i++ ) {
  549. bref->next = bref + 1;
  550. bref = bref->next;
  551. }
  552. bref->next = NULL;
  553. }
  554. bref = model->brushRefBlocks->nextRef;
  555. model->brushRefBlocks->nextRef = bref->next;
  556. return bref;
  557. }
  558. /*
  559. ================
  560. idCollisionModelManagerLocal::AllocPolygon
  561. ================
  562. */
  563. cm_polygon_t *idCollisionModelManagerLocal::AllocPolygon( cm_model_t *model, int numEdges ) {
  564. cm_polygon_t *poly;
  565. int size;
  566. size = sizeof( cm_polygon_t ) + ( numEdges - 1 ) * sizeof( poly->edges[0] );
  567. model->numPolygons++;
  568. model->polygonMemory += size;
  569. if ( model->polygonBlock && model->polygonBlock->bytesRemaining >= size ) {
  570. poly = (cm_polygon_t *) model->polygonBlock->next;
  571. model->polygonBlock->next += size;
  572. model->polygonBlock->bytesRemaining -= size;
  573. } else {
  574. poly = (cm_polygon_t *) Mem_ClearedAlloc( size, TAG_COLLISION );
  575. }
  576. return poly;
  577. }
  578. /*
  579. ================
  580. idCollisionModelManagerLocal::AllocBrush
  581. ================
  582. */
  583. cm_brush_t *idCollisionModelManagerLocal::AllocBrush( cm_model_t *model, int numPlanes ) {
  584. cm_brush_t *brush;
  585. int size;
  586. size = sizeof( cm_brush_t ) + ( numPlanes - 1 ) * sizeof( brush->planes[0] );
  587. model->numBrushes++;
  588. model->brushMemory += size;
  589. if ( model->brushBlock && model->brushBlock->bytesRemaining >= size ) {
  590. brush = (cm_brush_t *) model->brushBlock->next;
  591. model->brushBlock->next += size;
  592. model->brushBlock->bytesRemaining -= size;
  593. } else {
  594. brush = (cm_brush_t *) Mem_ClearedAlloc( size, TAG_COLLISION );
  595. }
  596. return brush;
  597. }
  598. /*
  599. ================
  600. idCollisionModelManagerLocal::AddPolygonToNode
  601. ================
  602. */
  603. void idCollisionModelManagerLocal::AddPolygonToNode( cm_model_t *model, cm_node_t *node, cm_polygon_t *p ) {
  604. cm_polygonRef_t *pref;
  605. pref = AllocPolygonReference( model, model->numPolygonRefs < REFERENCE_BLOCK_SIZE_SMALL ? REFERENCE_BLOCK_SIZE_SMALL : REFERENCE_BLOCK_SIZE_LARGE );
  606. pref->p = p;
  607. pref->next = node->polygons;
  608. node->polygons = pref;
  609. model->numPolygonRefs++;
  610. }
  611. /*
  612. ================
  613. idCollisionModelManagerLocal::AddBrushToNode
  614. ================
  615. */
  616. void idCollisionModelManagerLocal::AddBrushToNode( cm_model_t *model, cm_node_t *node, cm_brush_t *b ) {
  617. cm_brushRef_t *bref;
  618. bref = AllocBrushReference( model, model->numBrushRefs < REFERENCE_BLOCK_SIZE_SMALL ? REFERENCE_BLOCK_SIZE_SMALL : REFERENCE_BLOCK_SIZE_LARGE );
  619. bref->b = b;
  620. bref->next = node->brushes;
  621. node->brushes = bref;
  622. model->numBrushRefs++;
  623. }
  624. /*
  625. ================
  626. idCollisionModelManagerLocal::SetupTrmModelStructure
  627. ================
  628. */
  629. void idCollisionModelManagerLocal::SetupTrmModelStructure() {
  630. int i;
  631. cm_node_t *node;
  632. cm_model_t *model;
  633. // setup model
  634. model = AllocModel();
  635. assert( models );
  636. models[MAX_SUBMODELS] = model;
  637. // create node to hold the collision data
  638. node = (cm_node_t *) AllocNode( model, 1 );
  639. node->planeType = -1;
  640. model->node = node;
  641. // allocate vertex and edge arrays
  642. model->numVertices = 0;
  643. model->maxVertices = MAX_TRACEMODEL_VERTS;
  644. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->maxVertices * sizeof(cm_vertex_t), TAG_COLLISION );
  645. model->numEdges = 0;
  646. model->maxEdges = MAX_TRACEMODEL_EDGES+1;
  647. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->maxEdges * sizeof(cm_edge_t), TAG_COLLISION );
  648. // create a material for the trace model polygons
  649. trmMaterial = declManager->FindMaterial( "_tracemodel", false );
  650. if ( !trmMaterial ) {
  651. common->FatalError( "_tracemodel material not found" );
  652. }
  653. // allocate polygons
  654. for ( i = 0; i < MAX_TRACEMODEL_POLYS; i++ ) {
  655. trmPolygons[i] = AllocPolygonReference( model, MAX_TRACEMODEL_POLYS );
  656. trmPolygons[i]->p = AllocPolygon( model, MAX_TRACEMODEL_POLYEDGES );
  657. trmPolygons[i]->p->bounds.Clear();
  658. trmPolygons[i]->p->plane.Zero();
  659. trmPolygons[i]->p->checkcount = 0;
  660. trmPolygons[i]->p->contents = -1; // all contents
  661. trmPolygons[i]->p->material = trmMaterial;
  662. trmPolygons[i]->p->numEdges = 0;
  663. }
  664. // allocate brush for position test
  665. trmBrushes[0] = AllocBrushReference( model, 1 );
  666. trmBrushes[0]->b = AllocBrush( model, MAX_TRACEMODEL_POLYS );
  667. trmBrushes[0]->b->primitiveNum = 0;
  668. trmBrushes[0]->b->bounds.Clear();
  669. trmBrushes[0]->b->checkcount = 0;
  670. trmBrushes[0]->b->contents = -1; // all contents
  671. trmBrushes[ 0 ]->b->material = trmMaterial;
  672. trmBrushes[0]->b->numPlanes = 0;
  673. }
  674. /*
  675. ================
  676. idCollisionModelManagerLocal::SetupTrmModel
  677. Trace models (item boxes, etc) are converted to collision models on the fly, using the last model slot
  678. as a reusable temporary buffer
  679. ================
  680. */
  681. cmHandle_t idCollisionModelManagerLocal::SetupTrmModel( const idTraceModel &trm, const idMaterial *material ) {
  682. int i, j;
  683. cm_vertex_t *vertex;
  684. cm_edge_t *edge;
  685. cm_polygon_t *poly;
  686. cm_model_t *model;
  687. const traceModelVert_t *trmVert;
  688. const traceModelEdge_t *trmEdge;
  689. const traceModelPoly_t *trmPoly;
  690. assert( models );
  691. if ( material == NULL ) {
  692. material = trmMaterial;
  693. }
  694. model = models[MAX_SUBMODELS];
  695. model->node->brushes = NULL;
  696. model->node->polygons = NULL;
  697. // if not a valid trace model
  698. if ( trm.type == TRM_INVALID || !trm.numPolys ) {
  699. return TRACE_MODEL_HANDLE;
  700. }
  701. // vertices
  702. model->numVertices = trm.numVerts;
  703. vertex = model->vertices;
  704. trmVert = trm.verts;
  705. for ( i = 0; i < trm.numVerts; i++, vertex++, trmVert++ ) {
  706. vertex->p = *trmVert;
  707. vertex->sideSet = 0;
  708. }
  709. // edges
  710. model->numEdges = trm.numEdges;
  711. edge = model->edges + 1;
  712. trmEdge = trm.edges + 1;
  713. for ( i = 0; i < trm.numEdges; i++, edge++, trmEdge++ ) {
  714. edge->vertexNum[0] = trmEdge->v[0];
  715. edge->vertexNum[1] = trmEdge->v[1];
  716. edge->normal = trmEdge->normal;
  717. edge->internal = false;
  718. edge->sideSet = 0;
  719. }
  720. // polygons
  721. model->numPolygons = trm.numPolys;
  722. trmPoly = trm.polys;
  723. for ( i = 0; i < trm.numPolys; i++, trmPoly++ ) {
  724. poly = trmPolygons[i]->p;
  725. poly->numEdges = trmPoly->numEdges;
  726. for ( j = 0; j < trmPoly->numEdges; j++ ) {
  727. poly->edges[j] = trmPoly->edges[j];
  728. }
  729. poly->plane.SetNormal( trmPoly->normal );
  730. poly->plane.SetDist( trmPoly->dist );
  731. poly->bounds = trmPoly->bounds;
  732. poly->material = material;
  733. // link polygon at node
  734. trmPolygons[i]->next = model->node->polygons;
  735. model->node->polygons = trmPolygons[i];
  736. }
  737. // if the trace model is convex
  738. if ( trm.isConvex ) {
  739. // setup brush for position test
  740. trmBrushes[0]->b->numPlanes = trm.numPolys;
  741. for ( i = 0; i < trm.numPolys; i++ ) {
  742. trmBrushes[0]->b->planes[i] = trmPolygons[i]->p->plane;
  743. }
  744. trmBrushes[0]->b->bounds = trm.bounds;
  745. // link brush at node
  746. trmBrushes[0]->next = model->node->brushes;
  747. trmBrushes[ 0 ]->b->material = material;
  748. model->node->brushes = trmBrushes[0];
  749. }
  750. // model bounds
  751. model->bounds = trm.bounds;
  752. // convex
  753. model->isConvex = trm.isConvex;
  754. return TRACE_MODEL_HANDLE;
  755. }
  756. /*
  757. ===============================================================================
  758. Optimisation, removal of polygons contained within brushes or solid
  759. ===============================================================================
  760. */
  761. /*
  762. ============
  763. idCollisionModelManagerLocal::R_ChoppedAwayByProcBSP
  764. ============
  765. */
  766. int idCollisionModelManagerLocal::R_ChoppedAwayByProcBSP( int nodeNum, idFixedWinding *w, const idVec3 &normal, const idVec3 &origin, const float radius ) {
  767. int res;
  768. idFixedWinding back;
  769. cm_procNode_t *node;
  770. float dist;
  771. do {
  772. node = procNodes + nodeNum;
  773. dist = node->plane.Normal() * origin + node->plane[3];
  774. if ( dist > radius ) {
  775. res = SIDE_FRONT;
  776. }
  777. else if ( dist < -radius ) {
  778. res = SIDE_BACK;
  779. }
  780. else {
  781. res = w->Split( &back, node->plane, CHOP_EPSILON );
  782. }
  783. if ( res == SIDE_FRONT ) {
  784. nodeNum = node->children[0];
  785. }
  786. else if ( res == SIDE_BACK ) {
  787. nodeNum = node->children[1];
  788. }
  789. else if ( res == SIDE_ON ) {
  790. // continue with the side the winding faces
  791. if ( node->plane.Normal() * normal > 0.0f ) {
  792. nodeNum = node->children[0];
  793. }
  794. else {
  795. nodeNum = node->children[1];
  796. }
  797. }
  798. else {
  799. // if either node is not solid
  800. if ( node->children[0] < 0 || node->children[1] < 0 ) {
  801. return false;
  802. }
  803. // only recurse if the node is not solid
  804. if ( node->children[1] > 0 ) {
  805. if ( !R_ChoppedAwayByProcBSP( node->children[1], &back, normal, origin, radius ) ) {
  806. return false;
  807. }
  808. }
  809. nodeNum = node->children[0];
  810. }
  811. } while ( nodeNum > 0 );
  812. if ( nodeNum < 0 ) {
  813. return false;
  814. }
  815. return true;
  816. }
  817. /*
  818. ============
  819. idCollisionModelManagerLocal::ChoppedAwayByProcBSP
  820. ============
  821. */
  822. int idCollisionModelManagerLocal::ChoppedAwayByProcBSP( const idFixedWinding &w, const idPlane &plane, int contents ) {
  823. idFixedWinding neww;
  824. idBounds bounds;
  825. float radius;
  826. idVec3 origin;
  827. // if the .proc file has no BSP tree
  828. if ( procNodes == NULL ) {
  829. return false;
  830. }
  831. // don't chop if the polygon is not solid
  832. if ( !(contents & CONTENTS_SOLID) ) {
  833. return false;
  834. }
  835. // make a local copy of the winding
  836. neww = w;
  837. neww.GetBounds( bounds );
  838. origin = (bounds[1] - bounds[0]) * 0.5f;
  839. radius = origin.Length() + CHOP_EPSILON;
  840. origin = bounds[0] + origin;
  841. //
  842. return R_ChoppedAwayByProcBSP( 0, &neww, plane.Normal(), origin, radius );
  843. }
  844. /*
  845. =============
  846. idCollisionModelManagerLocal::ChopWindingWithBrush
  847. returns the least number of winding fragments outside the brush
  848. =============
  849. */
  850. void idCollisionModelManagerLocal::ChopWindingListWithBrush( cm_windingList_t *list, cm_brush_t *b ) {
  851. int i, k, res, startPlane, planeNum, bestNumWindings;
  852. idFixedWinding back, front;
  853. idPlane plane;
  854. bool chopped;
  855. int sidedness[MAX_POINTS_ON_WINDING];
  856. float dist;
  857. if ( b->numPlanes > MAX_POINTS_ON_WINDING ) {
  858. return;
  859. }
  860. // get sidedness for the list of windings
  861. for ( i = 0; i < b->numPlanes; i++ ) {
  862. plane = -b->planes[i];
  863. dist = plane.Distance( list->origin );
  864. if ( dist > list->radius ) {
  865. sidedness[i] = SIDE_FRONT;
  866. }
  867. else if ( dist < -list->radius ) {
  868. sidedness[i] = SIDE_BACK;
  869. }
  870. else {
  871. sidedness[i] = list->bounds.PlaneSide( plane );
  872. if ( sidedness[i] == PLANESIDE_FRONT ) {
  873. sidedness[i] = SIDE_FRONT;
  874. }
  875. else if ( sidedness[i] == PLANESIDE_BACK ) {
  876. sidedness[i] = SIDE_BACK;
  877. }
  878. else {
  879. sidedness[i] = SIDE_CROSS;
  880. }
  881. }
  882. }
  883. cm_outList->numWindings = 0;
  884. for ( k = 0; k < list->numWindings; k++ ) {
  885. //
  886. startPlane = 0;
  887. bestNumWindings = 1 + b->numPlanes;
  888. chopped = false;
  889. do {
  890. front = list->w[k];
  891. cm_tmpList->numWindings = 0;
  892. for ( planeNum = startPlane, i = 0; i < b->numPlanes; i++, planeNum++ ) {
  893. if ( planeNum >= b->numPlanes ) {
  894. planeNum = 0;
  895. }
  896. res = sidedness[planeNum];
  897. if ( res == SIDE_CROSS ) {
  898. plane = -b->planes[planeNum];
  899. res = front.Split( &back, plane, CHOP_EPSILON );
  900. }
  901. // NOTE: disabling this can create gaps at places where Z-fighting occurs
  902. // Z-fighting should not occur but what if there is a decal brush side
  903. // with exactly the same size as another brush side ?
  904. // only leave windings on a brush if the winding plane and brush side plane face the same direction
  905. if ( res == SIDE_ON && list->primitiveNum >= 0 && (list->normal * b->planes[planeNum].Normal()) > 0 ) {
  906. // return because all windings in the list will be on this brush side plane
  907. return;
  908. }
  909. if ( res == SIDE_BACK ) {
  910. if ( cm_outList->numWindings >= MAX_WINDING_LIST ) {
  911. common->Warning( "idCollisionModelManagerLocal::ChopWindingWithBrush: primitive %d more than %d windings", list->primitiveNum, MAX_WINDING_LIST );
  912. return;
  913. }
  914. // winding and brush didn't intersect, store the original winding
  915. cm_outList->w[cm_outList->numWindings] = list->w[k];
  916. cm_outList->numWindings++;
  917. chopped = false;
  918. break;
  919. }
  920. if ( res == SIDE_CROSS ) {
  921. if ( cm_tmpList->numWindings >= MAX_WINDING_LIST ) {
  922. common->Warning( "idCollisionModelManagerLocal::ChopWindingWithBrush: primitive %d more than %d windings", list->primitiveNum, MAX_WINDING_LIST );
  923. return;
  924. }
  925. // store the front winding in the temporary list
  926. cm_tmpList->w[cm_tmpList->numWindings] = back;
  927. cm_tmpList->numWindings++;
  928. chopped = true;
  929. }
  930. // if already found a start plane which generates less fragments
  931. if ( cm_tmpList->numWindings >= bestNumWindings ) {
  932. break;
  933. }
  934. }
  935. // find the best start plane to get the least number of fragments outside the brush
  936. if ( cm_tmpList->numWindings < bestNumWindings ) {
  937. bestNumWindings = cm_tmpList->numWindings;
  938. // store windings from temporary list in the out list
  939. for ( i = 0; i < cm_tmpList->numWindings; i++ ) {
  940. if ( cm_outList->numWindings + i >= MAX_WINDING_LIST ) {
  941. common->Warning( "idCollisionModelManagerLocal::ChopWindingWithBrush: primitive %d more than %d windings", list->primitiveNum, MAX_WINDING_LIST );
  942. return;
  943. }
  944. cm_outList->w[cm_outList->numWindings+i] = cm_tmpList->w[i];
  945. }
  946. // if only one winding left then we can't do any better
  947. if ( bestNumWindings == 1 ) {
  948. break;
  949. }
  950. }
  951. // try the next start plane
  952. startPlane++;
  953. } while ( chopped && startPlane < b->numPlanes );
  954. //
  955. if ( chopped ) {
  956. cm_outList->numWindings += bestNumWindings;
  957. }
  958. }
  959. for ( k = 0; k < cm_outList->numWindings; k++ ) {
  960. list->w[k] = cm_outList->w[k];
  961. }
  962. list->numWindings = cm_outList->numWindings;
  963. }
  964. /*
  965. ============
  966. idCollisionModelManagerLocal::R_ChopWindingListWithTreeBrushes
  967. ============
  968. */
  969. void idCollisionModelManagerLocal::R_ChopWindingListWithTreeBrushes( cm_windingList_t *list, cm_node_t *node ) {
  970. int i;
  971. cm_brushRef_t *bref;
  972. cm_brush_t *b;
  973. while( 1 ) {
  974. for ( bref = node->brushes; bref; bref = bref->next ) {
  975. b = bref->b;
  976. // if we checked this brush already
  977. if ( b->checkcount == checkCount ) {
  978. continue;
  979. }
  980. b->checkcount = checkCount;
  981. // if the windings in the list originate from this brush
  982. if ( b->primitiveNum == list->primitiveNum ) {
  983. continue;
  984. }
  985. // if brush has a different contents
  986. if ( b->contents != list->contents ) {
  987. continue;
  988. }
  989. // brush bounds and winding list bounds should overlap
  990. for ( i = 0; i < 3; i++ ) {
  991. if ( list->bounds[0][i] > b->bounds[1][i] ) {
  992. break;
  993. }
  994. if ( list->bounds[1][i] < b->bounds[0][i] ) {
  995. break;
  996. }
  997. }
  998. if ( i < 3 ) {
  999. continue;
  1000. }
  1001. // chop windings in the list with brush
  1002. ChopWindingListWithBrush( list, b );
  1003. // if all windings are chopped away we're done
  1004. if ( !list->numWindings ) {
  1005. return;
  1006. }
  1007. }
  1008. // if leaf node
  1009. if ( node->planeType == -1 ) {
  1010. break;
  1011. }
  1012. if ( list->bounds[0][node->planeType] > node->planeDist ) {
  1013. node = node->children[0];
  1014. }
  1015. else if ( list->bounds[1][node->planeType] < node->planeDist ) {
  1016. node = node->children[1];
  1017. }
  1018. else {
  1019. R_ChopWindingListWithTreeBrushes( list, node->children[1] );
  1020. if ( !list->numWindings ) {
  1021. return;
  1022. }
  1023. node = node->children[0];
  1024. }
  1025. }
  1026. }
  1027. /*
  1028. ============
  1029. idCollisionModelManagerLocal::WindingOutsideBrushes
  1030. Returns one winding which is not fully contained in brushes.
  1031. We always favor less polygons over a stitched world.
  1032. If the winding is partly contained and the contained pieces can be chopped off
  1033. without creating multiple winding fragments then the chopped winding is returned.
  1034. ============
  1035. */
  1036. idFixedWinding *idCollisionModelManagerLocal::WindingOutsideBrushes( idFixedWinding *w, const idPlane &plane, int contents, int primitiveNum, cm_node_t *headNode ) {
  1037. int i, windingLeft;
  1038. cm_windingList->bounds.Clear();
  1039. for ( i = 0; i < w->GetNumPoints(); i++ ) {
  1040. cm_windingList->bounds.AddPoint( (*w)[i].ToVec3() );
  1041. }
  1042. cm_windingList->origin = (cm_windingList->bounds[1] - cm_windingList->bounds[0]) * 0.5;
  1043. cm_windingList->radius = cm_windingList->origin.Length() + CHOP_EPSILON;
  1044. cm_windingList->origin = cm_windingList->bounds[0] + cm_windingList->origin;
  1045. cm_windingList->bounds[0] -= idVec3( CHOP_EPSILON, CHOP_EPSILON, CHOP_EPSILON );
  1046. cm_windingList->bounds[1] += idVec3( CHOP_EPSILON, CHOP_EPSILON, CHOP_EPSILON );
  1047. cm_windingList->w[0] = *w;
  1048. cm_windingList->numWindings = 1;
  1049. cm_windingList->normal = plane.Normal();
  1050. cm_windingList->contents = contents;
  1051. cm_windingList->primitiveNum = primitiveNum;
  1052. //
  1053. checkCount++;
  1054. R_ChopWindingListWithTreeBrushes( cm_windingList, headNode );
  1055. //
  1056. if ( !cm_windingList->numWindings ) {
  1057. return NULL;
  1058. }
  1059. if ( cm_windingList->numWindings == 1 ) {
  1060. return &cm_windingList->w[0];
  1061. }
  1062. // if not the world model
  1063. if ( numModels != 0 ) {
  1064. return w;
  1065. }
  1066. // check if winding fragments would be chopped away by the proc BSP tree
  1067. windingLeft = -1;
  1068. for ( i = 0; i < cm_windingList->numWindings; i++ ) {
  1069. if ( !ChoppedAwayByProcBSP( cm_windingList->w[i], plane, contents ) ) {
  1070. if ( windingLeft >= 0 ) {
  1071. return w;
  1072. }
  1073. windingLeft = i;
  1074. }
  1075. }
  1076. if ( windingLeft >= 0 ) {
  1077. return &cm_windingList->w[windingLeft];
  1078. }
  1079. return NULL;
  1080. }
  1081. /*
  1082. ===============================================================================
  1083. Merging polygons
  1084. ===============================================================================
  1085. */
  1086. /*
  1087. =============
  1088. idCollisionModelManagerLocal::ReplacePolygons
  1089. does not allow for a node to have multiple references to the same polygon
  1090. =============
  1091. */
  1092. void idCollisionModelManagerLocal::ReplacePolygons( cm_model_t *model, cm_node_t *node, cm_polygon_t *p1, cm_polygon_t *p2, cm_polygon_t *newp ) {
  1093. cm_polygonRef_t *pref, *lastpref, *nextpref;
  1094. cm_polygon_t *p;
  1095. bool linked;
  1096. while( 1 ) {
  1097. linked = false;
  1098. lastpref = NULL;
  1099. for ( pref = node->polygons; pref; pref = nextpref ) {
  1100. nextpref = pref->next;
  1101. //
  1102. p = pref->p;
  1103. // if this polygon reference should change
  1104. if ( p == p1 || p == p2 ) {
  1105. // if the new polygon is already linked at this node
  1106. if ( linked ) {
  1107. if ( lastpref ) {
  1108. lastpref->next = nextpref;
  1109. }
  1110. else {
  1111. node->polygons = nextpref;
  1112. }
  1113. FreePolygonReference( pref );
  1114. model->numPolygonRefs--;
  1115. }
  1116. else {
  1117. pref->p = newp;
  1118. linked = true;
  1119. lastpref = pref;
  1120. }
  1121. }
  1122. else {
  1123. lastpref = pref;
  1124. }
  1125. }
  1126. // if leaf node
  1127. if ( node->planeType == -1 ) {
  1128. break;
  1129. }
  1130. if ( p1->bounds[0][node->planeType] > node->planeDist && p2->bounds[0][node->planeType] > node->planeDist ) {
  1131. node = node->children[0];
  1132. }
  1133. else if ( p1->bounds[1][node->planeType] < node->planeDist && p2->bounds[1][node->planeType] < node->planeDist ) {
  1134. node = node->children[1];
  1135. }
  1136. else {
  1137. ReplacePolygons( model, node->children[1], p1, p2, newp );
  1138. node = node->children[0];
  1139. }
  1140. }
  1141. }
  1142. /*
  1143. =============
  1144. idCollisionModelManagerLocal::TryMergePolygons
  1145. =============
  1146. */
  1147. #define CONTINUOUS_EPSILON 0.005f
  1148. #define NORMAL_EPSILON 0.01f
  1149. cm_polygon_t *idCollisionModelManagerLocal::TryMergePolygons( cm_model_t *model, cm_polygon_t *p1, cm_polygon_t *p2 ) {
  1150. int i, j, nexti, prevj;
  1151. int p1BeforeShare, p1AfterShare, p2BeforeShare, p2AfterShare;
  1152. int newEdges[CM_MAX_POLYGON_EDGES], newNumEdges;
  1153. int edgeNum, edgeNum1, edgeNum2, newEdgeNum1, newEdgeNum2;
  1154. cm_edge_t *edge;
  1155. cm_polygon_t *newp;
  1156. idVec3 delta, normal;
  1157. float dot;
  1158. bool keep1, keep2;
  1159. if ( p1->material != p2->material ) {
  1160. return NULL;
  1161. }
  1162. if ( idMath::Fabs( p1->plane.Dist() - p2->plane.Dist() ) > NORMAL_EPSILON ) {
  1163. return NULL;
  1164. }
  1165. for ( i = 0; i < 3; i++ ) {
  1166. if ( idMath::Fabs( p1->plane.Normal()[i] - p2->plane.Normal()[i] ) > NORMAL_EPSILON ) {
  1167. return NULL;
  1168. }
  1169. if ( p1->bounds[0][i] > p2->bounds[1][i] ) {
  1170. return NULL;
  1171. }
  1172. if ( p1->bounds[1][i] < p2->bounds[0][i] ) {
  1173. return NULL;
  1174. }
  1175. }
  1176. // this allows for merging polygons with multiple shared edges
  1177. // polygons with multiple shared edges probably never occur tho ;)
  1178. p1BeforeShare = p1AfterShare = p2BeforeShare = p2AfterShare = -1;
  1179. for ( i = 0; i < p1->numEdges; i++ ) {
  1180. nexti = (i+1)%p1->numEdges;
  1181. for ( j = 0; j < p2->numEdges; j++ ) {
  1182. prevj = (j+p2->numEdges-1)%p2->numEdges;
  1183. //
  1184. if ( abs(p1->edges[i]) != abs(p2->edges[j]) ) {
  1185. // if the next edge of p1 and the previous edge of p2 are the same
  1186. if ( abs(p1->edges[nexti]) == abs(p2->edges[prevj]) ) {
  1187. // if both polygons don't use the edge in the same direction
  1188. if ( p1->edges[nexti] != p2->edges[prevj] ) {
  1189. p1BeforeShare = i;
  1190. p2AfterShare = j;
  1191. }
  1192. break;
  1193. }
  1194. }
  1195. // if both polygons don't use the edge in the same direction
  1196. else if ( p1->edges[i] != p2->edges[j] ) {
  1197. // if the next edge of p1 and the previous edge of p2 are not the same
  1198. if ( abs(p1->edges[nexti]) != abs(p2->edges[prevj]) ) {
  1199. p1AfterShare = nexti;
  1200. p2BeforeShare = prevj;
  1201. break;
  1202. }
  1203. }
  1204. }
  1205. }
  1206. if ( p1BeforeShare < 0 || p1AfterShare < 0 || p2BeforeShare < 0 || p2AfterShare < 0 ) {
  1207. return NULL;
  1208. }
  1209. // check if the new polygon would still be convex
  1210. edgeNum = p1->edges[p1BeforeShare];
  1211. edge = model->edges + abs(edgeNum);
  1212. delta = model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p -
  1213. model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1214. normal = p1->plane.Normal().Cross( delta );
  1215. normal.Normalize();
  1216. edgeNum = p2->edges[p2AfterShare];
  1217. edge = model->edges + abs(edgeNum);
  1218. delta = model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p -
  1219. model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1220. dot = delta * normal;
  1221. if (dot < -CONTINUOUS_EPSILON)
  1222. return NULL; // not a convex polygon
  1223. keep1 = (bool)(dot > CONTINUOUS_EPSILON);
  1224. edgeNum = p2->edges[p2BeforeShare];
  1225. edge = model->edges + abs(edgeNum);
  1226. delta = model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p -
  1227. model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1228. normal = p1->plane.Normal().Cross( delta );
  1229. normal.Normalize();
  1230. edgeNum = p1->edges[p1AfterShare];
  1231. edge = model->edges + abs(edgeNum);
  1232. delta = model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p -
  1233. model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1234. dot = delta * normal;
  1235. if (dot < -CONTINUOUS_EPSILON)
  1236. return NULL; // not a convex polygon
  1237. keep2 = (bool)(dot > CONTINUOUS_EPSILON);
  1238. newEdgeNum1 = newEdgeNum2 = 0;
  1239. // get new edges if we need to replace colinear ones
  1240. if ( !keep1 ) {
  1241. edgeNum1 = p1->edges[p1BeforeShare];
  1242. edgeNum2 = p2->edges[p2AfterShare];
  1243. GetEdge( model, model->vertices[model->edges[abs(edgeNum1)].vertexNum[INT32_SIGNBITSET(edgeNum1)]].p,
  1244. model->vertices[model->edges[abs(edgeNum2)].vertexNum[INT32_SIGNBITNOTSET(edgeNum2)]].p,
  1245. &newEdgeNum1, -1 );
  1246. if ( newEdgeNum1 == 0 ) {
  1247. keep1 = true;
  1248. }
  1249. }
  1250. if ( !keep2 ) {
  1251. edgeNum1 = p2->edges[p2BeforeShare];
  1252. edgeNum2 = p1->edges[p1AfterShare];
  1253. GetEdge( model, model->vertices[model->edges[abs(edgeNum1)].vertexNum[INT32_SIGNBITSET(edgeNum1)]].p,
  1254. model->vertices[model->edges[abs(edgeNum2)].vertexNum[INT32_SIGNBITNOTSET(edgeNum2)]].p,
  1255. &newEdgeNum2, -1 );
  1256. if ( newEdgeNum2 == 0 ) {
  1257. keep2 = true;
  1258. }
  1259. }
  1260. // set edges for new polygon
  1261. newNumEdges = 0;
  1262. if ( !keep2 ) {
  1263. newEdges[newNumEdges++] = newEdgeNum2;
  1264. }
  1265. if ( p1AfterShare < p1BeforeShare ) {
  1266. for ( i = p1AfterShare + (!keep2); i <= p1BeforeShare - (!keep1); i++ ) {
  1267. newEdges[newNumEdges++] = p1->edges[i];
  1268. }
  1269. }
  1270. else {
  1271. for ( i = p1AfterShare + (!keep2); i < p1->numEdges; i++ ) {
  1272. newEdges[newNumEdges++] = p1->edges[i];
  1273. }
  1274. for ( i = 0; i <= p1BeforeShare - (!keep1); i++ ) {
  1275. newEdges[newNumEdges++] = p1->edges[i];
  1276. }
  1277. }
  1278. if ( !keep1 ) {
  1279. newEdges[newNumEdges++] = newEdgeNum1;
  1280. }
  1281. if ( p2AfterShare < p2BeforeShare ) {
  1282. for ( i = p2AfterShare + (!keep1); i <= p2BeforeShare - (!keep2); i++ ) {
  1283. newEdges[newNumEdges++] = p2->edges[i];
  1284. }
  1285. }
  1286. else {
  1287. for ( i = p2AfterShare + (!keep1); i < p2->numEdges; i++ ) {
  1288. newEdges[newNumEdges++] = p2->edges[i];
  1289. }
  1290. for ( i = 0; i <= p2BeforeShare - (!keep2); i++ ) {
  1291. newEdges[newNumEdges++] = p2->edges[i];
  1292. }
  1293. }
  1294. newp = AllocPolygon( model, newNumEdges );
  1295. memcpy( newp, p1, sizeof(cm_polygon_t) );
  1296. memcpy( newp->edges, newEdges, newNumEdges * sizeof(int) );
  1297. newp->numEdges = newNumEdges;
  1298. newp->checkcount = 0;
  1299. // increase usage count for the edges of this polygon
  1300. for ( i = 0; i < newp->numEdges; i++ ) {
  1301. if ( !keep1 && newp->edges[i] == newEdgeNum1 ) {
  1302. continue;
  1303. }
  1304. if ( !keep2 && newp->edges[i] == newEdgeNum2 ) {
  1305. continue;
  1306. }
  1307. model->edges[abs(newp->edges[i])].numUsers++;
  1308. }
  1309. // create new bounds from the merged polygons
  1310. newp->bounds = p1->bounds + p2->bounds;
  1311. return newp;
  1312. }
  1313. /*
  1314. =============
  1315. idCollisionModelManagerLocal::MergePolygonWithTreePolygons
  1316. =============
  1317. */
  1318. bool idCollisionModelManagerLocal::MergePolygonWithTreePolygons( cm_model_t *model, cm_node_t *node, cm_polygon_t *polygon ) {
  1319. int i;
  1320. cm_polygonRef_t *pref;
  1321. cm_polygon_t *p, *newp;
  1322. while( 1 ) {
  1323. for ( pref = node->polygons; pref; pref = pref->next ) {
  1324. p = pref->p;
  1325. //
  1326. if ( p == polygon ) {
  1327. continue;
  1328. }
  1329. //
  1330. newp = TryMergePolygons( model, polygon, p );
  1331. // if polygons were merged
  1332. if ( newp ) {
  1333. model->numMergedPolys++;
  1334. // replace links to the merged polygons with links to the new polygon
  1335. ReplacePolygons( model, model->node, polygon, p, newp );
  1336. // decrease usage count for edges of both merged polygons
  1337. for ( i = 0; i < polygon->numEdges; i++ ) {
  1338. model->edges[abs(polygon->edges[i])].numUsers--;
  1339. }
  1340. for ( i = 0; i < p->numEdges; i++ ) {
  1341. model->edges[abs(p->edges[i])].numUsers--;
  1342. }
  1343. // free merged polygons
  1344. FreePolygon( model, polygon );
  1345. FreePolygon( model, p );
  1346. return true;
  1347. }
  1348. }
  1349. // if leaf node
  1350. if ( node->planeType == -1 ) {
  1351. break;
  1352. }
  1353. if ( polygon->bounds[0][node->planeType] > node->planeDist ) {
  1354. node = node->children[0];
  1355. }
  1356. else if ( polygon->bounds[1][node->planeType] < node->planeDist ) {
  1357. node = node->children[1];
  1358. }
  1359. else {
  1360. if ( MergePolygonWithTreePolygons( model, node->children[1], polygon ) ) {
  1361. return true;
  1362. }
  1363. node = node->children[0];
  1364. }
  1365. }
  1366. return false;
  1367. }
  1368. /*
  1369. =============
  1370. idCollisionModelManagerLocal::MergeTreePolygons
  1371. try to merge any two polygons with the same surface flags and the same contents
  1372. =============
  1373. */
  1374. void idCollisionModelManagerLocal::MergeTreePolygons( cm_model_t *model, cm_node_t *node ) {
  1375. cm_polygonRef_t *pref;
  1376. cm_polygon_t *p;
  1377. bool merge;
  1378. while( 1 ) {
  1379. do {
  1380. merge = false;
  1381. for ( pref = node->polygons; pref; pref = pref->next ) {
  1382. p = pref->p;
  1383. // if we checked this polygon already
  1384. if ( p->checkcount == checkCount ) {
  1385. continue;
  1386. }
  1387. p->checkcount = checkCount;
  1388. // try to merge this polygon with other polygons in the tree
  1389. if ( MergePolygonWithTreePolygons( model, model->node, p ) ) {
  1390. merge = true;
  1391. break;
  1392. }
  1393. }
  1394. } while (merge);
  1395. // if leaf node
  1396. if ( node->planeType == -1 ) {
  1397. break;
  1398. }
  1399. MergeTreePolygons( model, node->children[1] );
  1400. node = node->children[0];
  1401. }
  1402. }
  1403. /*
  1404. ===============================================================================
  1405. Find internal edges
  1406. ===============================================================================
  1407. */
  1408. /*
  1409. if (two polygons have the same contents)
  1410. if (the normals of the two polygon planes face towards each other)
  1411. if (an edge is shared between the polygons)
  1412. if (the edge is not shared in the same direction)
  1413. then this is an internal edge
  1414. else
  1415. if (this edge is on the plane of the other polygon)
  1416. if (this edge if fully inside the winding of the other polygon)
  1417. then this edge is an internal edge
  1418. */
  1419. /*
  1420. =============
  1421. idCollisionModelManagerLocal::PointInsidePolygon
  1422. =============
  1423. */
  1424. bool idCollisionModelManagerLocal::PointInsidePolygon( cm_model_t *model, cm_polygon_t *p, idVec3 &v ) {
  1425. int i, edgeNum;
  1426. idVec3 *v1, *v2, dir1, dir2, vec;
  1427. cm_edge_t *edge;
  1428. for ( i = 0; i < p->numEdges; i++ ) {
  1429. edgeNum = p->edges[i];
  1430. edge = model->edges + abs(edgeNum);
  1431. //
  1432. v1 = &model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1433. v2 = &model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p;
  1434. dir1 = (*v2) - (*v1);
  1435. vec = v - (*v1);
  1436. dir2 = dir1.Cross( p->plane.Normal() );
  1437. if ( vec * dir2 > VERTEX_EPSILON ) {
  1438. return false;
  1439. }
  1440. }
  1441. return true;
  1442. }
  1443. /*
  1444. =============
  1445. idCollisionModelManagerLocal::FindInternalEdgesOnPolygon
  1446. =============
  1447. */
  1448. void idCollisionModelManagerLocal::FindInternalEdgesOnPolygon( cm_model_t *model, cm_polygon_t *p1, cm_polygon_t *p2 ) {
  1449. int i, j, k, edgeNum;
  1450. cm_edge_t *edge;
  1451. idVec3 *v1, *v2, dir1, dir2;
  1452. float d;
  1453. // bounds of polygons should overlap or touch
  1454. for ( i = 0; i < 3; i++ ) {
  1455. if ( p1->bounds[0][i] > p2->bounds[1][i] ) {
  1456. return;
  1457. }
  1458. if ( p1->bounds[1][i] < p2->bounds[0][i] ) {
  1459. return;
  1460. }
  1461. }
  1462. //
  1463. // FIXME: doubled geometry causes problems
  1464. //
  1465. for ( i = 0; i < p1->numEdges; i++ ) {
  1466. edgeNum = p1->edges[i];
  1467. edge = model->edges + abs(edgeNum);
  1468. // if already an internal edge
  1469. if ( edge->internal ) {
  1470. continue;
  1471. }
  1472. //
  1473. v1 = &model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1474. v2 = &model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p;
  1475. // if either of the two vertices is outside the bounds of the other polygon
  1476. for ( k = 0; k < 3; k++ ) {
  1477. d = p2->bounds[1][k] + VERTEX_EPSILON;
  1478. if ( (*v1)[k] > d || (*v2)[k] > d ) {
  1479. break;
  1480. }
  1481. d = p2->bounds[0][k] - VERTEX_EPSILON;
  1482. if ( (*v1)[k] < d || (*v2)[k] < d ) {
  1483. break;
  1484. }
  1485. }
  1486. if ( k < 3 ) {
  1487. continue;
  1488. }
  1489. //
  1490. k = abs(edgeNum);
  1491. for ( j = 0; j < p2->numEdges; j++ ) {
  1492. if ( k == abs(p2->edges[j]) ) {
  1493. break;
  1494. }
  1495. }
  1496. // if the edge is shared between the two polygons
  1497. if ( j < p2->numEdges ) {
  1498. // if the edge is used by more than 2 polygons
  1499. if ( edge->numUsers > 2 ) {
  1500. // could still be internal but we'd have to test all polygons using the edge
  1501. continue;
  1502. }
  1503. // if the edge goes in the same direction for both polygons
  1504. if ( edgeNum == p2->edges[j] ) {
  1505. // the polygons can lay ontop of each other or one can obscure the other
  1506. continue;
  1507. }
  1508. }
  1509. // the edge was not shared
  1510. else {
  1511. // both vertices should be on the plane of the other polygon
  1512. d = p2->plane.Distance( *v1 );
  1513. if ( idMath::Fabs(d) > VERTEX_EPSILON ) {
  1514. continue;
  1515. }
  1516. d = p2->plane.Distance( *v2 );
  1517. if ( idMath::Fabs(d) > VERTEX_EPSILON ) {
  1518. continue;
  1519. }
  1520. }
  1521. // the two polygon plane normals should face towards each other
  1522. dir1 = (*v2) - (*v1);
  1523. dir2 = p1->plane.Normal().Cross( dir1 );
  1524. if ( p2->plane.Normal() * dir2 < 0 ) {
  1525. //continue;
  1526. break;
  1527. }
  1528. // if the edge was not shared
  1529. if ( j >= p2->numEdges ) {
  1530. // both vertices of the edge should be inside the winding of the other polygon
  1531. if ( !PointInsidePolygon( model, p2, *v1 ) ) {
  1532. continue;
  1533. }
  1534. if ( !PointInsidePolygon( model, p2, *v2 ) ) {
  1535. continue;
  1536. }
  1537. }
  1538. // we got another internal edge
  1539. edge->internal = true;
  1540. model->numInternalEdges++;
  1541. }
  1542. }
  1543. /*
  1544. =============
  1545. idCollisionModelManagerLocal::FindInternalPolygonEdges
  1546. =============
  1547. */
  1548. void idCollisionModelManagerLocal::FindInternalPolygonEdges( cm_model_t *model, cm_node_t *node, cm_polygon_t *polygon ) {
  1549. cm_polygonRef_t *pref;
  1550. cm_polygon_t *p;
  1551. if ( polygon->material->GetCullType() == CT_TWO_SIDED || polygon->material->ShouldCreateBackSides() ) {
  1552. return;
  1553. }
  1554. while( 1 ) {
  1555. for ( pref = node->polygons; pref; pref = pref->next ) {
  1556. p = pref->p;
  1557. //
  1558. // FIXME: use some sort of additional checkcount because currently
  1559. // polygons can be checked multiple times
  1560. //
  1561. // if the polygons don't have the same contents
  1562. if ( p->contents != polygon->contents ) {
  1563. continue;
  1564. }
  1565. if ( p == polygon ) {
  1566. continue;
  1567. }
  1568. FindInternalEdgesOnPolygon( model, polygon, p );
  1569. }
  1570. // if leaf node
  1571. if ( node->planeType == -1 ) {
  1572. break;
  1573. }
  1574. if ( polygon->bounds[0][node->planeType] > node->planeDist ) {
  1575. node = node->children[0];
  1576. }
  1577. else if ( polygon->bounds[1][node->planeType] < node->planeDist ) {
  1578. node = node->children[1];
  1579. }
  1580. else {
  1581. FindInternalPolygonEdges( model, node->children[1], polygon );
  1582. node = node->children[0];
  1583. }
  1584. }
  1585. }
  1586. /*
  1587. =============
  1588. idCollisionModelManagerLocal::FindContainedEdges
  1589. =============
  1590. */
  1591. void idCollisionModelManagerLocal::FindContainedEdges( cm_model_t *model, cm_polygon_t *p ) {
  1592. int i, edgeNum;
  1593. cm_edge_t *edge;
  1594. idFixedWinding w;
  1595. for ( i = 0; i < p->numEdges; i++ ) {
  1596. edgeNum = p->edges[i];
  1597. edge = model->edges + abs(edgeNum);
  1598. if ( edge->internal ) {
  1599. continue;
  1600. }
  1601. w.Clear();
  1602. w += model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p;
  1603. w += model->vertices[edge->vertexNum[INT32_SIGNBITNOTSET(edgeNum)]].p;
  1604. if ( ChoppedAwayByProcBSP( w, p->plane, p->contents ) ) {
  1605. edge->internal = true;
  1606. }
  1607. }
  1608. }
  1609. /*
  1610. =============
  1611. idCollisionModelManagerLocal::FindInternalEdges
  1612. =============
  1613. */
  1614. void idCollisionModelManagerLocal::FindInternalEdges( cm_model_t *model, cm_node_t *node ) {
  1615. cm_polygonRef_t *pref;
  1616. cm_polygon_t *p;
  1617. while( 1 ) {
  1618. for ( pref = node->polygons; pref; pref = pref->next ) {
  1619. p = pref->p;
  1620. // if we checked this polygon already
  1621. if ( p->checkcount == checkCount ) {
  1622. continue;
  1623. }
  1624. p->checkcount = checkCount;
  1625. FindInternalPolygonEdges( model, model->node, p );
  1626. //FindContainedEdges( model, p );
  1627. }
  1628. // if leaf node
  1629. if ( node->planeType == -1 ) {
  1630. break;
  1631. }
  1632. FindInternalEdges( model, node->children[1] );
  1633. node = node->children[0];
  1634. }
  1635. }
  1636. /*
  1637. ===============================================================================
  1638. Spatial subdivision
  1639. ===============================================================================
  1640. */
  1641. /*
  1642. ================
  1643. CM_FindSplitter
  1644. ================
  1645. */
  1646. static int CM_FindSplitter( const cm_node_t *node, const idBounds &bounds, int *planeType, float *planeDist ) {
  1647. int i, j, type, axis[3], polyCount;
  1648. float dist, t, bestt, size[3];
  1649. cm_brushRef_t *bref;
  1650. cm_polygonRef_t *pref;
  1651. const cm_node_t *n;
  1652. bool forceSplit = false;
  1653. for ( i = 0; i < 3; i++ ) {
  1654. size[i] = bounds[1][i] - bounds[0][i];
  1655. axis[i] = i;
  1656. }
  1657. // sort on largest axis
  1658. for ( i = 0; i < 2; i++ ) {
  1659. if ( size[i] < size[i+1] ) {
  1660. t = size[i];
  1661. size[i] = size[i+1];
  1662. size[i+1] = t;
  1663. j = axis[i];
  1664. axis[i] = axis[i+1];
  1665. axis[i+1] = j;
  1666. i = -1;
  1667. }
  1668. }
  1669. // if the node is too small for further splits
  1670. if ( size[0] < MIN_NODE_SIZE ) {
  1671. polyCount = 0;
  1672. for ( pref = node->polygons; pref; pref = pref->next) {
  1673. polyCount++;
  1674. }
  1675. if ( polyCount > MAX_NODE_POLYGONS ) {
  1676. forceSplit = true;
  1677. }
  1678. }
  1679. // find an axial aligned splitter
  1680. for ( i = 0; i < 3; i++ ) {
  1681. // start with the largest axis first
  1682. type = axis[i];
  1683. bestt = size[i];
  1684. // if the node is small anough in this axis direction
  1685. if ( !forceSplit && bestt < MIN_NODE_SIZE ) {
  1686. break;
  1687. }
  1688. // find an axial splitter from the brush bounding boxes
  1689. // also try brushes from parent nodes
  1690. for ( n = node; n; n = n->parent ) {
  1691. for ( bref = n->brushes; bref; bref = bref->next) {
  1692. for ( j = 0; j < 2; j++ ) {
  1693. dist = bref->b->bounds[j][type];
  1694. // if the splitter is already used or outside node bounds
  1695. if ( dist >= bounds[1][type] || dist <= bounds[0][type] ) {
  1696. continue;
  1697. }
  1698. // find the most centered splitter
  1699. t = abs((bounds[1][type] - dist) - (dist - bounds[0][type]));
  1700. if ( t < bestt ) {
  1701. bestt = t;
  1702. *planeType = type;
  1703. *planeDist = dist;
  1704. }
  1705. }
  1706. }
  1707. }
  1708. // find an axial splitter from the polygon bounding boxes
  1709. // also try brushes from parent nodes
  1710. for ( n = node; n; n = n->parent ) {
  1711. for ( pref = n->polygons; pref; pref = pref->next) {
  1712. for ( j = 0; j < 2; j++ ) {
  1713. dist = pref->p->bounds[j][type];
  1714. // if the splitter is already used or outside node bounds
  1715. if ( dist >= bounds[1][type] || dist <= bounds[0][type] ) {
  1716. continue;
  1717. }
  1718. // find the most centered splitter
  1719. t = abs((bounds[1][type] - dist) - (dist - bounds[0][type]));
  1720. if ( t < bestt ) {
  1721. bestt = t;
  1722. *planeType = type;
  1723. *planeDist = dist;
  1724. }
  1725. }
  1726. }
  1727. }
  1728. // if we found a splitter on the largest axis
  1729. if ( bestt < size[i] ) {
  1730. // if forced split due to lots of polygons
  1731. if ( forceSplit ) {
  1732. return true;
  1733. }
  1734. // don't create splitters real close to the bounds
  1735. if ( bounds[1][type] - *planeDist > (MIN_NODE_SIZE*0.5f) &&
  1736. *planeDist - bounds[0][type] > (MIN_NODE_SIZE*0.5f) ) {
  1737. return true;
  1738. }
  1739. }
  1740. }
  1741. return false;
  1742. }
  1743. /*
  1744. ================
  1745. CM_R_InsideAllChildren
  1746. ================
  1747. */
  1748. static int CM_R_InsideAllChildren( cm_node_t *node, const idBounds &bounds ) {
  1749. assert(node != NULL);
  1750. if ( node->planeType != -1 ) {
  1751. if ( bounds[0][node->planeType] >= node->planeDist ) {
  1752. return false;
  1753. }
  1754. if ( bounds[1][node->planeType] <= node->planeDist ) {
  1755. return false;
  1756. }
  1757. if ( !CM_R_InsideAllChildren( node->children[0], bounds ) ) {
  1758. return false;
  1759. }
  1760. if ( !CM_R_InsideAllChildren( node->children[1], bounds ) ) {
  1761. return false;
  1762. }
  1763. }
  1764. return true;
  1765. }
  1766. /*
  1767. ================
  1768. idCollisionModelManagerLocal::R_FilterPolygonIntoTree
  1769. ================
  1770. */
  1771. void idCollisionModelManagerLocal::R_FilterPolygonIntoTree( cm_model_t *model, cm_node_t *node, cm_polygonRef_t *pref, cm_polygon_t *p ) {
  1772. assert(node != NULL);
  1773. while ( node->planeType != -1 ) {
  1774. if ( CM_R_InsideAllChildren( node, p->bounds ) ) {
  1775. break;
  1776. }
  1777. if ( p->bounds[0][node->planeType] >= node->planeDist ) {
  1778. node = node->children[0];
  1779. }
  1780. else if ( p->bounds[1][node->planeType] <= node->planeDist ) {
  1781. node = node->children[1];
  1782. }
  1783. else {
  1784. R_FilterPolygonIntoTree( model, node->children[1], NULL, p );
  1785. node = node->children[0];
  1786. }
  1787. }
  1788. if ( pref ) {
  1789. pref->next = node->polygons;
  1790. node->polygons = pref;
  1791. }
  1792. else {
  1793. AddPolygonToNode( model, node, p );
  1794. }
  1795. }
  1796. /*
  1797. ================
  1798. idCollisionModelManagerLocal::R_FilterBrushIntoTree
  1799. ================
  1800. */
  1801. void idCollisionModelManagerLocal::R_FilterBrushIntoTree( cm_model_t *model, cm_node_t *node, cm_brushRef_t *pref, cm_brush_t *b ) {
  1802. assert(node != NULL);
  1803. while ( node->planeType != -1 ) {
  1804. if ( CM_R_InsideAllChildren( node, b->bounds ) ) {
  1805. break;
  1806. }
  1807. if ( b->bounds[0][node->planeType] >= node->planeDist ) {
  1808. node = node->children[0];
  1809. }
  1810. else if ( b->bounds[1][node->planeType] <= node->planeDist ) {
  1811. node = node->children[1];
  1812. }
  1813. else {
  1814. R_FilterBrushIntoTree( model, node->children[1], NULL, b );
  1815. node = node->children[0];
  1816. }
  1817. }
  1818. if ( pref ) {
  1819. pref->next = node->brushes;
  1820. node->brushes = pref;
  1821. }
  1822. else {
  1823. AddBrushToNode( model, node, b );
  1824. }
  1825. }
  1826. /*
  1827. ================
  1828. idCollisionModelManagerLocal::R_CreateAxialBSPTree
  1829. a brush or polygon is linked in the node closest to the root where
  1830. the brush or polygon is inside all children
  1831. ================
  1832. */
  1833. cm_node_t *idCollisionModelManagerLocal::R_CreateAxialBSPTree( cm_model_t *model, cm_node_t *node, const idBounds &bounds ) {
  1834. int planeType;
  1835. float planeDist;
  1836. cm_polygonRef_t *pref, *nextpref, *prevpref;
  1837. cm_brushRef_t *bref, *nextbref, *prevbref;
  1838. cm_node_t *frontNode, *backNode, *n;
  1839. idBounds frontBounds, backBounds;
  1840. if ( !CM_FindSplitter( node, bounds, &planeType, &planeDist ) ) {
  1841. node->planeType = -1;
  1842. return node;
  1843. }
  1844. // create two child nodes
  1845. frontNode = AllocNode( model, NODE_BLOCK_SIZE_LARGE );
  1846. memset( frontNode, 0, sizeof(cm_node_t) );
  1847. frontNode->parent = node;
  1848. frontNode->planeType = -1;
  1849. //
  1850. backNode = AllocNode( model, NODE_BLOCK_SIZE_LARGE );
  1851. memset( backNode, 0, sizeof(cm_node_t) );
  1852. backNode->parent = node;
  1853. backNode->planeType = -1;
  1854. //
  1855. model->numNodes += 2;
  1856. // set front node bounds
  1857. frontBounds = bounds;
  1858. frontBounds[0][planeType] = planeDist;
  1859. // set back node bounds
  1860. backBounds = bounds;
  1861. backBounds[1][planeType] = planeDist;
  1862. //
  1863. node->planeType = planeType;
  1864. node->planeDist = planeDist;
  1865. node->children[0] = frontNode;
  1866. node->children[1] = backNode;
  1867. // filter polygons and brushes down the tree if necesary
  1868. for ( n = node; n; n = n->parent ) {
  1869. prevpref = NULL;
  1870. for ( pref = n->polygons; pref; pref = nextpref) {
  1871. nextpref = pref->next;
  1872. // if polygon is not inside all children
  1873. if ( !CM_R_InsideAllChildren( n, pref->p->bounds ) ) {
  1874. // filter polygon down the tree
  1875. R_FilterPolygonIntoTree( model, n, pref, pref->p );
  1876. if ( prevpref ) {
  1877. prevpref->next = nextpref;
  1878. }
  1879. else {
  1880. n->polygons = nextpref;
  1881. }
  1882. }
  1883. else {
  1884. prevpref = pref;
  1885. }
  1886. }
  1887. prevbref = NULL;
  1888. for ( bref = n->brushes; bref; bref = nextbref) {
  1889. nextbref = bref->next;
  1890. // if brush is not inside all children
  1891. if ( !CM_R_InsideAllChildren( n, bref->b->bounds ) ) {
  1892. // filter brush down the tree
  1893. R_FilterBrushIntoTree( model, n, bref, bref->b );
  1894. if ( prevbref ) {
  1895. prevbref->next = nextbref;
  1896. }
  1897. else {
  1898. n->brushes = nextbref;
  1899. }
  1900. }
  1901. else {
  1902. prevbref = bref;
  1903. }
  1904. }
  1905. }
  1906. R_CreateAxialBSPTree( model, frontNode, frontBounds );
  1907. R_CreateAxialBSPTree( model, backNode, backBounds );
  1908. return node;
  1909. }
  1910. /*
  1911. int cm_numSavedPolygonLinks;
  1912. int cm_numSavedBrushLinks;
  1913. int CM_R_CountChildren( cm_node_t *node ) {
  1914. if ( node->planeType == -1 ) {
  1915. return 0;
  1916. }
  1917. return 2 + CM_R_CountChildren(node->children[0]) + CM_R_CountChildren(node->children[1]);
  1918. }
  1919. void CM_R_TestOptimisation( cm_node_t *node ) {
  1920. int polyCount, brushCount, numChildren;
  1921. cm_polygonRef_t *pref;
  1922. cm_brushRef_t *bref;
  1923. if ( node->planeType == -1 ) {
  1924. return;
  1925. }
  1926. polyCount = 0;
  1927. for ( pref = node->polygons; pref; pref = pref->next) {
  1928. polyCount++;
  1929. }
  1930. brushCount = 0;
  1931. for ( bref = node->brushes; bref; bref = bref->next) {
  1932. brushCount++;
  1933. }
  1934. if ( polyCount || brushCount ) {
  1935. numChildren = CM_R_CountChildren( node );
  1936. cm_numSavedPolygonLinks += (numChildren - 1) * polyCount;
  1937. cm_numSavedBrushLinks += (numChildren - 1) * brushCount;
  1938. }
  1939. CM_R_TestOptimisation( node->children[0] );
  1940. CM_R_TestOptimisation( node->children[1] );
  1941. }
  1942. */
  1943. /*
  1944. ================
  1945. idCollisionModelManagerLocal::CreateAxialBSPTree
  1946. ================
  1947. */
  1948. cm_node_t *idCollisionModelManagerLocal::CreateAxialBSPTree( cm_model_t *model, cm_node_t *node ) {
  1949. cm_polygonRef_t *pref;
  1950. cm_brushRef_t *bref;
  1951. idBounds bounds;
  1952. // get head node bounds
  1953. bounds.Clear();
  1954. for ( pref = node->polygons; pref; pref = pref->next) {
  1955. bounds += pref->p->bounds;
  1956. }
  1957. for ( bref = node->brushes; bref; bref = bref->next) {
  1958. bounds += bref->b->bounds;
  1959. }
  1960. // create axial BSP tree from head node
  1961. node = R_CreateAxialBSPTree( model, node, bounds );
  1962. return node;
  1963. }
  1964. /*
  1965. ===============================================================================
  1966. Raw polygon and brush data
  1967. ===============================================================================
  1968. */
  1969. /*
  1970. ================
  1971. idCollisionModelManagerLocal::SetupHash
  1972. ================
  1973. */
  1974. void idCollisionModelManagerLocal::SetupHash() {
  1975. if ( !cm_vertexHash ) {
  1976. cm_vertexHash = new (TAG_COLLISION) idHashIndex( VERTEX_HASH_SIZE, 1024 );
  1977. }
  1978. if ( !cm_edgeHash ) {
  1979. cm_edgeHash = new (TAG_COLLISION) idHashIndex( EDGE_HASH_SIZE, 1024 );
  1980. }
  1981. // init variables used during loading and optimization
  1982. if ( !cm_windingList ) {
  1983. cm_windingList = new (TAG_COLLISION) cm_windingList_t;
  1984. }
  1985. if ( !cm_outList ) {
  1986. cm_outList = new (TAG_COLLISION) cm_windingList_t;
  1987. }
  1988. if ( !cm_tmpList ) {
  1989. cm_tmpList = new (TAG_COLLISION) cm_windingList_t;
  1990. }
  1991. }
  1992. /*
  1993. ================
  1994. idCollisionModelManagerLocal::ShutdownHash
  1995. ================
  1996. */
  1997. void idCollisionModelManagerLocal::ShutdownHash() {
  1998. delete cm_vertexHash;
  1999. cm_vertexHash = NULL;
  2000. delete cm_edgeHash;
  2001. cm_edgeHash = NULL;
  2002. delete cm_tmpList;
  2003. cm_tmpList = NULL;
  2004. delete cm_outList;
  2005. cm_outList = NULL;
  2006. delete cm_windingList;
  2007. cm_windingList = NULL;
  2008. }
  2009. /*
  2010. ================
  2011. idCollisionModelManagerLocal::ClearHash
  2012. ================
  2013. */
  2014. void idCollisionModelManagerLocal::ClearHash( idBounds &bounds ) {
  2015. int i;
  2016. float f, max;
  2017. cm_vertexHash->Clear();
  2018. cm_edgeHash->Clear();
  2019. cm_modelBounds = bounds;
  2020. max = bounds[1].x - bounds[0].x;
  2021. f = bounds[1].y - bounds[0].y;
  2022. if ( f > max ) {
  2023. max = f;
  2024. }
  2025. cm_vertexShift = (float) max / VERTEX_HASH_BOXSIZE;
  2026. for ( i = 0; (1<<i) < cm_vertexShift; i++ ) {
  2027. }
  2028. if ( i == 0 ) {
  2029. cm_vertexShift = 1;
  2030. }
  2031. else {
  2032. cm_vertexShift = i;
  2033. }
  2034. }
  2035. /*
  2036. ================
  2037. idCollisionModelManagerLocal::HashVec
  2038. ================
  2039. */
  2040. ID_INLINE int idCollisionModelManagerLocal::HashVec(const idVec3 &vec) {
  2041. /*
  2042. int x, y;
  2043. x = (((int)(vec[0] - cm_modelBounds[0].x + 0.5 )) >> cm_vertexShift) & (VERTEX_HASH_BOXSIZE-1);
  2044. y = (((int)(vec[1] - cm_modelBounds[0].y + 0.5 )) >> cm_vertexShift) & (VERTEX_HASH_BOXSIZE-1);
  2045. assert (x >= 0 && x < VERTEX_HASH_BOXSIZE && y >= 0 && y < VERTEX_HASH_BOXSIZE);
  2046. return y * VERTEX_HASH_BOXSIZE + x;
  2047. */
  2048. int x, y, z;
  2049. x = (((int) (vec[0] - cm_modelBounds[0].x + 0.5)) + 2) >> 2;
  2050. y = (((int) (vec[1] - cm_modelBounds[0].y + 0.5)) + 2) >> 2;
  2051. z = (((int) (vec[2] - cm_modelBounds[0].z + 0.5)) + 2) >> 2;
  2052. return (x + y * VERTEX_HASH_BOXSIZE + z) & (VERTEX_HASH_SIZE-1);
  2053. }
  2054. /*
  2055. ================
  2056. idCollisionModelManagerLocal::GetVertex
  2057. ================
  2058. */
  2059. int idCollisionModelManagerLocal::GetVertex( cm_model_t *model, const idVec3 &v, int *vertexNum ) {
  2060. int i, hashKey, vn;
  2061. idVec3 vert, *p;
  2062. for (i = 0; i < 3; i++) {
  2063. if ( idMath::Fabs(v[i] - idMath::Rint(v[i])) < INTEGRAL_EPSILON )
  2064. vert[i] = idMath::Rint(v[i]);
  2065. else
  2066. vert[i] = v[i];
  2067. }
  2068. hashKey = HashVec( vert );
  2069. for (vn = cm_vertexHash->First( hashKey ); vn >= 0; vn = cm_vertexHash->Next( vn ) ) {
  2070. p = &model->vertices[vn].p;
  2071. // first compare z-axis because hash is based on x-y plane
  2072. if (idMath::Fabs(vert[2] - (*p)[2]) < VERTEX_EPSILON &&
  2073. idMath::Fabs(vert[0] - (*p)[0]) < VERTEX_EPSILON &&
  2074. idMath::Fabs(vert[1] - (*p)[1]) < VERTEX_EPSILON )
  2075. {
  2076. *vertexNum = vn;
  2077. return true;
  2078. }
  2079. }
  2080. if ( model->numVertices >= model->maxVertices ) {
  2081. cm_vertex_t *oldVertices;
  2082. // resize vertex array
  2083. model->maxVertices = (float) model->maxVertices * 1.5f + 1;
  2084. oldVertices = model->vertices;
  2085. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->maxVertices * sizeof(cm_vertex_t), TAG_COLLISION );
  2086. memcpy( model->vertices, oldVertices, model->numVertices * sizeof(cm_vertex_t) );
  2087. Mem_Free( oldVertices );
  2088. cm_vertexHash->ResizeIndex( model->maxVertices );
  2089. }
  2090. model->vertices[model->numVertices].p = vert;
  2091. model->vertices[model->numVertices].checkcount = 0;
  2092. *vertexNum = model->numVertices;
  2093. // add vertice to hash
  2094. cm_vertexHash->Add( hashKey, model->numVertices );
  2095. //
  2096. model->numVertices++;
  2097. return false;
  2098. }
  2099. /*
  2100. ================
  2101. idCollisionModelManagerLocal::GetEdge
  2102. ================
  2103. */
  2104. int idCollisionModelManagerLocal::GetEdge( cm_model_t *model, const idVec3 &v1, const idVec3 &v2, int *edgeNum, int v1num ) {
  2105. int v2num, hashKey, e;
  2106. int found, *vertexNum;
  2107. // the first edge is a dummy
  2108. if ( model->numEdges == 0 ) {
  2109. model->numEdges = 1;
  2110. }
  2111. if ( v1num != -1 ) {
  2112. found = 1;
  2113. }
  2114. else {
  2115. found = GetVertex( model, v1, &v1num );
  2116. }
  2117. found &= GetVertex( model, v2, &v2num );
  2118. // if both vertices are the same or snapped onto each other
  2119. if ( v1num == v2num ) {
  2120. *edgeNum = 0;
  2121. return true;
  2122. }
  2123. hashKey = cm_edgeHash->GenerateKey( v1num, v2num );
  2124. // if both vertices where already stored
  2125. if (found) {
  2126. for (e = cm_edgeHash->First( hashKey ); e >= 0; e = cm_edgeHash->Next( e ) )
  2127. {
  2128. // NOTE: only allow at most two users that use the edge in opposite direction
  2129. if ( model->edges[e].numUsers != 1 ) {
  2130. continue;
  2131. }
  2132. vertexNum = model->edges[e].vertexNum;
  2133. if ( vertexNum[0] == v2num ) {
  2134. if ( vertexNum[1] == v1num ) {
  2135. // negative for a reversed edge
  2136. *edgeNum = -e;
  2137. break;
  2138. }
  2139. }
  2140. /*
  2141. else if ( vertexNum[0] == v1num ) {
  2142. if ( vertexNum[1] == v2num ) {
  2143. *edgeNum = e;
  2144. break;
  2145. }
  2146. }
  2147. */
  2148. }
  2149. // if edge found in hash
  2150. if ( e >= 0 ) {
  2151. model->edges[e].numUsers++;
  2152. return true;
  2153. }
  2154. }
  2155. if ( model->numEdges >= model->maxEdges ) {
  2156. cm_edge_t *oldEdges;
  2157. // resize edge array
  2158. model->maxEdges = (float) model->maxEdges * 1.5f + 1;
  2159. oldEdges = model->edges;
  2160. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->maxEdges * sizeof(cm_edge_t), TAG_COLLISION );
  2161. memcpy( model->edges, oldEdges, model->numEdges * sizeof(cm_edge_t) );
  2162. Mem_Free( oldEdges );
  2163. cm_edgeHash->ResizeIndex( model->maxEdges );
  2164. }
  2165. // setup edge
  2166. model->edges[model->numEdges].vertexNum[0] = v1num;
  2167. model->edges[model->numEdges].vertexNum[1] = v2num;
  2168. model->edges[model->numEdges].internal = false;
  2169. model->edges[model->numEdges].checkcount = 0;
  2170. model->edges[model->numEdges].numUsers = 1; // used by one polygon atm
  2171. model->edges[model->numEdges].normal.Zero();
  2172. //
  2173. *edgeNum = model->numEdges;
  2174. // add edge to hash
  2175. cm_edgeHash->Add( hashKey, model->numEdges );
  2176. model->numEdges++;
  2177. return false;
  2178. }
  2179. /*
  2180. ================
  2181. idCollisionModelManagerLocal::CreatePolygon
  2182. ================
  2183. */
  2184. void idCollisionModelManagerLocal::CreatePolygon( cm_model_t *model, idFixedWinding *w, const idPlane &plane, const idMaterial *material, int primitiveNum ) {
  2185. int i, j, edgeNum, v1num;
  2186. int numPolyEdges, polyEdges[MAX_POINTS_ON_WINDING];
  2187. idBounds bounds;
  2188. cm_polygon_t *p;
  2189. // turn the winding into a sequence of edges
  2190. numPolyEdges = 0;
  2191. v1num = -1; // first vertex unknown
  2192. for ( i = 0, j = 1; i < w->GetNumPoints(); i++, j++ ) {
  2193. if ( j >= w->GetNumPoints() ) {
  2194. j = 0;
  2195. }
  2196. GetEdge( model, (*w)[i].ToVec3(), (*w)[j].ToVec3(), &polyEdges[numPolyEdges], v1num );
  2197. if ( polyEdges[numPolyEdges] ) {
  2198. // last vertex of this edge is the first vertex of the next edge
  2199. v1num = model->edges[ abs(polyEdges[numPolyEdges]) ].vertexNum[ INT32_SIGNBITNOTSET(polyEdges[numPolyEdges]) ];
  2200. // this edge is valid so keep it
  2201. numPolyEdges++;
  2202. }
  2203. }
  2204. // should have at least 3 edges
  2205. if ( numPolyEdges < 3 ) {
  2206. return;
  2207. }
  2208. // the polygon is invalid if some edge is found twice
  2209. for ( i = 0; i < numPolyEdges; i++ ) {
  2210. for ( j = i+1; j < numPolyEdges; j++ ) {
  2211. if ( abs(polyEdges[i]) == abs(polyEdges[j]) ) {
  2212. return;
  2213. }
  2214. }
  2215. }
  2216. // don't overflow max edges
  2217. if ( numPolyEdges > CM_MAX_POLYGON_EDGES ) {
  2218. common->Warning( "idCollisionModelManagerLocal::CreatePolygon: polygon has more than %d edges", numPolyEdges );
  2219. numPolyEdges = CM_MAX_POLYGON_EDGES;
  2220. }
  2221. w->GetBounds( bounds );
  2222. p = AllocPolygon( model, numPolyEdges );
  2223. p->numEdges = numPolyEdges;
  2224. p->contents = material->GetContentFlags();
  2225. p->material = material;
  2226. p->checkcount = 0;
  2227. p->plane = plane;
  2228. p->bounds = bounds;
  2229. for ( i = 0; i < numPolyEdges; i++ ) {
  2230. edgeNum = polyEdges[i];
  2231. p->edges[i] = edgeNum;
  2232. }
  2233. R_FilterPolygonIntoTree( model, model->node, NULL, p );
  2234. }
  2235. /*
  2236. ================
  2237. idCollisionModelManagerLocal::PolygonFromWinding
  2238. NOTE: for patches primitiveNum < 0 and abs(primitiveNum) is the real number
  2239. ================
  2240. */
  2241. void idCollisionModelManagerLocal::PolygonFromWinding( cm_model_t *model, idFixedWinding *w, const idPlane &plane, const idMaterial *material, int primitiveNum ) {
  2242. int contents;
  2243. contents = material->GetContentFlags();
  2244. // if this polygon is part of the world model
  2245. if ( numModels == 0 ) {
  2246. // if the polygon is fully chopped away by the proc bsp tree
  2247. if ( ChoppedAwayByProcBSP( *w, plane, contents ) ) {
  2248. model->numRemovedPolys++;
  2249. return;
  2250. }
  2251. }
  2252. // get one winding that is not or only partly contained in brushes
  2253. w = WindingOutsideBrushes( w, plane, contents, primitiveNum, model->node );
  2254. // if the polygon is fully contained within a brush
  2255. if ( !w ) {
  2256. model->numRemovedPolys++;
  2257. return;
  2258. }
  2259. if ( w->IsHuge() ) {
  2260. common->Warning( "idCollisionModelManagerLocal::PolygonFromWinding: model %s primitive %d is degenerate", model->name.c_str(), abs(primitiveNum) );
  2261. return;
  2262. }
  2263. CreatePolygon( model, w, plane, material, primitiveNum );
  2264. if ( material->GetCullType() == CT_TWO_SIDED || material->ShouldCreateBackSides() ) {
  2265. w->ReverseSelf();
  2266. CreatePolygon( model, w, -plane, material, primitiveNum );
  2267. }
  2268. }
  2269. /*
  2270. =================
  2271. idCollisionModelManagerLocal::CreatePatchPolygons
  2272. =================
  2273. */
  2274. void idCollisionModelManagerLocal::CreatePatchPolygons( cm_model_t *model, idSurface_Patch &mesh, const idMaterial *material, int primitiveNum ) {
  2275. int i, j;
  2276. float dot;
  2277. int v1, v2, v3, v4;
  2278. idFixedWinding w;
  2279. idPlane plane;
  2280. idVec3 d1, d2;
  2281. for ( i = 0; i < mesh.GetWidth() - 1; i++ ) {
  2282. for ( j = 0; j < mesh.GetHeight() - 1; j++ ) {
  2283. v1 = j * mesh.GetWidth() + i;
  2284. v2 = v1 + 1;
  2285. v3 = v1 + mesh.GetWidth() + 1;
  2286. v4 = v1 + mesh.GetWidth();
  2287. d1 = mesh[v2].xyz - mesh[v1].xyz;
  2288. d2 = mesh[v3].xyz - mesh[v1].xyz;
  2289. plane.SetNormal( d1.Cross(d2) );
  2290. if ( plane.Normalize() != 0.0f ) {
  2291. plane.FitThroughPoint( mesh[v1].xyz );
  2292. dot = plane.Distance( mesh[v4].xyz );
  2293. // if we can turn it into a quad
  2294. if ( idMath::Fabs(dot) < 0.1f ) {
  2295. w.Clear();
  2296. w += mesh[v1].xyz;
  2297. w += mesh[v2].xyz;
  2298. w += mesh[v3].xyz;
  2299. w += mesh[v4].xyz;
  2300. PolygonFromWinding( model, &w, plane, material, -primitiveNum );
  2301. continue;
  2302. }
  2303. else {
  2304. // create one of the triangles
  2305. w.Clear();
  2306. w += mesh[v1].xyz;
  2307. w += mesh[v2].xyz;
  2308. w += mesh[v3].xyz;
  2309. PolygonFromWinding( model, &w, plane, material, -primitiveNum );
  2310. }
  2311. }
  2312. // create the other triangle
  2313. d1 = mesh[v3].xyz - mesh[v1].xyz;
  2314. d2 = mesh[v4].xyz - mesh[v1].xyz;
  2315. plane.SetNormal( d1.Cross(d2) );
  2316. if ( plane.Normalize() != 0.0f ) {
  2317. plane.FitThroughPoint( mesh[v1].xyz );
  2318. w.Clear();
  2319. w += mesh[v1].xyz;
  2320. w += mesh[v3].xyz;
  2321. w += mesh[v4].xyz;
  2322. PolygonFromWinding( model, &w, plane, material, -primitiveNum );
  2323. }
  2324. }
  2325. }
  2326. }
  2327. /*
  2328. =================
  2329. CM_EstimateVertsAndEdges
  2330. =================
  2331. */
  2332. static void CM_EstimateVertsAndEdges( const idMapEntity *mapEnt, int *numVerts, int *numEdges ) {
  2333. int j, width, height;
  2334. *numVerts = *numEdges = 0;
  2335. for ( j = 0; j < mapEnt->GetNumPrimitives(); j++ ) {
  2336. const idMapPrimitive *mapPrim;
  2337. mapPrim = mapEnt->GetPrimitive(j);
  2338. if ( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH ) {
  2339. // assume maximum tesselation without adding verts
  2340. width = static_cast<const idMapPatch*>(mapPrim)->GetWidth();
  2341. height = static_cast<const idMapPatch*>(mapPrim)->GetHeight();
  2342. *numVerts += width * height;
  2343. *numEdges += (width-1) * height + width * (height-1) + (width-1) * (height-1);
  2344. continue;
  2345. }
  2346. if ( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
  2347. // assume cylinder with a polygon with (numSides - 2) edges ontop and on the bottom
  2348. *numVerts += (static_cast<const idMapBrush*>(mapPrim)->GetNumSides() - 2) * 2;
  2349. *numEdges += (static_cast<const idMapBrush*>(mapPrim)->GetNumSides() - 2) * 3;
  2350. continue;
  2351. }
  2352. }
  2353. }
  2354. /*
  2355. =================
  2356. idCollisionModelManagerLocal::ConverPatch
  2357. =================
  2358. */
  2359. void idCollisionModelManagerLocal::ConvertPatch( cm_model_t *model, const idMapPatch *patch, int primitiveNum ) {
  2360. const idMaterial *material;
  2361. idSurface_Patch *cp;
  2362. material = declManager->FindMaterial( patch->GetMaterial() );
  2363. if ( !( material->GetContentFlags() & CONTENTS_REMOVE_UTIL ) ) {
  2364. return;
  2365. }
  2366. // copy the patch
  2367. cp = new (TAG_COLLISION) idSurface_Patch( *patch );
  2368. // if the patch has an explicit number of subdivisions use it to avoid cracks
  2369. if ( patch->GetExplicitlySubdivided() ) {
  2370. cp->SubdivideExplicit( patch->GetHorzSubdivisions(), patch->GetVertSubdivisions(), false, true );
  2371. } else {
  2372. cp->Subdivide( DEFAULT_CURVE_MAX_ERROR_CD, DEFAULT_CURVE_MAX_ERROR_CD, DEFAULT_CURVE_MAX_LENGTH_CD, false );
  2373. }
  2374. // create collision polygons for the patch
  2375. CreatePatchPolygons( model, *cp, material, primitiveNum );
  2376. delete cp;
  2377. }
  2378. /*
  2379. ================
  2380. idCollisionModelManagerLocal::ConvertBrushSides
  2381. ================
  2382. */
  2383. void idCollisionModelManagerLocal::ConvertBrushSides( cm_model_t *model, const idMapBrush *mapBrush, int primitiveNum ) {
  2384. int i, j;
  2385. idMapBrushSide *mapSide;
  2386. idFixedWinding w;
  2387. idPlane *planes;
  2388. const idMaterial *material;
  2389. // fix degenerate planes
  2390. planes = (idPlane *) _alloca16( mapBrush->GetNumSides() * sizeof( planes[0] ) );
  2391. for ( i = 0; i < mapBrush->GetNumSides(); i++ ) {
  2392. planes[i] = mapBrush->GetSide(i)->GetPlane();
  2393. planes[i].FixDegeneracies( DEGENERATE_DIST_EPSILON );
  2394. }
  2395. // create a collision polygon for each brush side
  2396. for ( i = 0; i < mapBrush->GetNumSides(); i++ ) {
  2397. mapSide = mapBrush->GetSide(i);
  2398. material = declManager->FindMaterial( mapSide->GetMaterial() );
  2399. if ( !( material->GetContentFlags() & CONTENTS_REMOVE_UTIL ) ) {
  2400. continue;
  2401. }
  2402. w.BaseForPlane( -planes[i] );
  2403. for ( j = 0; j < mapBrush->GetNumSides() && w.GetNumPoints(); j++ ) {
  2404. if ( i == j ) {
  2405. continue;
  2406. }
  2407. w.ClipInPlace( -planes[j], 0 );
  2408. }
  2409. if ( w.GetNumPoints() ) {
  2410. PolygonFromWinding( model, &w, planes[i], material, primitiveNum );
  2411. }
  2412. }
  2413. }
  2414. /*
  2415. ================
  2416. idCollisionModelManagerLocal::ConvertBrush
  2417. ================
  2418. */
  2419. void idCollisionModelManagerLocal::ConvertBrush( cm_model_t *model, const idMapBrush *mapBrush, int primitiveNum ) {
  2420. int i, j, contents;
  2421. idBounds bounds;
  2422. idMapBrushSide *mapSide;
  2423. cm_brush_t *brush;
  2424. idPlane *planes;
  2425. idFixedWinding w;
  2426. const idMaterial *material = NULL;
  2427. contents = 0;
  2428. bounds.Clear();
  2429. // fix degenerate planes
  2430. planes = (idPlane *) _alloca16( mapBrush->GetNumSides() * sizeof( planes[0] ) );
  2431. for ( i = 0; i < mapBrush->GetNumSides(); i++ ) {
  2432. planes[i] = mapBrush->GetSide(i)->GetPlane();
  2433. planes[i].FixDegeneracies( DEGENERATE_DIST_EPSILON );
  2434. }
  2435. // we are only getting the bounds for the brush so there's no need
  2436. // to create a winding for the last brush side
  2437. for ( i = 0; i < mapBrush->GetNumSides() - 1; i++ ) {
  2438. mapSide = mapBrush->GetSide(i);
  2439. material = declManager->FindMaterial( mapSide->GetMaterial() );
  2440. contents |= ( material->GetContentFlags() & CONTENTS_REMOVE_UTIL );
  2441. w.BaseForPlane( -planes[i] );
  2442. for ( j = 0; j < mapBrush->GetNumSides() && w.GetNumPoints(); j++ ) {
  2443. if ( i == j ) {
  2444. continue;
  2445. }
  2446. w.ClipInPlace( -planes[j], 0 );
  2447. }
  2448. for ( j = 0; j < w.GetNumPoints(); j++ ) {
  2449. bounds.AddPoint( w[j].ToVec3() );
  2450. }
  2451. }
  2452. if ( !contents ) {
  2453. return;
  2454. }
  2455. // create brush for position test
  2456. brush = AllocBrush( model, mapBrush->GetNumSides() );
  2457. brush->checkcount = 0;
  2458. brush->contents = contents;
  2459. brush->material = material;
  2460. brush->primitiveNum = primitiveNum;
  2461. brush->bounds = bounds;
  2462. brush->numPlanes = mapBrush->GetNumSides();
  2463. for (i = 0; i < mapBrush->GetNumSides(); i++) {
  2464. brush->planes[i] = planes[i];
  2465. }
  2466. AddBrushToNode( model, model->node, brush );
  2467. }
  2468. /*
  2469. ================
  2470. CM_CountNodeBrushes
  2471. ================
  2472. */
  2473. static int CM_CountNodeBrushes( const cm_node_t *node ) {
  2474. int count;
  2475. cm_brushRef_t *bref;
  2476. count = 0;
  2477. for ( bref = node->brushes; bref; bref = bref->next ) {
  2478. count++;
  2479. }
  2480. return count;
  2481. }
  2482. /*
  2483. ================
  2484. CM_R_GetModelBounds
  2485. ================
  2486. */
  2487. static void CM_R_GetNodeBounds( idBounds *bounds, cm_node_t *node ) {
  2488. cm_polygonRef_t *pref;
  2489. cm_brushRef_t *bref;
  2490. while ( 1 ) {
  2491. for ( pref = node->polygons; pref; pref = pref->next ) {
  2492. bounds->AddPoint( pref->p->bounds[0] );
  2493. bounds->AddPoint( pref->p->bounds[1] );
  2494. }
  2495. for ( bref = node->brushes; bref; bref = bref->next ) {
  2496. bounds->AddPoint( bref->b->bounds[0] );
  2497. bounds->AddPoint( bref->b->bounds[1] );
  2498. }
  2499. if ( node->planeType == -1 ) {
  2500. break;
  2501. }
  2502. CM_R_GetNodeBounds( bounds, node->children[1] );
  2503. node = node->children[0];
  2504. }
  2505. }
  2506. /*
  2507. ================
  2508. CM_GetNodeBounds
  2509. ================
  2510. */
  2511. void CM_GetNodeBounds( idBounds *bounds, cm_node_t *node ) {
  2512. bounds->Clear();
  2513. CM_R_GetNodeBounds( bounds, node );
  2514. if ( bounds->IsCleared() ) {
  2515. bounds->Zero();
  2516. }
  2517. }
  2518. /*
  2519. ================
  2520. CM_GetNodeContents
  2521. ================
  2522. */
  2523. int CM_GetNodeContents( cm_node_t *node ) {
  2524. int contents;
  2525. cm_polygonRef_t *pref;
  2526. cm_brushRef_t *bref;
  2527. contents = 0;
  2528. while ( 1 ) {
  2529. for ( pref = node->polygons; pref; pref = pref->next ) {
  2530. contents |= pref->p->contents;
  2531. }
  2532. for ( bref = node->brushes; bref; bref = bref->next ) {
  2533. contents |= bref->b->contents;
  2534. }
  2535. if ( node->planeType == -1 ) {
  2536. break;
  2537. }
  2538. contents |= CM_GetNodeContents( node->children[1] );
  2539. node = node->children[0];
  2540. }
  2541. return contents;
  2542. }
  2543. /*
  2544. ==================
  2545. idCollisionModelManagerLocal::RemapEdges
  2546. ==================
  2547. */
  2548. void idCollisionModelManagerLocal::RemapEdges( cm_node_t *node, int *edgeRemap ) {
  2549. cm_polygonRef_t *pref;
  2550. cm_polygon_t *p;
  2551. int i;
  2552. while ( 1 ) {
  2553. for ( pref = node->polygons; pref; pref = pref->next ) {
  2554. p = pref->p;
  2555. // if we checked this polygon already
  2556. if ( p->checkcount == checkCount ) {
  2557. continue;
  2558. }
  2559. p->checkcount = checkCount;
  2560. for ( i = 0; i < p->numEdges; i++ ) {
  2561. if ( p->edges[i] < 0 ) {
  2562. p->edges[i] = -edgeRemap[ abs(p->edges[i]) ];
  2563. }
  2564. else {
  2565. p->edges[i] = edgeRemap[ p->edges[i] ];
  2566. }
  2567. }
  2568. }
  2569. if ( node->planeType == -1 ) {
  2570. break;
  2571. }
  2572. RemapEdges( node->children[1], edgeRemap );
  2573. node = node->children[0];
  2574. }
  2575. }
  2576. /*
  2577. ==================
  2578. idCollisionModelManagerLocal::OptimizeArrays
  2579. due to polygon merging and polygon removal the vertex and edge array
  2580. can have a lot of unused entries.
  2581. ==================
  2582. */
  2583. void idCollisionModelManagerLocal::OptimizeArrays( cm_model_t *model ) {
  2584. int i, newNumVertices, newNumEdges, *v;
  2585. int *remap;
  2586. cm_edge_t *oldEdges;
  2587. cm_vertex_t *oldVertices;
  2588. remap = (int *) Mem_ClearedAlloc( Max( model->numVertices, model->numEdges ) * sizeof( int ), TAG_COLLISION );
  2589. // get all used vertices
  2590. for ( i = 0; i < model->numEdges; i++ ) {
  2591. remap[ model->edges[i].vertexNum[0] ] = true;
  2592. remap[ model->edges[i].vertexNum[1] ] = true;
  2593. }
  2594. // create remap index and move vertices
  2595. newNumVertices = 0;
  2596. for ( i = 0; i < model->numVertices; i++ ) {
  2597. if ( remap[ i ] ) {
  2598. remap[ i ] = newNumVertices;
  2599. model->vertices[ newNumVertices ] = model->vertices[ i ];
  2600. newNumVertices++;
  2601. }
  2602. }
  2603. model->numVertices = newNumVertices;
  2604. // change edge vertex indexes
  2605. for ( i = 1; i < model->numEdges; i++ ) {
  2606. v = model->edges[i].vertexNum;
  2607. v[0] = remap[ v[0] ];
  2608. v[1] = remap[ v[1] ];
  2609. }
  2610. // create remap index and move edges
  2611. newNumEdges = 1;
  2612. for ( i = 1; i < model->numEdges; i++ ) {
  2613. // if the edge is used
  2614. if ( model->edges[ i ].numUsers ) {
  2615. remap[ i ] = newNumEdges;
  2616. model->edges[ newNumEdges ] = model->edges[ i ];
  2617. newNumEdges++;
  2618. }
  2619. }
  2620. // change polygon edge indexes
  2621. checkCount++;
  2622. RemapEdges( model->node, remap );
  2623. model->numEdges = newNumEdges;
  2624. Mem_Free( remap );
  2625. // realloc vertices
  2626. oldVertices = model->vertices;
  2627. model->maxVertices = model->numVertices;
  2628. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->numVertices * sizeof(cm_vertex_t), TAG_COLLISION );
  2629. if ( oldVertices ) {
  2630. memcpy( model->vertices, oldVertices, model->numVertices * sizeof(cm_vertex_t) );
  2631. Mem_Free( oldVertices );
  2632. }
  2633. // realloc edges
  2634. oldEdges = model->edges;
  2635. model->maxEdges = model->numEdges;
  2636. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->numEdges * sizeof(cm_edge_t), TAG_COLLISION );
  2637. if ( oldEdges ) {
  2638. memcpy( model->edges, oldEdges, model->numEdges * sizeof(cm_edge_t) );
  2639. Mem_Free( oldEdges );
  2640. }
  2641. }
  2642. /*
  2643. ================
  2644. idCollisionModelManagerLocal::FinishModel
  2645. ================
  2646. */
  2647. void idCollisionModelManagerLocal::FinishModel( cm_model_t *model ) {
  2648. // try to merge polygons
  2649. checkCount++;
  2650. MergeTreePolygons( model, model->node );
  2651. // find internal edges (no mesh can ever collide with internal edges)
  2652. checkCount++;
  2653. FindInternalEdges( model, model->node );
  2654. // calculate edge normals
  2655. checkCount++;
  2656. CalculateEdgeNormals( model, model->node );
  2657. //common->Printf( "%s vertex hash spread is %d\n", model->name.c_str(), cm_vertexHash->GetSpread() );
  2658. //common->Printf( "%s edge hash spread is %d\n", model->name.c_str(), cm_edgeHash->GetSpread() );
  2659. // remove all unused vertices and edges
  2660. OptimizeArrays( model );
  2661. // get model bounds from brush and polygon bounds
  2662. CM_GetNodeBounds( &model->bounds, model->node );
  2663. // get model contents
  2664. model->contents = CM_GetNodeContents( model->node );
  2665. // total memory used by this model
  2666. model->usedMemory = model->numVertices * sizeof(cm_vertex_t) +
  2667. model->numEdges * sizeof(cm_edge_t) +
  2668. model->polygonMemory +
  2669. model->brushMemory +
  2670. model->numNodes * sizeof(cm_node_t) +
  2671. model->numPolygonRefs * sizeof(cm_polygonRef_t) +
  2672. model->numBrushRefs * sizeof(cm_brushRef_t);
  2673. }
  2674. static const byte BCM_VERSION = 100;
  2675. static const unsigned int BCM_MAGIC = ( 'B' << 24 ) | ( 'C' << 16 ) | ( 'M' << 16 ) | BCM_VERSION;
  2676. /*
  2677. ================
  2678. idCollisionModelManagerLocal::LoadBinaryModel
  2679. ================
  2680. */
  2681. cm_model_t * idCollisionModelManagerLocal::LoadBinaryModelFromFile( idFile *file, ID_TIME_T sourceTimeStamp ) {
  2682. unsigned int magic = 0;
  2683. file->ReadBig( magic );
  2684. if ( magic != BCM_MAGIC ) {
  2685. return NULL;
  2686. }
  2687. ID_TIME_T storedTimeStamp = FILE_NOT_FOUND_TIMESTAMP;
  2688. file->ReadBig( storedTimeStamp );
  2689. if ( !fileSystem->InProductionMode() && storedTimeStamp != sourceTimeStamp ) {
  2690. return NULL;
  2691. }
  2692. cm_model_t * model = AllocModel();
  2693. file->ReadString( model->name );
  2694. file->ReadBig( model->bounds );
  2695. file->ReadBig( model->contents );
  2696. file->ReadBig( model->isConvex );
  2697. file->ReadBig( model->numVertices );
  2698. file->ReadBig( model->numEdges );
  2699. file->ReadBig( model->numPolygons );
  2700. file->ReadBig( model->numBrushes );
  2701. file->ReadBig( model->numNodes );
  2702. file->ReadBig( model->numBrushRefs );
  2703. file->ReadBig( model->numPolygonRefs );
  2704. file->ReadBig( model->numInternalEdges );
  2705. file->ReadBig( model->numSharpEdges );
  2706. file->ReadBig( model->numRemovedPolys );
  2707. file->ReadBig( model->numMergedPolys );
  2708. model->maxVertices = model->numVertices;
  2709. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->maxVertices * sizeof(cm_vertex_t), TAG_COLLISION );
  2710. for ( int i = 0; i < model->numVertices; i++ ) {
  2711. file->ReadBig( model->vertices[i].p );
  2712. file->ReadBig( model->vertices[i].checkcount );
  2713. file->ReadBig( model->vertices[i].side );
  2714. file->ReadBig( model->vertices[i].sideSet );
  2715. }
  2716. model->maxEdges = model->numEdges;
  2717. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->maxEdges * sizeof(cm_edge_t), TAG_COLLISION );
  2718. for ( int i = 0; i < model->numEdges; i++ ) {
  2719. file->ReadBig( model->edges[i].checkcount );
  2720. file->ReadBig( model->edges[i].internal );
  2721. file->ReadBig( model->edges[i].numUsers );
  2722. file->ReadBig( model->edges[i].side );
  2723. file->ReadBig( model->edges[i].sideSet );
  2724. file->ReadBig( model->edges[i].vertexNum[0] );
  2725. file->ReadBig( model->edges[i].vertexNum[1] );
  2726. file->ReadBig( model->edges[i].normal );
  2727. }
  2728. file->ReadBig( model->polygonMemory );
  2729. model->polygonBlock = (cm_polygonBlock_t *) Mem_ClearedAlloc( sizeof( cm_polygonBlock_t ) + model->polygonMemory, TAG_COLLISION );
  2730. model->polygonBlock->bytesRemaining = model->polygonMemory;
  2731. model->polygonBlock->next = ( (byte *) model->polygonBlock ) + sizeof( cm_polygonBlock_t );
  2732. file->ReadBig( model->brushMemory );
  2733. model->brushBlock = (cm_brushBlock_t *) Mem_ClearedAlloc( sizeof( cm_brushBlock_t ) + model->brushMemory, TAG_COLLISION );
  2734. model->brushBlock->bytesRemaining = model->brushMemory;
  2735. model->brushBlock->next = ( (byte *) model->brushBlock ) + sizeof( cm_brushBlock_t );
  2736. int numMaterials = 0;
  2737. file->ReadBig( numMaterials );
  2738. idList< const idMaterial * > materials;
  2739. materials.SetNum( numMaterials );
  2740. idStr materialName;
  2741. for ( int i = 0; i < materials.Num(); i++ ) {
  2742. file->ReadString( materialName );
  2743. if ( materialName.IsEmpty() ) {
  2744. materials[i] = NULL;
  2745. } else {
  2746. materials[i] = declManager->FindMaterial( materialName );
  2747. }
  2748. }
  2749. idList< cm_polygon_t * > polys;
  2750. idList< cm_brush_t * > brushes;
  2751. polys.SetNum( model->numPolygons );
  2752. brushes.SetNum( model->numBrushes );
  2753. for ( int i = 0; i < polys.Num(); i++ ) {
  2754. int materialIndex = 0;
  2755. file->ReadBig( materialIndex );
  2756. int numEdges = 0;
  2757. file->ReadBig( numEdges );
  2758. polys[i] = AllocPolygon( model, numEdges );
  2759. polys[i]->numEdges = numEdges;
  2760. polys[i]->material = materials[materialIndex];
  2761. file->ReadBig( polys[i]->bounds );
  2762. file->ReadBig( polys[i]->checkcount );
  2763. file->ReadBig( polys[i]->contents );
  2764. file->ReadBig( polys[i]->plane );
  2765. file->ReadBigArray( polys[i]->edges, polys[i]->numEdges );
  2766. }
  2767. for ( int i = 0; i < brushes.Num(); i++ ) {
  2768. int materialIndex = 0;
  2769. file->ReadBig( materialIndex );
  2770. int numPlanes = 0;
  2771. file->ReadBig( numPlanes );
  2772. brushes[i] = AllocBrush( model, numPlanes );
  2773. brushes[i]->numPlanes = numPlanes;
  2774. brushes[i]->material = materials[materialIndex];
  2775. file->ReadBig( brushes[i]->checkcount );
  2776. file->ReadBig( brushes[i]->bounds );
  2777. file->ReadBig( brushes[i]->contents );
  2778. file->ReadBig( brushes[i]->primitiveNum );
  2779. file->ReadBigArray( brushes[i]->planes, brushes[i]->numPlanes );
  2780. }
  2781. struct local {
  2782. static void ReadNodeTree( idFile * file, cm_model_t * model, cm_node_t * node, idList< cm_polygon_t * > & polys, idList< cm_brush_t * > & brushes ) {
  2783. file->ReadBig( node->planeType );
  2784. file->ReadBig( node->planeDist );
  2785. int i = 0;
  2786. while ( file->ReadBig( i ) == sizeof( i ) && ( i >= 0 ) ) {
  2787. cm_polygonRef_t * pref = collisionModelManagerLocal.AllocPolygonReference( model, model->numPolygonRefs );
  2788. pref->p = polys[i];
  2789. pref->next = node->polygons;
  2790. node->polygons = pref;
  2791. }
  2792. while ( file->ReadBig( i ) == sizeof( i ) && ( i >= 0 ) ) {
  2793. cm_brushRef_t * bref = collisionModelManagerLocal.AllocBrushReference( model, model->numBrushRefs );
  2794. bref->b = brushes[i];
  2795. bref->next = node->brushes;
  2796. node->brushes = bref;
  2797. }
  2798. if ( node->planeType != -1 ) {
  2799. node->children[0] = collisionModelManagerLocal.AllocNode( model, model->numNodes );
  2800. node->children[1] = collisionModelManagerLocal.AllocNode( model, model->numNodes );
  2801. node->children[0]->parent = node;
  2802. node->children[1]->parent = node;
  2803. ReadNodeTree( file, model, node->children[0], polys, brushes );
  2804. ReadNodeTree( file, model, node->children[1], polys, brushes );
  2805. }
  2806. }
  2807. };
  2808. model->node = AllocNode( model, model->numNodes + 1 );
  2809. local::ReadNodeTree( file, model, model->node, polys, brushes );
  2810. // We should have only allocated a single block, and used every entry in the block
  2811. // assert( model->nodeBlocks != NULL && model->nodeBlocks->next == NULL && model->nodeBlocks->nextNode == NULL );
  2812. assert( model->brushRefBlocks == NULL || ( model->brushRefBlocks->next == NULL && model->brushRefBlocks->nextRef == NULL ) );
  2813. assert( model->polygonRefBlocks == NULL || ( model->polygonRefBlocks->next == NULL && model->polygonRefBlocks->nextRef == NULL ) );
  2814. assert( model->polygonBlock->bytesRemaining == 0 );
  2815. assert( model->brushBlock->bytesRemaining == 0 );
  2816. model->usedMemory = model->numVertices * sizeof(cm_vertex_t) +
  2817. model->numEdges * sizeof(cm_edge_t) +
  2818. model->polygonMemory +
  2819. model->brushMemory +
  2820. model->numNodes * sizeof(cm_node_t) +
  2821. model->numPolygonRefs * sizeof(cm_polygonRef_t) +
  2822. model->numBrushRefs * sizeof(cm_brushRef_t);
  2823. return model;
  2824. }
  2825. /*
  2826. ================
  2827. idCollisionModelManagerLocal::LoadBinaryModel
  2828. ================
  2829. */
  2830. cm_model_t * idCollisionModelManagerLocal::LoadBinaryModel( const char *fileName, ID_TIME_T sourceTimeStamp ) {
  2831. idFileLocal file( fileSystem->OpenFileReadMemory( fileName ) );
  2832. if ( file == NULL ) {
  2833. return NULL;
  2834. }
  2835. return LoadBinaryModelFromFile( file, sourceTimeStamp );
  2836. }
  2837. /*
  2838. ================
  2839. idCollisionModelManagerLocal::WriteBinaryModel
  2840. ================
  2841. */
  2842. void idCollisionModelManagerLocal::WriteBinaryModelToFile( cm_model_t *model, idFile *file, ID_TIME_T sourceTimeStamp ) {
  2843. file->WriteBig( BCM_MAGIC );
  2844. file->WriteBig( sourceTimeStamp );
  2845. file->WriteString( model->name );
  2846. file->WriteBig( model->bounds );
  2847. file->WriteBig( model->contents );
  2848. file->WriteBig( model->isConvex );
  2849. file->WriteBig( model->numVertices );
  2850. file->WriteBig( model->numEdges );
  2851. file->WriteBig( model->numPolygons );
  2852. file->WriteBig( model->numBrushes );
  2853. file->WriteBig( model->numNodes );
  2854. file->WriteBig( model->numBrushRefs );
  2855. file->WriteBig( model->numPolygonRefs );
  2856. file->WriteBig( model->numInternalEdges );
  2857. file->WriteBig( model->numSharpEdges );
  2858. file->WriteBig( model->numRemovedPolys );
  2859. file->WriteBig( model->numMergedPolys );
  2860. for ( int i = 0; i < model->numVertices; i++ ) {
  2861. file->WriteBig( model->vertices[i].p );
  2862. file->WriteBig( model->vertices[i].checkcount );
  2863. file->WriteBig( model->vertices[i].side );
  2864. file->WriteBig( model->vertices[i].sideSet );
  2865. }
  2866. for ( int i = 0; i < model->numEdges; i++ ) {
  2867. file->WriteBig( model->edges[i].checkcount );
  2868. file->WriteBig( model->edges[i].internal );
  2869. file->WriteBig( model->edges[i].numUsers );
  2870. file->WriteBig( model->edges[i].side );
  2871. file->WriteBig( model->edges[i].sideSet );
  2872. file->WriteBig( model->edges[i].vertexNum[0] );
  2873. file->WriteBig( model->edges[i].vertexNum[1] );
  2874. file->WriteBig( model->edges[i].normal );
  2875. }
  2876. file->WriteBig( model->polygonMemory );
  2877. file->WriteBig( model->brushMemory );
  2878. struct local {
  2879. static void BuildUniqueLists( cm_node_t * node, idList< cm_polygon_t * > & polys, idList< cm_brush_t * > & brushes ) {
  2880. for ( cm_polygonRef_t * pr = node->polygons; pr != NULL; pr = pr->next ) {
  2881. polys.AddUnique( pr->p );
  2882. }
  2883. for ( cm_brushRef_t * br = node->brushes; br != NULL; br = br->next ) {
  2884. brushes.AddUnique( br->b );
  2885. }
  2886. if ( node->planeType != -1 ) {
  2887. BuildUniqueLists( node->children[0], polys, brushes );
  2888. BuildUniqueLists( node->children[1], polys, brushes );
  2889. }
  2890. }
  2891. static void WriteNodeTree( idFile * file, cm_node_t * node, idList< cm_polygon_t * > & polys, idList< cm_brush_t * > & brushes ) {
  2892. file->WriteBig( node->planeType );
  2893. file->WriteBig( node->planeDist );
  2894. for ( cm_polygonRef_t * pr = node->polygons; pr != NULL; pr = pr->next ) {
  2895. file->WriteBig( polys.FindIndex( pr->p ) );
  2896. }
  2897. file->WriteBig( -1 );
  2898. for ( cm_brushRef_t * br = node->brushes; br != NULL; br = br->next ) {
  2899. file->WriteBig( brushes.FindIndex( br->b ) );
  2900. }
  2901. file->WriteBig( -1 );
  2902. if ( node->planeType != -1 ) {
  2903. WriteNodeTree( file, node->children[0], polys, brushes );
  2904. WriteNodeTree( file, node->children[1], polys, brushes );
  2905. }
  2906. }
  2907. };
  2908. idList< cm_polygon_t * > polys;
  2909. idList< cm_brush_t * > brushes;
  2910. local::BuildUniqueLists( model->node, polys, brushes );
  2911. assert( polys.Num() == model->numPolygons );
  2912. assert( brushes.Num() == model->numBrushes );
  2913. idList< const idMaterial * > materials;
  2914. for ( int i = 0; i < polys.Num(); i++ ) {
  2915. materials.AddUnique( polys[i]->material );
  2916. }
  2917. for ( int i = 0; i < brushes.Num(); i++ ) {
  2918. materials.AddUnique( brushes[i]->material );
  2919. }
  2920. file->WriteBig( materials.Num() );
  2921. for ( int i = 0; i < materials.Num(); i++ ) {
  2922. if ( materials[i] == NULL ) {
  2923. file->WriteString( "" );
  2924. } else {
  2925. file->WriteString( materials[i]->GetName() );
  2926. }
  2927. }
  2928. for ( int i = 0; i < polys.Num(); i++ ) {
  2929. file->WriteBig( ( int )materials.FindIndex( polys[i]->material ) );
  2930. file->WriteBig( polys[i]->numEdges );
  2931. file->WriteBig( polys[i]->bounds );
  2932. file->WriteBig( polys[i]->checkcount );
  2933. file->WriteBig( polys[i]->contents );
  2934. file->WriteBig( polys[i]->plane );
  2935. file->WriteBigArray( polys[i]->edges, polys[i]->numEdges );
  2936. }
  2937. for ( int i = 0; i < brushes.Num(); i++ ) {
  2938. file->WriteBig( ( int )materials.FindIndex( brushes[i]->material ) );
  2939. file->WriteBig( brushes[i]->numPlanes );
  2940. file->WriteBig( brushes[i]->checkcount );
  2941. file->WriteBig( brushes[i]->bounds );
  2942. file->WriteBig( brushes[i]->contents );
  2943. file->WriteBig( brushes[i]->primitiveNum );
  2944. file->WriteBigArray( brushes[i]->planes, brushes[i]->numPlanes );
  2945. }
  2946. local::WriteNodeTree( file, model->node, polys, brushes );
  2947. }
  2948. /*
  2949. ================
  2950. idCollisionModelManagerLocal::WriteBinaryModel
  2951. ================
  2952. */
  2953. void idCollisionModelManagerLocal::WriteBinaryModel( cm_model_t *model, const char *fileName, ID_TIME_T sourceTimeStamp ) {
  2954. idFileLocal file( fileSystem->OpenFileWrite( fileName, "fs_basepath" ) );
  2955. if ( file == NULL ) {
  2956. common->Printf( "Failed to open %s\n", fileName );
  2957. return;
  2958. }
  2959. WriteBinaryModelToFile( model, file, sourceTimeStamp );
  2960. }
  2961. /*
  2962. ================
  2963. idCollisionModelManagerLocal::LoadRenderModel
  2964. ================
  2965. */
  2966. cm_model_t *idCollisionModelManagerLocal::LoadRenderModel( const char *fileName ) {
  2967. int i, j;
  2968. idRenderModel *renderModel;
  2969. const modelSurface_t *surf;
  2970. idFixedWinding w;
  2971. cm_node_t *node;
  2972. cm_model_t *model;
  2973. idPlane plane;
  2974. idBounds bounds;
  2975. bool collisionSurface;
  2976. idStr extension;
  2977. // only load ASE and LWO models
  2978. idStr( fileName ).ExtractFileExtension( extension );
  2979. if ( ( extension.Icmp( "ase" ) != 0 ) && ( extension.Icmp( "lwo" ) != 0 ) && ( extension.Icmp( "ma" ) != 0 ) ) {
  2980. return NULL;
  2981. }
  2982. renderModel = renderModelManager->CheckModel( fileName );
  2983. if ( !renderModel ) {
  2984. return NULL;
  2985. }
  2986. idStrStatic< MAX_OSPATH > generatedFileName = "generated/collision/";
  2987. generatedFileName.AppendPath( fileName );
  2988. generatedFileName.SetFileExtension( CMODEL_BINARYFILE_EXT );
  2989. ID_TIME_T sourceTimeStamp = renderModel->Timestamp();
  2990. model = LoadBinaryModel( generatedFileName, sourceTimeStamp );
  2991. if ( model != NULL ) {
  2992. return model;
  2993. }
  2994. idLib::Printf( "Writing %s\n", generatedFileName.c_str() );
  2995. model = AllocModel();
  2996. model->name = fileName;
  2997. node = AllocNode( model, NODE_BLOCK_SIZE_SMALL );
  2998. node->planeType = -1;
  2999. model->node = node;
  3000. model->maxVertices = 0;
  3001. model->numVertices = 0;
  3002. model->maxEdges = 0;
  3003. model->numEdges = 0;
  3004. bounds = renderModel->Bounds( NULL );
  3005. collisionSurface = false;
  3006. for ( i = 0; i < renderModel->NumSurfaces(); i++ ) {
  3007. surf = renderModel->Surface( i );
  3008. if ( surf->shader->GetSurfaceFlags() & SURF_COLLISION ) {
  3009. collisionSurface = true;
  3010. }
  3011. }
  3012. for ( i = 0; i < renderModel->NumSurfaces(); i++ ) {
  3013. surf = renderModel->Surface( i );
  3014. // if this surface has no contents
  3015. if ( ! ( surf->shader->GetContentFlags() & CONTENTS_REMOVE_UTIL ) ) {
  3016. continue;
  3017. }
  3018. // if the model has a collision surface and this surface is not a collision surface
  3019. if ( collisionSurface && !( surf->shader->GetSurfaceFlags() & SURF_COLLISION ) ) {
  3020. continue;
  3021. }
  3022. // get max verts and edges
  3023. model->maxVertices += surf->geometry->numVerts;
  3024. model->maxEdges += surf->geometry->numIndexes;
  3025. }
  3026. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->maxVertices * sizeof(cm_vertex_t), TAG_COLLISION );
  3027. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->maxEdges * sizeof(cm_edge_t), TAG_COLLISION );
  3028. // setup hash to speed up finding shared vertices and edges
  3029. SetupHash();
  3030. cm_vertexHash->ResizeIndex( model->maxVertices );
  3031. cm_edgeHash->ResizeIndex( model->maxEdges );
  3032. ClearHash( bounds );
  3033. for ( i = 0; i < renderModel->NumSurfaces(); i++ ) {
  3034. surf = renderModel->Surface( i );
  3035. // if this surface has no contents
  3036. if ( ! ( surf->shader->GetContentFlags() & CONTENTS_REMOVE_UTIL ) ) {
  3037. continue;
  3038. }
  3039. // if the model has a collision surface and this surface is not a collision surface
  3040. if ( collisionSurface && !( surf->shader->GetSurfaceFlags() & SURF_COLLISION ) ) {
  3041. continue;
  3042. }
  3043. for ( j = 0; j < surf->geometry->numIndexes; j += 3 ) {
  3044. w.Clear();
  3045. w += surf->geometry->verts[ surf->geometry->indexes[ j + 2 ] ].xyz;
  3046. w += surf->geometry->verts[ surf->geometry->indexes[ j + 1 ] ].xyz;
  3047. w += surf->geometry->verts[ surf->geometry->indexes[ j + 0 ] ].xyz;
  3048. w.GetPlane( plane );
  3049. plane = -plane;
  3050. PolygonFromWinding( model, &w, plane, surf->shader, 1 );
  3051. }
  3052. }
  3053. // create a BSP tree for the model
  3054. model->node = CreateAxialBSPTree( model, model->node );
  3055. model->isConvex = false;
  3056. FinishModel( model );
  3057. // shutdown the hash
  3058. ShutdownHash();
  3059. WriteBinaryModel( model, generatedFileName, sourceTimeStamp );
  3060. return model;
  3061. }
  3062. /*
  3063. ================
  3064. idCollisionModelManagerLocal::CollisionModelForMapEntity
  3065. ================
  3066. */
  3067. cm_model_t *idCollisionModelManagerLocal::CollisionModelForMapEntity( const idMapEntity *mapEnt ) {
  3068. cm_model_t *model;
  3069. idBounds bounds;
  3070. const char *name;
  3071. int i, brushCount;
  3072. // if the entity has no primitives
  3073. if ( mapEnt->GetNumPrimitives() < 1 ) {
  3074. return NULL;
  3075. }
  3076. // get a name for the collision model
  3077. mapEnt->epairs.GetString( "model", "", &name );
  3078. if ( !name[0] ) {
  3079. mapEnt->epairs.GetString( "name", "", &name );
  3080. if ( !name[0] ) {
  3081. if ( !numModels ) {
  3082. // first model is always the world
  3083. name = "worldMap";
  3084. }
  3085. else {
  3086. name = "unnamed inline model";
  3087. }
  3088. }
  3089. }
  3090. model = AllocModel();
  3091. model->node = AllocNode( model, NODE_BLOCK_SIZE_SMALL );
  3092. CM_EstimateVertsAndEdges( mapEnt, &model->maxVertices, &model->maxEdges );
  3093. model->numVertices = 0;
  3094. model->numEdges = 0;
  3095. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->maxVertices * sizeof(cm_vertex_t), TAG_COLLISION );
  3096. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->maxEdges * sizeof(cm_edge_t), TAG_COLLISION );
  3097. cm_vertexHash->ResizeIndex( model->maxVertices );
  3098. cm_edgeHash->ResizeIndex( model->maxEdges );
  3099. model->name = name;
  3100. model->isConvex = false;
  3101. // convert brushes
  3102. for ( i = 0; i < mapEnt->GetNumPrimitives(); i++ ) {
  3103. idMapPrimitive *mapPrim;
  3104. mapPrim = mapEnt->GetPrimitive(i);
  3105. if ( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
  3106. ConvertBrush( model, static_cast<idMapBrush*>(mapPrim), i );
  3107. continue;
  3108. }
  3109. }
  3110. // create an axial bsp tree for the model if it has more than just a bunch brushes
  3111. brushCount = CM_CountNodeBrushes( model->node );
  3112. if ( brushCount > 4 ) {
  3113. model->node = CreateAxialBSPTree( model, model->node );
  3114. } else {
  3115. model->node->planeType = -1;
  3116. }
  3117. // get bounds for hash
  3118. if ( brushCount ) {
  3119. CM_GetNodeBounds( &bounds, model->node );
  3120. } else {
  3121. bounds[0].Set( -256, -256, -256 );
  3122. bounds[1].Set( 256, 256, 256 );
  3123. }
  3124. // different models do not share edges and vertices with each other, so clear the hash
  3125. ClearHash( bounds );
  3126. // create polygons from patches and brushes
  3127. for ( i = 0; i < mapEnt->GetNumPrimitives(); i++ ) {
  3128. idMapPrimitive *mapPrim;
  3129. mapPrim = mapEnt->GetPrimitive(i);
  3130. if ( mapPrim->GetType() == idMapPrimitive::TYPE_PATCH ) {
  3131. ConvertPatch( model, static_cast<idMapPatch*>(mapPrim), i );
  3132. continue;
  3133. }
  3134. if ( mapPrim->GetType() == idMapPrimitive::TYPE_BRUSH ) {
  3135. ConvertBrushSides( model, static_cast<idMapBrush*>(mapPrim), i );
  3136. continue;
  3137. }
  3138. }
  3139. FinishModel( model );
  3140. return model;
  3141. }
  3142. /*
  3143. ================
  3144. idCollisionModelManagerLocal::FindModel
  3145. ================
  3146. */
  3147. cmHandle_t idCollisionModelManagerLocal::FindModel( const char *name ) {
  3148. int i;
  3149. // check if this model is already loaded
  3150. for ( i = 0; i < numModels; i++ ) {
  3151. if ( !models[i]->name.Icmp( name ) ) {
  3152. break;
  3153. }
  3154. }
  3155. // if the model is already loaded
  3156. if ( i < numModels ) {
  3157. return i;
  3158. }
  3159. return -1;
  3160. }
  3161. /*
  3162. ==================
  3163. idCollisionModelManagerLocal::PrintModelInfo
  3164. ==================
  3165. */
  3166. void idCollisionModelManagerLocal::PrintModelInfo( const cm_model_t *model ) {
  3167. common->Printf( "%6i vertices (%i KB)\n", model->numVertices, (model->numVertices * sizeof(cm_vertex_t))>>10 );
  3168. common->Printf( "%6i edges (%i KB)\n", model->numEdges, (model->numEdges * sizeof(cm_edge_t))>>10 );
  3169. common->Printf( "%6i polygons (%i KB)\n", model->numPolygons, model->polygonMemory>>10 );
  3170. common->Printf( "%6i brushes (%i KB)\n", model->numBrushes, model->brushMemory>>10 );
  3171. common->Printf( "%6i nodes (%i KB)\n", model->numNodes, (model->numNodes * sizeof(cm_node_t))>>10 );
  3172. common->Printf( "%6i polygon refs (%i KB)\n", model->numPolygonRefs, (model->numPolygonRefs * sizeof(cm_polygonRef_t))>>10 );
  3173. common->Printf( "%6i brush refs (%i KB)\n", model->numBrushRefs, (model->numBrushRefs * sizeof(cm_brushRef_t))>>10 );
  3174. common->Printf( "%6i internal edges\n", model->numInternalEdges );
  3175. common->Printf( "%6i sharp edges\n", model->numSharpEdges );
  3176. common->Printf( "%6i contained polygons removed\n", model->numRemovedPolys );
  3177. common->Printf( "%6i polygons merged\n", model->numMergedPolys );
  3178. common->Printf( "%6i KB total memory used\n", model->usedMemory>>10 );
  3179. }
  3180. /*
  3181. ================
  3182. idCollisionModelManagerLocal::AccumulateModelInfo
  3183. ================
  3184. */
  3185. void idCollisionModelManagerLocal::AccumulateModelInfo( cm_model_t *model ) {
  3186. int i;
  3187. memset( model, 0, sizeof( *model ) );
  3188. // accumulate statistics of all loaded models
  3189. for ( i = 0; i < numModels; i++ ) {
  3190. model->numVertices += models[i]->numVertices;
  3191. model->numEdges += models[i]->numEdges;
  3192. model->numPolygons += models[i]->numPolygons;
  3193. model->polygonMemory += models[i]->polygonMemory;
  3194. model->numBrushes += models[i]->numBrushes;
  3195. model->brushMemory += models[i]->brushMemory;
  3196. model->numNodes += models[i]->numNodes;
  3197. model->numBrushRefs += models[i]->numBrushRefs;
  3198. model->numPolygonRefs += models[i]->numPolygonRefs;
  3199. model->numInternalEdges += models[i]->numInternalEdges;
  3200. model->numSharpEdges += models[i]->numSharpEdges;
  3201. model->numRemovedPolys += models[i]->numRemovedPolys;
  3202. model->numMergedPolys += models[i]->numMergedPolys;
  3203. model->usedMemory += models[i]->usedMemory;
  3204. }
  3205. }
  3206. /*
  3207. ================
  3208. idCollisionModelManagerLocal::ModelInfo
  3209. ================
  3210. */
  3211. void idCollisionModelManagerLocal::ModelInfo( cmHandle_t model ) {
  3212. cm_model_t modelInfo;
  3213. if ( model == -1 ) {
  3214. AccumulateModelInfo( &modelInfo );
  3215. PrintModelInfo( &modelInfo );
  3216. return;
  3217. }
  3218. if ( model < 0 || model > MAX_SUBMODELS || model > maxModels ) {
  3219. common->Printf( "idCollisionModelManagerLocal::ModelInfo: invalid model handle\n" );
  3220. return;
  3221. }
  3222. if ( !models[model] ) {
  3223. common->Printf( "idCollisionModelManagerLocal::ModelInfo: invalid model\n" );
  3224. return;
  3225. }
  3226. PrintModelInfo( models[model] );
  3227. }
  3228. /*
  3229. ================
  3230. idCollisionModelManagerLocal::ListModels
  3231. ================
  3232. */
  3233. void idCollisionModelManagerLocal::ListModels() {
  3234. int i, totalMemory;
  3235. totalMemory = 0;
  3236. for ( i = 0; i < numModels; i++ ) {
  3237. common->Printf( "%4d: %5d KB %s\n", i, (models[i]->usedMemory>>10), models[i]->name.c_str() );
  3238. totalMemory += models[i]->usedMemory;
  3239. }
  3240. common->Printf( "%4d KB in %d models\n", (totalMemory>>10), numModels );
  3241. }
  3242. /*
  3243. ================
  3244. idCollisionModelManagerLocal::BuildModels
  3245. ================
  3246. */
  3247. void idCollisionModelManagerLocal::BuildModels( const idMapFile *mapFile ) {
  3248. int i;
  3249. const idMapEntity *mapEnt;
  3250. idTimer timer;
  3251. timer.Start();
  3252. if ( !LoadCollisionModelFile( mapFile->GetName(), mapFile->GetGeometryCRC() ) ) {
  3253. if ( !mapFile->GetNumEntities() ) {
  3254. return;
  3255. }
  3256. // load the .proc file bsp for data optimisation
  3257. LoadProcBSP( mapFile->GetName() );
  3258. // convert brushes and patches to collision data
  3259. for ( i = 0; i < mapFile->GetNumEntities(); i++ ) {
  3260. mapEnt = mapFile->GetEntity(i);
  3261. if ( numModels >= MAX_SUBMODELS ) {
  3262. common->Error( "idCollisionModelManagerLocal::BuildModels: more than %d collision models", MAX_SUBMODELS );
  3263. break;
  3264. }
  3265. models[numModels] = CollisionModelForMapEntity( mapEnt );
  3266. if ( models[ numModels] ) {
  3267. numModels++;
  3268. }
  3269. }
  3270. // free the proc bsp which is only used for data optimization
  3271. Mem_Free( procNodes );
  3272. procNodes = NULL;
  3273. // write the collision models to a file
  3274. WriteCollisionModelsToFile( mapFile->GetName(), 0, numModels, mapFile->GetGeometryCRC() );
  3275. }
  3276. timer.Stop();
  3277. // print statistics on collision data
  3278. cm_model_t model;
  3279. AccumulateModelInfo( &model );
  3280. common->Printf( "collision data:\n" );
  3281. common->Printf( "%6i models\n", numModels );
  3282. PrintModelInfo( &model );
  3283. common->Printf( "%.0f msec to load collision data.\n", timer.Milliseconds() );
  3284. }
  3285. /*
  3286. ================
  3287. idCollisionModelManagerLocal::Preload
  3288. ================
  3289. */
  3290. void idCollisionModelManagerLocal::Preload( const char *mapName ) {
  3291. if ( !preLoad_Collision.GetBool() ) {
  3292. return;
  3293. }
  3294. idStrStatic< MAX_OSPATH > manifestName = mapName;
  3295. manifestName.Replace( "game/", "maps/" );
  3296. manifestName.Replace( "maps/maps/", "maps/" );
  3297. manifestName.SetFileExtension( ".preload" );
  3298. idPreloadManifest manifest;
  3299. manifest.LoadManifest( manifestName );
  3300. if ( manifest.NumResources() >= 0 ) {
  3301. common->Printf( "Preloading collision models...\n" );
  3302. int start = Sys_Milliseconds();
  3303. int numLoaded = 0;
  3304. for ( int i = 0; i < manifest.NumResources(); i++ ) {
  3305. const preloadEntry_s & p = manifest.GetPreloadByIndex( i );
  3306. if ( p.resType == PRELOAD_COLLISION ) {
  3307. LoadModel( p.resourceName );
  3308. numLoaded++;
  3309. }
  3310. }
  3311. int end = Sys_Milliseconds();
  3312. common->Printf( "%05d collision models preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 );
  3313. common->Printf( "----------------------------------------\n" );
  3314. }
  3315. }
  3316. /*
  3317. ================
  3318. idCollisionModelManagerLocal::LoadMap
  3319. ================
  3320. */
  3321. void idCollisionModelManagerLocal::LoadMap( const idMapFile *mapFile ) {
  3322. if ( mapFile == NULL ) {
  3323. common->Error( "idCollisionModelManagerLocal::LoadMap: NULL mapFile" );
  3324. return;
  3325. }
  3326. // check whether we can keep the current collision map based on the mapName and mapFileTime
  3327. if ( loaded ) {
  3328. if ( mapName.Icmp( mapFile->GetName() ) == 0 ) {
  3329. if ( mapFile->GetFileTime() == mapFileTime ) {
  3330. common->DPrintf( "Using loaded version\n" );
  3331. return;
  3332. }
  3333. common->DPrintf( "Reloading modified map\n" );
  3334. }
  3335. FreeMap();
  3336. }
  3337. // clear the collision map
  3338. Clear();
  3339. // models
  3340. maxModels = MAX_SUBMODELS;
  3341. numModels = 0;
  3342. models = (cm_model_t **) Mem_ClearedAlloc( (maxModels+1) * sizeof(cm_model_t *), TAG_COLLISION );
  3343. // setup hash to speed up finding shared vertices and edges
  3344. SetupHash();
  3345. common->UpdateLevelLoadPacifier();
  3346. // setup trace model structure
  3347. SetupTrmModelStructure();
  3348. common->UpdateLevelLoadPacifier();
  3349. // build collision models
  3350. BuildModels( mapFile );
  3351. common->UpdateLevelLoadPacifier();
  3352. // save name and time stamp
  3353. mapName = mapFile->GetName();
  3354. mapFileTime = mapFile->GetFileTime();
  3355. loaded = true;
  3356. // shutdown the hash
  3357. ShutdownHash();
  3358. }
  3359. /*
  3360. ===================
  3361. idCollisionModelManagerLocal::GetModelName
  3362. ===================
  3363. */
  3364. const char *idCollisionModelManagerLocal::GetModelName( cmHandle_t model ) const {
  3365. if ( model < 0 || model > MAX_SUBMODELS || model >= numModels || !models[model] ) {
  3366. common->Printf( "idCollisionModelManagerLocal::GetModelBounds: invalid model handle\n" );
  3367. return "";
  3368. }
  3369. return models[model]->name.c_str();
  3370. }
  3371. /*
  3372. ===================
  3373. idCollisionModelManagerLocal::GetModelBounds
  3374. ===================
  3375. */
  3376. bool idCollisionModelManagerLocal::GetModelBounds( cmHandle_t model, idBounds &bounds ) const {
  3377. if ( model < 0 || model > MAX_SUBMODELS || model >= numModels || !models[model] ) {
  3378. common->Printf( "idCollisionModelManagerLocal::GetModelBounds: invalid model handle\n" );
  3379. return false;
  3380. }
  3381. bounds = models[model]->bounds;
  3382. return true;
  3383. }
  3384. /*
  3385. ===================
  3386. idCollisionModelManagerLocal::GetModelContents
  3387. ===================
  3388. */
  3389. bool idCollisionModelManagerLocal::GetModelContents( cmHandle_t model, int &contents ) const {
  3390. if ( model < 0 || model > MAX_SUBMODELS || model >= numModels || !models[model] ) {
  3391. common->Printf( "idCollisionModelManagerLocal::GetModelContents: invalid model handle\n" );
  3392. return false;
  3393. }
  3394. contents = models[model]->contents;
  3395. return true;
  3396. }
  3397. /*
  3398. ===================
  3399. idCollisionModelManagerLocal::GetModelVertex
  3400. ===================
  3401. */
  3402. bool idCollisionModelManagerLocal::GetModelVertex( cmHandle_t model, int vertexNum, idVec3 &vertex ) const {
  3403. if ( model < 0 || model > MAX_SUBMODELS || model >= numModels || !models[model] ) {
  3404. common->Printf( "idCollisionModelManagerLocal::GetModelVertex: invalid model handle\n" );
  3405. return false;
  3406. }
  3407. if ( vertexNum < 0 || vertexNum >= models[model]->numVertices ) {
  3408. common->Printf( "idCollisionModelManagerLocal::GetModelVertex: invalid vertex number\n" );
  3409. return false;
  3410. }
  3411. vertex = models[model]->vertices[vertexNum].p;
  3412. return true;
  3413. }
  3414. /*
  3415. ===================
  3416. idCollisionModelManagerLocal::GetModelEdge
  3417. ===================
  3418. */
  3419. bool idCollisionModelManagerLocal::GetModelEdge( cmHandle_t model, int edgeNum, idVec3 &start, idVec3 &end ) const {
  3420. if ( model < 0 || model > MAX_SUBMODELS || model >= numModels || !models[model] ) {
  3421. common->Printf( "idCollisionModelManagerLocal::GetModelEdge: invalid model handle\n" );
  3422. return false;
  3423. }
  3424. edgeNum = abs( edgeNum );
  3425. if ( edgeNum >= models[model]->numEdges ) {
  3426. common->Printf( "idCollisionModelManagerLocal::GetModelEdge: invalid edge number\n" );
  3427. return false;
  3428. }
  3429. start = models[model]->vertices[models[model]->edges[edgeNum].vertexNum[0]].p;
  3430. end = models[model]->vertices[models[model]->edges[edgeNum].vertexNum[1]].p;
  3431. return true;
  3432. }
  3433. /*
  3434. ===================
  3435. idCollisionModelManagerLocal::GetModelPolygon
  3436. ===================
  3437. */
  3438. bool idCollisionModelManagerLocal::GetModelPolygon( cmHandle_t model, int polygonNum, idFixedWinding &winding ) const {
  3439. int i, edgeNum;
  3440. cm_polygon_t *poly;
  3441. if ( model < 0 || model > MAX_SUBMODELS || model >= numModels || !models[model] ) {
  3442. common->Printf( "idCollisionModelManagerLocal::GetModelPolygon: invalid model handle\n" );
  3443. return false;
  3444. }
  3445. poly = *reinterpret_cast<cm_polygon_t **>(&polygonNum);
  3446. winding.Clear();
  3447. for ( i = 0; i < poly->numEdges; i++ ) {
  3448. edgeNum = poly->edges[i];
  3449. winding += models[model]->vertices[ models[model]->edges[abs(edgeNum)].vertexNum[INT32_SIGNBITSET(edgeNum)] ].p;
  3450. }
  3451. return true;
  3452. }
  3453. /*
  3454. ==================
  3455. idCollisionModelManagerLocal::LoadModel
  3456. ==================
  3457. */
  3458. cmHandle_t idCollisionModelManagerLocal::LoadModel( const char *modelName ) {
  3459. int handle;
  3460. handle = FindModel( modelName );
  3461. if ( handle >= 0 ) {
  3462. return handle;
  3463. }
  3464. if ( numModels >= MAX_SUBMODELS ) {
  3465. common->Error( "idCollisionModelManagerLocal::LoadModel: no free slots\n" );
  3466. return 0;
  3467. }
  3468. idStrStatic< MAX_OSPATH > generatedFileName = "generated/collision/";
  3469. generatedFileName.AppendPath( modelName );
  3470. generatedFileName.SetFileExtension( CMODEL_BINARYFILE_EXT );
  3471. ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( modelName );
  3472. models[ numModels ] = LoadBinaryModel( generatedFileName, sourceTimeStamp );
  3473. if ( models[ numModels ] != NULL ) {
  3474. numModels++;
  3475. if ( cvarSystem->GetCVarBool( "fs_buildresources" ) ) {
  3476. // for resource gathering write this model to the preload file for this map
  3477. fileSystem->AddCollisionPreload( modelName );
  3478. }
  3479. return ( numModels - 1 );
  3480. }
  3481. // try to load a .cm file
  3482. if ( LoadCollisionModelFile( modelName, 0 ) ) {
  3483. handle = FindModel( modelName );
  3484. if ( handle >= 0 && handle < numModels ) {
  3485. cm_model_t * cm = models[ handle ];
  3486. WriteBinaryModel( cm, generatedFileName, sourceTimeStamp );
  3487. return handle;
  3488. } else {
  3489. common->Warning( "idCollisionModelManagerLocal::LoadModel: collision file for '%s' contains different model", modelName );
  3490. }
  3491. }
  3492. // try to load a .ASE or .LWO model and convert it to a collision model
  3493. models[ numModels ] = LoadRenderModel( modelName );
  3494. if ( models[ numModels ] != NULL ) {
  3495. numModels++;
  3496. return ( numModels - 1 );
  3497. }
  3498. return 0;
  3499. }
  3500. /*
  3501. ==================
  3502. idCollisionModelManagerLocal::TrmFromModel_r
  3503. ==================
  3504. */
  3505. bool idCollisionModelManagerLocal::TrmFromModel_r( idTraceModel &trm, cm_node_t *node ) {
  3506. cm_polygonRef_t *pref;
  3507. cm_polygon_t *p;
  3508. int i;
  3509. while ( 1 ) {
  3510. for ( pref = node->polygons; pref; pref = pref->next ) {
  3511. p = pref->p;
  3512. if ( p->checkcount == checkCount ) {
  3513. continue;
  3514. }
  3515. p->checkcount = checkCount;
  3516. if ( trm.numPolys >= MAX_TRACEMODEL_POLYS ) {
  3517. return false;
  3518. }
  3519. // copy polygon properties
  3520. trm.polys[ trm.numPolys ].bounds = p->bounds;
  3521. trm.polys[ trm.numPolys ].normal = p->plane.Normal();
  3522. trm.polys[ trm.numPolys ].dist = p->plane.Dist();
  3523. trm.polys[ trm.numPolys ].numEdges = p->numEdges;
  3524. // copy edge index
  3525. for ( i = 0; i < p->numEdges; i++ ) {
  3526. trm.polys[ trm.numPolys ].edges[ i ] = p->edges[ i ];
  3527. }
  3528. trm.numPolys++;
  3529. }
  3530. if ( node->planeType == -1 ) {
  3531. break;
  3532. }
  3533. if ( !TrmFromModel_r( trm, node->children[1] ) ) {
  3534. return false;
  3535. }
  3536. node = node->children[0];
  3537. }
  3538. return true;
  3539. }
  3540. /*
  3541. ==================
  3542. idCollisionModelManagerLocal::TrmFromModel
  3543. NOTE: polygon merging can merge colinear edges and as such might cause dangling edges.
  3544. ==================
  3545. */
  3546. bool idCollisionModelManagerLocal::TrmFromModel( const cm_model_t *model, idTraceModel &trm ) {
  3547. int i, j, numEdgeUsers[MAX_TRACEMODEL_EDGES+1];
  3548. // if the model has too many vertices to fit in a trace model
  3549. if ( model->numVertices > MAX_TRACEMODEL_VERTS ) {
  3550. common->Printf( "idCollisionModelManagerLocal::TrmFromModel: model %s has too many vertices.\n", model->name.c_str() );
  3551. PrintModelInfo( model );
  3552. return false;
  3553. }
  3554. // plus one because the collision model accounts for the first unused edge
  3555. if ( model->numEdges > MAX_TRACEMODEL_EDGES+1 ) {
  3556. common->Printf( "idCollisionModelManagerLocal::TrmFromModel: model %s has too many edges.\n", model->name.c_str() );
  3557. PrintModelInfo( model );
  3558. return false;
  3559. }
  3560. trm.type = TRM_CUSTOM;
  3561. trm.numVerts = 0;
  3562. trm.numEdges = 1;
  3563. trm.numPolys = 0;
  3564. trm.bounds.Clear();
  3565. // copy polygons
  3566. checkCount++;
  3567. if ( !TrmFromModel_r( trm, model->node ) ) {
  3568. common->Printf( "idCollisionModelManagerLocal::TrmFromModel: model %s has too many polygons.\n", model->name.c_str() );
  3569. PrintModelInfo( model );
  3570. return false;
  3571. }
  3572. // copy vertices
  3573. for ( i = 0; i < model->numVertices; i++ ) {
  3574. trm.verts[ i ] = model->vertices[ i ].p;
  3575. trm.bounds.AddPoint( trm.verts[ i ] );
  3576. }
  3577. trm.numVerts = model->numVertices;
  3578. // copy edges
  3579. for ( i = 0; i < model->numEdges; i++ ) {
  3580. trm.edges[ i ].v[0] = model->edges[ i ].vertexNum[0];
  3581. trm.edges[ i ].v[1] = model->edges[ i ].vertexNum[1];
  3582. }
  3583. // minus one because the collision model accounts for the first unused edge
  3584. trm.numEdges = model->numEdges - 1;
  3585. // each edge should be used exactly twice
  3586. memset( numEdgeUsers, 0, sizeof(numEdgeUsers) );
  3587. for ( i = 0; i < trm.numPolys; i++ ) {
  3588. for ( j = 0; j < trm.polys[i].numEdges; j++ ) {
  3589. numEdgeUsers[ abs( trm.polys[i].edges[j] ) ]++;
  3590. }
  3591. }
  3592. for ( i = 1; i <= trm.numEdges; i++ ) {
  3593. if ( numEdgeUsers[i] != 2 ) {
  3594. common->Printf( "idCollisionModelManagerLocal::TrmFromModel: model %s has dangling edges, the model has to be an enclosed hull.\n", model->name.c_str() );
  3595. PrintModelInfo( model );
  3596. return false;
  3597. }
  3598. }
  3599. // assume convex
  3600. trm.isConvex = true;
  3601. // check if really convex
  3602. for ( i = 0; i < trm.numPolys; i++ ) {
  3603. // to be convex no vertices should be in front of any polygon plane
  3604. for ( j = 0; j < trm.numVerts; j++ ) {
  3605. if ( trm.polys[ i ].normal * trm.verts[ j ] - trm.polys[ i ].dist > 0.01f ) {
  3606. trm.isConvex = false;
  3607. break;
  3608. }
  3609. }
  3610. if ( j < trm.numVerts ) {
  3611. break;
  3612. }
  3613. }
  3614. // offset to center of model
  3615. trm.offset = trm.bounds.GetCenter();
  3616. trm.GenerateEdgeNormals();
  3617. return true;
  3618. }
  3619. /*
  3620. ==================
  3621. idCollisionModelManagerLocal::TrmFromModel
  3622. ==================
  3623. */
  3624. bool idCollisionModelManagerLocal::TrmFromModel( const char *modelName, idTraceModel &trm ) {
  3625. cmHandle_t handle;
  3626. handle = LoadModel( modelName );
  3627. if ( !handle ) {
  3628. common->Printf( "idCollisionModelManagerLocal::TrmFromModel: model %s not found.\n", modelName );
  3629. return false;
  3630. }
  3631. return TrmFromModel( models[ handle ], trm );
  3632. }