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