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 |
|
---|
24 | i4_profile_class pf_part_emit("particle_emit::think");
|
---|
25 |
|
---|
26 |
|
---|
27 | g1_object_definer<g1_particle_emitter_class>
|
---|
28 | g1_particle_emitter_def("particle_emitter",
|
---|
29 | g1_object_definition_class::EDITOR_SELECTABLE |
|
---|
30 | g1_object_definition_class::HAS_ALPHA);
|
---|
31 |
|
---|
32 |
|
---|
33 | i4_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 |
|
---|
44 | void 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 |
|
---|
52 | void 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 |
|
---|
59 | void 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 |
|
---|
66 | g1_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 |
|
---|
81 | void g1_particle_emitter_class::save(g1_saver_class *fp)
|
---|
82 | {
|
---|
83 | g1_object_class::save(fp);
|
---|
84 | }
|
---|
85 |
|
---|
86 |
|
---|
87 | r1_texture_ref g1_default_particle_texture("red_flare");
|
---|
88 |
|
---|
89 |
|
---|
90 | void 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 |
|
---|
109 | void 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 |
|
---|
127 | void 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 |
|
---|
141 | void 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 |
|
---|
189 | void 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 | }
|
---|