home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2006 March / Gamestar_82_2006-03_dvd.iso / DVDStar / Editace / quake4_sdkv10.exe / source / game / BrittleFracture.cpp < prev    next >
C/C++ Source or Header  |  2005-11-14  |  35KB  |  1,356 lines

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