/* 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=0 && g=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;iparticles_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;ittl_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;iposition[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