ld33_umonster

annotate src/dragon.cc @ 7:92d662deb66e

capsule distance seems broken
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 25 Aug 2015 00:38:00 +0300
parents 3b4460b34d43
children bed39534d471
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@7 7 #include "shadow.h"
nuclear@7 8
nuclear@7 9 #define VOXEL_PAD 1.0f
nuclear@7 10 #define DYN_FCOUNT 64
nuclear@7 11 #define DYN_VCOUNT (DYN_FCOUNT * 3)
nuclear@7 12
nuclear@7 13 #define NUM_NECK_SEG 8
nuclear@7 14 static const float nseg_sizes[NUM_NECK_SEG][2] = {
nuclear@7 15 {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 16 };
nuclear@7 17
nuclear@7 18 static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t);
nuclear@7 19 static float mseval(struct metasurface *ms, float x, float y, float z);
nuclear@7 20 static void msvertex(struct metasurface *ms, float x, float y, float z);
nuclear@7 21
nuclear@6 22
nuclear@6 23 Dragon::Dragon()
nuclear@6 24 : pos(0, 0, 0), dir(0, 0, -1), head_pos(0, 0, -1), target(0, 0, -2)
nuclear@6 25 {
nuclear@6 26 set_head_limits(-1, 1, -1, 1);
nuclear@7 27
nuclear@7 28 glGenBuffers(1, &dyn_vbo);
nuclear@7 29 glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo);
nuclear@7 30 glBufferData(GL_ARRAY_BUFFER, DYN_VCOUNT * sizeof(DynVertex), 0, GL_STREAM_DRAW);
nuclear@7 31 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@7 32
nuclear@7 33 dyn_varr = new DynVertex[DYN_VCOUNT];
nuclear@7 34
nuclear@7 35 neck_seg_count = NUM_NECK_SEG;
nuclear@7 36 neck_seg = new Capsule[neck_seg_count];
nuclear@7 37
nuclear@7 38 for(int i=0; i<neck_seg_count; i++) {
nuclear@7 39 neck_seg[i].w[0] = nseg_sizes[i][0];
nuclear@7 40 neck_seg[i].w[1] = nseg_sizes[i][1];
nuclear@7 41 }
nuclear@7 42
nuclear@7 43 msurf = msurf_create();
nuclear@7 44 msurf_set_user_data(msurf, this);
nuclear@7 45 msurf_set_resolution(msurf, 36, 36, 36);
nuclear@7 46 msurf_set_threshold(msurf, 1.0);
nuclear@7 47 msurf_eval_func(msurf, mseval);
nuclear@7 48 msurf_vertex_func(msurf, msvertex);
nuclear@6 49 }
nuclear@6 50
nuclear@6 51 Dragon::~Dragon()
nuclear@6 52 {
nuclear@7 53 delete [] neck_seg;
nuclear@7 54 msurf_free(msurf);
nuclear@7 55
nuclear@7 56 delete [] dyn_varr;
nuclear@7 57 glDeleteBuffers(1, &dyn_vbo);
nuclear@6 58 }
nuclear@6 59
nuclear@6 60 void Dragon::set_position(const Vector3 &p)
nuclear@6 61 {
nuclear@6 62 pos = p;
nuclear@6 63 }
nuclear@6 64
nuclear@6 65 void Dragon::set_direction(const Vector3 &dir)
nuclear@6 66 {
nuclear@6 67 this->dir = dir.normalized();
nuclear@6 68 }
nuclear@6 69
nuclear@6 70 void Dragon::set_target(const Vector3 &p)
nuclear@6 71 {
nuclear@6 72 target = p;
nuclear@6 73 }
nuclear@6 74
nuclear@6 75 void Dragon::set_head_limits(float xmin, float xmax, float ymin, float ymax)
nuclear@6 76 {
nuclear@6 77 head_xlim[0] = std::min(xmin, xmax);
nuclear@6 78 head_xlim[1] = std::max(xmin, xmax);
nuclear@6 79 head_ylim[0] = std::min(ymin, ymax);
nuclear@6 80 head_ylim[1] = std::max(ymin, ymax);
nuclear@6 81 }
nuclear@6 82
nuclear@6 83 void Dragon::move_head(const Vector3 &p)
nuclear@6 84 {
nuclear@6 85 head_pos = p;
nuclear@6 86 }
nuclear@6 87
nuclear@6 88 static float clamp(float x, float low, float high)
nuclear@6 89 {
nuclear@6 90 return x < low ? low : (x > high ? high : x);
nuclear@6 91 }
nuclear@6 92
nuclear@6 93 void Dragon::move_head(float dx, float dy)
nuclear@6 94 {
nuclear@6 95 float newx = clamp(head_pos.x + dx, head_xlim[0], head_xlim[1]);
nuclear@6 96 float newy = clamp(head_pos.y + dy, head_ylim[0], head_ylim[1]);
nuclear@6 97
nuclear@6 98 dx = newx - head_pos.x;
nuclear@6 99 dy = newy - head_pos.y;
nuclear@6 100 head_pos.x = newx;
nuclear@6 101 head_pos.y = newy;
nuclear@6 102
nuclear@6 103 target.x += dx * 0.7;
nuclear@6 104 target.y += dy * 0.5;
nuclear@6 105 }
nuclear@6 106
nuclear@6 107 const Vector3 &Dragon::head_position() const
nuclear@6 108 {
nuclear@6 109 return head_pos;
nuclear@6 110 }
nuclear@6 111
nuclear@6 112 Vector3 Dragon::breath_dir() const
nuclear@6 113 {
nuclear@6 114 return (target - head_pos).normalized();
nuclear@6 115 }
nuclear@6 116
nuclear@6 117 void Dragon::update()
nuclear@6 118 {
nuclear@7 119 Vector3 bdir = breath_dir();
nuclear@7 120 Vector3 bezcp[] = { pos, pos + dir * 6.0, head_pos - bdir * 8.0, head_pos };
nuclear@7 121
nuclear@7 122 float t = 0.0, dt = 1.0 / (float)(neck_seg_count + 1);
nuclear@7 123 Vector3 p = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t);
nuclear@7 124
nuclear@7 125 for(int i=0; i<neck_seg_count; i++) {
nuclear@7 126 t += dt;
nuclear@7 127 Vector3 pnext = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t);
nuclear@7 128
nuclear@7 129 neck_seg[i].p[0] = p;
nuclear@7 130 neck_seg[i].p[1] = pnext;
nuclear@7 131
nuclear@7 132 p = pnext;
nuclear@7 133 }
nuclear@6 134 }
nuclear@6 135
nuclear@7 136 void Dragon::draw() const
nuclear@7 137 {
nuclear@7 138 static float bmin[] = { head_xlim[0] - VOXEL_PAD * 0.9, head_ylim[0] - VOXEL_PAD, head_pos.z };
nuclear@7 139 static float bmax[] = { head_xlim[1] + VOXEL_PAD * 0.9, head_ylim[1] + VOXEL_PAD * 2.1f, pos.z + VOXEL_PAD };
nuclear@7 140 msurf_set_bounds(msurf, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]);
nuclear@7 141
nuclear@7 142
nuclear@7 143 if(!shadow_pass) {
nuclear@7 144
nuclear@7 145 if(dbg_wireframe) {
nuclear@7 146 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
nuclear@7 147 }
nuclear@7 148
nuclear@7 149 dyn_vidx = 0;
nuclear@7 150 msurf_polygonize(msurf);
nuclear@7 151 flush_dynvbo();
nuclear@7 152
nuclear@7 153 if(dbg_wireframe) {
nuclear@7 154 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
nuclear@7 155 }
nuclear@7 156
nuclear@7 157 int cur_sdr;
nuclear@7 158 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
nuclear@7 159 glUseProgram(0);
nuclear@7 160
nuclear@7 161 glPushAttrib(GL_ENABLE_BIT);
nuclear@7 162 glDisable(GL_LIGHTING);
nuclear@7 163
nuclear@7 164 // bounds
nuclear@7 165 glColor3f(1, 0, 0);
nuclear@7 166 glBegin(GL_LINE_LOOP);
nuclear@7 167 glVertex3f(bmin[0], bmin[1], bmin[2]);
nuclear@7 168 glVertex3f(bmax[0], bmin[1], bmin[2]);
nuclear@7 169 glVertex3f(bmax[0], bmax[1], bmin[2]);
nuclear@7 170 glVertex3f(bmin[0], bmax[1], bmin[2]);
nuclear@7 171 glEnd();
nuclear@7 172 glBegin(GL_LINE_LOOP);
nuclear@7 173 glVertex3f(bmin[0], bmin[1], bmax[2]);
nuclear@7 174 glVertex3f(bmax[0], bmin[1], bmax[2]);
nuclear@7 175 glVertex3f(bmax[0], bmax[1], bmax[2]);
nuclear@7 176 glVertex3f(bmin[0], bmax[1], bmax[2]);
nuclear@7 177 glEnd();
nuclear@7 178 glBegin(GL_LINE_LOOP);
nuclear@7 179 glVertex3f(bmin[0], bmax[1], bmin[2]);
nuclear@7 180 glVertex3f(bmax[0], bmax[1], bmin[2]);
nuclear@7 181 glVertex3f(bmax[0], bmax[1], bmax[2]);
nuclear@7 182 glVertex3f(bmin[0], bmax[1], bmax[2]);
nuclear@7 183 glEnd();
nuclear@7 184 glBegin(GL_LINE_LOOP);
nuclear@7 185 glVertex3f(bmin[0], bmin[1], bmin[2]);
nuclear@7 186 glVertex3f(bmax[0], bmin[1], bmin[2]);
nuclear@7 187 glVertex3f(bmax[0], bmin[1], bmax[2]);
nuclear@7 188 glVertex3f(bmin[0], bmin[1], bmax[2]);
nuclear@7 189 glEnd();
nuclear@7 190
nuclear@7 191 // foo
nuclear@7 192 glDisable(GL_DEPTH_TEST);
nuclear@7 193 glEnable(GL_BLEND);
nuclear@7 194 glBlendFunc(GL_ONE, GL_ONE);
nuclear@7 195 glLineWidth(2.0);
nuclear@7 196 glColor3f(0, 0, 1);
nuclear@7 197
nuclear@7 198 glBegin(GL_LINES);
nuclear@7 199 for(int i=0; i<neck_seg_count; i++) {
nuclear@7 200 glVertex3f(neck_seg[i].p[0].x, neck_seg[i].p[0].y, neck_seg[i].p[0].z);
nuclear@7 201 glVertex3f(neck_seg[i].p[1].x, neck_seg[i].p[1].y, neck_seg[i].p[1].z);
nuclear@7 202 }
nuclear@7 203 glEnd();
nuclear@7 204 glLineWidth(1);
nuclear@7 205
nuclear@7 206 // done debug drawing
nuclear@7 207 glPopAttrib();
nuclear@7 208 if(cur_sdr) glUseProgram(cur_sdr);
nuclear@7 209 }
nuclear@7 210 }
nuclear@7 211
nuclear@7 212 void Dragon::flush_dynvbo() const
nuclear@7 213 {
nuclear@7 214 if(!dyn_vidx) return;
nuclear@7 215
nuclear@7 216 glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo);
nuclear@7 217 glBufferSubData(GL_ARRAY_BUFFER, 0, dyn_vidx * sizeof(DynVertex), dyn_varr);
nuclear@7 218
nuclear@7 219 glEnableClientState(GL_VERTEX_ARRAY);
nuclear@7 220 glVertexPointer(3, GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, x));
nuclear@7 221 glEnableClientState(GL_NORMAL_ARRAY);
nuclear@7 222 glNormalPointer(GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, nx));
nuclear@7 223 glBindBuffer(GL_ARRAY_BUFFER, 0);
nuclear@7 224
nuclear@7 225 glDrawArrays(GL_TRIANGLES, 0, dyn_vidx);
nuclear@7 226
nuclear@7 227 glDisableClientState(GL_VERTEX_ARRAY);
nuclear@7 228 glDisableClientState(GL_NORMAL_ARRAY);
nuclear@7 229 dyn_vidx = 0;
nuclear@7 230 }
nuclear@7 231
nuclear@7 232
nuclear@6 233 static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t)
nuclear@6 234 {
nuclear@6 235 float x = bezier(a.x, b.x, c.x, d.x, t);
nuclear@6 236 float y = bezier(a.y, b.y, c.y, d.y, t);
nuclear@6 237 float z = bezier(a.z, b.z, c.z, d.z, t);
nuclear@6 238 return Vector3(x, y, z);
nuclear@6 239 }
nuclear@6 240
nuclear@7 241 static float mseval(struct metasurface *ms, float x, float y, float z)
nuclear@6 242 {
nuclear@7 243 Dragon *dragon = (Dragon*)msurf_get_user_data(ms);
nuclear@6 244
nuclear@7 245 Vector3 pt = Vector3(x, y, z);
nuclear@7 246 Capsule *seg = dragon->neck_seg;
nuclear@6 247
nuclear@7 248 //printf("eval(%g %g %g)\n", x, y, z);
nuclear@6 249
nuclear@7 250 float sum = 0.0f;
nuclear@7 251 for(int i=0; i<dragon->neck_seg_count; i++) {
nuclear@7 252 float dist = capsule_distance(seg[i].p[0], seg[i].w[0], seg[i].p[1], seg[i].w[1], pt);
nuclear@7 253 //float dist = sphere_distance(seg[i].p[0], 1.0, pt);
nuclear@7 254 if(dist < 1e-4) dist = 1e-4;
nuclear@7 255 float energy = 0.0001 / (dist * dist);
nuclear@7 256 /*float dx = x - seg[i].p[0].x;
nuclear@7 257 float dy = y - seg[i].p[0].y;
nuclear@7 258 float dz = z - seg[i].p[0].z;
nuclear@7 259 float energy = 0.5 / (dx * dx + dy * dy + dz * dz);*/
nuclear@7 260 sum += energy;
nuclear@7 261 }
nuclear@7 262 return sum;
nuclear@7 263 }
nuclear@6 264
nuclear@7 265 static void msvertex(struct metasurface *ms, float x, float y, float z)
nuclear@7 266 {
nuclear@7 267 Dragon *dragon = (Dragon*)msurf_get_user_data(ms);
nuclear@7 268
nuclear@7 269 const float dt = 0.001;
nuclear@7 270 float dfdx = mseval(ms, x - dt, y, z) - mseval(ms, x + dt, y, z);
nuclear@7 271 float dfdy = mseval(ms, x, y - dt, z) - mseval(ms, x, y + dt, z);
nuclear@7 272 float dfdz = mseval(ms, x, y, z - dt) - mseval(ms, x, y, z + dt);
nuclear@7 273
nuclear@7 274 DynVertex *vptr = dragon->dyn_varr + dragon->dyn_vidx++;
nuclear@7 275 vptr->x = x;
nuclear@7 276 vptr->y = y;
nuclear@7 277 vptr->z = z;
nuclear@7 278 vptr->nx = dfdx;
nuclear@7 279 vptr->ny = dfdy;
nuclear@7 280 vptr->nz = dfdz;
nuclear@7 281
nuclear@7 282 if(dragon->dyn_vidx >= DYN_VCOUNT) {
nuclear@7 283 dragon->flush_dynvbo();
nuclear@6 284 }
nuclear@6 285 }