/* * PlanetPenguin Racer * Copyright (C) 2004-2005 Volker Stroebel * * Copyright (C) 1999-2001 Jasmin F. Patry * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ui_snow.h" #include "gl_util.h" #include "course_render.h" #include "render_util.h" #include "loop.h" #include "stuff.h" #include "ppogl/base/defs.h" #include "ppogl/base/glwrappers.h" #include "ppogl/textures.h" #define MAX_NUM_PARTICLES 10000 #define BASE_NUM_PARTICLES 400 #define GRAVITY_FACTOR 0.015 #define BASE_VELOCITY 0.05 #define VELOCITY_RANGE 0.02 #define PUSH_DECAY_TIME_CONSTANT 0.2 #define PUSH_DIST_DECAY 100 #define PUSH_FACTOR 0.5 #define MAX_PUSH_FORCE 5 #define WIND_FORCE 0.03 #define AIR_DRAG 0.4 #define PARTICLE_MIN_SIZE 1 #define PARTICLE_SIZE_RANGE 10 #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) typedef struct _particle_t { ppogl::Vec2d pt; double size; ppogl::Vec2d vel; ppogl::Vec2d tex_min; ppogl::Vec2d tex_max; } particle_t; static particle_t particles[MAX_NUM_PARTICLES]; static int num_particles = BASE_NUM_PARTICLES; static ppogl::Color particleColor(1, 1, 1, 0.4); static ppogl::Vec2d push_position(0,0); static ppogl::Vec2d last_push_position; static double last_update_time = -1; static bool push_position_initialized = false; static double frand() { return double(rand())/RAND_MAX; } static void make_particle(int i, double x, double y) { double p_dist; int type; particles[i].pt.x() = x; particles[i].pt.y() = y; p_dist = frand(); particles[i].size = PARTICLE_MIN_SIZE + (1.0 - p_dist)*PARTICLE_SIZE_RANGE; particles[i].vel.x() = 0; particles[i].vel.y() = -BASE_VELOCITY-p_dist*VELOCITY_RANGE; type = int(frand() * (4.0 - EPS)); if (type == 0) { particles[i].tex_min = ppogl::Vec2d( 0.0, 0.0 ); particles[i].tex_max = ppogl::Vec2d( 0.5, 0.5 ); } else if (type == 1) { particles[i].tex_min = ppogl::Vec2d( 0.5, 0.0 ); particles[i].tex_max = ppogl::Vec2d( 1.0, 0.5 ); } else if (type == 2) { particles[i].tex_min = ppogl::Vec2d( 0.5, 0.5 ); particles[i].tex_max = ppogl::Vec2d( 1.0, 1.0 ); } else { particles[i].tex_min = ppogl::Vec2d( 0.0, 0.5 ); particles[i].tex_max = ppogl::Vec2d( 0.5, 1.0 ); } } void init_ui_snow() { for(int i=0; ix() - push_position.x()), 2) + pow((pt->y() - push_position.y()), 2)); if ( push_timestep > 0 ) { f.x() = PUSH_FACTOR * push_vector.x() / push_timestep; f.y() = PUSH_FACTOR * push_vector.y() / push_timestep; f.x() = min(MAX_PUSH_FORCE,f.x()); f.x() = max(-MAX_PUSH_FORCE,f.x()); f.y() = min(MAX_PUSH_FORCE,f.y()); f.y() = max(-MAX_PUSH_FORCE,f.y()); f.x() *= 1.0/(PUSH_DIST_DECAY*dist_from_push + 1) * size/PARTICLE_SIZE_RANGE; f.y() *= 1.0/(PUSH_DIST_DECAY*dist_from_push + 1) * size/PARTICLE_SIZE_RANGE; } /* Update velocity */ v->x() += ( f.x() + ( windy ? WIND_FORCE : 0.0 ) - v->x() * AIR_DRAG ) * time_step; v->y() += ( f.y() - GRAVITY_FACTOR - v->y() * AIR_DRAG ) * time_step; /* Update position */ pt->x() += v->x() * time_step * ( size / PARTICLE_SIZE_RANGE ); pt->y()+= v->y() * time_step * ( size / PARTICLE_SIZE_RANGE ); if ( pt->x() < 0 ) { pt->x() = 1; } else if ( pt->x() > 1 ) { pt->x() = 0.0; } } /* Kill off & regenerate particles */ for (i=0; ipt.y() < -0.05) { /* If we have an excess of particles, kill off with 50% probability */ if ( num_particles > BASE_NUM_PARTICLES && frand() > 0.5 ) { /* Delete the particle */ *p = particles[num_particles-1]; num_particles -= 1; } else { p->pt.x() = frand(); p->pt.y() = 1+frand()*BASE_VELOCITY; p_dist = frand(); p->size = PARTICLE_MIN_SIZE + ( 1.0 - p_dist ) * PARTICLE_SIZE_RANGE; p->vel.x() = 0; p->vel.y() = -BASE_VELOCITY-p_dist*VELOCITY_RANGE; } } } if ( time_step < PUSH_DECAY_TIME_CONSTANT ) { push_vector.x() *= 1.0 - time_step/PUSH_DECAY_TIME_CONSTANT; push_vector.y() *= 1.0 - time_step/PUSH_DECAY_TIME_CONSTANT; } else { push_vector.x() = 0.0; push_vector.y() = 0.0; } } void draw_ui_snow() { ppogl::Vec2d *pt, *tex_min, *tex_max; double size; int i; gl::PushMatrix(); { gl::MatrixMode(GL_PROJECTION); gl::LoadIdentity(); gl::Ortho(0.0, GameMode::resolutionX, 0.0, GameMode::resolutionY, -1.0, 1.0); gl::MatrixMode(GL_MODELVIEW); gl::LoadIdentity(); gl::Translate(0.0, 0.0, -1.0); gl::Color(ppogl::Color::white); ppogl::TextureRef texture = ppogl::TextureMgr::getInstance().get("ui_snow_particle"); gl::TexEnv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); gl::BindTexture( GL_TEXTURE_2D, texture ); gl::Color(particleColor); gl::PushMatrix(); { for ( i=0; ix()*GameMode::resolutionX, pt->y()*GameMode::resolutionY); gl::Begin(GL_QUADS); { gl::TexCoord(tex_min->x(), tex_min->y()); gl::Vertex(0, 0); gl::TexCoord(tex_max->x(), tex_min->y()); gl::Vertex(size, 0); gl::TexCoord(tex_max->x(), tex_max->y()); gl::Vertex(size, size); gl::TexCoord(tex_min->x(), tex_max->y()); gl::Vertex(0, size); } gl::End(); } gl::PopMatrix(); } } gl::PopMatrix(); } gl::PopMatrix(); } void reset_ui_snow_cursor_pos(const ppogl::Vec2d& pos ) { push_position = ppogl::Vec2d( pos.x()/double(GameMode::resolutionX), pos.y()/double(GameMode::resolutionY) ); last_push_position = push_position; push_position_initialized = true; } void push_ui_snow(const ppogl::Vec2d& pos) { push_position = ppogl::Vec2d( pos.x()/double(GameMode::resolutionX), pos.y()/double(GameMode::resolutionY) ); if ( !push_position_initialized ) { last_push_position = push_position; } push_position_initialized = true; } void make_ui_snow(const ppogl::Vec2d& pos) { if(num_particles < MAX_NUM_PARTICLES){ make_particle( num_particles, pos.x()/GameMode::resolutionX, pos.y()/GameMode::resolutionY); num_particles++; } }