Back to index

extremetuxracer  0.5beta
part_sys.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020  */
00021 
00022 #include "part_sys.h"
00023 #include "phys_sim.h"
00024 #include "gl_util.h"
00025 #include "tcl_util.h"
00026 #include "course_render.h"
00027 #include "render_util.h"
00028 #include "textures.h"
00029 
00030 #include "ppgltk/alg/defs.h"
00031 
00032 /* This constant is here as part of a debugging check to prevent an infinite 
00033    number of particles from being created */
00034 #define MAX_PARTICLES 500000
00035 
00036 #define START_RADIUS 0.04
00037 #define OLD_PART_SIZE 0.07
00038 #define NEW_PART_SIZE 0.02
00039 #define MIN_AGE     -0.2
00040 #define MAX_AGE      1.0
00041 
00042 #define VARIANCE_FACTOR 0.8
00043 
00044 #define PARTICLE_SHADOW_HEIGHT 0.05
00045 #define PARTICLE_SHADOW_ALPHA 0.1
00046 
00047 GLfloat particleColor[4];
00048 
00049 typedef struct _Particle {
00050     pp::Vec3d pt;
00051     short type;
00052     double base_size;
00053     double cur_size;
00054     double terrain_height;
00055     double age;
00056     double death;
00057     double alpha;
00058     pp::Vec3d vel;
00059        GLuint particle_binding;
00060     struct _Particle *next;
00061 } Particle;
00062 
00063 static Particle* head = NULL;
00064 static int num_particles = 0;
00065 
00066 double frand() 
00067 {
00068     return (double)rand()/RAND_MAX;
00069 } 
00070 
00071 void create_new_particles( pp::Vec3d loc, pp::Vec3d vel, int num, GLuint particle_binding) 
00072 {
00073     Particle *newp;
00074     int i;
00075     double speed;
00076 
00077     speed = vel.normalize();
00078 
00079     /* Debug check to track down infinite particle bug */
00080     if ( num_particles + num > MAX_PARTICLES ) {
00081        check_assertion( 0, "maximum number of particles exceeded" );
00082     } 
00083 
00084     for (i=0; i<num; i++) {
00085 
00086         newp = (Particle*)malloc( sizeof( Particle) );
00087 
00088         if ( newp == NULL ) {
00089             handle_system_error( 1, "out of memory" );
00090         } 
00091 
00092         num_particles += 1;
00093 
00094         newp->next = head;
00095         head = newp;
00096 
00097         newp->pt.x = loc.x + 2.*(frand() - 0.5) * START_RADIUS;
00098         newp->pt.y = loc.y;
00099         newp->pt.z = loc.z + 2.*(frand() - 0.5) * START_RADIUS;
00100 
00101        newp->type = (int) (frand() * (4.0 - EPS));
00102               
00103        //get_texture_binding( "snow_particle", &(newp->particle_binding) );  
00104        newp->particle_binding = particle_binding;       
00105        
00106        newp->base_size = ( frand() + 0.5 ) * OLD_PART_SIZE;
00107        newp->cur_size = NEW_PART_SIZE;
00108 
00109         newp->age = frand() * MIN_AGE;
00110         newp->death = frand() * MAX_AGE;
00111 
00112 
00113         newp->vel =(speed*vel)+
00114            pp::Vec3d( VARIANCE_FACTOR * (frand() - 0.5) * speed, 
00115                       VARIANCE_FACTOR * (frand() - 0.5) * speed,
00116                       VARIANCE_FACTOR * (frand() - 0.5) * speed  );
00117     }
00118 } 
00119 
00120 void update_particles( double time_step )
00121 {
00122     Particle **p, *q;
00123     double ycoord;
00124 
00125     for (p = &head; *p != NULL; ) {
00126         (**p).age += time_step;
00127 
00128         if ( (**p).age < 0 ) continue;
00129 
00130        (**p).pt = ( (**p).pt)+(time_step*(**p).vel );
00131 
00132        ycoord = find_y_coord( (**p).pt.x, (**p).pt.z );
00133 
00134        if ( (**p).pt.y < ycoord - 3 ) {
00135            (**p).age = (**p).death + 1;
00136        } 
00137 
00138         if ( (**p).age >= (**p).death ) {
00139             q = *p;
00140             *p = q->next;
00141             free(q);
00142             num_particles -= 1;
00143             continue;
00144         } 
00145 
00146         (**p).alpha = ( (**p).death - (**p).age ) / (**p).death;
00147 
00148        (**p).cur_size = NEW_PART_SIZE + 
00149            ( OLD_PART_SIZE - NEW_PART_SIZE ) * ( (**p).age / (**p).death );
00150 
00151         (**p).vel.y += -EARTH_GRAV * time_step;
00152 
00153         p = &( (**p).next );
00154     } 
00155 } 
00156 
00157 void draw_particles( Player& plyr )
00158 {
00159     Particle *p;
00160     //GLuint   texture_id;
00161     //char *binding;
00162     pp::Vec2d min_tex_coord, max_tex_coord;
00163 
00164     set_gl_options( PARTICLES );
00165 
00166  /*
00167        binding = "snow_particle";
00168     if (!get_texture_binding( "snow_particle", &texture_id ) ) {
00169        print_warning( IMPORTANT_WARNING,
00170                      "Couldn't get texture for binding %s", 
00171                      binding );
00172        texture_id = 0;
00173        } 
00174  */
00175 
00176     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
00177 
00178     //glBindTexture( GL_TEXTURE_2D, texture_id );
00179        
00180     for (p=head; p!=NULL; p = p->next) {
00181         if ( p->age < 0 ) continue;
00182        glBindTexture( GL_TEXTURE_2D, p->particle_binding);
00183        if ( p->type == 0 || p->type == 1 ) {
00184            min_tex_coord.y = 0;
00185            max_tex_coord.y = 0.5;
00186        } else {
00187            min_tex_coord.y = 0.5;
00188            max_tex_coord.y = 1.0;
00189        }
00190 
00191        if ( p->type == 0 || p->type == 3 ) {
00192            min_tex_coord.x = 0;
00193            max_tex_coord.x = 0.5;
00194        } else {
00195            min_tex_coord.x = 0.5;
00196            max_tex_coord.x = 1.0;
00197        }
00198 
00199        glColor4f( particleColor[0], 
00200                  particleColor[1], 
00201                  particleColor[2],
00202                  particleColor[3] * p->alpha );
00203 
00204        draw_billboard( plyr, p->pt, p->cur_size, p->cur_size,
00205                      false, min_tex_coord, max_tex_coord );
00206     } 
00207 
00208 } 
00209 
00210 void clear_particles()
00211 {
00212     Particle *p, *q;
00213 
00214     p = head;
00215     for (;;) {
00216         if (p == NULL ) break;
00217         q=p;
00218         p=p->next;
00219         free(q);
00220     } 
00221     head = NULL;
00222     num_particles = 0;
00223 }
00224 
00225 void reset_particles() {
00226     particleColor[0] = 1.0;
00227     particleColor[1] = 1.0;
00228     particleColor[2] = 1.0;
00229     particleColor[3] = 1.0;
00230 } 
00231 
00232 static int particle_color_cb(ClientData cd, Tcl_Interp *ip, 
00233                            int argc, CONST84 char *argv[]) 
00234 {
00235     double tmp_arr[4];
00236     bool error = false;
00237 
00238     if ( argc == 2 ) {
00239        /* New format */
00240        if ( get_tcl_tuple ( ip, argv[1], tmp_arr, 4 ) == TCL_ERROR ) {
00241            error = true;
00242        } else {
00243            copy_to_glfloat_array( particleColor, tmp_arr, 4 );
00244        }
00245     } else {
00246        /* Old format */
00247        if (argc < 3) {
00248            error = true;
00249        } else {
00250 
00251            NEXT_ARG;
00252 
00253            print_warning( DEPRECATION_WARNING,
00254                         "This format for tux_particle_color is deprecated."
00255                         "  The new format is:\n"
00256                         "\ttux_particle_color {r g b a}" );
00257 
00258            while ( !error && argc > 0 ) {
00259               
00260               if ( strcmp( "-ambient_and_diffuse", *argv ) == 0 ||
00261                    strcmp( "-diffuse",  *argv ) == 0 ) 
00262               {
00263                   NEXT_ARG;
00264                   if ( argc == 0 ) {
00265                      error = true;
00266                      break;
00267                   }
00268                   if ( get_tcl_tuple ( ip, *argv, tmp_arr, 4 ) == 
00269                       TCL_ERROR ) 
00270                   {
00271                      error = true;
00272                      break;
00273                   }
00274                   copy_to_glfloat_array( particleColor, tmp_arr, 4 );
00275               } else if ( strcmp( "-specular", *argv ) == 0 ) {
00276                   /* Ignore */
00277                   NEXT_ARG;
00278               } else if ( strcmp( "-shininess", *argv ) == 0 ) {
00279                   /* Ignore */
00280                   NEXT_ARG;
00281               } else {
00282                   print_warning( TCL_WARNING, 
00283                                "tux_particle_color: unrecognized "
00284                                "parameter `%s'", *argv );
00285               }
00286               
00287               NEXT_ARG;
00288            }
00289        }
00290     }
00291 
00292     if ( error ) {
00293        print_warning( TCL_WARNING, "error in call to tux_particle_color" );
00294        Tcl_AppendResult(
00295            ip, 
00296            "\nUsage: tux_particle_color {r g b a}", (char *) 0 );
00297        return TCL_ERROR;
00298     }
00299 
00300     return TCL_OK;
00301 }
00302 
00303 void register_particle_callbacks( Tcl_Interp *ip )
00304 {
00305     Tcl_CreateCommand (ip, "tux_particle_color", particle_color_cb,  0,0);
00306 }