Destructible.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Game{
  5. /******************************************************************************/
  6. #define DEFAULT_MODE BREAKABLE // here you can specify the default mode for Destructible objects - STATIC or BREAKABLE
  7. /******************************************************************************/
  8. static void CreateJoint(Joint &joint, Actor &a, Actor *b)
  9. {
  10. Flt mass=(b ? (a.mass()+b->mass()) : a.mass());
  11. joint.create(a, b).breakable(mass*3.1f, mass*0.22f);
  12. }
  13. static void CreateJoint(Joint &joint, Destructible &a, Destructible *b)
  14. {
  15. if(a.actors.elms())
  16. {
  17. if(b) // joint attaches actor with other actor
  18. {
  19. if(b->actors.elms())CreateJoint(joint, a.actors.first(), &b->actors.first());
  20. }else // joint attaches actor with world
  21. {
  22. CreateJoint(joint, a.actors.first(), null);
  23. }
  24. }
  25. }
  26. /******************************************************************************/
  27. Destructible::~Destructible()
  28. {
  29. }
  30. Destructible::Destructible()
  31. {
  32. mode =STATIC;
  33. piece_index =-1;
  34. mesh_variation= 0;
  35. scale = 0;
  36. destruct_mesh =null;
  37. }
  38. /******************************************************************************/
  39. // MANAGE
  40. /******************************************************************************/
  41. void Destructible::setUnsavedParams()
  42. {
  43. if(base)if(C Param *destruct=base->findParam("destruct"))destruct_mesh=DestructMeshes.get(destruct->asID());
  44. mesh=null;
  45. if(mode==PIECE)
  46. {
  47. if(destruct_mesh && InRange(piece_index, destruct_mesh->parts()))mesh=&destruct_mesh->part(piece_index).mesh;
  48. }else
  49. {
  50. if(base)mesh=base->mesh();
  51. }
  52. }
  53. void Destructible::create(Object &obj)
  54. {
  55. scale =obj.scale();
  56. base =obj.firstStored();
  57. mode =DEFAULT_MODE;
  58. piece_index =-1;
  59. mesh_variation=obj.meshVariationIndex();
  60. setUnsavedParams();
  61. Matrix matrix=obj.matrixFinal().normalize();
  62. switch(mode)
  63. {
  64. case BREAKABLE: setBreakable(matrix, AG_DEFAULT); break;
  65. case STATIC : setStatic (matrix, AG_DEFAULT); break;
  66. default : Exit("Unrecognized Destructible Mode"); break;
  67. }
  68. }
  69. /******************************************************************************/
  70. // GET / SET
  71. /******************************************************************************/
  72. Vec Destructible::pos ( ) {return actors.elms() ? actors.first().pos ( ) : 0;}
  73. Matrix Destructible::matrix ( ) {return actors.elms() ? actors.first().matrix( ) : MatrixIdentity;}
  74. Matrix Destructible::matrixScaled( ) {return actors.elms() ? actors.first().matrix( ).scaleOrn(scale) : MatrixIdentity;}
  75. void Destructible::pos (C Vec &pos ) { REPAO(actors) .pos (pos ); }
  76. void Destructible::matrix (C Matrix &matrix) { REPAO(actors) .matrix(matrix); }
  77. /******************************************************************************/
  78. // OPERATIONS
  79. /******************************************************************************/
  80. void Destructible::setStatic(C Matrix &matrix, Byte actor_group)
  81. {
  82. mode=STATIC;
  83. piece_index=-1;
  84. joints.del();
  85. actors.del();
  86. if(base && base->phys())actors.New().create(*base->phys(), 0, scale) // create main actor
  87. .matrix(matrix)
  88. .obj (this)
  89. .group (actor_group);
  90. }
  91. void Destructible::setBreakable(C Matrix &matrix, Byte actor_group)
  92. {
  93. mode=BREAKABLE;
  94. piece_index=-1;
  95. joints.del();
  96. actors.del();
  97. if(destruct_mesh) // create actors
  98. {
  99. FREP(destruct_mesh->parts())actors.New().create(destruct_mesh->part(i).phys, 1, scale)
  100. .matrix(matrix)
  101. .obj (this)
  102. .group (actor_group);
  103. REPAO(actors).sleep(true); // put to sleep, call this after all actors have been created, in case creating other actors will wake up the neighbors
  104. }
  105. }
  106. struct ActorInfo
  107. {
  108. Vec vel, ang_vel;
  109. Matrix matrix;
  110. Byte group;
  111. void set(C Matrix &matrix, C Vec &vel, C Vec &ang_vel, Byte group) {T.matrix=matrix; T.vel=vel; T.ang_vel=ang_vel; T.group=group;}
  112. };
  113. void Destructible::setPieces(Bool create_joints)
  114. {
  115. if((mode==STATIC || mode==BREAKABLE) // not a piece
  116. && destruct_mesh // has information about destructible mesh
  117. && destruct_mesh->parts() // destructible mesh has parts
  118. && type()>=0) // has information about OBJ_TYPE
  119. {
  120. Memc<Destructible*> pieces ; // i-th element will point to i-th DestructMesh part
  121. Memc<ActorInfo > actor_info; // i-th element will point to i-th DestructMesh part
  122. // create objects (pieces)
  123. Object op;
  124. op.type(true, ObjType.elmID(type()));
  125. FREP(destruct_mesh->parts()) // order is important
  126. {
  127. Destructible *destr=null;
  128. if(!i)destr=this; // 0-th piece is created from this object
  129. else destr=CAST(Destructible, World.objCreateNear(op, matrixScaled())); // rest of pieces are dynamically created from new objects
  130. pieces.add(destr); // add object to the lookup array
  131. }
  132. if(mode==BREAKABLE && actors.elms()==pieces.elms())FREPA(actors)actor_info.New().set(actors[i].matrix(), actors[i].vel(), actors[i].angVel(), actors[i].group() ); // remember actor info from current object, to recreate later
  133. else actor_info.New().set( T.matrix(), VecZero, VecZero, actors.elms() ? actors[0].group() : 0);
  134. // setup new objects
  135. joints.del(); // delete all joints of current object
  136. actors.del(); // delete all actors of current object
  137. UInt meshVariationID=(mesh ? mesh->variationID(mesh_variation) : 0);
  138. FREPA(pieces)if(Destructible *destr=pieces[i]) // create each piece
  139. {
  140. destr->mode = PIECE;
  141. destr->piece_index = i;
  142. destr->base = base;
  143. destr->scale = scale;
  144. destr->destruct_mesh = destruct_mesh;
  145. destr->mesh =&destruct_mesh->part(i).mesh;
  146. destr->mesh_variation = destr->mesh->variationFind(meshVariationID);
  147. destr->actors.del().New().create( destruct_mesh->part(i).phys, 1, scale).obj(destr).sleepEnergy(0.35f); // set big sleeping energy threshold to more often put actors to sleep
  148. }
  149. // create joints
  150. if(create_joints)FREP(destruct_mesh->joints())
  151. {
  152. DestructMesh::Joint joint=destruct_mesh->joint(i);
  153. if(!InRange(joint.a, pieces) || !pieces[joint.a])Swap(joint.a, joint.b); // if 'a' is not valid then swap 'a' with 'b'
  154. if( InRange(joint.a, pieces) && pieces[joint.a]) // if 'a' is valid
  155. {
  156. Destructible *destr_a=pieces[joint.a];
  157. if(InRange(joint.b, pieces)) // b index is valid and points to other piece
  158. {
  159. if(Destructible *destr_b=pieces[joint.b])
  160. {
  161. Joint &joint=destr_a->joints.New();
  162. joint.destr= destr_b ;
  163. CreateJoint(joint.joint, *destr_a, destr_b);
  164. }
  165. }else // b index is not valid, so attach to world
  166. {
  167. Joint &joint=destr_a->joints.New();
  168. CreateJoint(joint.joint, *destr_a, null);
  169. }
  170. }
  171. }
  172. // adjust object actors
  173. FREPA(pieces)if(Destructible *destr=pieces[i])
  174. {
  175. ActorInfo &ai=actor_info[Min(i, actor_info.elms()-1)];
  176. destr->actors.first().matrix(ai.matrix).vel(ai.vel).angVel(ai.ang_vel).group(ai.group);
  177. }
  178. }
  179. }
  180. /******************************************************************************/
  181. void Destructible::toStatic()
  182. {
  183. if(mode==BREAKABLE)setStatic(matrix(), actors.elms() ? actors[0].group() : 0);
  184. }
  185. void Destructible::toBreakable()
  186. {
  187. if(mode==STATIC)setBreakable(matrix(), actors.elms() ? actors[0].group() : 0);
  188. }
  189. void Destructible::toPieces()
  190. {
  191. if(mode==STATIC || mode==BREAKABLE)setPieces(false);
  192. }
  193. /******************************************************************************/
  194. // CALLBACKS
  195. /******************************************************************************/
  196. void Destructible::memoryAddressChanged()
  197. {
  198. REPAO(actors).obj(this);
  199. }
  200. void Destructible::linkReferences()
  201. {
  202. // create joints that attach actor with other objects (and their actors)
  203. REPA(joints)
  204. {
  205. Joint &joint=joints[i];
  206. Bool was_valid= joint.destr.valid(); joint.destr.link(World);
  207. if( !was_valid && joint.destr.valid())CreateJoint(joint.joint, T, &joint.destr()); // create the joint only if reference was successfully linked at this moment (was not valid, but after linking it is valid)
  208. }
  209. }
  210. /******************************************************************************/
  211. // UPDATE
  212. /******************************************************************************/
  213. #define EPS_ACTOR_ENERGY 0.0002f
  214. Bool Destructible::update()
  215. {
  216. switch(mode)
  217. {
  218. case BREAKABLE:
  219. {
  220. REPA(actors)if(!actors[i].sleep() && actors[i].energy()>EPS_ACTOR_ENERGY) // if at least one actor was moved
  221. {
  222. setPieces(true);
  223. break;
  224. }
  225. }break;
  226. case PIECE:
  227. {
  228. if(!destruct_mesh || !InRange(piece_index, destruct_mesh->parts()))return false;
  229. // pieces can reach very high velocities due to collisions, so clamp the velocity to maximum of 100
  230. Vec vel=actors.first().vel();
  231. if( vel.length()>100){vel.setLength(100); actors.first().vel(vel);}
  232. }break;
  233. }
  234. return true;
  235. }
  236. /******************************************************************************/
  237. // DRAW
  238. /******************************************************************************/
  239. UInt Destructible::drawPrepare()
  240. {
  241. if(mesh)
  242. {
  243. Matrix matrix=matrixScaled(); if(Frustum(*mesh, matrix))
  244. {
  245. SetVariation(mesh_variation);
  246. mesh->draw(matrix, actors.elms() ? actors.first().vel() : VecZero, actors.elms() ? actors.first().angVel() : VecZero);
  247. SetVariation();
  248. }
  249. }
  250. return 0; // no additional render modes required
  251. }
  252. /******************************************************************************/
  253. void Destructible::drawShadow()
  254. {
  255. if(mesh)
  256. {
  257. Matrix matrix=matrixScaled(); if(Frustum(*mesh, matrix))
  258. {
  259. SetVariation(mesh_variation);
  260. mesh->drawShadow(matrix);
  261. SetVariation();
  262. }
  263. }
  264. }
  265. /******************************************************************************/
  266. // ENABLE / DISABLE
  267. /******************************************************************************/
  268. void Destructible::disable()
  269. {
  270. // freeze all actors
  271. if(mode!=STATIC) // static actor doesn't need to be freezed
  272. {
  273. REPAO(actors).kinematic(true); // freeze
  274. }
  275. }
  276. void Destructible::enable()
  277. {
  278. // unfreeze all actors
  279. if(mode!=STATIC) // static actor doesn't need to be unfreezed
  280. {
  281. REPAO(actors).kinematic(false); // unfreeze
  282. if(mode==BREAKABLE)REPAO(actors).sleep (false); // put to sleep
  283. }
  284. }
  285. /******************************************************************************/
  286. // IO
  287. /******************************************************************************/
  288. Bool Destructible::Joint::save(File &f)C {return destr.save(f);}
  289. Bool Destructible::Joint::load(File &f) {return destr.load(f);}
  290. /******************************************************************************/
  291. Bool Destructible::canBeSaved() {return super::canBeSaved() && actors.elms()>=1;} // save only if has at least 1 actor
  292. /******************************************************************************/
  293. Bool Destructible::save(File &f)
  294. {
  295. DYNAMIC_ASSERT(actors.elms()>=1, "Destructible object doesn't have any actors");
  296. if(super::save(f))
  297. {
  298. f.cmpUIntV(0); // version
  299. f<<mode<<piece_index<<scale;
  300. f.putAsset(base.id());
  301. switch(mode)
  302. {
  303. case STATIC :
  304. case BREAKABLE:
  305. {
  306. f<<matrix();
  307. f.putByte(actors.elms() ? actors.first().group() : 0);
  308. }break;
  309. case PIECE:
  310. {
  311. REPA(joints)if(joints[i].joint.broken())joints.remove(i); // remove unused joints
  312. if(!joints.save(f) )return false;
  313. if(!actors.first().saveState(f))return false;
  314. }break;
  315. }
  316. f.putUInt(mesh ? mesh->variationID(mesh_variation) : 0);
  317. return f.ok();
  318. }
  319. return false;
  320. }
  321. /******************************************************************************/
  322. Bool Destructible::load(File &f)
  323. {
  324. if(super::load(f))switch(f.decUIntV()) // version
  325. {
  326. case 0:
  327. {
  328. f>>mode>>piece_index>>scale;
  329. base=f.getAssetID();
  330. setUnsavedParams();
  331. switch(mode)
  332. {
  333. case STATIC :
  334. case BREAKABLE:
  335. {
  336. Matrix matrix; f>>matrix;
  337. Byte group=f.getByte();
  338. switch(mode)
  339. {
  340. case STATIC : setStatic (matrix, group); break;
  341. case BREAKABLE: setBreakable(matrix, group); break;
  342. }
  343. }break;
  344. case PIECE:
  345. {
  346. if(!joints.load(f))return false;
  347. if(destruct_mesh && InRange(piece_index, destruct_mesh->parts()))
  348. {
  349. Actor &actor=actors.New().create(destruct_mesh->part(piece_index).phys, 1, scale).obj(this);
  350. if(!actor.loadState(f))return false;
  351. }else
  352. {
  353. if(!Actor().loadState(f))return false;
  354. }
  355. // create joints that attach actor with world (joints which attach actor with other objects must be performed later in 'linkReferences')
  356. REPA(joints)
  357. {
  358. Joint &joint=joints[i];
  359. if(joint.destr.empty())CreateJoint(joint.joint, T, null); // if joint doesn't want to point to any other object, it means that it's a world joint
  360. }
  361. }break;
  362. default: return false;
  363. }
  364. UInt mesh_variation_id=f.getUInt(); mesh_variation=(mesh ? mesh->variationFind(mesh_variation_id) : 0);
  365. if(f.ok())return true;
  366. }break;
  367. }
  368. return false;
  369. }
  370. /******************************************************************************/
  371. }}
  372. /******************************************************************************/