particle_emitter.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /********************************************************************** <BR>
  2. This file is part of Crack dot Com's free source code release of
  3. Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
  4. information about compiling & licensing issues visit this URL</a>
  5. <PRE> If that doesn't help, contact Jonathan Clark at
  6. golgotha_source@usa.net (Subject should have "GOLG" in it)
  7. ***********************************************************************/
  8. #include "objs/particle_emitter.hh"
  9. #include "object_definer.hh"
  10. #include "g1_render.hh"
  11. #include "r1_api.hh"
  12. #include "g1_texture_id.hh"
  13. #include "r1_clip.hh"
  14. #include "g1_rand.hh"
  15. #include "math/random.hh"
  16. #include "map_man.hh"
  17. #include "map.hh"
  18. #include "time/profile.hh"
  19. #include "lisp/li_class.hh"
  20. #include "saver.hh"
  21. #include "draw_context.hh"
  22. i4_profile_class pf_part_emit("particle_emit::think");
  23. g1_object_definer<g1_particle_emitter_class>
  24. g1_particle_emitter_def("particle_emitter",
  25. g1_object_definition_class::EDITOR_SELECTABLE |
  26. g1_object_definition_class::HAS_ALPHA);
  27. i4_bool g1_particle_emitter_class::occupy_location()
  28. {
  29. i4_bool ret=g1_object_class::occupy_location();
  30. if (radius>2)
  31. g1_get_map()->add_object(cell_on, i4_f_to_i(x), i4_f_to_i(y));
  32. return ret;
  33. }
  34. void g1_particle_emitter_class::unoccupy_location()
  35. {
  36. g1_object_class::unoccupy_location();
  37. if (radius>2)
  38. g1_get_map()->remove_object(cell_on);
  39. }
  40. void g1_particle_class::load(i4_file_class *fp)
  41. {
  42. fp->read_format("ffffffff", &x,&y,&z, &xv,&yv,&zv, &grow_speed, &size);
  43. ticks_left=fp->read_32();
  44. lx=x; ly=y; lz=z;
  45. }
  46. void g1_particle_class::save(i4_file_class *fp)
  47. {
  48. fp->write_format("ffffffff", &x,&y,&z, &xv,&yv,&zv, &grow_speed, &size);
  49. fp->write_32(ticks_left);
  50. }
  51. g1_particle_emitter_class::g1_particle_emitter_class(g1_object_type id, g1_loader_class *fp)
  52. : g1_object_class(id, fp)
  53. {
  54. cell_on.object=this;
  55. stopping=i4_F;
  56. t_in_use=0;
  57. x1=y1=x2=y2=0;
  58. radius=0;
  59. params.emitter_lifetime=0;
  60. for (int i=0; i<MAX_PARTICLES; i++)
  61. particles[i].in_use=i4_F;
  62. }
  63. void g1_particle_emitter_class::save(g1_saver_class *fp)
  64. {
  65. g1_object_class::save(fp);
  66. }
  67. r1_texture_ref g1_default_particle_texture("red_flare");
  68. void g1_particle_emitter_params::defaults()
  69. {
  70. texture=g1_default_particle_texture.get();
  71. start_size=0.2;
  72. grow_speed=0.01;
  73. grow_accel=0;
  74. creation_probability=0.75;
  75. max_speed=0.1;
  76. air_friction=0.95;
  77. particle_lifetime=20;
  78. emitter_lifetime = -1;
  79. num_create_attempts_per_tick=2;
  80. start_size_random_range=0;
  81. gravity=0;
  82. speed=i4_3d_vector(0,0,0);
  83. }
  84. void g1_particle_emitter_class::setup(float _x, float _y, float _h,
  85. g1_particle_emitter_params &_params)
  86. {
  87. params=_params;
  88. x=_x; y=_y; h=_h;
  89. grab_old();
  90. for (int i=0; i<MAX_PARTICLES; i++)
  91. particles[i].in_use=i4_F;
  92. t_in_use=0;
  93. occupy_location();
  94. think();
  95. }
  96. void g1_particle_emitter_class::move(float new_x, float new_y, float new_h)
  97. {
  98. li_class_context v_context(vars);
  99. unoccupy_location();
  100. grab_old();
  101. params.speed.x=new_x-x;
  102. params.speed.y=new_y-y;
  103. params.speed.z=new_h-h;
  104. x=new_x; y=new_y; h=new_h;
  105. occupy_location();
  106. }
  107. void g1_particle_emitter_class::draw(g1_draw_context_class *context)
  108. {
  109. if (!t_in_use) return;
  110. float center_x=g1_render.center_x, center_y=g1_render.center_y;
  111. if (!params.texture) return;
  112. g1_render.r_api->set_filter_mode(R1_BILINEAR_FILTERING);
  113. float fr=g1_render.frame_ratio;
  114. for (int i=0; i<MAX_PARTICLES; i++)
  115. {
  116. if (particles[i].in_use)
  117. {
  118. // calculate interpolated position of the particle
  119. float rx=(particles[i].x-particles[i].lx)*fr + particles[i].lx,
  120. ry=(particles[i].y-particles[i].ly)*fr + particles[i].ly,
  121. rh=(particles[i].z-particles[i].lz)*fr + particles[i].lz;
  122. i4_3d_vector screen_pos;
  123. context->transform->transform(i4_3d_point_class(rx,ry,rh), screen_pos);
  124. i4_float ooz = 1 / screen_pos.z;
  125. i4_float xs = center_x * ooz * g1_render.scale_x;
  126. i4_float ys = center_y * ooz * g1_render.scale_y;
  127. if (screen_pos.z > r1_near_clip_z)
  128. {
  129. float cx=center_x + screen_pos.x*xs;
  130. float cy=center_y + screen_pos.y*ys;
  131. float w=particles[i].size * center_x * 2 * ooz;
  132. r1_clip_render_textured_rect(i4_f_to_i(cx-w/2), i4_f_to_i(cy-w/2),
  133. i4_f_to_i(cx+w/2), i4_f_to_i(cy+w/2), screen_pos.z,
  134. particles[i].ticks_left/(float)params.particle_lifetime,
  135. i4_f_to_i(center_x*2), i4_f_to_i(center_y*2),
  136. params.texture, 0, g1_render.r_api);
  137. }
  138. }
  139. }
  140. g1_render.r_api->set_filter_mode(R1_NO_FILTERING);
  141. }
  142. void g1_particle_emitter_class::think()
  143. {
  144. pf_part_emit.start();
  145. if (params.emitter_lifetime>0)
  146. params.emitter_lifetime--;
  147. else if (params.emitter_lifetime!=-1)
  148. stopping = i4_T;
  149. if (t_in_use!=MAX_PARTICLES && !stopping) // check to see if we should add some more particles
  150. {
  151. int t_tries=params.num_create_attempts_per_tick;
  152. float max_s=params.max_speed;
  153. for (int j=0; j<t_tries; j++)
  154. {
  155. if (i4_float_rand()<params.creation_probability)
  156. {
  157. for (int i=0; i<MAX_PARTICLES; i++)
  158. {
  159. if (!particles[i].in_use)
  160. {
  161. particles[i].x=particles[i].lx=lx;
  162. particles[i].y=particles[i].ly=ly;
  163. particles[i].z=particles[i].lz=lh;
  164. particles[i].xv=(g1_float_rand(i+2)*2-1) * params.speed.x;
  165. if (particles[i].xv> max_s)
  166. particles[i].xv=max_s;
  167. particles[i].yv=(g1_float_rand(i+3)*2-1) * params.speed.y;
  168. if (particles[i].yv> max_s)
  169. particles[i].yv=max_s;
  170. particles[i].zv=(g1_float_rand(i+4)*2-1) * params.speed.z;
  171. if (particles[i].zv> max_s)
  172. particles[i].zv=max_s;
  173. particles[i].grow_speed=params.grow_speed;
  174. particles[i].size=params.start_size + i4_float_rand() * params.start_size_random_range;
  175. particles[i].ticks_left=params.particle_lifetime;
  176. particles[i].in_use=i4_T;
  177. t_in_use++;
  178. i=MAX_PARTICLES;
  179. }
  180. }
  181. }
  182. }
  183. }
  184. float bx1=100000,by1=100000,bx2=-100000,by2=-100000;
  185. if (t_in_use)
  186. {
  187. float airf=params.air_friction;
  188. for (int i=0; i<MAX_PARTICLES; i++)
  189. {
  190. if (particles[i].in_use)
  191. {
  192. if (particles[i].ticks_left<=0 || particles[i].size<=0)
  193. {
  194. particles[i].in_use=i4_F;
  195. t_in_use--;
  196. }
  197. else
  198. {
  199. particles[i].lx=particles[i].x; // grab old position
  200. particles[i].ly=particles[i].y;
  201. particles[i].lz=particles[i].z;
  202. particles[i].x+=particles[i].xv; // move with speed
  203. particles[i].y+=particles[i].yv;
  204. particles[i].z+=particles[i].zv;
  205. particles[i].size+=particles[i].grow_speed;
  206. particles[i].xv*=airf; // apply air friction
  207. particles[i].yv*=airf;
  208. particles[i].zv=airf*particles[i].zv + params.gravity;
  209. particles[i].grow_speed+=params.grow_accel;
  210. particles[i].ticks_left--;
  211. if (particles[i].x<bx1) bx1=particles[i].x;
  212. if (particles[i].x>bx2) bx2=particles[i].x;
  213. if (particles[i].y<by1) by1=particles[i].y;
  214. if (particles[i].y>by2) by2=particles[i].y;
  215. }
  216. }
  217. }
  218. if (bx1!=100000)
  219. {
  220. if (bx1<0) bx1=0;
  221. if (bx2>=g1_get_map()->width()) bx2=g1_get_map()->width()-1;
  222. if (by1<0) by1=0;
  223. if (by2>=g1_get_map()->height()) by2=g1_get_map()->height()-1;
  224. if (bx1!=x1 || by1!=y1 || bx2!=x2 || by2!=y2) // have bounds changed?
  225. {
  226. unoccupy_location();
  227. x1=bx1; y1=by1; x2=bx2; y2=by2;
  228. radius=x2-x1;
  229. if (y2-y1>radius)
  230. radius=y2-y1;
  231. if (radius<0)
  232. radius=0;
  233. occupy_location();
  234. }
  235. }
  236. }
  237. if (!t_in_use && stopping)
  238. {
  239. unoccupy_location();
  240. request_remove();
  241. }
  242. else
  243. request_think();
  244. pf_part_emit.stop();
  245. }