source: golgotha/src/golg/objs/particle_emitter.cc

Last change on this file was 80, checked in by Sam Hocevar, 11 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 8.4 KB
Line 
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
9#include "objs/particle_emitter.hh"
10#include "object_definer.hh"
11#include "g1_render.hh"
12#include "r1_api.hh"
13#include "g1_texture_id.hh"
14#include "r1_clip.hh"
15#include "g1_rand.hh"
16#include "math/random.hh"
17#include "map_man.hh"
18#include "map.hh"
19#include "time/profile.hh"
20#include "lisp/li_class.hh"
21#include "saver.hh"
22#include "draw_context.hh"
23
24i4_profile_class pf_part_emit("particle_emit::think");
25
26
27g1_object_definer<g1_particle_emitter_class>
28g1_particle_emitter_def("particle_emitter",
29                        g1_object_definition_class::EDITOR_SELECTABLE |
30                        g1_object_definition_class::HAS_ALPHA);
31
32
33i4_bool g1_particle_emitter_class::occupy_location()
34{
35  i4_bool ret=g1_object_class::occupy_location();
36
37  if (radius>2)
38    g1_get_map()->add_object(cell_on, i4_f_to_i(x), i4_f_to_i(y));
39 
40  return ret;
41}
42
43
44void g1_particle_emitter_class::unoccupy_location()
45{
46  g1_object_class::unoccupy_location();
47
48  if (radius>2)
49    g1_get_map()->remove_object(cell_on);
50}
51
52void g1_particle_class::load(i4_file_class *fp)
53{
54  fp->read_format("ffffffff", &x,&y,&z, &xv,&yv,&zv, &grow_speed, &size);
55  ticks_left=fp->read_32();
56  lx=x; ly=y; lz=z;
57}
58
59void g1_particle_class::save(i4_file_class *fp)
60{
61  fp->write_format("ffffffff", &x,&y,&z, &xv,&yv,&zv, &grow_speed, &size);
62  fp->write_32(ticks_left);
63
64}
65
66g1_particle_emitter_class::g1_particle_emitter_class(g1_object_type id, g1_loader_class *fp)
67  : g1_object_class(id, fp)
68{
69  cell_on.object=this;
70  stopping=i4_F;
71  t_in_use=0;
72  x1=y1=x2=y2=0;
73  radius=0;
74
75  params.emitter_lifetime=0;
76  for (int i=0; i<MAX_PARTICLES; i++)
77    particles[i].in_use=i4_F;
78
79}
80
81void g1_particle_emitter_class::save(g1_saver_class *fp)
82{
83  g1_object_class::save(fp);
84}
85
86
87r1_texture_ref g1_default_particle_texture("red_flare");
88
89 
90void g1_particle_emitter_params::defaults()
91{
92  texture=g1_default_particle_texture.get();
93
94  start_size=0.2;
95  grow_speed=0.01;
96  grow_accel=0;
97 
98  creation_probability=0.75;
99  max_speed=0.1;
100  air_friction=0.95;
101  particle_lifetime=20;
102  emitter_lifetime = -1;
103  num_create_attempts_per_tick=2;
104  start_size_random_range=0;
105  gravity=0;
106  speed=i4_3d_vector(0,0,0);
107}
108
109void g1_particle_emitter_class::setup(float _x, float _y, float _h,
110                                      g1_particle_emitter_params &_params)
111{
112  params=_params;
113
114  x=_x; y=_y; h=_h;
115  grab_old();
116
117  for (int i=0; i<MAX_PARTICLES; i++)
118    particles[i].in_use=i4_F;   
119  t_in_use=0;
120
121  occupy_location();
122  think();
123}
124
125
126
127void g1_particle_emitter_class::move(float new_x, float new_y, float new_h)
128{
129  li_class_context v_context(vars);
130  unoccupy_location();
131  grab_old();
132
133  params.speed.x=new_x-x;
134  params.speed.y=new_y-y;
135  params.speed.z=new_h-h;
136 
137  x=new_x; y=new_y; h=new_h;
138  occupy_location();
139}
140
141void g1_particle_emitter_class::draw(g1_draw_context_class *context)
142{
143  if (!t_in_use) return;
144
145  float center_x=g1_render.center_x, center_y=g1_render.center_y;
146
147 
148  if (!params.texture) return;
149
150  g1_render.r_api->set_filter_mode(R1_BILINEAR_FILTERING);
151
152  float fr=g1_render.frame_ratio;
153
154
155  for (int i=0; i<MAX_PARTICLES; i++)
156  {
157    if (particles[i].in_use)
158    {
159      // calculate interpolated position of the particle
160      float rx=(particles[i].x-particles[i].lx)*fr + particles[i].lx,
161        ry=(particles[i].y-particles[i].ly)*fr + particles[i].ly,
162        rh=(particles[i].z-particles[i].lz)*fr + particles[i].lz;
163   
164      i4_3d_vector screen_pos;
165      context->transform->transform(i4_3d_point_class(rx,ry,rh), screen_pos);
166
167      i4_float ooz = 1 / screen_pos.z;
168      i4_float xs = center_x * ooz * g1_render.scale_x;
169      i4_float ys = center_y * ooz * g1_render.scale_y;
170
171      if (screen_pos.z > r1_near_clip_z)
172      {
173        float cx=center_x + screen_pos.x*xs;
174        float cy=center_y + screen_pos.y*ys;
175        float w=particles[i].size * center_x * 2 * ooz;
176       
177        r1_clip_render_textured_rect(i4_f_to_i(cx-w/2), i4_f_to_i(cy-w/2),
178                                     i4_f_to_i(cx+w/2), i4_f_to_i(cy+w/2), screen_pos.z,
179                                     particles[i].ticks_left/(float)params.particle_lifetime,
180                                     i4_f_to_i(center_x*2), i4_f_to_i(center_y*2),
181                                     params.texture, 0, g1_render.r_api);       
182      }
183    }
184  }
185
186  g1_render.r_api->set_filter_mode(R1_NO_FILTERING);
187}
188 
189void g1_particle_emitter_class::think()
190{
191  pf_part_emit.start();
192
193  if (params.emitter_lifetime>0)
194    params.emitter_lifetime--;
195  else if (params.emitter_lifetime!=-1)
196    stopping = i4_T;
197
198  if (t_in_use!=MAX_PARTICLES && !stopping)   // check to see if we should add some more particles
199  {
200    int t_tries=params.num_create_attempts_per_tick;
201    float max_s=params.max_speed;
202
203    for (int j=0; j<t_tries; j++)
204    {
205      if (i4_float_rand()<params.creation_probability)
206      {
207        for (int i=0; i<MAX_PARTICLES; i++)
208        {
209          if (!particles[i].in_use)
210          {
211            particles[i].x=particles[i].lx=lx;
212            particles[i].y=particles[i].ly=ly;
213            particles[i].z=particles[i].lz=lh;
214         
215
216            particles[i].xv=(g1_float_rand(i+2)*2-1) * params.speed.x;
217            if (particles[i].xv> max_s)
218              particles[i].xv=max_s;
219
220            particles[i].yv=(g1_float_rand(i+3)*2-1) * params.speed.y;
221            if (particles[i].yv> max_s)
222              particles[i].yv=max_s;
223
224            particles[i].zv=(g1_float_rand(i+4)*2-1) * params.speed.z;
225            if (particles[i].zv> max_s)
226              particles[i].zv=max_s;
227
228            particles[i].grow_speed=params.grow_speed;
229            particles[i].size=params.start_size + i4_float_rand() * params.start_size_random_range;
230            particles[i].ticks_left=params.particle_lifetime;
231            particles[i].in_use=i4_T;
232
233            t_in_use++;
234            i=MAX_PARTICLES;
235          }
236        }
237      }
238    }
239  }
240 
241  float bx1=100000,by1=100000,bx2=-100000,by2=-100000;
242
243  if (t_in_use)
244  {
245    float airf=params.air_friction;
246    for (int i=0; i<MAX_PARTICLES; i++)
247    {
248      if (particles[i].in_use)
249      {
250        if (particles[i].ticks_left<=0 || particles[i].size<=0)
251        {
252          particles[i].in_use=i4_F;
253          t_in_use--;
254        }
255        else
256        {
257          particles[i].lx=particles[i].x;     // grab old position
258          particles[i].ly=particles[i].y;
259          particles[i].lz=particles[i].z;
260
261          particles[i].x+=particles[i].xv;    // move with speed
262          particles[i].y+=particles[i].yv;
263          particles[i].z+=particles[i].zv;
264          particles[i].size+=particles[i].grow_speed;
265
266          particles[i].xv*=airf;    // apply air friction
267          particles[i].yv*=airf;
268          particles[i].zv=airf*particles[i].zv + params.gravity;
269
270          particles[i].grow_speed+=params.grow_accel;
271
272          particles[i].ticks_left--;
273
274          if (particles[i].x<bx1) bx1=particles[i].x;
275          if (particles[i].x>bx2) bx2=particles[i].x;
276          if (particles[i].y<by1) by1=particles[i].y;
277          if (particles[i].y>by2) by2=particles[i].y;
278        }
279      }
280    }
281
282
283    if (bx1!=100000)
284    {
285      if (bx1<0) bx1=0;
286      if (bx2>=g1_get_map()->width())  bx2=g1_get_map()->width()-1;
287      if (by1<0) by1=0;
288      if (by2>=g1_get_map()->height())  by2=g1_get_map()->height()-1;
289
290      if (bx1!=x1 || by1!=y1 || bx2!=x2 || by2!=y2)  // have bounds changed?
291      {
292        unoccupy_location();
293        x1=bx1;  y1=by1; x2=bx2; y2=by2;
294
295   
296
297        radius=x2-x1;
298     
299        if (y2-y1>radius)
300          radius=y2-y1;
301        if (radius<0)
302          radius=0;
303       
304        occupy_location();
305      }
306    }
307  }
308
309  if (!t_in_use && stopping)
310  {
311    unoccupy_location();
312    request_remove();
313  }
314  else
315    request_think();
316
317  pf_part_emit.stop();
318}
Note: See TracBrowser for help on using the repository browser.