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