You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
5.4 KiB

#include "scene.h"
#include "modes.h"
#include <GL/glu.h>
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<Firefly*>::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<Tail*>::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<Tail*>::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++;
}
}