#include "tail.h" #include "firefly.h" #include "scene.h" Tail::Tail(Firefly *_owner) : owner(_owner) { } #define SET_COLOR(c, a) glColor4f(c[0], c[1], c[2], a) #define SET_VERTEX(v, dx) glVertex3d(v[0]+dx, v[1], v[2]) #define DO_POINT(t, dx, a)\ SET_COLOR((t).color, a); SET_VERTEX((t).pos, dx) void Tail::draw() { if (links.size() < 2) // need at least 2 links return; deque::iterator it = links.begin(); double glow_width = scene.glow_factor*scene.tail_width; double stretch_factor = 2*scene.fsize*scene.wind[0]; double dx1, dx2; dx2 = ((*it).glow ? glow_width : scene.tail_width); for (; (it+1) != links.end(); it++) { // half-width of the tail dx1 = dx2; dx2 = ((*(it+1)).glow ? glow_width : scene.tail_width); // have the wind stretch the tail (greater effect on ends) double age = (*it).age/scene.tail_length; double stretch = stretch_factor*age*age; double alpha = 0.9 - age; if (alpha > scene.tail_opaq) alpha = scene.tail_opaq; // two rectangles: outer vertices have alpha=0, inner two have // alpha based on age. note: alpha goes negative, but opengl // should clamp it to 0. if (stretch > 0) { // stretch to the right glBegin(GL_QUAD_STRIP); DO_POINT(*it, -dx1, 0); DO_POINT(*(it+1), -dx2, 0); DO_POINT(*it, 0, alpha); DO_POINT(*(it+1), 0, alpha); DO_POINT(*it, dx1 + stretch, 0); DO_POINT(*(it+1), dx2 + stretch, 0); } else { // stretch to the left glBegin(GL_QUAD_STRIP); DO_POINT(*it, -dx1 + stretch, 0); DO_POINT(*(it+1), -dx2 + stretch, 0); DO_POINT(*it, 0, alpha); DO_POINT(*(it+1), 0, alpha); DO_POINT(*it, dx1, 0); DO_POINT(*(it+1), dx2, 0); } glEnd(); } } bool Tail::elapse(double t) { // pop off the dead ones. // note we only have to check the end, since that's where they're gonna // be dying from. deque is very nice for this, because it has constant // time insertion/removal from both ends. while (!links.empty() && links.back().age >= scene.tail_length) links.pop_back(); deque::iterator it = links.begin(); for (; it != links.end(); it++) { (*it).age += t; double age = (*it).age/scene.tail_length; (*it).pos += scene.wind*age*age; } if (owner == 0) // my owner died! grow no longer return links.empty(); // if we're empty, tell caller we're dead links.push_front(Link(owner->pos, owner->color, owner->bait->glow)); return false; }