1012 lines
26 KiB
C
1012 lines
26 KiB
C
/*
|
|
Raydium - CQFD Corp.
|
|
http://raydium.org/
|
|
License: GPL - GNU General Public License, see "gpl.txt" file.
|
|
*/
|
|
|
|
#ifndef DONT_INCLUDE_HEADERS
|
|
#include "index.h"
|
|
#else
|
|
#include "headers/particle2.h"
|
|
#endif
|
|
|
|
// Raydium Particle Engine, version 2
|
|
|
|
// TODO:
|
|
// relative texture filename (as for include statement) ?
|
|
// multiple file loading (composite generators)
|
|
// rotation
|
|
|
|
#include "particle2.h"
|
|
|
|
#ifdef ODE_SUPPORT
|
|
// proto
|
|
void raydium_ode_internal_particle_genetator_deleted_callback(int gen);
|
|
#endif
|
|
|
|
void raydium_particle_name_auto(char *prefix, char *dest)
|
|
{
|
|
static int counter;
|
|
sprintf(dest,"%s_particle_%i",prefix,counter);
|
|
counter++;
|
|
}
|
|
|
|
void raydium_particle_init(void)
|
|
{
|
|
int i;
|
|
|
|
raydium_particle_time_factor=1;
|
|
raydium_particle_scale_factor=1;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
|
|
{
|
|
raydium_particle_generators[i].state=0;
|
|
raydium_particle_generators[i].id=i;
|
|
}
|
|
|
|
for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
|
|
raydium_particle_particles[i]=NULL;
|
|
|
|
raydium_log("particle: OK");
|
|
}
|
|
|
|
signed char raydium_particle_generator_isvalid(int g)
|
|
{
|
|
if(g>=0 && g<RAYDIUM_MAX_GENERATORS && raydium_particle_generators[g].state)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int raydium_particle_generator_find(char *name)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
|
|
if(!strcmp(name,raydium_particle_generators[i].name) && raydium_particle_generator_isvalid(i))
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
int raydium_particle_find_free(void)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
|
|
if(raydium_particle_particles[i]==NULL)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
|
|
void raydium_particle_generator_delete(int gen)
|
|
{
|
|
|
|
if(!raydium_particle_generator_isvalid(gen))
|
|
{
|
|
raydium_log("particle: cannot delete generator: invalid name or index");
|
|
return;
|
|
}
|
|
#ifdef ODE_SUPPORT
|
|
raydium_ode_internal_particle_genetator_deleted_callback(gen);
|
|
#endif
|
|
raydium_particle_generators[gen].state=0;
|
|
}
|
|
|
|
void raydium_particle_generator_delete_name(char *gen)
|
|
{
|
|
raydium_particle_generator_delete(raydium_particle_generator_find(gen));
|
|
}
|
|
|
|
void raydium_particle_generator_enable(int gen, signed char enabled)
|
|
{
|
|
if(!raydium_particle_generator_isvalid(gen))
|
|
{
|
|
raydium_log("particle: cannot enable/disable generator: invalid name or index");
|
|
return;
|
|
}
|
|
raydium_particle_generators[gen].enabled=enabled;
|
|
}
|
|
|
|
void raydium_particle_generator_enable_name(char *gen, signed char enable)
|
|
{
|
|
raydium_particle_generator_enable(raydium_particle_generator_find(gen),enable);
|
|
}
|
|
|
|
void raydium_particle_preload(char *filename)
|
|
{
|
|
FILE *fp;
|
|
int ret;
|
|
char var[RAYDIUM_MAX_NAME_LEN];
|
|
char val_s[RAYDIUM_MAX_NAME_LEN];
|
|
GLfloat val_f[4];
|
|
int size;
|
|
|
|
|
|
fp=raydium_file_fopen(filename,"rt"); // idem ("rb" ?)
|
|
if(!fp)
|
|
{
|
|
raydium_log("particle: ERROR: Cannot open %s particle file for preloading",filename);
|
|
return;
|
|
}
|
|
|
|
// parse (and cache) file
|
|
while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
|
|
{
|
|
if(!strcasecmp(var,"include"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_STRING)
|
|
{
|
|
raydium_log("particle: parser: include: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_preload(val_s);
|
|
}
|
|
|
|
if(!strcasecmp(var,"texture"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_STRING)
|
|
{
|
|
raydium_log("particle: parser: texture: wrong type");
|
|
continue; // in case of multiple textures ? (degenarated file)
|
|
}
|
|
// cache texture
|
|
raydium_texture_current_set_name(val_s);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
void raydium_particle_generator_load_internal(int generator,FILE *fp, char *filename)
|
|
{
|
|
int ret;
|
|
char var[RAYDIUM_MAX_NAME_LEN];
|
|
char val_s[RAYDIUM_MAX_NAME_LEN];
|
|
GLfloat val_f[4];
|
|
int size;
|
|
char done;
|
|
|
|
while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
|
|
{
|
|
done=0;
|
|
|
|
if(!strcasecmp(var,"include"))
|
|
{
|
|
FILE *sub;
|
|
char dir[RAYDIUM_MAX_NAME_LEN];
|
|
|
|
if(ret!=RAYDIUM_PARSER_TYPE_STRING)
|
|
{
|
|
raydium_log("particle: parser: include: wrong type");
|
|
continue;
|
|
}
|
|
raydium_file_dirname(dir,filename);
|
|
strcat(dir,val_s);
|
|
strcpy(val_s,dir);
|
|
sub=raydium_file_fopen(val_s,"rt"); // idem
|
|
if(!sub)
|
|
{
|
|
raydium_log("particle: ERROR: %s cannot open %s particle subfile",filename,val_s);
|
|
continue;
|
|
}
|
|
raydium_particle_generator_load_internal(generator,sub,val_s);
|
|
fclose(sub);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"position"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: position: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].position,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"position_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: position_random: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].position_random,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"ttl_generator"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: ttl_generator: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].ttl_generator=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"ttl_particles"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: ttl_particles: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].ttl_particles=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"ttl_particles_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: ttl_particles_random: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].ttl_particles_random=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"particles_per_second"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: particles_per_second: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].particles_per_second=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"texture"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_STRING)
|
|
{
|
|
raydium_log("particle: parser: texture: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].texture=
|
|
raydium_texture_find_by_name(val_s);
|
|
done=1;
|
|
}
|
|
|
|
|
|
if(!strcasecmp(var,"size"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: size: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].size=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"size_inc_per_sec"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: size_inc_per_sec: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].size_inc_per_sec=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"size_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: size_random: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].size_random=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"size_limit"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: size_limit: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].size_limit=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"gravity"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: gravity: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].gravity,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"vector"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: vector: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].vector,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"vector_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: vector_random: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].vector_random,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"vector_sphere_angles"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: vector_sphere_angles: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].vector_sphere_angles,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"vector_sphere_angles_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
|
|
{
|
|
raydium_log("particle: parser: vector_sphere_angles_random: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].vector_sphere_angles_random,val_f,sizeof(GLfloat)*3);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"vector_sphere_force"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: vector_sphere_force: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].vector_sphere_force=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"vector_sphere_force_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: vector_sphere_force_random: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].vector_sphere_force_random=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"rotation_speed"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: rotation_speed: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].rotation_speed=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"rotation_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: rotation_random: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].rotation_random=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"color_start"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
|
|
{
|
|
raydium_log("particle: parser: color_start: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].color_start,val_f,sizeof(GLfloat)*4);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"color_start_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
|
|
{
|
|
raydium_log("particle: parser: color_start_random: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].color_start_random,val_f,sizeof(GLfloat)*4);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"color_end"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
|
|
{
|
|
raydium_log("particle: parser: color_end: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].color_end,val_f,sizeof(GLfloat)*4);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"color_end_random"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
|
|
{
|
|
raydium_log("particle: parser: color_end_random: wrong type");
|
|
continue;
|
|
}
|
|
memcpy(raydium_particle_generators[generator].color_end_random,val_f,sizeof(GLfloat)*4);
|
|
done=1;
|
|
}
|
|
|
|
if(!strcasecmp(var,"visibility"))
|
|
{
|
|
if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
|
|
{
|
|
raydium_log("particle: parser: visibility: wrong type");
|
|
continue;
|
|
}
|
|
raydium_particle_generators[generator].visibility=val_f[0];
|
|
done=1;
|
|
}
|
|
|
|
if(!done)
|
|
raydium_log("particle: parser: invalid or unsupported option '%s' (%s)",var,filename);
|
|
}
|
|
}
|
|
|
|
int raydium_particle_generator_load(char *filename,char *name)
|
|
{
|
|
FILE *fp;
|
|
int generator;
|
|
int i;
|
|
|
|
|
|
if(raydium_particle_generator_find(name)>=0)
|
|
{
|
|
raydium_log("particle: Cannot load \"%s\": '%s' already exists",filename,name);
|
|
return -1;
|
|
}
|
|
|
|
fp=raydium_file_fopen(filename,"rt"); // rb ? must test under win32
|
|
if(!fp)
|
|
{
|
|
raydium_log("particle: ERROR: Cannot open %s particle file",filename);
|
|
return -1;
|
|
}
|
|
|
|
for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
|
|
if(raydium_particle_generators[i].state==0)
|
|
break;
|
|
|
|
if(i==RAYDIUM_MAX_GENERATORS)
|
|
{
|
|
raydium_log("particle: no more available slots !");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
generator=i;
|
|
|
|
raydium_particle_generators[generator].state=1;
|
|
raydium_particle_generators[generator].enabled=1;
|
|
strcpy(raydium_particle_generators[generator].name,name);
|
|
raydium_particle_generators[generator].position[0]=0;
|
|
raydium_particle_generators[generator].position[1]=0;
|
|
raydium_particle_generators[generator].position[2]=0;
|
|
raydium_particle_generators[generator].position_random[0]=0;
|
|
raydium_particle_generators[generator].position_random[1]=0;
|
|
raydium_particle_generators[generator].position_random[2]=0;
|
|
raydium_particle_generators[generator].position_user[0]=0;
|
|
raydium_particle_generators[generator].position_user[1]=0;
|
|
raydium_particle_generators[generator].position_user[2]=0;
|
|
raydium_particle_generators[generator].ttl_generator=1;
|
|
raydium_particle_generators[generator].ttl_particles=1;
|
|
raydium_particle_generators[generator].particles_per_second=100;
|
|
raydium_particle_generators[generator].texture=0;
|
|
raydium_particle_generators[generator].size=1;
|
|
raydium_particle_generators[generator].size_inc_per_sec=0;
|
|
raydium_particle_generators[generator].size_random=0;
|
|
raydium_particle_generators[generator].size_limit=-1;
|
|
raydium_particle_generators[generator].gravity[0]=0;
|
|
raydium_particle_generators[generator].gravity[1]=0;
|
|
raydium_particle_generators[generator].gravity[2]=0;
|
|
raydium_particle_generators[generator].vector[0]=0;
|
|
raydium_particle_generators[generator].vector[1]=0;
|
|
raydium_particle_generators[generator].vector[2]=0;
|
|
raydium_particle_generators[generator].vector_random[0]=0;
|
|
raydium_particle_generators[generator].vector_random[1]=0;
|
|
raydium_particle_generators[generator].vector_random[2]=0;
|
|
raydium_particle_generators[generator].vector_sphere_angles[0]=0;
|
|
raydium_particle_generators[generator].vector_sphere_angles[1]=0;
|
|
raydium_particle_generators[generator].vector_sphere_angles[2]=0;
|
|
raydium_particle_generators[generator].vector_sphere_angles_random[0]=0;
|
|
raydium_particle_generators[generator].vector_sphere_angles_random[1]=0;
|
|
raydium_particle_generators[generator].vector_sphere_angles_random[2]=0;
|
|
raydium_particle_generators[generator].vector_sphere_force=0;
|
|
raydium_particle_generators[generator].vector_sphere_force_random=0;
|
|
// velocity_limit
|
|
raydium_particle_generators[generator].rotation_speed=45;
|
|
raydium_particle_generators[generator].rotation_random=0;
|
|
raydium_particle_generators[generator].color_start[0]=1;
|
|
raydium_particle_generators[generator].color_start[1]=1;
|
|
raydium_particle_generators[generator].color_start[2]=1;
|
|
raydium_particle_generators[generator].color_start[3]=1;
|
|
raydium_particle_generators[generator].color_start_random[0]=0;
|
|
raydium_particle_generators[generator].color_start_random[1]=0;
|
|
raydium_particle_generators[generator].color_start_random[2]=0;
|
|
raydium_particle_generators[generator].color_start_random[3]=0;
|
|
raydium_particle_generators[generator].color_end[0]=1;
|
|
raydium_particle_generators[generator].color_end[1]=1;
|
|
raydium_particle_generators[generator].color_end[2]=1;
|
|
raydium_particle_generators[generator].color_end[3]=1;
|
|
raydium_particle_generators[generator].color_end_random[0]=0;
|
|
raydium_particle_generators[generator].color_end_random[1]=0;
|
|
raydium_particle_generators[generator].color_end_random[2]=0;
|
|
raydium_particle_generators[generator].color_end_random[3]=0;
|
|
raydium_particle_generators[generator].visibility=1;
|
|
raydium_particle_generators[generator].OnDeleteParticle=NULL;
|
|
|
|
// transform
|
|
raydium_particle_generator_load_internal(generator,fp,filename);
|
|
|
|
fclose(fp);
|
|
return generator;
|
|
}
|
|
|
|
|
|
void raydium_particle_generator_update(int g,GLfloat step)
|
|
{
|
|
int i,j,p,to_create;
|
|
raydium_particle_Generator *gen;
|
|
raydium_particle_Particle *part;
|
|
|
|
/*
|
|
if(!raydium_particle_generators[g].state)
|
|
{
|
|
raydium_log("particle: Cannot update generator: invalid index");
|
|
return;
|
|
}
|
|
*/
|
|
|
|
gen=&raydium_particle_generators[g];
|
|
|
|
// This +1 is bad, must use a "float" counter on generator
|
|
to_create=(step*gen->particles_per_second)+1;
|
|
//raydium_log("will create %i particles for %s (%i)",to_create,gen->name,g);
|
|
|
|
if(!gen->enabled) to_create=0;
|
|
|
|
for(i=0;i<to_create;i++)
|
|
{
|
|
p=raydium_particle_find_free();
|
|
if(p<0)
|
|
{
|
|
//raydium_log("particle: No more particle slots !");
|
|
break;
|
|
}
|
|
|
|
raydium_particle_particles[p]=malloc(sizeof(raydium_particle_Particle));
|
|
if(!raydium_particle_particles[p])
|
|
{
|
|
raydium_log("particle: ERROR: malloc failed !");
|
|
return;
|
|
}
|
|
|
|
|
|
part=raydium_particle_particles[p];
|
|
|
|
part->ttl_init=raydium_random_f(gen->ttl_particles-gen->ttl_particles_random,gen->ttl_particles+gen->ttl_particles_random);
|
|
part->ttl=part->ttl_init;
|
|
part->texture=gen->texture;
|
|
|
|
memcpy(part->position,gen->position,sizeof(GLfloat)*3);
|
|
for(j=0;j<3;j++)
|
|
part->position[j]+=raydium_random_f(-gen->position_random[j],gen->position_random[j]);
|
|
|
|
for(j=0;j<3;j++)
|
|
part->position[j]+=gen->position_user[j];
|
|
|
|
part->size=raydium_random_f(gen->size-gen->size_random,gen->size+gen->size_random);
|
|
part->size_inc_per_sec=gen->size_inc_per_sec;
|
|
part->size_limit=gen->size_limit;
|
|
|
|
memcpy(part->gravity,gen->gravity,sizeof(GLfloat)*3);
|
|
|
|
|
|
if(gen->vector_sphere_force==0 && gen->vector_sphere_force_random==0)
|
|
{
|
|
// ortho
|
|
memcpy(part->vel,gen->vector,sizeof(GLfloat)*3);
|
|
for(j=0;j<3;j++)
|
|
part->vel[j]+=raydium_random_f(-gen->vector_random[j],gen->vector_random[j]);
|
|
}
|
|
else
|
|
{
|
|
// spherical
|
|
GLfloat def_angles[3]={0,0,1};
|
|
GLfloat angles[3];
|
|
GLfloat force;
|
|
|
|
memcpy(angles,gen->vector_sphere_angles,sizeof(GLfloat)*3);
|
|
for(j=0;j<3;j++)
|
|
angles[j]+=raydium_random_f(-gen->vector_sphere_angles_random[j],gen->vector_sphere_angles_random[j]);
|
|
|
|
|
|
force=gen->vector_sphere_force
|
|
+raydium_random_f(-gen->vector_sphere_force_random,
|
|
gen->vector_sphere_force_random);
|
|
for(j=0;j<3;j++)
|
|
def_angles[j]*=force;
|
|
|
|
raydium_trigo_rotate(def_angles,angles[0],angles[1],angles[2],part->vel);
|
|
}
|
|
|
|
memcpy(part->color_start,gen->color_start,sizeof(GLfloat)*4);
|
|
for(j=0;j<4;j++)
|
|
part->color_start[j]+=raydium_random_f(-gen->color_start_random[j],gen->color_start_random[j]);
|
|
|
|
memcpy(part->color_end,gen->color_end,sizeof(GLfloat)*4);
|
|
for(j=0;j<4;j++)
|
|
part->color_end[j]+=raydium_random_f(-gen->color_end_random[j],gen->color_end_random[j]);
|
|
|
|
part->rotation_speed=raydium_random_f(gen->rotation_speed-gen->rotation_random,
|
|
gen->rotation_speed+gen->rotation_random);
|
|
|
|
part->visibility=gen->visibility;
|
|
part->OnDelete=gen->OnDeleteParticle;
|
|
}
|
|
|
|
|
|
if(gen->ttl_generator==0)
|
|
return; // infinite generator
|
|
|
|
gen->ttl_generator-=step;
|
|
if(gen->ttl_generator<=0)
|
|
{
|
|
// we've a OnDelete callback for particles and not for
|
|
// generators ... 'must code it.
|
|
raydium_particle_generator_delete(gen->id);
|
|
}
|
|
}
|
|
|
|
void raydium_particle_update(int part, GLfloat step)
|
|
{
|
|
int i;
|
|
GLfloat age,age_factor;
|
|
raydium_particle_Particle *p;
|
|
|
|
p=raydium_particle_particles[part];
|
|
// ttl
|
|
if(p->ttl!=0) // if not an infinite particle
|
|
{
|
|
p->ttl-=step;
|
|
if(p->ttl<=0) // "timeout" ...
|
|
{
|
|
void (*f)(raydium_particle_Particle *);
|
|
|
|
f=p->OnDelete;
|
|
if(f) f(p);
|
|
|
|
free(p);
|
|
raydium_particle_particles[part]=NULL;
|
|
return;
|
|
}
|
|
}
|
|
|
|
age=(p->ttl_init-p->ttl);
|
|
if(p->ttl_init)
|
|
age_factor=age/p->ttl_init;
|
|
else
|
|
age_factor=0;
|
|
|
|
// pos
|
|
for(i=0;i<3;i++)
|
|
p->position[i]+=(p->vel[i]*step);
|
|
|
|
// vel
|
|
for(i=0;i<3;i++)
|
|
p->vel[i]+=(p->gravity[i]*step);
|
|
|
|
// size
|
|
p->size+=(p->size_inc_per_sec*step);
|
|
if(p->size<0) p->size=0;
|
|
if(p->size>p->size_limit && p->size_limit>0) p->size=p->size_limit;
|
|
|
|
// color
|
|
for(i=0;i<4;i++)
|
|
p->current_color[i]=(p->color_end[i]-p->color_start[i])*age_factor+p->color_start[i];
|
|
|
|
// rotation
|
|
p->current_rotation=age*p->rotation_speed;
|
|
|
|
}
|
|
|
|
void raydium_particle_callback(void)
|
|
{
|
|
int i;
|
|
|
|
//raydium_profile_start();
|
|
|
|
for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
|
|
if(raydium_particle_generators[i].state)
|
|
raydium_particle_generator_update(i,raydium_frame_time*raydium_particle_time_factor);
|
|
|
|
for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
|
|
if(raydium_particle_particles[i])
|
|
raydium_particle_update(i,raydium_frame_time*raydium_particle_time_factor);
|
|
|
|
//raydium_profile_end("particles updating");
|
|
}
|
|
|
|
|
|
int raydium_particle_state_dump(char *filename)
|
|
{
|
|
FILE *fp;
|
|
int i;
|
|
int cpt=0;
|
|
raydium_particle_Particle *p;
|
|
|
|
fp=raydium_file_fopen(filename,"wt");
|
|
if(!fp)
|
|
{
|
|
raydium_log("particle: ERROR: cannot create '%s' filename",filename);
|
|
return 0;
|
|
}
|
|
|
|
fprintf(fp,"0\n");
|
|
|
|
for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
|
|
if(raydium_particle_particles[i])
|
|
{
|
|
cpt++;
|
|
p=raydium_particle_particles[i];
|
|
fprintf(fp,"%f %f %f %f %f %f %f %f %f %s\n",
|
|
p->position[0],
|
|
p->position[1],
|
|
p->position[2],
|
|
p->size,
|
|
p->current_color[0],
|
|
p->current_color[1],
|
|
p->current_color[2],
|
|
p->current_color[3],
|
|
p->visibility,
|
|
raydium_texture_name[p->texture]);
|
|
}
|
|
fclose(fp);
|
|
raydium_log("particle: %i particle(s) dumped",cpt);
|
|
return 1;
|
|
}
|
|
|
|
int raydium_particle_state_restore(char *filename)
|
|
{
|
|
FILE *fp;
|
|
int p,visu,cpt=0;
|
|
raydium_particle_Particle *part;
|
|
GLfloat pos[3],color[4],size,visibility;
|
|
char texture[RAYDIUM_MAX_NAME_LEN];
|
|
|
|
fp=raydium_file_fopen(filename,"rt");
|
|
if(!fp)
|
|
{
|
|
raydium_log("particle: ERROR: cannot read from file '%s'",filename);
|
|
return 0;
|
|
}
|
|
fscanf(fp,"%i\n",&visu);
|
|
|
|
if(visu!=0)
|
|
{
|
|
raydium_log("particle: ERROR: '%s' file must be 'version 0'",filename);
|
|
return 0;
|
|
}
|
|
|
|
|
|
while( fscanf(fp,"%f %f %f %f %f %f %f %f %f %s\n",
|
|
&pos[0],
|
|
&pos[1],
|
|
&pos[2],
|
|
&size,
|
|
&color[0],
|
|
&color[1],
|
|
&color[2],
|
|
&color[3],
|
|
&visibility,
|
|
texture)!=EOF )
|
|
{
|
|
cpt++;
|
|
p=raydium_particle_find_free();
|
|
if(p<0)
|
|
{
|
|
raydium_log("particle: No more particle slots !");
|
|
return -1;
|
|
}
|
|
|
|
raydium_particle_particles[p]=malloc(sizeof(raydium_particle_Particle));
|
|
if(!raydium_particle_particles[p])
|
|
{
|
|
raydium_log("particle: ERROR: malloc failed !");
|
|
return 0;
|
|
}
|
|
|
|
|
|
part=raydium_particle_particles[p];
|
|
|
|
part->ttl_init=0;
|
|
part->ttl=part->ttl_init;
|
|
part->texture=raydium_texture_find_by_name(texture);
|
|
|
|
memcpy(part->position,pos,sizeof(GLfloat)*3);
|
|
|
|
part->size=size;
|
|
part->size_inc_per_sec=0;
|
|
part->size_limit=size+1;
|
|
|
|
part->gravity[0]=part->gravity[1]=part->gravity[2]=0;
|
|
|
|
part->vel[0]=part->vel[1]=part->vel[2]=0;
|
|
|
|
memcpy(part->color_start, color,sizeof(GLfloat)*4);
|
|
memcpy(part->color_end, color,sizeof(GLfloat)*4);
|
|
memcpy(part->current_color, color,sizeof(GLfloat)*4);
|
|
|
|
part->rotation_speed=0;
|
|
part->visibility=visibility;
|
|
part->OnDelete=NULL;
|
|
}
|
|
fclose(fp);
|
|
raydium_log("particle: %i infinite particle(s) created",cpt);
|
|
return 1;
|
|
}
|
|
|
|
|
|
void raydium_particle_draw(raydium_particle_Particle *p,GLfloat ux, GLfloat uy, GLfloat uz, GLfloat rx, GLfloat ry, GLfloat rz)
|
|
{
|
|
GLfloat TSIZE;
|
|
|
|
if(!raydium_random_proba(p->visibility))
|
|
return;
|
|
|
|
// need to order drawing by texture id
|
|
raydium_rendering_internal_prepare_texture_render(raydium_texture_current_set(p->texture));
|
|
glColor4fv(p->current_color);
|
|
TSIZE=p->size;
|
|
|
|
ux*=TSIZE/2;
|
|
uy*=TSIZE/2;
|
|
uz*=TSIZE/2;
|
|
|
|
rx*=TSIZE/2;
|
|
ry*=TSIZE/2;
|
|
rz*=TSIZE/2;
|
|
|
|
// p->rotation
|
|
|
|
glBegin(GL_QUADS); // berk... but i'll switch to triangles one day ;)
|
|
glTexCoord2f(1.0f, 0.0f);
|
|
glVertex3f(p->position[0] + (-rx - ux),
|
|
p->position[1] + (-ry - uy),
|
|
p->position[2] + (-rz - uz));
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
glVertex3f(p->position[0] + (rx - ux),
|
|
p->position[1] + (ry - uy),
|
|
p->position[2] + (rz - uz));
|
|
glTexCoord2f(0.0f, 1.0f);
|
|
glVertex3f(p->position[0] + (rx + ux),
|
|
p->position[1] + (ry + uy),
|
|
p->position[2] + (rz + uz));
|
|
glTexCoord2f(0.0f, 0.0f);
|
|
glVertex3f(p->position[0] + (ux - rx),
|
|
p->position[1] + (uy - ry),
|
|
p->position[2] + (uz - rz));
|
|
glEnd();
|
|
}
|
|
|
|
|
|
void raydium_particle_scale_all(GLfloat scale)
|
|
{
|
|
raydium_particle_scale_factor=scale;
|
|
}
|
|
|
|
void raydium_particle_draw_all(void)
|
|
{
|
|
GLuint i;
|
|
GLuint texsave;
|
|
char light;
|
|
GLfloat modmat[16];
|
|
GLfloat ux;
|
|
GLfloat uy;
|
|
GLfloat uz;
|
|
GLfloat rx;
|
|
GLfloat ry;
|
|
GLfloat rz;
|
|
|
|
//raydium_profile_start();
|
|
|
|
texsave=raydium_texture_current_main;
|
|
light=raydium_light_enabled_tag;
|
|
raydium_light_disable();
|
|
if (raydium_camera_pushed) raydium_camera_replace(); // is it really our job to do it here ?
|
|
//raydium_rendering_internal_restore_render_state();
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX,modmat);
|
|
ux=modmat[0]*raydium_particle_scale_factor;
|
|
uy=modmat[4]*raydium_particle_scale_factor;
|
|
uz=modmat[8]*raydium_particle_scale_factor;
|
|
rx=modmat[1]*raydium_particle_scale_factor;
|
|
ry=modmat[5]*raydium_particle_scale_factor;
|
|
rz=modmat[9]*raydium_particle_scale_factor;
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
|
|
if(raydium_particle_particles[i])
|
|
raydium_particle_draw(raydium_particle_particles[i],ux,uy,uz,rx,ry,rz);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
if(light) raydium_light_enable();
|
|
|
|
raydium_texture_current_set(texsave);
|
|
//raydium_rendering_internal_prepare_texture_render(texsave);
|
|
//raydium_profile_end("particles drawing");
|
|
}
|
|
|
|
|
|
void raydium_particle_generator_move(int gen, GLfloat *pos)
|
|
{
|
|
if(!raydium_particle_generator_isvalid(gen))
|
|
{
|
|
raydium_log("particle: cannot move generator: invalid name or index");
|
|
return;
|
|
}
|
|
memcpy(raydium_particle_generators[gen].position_user,pos,sizeof(GLfloat)*3);
|
|
}
|
|
|
|
void raydium_particle_generator_move_name(char *gen, GLfloat *pos)
|
|
{
|
|
raydium_particle_generator_move(raydium_particle_generator_find(gen),pos);
|
|
}
|
|
|
|
void raydium_particle_generator_move_name_3f(char *gen, GLfloat x, GLfloat y, GLfloat z)
|
|
{
|
|
GLfloat tmp[3];
|
|
tmp[0]=x;
|
|
tmp[1]=y;
|
|
tmp[2]=z;
|
|
raydium_particle_generator_move_name(gen,tmp);
|
|
}
|
|
|
|
void raydium_particle_generator_particles_OnDelete(int gen, void *OnDelete)
|
|
{
|
|
if(!raydium_particle_generator_isvalid(gen))
|
|
{
|
|
raydium_log("particle: cannot set OnDelete: invalid name or index");
|
|
return;
|
|
}
|
|
raydium_particle_generators[gen].OnDeleteParticle=OnDelete;
|
|
}
|
|
|
|
void raydium_particle_generator_particles_OnDelete_name(char *gen, void *OnDelete)
|
|
{
|
|
raydium_particle_generator_particles_OnDelete(raydium_particle_generator_find(gen),OnDelete);
|
|
}
|