[80] | 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 | }
|
---|