particles.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "particles.h"
  17. #include "constants.h"
  18. #include "debug.h"
  19. #include "main.h" // For g_profiler and g_settings
  20. #include "settings.h"
  21. #include "tile.h"
  22. #include "gamedef.h"
  23. #include "collision.h"
  24. #include <stdlib.h>
  25. #include "util/numeric.h"
  26. #include "light.h"
  27. #include "environment.h"
  28. #include "clientmap.h"
  29. #include "mapnode.h"
  30. /*
  31. Utility
  32. */
  33. v3f random_v3f(v3f min, v3f max)
  34. {
  35. return v3f( rand()/(float)RAND_MAX*(max.X-min.X)+min.X,
  36. rand()/(float)RAND_MAX*(max.Y-min.Y)+min.Y,
  37. rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
  38. }
  39. std::vector<Particle*> all_particles;
  40. std::map<u32, ParticleSpawner*> all_particlespawners;
  41. Particle::Particle(
  42. IGameDef *gamedef,
  43. scene::ISceneManager* smgr,
  44. LocalPlayer *player,
  45. ClientEnvironment &env,
  46. v3f pos,
  47. v3f velocity,
  48. v3f acceleration,
  49. float expirationtime,
  50. float size,
  51. bool collisiondetection,
  52. bool vertical,
  53. video::ITexture *texture,
  54. v2f texpos,
  55. v2f texsize
  56. ):
  57. scene::ISceneNode(smgr->getRootSceneNode(), smgr)
  58. {
  59. // Misc
  60. m_gamedef = gamedef;
  61. m_env = &env;
  62. // Texture
  63. m_material.setFlag(video::EMF_LIGHTING, false);
  64. m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
  65. m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
  66. m_material.setFlag(video::EMF_FOG_ENABLE, true);
  67. m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  68. m_material.setTexture(0, texture);
  69. m_texpos = texpos;
  70. m_texsize = texsize;
  71. // Particle related
  72. m_pos = pos;
  73. m_velocity = velocity;
  74. m_acceleration = acceleration;
  75. m_expiration = expirationtime;
  76. m_time = 0;
  77. m_player = player;
  78. m_size = size;
  79. m_collisiondetection = collisiondetection;
  80. m_vertical = vertical;
  81. // Irrlicht stuff
  82. m_collisionbox = core::aabbox3d<f32>
  83. (-size/2,-size/2,-size/2,size/2,size/2,size/2);
  84. this->setAutomaticCulling(scene::EAC_OFF);
  85. // Init lighting
  86. updateLight();
  87. // Init model
  88. updateVertices();
  89. all_particles.push_back(this);
  90. }
  91. Particle::~Particle()
  92. {
  93. }
  94. void Particle::OnRegisterSceneNode()
  95. {
  96. if (IsVisible)
  97. {
  98. SceneManager->registerNodeForRendering
  99. (this, scene::ESNRP_TRANSPARENT);
  100. SceneManager->registerNodeForRendering
  101. (this, scene::ESNRP_SOLID);
  102. }
  103. ISceneNode::OnRegisterSceneNode();
  104. }
  105. void Particle::render()
  106. {
  107. // TODO: Render particles in front of water and the selectionbox
  108. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  109. driver->setMaterial(m_material);
  110. driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
  111. u16 indices[] = {0,1,2, 2,3,0};
  112. driver->drawVertexPrimitiveList(m_vertices, 4,
  113. indices, 2, video::EVT_STANDARD,
  114. scene::EPT_TRIANGLES, video::EIT_16BIT);
  115. }
  116. void Particle::step(float dtime)
  117. {
  118. m_time += dtime;
  119. if (m_collisiondetection)
  120. {
  121. core::aabbox3d<f32> box = m_collisionbox;
  122. v3f p_pos = m_pos*BS;
  123. v3f p_velocity = m_velocity*BS;
  124. v3f p_acceleration = m_acceleration*BS;
  125. collisionMoveSimple(m_env, m_gamedef,
  126. BS*0.5, box,
  127. 0, dtime,
  128. p_pos, p_velocity, p_acceleration);
  129. m_pos = p_pos/BS;
  130. m_velocity = p_velocity/BS;
  131. m_acceleration = p_acceleration/BS;
  132. }
  133. else
  134. {
  135. m_velocity += m_acceleration * dtime;
  136. m_pos += m_velocity * dtime;
  137. }
  138. // Update lighting
  139. updateLight();
  140. // Update model
  141. updateVertices();
  142. }
  143. void Particle::updateLight()
  144. {
  145. u8 light = 0;
  146. try{
  147. v3s16 p = v3s16(
  148. floor(m_pos.X+0.5),
  149. floor(m_pos.Y+0.5),
  150. floor(m_pos.Z+0.5)
  151. );
  152. MapNode n = m_env->getClientMap().getNode(p);
  153. light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef());
  154. }
  155. catch(InvalidPositionException &e){
  156. light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
  157. }
  158. m_light = decode_light(light);
  159. }
  160. void Particle::updateVertices()
  161. {
  162. video::SColor c(255, m_light, m_light, m_light);
  163. f32 tx0 = m_texpos.X;
  164. f32 tx1 = m_texpos.X + m_texsize.X;
  165. f32 ty0 = m_texpos.Y;
  166. f32 ty1 = m_texpos.Y + m_texsize.Y;
  167. m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
  168. c, tx0, ty1);
  169. m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
  170. c, tx1, ty1);
  171. m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
  172. c, tx1, ty0);
  173. m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
  174. c, tx0, ty0);
  175. v3s16 camera_offset = m_env->getCameraOffset();
  176. for(u16 i=0; i<4; i++)
  177. {
  178. if (m_vertical) {
  179. v3f ppos = m_player->getPosition()/BS;
  180. m_vertices[i].Pos.rotateXZBy(atan2(ppos.Z-m_pos.Z, ppos.X-m_pos.X)/core::DEGTORAD+90);
  181. } else {
  182. m_vertices[i].Pos.rotateYZBy(m_player->getPitch());
  183. m_vertices[i].Pos.rotateXZBy(m_player->getYaw());
  184. }
  185. m_box.addInternalPoint(m_vertices[i].Pos);
  186. m_vertices[i].Pos += m_pos*BS - intToFloat(camera_offset, BS);
  187. }
  188. }
  189. /*
  190. Helpers
  191. */
  192. void allparticles_step (float dtime)
  193. {
  194. for(std::vector<Particle*>::iterator i = all_particles.begin();
  195. i != all_particles.end();)
  196. {
  197. if ((*i)->get_expired())
  198. {
  199. (*i)->remove();
  200. delete *i;
  201. i = all_particles.erase(i);
  202. }
  203. else
  204. {
  205. (*i)->step(dtime);
  206. i++;
  207. }
  208. }
  209. }
  210. void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
  211. LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
  212. const TileSpec tiles[])
  213. {
  214. for (u16 j = 0; j < 32; j++) // set the amount of particles here
  215. {
  216. addNodeParticle(gamedef, smgr, player, env, pos, tiles);
  217. }
  218. }
  219. void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
  220. LocalPlayer *player, ClientEnvironment &env,
  221. v3s16 pos, const TileSpec tiles[])
  222. {
  223. addNodeParticle(gamedef, smgr, player, env, pos, tiles);
  224. }
  225. // add a particle of a node
  226. // used by digging and punching particles
  227. void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
  228. LocalPlayer *player, ClientEnvironment &env, v3s16 pos,
  229. const TileSpec tiles[])
  230. {
  231. // Texture
  232. u8 texid = myrand_range(0,5);
  233. video::ITexture *texture = tiles[texid].texture;
  234. // Only use first frame of animated texture
  235. f32 ymax = 1;
  236. if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
  237. ymax /= tiles[texid].animation_frame_count;
  238. float size = rand()%64/512.;
  239. float visual_size = BS*size;
  240. v2f texsize(size*2, ymax*size*2);
  241. v2f texpos;
  242. texpos.X = ((rand()%64)/64.-texsize.X);
  243. texpos.Y = ymax*((rand()%64)/64.-texsize.Y);
  244. // Physics
  245. v3f velocity( (rand()%100/50.-1)/1.5,
  246. rand()%100/35.,
  247. (rand()%100/50.-1)/1.5);
  248. v3f acceleration(0,-9,0);
  249. v3f particlepos = v3f(
  250. (f32)pos.X+rand()%100/200.-0.25,
  251. (f32)pos.Y+rand()%100/200.-0.25,
  252. (f32)pos.Z+rand()%100/200.-0.25
  253. );
  254. new Particle(
  255. gamedef,
  256. smgr,
  257. player,
  258. env,
  259. particlepos,
  260. velocity,
  261. acceleration,
  262. rand()%100/100., // expiration time
  263. visual_size,
  264. true,
  265. false,
  266. texture,
  267. texpos,
  268. texsize);
  269. }
  270. /*
  271. ParticleSpawner
  272. */
  273. ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, LocalPlayer *player,
  274. u16 amount, float time,
  275. v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
  276. float minexptime, float maxexptime, float minsize, float maxsize,
  277. bool collisiondetection, bool vertical, video::ITexture *texture, u32 id)
  278. {
  279. m_gamedef = gamedef;
  280. m_smgr = smgr;
  281. m_player = player;
  282. m_amount = amount;
  283. m_spawntime = time;
  284. m_minpos = minpos;
  285. m_maxpos = maxpos;
  286. m_minvel = minvel;
  287. m_maxvel = maxvel;
  288. m_minacc = minacc;
  289. m_maxacc = maxacc;
  290. m_minexptime = minexptime;
  291. m_maxexptime = maxexptime;
  292. m_minsize = minsize;
  293. m_maxsize = maxsize;
  294. m_collisiondetection = collisiondetection;
  295. m_vertical = vertical;
  296. m_texture = texture;
  297. m_time = 0;
  298. for (u16 i = 0; i<=m_amount; i++)
  299. {
  300. float spawntime = (float)rand()/(float)RAND_MAX*m_spawntime;
  301. m_spawntimes.push_back(spawntime);
  302. }
  303. all_particlespawners.insert(std::pair<u32, ParticleSpawner*>(id, this));
  304. }
  305. ParticleSpawner::~ParticleSpawner() {}
  306. void ParticleSpawner::step(float dtime, ClientEnvironment &env)
  307. {
  308. m_time += dtime;
  309. if (m_spawntime != 0) // Spawner exists for a predefined timespan
  310. {
  311. for(std::vector<float>::iterator i = m_spawntimes.begin();
  312. i != m_spawntimes.end();)
  313. {
  314. if ((*i) <= m_time && m_amount > 0)
  315. {
  316. m_amount--;
  317. v3f pos = random_v3f(m_minpos, m_maxpos);
  318. v3f vel = random_v3f(m_minvel, m_maxvel);
  319. v3f acc = random_v3f(m_minacc, m_maxacc);
  320. float exptime = rand()/(float)RAND_MAX
  321. *(m_maxexptime-m_minexptime)
  322. +m_minexptime;
  323. float size = rand()/(float)RAND_MAX
  324. *(m_maxsize-m_minsize)
  325. +m_minsize;
  326. new Particle(
  327. m_gamedef,
  328. m_smgr,
  329. m_player,
  330. env,
  331. pos,
  332. vel,
  333. acc,
  334. exptime,
  335. size,
  336. m_collisiondetection,
  337. m_vertical,
  338. m_texture,
  339. v2f(0.0, 0.0),
  340. v2f(1.0, 1.0));
  341. i = m_spawntimes.erase(i);
  342. }
  343. else
  344. {
  345. i++;
  346. }
  347. }
  348. }
  349. else // Spawner exists for an infinity timespan, spawn on a per-second base
  350. {
  351. for (int i = 0; i <= m_amount; i++)
  352. {
  353. if (rand()/(float)RAND_MAX < dtime)
  354. {
  355. v3f pos = random_v3f(m_minpos, m_maxpos);
  356. v3f vel = random_v3f(m_minvel, m_maxvel);
  357. v3f acc = random_v3f(m_minacc, m_maxacc);
  358. float exptime = rand()/(float)RAND_MAX
  359. *(m_maxexptime-m_minexptime)
  360. +m_minexptime;
  361. float size = rand()/(float)RAND_MAX
  362. *(m_maxsize-m_minsize)
  363. +m_minsize;
  364. new Particle(
  365. m_gamedef,
  366. m_smgr,
  367. m_player,
  368. env,
  369. pos,
  370. vel,
  371. acc,
  372. exptime,
  373. size,
  374. m_collisiondetection,
  375. m_vertical,
  376. m_texture,
  377. v2f(0.0, 0.0),
  378. v2f(1.0, 1.0));
  379. }
  380. }
  381. }
  382. }
  383. void allparticlespawners_step (float dtime, ClientEnvironment &env)
  384. {
  385. for(std::map<u32, ParticleSpawner*>::iterator i =
  386. all_particlespawners.begin();
  387. i != all_particlespawners.end();)
  388. {
  389. if (i->second->get_expired())
  390. {
  391. delete i->second;
  392. all_particlespawners.erase(i++);
  393. }
  394. else
  395. {
  396. i->second->step(dtime, env);
  397. i++;
  398. }
  399. }
  400. }
  401. void delete_particlespawner (u32 id)
  402. {
  403. if (all_particlespawners.find(id) != all_particlespawners.end())
  404. {
  405. delete all_particlespawners.find(id)->second;
  406. all_particlespawners.erase(id);
  407. }
  408. }
  409. void clear_particles ()
  410. {
  411. for(std::map<u32, ParticleSpawner*>::iterator i =
  412. all_particlespawners.begin();
  413. i != all_particlespawners.end();)
  414. {
  415. delete i->second;
  416. all_particlespawners.erase(i++);
  417. }
  418. for(std::vector<Particle*>::iterator i =
  419. all_particles.begin();
  420. i != all_particles.end();)
  421. {
  422. (*i)->remove();
  423. delete *i;
  424. i = all_particles.erase(i);
  425. }
  426. }