PointCloud.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. #include "gosFXHeaders.hpp"
  2. #include <MLR\MLRPointCloud.hpp>
  3. //==========================================================================//
  4. // File: gosFX_PointCloud.cpp //
  5. // Contents: Base gosFX::PointCloud Component //
  6. //---------------------------------------------------------------------------//
  7. // Copyright (C) Microsoft Corporation. All rights reserved. //
  8. //===========================================================================//
  9. //
  10. //############################################################################
  11. //######################## gosFX::PointCloud__Specification #############################
  12. //############################################################################
  13. //------------------------------------------------------------------------------
  14. //
  15. gosFX::PointCloud__Specification::PointCloud__Specification(
  16. Stuff::MemoryStream *stream,
  17. int gfx_version
  18. ):
  19. ParticleCloud__Specification(gosFX::PointCloudClassID, stream, gfx_version)
  20. {
  21. Check_Pointer(this);
  22. Verify(m_class == PointCloudClassID);
  23. Verify(gos_GetCurrentHeap() == Heap);
  24. m_totalParticleSize = gosFX::PointCloud::ParticleSize;
  25. m_particleClassSize = sizeof(gosFX::PointCloud::Particle);
  26. }
  27. //------------------------------------------------------------------------------
  28. //
  29. gosFX::PointCloud__Specification::PointCloud__Specification():
  30. ParticleCloud__Specification(gosFX::PointCloudClassID)
  31. {
  32. Check_Pointer(this);
  33. Verify(gos_GetCurrentHeap() == Heap);
  34. m_totalParticleSize = gosFX::PointCloud::ParticleSize;
  35. m_particleClassSize = sizeof(gosFX::PointCloud::Particle);
  36. }
  37. //------------------------------------------------------------------------------
  38. //
  39. gosFX::PointCloud__Specification*
  40. gosFX::PointCloud__Specification::Make(
  41. Stuff::MemoryStream *stream,
  42. int gfx_version
  43. )
  44. {
  45. Check_Object(stream);
  46. gos_PushCurrentHeap(Heap);
  47. PointCloud__Specification *spec =
  48. new gosFX::PointCloud__Specification(stream, gfx_version);
  49. gos_PopCurrentHeap();
  50. return spec;
  51. }
  52. //############################################################################
  53. //############################## gosFX::PointCloud ################################
  54. //############################################################################
  55. gosFX::PointCloud::ClassData*
  56. gosFX::PointCloud::DefaultData = NULL;
  57. //------------------------------------------------------------------------------
  58. //
  59. void
  60. gosFX::PointCloud::InitializeClass()
  61. {
  62. Verify(!DefaultData);
  63. Verify(gos_GetCurrentHeap() == Heap);
  64. DefaultData =
  65. new ClassData(
  66. PointCloudClassID,
  67. "gosFX::PointCloud",
  68. ParticleCloud::DefaultData,
  69. (Effect::Factory)&Make,
  70. (Specification::Factory)&Specification::Make
  71. );
  72. Register_Object(DefaultData);
  73. }
  74. //------------------------------------------------------------------------------
  75. //
  76. void
  77. gosFX::PointCloud::TerminateClass()
  78. {
  79. Unregister_Object(DefaultData);
  80. delete DefaultData;
  81. DefaultData = NULL;
  82. }
  83. //------------------------------------------------------------------------------
  84. //
  85. gosFX::PointCloud::PointCloud(
  86. Specification *spec,
  87. unsigned flags
  88. ):
  89. ParticleCloud(DefaultData, spec, flags)
  90. {
  91. Check_Object(spec);
  92. Verify(gos_GetCurrentHeap() == Heap);
  93. gos_PushCurrentHeap(MidLevelRenderer::Heap);
  94. m_cloudImplementation =
  95. new MidLevelRenderer::MLRPointCloud(spec->m_maxParticleCount);
  96. Register_Object(m_cloudImplementation);
  97. gos_PopCurrentHeap();
  98. unsigned index = spec->m_maxParticleCount*sizeof(Particle);
  99. m_P_localTranslation = Cast_Pointer(Stuff::Point3D*, &m_data[index]);
  100. index += spec->m_maxParticleCount*sizeof(Stuff::Point3D);
  101. m_P_color = Cast_Pointer(Stuff::RGBAColor*, &m_data[index]);
  102. m_cloudImplementation->SetData(
  103. Cast_Pointer(const int *, &m_activeParticleCount),
  104. m_P_localTranslation,
  105. m_P_color
  106. );
  107. }
  108. //------------------------------------------------------------------------------
  109. //
  110. gosFX::PointCloud::~PointCloud()
  111. {
  112. Unregister_Object(m_cloudImplementation);
  113. delete m_cloudImplementation;
  114. }
  115. //------------------------------------------------------------------------------
  116. //
  117. gosFX::PointCloud*
  118. gosFX::PointCloud::Make(
  119. Specification *spec,
  120. unsigned flags
  121. )
  122. {
  123. Check_Object(spec);
  124. gos_PushCurrentHeap(Heap);
  125. PointCloud *cloud = new gosFX::PointCloud(spec, flags);
  126. gos_PopCurrentHeap();
  127. return cloud;
  128. }
  129. //------------------------------------------------------------------------------
  130. //
  131. bool
  132. gosFX::PointCloud::Execute(ExecuteInfo *info)
  133. {
  134. Check_Object(this);
  135. Check_Object(info);
  136. //
  137. //----------------------------------------
  138. // If we aren't supposed to execute, don't
  139. //----------------------------------------
  140. //
  141. if (!IsExecuted())
  142. return false;
  143. //
  144. //------------------------------------------------------------------
  145. // Animate the particles. If it is time for us to die, return false
  146. //------------------------------------------------------------------
  147. //
  148. if (!ParticleCloud::Execute(info))
  149. return false;
  150. //
  151. //-----------------------------------------------------------------------
  152. // If there are active particles to animate, get the current center point
  153. // of the bounds
  154. //-----------------------------------------------------------------------
  155. //
  156. if (m_activeParticleCount > 0)
  157. {
  158. Stuff::ExtentBox box(Stuff::Point3D::Identity, Stuff::Point3D::Identity);
  159. Stuff::Point3D *vertex = &m_P_localTranslation[0];
  160. unsigned i=0;
  161. //
  162. //-------------------------------------------------------------------
  163. // If there is no bounds yet, we need to create our extent box around
  164. // the first legal point we find
  165. //-------------------------------------------------------------------
  166. //
  167. while (i<m_activeParticleCount)
  168. {
  169. Particle *particle = GetParticle(i);
  170. Check_Object(particle);
  171. if (particle->m_age < 1.0f)
  172. {
  173. Check_Object(vertex);
  174. box.maxX = vertex->x;
  175. box.minX = vertex->x;
  176. box.maxY = vertex->y;
  177. box.minY = vertex->y;
  178. box.maxZ = vertex->z;
  179. box.minZ = vertex->z;
  180. ++vertex;
  181. ++i;
  182. break;
  183. }
  184. ++vertex;
  185. ++i;
  186. }
  187. //
  188. //-----------------------------
  189. // Look for the other particles
  190. //-----------------------------
  191. //
  192. while (i<m_activeParticleCount)
  193. {
  194. Particle *particle = GetParticle(i);
  195. Check_Object(particle);
  196. if (particle->m_age < 1.0f)
  197. {
  198. Check_Object(vertex);
  199. if (vertex->x > box.maxX)
  200. box.maxX = vertex->x;
  201. else if (vertex->x < box.minX)
  202. box.minX = vertex->x;
  203. if (vertex->y > box.maxY)
  204. box.maxY = vertex->y;
  205. else if (vertex->y < box.minY)
  206. box.minY = vertex->y;
  207. if (vertex->z > box.maxZ)
  208. box.maxZ = vertex->z;
  209. else if (vertex->z < box.minZ)
  210. box.minZ = vertex->z;
  211. }
  212. ++vertex;
  213. ++i;
  214. }
  215. //
  216. //------------------------------------
  217. // Now, build a info->m_bounds around this box
  218. //------------------------------------
  219. //
  220. Verify(box.maxX >= box.minX);
  221. Verify(box.maxY >= box.minY);
  222. Verify(box.maxZ >= box.minZ);
  223. Stuff::OBB local_bounds = Stuff::OBB::Identity;
  224. local_bounds.axisExtents.x = 0.5f * (box.maxX - box.minX);
  225. local_bounds.axisExtents.y = 0.5f * (box.maxY - box.minY);
  226. local_bounds.axisExtents.z = 0.5f * (box.maxZ - box.minZ);
  227. local_bounds.localToParent(3,0) = box.minX + local_bounds.axisExtents.x;
  228. local_bounds.localToParent(3,1) = box.minY + local_bounds.axisExtents.y;
  229. local_bounds.localToParent(3,2) = box.minZ + local_bounds.axisExtents.z;
  230. local_bounds.sphereRadius = local_bounds.axisExtents.GetLength();
  231. if (local_bounds.sphereRadius < Stuff::SMALL)
  232. local_bounds.sphereRadius = 0.01f;
  233. Stuff::OBB parent_bounds;
  234. parent_bounds.Multiply(local_bounds, m_localToParent);
  235. info->m_bounds->Union(*info->m_bounds, parent_bounds);
  236. }
  237. //
  238. //----------------------------------------------
  239. // Tell our caller that we get to keep executing
  240. //----------------------------------------------
  241. //
  242. return true;
  243. }
  244. //------------------------------------------------------------------------------
  245. //
  246. void
  247. gosFX::PointCloud::CreateNewParticle(
  248. unsigned index,
  249. Stuff::Point3D *translation
  250. )
  251. {
  252. Check_Object(this);
  253. Check_Pointer(translation);
  254. //
  255. //-----------------------------------------------------------------------
  256. // Let our parent do creation, then turn on the particle in the cloud and
  257. // set its position
  258. //-----------------------------------------------------------------------
  259. //
  260. ParticleCloud::CreateNewParticle(index, translation);
  261. m_cloudImplementation->TurnOn(index);
  262. Verify(m_cloudImplementation->IsOn(index));
  263. m_P_localTranslation[index] = *translation;
  264. }
  265. //------------------------------------------------------------------------------
  266. //
  267. bool
  268. gosFX::PointCloud::AnimateParticle(
  269. unsigned index,
  270. const Stuff::LinearMatrix4D *world_to_new_local,
  271. Stuff::Time till
  272. )
  273. {
  274. Check_Object(this);
  275. //
  276. //-----------------------------------------------------------------------
  277. // If this cloud is unparented, we need to transform the point from local
  278. // space into world space and set the internal position/velocity pointers
  279. // to these temporary values
  280. //-----------------------------------------------------------------------
  281. //
  282. Particle *particle = GetParticle(index);
  283. Check_Object(particle);
  284. Stuff::Scalar age = particle->m_age;
  285. if (age >= 1.0f)
  286. return false;
  287. Set_Statistic(Point_Count, Point_Count+1);
  288. Stuff::Vector3D *velocity = &particle->m_localLinearVelocity;
  289. Stuff::Point3D *translation = &m_P_localTranslation[index];
  290. int sim_mode = GetSimulationMode();
  291. if (sim_mode == DynamicWorldSpaceSimulationMode)
  292. {
  293. Check_Object(translation);
  294. Check_Object(velocity);
  295. particle->m_worldLinearVelocity.Multiply(*velocity, m_localToWorld);
  296. particle->m_worldTranslation.Multiply(*translation, m_localToWorld);
  297. translation = &particle->m_worldTranslation;
  298. velocity = &particle->m_worldLinearVelocity;
  299. }
  300. Check_Object(translation);
  301. Check_Object(velocity);
  302. //
  303. //------------------------------------------------------------------
  304. // First, calculate the drag on the particle. Drag can never assist
  305. // velocity
  306. //------------------------------------------------------------------
  307. //
  308. Stuff::Scalar seed = particle->m_seed;
  309. Specification *spec = GetSpecification();
  310. Check_Object(spec);
  311. Stuff::Vector3D ether;
  312. ether.x = spec->m_pEtherVelocityX.ComputeValue(age, seed);
  313. ether.y = spec->m_pEtherVelocityY.ComputeValue(age, seed);
  314. ether.z = spec->m_pEtherVelocityZ.ComputeValue(age, seed);
  315. Stuff::Vector3D accel(Stuff::Vector3D::Identity);
  316. //
  317. //-------------------------------------------------------------------
  318. // Deal with pseudo-world simulation. In this mode, we interpret the
  319. // forces as if they are already in worldspace, and we transform them
  320. // back to local space
  321. //-------------------------------------------------------------------
  322. //
  323. Stuff::Scalar drag = -spec->m_pDrag.ComputeValue(age, seed);
  324. Max_Clamp(drag, 0.0f);
  325. if (sim_mode == StaticWorldSpaceSimulationMode)
  326. {
  327. Stuff::LinearMatrix4D world_to_effect;
  328. world_to_effect.Invert(m_localToWorld);
  329. Stuff::Vector3D local_ether;
  330. local_ether.MultiplyByInverse(ether, world_to_effect);
  331. Stuff::Vector3D rel_vel;
  332. rel_vel.Subtract(*velocity, local_ether);
  333. accel.Multiply(rel_vel, drag);
  334. //
  335. //-----------------------------------------
  336. // Now, add in acceleration of the particle
  337. //-----------------------------------------
  338. //
  339. Stuff::Vector3D world_accel;
  340. world_accel.x = spec->m_pAccelerationX.ComputeValue(age, seed);
  341. world_accel.y = spec->m_pAccelerationY.ComputeValue(age, seed);
  342. world_accel.z = spec->m_pAccelerationZ.ComputeValue(age, seed);
  343. Stuff::Vector3D local_accel;
  344. local_accel.Multiply(world_accel, world_to_effect);
  345. accel += local_accel;
  346. }
  347. //
  348. //----------------------------------------------------------------------
  349. // Otherwise, just add the forces in the same space the particles are in
  350. //----------------------------------------------------------------------
  351. //
  352. else
  353. {
  354. Stuff::Vector3D rel_vel;
  355. rel_vel.Subtract(*velocity, ether);
  356. accel.Multiply(rel_vel, drag);
  357. //
  358. //-----------------------------------------
  359. // Now, add in acceleration of the particle
  360. //-----------------------------------------
  361. //
  362. accel.x += spec->m_pAccelerationX.ComputeValue(age, seed);
  363. accel.y += spec->m_pAccelerationY.ComputeValue(age, seed);
  364. accel.z += spec->m_pAccelerationZ.ComputeValue(age, seed);
  365. }
  366. //
  367. //-------------------------------------------------
  368. // Compute the particle's new velocity and position
  369. //-------------------------------------------------
  370. //
  371. Stuff::Scalar time_slice =
  372. static_cast<Stuff::Scalar>(till - m_lastRan);
  373. velocity->AddScaled(*velocity, accel, time_slice);
  374. translation->AddScaled(*translation, *velocity, time_slice);
  375. //
  376. //---------------------------------------------------------------------
  377. // If we are unparented, we need to transform the velocity and position
  378. // data back into the NEW local space
  379. //---------------------------------------------------------------------
  380. //
  381. if (sim_mode == DynamicWorldSpaceSimulationMode)
  382. {
  383. Check_Object(world_to_new_local);
  384. particle->m_localLinearVelocity.Multiply(
  385. particle->m_worldLinearVelocity,
  386. *world_to_new_local
  387. );
  388. m_P_localTranslation[index].Multiply(
  389. particle->m_worldTranslation,
  390. *world_to_new_local
  391. );
  392. }
  393. //
  394. //------------------
  395. // Animate the color
  396. //------------------
  397. //
  398. Check_Pointer(m_P_color);
  399. m_P_color[index].red = spec->m_pRed.ComputeValue(age, seed);
  400. m_P_color[index].green = spec->m_pGreen.ComputeValue(age, seed);
  401. m_P_color[index].blue = spec->m_pBlue.ComputeValue(age, seed);
  402. m_P_color[index].alpha = spec->m_pAlpha.ComputeValue(age, seed);
  403. return true;
  404. }
  405. //------------------------------------------------------------------------------
  406. //
  407. void gosFX::PointCloud::DestroyParticle(unsigned index)
  408. {
  409. Check_Object(this);
  410. m_cloudImplementation->TurnOff(index);
  411. Verify(!m_cloudImplementation->IsOn(index));
  412. ParticleCloud::DestroyParticle(index);
  413. }
  414. //------------------------------------------------------------------------------
  415. //
  416. void gosFX::PointCloud::Draw(DrawInfo *info)
  417. {
  418. Check_Object(this);
  419. Check_Object(info);
  420. if (m_activeParticleCount)
  421. {
  422. MidLevelRenderer::DrawEffectInformation dInfo;
  423. dInfo.effect = m_cloudImplementation;
  424. Specification *spec = GetSpecification();
  425. Check_Object(spec);
  426. dInfo.state.Combine(info->m_state, spec->m_state);
  427. dInfo.clippingFlags = info->m_clippingFlags;
  428. Stuff::LinearMatrix4D local_to_world;
  429. local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
  430. dInfo.effectToWorld = &local_to_world;
  431. info->m_clipper->DrawEffect(&dInfo);
  432. }
  433. ParticleCloud::Draw(info);
  434. }
  435. //------------------------------------------------------------------------------
  436. //
  437. void
  438. gosFX::PointCloud::TestInstance() const
  439. {
  440. Verify(IsDerivedFrom(DefaultData));
  441. }