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