#include "scene.h" #include "modes.h" #include Vec3f world; #define WIND_WAIT rand_real(4*tail_length, 8*tail_length) #define OFFSCREEN_VEC3() rand_vec3(-2*world[0], 2*world[0]) // max elapse time is 1/10th of a second so we don't get jaggies even if // the CPU load is high and everything slows down #define MAX_ELAPSE 0.1 Scene::Scene() : matrix(-1.0) { set_defaults(); } Scene::~Scene() { GLuint i; for (i = 0; i < baits.size(); i++) delete baits[i]; for (i = 0; i < flies.size(); i++) delete flies[i]; } void Scene::set_defaults() { bmodes.clear(); smodes.clear(); // all bmodes equally likely for (int i = 0; i < NUM_BMODES; i++) bmodes.add(i, 10); // except these bmodes.change(BMODE_NORMAL, 20); bmodes.change(BMODE_GLOW, 15); // all smodes equally likely for (int i = 0; i < NUM_SMODES; i++) smodes.add(i, 10); // except... smodes.change(SMODE_SWARMS, 5); fast_forward = 1; minbaits = 2; maxbaits = 5; minflies = 100; maxflies = 175; fsize = 1.5; bspeed = 50.; baccel = 600.; fspeed = 100.; faccel = 300.; hue_rate = 15.; tail_length = 2.25; tail_width = 2.5; tail_opaq = 0.6; glow_factor = 2.; wind_speed = 3.; draw_bait = false; } void Scene::create() { GLuint i, nbaits, nflies; curtime = 0.0; wind_when = curtime + WIND_WAIT; scene_start_mode(-1); // non-existent, just to initialize nbaits = (minbaits + maxbaits)/2; nflies = (minflies + maxflies)/2; baits.reserve(nbaits); for (i = 0; i < nbaits; i++) { baits.push_back(new Bait()); } add_flies(nflies); for (i = 0; i < 3; i++) { switch (rand_int(0, 1)) { case 0: accel[i] = -1; wind[i] = -wind_speed; break; default: accel[i] = 1; wind[i] = wind_speed; break; } } } void Scene::add_flies(unsigned n) { if (flies.size() >= maxflies) return; if (flies.size()+n >= maxflies) n = maxflies - flies.size(); // about 3 groups per bait int groupsize = (flies.size()+n)/(3*baits.size()); if (groupsize < 10) // but at least size 10 groupsize = 10; Vec3f where; Bait *b = baits[0]; flies.reserve(flies.size()+n); for (unsigned i = 0; i < n; i++) { if ((i % groupsize) == 0) { where = OFFSCREEN_VEC3(); b = baits[rand_int(0, baits.size()-1)]; } flies.push_back(new Firefly(b, where, world[2]/3)); } } void Scene::rem_flies(unsigned n) { if (flies.size() <= minflies) return; if (flies.size()-n <= minflies) n = flies.size() - minflies; Bait *b = baits[rand_int(0, baits.size()-1)]; vector::iterator it = flies.begin(); while (it != flies.end() && n > 0) { if ((*it)->bait == b) { delete (*it); it = flies.erase(it); n--; } else it++; } } void Scene::resize(int width, int height) { GLfloat aspect = (GLfloat)width / (GLfloat)height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(80., aspect, 5, 2000); world[2] = 50.; if (width > height) { world[1] = 80.; world[0] = world[1] * (width) / height; } else { world[0] = 80.; world[1] = world[0] * (height) / width; } camera.pos = Vec3f(0., 0., 3*world[2]); // For some reason this needs to be done everytime we resize, otherwise // blending is disabled (and I assume other functions) glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); } void Scene::apply_camera() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslated(-camera.pos[0], -camera.pos[1], -camera.pos[2]); glRotated(camera.rot_angle, camera.rot_axis[0], camera.rot_axis[1], camera.rot_axis[2]); } void Scene::draw() { #if 0 glColor4f(0.5f, 0.5f, 0.5f, 1.0f); draw_box(-world, world); #endif for (GLuint i = 0; i < baits.size(); i++) baits[i]->draw(); for (GLuint i = 0; i < flies.size(); i++) flies[i]->draw(); vector::iterator it = dead_tails.begin(); for (; it != dead_tails.end(); it++) (*it)->draw(); } void Scene::elapse(double t) { for (unsigned i = 0; i < fast_forward; i++) elapse_once(t); } void Scene::elapse_once(double t) { if (t > MAX_ELAPSE) t = MAX_ELAPSE; // matrix mode? if (matrix > 0) { matrix += t; if (matrix >= mode_when) scene_start_mode(-SMODE_MATRIX); else if (matrix-curtime >= 0.5) { Quat q = axis_to_quat(camera.rot_axis, DEG_TO_RAD(camera.rot_angle)); Quat dq = axis_to_quat(matrix_axis, 0.7*t); q = q * dq; unitize(q); camera.rot_axis = q.vector(); camera.rot_angle = RAD_TO_DEG(2.0*acos(q.scalar())); } return; } curtime += t; if (curtime >= mode_when) scene_start_mode(mode_next); // the wind, she's a changin! if (curtime >= wind_when) { for (int i = 0; i < 3; i++) { if (rand_int(0, 1) == 0) accel[i] = -accel[i]; } // next change based on tail length (so we can see a whole cycle of // prettiness blow one way before it gets tossed another) wind_when = curtime + WIND_WAIT; } wind += accel*t; clamp_vec(wind, wind_speed); // elapse, my children for (GLuint i = 0; i < baits.size(); i++) baits[i]->elapse(t); for (GLuint i = 0; i < flies.size(); i++) flies[i]->elapse(t); vector::iterator it = dead_tails.begin(); while (it != dead_tails.end()) { if ((*it)->elapse(t)) { // he's dead! delete (*it); it = dead_tails.erase(it); } else it++; } }