big batch of changes
[chaz/yoink] / src / Scene.cc
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 *******************************************************************************/
28
29 #include <map>
30 #include <vector>
31
32 #include <Moof/Aabb.hh>
33 #include <Moof/Camera.hh>
34 #include <Moof/Entity.hh>
35 #include <Moof/Exception.hh>
36 #include <Moof/Library.hh>
37 #include <Moof/Log.hh>
38 #include <Moof/Math.hh>
39 //#include <Moof/Octree.hh>
40 #include <Moof/Script.hh>
41 #include <Moof/Settings.hh>
42
43 #include "Character.hh"
44 #include "Scene.hh"
45 #include "Tilemap.hh"
46
47
48 struct Scene::Impl : public Mf::Library<Impl>
49 {
50 struct Quad : public Mf::Entity
51 {
52 enum SURFACE
53 {
54 NONE = 0,
55 LEFT = 1,
56 RIGHT = 2,
57 TOP = 3
58 };
59
60 Quad(const Mf::Vector3 vertices[4], const std::string& texture,
61 Tilemap::Index tileIndex) :
62 mTilemap(texture),
63 mBlending(false),
64 mFog(false),
65 mSurface(NONE)
66 {
67 for (int i = 0, num = 0; i < 4; ++i)
68 {
69 for (int j = 0; j < 3; ++j, ++num)
70 {
71 mVertices[num] = vertices[i][j];
72 }
73 }
74
75 if (!mTilemap.getTileCoords(tileIndex, mTexCoords))
76 {
77 Mf::logWarning("no index %d in texture %s", tileIndex,
78 texture.c_str());
79
80 mTexCoords[0] = mTexCoords[1] =
81 mTexCoords[3] = mTexCoords[6] = 0.0;
82 mTexCoords[2] = mTexCoords[4] =
83 mTexCoords[5] = mTexCoords[7] = 1.0;
84 }
85
86 mAabb.encloseVertices(vertices, 4);
87 mSphere.point = mAabb.getCenter();
88 mSphere.radius = (mAabb.min - mSphere.point).length();
89 }
90
91 void setBlending(bool blending)
92 {
93 mBlending = blending;
94 }
95
96 void setFog(bool fog)
97 {
98 mFog = fog;
99 }
100
101 void setSurface(SURFACE type)
102 {
103 mSurface = type;
104 }
105
106 SURFACE getSurface() const
107 {
108 return mSurface;
109 }
110
111 void draw(Mf::Scalar alpha = 0.0) const
112 {
113 if (mBlending)
114 {
115 glEnable(GL_BLEND);
116 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
117 }
118
119 if (mFog)
120 {
121 glEnable(GL_FOG);
122 glFogi(GL_FOG_MODE, GL_LINEAR);
123 }
124
125 //glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
126 mTilemap.bind();
127
128 glVertexPointer(3, GL_SCALAR, 0, mVertices);
129 glTexCoordPointer(2, GL_SCALAR, 0, mTexCoords);
130
131 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
132
133 glDisable(GL_BLEND);
134 glDisable(GL_FOG);
135 }
136
137 bool isVisible(const Mf::Frustum& frustum) const
138 {
139 return mSphere.isVisible(frustum);
140 }
141
142
143 Mf::Scalar mVertices[12];
144 Mf::Scalar mTexCoords[8];
145
146 Tilemap mTilemap;
147
148 bool mBlending;
149 bool mFog;
150 SURFACE mSurface;
151 };
152
153
154
155 Mf::Matrix4 mTransform;
156 std::string mTexture;
157
158 //Mf::Octree<Quad>::Ptr mOctree;
159 std::list< boost::shared_ptr<Impl::Quad> > mObjects;
160
161 Mf::Aabb mBounds;
162
163
164 enum AXIS
165 {
166 X = 0,
167 Y = 1,
168 Z = 2
169 };
170
171
172 explicit Impl(const std::string& name) :
173 Mf::Library<Impl>(name) {}
174
175 void importSceneBindings(Mf::Script& script)
176 {
177 script.importFunction("SetBounds",
178 boost::bind(&Impl::setBounds, this, _1));
179 script.importFunction("ResetTransform",
180 boost::bind(&Impl::resetTransform, this, _1));
181 script.importFunction("Translate",
182 boost::bind(&Impl::translate, this, _1));
183 script.importFunction("Scale",
184 boost::bind(&Impl::scale, this, _1));
185 script.importFunction("Rotate",
186 boost::bind(&Impl::rotate, this, _1));
187 script.importFunction("SetTexture",
188 boost::bind(&Impl::setTexture, this, _1));
189 script.importFunction("DrawTilemap",
190 boost::bind(&Impl::drawTilemap, this, _1));
191 script.importFunction("DrawTile",
192 boost::bind(&Impl::drawTile, this, _1));
193
194 int detail = 3;
195 Mf::Settings::getInstance().get("detail", detail);
196 script.push(detail); script.set("detail");
197
198 script.push(1); script.set("LOW");
199 script.push(2); script.set("MEDIUM");
200 script.push(3); script.set("HIGH");
201
202 script.push(X); script.set("X");
203 script.push(Y); script.set("Y");
204 script.push(Z); script.set("Z");
205
206 script.push(Quad::LEFT); script.set("LEFT");
207 script.push(Quad::RIGHT); script.set("RIGHT");
208 script.push(Quad::TOP); script.set("TOP");
209 }
210
211
212 Mf::Script::Status load(Mf::Script& script)
213 {
214 std::string filePath = Scene::getPath(getName());
215 if (filePath == "") return Mf::Script::FILE_ERROR;
216
217 importSceneBindings(script);
218 return script.doFile(filePath);
219 }
220
221
222 static int loadBox(Mf::Script& script, Mf::Aabb& aabb)
223 {
224 Mf::Script::Value table[] =
225 {
226 script[1].requireTable(),
227 script[2].requireTable()
228 };
229
230 for (int i = 0; i <= 1; ++i)
231 {
232 for (int j = 1; j <= 3; ++j)
233 {
234 script.push(j);
235 table[i].pushField();
236 }
237 }
238
239 script[3].get(aabb.min[0]);
240 script[4].get(aabb.min[1]);
241 script[5].get(aabb.min[2]);
242 script[6].get(aabb.max[0]);
243 script[7].get(aabb.max[1]);
244 script[8].get(aabb.max[2]);
245
246 return 0;
247 }
248
249 int setBounds(Mf::Script& script)
250 {
251 int ret = loadBox(script, mBounds);
252 //mOctree = Mf::Octree<Quad>::alloc(mBounds);
253 return ret;
254 }
255
256 int resetTransform(Mf::Script& script)
257 {
258 mTransform.identity();
259 return 0;
260 }
261
262 int translate(Mf::Script& script)
263 {
264 Mf::Script::Value x = script[1].requireNumber();
265 Mf::Script::Value y = script[2].requireNumber();
266 Mf::Script::Value z = script[3].requireNumber();
267
268 Mf::Vector3 vec;
269 x.get(vec[0]);
270 y.get(vec[1]);
271 z.get(vec[2]);
272
273 Mf::Matrix4 translation;
274 cml::matrix_translation(translation, vec);
275 mTransform = translation * mTransform;
276
277 return 0;
278 }
279
280 int scale(Mf::Script& script)
281 {
282 if (script.getSize() == 3)
283 {
284 Mf::Vector3 vec;
285 script[1].requireNumber().get(vec[0]);
286 script[2].requireNumber().get(vec[1]);
287 script[3].requireNumber().get(vec[2]);
288
289 Mf::Matrix4 scaling;
290 cml::matrix_scale(scaling, vec);
291 mTransform = scaling * mTransform;
292 }
293 else if (script.getSize() == 1)
294 {
295 Mf::Scalar value = 1.0;
296 script[1].requireNumber().get(value);
297
298 Mf::Matrix4 scaling;
299 cml::matrix_uniform_scale(scaling, value);
300 mTransform = scaling * mTransform;
301 }
302 else
303 {
304 script.getTop().throwError("wrong number of arguments");
305 }
306
307 return 0;
308 }
309
310 int rotate(Mf::Script& script)
311 {
312 Mf::Script::Value axis = script[1].requireNumber();
313 Mf::Script::Value angle = script[2].requireNumber();
314
315 size_t index = 0;
316 axis.get(index);
317
318 Mf::Scalar value;
319 angle.get(value);
320
321 cml::matrix_rotate_about_world_axis(mTransform, index, cml::rad(value));
322
323 return 0;
324 }
325
326 int setTexture(Mf::Script& script)
327 {
328 script[1].requireString().get(mTexture);
329 return 0;
330 }
331
332 int drawTilemap(Mf::Script& script)
333 {
334 Mf::Script::Value table = script[1].requireTable();
335 Mf::Script::Value top = script[-1];
336
337 Quad::SURFACE surface;
338 table.pushField("surface");
339 top.get(surface);
340 script.pop();
341
342 int width = 1;
343 int height = 1;
344
345 table.pushField("width");
346 top.get(width);
347 script.pop();
348
349 int nTiles = 0;
350
351 //table.pushField("tiles");
352 Mf::Script::Value tiles = script.getTop();
353 nTiles = tiles.getLength();
354
355 if (nTiles % width != 0) table.throwError("invalid number of tiles");
356
357 std::vector< std::vector<Tilemap::Index> > indices;
358
359 int i, w, h;
360
361 height = nTiles / width;
362 indices.resize(height);
363
364 // the indices are stored upside-down in the scene file so that they are
365 // easier to edit as text, so we'll need to load them last row first
366
367 i = 1;
368 for (h = height - 1; h >= 0; --h)
369 {
370 std::vector<Tilemap::Index> row;
371
372 for (w = 0; w < width; ++w, ++i)
373 {
374 script.checkStack(2);
375 script.push(i);
376 tiles.pushField();
377
378 Tilemap::Index index;
379 top.get(index);
380
381 row.push_back(index);
382 }
383
384 indices[h] = row;
385 }
386
387 Mf::Vector4 vertices[height+1][width+1];
388
389 Mf::Matrix4 transposedTransform = mTransform;
390 transposedTransform.transpose();
391
392 for (int h = 0; h <= height; ++h)
393 {
394 for (int w = 0; w <= width; ++w)
395 {
396 vertices[h][w] = Mf::Vector4(w, h, 0.0, 1.0) * transposedTransform;
397 }
398 }
399
400 for (int h = 0; h < height; ++h)
401 {
402 for (int w = 0; w < width; ++w)
403 {
404 if (indices[h][w] == Tilemap::NO_TILE) continue;
405
406 Mf::Vector3 demotedVertices[4];
407
408 demotedVertices[0] = Mf::demote(vertices[h][w]);
409 demotedVertices[1] = Mf::demote(vertices[h][w+1]);
410 demotedVertices[2] = Mf::demote(vertices[h+1][w+1]);
411 demotedVertices[3] = Mf::demote(vertices[h+1][w]);
412
413 Quad* quad = new Quad(demotedVertices, mTexture, indices[h][w]);
414 quad->setSurface(surface);
415
416 boost::shared_ptr<Quad> quadPtr(quad);
417 //mOctree->insert(quadPtr);
418 mObjects.push_back(quadPtr);
419 }
420 }
421
422 return 0;
423 }
424
425 int drawTile(Mf::Script& script)
426 {
427 Mf::Script::Value param = script[1];
428 Mf::Script::Value top = script[-1];
429
430 Tilemap::Index index = 0;
431 int width = 1;
432 bool blending = false;
433 bool fog = false;
434
435 if (param.isTable())
436 {
437 script.push(1);
438 param.pushField();
439 top.get(index);
440
441 param.pushField("u_scale");
442 top.get(width);
443
444 param.pushField("blend");
445 top.get(blending);
446
447 param.pushField("fog");
448 top.get(fog);
449 }
450 else if (param.isNumber())
451 {
452 param.get(index);
453 }
454
455 Mf::Vector4 vertices[2][width+1];
456
457 Mf::Matrix4 transposedTransform = mTransform;
458 transposedTransform.transpose();
459
460 Mf::Scalar xf;
461 Mf::Scalar increment = 1.0 / Mf::Scalar(width);
462
463 for (int h = 0; h <= 1; ++h)
464 {
465 xf = 0.0;
466 for (int w = 0; w <= width; ++w, xf += increment)
467 {
468 vertices[h][w] = Mf::Vector4(xf, Mf::Scalar(h), 0.0, 1.0) *
469 transposedTransform;
470 }
471 }
472
473 for (int w = 0; w < width; ++w)
474 {
475 Mf::Vector3 demotedVertices[4];
476
477 demotedVertices[0] = Mf::demote(vertices[0][w]);
478 demotedVertices[1] = Mf::demote(vertices[0][w+1]);
479 demotedVertices[2] = Mf::demote(vertices[1][w+1]);
480 demotedVertices[3] = Mf::demote(vertices[1][w]);
481
482 Quad* quad = new Quad(demotedVertices, mTexture, index);
483 quad->setBlending(blending);
484 quad->setFog(fog);
485
486 boost::shared_ptr<Quad> quadPtr(quad);
487 //mOctree->insert(quadPtr);
488 mObjects.push_back(quadPtr);
489 }
490
491 return 0;
492 }
493 };
494
495
496 Scene::Scene(const std::string& name) :
497 // pass through
498 mImpl(Scene::Impl::getInstance(name)) {}
499
500
501 Mf::Script::Status Scene::load(Mf::Script& script)
502 {
503 // pass through
504 return mImpl->load(script);
505 }
506
507
508 void Scene::draw(Mf::Scalar alpha) const
509 {
510 //mImpl->mOctree->draw(alpha);
511 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
512 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
513
514 for (it = objects.begin(); it != objects.end(); ++it)
515 {
516 (*it)->draw(alpha);
517 }
518
519 mImpl->mBounds.draw();
520 }
521
522 void Scene::drawIfVisible(Mf::Scalar alpha, const Mf::Frustum& frustum) const
523 {
524 //mImpl->mOctree->drawIfVisible(alpha, frustum);
525 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
526 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
527
528 for (it = objects.begin(); it != objects.end(); ++it)
529 {
530 (*it)->drawIfVisible(alpha, frustum);
531 }
532
533 mImpl->mBounds.draw();
534 }
535
536
537 bool Scene::checkForCollision(Character& character)
538 {
539 return false;
540 //std::list< boost::shared_ptr<Impl::Quad> > objects;
541 //std::list<Mf::Octree<Impl::Quad>::InsertableP> objects;
542 //mImpl->mOctree->getNearbyObjects(objects, character);
543
544 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
545 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
546
547 int collisions = 0;
548 Mf::Sphere sphere = character.getSphere();
549
550 for (it = objects.begin(); it != objects.end(); ++it)
551 {
552 Impl::Quad::SURFACE type = (*it)->getSurface();
553 if (type == Impl::Quad::NONE) continue;
554
555 if (Mf::checkCollision(sphere, (*it)->getSphere()))
556 {
557 ++collisions;
558
559 Mf::Vector2 impulse(0.0, 0.0);
560 Mf::Vector2 p = character.getState().momentum;
561
562 Mf::State2 state = character.getState(1.0);
563 sphere = character.getSphere();
564 Mf::Scalar alpha = 1.0;
565 while (Mf::checkCollision(sphere, (*it)->getSphere()))
566 {
567 alpha -= 0.05;
568 state = character.getState(alpha);
569 }
570
571 character.setPosition(state.position);
572
573 //switch (type)
574 //{
575 //case Impl::Quad::TOP:
576 //if (p[1] < 0.0) impulse[1] = -p[1];
577 //break;
578 //case Impl::Quad::LEFT:
579 //if (p[0] > 0.0) impulse[0] = 1.5*-p[0];
580 //break;
581 //case Impl::Quad::RIGHT:
582 //if (p[0] < 0.0) impulse[0] = 1.5*-p[0];
583 //break;
584 //}
585
586 //character.addImpulse(impulse);
587 }
588 }
589
590 if (collisions > 0)
591 {
592 Mf::logInfo("collisions: %d", collisions);
593 }
594
595 return false;
596 }
597
598
599 std::string Scene::getPath(const std::string& name)
600 {
601 return Mf::Resource::getPath("scenes/" + name + ".lua");
602 }
603
604
605 /** vim: set ts=4 sw=4 tw=80: *************************************************/
606
This page took 0.057338 seconds and 4 git commands to generate.