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@10: #include "object.h" nuclear@7: #include "shadow.h" nuclear@10: #include "meshgen.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@8: #define NUM_NECK_SEG 10 nuclear@7: static const float nseg_sizes[NUM_NECK_SEG][2] = { nuclear@8: {2.0, 2.0}, {1.0, 1.0}, {1.0, 1.0}, {1.25, 1.25}, {1.3, 1.3}, {1.5, 1.5}, {1.6, 1.6}, {1.75, 1.75}, {2.0, 2.0}, {2.1, 2.1} nuclear@7: }; nuclear@8: #define NSEG_SZ_SCALE 0.5f 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@10: static void gen_detail_meshes(); nuclear@10: nuclear@10: static std::vector detail_obj; 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; ixform().set_translation(head_pos); nuclear@10: nuclear@10: if(dbg_wireframe) { nuclear@10: detail_obj[i]->draw_wire(); nuclear@10: } else { nuclear@10: detail_obj[i]->draw(); nuclear@10: } nuclear@10: } nuclear@7: } nuclear@7: nuclear@7: void Dragon::flush_dynvbo() const nuclear@7: { nuclear@7: if(!dyn_vidx) return; nuclear@7: nuclear@7: glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo); nuclear@7: glBufferSubData(GL_ARRAY_BUFFER, 0, dyn_vidx * sizeof(DynVertex), dyn_varr); nuclear@7: nuclear@7: glEnableClientState(GL_VERTEX_ARRAY); nuclear@7: glVertexPointer(3, GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, x)); nuclear@7: glEnableClientState(GL_NORMAL_ARRAY); nuclear@7: glNormalPointer(GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, nx)); nuclear@7: glBindBuffer(GL_ARRAY_BUFFER, 0); nuclear@7: nuclear@7: glDrawArrays(GL_TRIANGLES, 0, dyn_vidx); nuclear@7: nuclear@7: glDisableClientState(GL_VERTEX_ARRAY); nuclear@7: glDisableClientState(GL_NORMAL_ARRAY); nuclear@7: dyn_vidx = 0; nuclear@7: } nuclear@7: nuclear@7: nuclear@6: static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t) nuclear@6: { nuclear@6: float x = bezier(a.x, b.x, c.x, d.x, t); nuclear@6: float y = bezier(a.y, b.y, c.y, d.y, t); nuclear@6: float z = bezier(a.z, b.z, c.z, d.z, t); nuclear@6: return Vector3(x, y, z); nuclear@6: } nuclear@6: nuclear@7: static float mseval(struct metasurface *ms, float x, float y, float z) nuclear@6: { nuclear@7: Dragon *dragon = (Dragon*)msurf_get_user_data(ms); nuclear@6: nuclear@7: Vector3 pt = Vector3(x, y, z); nuclear@7: Capsule *seg = dragon->neck_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: } nuclear@10: nuclear@10: nuclear@10: #define HORN_RAD 0.15f nuclear@10: static Vector2 horn_sweep(float u, float v, void *cls) nuclear@10: { nuclear@10: float t = 1.0f - v; nuclear@10: float angle = u * 2.0 * M_PI; nuclear@10: float x = sin(angle) * t * HORN_RAD; nuclear@10: float y = cos(angle) * t * HORN_RAD; nuclear@10: return Vector2(x, y + smoothstep(0.3, 1.0, v) * 0.5); nuclear@10: } nuclear@10: nuclear@10: static void gen_detail_meshes() nuclear@10: { nuclear@10: Mesh *mesh; nuclear@10: Object *obj; nuclear@10: Matrix4x4 xform; nuclear@10: nuclear@10: for(int i=0; i<2; i++) { nuclear@10: float sign = i ? 1.0f : -1.0f; nuclear@10: nuclear@10: mesh = new Mesh; nuclear@10: gen_sweep(mesh, 2, 6, 6, horn_sweep, 0); nuclear@10: xform.set_translation(Vector3(0.5 * sign, 1.5, 3)); nuclear@10: xform.rotate(Vector3(DEG_TO_RAD(25), 0, 0)); nuclear@10: xform.rotate(Vector3(0, 0, DEG_TO_RAD(15) * -sign)); nuclear@10: mesh->apply_xform(xform, Matrix4x4::identity); nuclear@10: nuclear@10: obj = new Object; nuclear@10: obj->set_mesh(mesh); nuclear@10: obj->mtl.diffuse = Vector3(1.0, 0.85, 0.8); nuclear@10: obj->mtl.specular = Vector3(1, 1, 1); nuclear@10: obj->mtl.shininess = 60.0; nuclear@10: nuclear@10: detail_obj.push_back(obj); nuclear@10: } nuclear@10: }