nuclear@6: #include nuclear@6: #include "opengl.h" nuclear@6: #include "dragon.h" nuclear@7: #include "metasurf.h" nuclear@7: #include "geom.h" nuclear@7: #include "game.h" nuclear@7: #include "shadow.h" nuclear@7: nuclear@7: #define VOXEL_PAD 1.0f nuclear@7: #define DYN_FCOUNT 64 nuclear@7: #define DYN_VCOUNT (DYN_FCOUNT * 3) nuclear@7: nuclear@7: #define NUM_NECK_SEG 8 nuclear@7: static const float nseg_sizes[NUM_NECK_SEG][2] = { nuclear@7: {1.0, 3.0}, {1.0, 1.5}, {1.5, 2.0}, {2.0, 2.5}, {2.5, 3.0}, {3.0, 3.5} nuclear@7: }; nuclear@7: nuclear@7: static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t); nuclear@7: static float mseval(struct metasurface *ms, float x, float y, float z); nuclear@7: static void msvertex(struct metasurface *ms, float x, float y, float z); nuclear@7: nuclear@6: nuclear@6: Dragon::Dragon() nuclear@6: : pos(0, 0, 0), dir(0, 0, -1), head_pos(0, 0, -1), target(0, 0, -2) nuclear@6: { nuclear@6: set_head_limits(-1, 1, -1, 1); nuclear@7: nuclear@7: glGenBuffers(1, &dyn_vbo); nuclear@7: glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo); nuclear@7: glBufferData(GL_ARRAY_BUFFER, DYN_VCOUNT * sizeof(DynVertex), 0, GL_STREAM_DRAW); nuclear@7: glBindBuffer(GL_ARRAY_BUFFER, 0); nuclear@7: nuclear@7: dyn_varr = new DynVertex[DYN_VCOUNT]; nuclear@7: nuclear@7: neck_seg_count = NUM_NECK_SEG; nuclear@7: neck_seg = new Capsule[neck_seg_count]; nuclear@7: nuclear@7: for(int i=0; idir = dir.normalized(); nuclear@6: } nuclear@6: nuclear@6: void Dragon::set_target(const Vector3 &p) nuclear@6: { nuclear@6: target = p; nuclear@6: } nuclear@6: nuclear@6: void Dragon::set_head_limits(float xmin, float xmax, float ymin, float ymax) nuclear@6: { nuclear@6: head_xlim[0] = std::min(xmin, xmax); nuclear@6: head_xlim[1] = std::max(xmin, xmax); nuclear@6: head_ylim[0] = std::min(ymin, ymax); nuclear@6: head_ylim[1] = std::max(ymin, ymax); nuclear@6: } nuclear@6: nuclear@6: void Dragon::move_head(const Vector3 &p) nuclear@6: { nuclear@6: head_pos = p; nuclear@6: } nuclear@6: nuclear@6: static float clamp(float x, float low, float high) nuclear@6: { nuclear@6: return x < low ? low : (x > high ? high : x); nuclear@6: } nuclear@6: nuclear@6: void Dragon::move_head(float dx, float dy) nuclear@6: { nuclear@6: float newx = clamp(head_pos.x + dx, head_xlim[0], head_xlim[1]); nuclear@6: float newy = clamp(head_pos.y + dy, head_ylim[0], head_ylim[1]); nuclear@6: nuclear@6: dx = newx - head_pos.x; nuclear@6: dy = newy - head_pos.y; nuclear@6: head_pos.x = newx; nuclear@6: head_pos.y = newy; nuclear@6: nuclear@6: target.x += dx * 0.7; nuclear@6: target.y += dy * 0.5; nuclear@6: } nuclear@6: nuclear@6: const Vector3 &Dragon::head_position() const nuclear@6: { nuclear@6: return head_pos; nuclear@6: } nuclear@6: nuclear@6: Vector3 Dragon::breath_dir() const nuclear@6: { nuclear@6: return (target - head_pos).normalized(); nuclear@6: } nuclear@6: nuclear@6: void Dragon::update() nuclear@6: { nuclear@7: Vector3 bdir = breath_dir(); nuclear@7: Vector3 bezcp[] = { pos, pos + dir * 6.0, head_pos - bdir * 8.0, head_pos }; nuclear@7: nuclear@7: float t = 0.0, dt = 1.0 / (float)(neck_seg_count + 1); nuclear@7: Vector3 p = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t); nuclear@7: nuclear@7: for(int i=0; ineck_seg; nuclear@6: nuclear@7: //printf("eval(%g %g %g)\n", x, y, z); nuclear@6: nuclear@7: float sum = 0.0f; nuclear@7: for(int i=0; ineck_seg_count; i++) { nuclear@7: float dist = capsule_distance(seg[i].p[0], seg[i].w[0], seg[i].p[1], seg[i].w[1], pt); nuclear@7: //float dist = sphere_distance(seg[i].p[0], 1.0, pt); nuclear@7: if(dist < 1e-4) dist = 1e-4; nuclear@7: float energy = 0.0001 / (dist * dist); nuclear@7: /*float dx = x - seg[i].p[0].x; nuclear@7: float dy = y - seg[i].p[0].y; nuclear@7: float dz = z - seg[i].p[0].z; nuclear@7: float energy = 0.5 / (dx * dx + dy * dy + dz * dz);*/ nuclear@7: sum += energy; nuclear@7: } nuclear@7: return sum; nuclear@7: } nuclear@6: nuclear@7: static void msvertex(struct metasurface *ms, float x, float y, float z) nuclear@7: { nuclear@7: Dragon *dragon = (Dragon*)msurf_get_user_data(ms); nuclear@7: nuclear@7: const float dt = 0.001; nuclear@7: float dfdx = mseval(ms, x - dt, y, z) - mseval(ms, x + dt, y, z); nuclear@7: float dfdy = mseval(ms, x, y - dt, z) - mseval(ms, x, y + dt, z); nuclear@7: float dfdz = mseval(ms, x, y, z - dt) - mseval(ms, x, y, z + dt); nuclear@7: nuclear@7: DynVertex *vptr = dragon->dyn_varr + dragon->dyn_vidx++; nuclear@7: vptr->x = x; nuclear@7: vptr->y = y; nuclear@7: vptr->z = z; nuclear@7: vptr->nx = dfdx; nuclear@7: vptr->ny = dfdy; nuclear@7: vptr->nz = dfdz; nuclear@7: nuclear@7: if(dragon->dyn_vidx >= DYN_VCOUNT) { nuclear@7: dragon->flush_dynvbo(); nuclear@6: } nuclear@6: }