ld33_umonster

annotate src/dragon.cc @ 10:1b30bd381667

sweep curve mesh gen and dragon horns
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 27 Aug 2015 05:25:04 +0300
parents 4f6168f3ca82
children
rev   line source
nuclear@6 1 #include <algorithm>
nuclear@6 2 #include "opengl.h"
nuclear@6 3 #include "dragon.h"
nuclear@7 4 #include "metasurf.h"
nuclear@7 5 #include "geom.h"
nuclear@7 6 #include "game.h"
nuclear@10 7 #include "object.h"
nuclear@7 8 #include "shadow.h"
nuclear@10 9 #include "meshgen.h"
nuclear@7 10
nuclear@7 11 #define VOXEL_PAD 1.0f
nuclear@7 12 #define DYN_FCOUNT 64
nuclear@7 13 #define DYN_VCOUNT (DYN_FCOUNT * 3)
nuclear@7 14
nuclear@8 15 #define NUM_NECK_SEG 10
nuclear@7 16 static const float nseg_sizes[NUM_NECK_SEG][2] = {
nuclear@8 17 {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 18 };
nuclear@8 19 #define NSEG_SZ_SCALE 0.5f
nuclear@7 20
nuclear@7 21 static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t);
nuclear@7 22 static float mseval(struct metasurface *ms, float x, float y, float z);
nuclear@7 23 static void msvertex(struct metasurface *ms, float x, float y, float z);
nuclear@10 24 static void gen_detail_meshes();
nuclear@10 25
nuclear@10 26 static std::vector<Object*> detail_obj;
nuclear@7 27
nuclear@6 28
nuclear@6 29 Dragon::Dragon()
nuclear@6 30 : pos(0, 0, 0), dir(0, 0, -1), head_pos(0, 0, -1), target(0, 0, -2)
nuclear@6 31 {
nuclear@6 32 set_head_limits(-1, 1, -1, 1);
nuclear@7 33
nuclear@7 34 glGenBuffers(1, &dyn_vbo);
nuclear@7 35 glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo);
nuclear@7 36 glBufferData(GL_ARRAY_BUFFER, DYN_VCOUNT * sizeof(DynVertex), 0, GL_STREAM_DRAW);
nuclear@7 37 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@7 38
nuclear@7 39 dyn_varr = new DynVertex[DYN_VCOUNT];
nuclear@7 40
nuclear@7 41 neck_seg_count = NUM_NECK_SEG;
nuclear@7 42 neck_seg = new Capsule[neck_seg_count];
nuclear@7 43
nuclear@7 44 for(int i=0; i<neck_seg_count; i++) {
nuclear@8 45 int idx = neck_seg_count - i - 1;
nuclear@8 46 neck_seg[i].w[0] = nseg_sizes[idx][0] * NSEG_SZ_SCALE;
nuclear@8 47 neck_seg[i].w[1] = nseg_sizes[idx][1] * NSEG_SZ_SCALE;
nuclear@7 48 }
nuclear@7 49
nuclear@7 50 msurf = msurf_create();
nuclear@7 51 msurf_set_user_data(msurf, this);
nuclear@9 52 msurf_set_resolution(msurf, 28, 28, 35);
nuclear@7 53 msurf_set_threshold(msurf, 1.0);
nuclear@7 54 msurf_eval_func(msurf, mseval);
nuclear@7 55 msurf_vertex_func(msurf, msvertex);
nuclear@10 56
nuclear@10 57 if(detail_obj.empty()) {
nuclear@10 58 gen_detail_meshes();
nuclear@10 59 }
nuclear@6 60 }
nuclear@6 61
nuclear@6 62 Dragon::~Dragon()
nuclear@6 63 {
nuclear@7 64 delete [] neck_seg;
nuclear@7 65 msurf_free(msurf);
nuclear@7 66
nuclear@7 67 delete [] dyn_varr;
nuclear@7 68 glDeleteBuffers(1, &dyn_vbo);
nuclear@6 69 }
nuclear@6 70
nuclear@6 71 void Dragon::set_position(const Vector3 &p)
nuclear@6 72 {
nuclear@6 73 pos = p;
nuclear@6 74 }
nuclear@6 75
nuclear@6 76 void Dragon::set_direction(const Vector3 &dir)
nuclear@6 77 {
nuclear@6 78 this->dir = dir.normalized();
nuclear@6 79 }
nuclear@6 80
nuclear@6 81 void Dragon::set_target(const Vector3 &p)
nuclear@6 82 {
nuclear@6 83 target = p;
nuclear@6 84 }
nuclear@6 85
nuclear@6 86 void Dragon::set_head_limits(float xmin, float xmax, float ymin, float ymax)
nuclear@6 87 {
nuclear@6 88 head_xlim[0] = std::min(xmin, xmax);
nuclear@6 89 head_xlim[1] = std::max(xmin, xmax);
nuclear@6 90 head_ylim[0] = std::min(ymin, ymax);
nuclear@6 91 head_ylim[1] = std::max(ymin, ymax);
nuclear@6 92 }
nuclear@6 93
nuclear@6 94 void Dragon::move_head(const Vector3 &p)
nuclear@6 95 {
nuclear@6 96 head_pos = p;
nuclear@6 97 }
nuclear@6 98
nuclear@6 99 static float clamp(float x, float low, float high)
nuclear@6 100 {
nuclear@6 101 return x < low ? low : (x > high ? high : x);
nuclear@6 102 }
nuclear@6 103
nuclear@6 104 void Dragon::move_head(float dx, float dy)
nuclear@6 105 {
nuclear@6 106 float newx = clamp(head_pos.x + dx, head_xlim[0], head_xlim[1]);
nuclear@6 107 float newy = clamp(head_pos.y + dy, head_ylim[0], head_ylim[1]);
nuclear@6 108
nuclear@6 109 dx = newx - head_pos.x;
nuclear@6 110 dy = newy - head_pos.y;
nuclear@6 111 head_pos.x = newx;
nuclear@6 112 head_pos.y = newy;
nuclear@6 113
nuclear@6 114 target.x += dx * 0.7;
nuclear@6 115 target.y += dy * 0.5;
nuclear@6 116 }
nuclear@6 117
nuclear@6 118 const Vector3 &Dragon::head_position() const
nuclear@6 119 {
nuclear@6 120 return head_pos;
nuclear@6 121 }
nuclear@6 122
nuclear@6 123 Vector3 Dragon::breath_dir() const
nuclear@6 124 {
nuclear@6 125 return (target - head_pos).normalized();
nuclear@6 126 }
nuclear@6 127
nuclear@6 128 void Dragon::update()
nuclear@6 129 {
nuclear@7 130 Vector3 bdir = breath_dir();
nuclear@7 131 Vector3 bezcp[] = { pos, pos + dir * 6.0, head_pos - bdir * 8.0, head_pos };
nuclear@7 132
nuclear@7 133 float t = 0.0, dt = 1.0 / (float)(neck_seg_count + 1);
nuclear@7 134 Vector3 p = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t);
nuclear@7 135
nuclear@7 136 for(int i=0; i<neck_seg_count; i++) {
nuclear@7 137 t += dt;
nuclear@7 138 Vector3 pnext = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t);
nuclear@7 139
nuclear@7 140 neck_seg[i].p[0] = p;
nuclear@7 141 neck_seg[i].p[1] = pnext;
nuclear@7 142
nuclear@7 143 p = pnext;
nuclear@7 144 }
nuclear@6 145 }
nuclear@6 146
nuclear@7 147 void Dragon::draw() const
nuclear@7 148 {
nuclear@9 149 float xmin = std::min(head_pos.x, pos.x);
nuclear@9 150 float xmax = std::max(head_pos.x, pos.x);
nuclear@9 151 float ymin = std::min(head_pos.y, pos.y);
nuclear@9 152 float ymax = std::max(head_pos.y, pos.y);
nuclear@9 153
nuclear@9 154 float bmin[] = { xmin - VOXEL_PAD * 1.2f, ymin - VOXEL_PAD, head_pos.z };
nuclear@9 155 float bmax[] = { xmax + VOXEL_PAD * 1.2f, ymax + VOXEL_PAD * 2.1f, pos.z + VOXEL_PAD };
nuclear@7 156 msurf_set_bounds(msurf, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]);
nuclear@7 157
nuclear@7 158
nuclear@7 159 if(!shadow_pass) {
nuclear@7 160
nuclear@7 161 if(dbg_wireframe) {
nuclear@7 162 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
nuclear@7 163 }
nuclear@7 164
nuclear@7 165 dyn_vidx = 0;
nuclear@7 166 msurf_polygonize(msurf);
nuclear@7 167 flush_dynvbo();
nuclear@7 168
nuclear@7 169 if(dbg_wireframe) {
nuclear@7 170 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
nuclear@7 171 }
nuclear@7 172
nuclear@7 173 int cur_sdr;
nuclear@7 174 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
nuclear@7 175 glUseProgram(0);
nuclear@7 176
nuclear@7 177 glPushAttrib(GL_ENABLE_BIT);
nuclear@7 178 glDisable(GL_LIGHTING);
nuclear@7 179
nuclear@7 180 // bounds
nuclear@7 181 glColor3f(1, 0, 0);
nuclear@7 182 glBegin(GL_LINE_LOOP);
nuclear@7 183 glVertex3f(bmin[0], bmin[1], bmin[2]);
nuclear@7 184 glVertex3f(bmax[0], bmin[1], bmin[2]);
nuclear@7 185 glVertex3f(bmax[0], bmax[1], bmin[2]);
nuclear@7 186 glVertex3f(bmin[0], bmax[1], bmin[2]);
nuclear@7 187 glEnd();
nuclear@7 188 glBegin(GL_LINE_LOOP);
nuclear@7 189 glVertex3f(bmin[0], bmin[1], bmax[2]);
nuclear@7 190 glVertex3f(bmax[0], bmin[1], bmax[2]);
nuclear@7 191 glVertex3f(bmax[0], bmax[1], bmax[2]);
nuclear@7 192 glVertex3f(bmin[0], bmax[1], bmax[2]);
nuclear@7 193 glEnd();
nuclear@7 194 glBegin(GL_LINE_LOOP);
nuclear@7 195 glVertex3f(bmin[0], bmax[1], bmin[2]);
nuclear@7 196 glVertex3f(bmax[0], bmax[1], bmin[2]);
nuclear@7 197 glVertex3f(bmax[0], bmax[1], bmax[2]);
nuclear@7 198 glVertex3f(bmin[0], bmax[1], bmax[2]);
nuclear@7 199 glEnd();
nuclear@7 200 glBegin(GL_LINE_LOOP);
nuclear@7 201 glVertex3f(bmin[0], bmin[1], bmin[2]);
nuclear@7 202 glVertex3f(bmax[0], bmin[1], bmin[2]);
nuclear@7 203 glVertex3f(bmax[0], bmin[1], bmax[2]);
nuclear@7 204 glVertex3f(bmin[0], bmin[1], bmax[2]);
nuclear@7 205 glEnd();
nuclear@7 206
nuclear@7 207 // foo
nuclear@7 208 glDisable(GL_DEPTH_TEST);
nuclear@7 209 glEnable(GL_BLEND);
nuclear@7 210 glBlendFunc(GL_ONE, GL_ONE);
nuclear@7 211 glLineWidth(2.0);
nuclear@7 212 glColor3f(0, 0, 1);
nuclear@7 213
nuclear@7 214 glBegin(GL_LINES);
nuclear@7 215 for(int i=0; i<neck_seg_count; i++) {
nuclear@7 216 glVertex3f(neck_seg[i].p[0].x, neck_seg[i].p[0].y, neck_seg[i].p[0].z);
nuclear@7 217 glVertex3f(neck_seg[i].p[1].x, neck_seg[i].p[1].y, neck_seg[i].p[1].z);
nuclear@7 218 }
nuclear@7 219 glEnd();
nuclear@7 220 glLineWidth(1);
nuclear@7 221
nuclear@7 222 // done debug drawing
nuclear@7 223 glPopAttrib();
nuclear@7 224 if(cur_sdr) glUseProgram(cur_sdr);
nuclear@7 225 }
nuclear@10 226
nuclear@10 227 // draw detail objects
nuclear@10 228 for(size_t i=0; i<detail_obj.size(); i++) {
nuclear@10 229 detail_obj[i]->xform().set_translation(head_pos);
nuclear@10 230
nuclear@10 231 if(dbg_wireframe) {
nuclear@10 232 detail_obj[i]->draw_wire();
nuclear@10 233 } else {
nuclear@10 234 detail_obj[i]->draw();
nuclear@10 235 }
nuclear@10 236 }
nuclear@7 237 }
nuclear@7 238
nuclear@7 239 void Dragon::flush_dynvbo() const
nuclear@7 240 {
nuclear@7 241 if(!dyn_vidx) return;
nuclear@7 242
nuclear@7 243 glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo);
nuclear@7 244 glBufferSubData(GL_ARRAY_BUFFER, 0, dyn_vidx * sizeof(DynVertex), dyn_varr);
nuclear@7 245
nuclear@7 246 glEnableClientState(GL_VERTEX_ARRAY);
nuclear@7 247 glVertexPointer(3, GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, x));
nuclear@7 248 glEnableClientState(GL_NORMAL_ARRAY);
nuclear@7 249 glNormalPointer(GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, nx));
nuclear@7 250 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@7 251
nuclear@7 252 glDrawArrays(GL_TRIANGLES, 0, dyn_vidx);
nuclear@7 253
nuclear@7 254 glDisableClientState(GL_VERTEX_ARRAY);
nuclear@7 255 glDisableClientState(GL_NORMAL_ARRAY);
nuclear@7 256 dyn_vidx = 0;
nuclear@7 257 }
nuclear@7 258
nuclear@7 259
nuclear@6 260 static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t)
nuclear@6 261 {
nuclear@6 262 float x = bezier(a.x, b.x, c.x, d.x, t);
nuclear@6 263 float y = bezier(a.y, b.y, c.y, d.y, t);
nuclear@6 264 float z = bezier(a.z, b.z, c.z, d.z, t);
nuclear@6 265 return Vector3(x, y, z);
nuclear@6 266 }
nuclear@6 267
nuclear@7 268 static float mseval(struct metasurface *ms, float x, float y, float z)
nuclear@6 269 {
nuclear@7 270 Dragon *dragon = (Dragon*)msurf_get_user_data(ms);
nuclear@6 271
nuclear@7 272 Vector3 pt = Vector3(x, y, z);
nuclear@7 273 Capsule *seg = dragon->neck_seg;
nuclear@6 274
nuclear@7 275 //printf("eval(%g %g %g)\n", x, y, z);
nuclear@6 276
nuclear@7 277 float sum = 0.0f;
nuclear@7 278 for(int i=0; i<dragon->neck_seg_count; i++) {
nuclear@7 279 float dist = capsule_distance(seg[i].p[0], seg[i].w[0], seg[i].p[1], seg[i].w[1], pt);
nuclear@7 280 //float dist = sphere_distance(seg[i].p[0], 1.0, pt);
nuclear@7 281 if(dist < 1e-4) dist = 1e-4;
nuclear@7 282 float energy = 0.0001 / (dist * dist);
nuclear@7 283 /*float dx = x - seg[i].p[0].x;
nuclear@7 284 float dy = y - seg[i].p[0].y;
nuclear@7 285 float dz = z - seg[i].p[0].z;
nuclear@7 286 float energy = 0.5 / (dx * dx + dy * dy + dz * dz);*/
nuclear@7 287 sum += energy;
nuclear@7 288 }
nuclear@7 289 return sum;
nuclear@7 290 }
nuclear@6 291
nuclear@7 292 static void msvertex(struct metasurface *ms, float x, float y, float z)
nuclear@7 293 {
nuclear@7 294 Dragon *dragon = (Dragon*)msurf_get_user_data(ms);
nuclear@7 295
nuclear@7 296 const float dt = 0.001;
nuclear@7 297 float dfdx = mseval(ms, x - dt, y, z) - mseval(ms, x + dt, y, z);
nuclear@7 298 float dfdy = mseval(ms, x, y - dt, z) - mseval(ms, x, y + dt, z);
nuclear@7 299 float dfdz = mseval(ms, x, y, z - dt) - mseval(ms, x, y, z + dt);
nuclear@7 300
nuclear@7 301 DynVertex *vptr = dragon->dyn_varr + dragon->dyn_vidx++;
nuclear@7 302 vptr->x = x;
nuclear@7 303 vptr->y = y;
nuclear@7 304 vptr->z = z;
nuclear@7 305 vptr->nx = dfdx;
nuclear@7 306 vptr->ny = dfdy;
nuclear@7 307 vptr->nz = dfdz;
nuclear@7 308
nuclear@7 309 if(dragon->dyn_vidx >= DYN_VCOUNT) {
nuclear@7 310 dragon->flush_dynvbo();
nuclear@6 311 }
nuclear@6 312 }
nuclear@10 313
nuclear@10 314
nuclear@10 315 #define HORN_RAD 0.15f
nuclear@10 316 static Vector2 horn_sweep(float u, float v, void *cls)
nuclear@10 317 {
nuclear@10 318 float t = 1.0f - v;
nuclear@10 319 float angle = u * 2.0 * M_PI;
nuclear@10 320 float x = sin(angle) * t * HORN_RAD;
nuclear@10 321 float y = cos(angle) * t * HORN_RAD;
nuclear@10 322 return Vector2(x, y + smoothstep(0.3, 1.0, v) * 0.5);
nuclear@10 323 }
nuclear@10 324
nuclear@10 325 static void gen_detail_meshes()
nuclear@10 326 {
nuclear@10 327 Mesh *mesh;
nuclear@10 328 Object *obj;
nuclear@10 329 Matrix4x4 xform;
nuclear@10 330
nuclear@10 331 for(int i=0; i<2; i++) {
nuclear@10 332 float sign = i ? 1.0f : -1.0f;
nuclear@10 333
nuclear@10 334 mesh = new Mesh;
nuclear@10 335 gen_sweep(mesh, 2, 6, 6, horn_sweep, 0);
nuclear@10 336 xform.set_translation(Vector3(0.5 * sign, 1.5, 3));
nuclear@10 337 xform.rotate(Vector3(DEG_TO_RAD(25), 0, 0));
nuclear@10 338 xform.rotate(Vector3(0, 0, DEG_TO_RAD(15) * -sign));
nuclear@10 339 mesh->apply_xform(xform, Matrix4x4::identity);
nuclear@10 340
nuclear@10 341 obj = new Object;
nuclear@10 342 obj->set_mesh(mesh);
nuclear@10 343 obj->mtl.diffuse = Vector3(1.0, 0.85, 0.8);
nuclear@10 344 obj->mtl.specular = Vector3(1, 1, 1);
nuclear@10 345 obj->mtl.shininess = 60.0;
nuclear@10 346
nuclear@10 347 detail_obj.push_back(obj);
nuclear@10 348 }
nuclear@10 349 }