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