/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "objs/particle_emitter.hh"
#include "object_definer.hh"
#include "g1_render.hh"
#include "r1_api.hh"
#include "g1_texture_id.hh"
#include "r1_clip.hh"
#include "g1_rand.hh"
#include "math/random.hh"
#include "map_man.hh"
#include "map.hh"
#include "time/profile.hh"
#include "lisp/li_class.hh"
#include "saver.hh"
#include "draw_context.hh"

i4_profile_class pf_part_emit("particle_emit::think");


g1_object_definer 
g1_particle_emitter_def("particle_emitter", 
                        g1_object_definition_class::EDITOR_SELECTABLE |
                        g1_object_definition_class::HAS_ALPHA);


i4_bool g1_particle_emitter_class::occupy_location()
{
  i4_bool ret=g1_object_class::occupy_location();

  if (radius>2)
    g1_get_map()->add_object(cell_on, i4_f_to_i(x), i4_f_to_i(y));
  
  return ret;
}


void g1_particle_emitter_class::unoccupy_location()
{
  g1_object_class::unoccupy_location();

  if (radius>2)
    g1_get_map()->remove_object(cell_on);
}

void g1_particle_class::load(i4_file_class *fp)
{
  fp->read_format("ffffffff", &x,&y,&z, &xv,&yv,&zv, &grow_speed, &size);
  ticks_left=fp->read_32();
  lx=x; ly=y; lz=z;
}

void g1_particle_class::save(i4_file_class *fp)
{
  fp->write_format("ffffffff", &x,&y,&z, &xv,&yv,&zv, &grow_speed, &size);
  fp->write_32(ticks_left);

}

g1_particle_emitter_class::g1_particle_emitter_class(g1_object_type id, g1_loader_class *fp)
  : g1_object_class(id, fp)
{
  cell_on.object=this;
  stopping=i4_F;
  t_in_use=0;
  x1=y1=x2=y2=0;
  radius=0;

  params.emitter_lifetime=0;
  for (int i=0; iset_filter_mode(R1_BILINEAR_FILTERING);

  float fr=g1_render.frame_ratio; 


  for (int i=0; itransform->transform(i4_3d_point_class(rx,ry,rh), screen_pos);

      i4_float ooz = 1 / screen_pos.z;
      i4_float xs = center_x * ooz * g1_render.scale_x;
      i4_float ys = center_y * ooz * g1_render.scale_y;

      if (screen_pos.z > r1_near_clip_z)
      {
        float cx=center_x + screen_pos.x*xs;
        float cy=center_y + screen_pos.y*ys;
        float w=particles[i].size * center_x * 2 * ooz;
        
        r1_clip_render_textured_rect(i4_f_to_i(cx-w/2), i4_f_to_i(cy-w/2), 
                                     i4_f_to_i(cx+w/2), i4_f_to_i(cy+w/2), screen_pos.z,
                                     particles[i].ticks_left/(float)params.particle_lifetime,
                                     i4_f_to_i(center_x*2), i4_f_to_i(center_y*2),
                                     params.texture, 0, g1_render.r_api);        
      }
    }
  }

  g1_render.r_api->set_filter_mode(R1_NO_FILTERING);
}
  
void g1_particle_emitter_class::think()
{
  pf_part_emit.start();

  if (params.emitter_lifetime>0)
    params.emitter_lifetime--;
  else if (params.emitter_lifetime!=-1)
    stopping = i4_T;

  if (t_in_use!=MAX_PARTICLES && !stopping)   // check to see if we should add some more particles
  {
    int t_tries=params.num_create_attempts_per_tick;
    float max_s=params.max_speed;

    for (int j=0; j max_s)
              particles[i].xv=max_s;

            particles[i].yv=(g1_float_rand(i+3)*2-1) * params.speed.y;
            if (particles[i].yv> max_s)
              particles[i].yv=max_s;

            particles[i].zv=(g1_float_rand(i+4)*2-1) * params.speed.z;
            if (particles[i].zv> max_s)
              particles[i].zv=max_s;

            particles[i].grow_speed=params.grow_speed;
            particles[i].size=params.start_size + i4_float_rand() * params.start_size_random_range;
            particles[i].ticks_left=params.particle_lifetime;
            particles[i].in_use=i4_T;

            t_in_use++;
            i=MAX_PARTICLES;
          }
        }
      }
    }
  }
  
  float bx1=100000,by1=100000,bx2=-100000,by2=-100000;

  if (t_in_use)
  {
    float airf=params.air_friction;
    for (int i=0; ibx2) bx2=particles[i].x;
          if (particles[i].yby2) by2=particles[i].y;
        }
      }
    }


    if (bx1!=100000)
    {
      if (bx1<0) bx1=0; 
      if (bx2>=g1_get_map()->width())  bx2=g1_get_map()->width()-1;
      if (by1<0) by1=0; 
      if (by2>=g1_get_map()->height())  by2=g1_get_map()->height()-1;

      if (bx1!=x1 || by1!=y1 || bx2!=x2 || by2!=y2)  // have bounds changed?
      {
        unoccupy_location();
        x1=bx1;  y1=by1; x2=bx2; y2=by2;

   

        radius=x2-x1;
      
        if (y2-y1>radius)
          radius=y2-y1;
        if (radius<0)
          radius=0;
        
        occupy_location();
      }
    }
  }

  if (!t_in_use && stopping)
  {
    unoccupy_location();
    request_remove();
  }
  else
    request_think();

  pf_part_emit.stop();
}