BrittleFracture.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. CLASS_DECLARATION( idEntity, idBrittleFracture )
  24. EVENT( EV_Activate, idBrittleFracture::Event_Activate )
  25. EVENT( EV_Touch, idBrittleFracture::Event_Touch )
  26. END_CLASS
  27. const int SHARD_ALIVE_TIME = 10000;
  28. const int SHARD_FADE_START = 2000;
  29. static const char *brittleFracture_SnapshotName = "_BrittleFracture_Snapshot_";
  30. /*
  31. ================
  32. idBrittleFracture::idBrittleFracture
  33. ================
  34. */
  35. idBrittleFracture::idBrittleFracture( void ) {
  36. material = NULL;
  37. decalMaterial = NULL;
  38. decalSize = 0.0f;
  39. maxShardArea = 0.0f;
  40. maxShatterRadius = 0.0f;
  41. minShatterRadius = 0.0f;
  42. linearVelocityScale = 0.0f;
  43. angularVelocityScale = 0.0f;
  44. shardMass = 0.0f;
  45. density = 0.0f;
  46. friction = 0.0f;
  47. bouncyness = 0.0f;
  48. fxFracture.Clear();
  49. bounds.Clear();
  50. disableFracture = false;
  51. lastRenderEntityUpdate = -1;
  52. changed = false;
  53. fl.networkSync = true;
  54. firedTargets = false;
  55. #ifdef _D3XP
  56. isXraySurface = false;
  57. #endif
  58. }
  59. /*
  60. ================
  61. idBrittleFracture::~idBrittleFracture
  62. ================
  63. */
  64. idBrittleFracture::~idBrittleFracture( void ) {
  65. int i;
  66. for ( i = 0; i < shards.Num(); i++ ) {
  67. shards[i]->decals.DeleteContents( true );
  68. delete shards[i];
  69. }
  70. // make sure the render entity is freed before the model is freed
  71. FreeModelDef();
  72. renderModelManager->FreeModel( renderEntity.hModel );
  73. }
  74. /*
  75. ================
  76. idBrittleFracture::Save
  77. ================
  78. */
  79. void idBrittleFracture::Save( idSaveGame *savefile ) const {
  80. int i, j;
  81. savefile->WriteInt( health );
  82. entityFlags_s flags = fl;
  83. LittleBitField( &flags, sizeof( flags ) );
  84. savefile->Write( &flags, sizeof( flags ) );
  85. // setttings
  86. savefile->WriteMaterial( material );
  87. savefile->WriteMaterial( decalMaterial );
  88. savefile->WriteFloat( decalSize );
  89. savefile->WriteFloat( maxShardArea );
  90. savefile->WriteFloat( maxShatterRadius );
  91. savefile->WriteFloat( minShatterRadius );
  92. savefile->WriteFloat( linearVelocityScale );
  93. savefile->WriteFloat( angularVelocityScale );
  94. savefile->WriteFloat( shardMass );
  95. savefile->WriteFloat( density );
  96. savefile->WriteFloat( friction );
  97. savefile->WriteFloat( bouncyness );
  98. savefile->WriteString( fxFracture );
  99. // state
  100. savefile->WriteBounds( bounds );
  101. savefile->WriteBool( disableFracture );
  102. savefile->WriteInt( lastRenderEntityUpdate );
  103. savefile->WriteBool( changed );
  104. savefile->WriteStaticObject( physicsObj );
  105. savefile->WriteInt( shards.Num() );
  106. for ( i = 0; i < shards.Num(); i++ ) {
  107. savefile->WriteWinding( shards[i]->winding );
  108. savefile->WriteInt( shards[i]->decals.Num() );
  109. for ( j = 0; j < shards[i]->decals.Num(); j++ ) {
  110. savefile->WriteWinding( *shards[i]->decals[j] );
  111. }
  112. savefile->WriteInt( shards[i]->neighbours.Num() );
  113. for ( j = 0; j < shards[i]->neighbours.Num(); j++ ) {
  114. int index = shards.FindIndex(shards[i]->neighbours[j]);
  115. assert(index != -1);
  116. savefile->WriteInt( index );
  117. }
  118. savefile->WriteInt( shards[i]->edgeHasNeighbour.Num() );
  119. for ( j = 0; j < shards[i]->edgeHasNeighbour.Num(); j++ ) {
  120. savefile->WriteBool( shards[i]->edgeHasNeighbour[j] );
  121. }
  122. savefile->WriteInt( shards[i]->droppedTime );
  123. savefile->WriteInt( shards[i]->islandNum );
  124. savefile->WriteBool( shards[i]->atEdge );
  125. savefile->WriteStaticObject( shards[i]->physicsObj );
  126. }
  127. #ifdef _D3XP
  128. savefile->WriteBool( isXraySurface );
  129. #endif
  130. }
  131. /*
  132. ================
  133. idBrittleFracture::Restore
  134. ================
  135. */
  136. void idBrittleFracture::Restore( idRestoreGame *savefile ) {
  137. int i, j , num;
  138. renderEntity.hModel = renderModelManager->AllocModel();
  139. renderEntity.hModel->InitEmpty( brittleFracture_SnapshotName );
  140. renderEntity.callback = idBrittleFracture::ModelCallback;
  141. renderEntity.noShadow = true;
  142. renderEntity.noSelfShadow = true;
  143. renderEntity.noDynamicInteractions = false;
  144. savefile->ReadInt( health );
  145. savefile->Read( &fl, sizeof( fl ) );
  146. LittleBitField( &fl, sizeof( fl ) );
  147. // setttings
  148. savefile->ReadMaterial( material );
  149. savefile->ReadMaterial( decalMaterial );
  150. savefile->ReadFloat( decalSize );
  151. savefile->ReadFloat( maxShardArea );
  152. savefile->ReadFloat( maxShatterRadius );
  153. savefile->ReadFloat( minShatterRadius );
  154. savefile->ReadFloat( linearVelocityScale );
  155. savefile->ReadFloat( angularVelocityScale );
  156. savefile->ReadFloat( shardMass );
  157. savefile->ReadFloat( density );
  158. savefile->ReadFloat( friction );
  159. savefile->ReadFloat( bouncyness );
  160. savefile->ReadString( fxFracture );
  161. // state
  162. savefile->ReadBounds(bounds);
  163. savefile->ReadBool( disableFracture );
  164. savefile->ReadInt( lastRenderEntityUpdate );
  165. savefile->ReadBool( changed );
  166. savefile->ReadStaticObject( physicsObj );
  167. RestorePhysics( &physicsObj );
  168. savefile->ReadInt( num );
  169. shards.SetNum( num );
  170. for ( i = 0; i < num; i++ ) {
  171. shards[i] = new shard_t;
  172. }
  173. for ( i = 0; i < num; i++ ) {
  174. savefile->ReadWinding( shards[i]->winding );
  175. savefile->ReadInt( j );
  176. shards[i]->decals.SetNum( j );
  177. for ( j = 0; j < shards[i]->decals.Num(); j++ ) {
  178. shards[i]->decals[j] = new idFixedWinding;
  179. savefile->ReadWinding( *shards[i]->decals[j] );
  180. }
  181. savefile->ReadInt( j );
  182. shards[i]->neighbours.SetNum( j );
  183. for ( j = 0; j < shards[i]->neighbours.Num(); j++ ) {
  184. int index;
  185. savefile->ReadInt( index );
  186. assert(index != -1);
  187. shards[i]->neighbours[j] = shards[index];
  188. }
  189. savefile->ReadInt( j );
  190. shards[i]->edgeHasNeighbour.SetNum( j );
  191. for ( j = 0; j < shards[i]->edgeHasNeighbour.Num(); j++ ) {
  192. savefile->ReadBool( shards[i]->edgeHasNeighbour[j] );
  193. }
  194. savefile->ReadInt( shards[i]->droppedTime );
  195. savefile->ReadInt( shards[i]->islandNum );
  196. savefile->ReadBool( shards[i]->atEdge );
  197. savefile->ReadStaticObject( shards[i]->physicsObj );
  198. if ( shards[i]->droppedTime < 0 ) {
  199. shards[i]->clipModel = physicsObj.GetClipModel( i );
  200. } else {
  201. shards[i]->clipModel = shards[i]->physicsObj.GetClipModel();
  202. }
  203. }
  204. #ifdef _D3XP
  205. savefile->ReadBool( isXraySurface );
  206. #endif
  207. }
  208. /*
  209. ================
  210. idBrittleFracture::Spawn
  211. ================
  212. */
  213. void idBrittleFracture::Spawn( void ) {
  214. // get shard properties
  215. decalMaterial = declManager->FindMaterial( spawnArgs.GetString( "mtr_decal" ) );
  216. decalSize = spawnArgs.GetFloat( "decalSize", "40" );
  217. maxShardArea = spawnArgs.GetFloat( "maxShardArea", "600" ); //shard size.
  218. maxShardArea = idMath::ClampFloat( 100, 10000, maxShardArea );
  219. maxShatterRadius = spawnArgs.GetFloat( "maxShatterRadius", "60" ); //destruction radius
  220. minShatterRadius = spawnArgs.GetFloat( "minShatterRadius", "20" );
  221. linearVelocityScale = spawnArgs.GetFloat( "linearVelocityScale", "0.1" );
  222. angularVelocityScale = spawnArgs.GetFloat( "angularVelocityScale", "40" );
  223. fxFracture = spawnArgs.GetString( "fx" );
  224. // get rigid body properties
  225. shardMass = spawnArgs.GetFloat( "shardMass", "20" );
  226. shardMass = idMath::ClampFloat( 0.001f, 1000.0f, shardMass );
  227. spawnArgs.GetFloat( "density", "0.1", density );
  228. density = idMath::ClampFloat( 0.001f, 1000.0f, density );
  229. spawnArgs.GetFloat( "friction", "0.4", friction );
  230. friction = idMath::ClampFloat( 0.0f, 1.0f, friction );
  231. spawnArgs.GetFloat( "bouncyness", "0.01", bouncyness );
  232. bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness );
  233. disableFracture = spawnArgs.GetBool( "disableFracture", "0" );
  234. health = spawnArgs.GetInt( "health", "40" );
  235. fl.takedamage = true;
  236. // FIXME: set "bleed" so idProjectile calls AddDamageEffect
  237. spawnArgs.SetBool( "bleed", 1 );
  238. #ifdef _D3XP
  239. // check for xray surface
  240. if ( 1 ) {
  241. const idRenderModel *model = renderEntity.hModel;
  242. isXraySurface = false;
  243. for ( int i = 0; i < model->NumSurfaces(); i++ ) {
  244. const modelSurface_t *surf = model->Surface( i );
  245. if ( idStr( surf->shader->GetName() ) == "textures/smf/window_scratch" ) {
  246. isXraySurface = true;
  247. break;
  248. }
  249. }
  250. }
  251. #endif
  252. CreateFractures( renderEntity.hModel );
  253. FindNeighbours();
  254. renderEntity.hModel = renderModelManager->AllocModel();
  255. renderEntity.hModel->InitEmpty( brittleFracture_SnapshotName );
  256. renderEntity.callback = idBrittleFracture::ModelCallback;
  257. renderEntity.noShadow = true;
  258. renderEntity.noSelfShadow = true;
  259. renderEntity.noDynamicInteractions = false;
  260. }
  261. /*
  262. ================
  263. idBrittleFracture::AddShard
  264. ================
  265. */
  266. void idBrittleFracture::AddShard( idClipModel *clipModel, idFixedWinding &w ) {
  267. shard_t *shard = new shard_t;
  268. shard->clipModel = clipModel;
  269. shard->droppedTime = -1;
  270. shard->winding = w;
  271. shard->decals.Clear();
  272. shard->edgeHasNeighbour.AssureSize( w.GetNumPoints(), false );
  273. shard->neighbours.Clear();
  274. shard->atEdge = false;
  275. shards.Append( shard );
  276. }
  277. /*
  278. ================
  279. idBrittleFracture::RemoveShard
  280. ================
  281. */
  282. void idBrittleFracture::RemoveShard( int index ) {
  283. int i;
  284. delete shards[index];
  285. shards.RemoveIndex( index );
  286. physicsObj.RemoveIndex( index );
  287. for ( i = index; i < shards.Num(); i++ ) {
  288. shards[i]->clipModel->SetId( i );
  289. }
  290. }
  291. /*
  292. ================
  293. idBrittleFracture::UpdateRenderEntity
  294. ================
  295. */
  296. bool idBrittleFracture::UpdateRenderEntity( renderEntity_s *renderEntity, const renderView_t *renderView ) const {
  297. int i, j, k, n, msec, numTris, numDecalTris;
  298. float fade;
  299. dword packedColor;
  300. srfTriangles_t *tris, *decalTris;
  301. modelSurface_t surface;
  302. idDrawVert *v;
  303. idPlane plane;
  304. idMat3 tangents;
  305. // this may be triggered by a model trace or other non-view related source,
  306. // to which we should look like an empty model
  307. if ( !renderView ) {
  308. return false;
  309. }
  310. // don't regenerate it if it is current
  311. if ( lastRenderEntityUpdate == gameLocal.time || !changed ) {
  312. return false;
  313. }
  314. lastRenderEntityUpdate = gameLocal.time;
  315. changed = false;
  316. numTris = 0;
  317. numDecalTris = 0;
  318. for ( i = 0; i < shards.Num(); i++ ) {
  319. n = shards[i]->winding.GetNumPoints();
  320. if ( n > 2 ) {
  321. numTris += n - 2;
  322. }
  323. for ( k = 0; k < shards[i]->decals.Num(); k++ ) {
  324. n = shards[i]->decals[k]->GetNumPoints();
  325. if ( n > 2 ) {
  326. numDecalTris += n - 2;
  327. }
  328. }
  329. }
  330. // FIXME: re-use model surfaces
  331. renderEntity->hModel->InitEmpty( brittleFracture_SnapshotName );
  332. // allocate triangle surfaces for the fractures and decals
  333. tris = renderEntity->hModel->AllocSurfaceTriangles( numTris * 3, material->ShouldCreateBackSides() ? numTris * 6 : numTris * 3 );
  334. decalTris = renderEntity->hModel->AllocSurfaceTriangles( numDecalTris * 3, decalMaterial->ShouldCreateBackSides() ? numDecalTris * 6 : numDecalTris * 3 );
  335. for ( i = 0; i < shards.Num(); i++ ) {
  336. const idVec3 &origin = shards[i]->clipModel->GetOrigin();
  337. const idMat3 &axis = shards[i]->clipModel->GetAxis();
  338. fade = 1.0f;
  339. if ( shards[i]->droppedTime >= 0 ) {
  340. msec = gameLocal.time - shards[i]->droppedTime - SHARD_FADE_START;
  341. if ( msec > 0 ) {
  342. fade = 1.0f - (float) msec / ( SHARD_ALIVE_TIME - SHARD_FADE_START );
  343. }
  344. }
  345. packedColor = PackColor( idVec4( renderEntity->shaderParms[ SHADERPARM_RED ] * fade,
  346. renderEntity->shaderParms[ SHADERPARM_GREEN ] * fade,
  347. renderEntity->shaderParms[ SHADERPARM_BLUE ] * fade,
  348. fade ) );
  349. const idWinding &winding = shards[i]->winding;
  350. winding.GetPlane( plane );
  351. tangents = ( plane.Normal() * axis ).ToMat3();
  352. for ( j = 2; j < winding.GetNumPoints(); j++ ) {
  353. v = &tris->verts[tris->numVerts++];
  354. v->Clear();
  355. v->xyz = origin + winding[0].ToVec3() * axis;
  356. v->st[0] = winding[0].s;
  357. v->st[1] = winding[0].t;
  358. v->normal = tangents[0];
  359. v->tangents[0] = tangents[1];
  360. v->tangents[1] = tangents[2];
  361. v->SetColor( packedColor );
  362. v = &tris->verts[tris->numVerts++];
  363. v->Clear();
  364. v->xyz = origin + winding[j-1].ToVec3() * axis;
  365. v->st[0] = winding[j-1].s;
  366. v->st[1] = winding[j-1].t;
  367. v->normal = tangents[0];
  368. v->tangents[0] = tangents[1];
  369. v->tangents[1] = tangents[2];
  370. v->SetColor( packedColor );
  371. v = &tris->verts[tris->numVerts++];
  372. v->Clear();
  373. v->xyz = origin + winding[j].ToVec3() * axis;
  374. v->st[0] = winding[j].s;
  375. v->st[1] = winding[j].t;
  376. v->normal = tangents[0];
  377. v->tangents[0] = tangents[1];
  378. v->tangents[1] = tangents[2];
  379. v->SetColor( packedColor );
  380. tris->indexes[tris->numIndexes++] = tris->numVerts - 3;
  381. tris->indexes[tris->numIndexes++] = tris->numVerts - 2;
  382. tris->indexes[tris->numIndexes++] = tris->numVerts - 1;
  383. if ( material->ShouldCreateBackSides() ) {
  384. tris->indexes[tris->numIndexes++] = tris->numVerts - 2;
  385. tris->indexes[tris->numIndexes++] = tris->numVerts - 3;
  386. tris->indexes[tris->numIndexes++] = tris->numVerts - 1;
  387. }
  388. }
  389. for ( k = 0; k < shards[i]->decals.Num(); k++ ) {
  390. const idWinding &decalWinding = *shards[i]->decals[k];
  391. for ( j = 2; j < decalWinding.GetNumPoints(); j++ ) {
  392. v = &decalTris->verts[decalTris->numVerts++];
  393. v->Clear();
  394. v->xyz = origin + decalWinding[0].ToVec3() * axis;
  395. v->st[0] = decalWinding[0].s;
  396. v->st[1] = decalWinding[0].t;
  397. v->normal = tangents[0];
  398. v->tangents[0] = tangents[1];
  399. v->tangents[1] = tangents[2];
  400. v->SetColor( packedColor );
  401. v = &decalTris->verts[decalTris->numVerts++];
  402. v->Clear();
  403. v->xyz = origin + decalWinding[j-1].ToVec3() * axis;
  404. v->st[0] = decalWinding[j-1].s;
  405. v->st[1] = decalWinding[j-1].t;
  406. v->normal = tangents[0];
  407. v->tangents[0] = tangents[1];
  408. v->tangents[1] = tangents[2];
  409. v->SetColor( packedColor );
  410. v = &decalTris->verts[decalTris->numVerts++];
  411. v->Clear();
  412. v->xyz = origin + decalWinding[j].ToVec3() * axis;
  413. v->st[0] = decalWinding[j].s;
  414. v->st[1] = decalWinding[j].t;
  415. v->normal = tangents[0];
  416. v->tangents[0] = tangents[1];
  417. v->tangents[1] = tangents[2];
  418. v->SetColor( packedColor );
  419. decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 3;
  420. decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 2;
  421. decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 1;
  422. if ( decalMaterial->ShouldCreateBackSides() ) {
  423. decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 2;
  424. decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 3;
  425. decalTris->indexes[decalTris->numIndexes++] = decalTris->numVerts - 1;
  426. }
  427. }
  428. }
  429. }
  430. tris->tangentsCalculated = true;
  431. decalTris->tangentsCalculated = true;
  432. SIMDProcessor->MinMax( tris->bounds[0], tris->bounds[1], tris->verts, tris->numVerts );
  433. SIMDProcessor->MinMax( decalTris->bounds[0], decalTris->bounds[1], decalTris->verts, decalTris->numVerts );
  434. memset( &surface, 0, sizeof( surface ) );
  435. surface.shader = material;
  436. surface.id = 0;
  437. surface.geometry = tris;
  438. renderEntity->hModel->AddSurface( surface );
  439. memset( &surface, 0, sizeof( surface ) );
  440. surface.shader = decalMaterial;
  441. surface.id = 1;
  442. surface.geometry = decalTris;
  443. renderEntity->hModel->AddSurface( surface );
  444. return true;
  445. }
  446. /*
  447. ================
  448. idBrittleFracture::ModelCallback
  449. ================
  450. */
  451. bool idBrittleFracture::ModelCallback( renderEntity_s *renderEntity, const renderView_t *renderView ) {
  452. const idBrittleFracture *ent;
  453. ent = static_cast<idBrittleFracture *>(gameLocal.entities[ renderEntity->entityNum ]);
  454. if ( !ent ) {
  455. gameLocal.Error( "idBrittleFracture::ModelCallback: callback with NULL game entity" );
  456. }
  457. return ent->UpdateRenderEntity( renderEntity, renderView );
  458. }
  459. /*
  460. ================
  461. idBrittleFracture::Present
  462. ================
  463. */
  464. void idBrittleFracture::Present() {
  465. // don't present to the renderer if the entity hasn't changed
  466. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  467. return;
  468. }
  469. BecomeInactive( TH_UPDATEVISUALS );
  470. renderEntity.bounds = bounds;
  471. renderEntity.origin.Zero();
  472. renderEntity.axis.Identity();
  473. // force an update because the bounds/origin/axis may stay the same while the model changes
  474. renderEntity.forceUpdate = true;
  475. // add to refresh list
  476. if ( modelDefHandle == -1 ) {
  477. modelDefHandle = gameRenderWorld->AddEntityDef( &renderEntity );
  478. } else {
  479. gameRenderWorld->UpdateEntityDef( modelDefHandle, &renderEntity );
  480. }
  481. changed = true;
  482. }
  483. /*
  484. ================
  485. idBrittleFracture::Think
  486. ================
  487. */
  488. void idBrittleFracture::Think( void ) {
  489. int i, startTime, endTime, droppedTime;
  490. shard_t *shard;
  491. bool atRest = true, fading = false;
  492. // remove overdue shards
  493. for ( i = 0; i < shards.Num(); i++ ) {
  494. droppedTime = shards[i]->droppedTime;
  495. if ( droppedTime != -1 ) {
  496. if ( gameLocal.time - droppedTime > SHARD_ALIVE_TIME ) {
  497. RemoveShard( i );
  498. i--;
  499. }
  500. fading = true;
  501. }
  502. }
  503. // remove the entity when nothing is visible
  504. if ( !shards.Num() ) {
  505. PostEventMS( &EV_Remove, 0 );
  506. return;
  507. }
  508. if ( thinkFlags & TH_PHYSICS ) {
  509. startTime = gameLocal.previousTime;
  510. endTime = gameLocal.time;
  511. // run physics on shards
  512. for ( i = 0; i < shards.Num(); i++ ) {
  513. shard = shards[i];
  514. if ( shard->droppedTime == -1 ) {
  515. continue;
  516. }
  517. shard->physicsObj.Evaluate( endTime - startTime, endTime );
  518. if ( !shard->physicsObj.IsAtRest() ) {
  519. atRest = false;
  520. }
  521. }
  522. if ( atRest ) {
  523. BecomeInactive( TH_PHYSICS );
  524. } else {
  525. BecomeActive( TH_PHYSICS );
  526. }
  527. }
  528. if ( !atRest || bounds.IsCleared() ) {
  529. bounds.Clear();
  530. for ( i = 0; i < shards.Num(); i++ ) {
  531. bounds.AddBounds( shards[i]->clipModel->GetAbsBounds() );
  532. }
  533. }
  534. if ( fading ) {
  535. BecomeActive( TH_UPDATEVISUALS | TH_THINK );
  536. } else {
  537. BecomeInactive( TH_THINK );
  538. }
  539. RunPhysics();
  540. Present();
  541. }
  542. /*
  543. ================
  544. idBrittleFracture::ApplyImpulse
  545. ================
  546. */
  547. void idBrittleFracture::ApplyImpulse( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse ) {
  548. if ( id < 0 || id >= shards.Num() ) {
  549. return;
  550. }
  551. if ( shards[id]->droppedTime != -1 ) {
  552. shards[id]->physicsObj.ApplyImpulse( 0, point, impulse );
  553. } else if ( health <= 0 && !disableFracture ) {
  554. Shatter( point, impulse, gameLocal.time );
  555. }
  556. }
  557. /*
  558. ================
  559. idBrittleFracture::AddForce
  560. ================
  561. */
  562. void idBrittleFracture::AddForce( idEntity *ent, int id, const idVec3 &point, const idVec3 &force ) {
  563. //if ( id < 0 || id >= shards.Num() )
  564. if ( id < 0)
  565. {
  566. return;
  567. }
  568. if (id >= shards.Num())
  569. id = shards.Num() - 1;
  570. if ( shards[id]->droppedTime != -1 )
  571. {
  572. shards[id]->physicsObj.AddForce( 0, point, force );
  573. }
  574. //else if ( health <= 0 && !disableFracture )
  575. else if ( !disableFracture )
  576. {
  577. Shatter( point, force, gameLocal.time );
  578. //StartSound( "snd_shatter", SND_CHANNEL_ANY, 0, false, NULL );
  579. //BC Trigger any alarm things.
  580. ActivateTargets( gameLocal.GetLocalPlayer() );
  581. }
  582. }
  583. /*
  584. ================
  585. idBrittleFracture::ProjectDecal
  586. ================
  587. */
  588. void idBrittleFracture::ProjectDecal( const idVec3 &point, const idVec3 &dir, const int time, const char *damageDefName ) {
  589. int i, j, bits, clipBits;
  590. float a, c, s;
  591. idVec2 st[MAX_POINTS_ON_WINDING];
  592. idVec3 origin;
  593. idMat3 axis, axistemp;
  594. idPlane textureAxis[2];
  595. if ( gameLocal.isServer ) {
  596. idBitMsg msg;
  597. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  598. msg.Init( msgBuf, sizeof( msgBuf ) );
  599. msg.BeginWriting();
  600. msg.WriteFloat( point[0] );
  601. msg.WriteFloat( point[1] );
  602. msg.WriteFloat( point[2] );
  603. msg.WriteFloat( dir[0] );
  604. msg.WriteFloat( dir[1] );
  605. msg.WriteFloat( dir[2] );
  606. ServerSendEvent( EVENT_PROJECT_DECAL, &msg, true, -1 );
  607. }
  608. if ( time >= gameLocal.time ) {
  609. // try to get the sound from the damage def
  610. const idDeclEntityDef *damageDef = NULL;
  611. const idSoundShader *sndShader = NULL;
  612. /*
  613. if ( damageDefName )
  614. {
  615. damageDef = gameLocal.FindEntityDef( damageDefName, false );
  616. if ( damageDef )
  617. {
  618. sndShader = declManager->FindSound( damageDef->dict.GetString( "snd_shatter", "" ) );
  619. }
  620. }
  621. if ( sndShader )
  622. {
  623. StartSoundShader( sndShader, SND_CHANNEL_ANY, 0, false, NULL );
  624. }
  625. else
  626. {
  627. StartSound( "snd_bullethole", SND_CHANNEL_ANY, 0, false, NULL );
  628. }*/
  629. StartSound( "snd_shatter", SND_CHANNEL_ANY, 0, false, NULL );
  630. }
  631. a = gameLocal.random.RandomFloat() * idMath::TWO_PI;
  632. c = cos( a );
  633. s = -sin( a );
  634. axis[2] = -dir;
  635. axis[2].Normalize();
  636. axis[2].NormalVectors( axistemp[0], axistemp[1] );
  637. axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s;
  638. axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c;
  639. textureAxis[0] = axis[0] * ( 1.0f / decalSize );
  640. textureAxis[0][3] = -( point * textureAxis[0].Normal() ) + 0.5f;
  641. textureAxis[1] = axis[1] * ( 1.0f / decalSize );
  642. textureAxis[1][3] = -( point * textureAxis[1].Normal() ) + 0.5f;
  643. for ( i = 0; i < shards.Num(); i++ ) {
  644. idFixedWinding &winding = shards[i]->winding;
  645. origin = shards[i]->clipModel->GetOrigin();
  646. axis = shards[i]->clipModel->GetAxis();
  647. float d0, d1;
  648. clipBits = -1;
  649. for ( j = 0; j < winding.GetNumPoints(); j++ ) {
  650. idVec3 p = origin + winding[j].ToVec3() * axis;
  651. st[j].x = d0 = textureAxis[0].Distance( p );
  652. st[j].y = d1 = textureAxis[1].Distance( p );
  653. bits = FLOATSIGNBITSET( d0 );
  654. d0 = 1.0f - d0;
  655. bits |= FLOATSIGNBITSET( d1 ) << 2;
  656. d1 = 1.0f - d1;
  657. bits |= FLOATSIGNBITSET( d0 ) << 1;
  658. bits |= FLOATSIGNBITSET( d1 ) << 3;
  659. clipBits &= bits;
  660. }
  661. if ( clipBits ) {
  662. continue;
  663. }
  664. idFixedWinding *decal = new idFixedWinding;
  665. shards[i]->decals.Append( decal );
  666. decal->SetNumPoints( winding.GetNumPoints() );
  667. for ( j = 0; j < winding.GetNumPoints(); j++ ) {
  668. (*decal)[j].ToVec3() = winding[j].ToVec3();
  669. (*decal)[j].s = st[j].x;
  670. (*decal)[j].t = st[j].y;
  671. }
  672. }
  673. BecomeActive( TH_UPDATEVISUALS );
  674. }
  675. /*
  676. ================
  677. idBrittleFracture::DropShard
  678. ================
  679. */
  680. void idBrittleFracture::DropShard( shard_t *shard, const idVec3 &point, const idVec3 &dir, const float impulse, const int time ) {
  681. int i, j, clipModelId;
  682. float dist, f;
  683. idVec3 dir2, origin;
  684. idMat3 axis;
  685. shard_t *neighbour;
  686. // don't display decals on dropped shards
  687. shard->decals.DeleteContents( true );
  688. // remove neighbour pointers of neighbours pointing to this shard
  689. for ( i = 0; i < shard->neighbours.Num(); i++ ) {
  690. neighbour = shard->neighbours[i];
  691. for ( j = 0; j < neighbour->neighbours.Num(); j++ ) {
  692. if ( neighbour->neighbours[j] == shard ) {
  693. neighbour->neighbours.RemoveIndex( j );
  694. break;
  695. }
  696. }
  697. }
  698. // remove neighbour pointers
  699. shard->neighbours.Clear();
  700. // remove the clip model from the static physics object
  701. clipModelId = shard->clipModel->GetId();
  702. physicsObj.SetClipModel( NULL, 1.0f, clipModelId, false );
  703. origin = shard->clipModel->GetOrigin();
  704. axis = shard->clipModel->GetAxis();
  705. // set the dropped time for fading
  706. shard->droppedTime = time;
  707. dir2 = origin - point;
  708. dist = dir2.Normalize();
  709. f = dist > maxShatterRadius ? 1.0f : idMath::Sqrt( dist - minShatterRadius ) * ( 1.0f / idMath::Sqrt( maxShatterRadius - minShatterRadius ) );
  710. // setup the physics
  711. shard->physicsObj.SetSelf( this );
  712. shard->physicsObj.SetClipModel( shard->clipModel, density );
  713. shard->physicsObj.SetMass( shardMass );
  714. shard->physicsObj.SetOrigin( origin );
  715. shard->physicsObj.SetAxis( axis );
  716. shard->physicsObj.SetBouncyness( bouncyness );
  717. shard->physicsObj.SetFriction( 0.6f, 0.6f, friction );
  718. shard->physicsObj.SetGravity( gameLocal.GetGravity() );
  719. shard->physicsObj.SetContents( CONTENTS_RENDERMODEL );
  720. shard->physicsObj.SetClipMask( MASK_SOLID | CONTENTS_MOVEABLECLIP );
  721. shard->physicsObj.ApplyImpulse( 0, origin, impulse * linearVelocityScale * dir );
  722. shard->physicsObj.SetAngularVelocity( dir.Cross( dir2 ) * ( f * angularVelocityScale ) );
  723. shard->clipModel->SetId( clipModelId );
  724. BecomeActive( TH_PHYSICS );
  725. }
  726. /*
  727. ================
  728. idBrittleFracture::Shatter
  729. ================
  730. */
  731. void idBrittleFracture::Shatter( const idVec3 &point, const idVec3 &impulse, const int time ) {
  732. int i;
  733. idVec3 dir;
  734. shard_t *shard;
  735. float m;
  736. if ( gameLocal.isServer ) {
  737. idBitMsg msg;
  738. byte msgBuf[MAX_EVENT_PARAM_SIZE];
  739. msg.Init( msgBuf, sizeof( msgBuf ) );
  740. msg.BeginWriting();
  741. msg.WriteFloat( point[0] );
  742. msg.WriteFloat( point[1] );
  743. msg.WriteFloat( point[2] );
  744. msg.WriteFloat( impulse[0] );
  745. msg.WriteFloat( impulse[1] );
  746. msg.WriteFloat( impulse[2] );
  747. ServerSendEvent( EVENT_SHATTER, &msg, true, -1 );
  748. }
  749. if ( time > ( gameLocal.time - SHARD_ALIVE_TIME ) ) {
  750. StartSound( "snd_shatter", SND_CHANNEL_ANY, 0, false, NULL );
  751. }
  752. if ( !IsBroken() ) {
  753. Break();
  754. }
  755. if ( fxFracture.Length() ) {
  756. idEntityFx::StartFx( fxFracture, &point, &GetPhysics()->GetAxis(), this, true );
  757. }
  758. dir = impulse;
  759. m = dir.Normalize();
  760. for ( i = 0; i < shards.Num(); i++ ) {
  761. shard = shards[i];
  762. if ( shard->droppedTime != -1 ) {
  763. continue;
  764. }
  765. if ( ( shard->clipModel->GetOrigin() - point ).LengthSqr() > Square( maxShatterRadius ) ) {
  766. continue;
  767. }
  768. DropShard( shard, point, dir, m, time );
  769. }
  770. DropFloatingIslands( point, impulse, time );
  771. //trigger it.
  772. if (!firedTargets)
  773. {
  774. firedTargets = true;
  775. ActivateTargets(this);
  776. }
  777. }
  778. /*
  779. ================
  780. idBrittleFracture::DropFloatingIslands
  781. ================
  782. */
  783. void idBrittleFracture::DropFloatingIslands( const idVec3 &point, const idVec3 &impulse, const int time ) {
  784. int i, j, numIslands;
  785. int queueStart, queueEnd;
  786. shard_t *curShard, *nextShard, **queue;
  787. bool touchesEdge;
  788. idVec3 dir;
  789. dir = impulse;
  790. dir.Normalize();
  791. numIslands = 0;
  792. queue = (shard_t **) _alloca16( shards.Num() * sizeof(shard_t **) );
  793. for ( i = 0; i < shards.Num(); i++ ) {
  794. shards[i]->islandNum = 0;
  795. }
  796. for ( i = 0; i < shards.Num(); i++ ) {
  797. if ( shards[i]->droppedTime != -1 ) {
  798. continue;
  799. }
  800. if ( shards[i]->islandNum ) {
  801. continue;
  802. }
  803. queueStart = 0;
  804. queueEnd = 1;
  805. queue[0] = shards[i];
  806. shards[i]->islandNum = numIslands+1;
  807. touchesEdge = false;
  808. if ( shards[i]->atEdge ) {
  809. touchesEdge = true;
  810. }
  811. for ( curShard = queue[queueStart]; queueStart < queueEnd; curShard = queue[++queueStart] ) {
  812. for ( j = 0; j < curShard->neighbours.Num(); j++ ) {
  813. nextShard = curShard->neighbours[j];
  814. if ( nextShard->droppedTime != -1 ) {
  815. continue;
  816. }
  817. if ( nextShard->islandNum ) {
  818. continue;
  819. }
  820. queue[queueEnd++] = nextShard;
  821. nextShard->islandNum = numIslands+1;
  822. if ( nextShard->atEdge ) {
  823. touchesEdge = true;
  824. }
  825. }
  826. }
  827. numIslands++;
  828. // if the island is not connected to the world at any edges
  829. if ( !touchesEdge ) {
  830. for ( j = 0; j < queueEnd; j++ ) {
  831. DropShard( queue[j], point, dir, 0.0f, time );
  832. }
  833. }
  834. }
  835. }
  836. /*
  837. ================
  838. idBrittleFracture::Break
  839. ================
  840. */
  841. void idBrittleFracture::Break( void ) {
  842. fl.takedamage = false;
  843. //bc
  844. //physicsObj.SetContents( CONTENTS_RENDERMODEL | CONTENTS_TRIGGER );
  845. }
  846. /*
  847. ================
  848. idBrittleFracture::IsBroken
  849. ================
  850. */
  851. bool idBrittleFracture::IsBroken( void ) const {
  852. return ( fl.takedamage == false );
  853. }
  854. /*
  855. ================
  856. idBrittleFracture::Killed
  857. ================
  858. */
  859. void idBrittleFracture::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
  860. if ( !disableFracture ) {
  861. ActivateTargets( this );
  862. Break();
  863. }
  864. }
  865. /*
  866. ================
  867. idBrittleFracture::AddDamageEffect
  868. ================
  869. */
  870. void idBrittleFracture::AddDamageEffect( const trace_t &collision, const idVec3 &velocity, const char *damageDefName ) {
  871. if ( !disableFracture ) {
  872. ProjectDecal( collision.c.point, collision.c.normal, gameLocal.time, damageDefName );
  873. }
  874. }
  875. /*
  876. ================
  877. idBrittleFracture::Fracture_r
  878. ================
  879. */
  880. void idBrittleFracture::Fracture_r( idFixedWinding &w ) {
  881. int i, j, bestPlane;
  882. float a, c, s, dist, bestDist;
  883. idVec3 origin;
  884. idPlane windingPlane, splitPlanes[2];
  885. idMat3 axis, axistemp;
  886. idFixedWinding back;
  887. idTraceModel trm;
  888. idClipModel *clipModel;
  889. while( 1 ) {
  890. origin = w.GetCenter();
  891. w.GetPlane( windingPlane );
  892. if ( w.GetArea() < maxShardArea ) {
  893. break;
  894. }
  895. // randomly create a split plane
  896. axis[2] = windingPlane.Normal();
  897. #ifdef _D3XP
  898. if ( isXraySurface ) {
  899. a = idMath::TWO_PI / 2.f;
  900. }
  901. else {
  902. a = gameLocal.random.RandomFloat() * idMath::TWO_PI;
  903. }
  904. #else
  905. a = gameLocal.random.RandomFloat() * idMath::TWO_PI;
  906. #endif
  907. c = cos( a );
  908. s = -sin( a );
  909. axis[2].NormalVectors( axistemp[0], axistemp[1] );
  910. axis[0] = axistemp[ 0 ] * c + axistemp[ 1 ] * s;
  911. axis[1] = axistemp[ 0 ] * s + axistemp[ 1 ] * -c;
  912. // get the best split plane
  913. bestDist = 0.0f;
  914. bestPlane = 0;
  915. for ( i = 0; i < 2; i++ ) {
  916. splitPlanes[i].SetNormal( axis[i] );
  917. splitPlanes[i].FitThroughPoint( origin );
  918. for ( j = 0; j < w.GetNumPoints(); j++ ) {
  919. dist = splitPlanes[i].Distance( w[j].ToVec3() );
  920. if ( dist > bestDist ) {
  921. bestDist = dist;
  922. bestPlane = i;
  923. }
  924. }
  925. }
  926. // split the winding
  927. if ( !w.Split( &back, splitPlanes[bestPlane] ) ) {
  928. break;
  929. }
  930. // recursively create shards for the back winding
  931. Fracture_r( back );
  932. }
  933. // translate the winding to it's center
  934. origin = w.GetCenter();
  935. for ( j = 0; j < w.GetNumPoints(); j++ ) {
  936. w[j].ToVec3() -= origin;
  937. }
  938. w.RemoveEqualPoints();
  939. trm.SetupPolygon( w );
  940. trm.Shrink( CM_CLIP_EPSILON );
  941. clipModel = new idClipModel( trm );
  942. physicsObj.SetClipModel( clipModel, 1.0f, shards.Num() );
  943. physicsObj.SetOrigin( GetPhysics()->GetOrigin() + origin, shards.Num() );
  944. physicsObj.SetAxis( GetPhysics()->GetAxis(), shards.Num() );
  945. AddShard( clipModel, w );
  946. }
  947. /*
  948. ================
  949. idBrittleFracture::CreateFractures
  950. ================
  951. */
  952. void idBrittleFracture::CreateFractures( const idRenderModel *renderModel ) {
  953. int i, j, k;
  954. const modelSurface_t *surf;
  955. const idDrawVert *v;
  956. idFixedWinding w;
  957. if ( !renderModel ) {
  958. return;
  959. }
  960. physicsObj.SetSelf( this );
  961. physicsObj.SetOrigin( GetPhysics()->GetOrigin(), 0 );
  962. physicsObj.SetAxis( GetPhysics()->GetAxis(), 0 );
  963. #ifdef _D3XP
  964. if ( isXraySurface ) {
  965. for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) {
  966. surf = renderModel->Surface( i );
  967. material = surf->shader;
  968. w.Clear();
  969. int k = 0;
  970. v = &surf->geometry->verts[k];
  971. w.AddPoint( v->xyz );
  972. w[k].s = v->st[0];
  973. w[k].t = v->st[1];
  974. k = 1;
  975. v = &surf->geometry->verts[k];
  976. w.AddPoint( v->xyz );
  977. w[k].s = v->st[0];
  978. w[k].t = v->st[1];
  979. k = 3;
  980. v = &surf->geometry->verts[k];
  981. w.AddPoint( v->xyz );
  982. w[k].s = v->st[0];
  983. w[k].t = v->st[1];
  984. k = 2;
  985. v = &surf->geometry->verts[k];
  986. w.AddPoint( v->xyz );
  987. w[k].s = v->st[0];
  988. w[k].t = v->st[1];
  989. Fracture_r( w );
  990. }
  991. }
  992. else {
  993. for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) {
  994. surf = renderModel->Surface( i );
  995. material = surf->shader;
  996. for ( j = 0; j < surf->geometry->numIndexes; j += 3 ) {
  997. w.Clear();
  998. for ( k = 0; k < 3; k++ ) {
  999. v = &surf->geometry->verts[ surf->geometry->indexes[ j + 2 - k ] ];
  1000. w.AddPoint( v->xyz );
  1001. w[k].s = v->st[0];
  1002. w[k].t = v->st[1];
  1003. }
  1004. Fracture_r( w );
  1005. }
  1006. }
  1007. }
  1008. #else
  1009. for ( i = 0; i < 1 /*renderModel->NumSurfaces()*/; i++ ) {
  1010. surf = renderModel->Surface( i );
  1011. material = surf->shader;
  1012. for ( j = 0; j < surf->geometry->numIndexes; j += 3 ) {
  1013. w.Clear();
  1014. for ( k = 0; k < 3; k++ ) {
  1015. v = &surf->geometry->verts[ surf->geometry->indexes[ j + 2 - k ] ];
  1016. w.AddPoint( v->xyz );
  1017. w[k].s = v->st[0];
  1018. w[k].t = v->st[1];
  1019. }
  1020. Fracture_r( w );
  1021. }
  1022. }
  1023. #endif
  1024. physicsObj.SetContents( material->GetContentFlags() );
  1025. SetPhysics( &physicsObj );
  1026. }
  1027. /*
  1028. ================
  1029. idBrittleFracture::FindNeighbours
  1030. ================
  1031. */
  1032. void idBrittleFracture::FindNeighbours( void ) {
  1033. int i, j, k, l;
  1034. idVec3 p1, p2, dir;
  1035. idMat3 axis;
  1036. idPlane plane[4];
  1037. for ( i = 0; i < shards.Num(); i++ ) {
  1038. shard_t *shard1 = shards[i];
  1039. const idWinding &w1 = shard1->winding;
  1040. const idVec3 &origin1 = shard1->clipModel->GetOrigin();
  1041. const idMat3 &axis1 = shard1->clipModel->GetAxis();
  1042. for ( k = 0; k < w1.GetNumPoints(); k++ ) {
  1043. p1 = origin1 + w1[k].ToVec3() * axis1;
  1044. p2 = origin1 + w1[(k+1)%w1.GetNumPoints()].ToVec3() * axis1;
  1045. dir = p2 - p1;
  1046. dir.Normalize();
  1047. axis = dir.ToMat3();
  1048. plane[0].SetNormal( dir );
  1049. plane[0].FitThroughPoint( p1 );
  1050. plane[1].SetNormal( -dir );
  1051. plane[1].FitThroughPoint( p2 );
  1052. plane[2].SetNormal( axis[1] );
  1053. plane[2].FitThroughPoint( p1 );
  1054. plane[3].SetNormal( axis[2] );
  1055. plane[3].FitThroughPoint( p1 );
  1056. for ( j = 0; j < shards.Num(); j++ ) {
  1057. if ( i == j ) {
  1058. continue;
  1059. }
  1060. shard_t *shard2 = shards[j];
  1061. for ( l = 0; l < shard1->neighbours.Num(); l++ ) {
  1062. if ( shard1->neighbours[l] == shard2 ) {
  1063. break;
  1064. }
  1065. }
  1066. if ( l < shard1->neighbours.Num() ) {
  1067. continue;
  1068. }
  1069. const idWinding &w2 = shard2->winding;
  1070. const idVec3 &origin2 = shard2->clipModel->GetOrigin();
  1071. const idMat3 &axis2 = shard2->clipModel->GetAxis();
  1072. for ( l = w2.GetNumPoints()-1; l >= 0; l-- ) {
  1073. p1 = origin2 + w2[l].ToVec3() * axis2;
  1074. p2 = origin2 + w2[(l-1+w2.GetNumPoints())%w2.GetNumPoints()].ToVec3() * axis2;
  1075. if ( plane[0].Side( p2, 0.1f ) == SIDE_FRONT && plane[1].Side( p1, 0.1f ) == SIDE_FRONT ) {
  1076. if ( plane[2].Side( p1, 0.1f ) == SIDE_ON && plane[3].Side( p1, 0.1f ) == SIDE_ON ) {
  1077. if ( plane[2].Side( p2, 0.1f ) == SIDE_ON && plane[3].Side( p2, 0.1f ) == SIDE_ON ) {
  1078. shard1->neighbours.Append( shard2 );
  1079. shard1->edgeHasNeighbour[k] = true;
  1080. shard2->neighbours.Append( shard1 );
  1081. shard2->edgeHasNeighbour[(l-1+w2.GetNumPoints())%w2.GetNumPoints()] = true;
  1082. break;
  1083. }
  1084. }
  1085. }
  1086. }
  1087. }
  1088. }
  1089. for ( k = 0; k < w1.GetNumPoints(); k++ ) {
  1090. if ( !shard1->edgeHasNeighbour[k] ) {
  1091. break;
  1092. }
  1093. }
  1094. if ( k < w1.GetNumPoints() ) {
  1095. shard1->atEdge = true;
  1096. } else {
  1097. shard1->atEdge = false;
  1098. }
  1099. }
  1100. }
  1101. /*
  1102. ================
  1103. idBrittleFracture::Event_Activate
  1104. ================
  1105. */
  1106. void idBrittleFracture::Event_Activate( idEntity *activator ) {
  1107. disableFracture = false;
  1108. if ( health <= 0 ) {
  1109. Break();
  1110. }
  1111. }
  1112. /*
  1113. ================
  1114. idBrittleFracture::Event_Touch
  1115. ================
  1116. */
  1117. void idBrittleFracture::Event_Touch( idEntity *other, trace_t *trace ) {
  1118. idVec3 point, impulse;
  1119. if ( !IsBroken() ) {
  1120. return;
  1121. }
  1122. if ( trace->c.id < 0 || trace->c.id >= shards.Num() ) {
  1123. return;
  1124. }
  1125. point = shards[trace->c.id]->clipModel->GetOrigin();
  1126. impulse = other->GetPhysics()->GetLinearVelocity() * other->GetPhysics()->GetMass();
  1127. Shatter( point, impulse, gameLocal.time );
  1128. }
  1129. /*
  1130. ================
  1131. idBrittleFracture::ClientPredictionThink
  1132. ================
  1133. */
  1134. void idBrittleFracture::ClientPredictionThink( void ) {
  1135. // only think forward because the state is not synced through snapshots
  1136. if ( !gameLocal.isNewFrame ) {
  1137. return;
  1138. }
  1139. Think();
  1140. }
  1141. /*
  1142. ================
  1143. idBrittleFracture::ClientReceiveEvent
  1144. ================
  1145. */
  1146. bool idBrittleFracture::ClientReceiveEvent( int event, int time, const idBitMsg &msg ) {
  1147. idVec3 point, dir;
  1148. switch( event ) {
  1149. case EVENT_PROJECT_DECAL: {
  1150. point[0] = msg.ReadFloat();
  1151. point[1] = msg.ReadFloat();
  1152. point[2] = msg.ReadFloat();
  1153. dir[0] = msg.ReadFloat();
  1154. dir[1] = msg.ReadFloat();
  1155. dir[2] = msg.ReadFloat();
  1156. ProjectDecal( point, dir, time, NULL );
  1157. return true;
  1158. }
  1159. case EVENT_SHATTER: {
  1160. point[0] = msg.ReadFloat();
  1161. point[1] = msg.ReadFloat();
  1162. point[2] = msg.ReadFloat();
  1163. dir[0] = msg.ReadFloat();
  1164. dir[1] = msg.ReadFloat();
  1165. dir[2] = msg.ReadFloat();
  1166. Shatter( point, dir, time );
  1167. return true;
  1168. }
  1169. default: {
  1170. return idEntity::ClientReceiveEvent( event, time, msg );
  1171. }
  1172. }
  1173. return false;
  1174. }