]> Dogcows Code - chaz/yoink/blob - src/Scene.cc
sockets documentation and cleanup
[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.globals().setField("detail", detail);
181
182 script.globals().setField("LOW", 1);
183 script.globals().setField("MEDIUM", 2);
184 script.globals().setField("HIGH", 3);
185
186 script.globals().setField("X", X);
187 script.globals().setField("Y", Y);
188 script.globals().setField("Z", Z);
189
190 script.globals().setField("LEFT", Quad::LEFT);
191 script.globals().setField("RIGHT", Quad::RIGHT);
192 script.globals().setField("TOP", Quad::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::Aabb3& aabb)
211 {
212 script[1].requireTable();
213 script[2].requireTable();
214
215 script[1].pushField(1).get(aabb.min[0]);
216 script[1].pushField(2).get(aabb.min[1]);
217 script[1].pushField(3).get(aabb.min[2]);
218 script[2].pushField(1).get(aabb.max[0]);
219 script[2].pushField(2).get(aabb.max[1]);
220 script[2].pushField(3).get(aabb.max[2]);
221
222 return 0;
223 }
224
225 int setBounds(Mf::Script& script)
226 {
227 int ret = loadBox(script, mBounds);
228 //mOctree = Mf::Octree<Quad>::alloc(mBounds);
229 return ret;
230 }
231
232 int resetTransform(Mf::Script& script)
233 {
234 mTransform.identity();
235 return 0;
236 }
237
238 int translate(Mf::Script& script)
239 {
240 Mf::Vector3 vec;
241 script[1].requireNumber().get(vec[0]);
242 script[2].requireNumber().get(vec[1]);
243 script[3].requireNumber().get(vec[2]);
244
245 Mf::Matrix4 translation;
246 cml::matrix_translation(translation, vec);
247 mTransform = translation * mTransform;
248
249 return 0;
250 }
251
252 int scale(Mf::Script& script)
253 {
254 int size = script.stackSize();
255
256 if (size == 1)
257 {
258 Mf::Scalar value = 1.0;
259 script[1].requireNumber().get(value);
260
261 Mf::Matrix4 scaling;
262 cml::matrix_uniform_scale(scaling, value);
263 mTransform = scaling * mTransform;
264 }
265 else if (size == 3)
266 {
267 Mf::Vector3 vec;
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 scaling;
273 cml::matrix_scale(scaling, vec);
274 mTransform = scaling * mTransform;
275 }
276 else
277 {
278 script.top().raise("wrong number of arguments");
279 }
280
281 return 0;
282 }
283
284 int rotate(Mf::Script& script)
285 {
286 size_t index = 0;
287 script[1].requireNumber().get(index);
288
289 Mf::Scalar value;
290 script[2].requireNumber().get(value);
291
292 cml::matrix_rotate_about_world_axis(mTransform,
293 index, cml::rad(value));
294
295 return 0;
296 }
297
298 int setTexture(Mf::Script& script)
299 {
300 script[1].requireString().get(mTexture);
301 return 0;
302 }
303
304 int drawTilemap(Mf::Script& script)
305 {
306 Mf::Script::Slot table = script[1].requireTable();
307
308 int width = 1;
309 table.get(width, "width");
310
311 int nTiles = table.length();
312 if (nTiles % width != 0)
313 {
314 table.raise("invalid number of tiles");
315 }
316
317 if (width == 0) table.raise("width field must not be zero");
318 int height = nTiles / width;
319
320 Mf::Vector3 vertices[height+1][width+1];
321
322 // the indices are stored upside-down in the scene file so that
323 // they are easier to edit as text, so we'll need to load them last
324 // row first
325
326 // do first row and first column of vertices
327
328 for (int w = 0; w <= width; ++w)
329 {
330 vertices[height][w] = Mf::demote(mTransform *
331 Mf::Vector4(w, height, 0.0, 1.0));
332 }
333 for (int h = 0; h < height; ++h)
334 {
335 vertices[h][0] = Mf::demote(mTransform *
336 Mf::Vector4(0.0, h, 0.0, 1.0));
337 }
338
339 size_t i = 1;
340 for (int h = height - 1; h >= 0; --h)
341 {
342 for (int w = 0; w < width; ++w, ++i)
343 {
344 int wPlus1 = w + 1;
345 int hPlus1 = h + 1;
346
347 Mf::Texture::TileIndex index;
348 table.get(index, i);
349
350 vertices[h][wPlus1] = Mf::demote(mTransform *
351 Mf::Vector4(wPlus1, h, 0.0, 1.0));
352
353 if (index == Mf::Texture::NO_TILE) continue;
354
355 const Mf::Vector3* corners[4] = {
356 &vertices[h][w],
357 &vertices[h][wPlus1],
358 &vertices[hPlus1][wPlus1],
359 &vertices[hPlus1][w]
360 };
361
362 Quad* quad = new Quad(corners, mTexture, index);
363 //quad->setSurface(surface);
364
365 boost::shared_ptr<Quad> quadPtr(quad);
366 mObjects.push_back(quadPtr);
367 }
368 }
369
370 Quad::Surface surface = Quad::NONE;
371 table.get(surface, "surface");
372
373 if (surface != Quad::NONE)
374 {
375 // need a 2d line for collisions
376 // assuming the camera always looks directly to -z when the
377 // scene is built, simply demoting the vector again should
378 // project the points to the xy-plane
379
380 Mf::Vector2 bl = Mf::demote(vertices[0][0]);
381 Mf::Vector2 tr = Mf::demote(vertices[height][width]);
382
383 mLines.push_back(Mf::Line<2>(bl, tr));
384 }
385
386 return 0;
387 }
388
389 int drawTile(Mf::Script& script)
390 {
391 Mf::Script::Slot param = script[1];
392 Mf::Script::Slot top = script[-1];
393
394 Mf::Texture::TileIndex index = 0;
395 int width = 1;
396 bool blending = false;
397 bool fog = false;
398
399 if (param.isTable())
400 {
401 param.get(index, 1);
402 param.get(width, "u_scale");
403 param.get(blending, "blend");
404 param.get(fog, "fog");
405 }
406 else if (param.isNumber())
407 {
408 param.get(index);
409 }
410
411 Mf::Vector3 vertices[2][width+1];
412
413 Mf::Scalar xf;
414 Mf::Scalar increment = SCALAR(1.0) / Mf::Scalar(width);
415
416 for (int h = 0; h <= 1; ++h)
417 {
418 xf = 0.0;
419 for (int w = 0; w <= width; ++w, xf += increment)
420 {
421 vertices[h][w] = Mf::demote(mTransform *
422 Mf::Vector4(xf, Mf::Scalar(h), 0.0, 1.0));
423 }
424 }
425
426 for (int w = 0; w < width; ++w)
427 {
428 int wPlus1 = w + 1;
429
430 const Mf::Vector3* corners[4] = {
431 &vertices[0][w],
432 &vertices[0][wPlus1],
433 &vertices[1][wPlus1],
434 &vertices[1][w]
435 };
436
437 Quad* quad = new Quad(corners, mTexture, index);
438 quad->setBlending(blending);
439 quad->setFog(fog);
440
441 boost::shared_ptr<Quad> quadPtr(quad);
442 mObjects.push_back(quadPtr);
443 }
444
445 return 0;
446 }
447 };
448
449
450 Scene::Scene(const std::string& name) :
451 // pass through
452 mImpl(Scene::Impl::getInstance(name)) {}
453
454
455 Mf::Script::Result Scene::load(Mf::Settings& settings, Mf::Script& script)
456 {
457 // pass through
458 return mImpl->load(settings, script);
459 }
460
461
462 void Scene::draw(Mf::Scalar alpha) const
463 {
464 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
465 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
466
467 for (it = objects.begin(); it != objects.end(); ++it)
468 {
469 (*it)->draw(alpha);
470 }
471
472 mImpl->mBounds.draw();
473 }
474
475 void Scene::drawIfVisible(Mf::Scalar alpha,
476 const Mf::Frustum& frustum) const
477 {
478 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
479 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
480
481 for (it = objects.begin(); it != objects.end(); ++it)
482 {
483 (*it)->drawIfVisible(alpha, frustum);
484 }
485
486 std::list< Mf::Line<2> >& lines = mImpl->mLines;
487 std::list< Mf::Line<2> >::const_iterator lit;
488
489 for (lit = lines.begin(); lit != lines.end(); ++lit)
490 {
491 (*lit).draw(alpha);
492 }
493
494 mImpl->mBounds.draw();
495 }
496
497
498 bool Scene::castRay(const Mf::Ray<2>& ray,
499 std::list<Mf::Ray<2>::Contact>& hits) const
500 {
501 std::list< Mf::Line<2> >& lines = mImpl->mLines;
502 std::list< Mf::Line<2> >::const_iterator it;
503
504 for (it = lines.begin(); it != lines.end(); ++it)
505 {
506 Mf::Ray<2>::Contact hit;
507 Mf::Scalar d = (*it).intersectRay(ray, hit);
508 if (d > 0.0)
509 {
510 hits.push_back(hit);
511 //return true;
512 }
513 }
514
515 hits.sort();
516 return !hits.empty();
517 //return false;
518 }
519
520 bool Scene::checkForCollision(Character& character)
521 {
522 return false;
523 //std::list< boost::shared_ptr<Impl::Quad> > objects;
524 //std::list<Mf::Octree<Impl::Quad>::InsertableP> objects;
525 //mImpl->mOctree->getNearbyObjects(objects, character);
526
527 std::list< boost::shared_ptr<Impl::Quad> >& objects = mImpl->mObjects;
528 std::list< boost::shared_ptr<Impl::Quad> >::const_iterator it;
529
530 int collisions = 0;
531 Mf::Sphere<3> sphere = character.getSphere();
532
533 for (it = objects.begin(); it != objects.end(); ++it)
534 {
535 Impl::Quad::Surface type = (*it)->getSurface();
536 if (type == Impl::Quad::NONE) continue;
537
538 if (Mf::checkCollision(sphere, (*it)->getSphere()))
539 {
540 ++collisions;
541
542 Mf::Vector2 impulse(0.0, 0.0);
543 Mf::Vector2 p = character.getState().momentum;
544
545 Mf::State2 state = character.getState(1.0);
546 sphere = character.getSphere();
547 Mf::Scalar alpha = 1.0;
548 while (Mf::checkCollision(sphere, (*it)->getSphere()))
549 {
550 alpha -= 0.05;
551 state = character.getState(alpha);
552 }
553
554 character.setPosition(state.position);
555
556 //switch (type)
557 //{
558 //case Impl::Quad::TOP:
559 //if (p[1] < 0.0) impulse[1] = -p[1];
560 //break;
561 //case Impl::Quad::LEFT:
562 //if (p[0] > 0.0) impulse[0] = 1.5*-p[0];
563 //break;
564 //case Impl::Quad::RIGHT:
565 //if (p[0] < 0.0) impulse[0] = 1.5*-p[0];
566 //break;
567 //}
568
569 //character.addImpulse(impulse);
570 }
571 }
572
573 if (collisions > 0)
574 {
575 Mf::logInfo << "collisions: " << collisions << std::endl;
576 }
577
578 return false;
579 }
580
581
582 bool Scene::getPath(std::string& name)
583 {
584 return Mf::Resource::getPath(name, "scenes/", "lua");
585 }
586
This page took 0.055771 seconds and 4 git commands to generate.