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 }
|