]> Dogcows Code - chaz/yoink/blob - src/Scene.cc
9510e3670577fff9a7385f343f34a6773a9a9392
[chaz/yoink] / src / Scene.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include <map>
13
14 #include <moof/aabb.hh>
15 #include <moof/camera.hh>
16 #include <moof/entity.hh>
17 #include <moof/line.hh>
18 #include <moof/log.hh>
19 #include <moof/manager.hh>
20 #include <moof/math.hh>
21 #include <moof/script.hh>
22 #include <moof/settings.hh>
23 #include <moof/texture.hh>
24
25 #include "Character.hh"
26 #include "Scene.hh"
27
28
29 struct Scene::impl : public moof::manager<impl>
30 {
31 struct Quad : public moof::entity
32 {
33 enum Surface
34 {
35 NONE = 0,
36 LEFT = 1,
37 RIGHT = 2,
38 TOP = 3
39 };
40
41 Quad(const moof::vector3* vertices[4],
42 const std::string& texture,
43 int tileIndex) :
44 mTilemap(texture),
45 mBlending(false),
46 mFog(false),
47 mSurface(NONE)
48 {
49 for (int i = 0; i < 4; ++i)
50 {
51 mVertices[i] = *vertices[i];
52 //for (int j = 0; j < 3; ++j, ++num)
53 //{
54 //mVertices[num] = (*vertices[i])[j];
55 //}
56 }
57
58 if (!mTilemap.tile_coordinates(tileIndex, mTexCoords))
59 {
60 moof::log_warning << "no index " << tileIndex <<
61 " in texture " << texture << std::endl;
62
63 mTexCoords[0] = mTexCoords[1] =
64 mTexCoords[3] = mTexCoords[6] = 0.0;
65 mTexCoords[2] = mTexCoords[4] =
66 mTexCoords[5] = mTexCoords[7] = 1.0;
67 }
68
69 aabb_.enclose_vertices(mVertices, 4);
70 sphere_.point = aabb_.center();
71 sphere_.radius = (aabb_.min - sphere_.point).length();
72 }
73
74 void setBlending(bool blending)
75 {
76 mBlending = blending;
77 }
78
79 void setFog(bool fog)
80 {
81 mFog = fog;
82 }
83
84 void setSurface(Surface type)
85 {
86 mSurface = type;
87 }
88
89 Surface getSurface() const
90 {
91 return mSurface;
92 }
93
94 void draw(moof::scalar alpha = 0.0) const
95 {
96 if (mBlending)
97 {
98 glEnable(GL_BLEND);
99 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
100 }
101
102 if (mFog)
103 {
104 glEnable(GL_FOG);
105 glFogi(GL_FOG_MODE, GL_LINEAR);
106 }
107
108 //glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
109 mTilemap.bind();
110
111 glVertexPointer(3, GL_SCALAR, 0, mVertices[0].data());
112 glTexCoordPointer(2, GL_SCALAR, 0, mTexCoords);
113
114 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
115
116 glDisable(GL_BLEND);
117 glDisable(GL_FOG);
118 }
119
120 bool is_visible(const moof::frustum& frustum) const
121 {
122 return sphere_.is_visible(frustum);
123 }
124
125
126 moof::vector3 mVertices[4];
127 moof::scalar mTexCoords[8];
128
129 moof::texture mTilemap;
130
131 bool mBlending;
132 bool mFog;
133 Surface mSurface;
134 };
135
136
137
138 moof::matrix4 mTransform;
139 std::string mTexture;
140
141 std::list< boost::shared_ptr<impl::Quad> > mObjects;
142 std::list<moof::line2> mLines;
143
144 moof::aabb<3> mBounds;
145
146
147 enum AXIS
148 {
149 X = 0,
150 Y = 1,
151 Z = 2
152 };
153
154
155 void init(const std::string& name) {}
156
157
158 void importSceneBindings(moof::settings& settings, moof::script& script)
159 {
160 script.import_function("SetBounds",
161 boost::bind(&impl::setBounds, this, _1));
162 script.import_function("ResetTransform",
163 boost::bind(&impl::resetTransform, this, _1));
164 script.import_function("Translate",
165 boost::bind(&impl::translate, this, _1));
166 script.import_function("Scale",
167 boost::bind(&impl::scale, this, _1));
168 script.import_function("Rotate",
169 boost::bind(&impl::rotate, this, _1));
170 script.import_function("SetTexture",
171 boost::bind(&impl::setTexture, this, _1));
172 script.import_function("DrawTilemap",
173 boost::bind(&impl::drawTilemap, this, _1));
174 script.import_function("DrawTile",
175 boost::bind(&impl::drawTile, this, _1));
176
177 int detail = 3;
178 settings.get("detail", detail);
179 script.globals().set_field("detail", detail);
180
181 script.globals().set_field("LOW", 1);
182 script.globals().set_field("MEDIUM", 2);
183 script.globals().set_field("HIGH", 3);
184
185 script.globals().set_field("X", X);
186 script.globals().set_field("Y", Y);
187 script.globals().set_field("Z", Z);
188
189 script.globals().set_field("LEFT", Quad::LEFT);
190 script.globals().set_field("RIGHT", Quad::RIGHT);
191 script.globals().set_field("TOP", Quad::TOP);
192 }
193
194
195 moof::script::status load(moof::settings& settings, moof::script& script)
196 {
197 std::string path(name());
198 if (!Scene::find_path(path))
199 {
200 script.push("the scene file could not be found");
201 return moof::script::file_error;
202 }
203
204 importSceneBindings(settings, script);
205 return script.do_file(path);
206 }
207
208
209 static int loadBox(moof::script& script, moof::aabb3& aabb)
210 {
211 script[1].require_table();
212 script[2].require_table();
213
214 script[1].push_field(1).get(aabb.min[0]);
215 script[1].push_field(2).get(aabb.min[1]);
216 script[1].push_field(3).get(aabb.min[2]);
217 script[2].push_field(1).get(aabb.max[0]);
218 script[2].push_field(2).get(aabb.max[1]);
219 script[2].push_field(3).get(aabb.max[2]);
220
221 return 0;
222 }
223
224 int setBounds(moof::script& script)
225 {
226 int ret = loadBox(script, mBounds);
227 return ret;
228 }
229
230 int resetTransform(moof::script& script)
231 {
232 mTransform.identity();
233 return 0;
234 }
235
236 int translate(moof::script& script)
237 {
238 moof::vector3 vec;
239 script[1].require_number().get(vec[0]);
240 script[2].require_number().get(vec[1]);
241 script[3].require_number().get(vec[2]);
242
243 moof::matrix4 translation;
244 moof::matrix_translation(translation, vec);
245 mTransform = translation * mTransform;
246
247 return 0;
248 }
249
250 int scale(moof::script& script)
251 {
252 int size = script.stack_size();
253
254 if (size == 1)
255 {
256 moof::scalar value = 1.0;
257 script[1].require_number().get(value);
258
259 moof::matrix4 scaling;
260 moof::matrix_uniform_scale(scaling, value);
261 mTransform = scaling * mTransform;
262 }
263 else if (size == 3)
264 {
265 moof::vector3 vec;
266 script[1].require_number().get(vec[0]);
267 script[2].require_number().get(vec[1]);
268 script[3].require_number().get(vec[2]);
269
270 moof::matrix4 scaling;
271 moof::matrix_scale(scaling, vec);
272 mTransform = scaling * mTransform;
273 }
274 else
275 {
276 script.top().raise("wrong number of arguments");
277 }
278
279 return 0;
280 }
281
282 int rotate(moof::script& script)
283 {
284 size_t index = 0;
285 script[1].require_number().get(index);
286
287 moof::scalar value;
288 script[2].require_number().get(value);
289
290 moof::matrix_rotate_about_world_axis(mTransform, index,
291 moof::rad(value));
292
293 return 0;
294 }
295
296 int setTexture(moof::script& script)
297 {
298 script[1].require_string().get(mTexture);
299 return 0;
300 }
301
302 int drawTilemap(moof::script& script)
303 {
304 moof::script::slot table = script[1].require_table();
305
306 int width = 1;
307 table.get(width, "width");
308
309 int nTiles = table.length();
310 if (nTiles % width != 0)
311 {
312 table.raise("invalid number of tiles");
313 }
314
315 if (width == 0) table.raise("width field must not be zero");
316 int height = nTiles / width;
317
318 moof::vector3 vertices[height+1][width+1];
319
320 // the indices are stored upside-down in the scene file so that
321 // they are easier to edit as text, so we'll need to load them last
322 // row first
323
324 // do first row and first column of vertices
325
326 for (int w = 0; w <= width; ++w)
327 {
328 vertices[height][w] = moof::demote(mTransform *
329 moof::vector4(w, height, 0.0, 1.0));
330 }
331 for (int h = 0; h < height; ++h)
332 {
333 vertices[h][0] = moof::demote(mTransform *
334 moof::vector4(0.0, h, 0.0, 1.0));
335 }
336
337 size_t i = 1;
338 for (int h = height - 1; h >= 0; --h)
339 {
340 for (int w = 0; w < width; ++w, ++i)
341 {
342 int wPlus1 = w + 1;
343 int hPlus1 = h + 1;
344
345 int index;
346 table.get(index, i);
347
348 vertices[h][wPlus1] = moof::demote(mTransform *
349 moof::vector4(wPlus1, h, 0.0, 1.0));
350
351 if (index == moof::texture::no_tile) continue;
352
353 const moof::vector3* corners[4] = {
354 &vertices[h][w],
355 &vertices[h][wPlus1],
356 &vertices[hPlus1][wPlus1],
357 &vertices[hPlus1][w]
358 };
359
360 Quad* quad = new Quad(corners, mTexture, index);
361 //quad->setSurface(surface);
362
363 boost::shared_ptr<Quad> quadPtr(quad);
364 mObjects.push_back(quadPtr);
365 }
366 }
367
368 Quad::Surface surface = Quad::NONE;
369 table.get(surface, "surface");
370
371 if (surface != Quad::NONE)
372 {
373 // need a 2d line for collisions
374 // assuming the camera always looks directly to -z when the
375 // scene is built, simply demoting the vector again should
376 // project the points to the xy-plane
377
378 moof::vector2 bl = moof::demote(vertices[0][0]);
379 moof::vector2 tr = moof::demote(vertices[height][width]);
380
381 mLines.push_back(moof::line<2>(bl, tr));
382 }
383
384 return 0;
385 }
386
387 int drawTile(moof::script& script)
388 {
389 moof::script::slot param = script[1];
390 moof::script::slot top = script[-1];
391
392 int index = 0;
393 int width = 1;
394 bool blending = false;
395 bool fog = false;
396
397 if (param.is_table())
398 {
399 param.get(index, 1);
400 param.get(width, "u_scale");
401 param.get(blending, "blend");
402 param.get(fog, "fog");
403 }
404 else if (param.is_number())
405 {
406 param.get(index);
407 }
408
409 moof::vector3 vertices[2][width+1];
410
411 moof::scalar xf;
412 moof::scalar increment = SCALAR(1.0) / moof::scalar(width);
413
414 for (int h = 0; h <= 1; ++h)
415 {
416 xf = 0.0;
417 for (int w = 0; w <= width; ++w, xf += increment)
418 {
419 vertices[h][w] = moof::demote(mTransform *
420 moof::vector4(xf, moof::scalar(h), 0.0, 1.0));
421 }
422 }
423
424 for (int w = 0; w < width; ++w)
425 {
426 int wPlus1 = w + 1;
427
428 const moof::vector3* corners[4] = {
429 &vertices[0][w],
430 &vertices[0][wPlus1],
431 &vertices[1][wPlus1],
432 &vertices[1][w]
433 };
434
435 Quad* quad = new Quad(corners, mTexture, index);
436 quad->setBlending(blending);
437 quad->setFog(fog);
438
439 boost::shared_ptr<Quad> quadPtr(quad);
440 mObjects.push_back(quadPtr);
441 }
442
443 return 0;
444 }
445 };
446
447
448 Scene::Scene(const std::string& name) :
449 // pass through
450 impl_(Scene::impl::instance(name)) {}
451
452
453 moof::script::status Scene::load(moof::settings& settings, moof::script& script)
454 {
455 // pass through
456 return impl_->load(settings, script);
457 }
458
459
460 void Scene::draw(moof::scalar alpha) const
461 {
462 std::list< boost::shared_ptr<impl::Quad> >& objects = impl_->mObjects;
463 std::list< boost::shared_ptr<impl::Quad> >::const_iterator it;
464
465 for (it = objects.begin(); it != objects.end(); ++it)
466 {
467 (*it)->draw(alpha);
468 }
469
470 impl_->mBounds.draw();
471 }
472
473 void Scene::draw_if_visible(moof::scalar alpha,
474 const moof::frustum& frustum) const
475 {
476 std::list< boost::shared_ptr<impl::Quad> >& objects = impl_->mObjects;
477 std::list< boost::shared_ptr<impl::Quad> >::const_iterator it;
478
479 for (it = objects.begin(); it != objects.end(); ++it)
480 {
481 (*it)->draw_if_visible(alpha, frustum);
482 }
483
484 std::list< moof::line<2> >& lines = impl_->mLines;
485 std::list< moof::line<2> >::const_iterator lit;
486
487 for (lit = lines.begin(); lit != lines.end(); ++lit)
488 {
489 (*lit).draw(alpha);
490 }
491
492 impl_->mBounds.draw();
493 }
494
495
496 bool Scene::castRay(const moof::ray<2>& ray,
497 std::list<moof::ray<2>::contact>& hits) const
498 {
499 std::list< moof::line<2> >& lines = impl_->mLines;
500 std::list< moof::line<2> >::const_iterator it;
501
502 for (it = lines.begin(); it != lines.end(); ++it)
503 {
504 moof::ray<2>::contact hit;
505 moof::scalar d = (*it).intersect_ray(ray, hit);
506 if (d > 0.0)
507 {
508 hits.push_back(hit);
509 //return true;
510 }
511 }
512
513 hits.sort();
514 return !hits.empty();
515 //return false;
516 }
517
518 bool Scene::checkForCollision(Character& character)
519 {
520 return false;
521
522 std::list< boost::shared_ptr<impl::Quad> >& objects = impl_->mObjects;
523 std::list< boost::shared_ptr<impl::Quad> >::const_iterator it;
524
525 int collisions = 0;
526 moof::sphere<3> sphere = character.sphere();
527
528 for (it = objects.begin(); it != objects.end(); ++it)
529 {
530 impl::Quad::Surface type = (*it)->getSurface();
531 if (type == impl::Quad::NONE) continue;
532
533 if (moof::checkCollision(sphere, (*it)->sphere()))
534 {
535 ++collisions;
536
537 moof::vector2 impulse(0.0, 0.0);
538 moof::vector2 p = character.state().momentum;
539
540 moof::state2 state = character.state(1.0);
541 sphere = character.sphere();
542 moof::scalar alpha = 1.0;
543 while (moof::checkCollision(sphere, (*it)->sphere()))
544 {
545 alpha -= 0.05;
546 state = character.state(alpha);
547 }
548
549 character.setPosition(state.position);
550
551 //switch (type)
552 //{
553 //case impl::Quad::TOP:
554 //if (p[1] < 0.0) impulse[1] = -p[1];
555 //break;
556 //case impl::Quad::LEFT:
557 //if (p[0] > 0.0) impulse[0] = 1.5*-p[0];
558 //break;
559 //case impl::Quad::RIGHT:
560 //if (p[0] < 0.0) impulse[0] = 1.5*-p[0];
561 //break;
562 //}
563
564 //character.addImpulse(impulse);
565 }
566 }
567
568 if (collisions > 0)
569 {
570 moof::log_info << "collisions: " << collisions << std::endl;
571 }
572
573 return false;
574 }
575
576
577 bool Scene::find_path(std::string& name)
578 {
579 return moof::resource::find_path(name, "scenes/", "lua");
580 }
581
This page took 0.052434 seconds and 3 git commands to generate.