]> Dogcows Code - chaz/yoink/blob - src/Scene.cc
cade lab fixes
[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
31 #include <Moof/Aabb.hh>
32 #include <Moof/Camera.hh>
33 #include <Moof/Entity.hh>
34 #include <Moof/Library.hh>
35 #include <Moof/Line.hh>
36 #include <Moof/Log.hh>
37 #include <Moof/Math.hh>
38 //#include <Moof/Octree.hh>
39 #include <Moof/Script.hh>
40 #include <Moof/Settings.hh>
41
42 #include "Character.hh"
43 #include "Scene.hh"
44 #include "Tilemap.hh"
45
46
47 struct Scene::Impl : public Mf::Library<Impl>
48 {
49 struct Quad : public Mf::Entity
50 {
51 enum Surface
52 {
53 NONE = 0,
54 LEFT = 1,
55 RIGHT = 2,
56 TOP = 3
57 };
58
59 Quad(const Mf::Vector3* vertices[4], const std::string& texture,
60 Tilemap::Index tileIndex) :
61 mTilemap(texture),
62 mBlending(false),
63 mFog(false),
64 mSurface(NONE)
65 {
66 for (int i = 0; i < 4; ++i)
67 {
68 mVertices[i] = *vertices[i];
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 " << tileIndex <<
78 " in texture " << texture << std::endl;
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(mVertices, 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[0].data());
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::Vector3 mVertices[4];
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 std::list< Mf::Line<2> > mLines;
161
162 Mf::Aabb<3> mBounds;
163
164
165 enum AXIS
166 {
167 X = 0,
168 Y = 1,
169 Z = 2
170 };
171
172
173 explicit Impl(const std::string& name) :
174 Mf::Library<Impl>(name) {}
175
176 void importSceneBindings(Mf::Script& script)
177 {
178 script.importFunction("SetBounds",
179 boost::bind(&Impl::setBounds, this, _1));
180 script.importFunction("ResetTransform",
181 boost::bind(&Impl::resetTransform, this, _1));
182 script.importFunction("Translate",
183 boost::bind(&Impl::translate, this, _1));
184 script.importFunction("Scale",
185 boost::bind(&Impl::scale, this, _1));
186 script.importFunction("Rotate",
187 boost::bind(&Impl::rotate, this, _1));
188 script.importFunction("SetTexture",
189 boost::bind(&Impl::setTexture, this, _1));
190 script.importFunction("DrawTilemap",
191 boost::bind(&Impl::drawTilemap, this, _1));
192 script.importFunction("DrawTile",
193 boost::bind(&Impl::drawTile, this, _1));
194
195 int detail = 3;
196 Mf::settings.get("detail", detail);
197 script.push(detail); script.set("detail");
198
199 script.push(1); script.set("LOW");
200 script.push(2); script.set("MEDIUM");
201 script.push(3); script.set("HIGH");
202
203 script.push(X); script.set("X");
204 script.push(Y); script.set("Y");
205 script.push(Z); script.set("Z");
206
207 script.push(Quad::LEFT); script.set("LEFT");
208 script.push(Quad::RIGHT); script.set("RIGHT");
209 script.push(Quad::TOP); script.set("TOP");
210 }
211
212
213 Mf::Script::Result load(Mf::Script& script)
214 {
215 std::string filePath = Scene::getPath(getName());
216 if (filePath == "")
217 {
218 script.push("the scene file could not be found");
219 return Mf::Script::FILE_ERROR;
220 }
221
222 importSceneBindings(script);
223 return script.doFile(filePath);
224 }
225
226
227 static int loadBox(Mf::Script& script, Mf::Aabb<3>& aabb)
228 {
229 script[1].requireTable();
230 script[2].requireTable();
231 script.setSize(2);
232
233 for (int i = 1; i <= 2; ++i)
234 {
235 for (int j = 1; j <= 3; ++j)
236 {
237 script[i].pushField(j);
238 }
239 }
240
241 script[3].get(aabb.min[0]);
242 script[4].get(aabb.min[1]);
243 script[5].get(aabb.min[2]);
244 script[6].get(aabb.max[0]);
245 script[7].get(aabb.max[1]);
246 script[8].get(aabb.max[2]);
247
248 return 0;
249 }
250
251 int setBounds(Mf::Script& script)
252 {
253 int ret = loadBox(script, mBounds);
254 //mOctree = Mf::Octree<Quad>::alloc(mBounds);
255 return ret;
256 }
257
258 int resetTransform(Mf::Script& script)
259 {
260 mTransform.identity();
261 return 0;
262 }
263
264 int translate(Mf::Script& script)
265 {
266 Mf::Vector3 vec;
267
268 script[1].requireNumber().get(vec[0]);
269 script[2].requireNumber().get(vec[1]);
270 script[3].requireNumber().get(vec[2]);
271
272 Mf::Matrix4 translation;
273 cml::matrix_translation(translation, vec);
274 mTransform = translation * mTransform;
275
276 return 0;
277 }
278
279 int scale(Mf::Script& script)
280 {
281 if (script.getSize() == 3)
282 {
283 Mf::Vector3 vec;
284 script[1].requireNumber().get(vec[0]);
285 script[2].requireNumber().get(vec[1]);
286 script[3].requireNumber().get(vec[2]);
287
288 Mf::Matrix4 scaling;
289 cml::matrix_scale(scaling, vec);
290 mTransform = scaling * mTransform;
291 }
292 else if (script.getSize() == 1)
293 {
294 Mf::Scalar value = 1.0;
295 script[1].requireNumber().get(value);
296
297 Mf::Matrix4 scaling;
298 cml::matrix_uniform_scale(scaling, value);
299 mTransform = scaling * mTransform;
300 }
301 else
302 {
303 script.getTop().throwError("wrong number of arguments");
304 }
305
306 return 0;
307 }
308
309 int rotate(Mf::Script& script)
310 {
311 size_t index = 0;
312 script[1].requireNumber().get(index);
313
314 Mf::Scalar value;
315 script[2].requireNumber().get(value);
316
317 cml::matrix_rotate_about_world_axis(mTransform, index, cml::rad(value));
318
319 return 0;
320 }
321
322 int setTexture(Mf::Script& script)
323 {
324 script[1].requireString().get(mTexture);
325 return 0;
326 }
327
328 int drawTilemap(Mf::Script& script)
329 {
330 Mf::Script::Slot table = script[1].requireTable();
331 Mf::Script::Slot top = script[-1];
332
333 int width = 1;
334 int height = 1;
335 int nTiles = 0;
336
337 table.pushField("width");
338 top.get(width);
339 script.pop();
340
341 nTiles = table.getLength();
342 if (nTiles % width != 0) table.throwError("invalid number of tiles");
343
344 if (width == 0) table.throwError("width field must not be zero");
345 height = nTiles / width;
346
347 Mf::Vector3 vertices[height+1][width+1];
348
349 // the indices are stored upside-down in the scene file so that they are
350 // easier to edit as text, so we'll need to load them last row first
351
352 // do first row and first column of vertices
353
354 for (int w = 0; w <= width; ++w)
355 {
356 vertices[height][w] = Mf::demote(mTransform *
357 Mf::Vector4(w, height, 0.0, 1.0));
358 }
359 for (int h = 0; h < height; ++h)
360 {
361 vertices[h][0] = Mf::demote(mTransform *
362 Mf::Vector4(0.0, h, 0.0, 1.0));
363 }
364
365 size_t i = 1;
366 for (int h = height - 1; h >= 0; --h)
367 {
368 for (int w = 0; w < width; ++w, ++i)
369 {
370 int wPlus1 = w + 1;
371 int hPlus1 = h + 1;
372
373 table.pushField(i);
374
375 Tilemap::Index index;
376 top.get(index);
377
378 script.pop();
379
380 vertices[h][wPlus1] = Mf::demote(mTransform *
381 Mf::Vector4(wPlus1, h, 0.0, 1.0));
382
383 if (index == Tilemap::NO_TILE) continue;
384
385 const Mf::Vector3* corners[4] = {
386 &vertices[h][w],
387 &vertices[h][wPlus1],
388 &vertices[hPlus1][wPlus1],
389 &vertices[hPlus1][w]
390 };
391
392 Quad* quad = new Quad(corners, mTexture, index);
393 //quad->setSurface(surface);
394
395 boost::shared_ptr<Quad> quadPtr(quad);
396 mObjects.push_back(quadPtr);
397 }
398 }
399
400 Quad::Surface surface = Quad::NONE;
401
402 table.pushField("surface");
403 top.get(surface);
404 script.pop();
405
406 if (surface != Quad::NONE)
407 {
408 // need a 2d line for collisions
409 // assuming the camera always looks directly to -z when the
410 // scene is built, simply demoting the vector again should
411 // project the points to the xy-plane
412
413 Mf::Vector2 bl = Mf::demote(vertices[0][0]);
414 Mf::Vector2 tr = Mf::demote(vertices[height][width]);
415
416 mLines.push_back(Mf::Line<2>(bl, tr));
417 Mf::logInfo("new line");
418 }
419
420 return 0;
421 }
422
423 int drawTile(Mf::Script& script)
424 {
425 Mf::Script::Slot param = script[1];
426 Mf::Script::Slot top = script[-1];
427
428 Tilemap::Index index = 0;
429 int width = 1;
430 bool blending = false;
431 bool fog = false;
432
433 if (param.isTable())
434 {
435 script.push(1);
436 param.pushField();
437 top.get(index);
438
439 param.pushField("u_scale");
440 top.get(width);
441
442 param.pushField("blend");
443 top.get(blending);
444
445 param.pushField("fog");
446 top.get(fog);
447 }
448 else if (param.isNumber())
449 {
450 param.get(index);
451 }
452
453 Mf::Vector3 vertices[2][width+1];
454
455 Mf::Scalar xf;
456 Mf::Scalar increment = 1.0 / Mf::Scalar(width);
457
458 for (int h = 0; h <= 1; ++h)
459 {
460 xf = 0.0;
461 for (int w = 0; w <= width; ++w, xf += increment)
462 {
463 vertices[h][w] = Mf::demote(mTransform *
464 Mf::Vector4(xf, Mf::Scalar(h), 0.0, 1.0));
465 }
466 }
467
468 for (int w = 0; w < width; ++w)
469 {
470 int wPlus1 = w + 1;
471
472 const Mf::Vector3* corners[4] = {
473 &vertices[0][w],
474 &vertices[0][wPlus1],
475 &vertices[1][wPlus1],
476 &vertices[1][w]
477 };
478
479 Quad* quad = new Quad(corners, mTexture, index);
480 quad->setBlending(blending);
481 quad->setFog(fog);
482
483 boost::shared_ptr<Quad> quadPtr(quad);
484 mObjects.push_back(quadPtr);
485 }
486
487 return 0;
488 }
489 };
490
491
492 Scene::Scene(const std::string& name) :
493 // pass through
494 mImpl(Scene::Impl::getInstance(name)) {}
495
496
497 Mf::Script::Result Scene::load(Mf::Script& script)
498 {
499 // pass through
500 return mImpl->load(script);
501 }
502
503
504 void Scene::draw(Mf::Scalar alpha) const
505 {
506 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
507 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
508
509 for (it = objects.begin(); it != objects.end(); ++it)
510 {
511 (*it)->draw(alpha);
512 }
513
514 mImpl->mBounds.draw();
515 }
516
517 void Scene::drawIfVisible(Mf::Scalar alpha, const Mf::Frustum& frustum) const
518 {
519 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
520 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
521
522 for (it = objects.begin(); it != objects.end(); ++it)
523 {
524 (*it)->drawIfVisible(alpha, frustum);
525 }
526
527 std::list< Mf::Line<2> >& lines = mImpl->mLines;
528 std::list< Mf::Line<2> >::const_iterator lit;
529
530 for (lit = lines.begin(); lit != lines.end(); ++lit)
531 {
532 (*lit).draw(alpha);
533 }
534
535 mImpl->mBounds.draw();
536 }
537
538
539 bool Scene::castRay(const Mf::Ray<2>& ray,
540 std::list<Mf::Ray<2>::Intersection>& hits) const
541 {
542 std::list< Mf::Line<2> >& lines = mImpl->mLines;
543 std::list< Mf::Line<2> >::const_iterator it;
544
545 for (it = lines.begin(); it != lines.end(); ++it)
546 {
547 Mf::Ray<2>::Intersection hit;
548 Mf::Scalar d = (*it).intersectRay(ray, hit);
549 if (d > 0.0)
550 {
551 hits.push_back(hit);
552 //return true;
553 }
554 }
555
556 hits.sort();
557 return !hits.empty();
558 //return false;
559 }
560
561 bool Scene::checkForCollision(Character& character)
562 {
563 return false;
564 //std::list< boost::shared_ptr<Impl::Quad> > objects;
565 //std::list<Mf::Octree<Impl::Quad>::InsertableP> objects;
566 //mImpl->mOctree->getNearbyObjects(objects, character);
567
568 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
569 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
570
571 int collisions = 0;
572 Mf::Sphere<3> sphere = character.getSphere();
573
574 for (it = objects.begin(); it != objects.end(); ++it)
575 {
576 Impl::Quad::Surface type = (*it)->getSurface();
577 if (type == Impl::Quad::NONE) continue;
578
579 if (Mf::checkCollision(sphere, (*it)->getSphere()))
580 {
581 ++collisions;
582
583 Mf::Vector2 impulse(0.0, 0.0);
584 Mf::Vector2 p = character.getState().momentum;
585
586 Mf::State2 state = character.getState(1.0);
587 sphere = character.getSphere();
588 Mf::Scalar alpha = 1.0;
589 while (Mf::checkCollision(sphere, (*it)->getSphere()))
590 {
591 alpha -= 0.05;
592 state = character.getState(alpha);
593 }
594
595 character.setPosition(state.position);
596
597 //switch (type)
598 //{
599 //case Impl::Quad::TOP:
600 //if (p[1] < 0.0) impulse[1] = -p[1];
601 //break;
602 //case Impl::Quad::LEFT:
603 //if (p[0] > 0.0) impulse[0] = 1.5*-p[0];
604 //break;
605 //case Impl::Quad::RIGHT:
606 //if (p[0] < 0.0) impulse[0] = 1.5*-p[0];
607 //break;
608 //}
609
610 //character.addImpulse(impulse);
611 }
612 }
613
614 if (collisions > 0)
615 {
616 Mf::logInfo << "collisions: " << collisions << std::endl;
617 }
618
619 return false;
620 }
621
622
623 std::string Scene::getPath(const std::string& name)
624 {
625 return Mf::Resource::getPath("scenes/" + name + ".lua");
626 }
627
628
629 /** vim: set ts=4 sw=4 tw=80: *************************************************/
630
This page took 0.056836 seconds and 4 git commands to generate.