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