]> Dogcows Code - chaz/yoink/blob - src/Moof/Scene.cc
revamped scene drawing in preparation for octree
[chaz/yoink] / src / Moof / 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 <iostream>
30 #include <map>
31 #include <vector>
32
33 #include "Aabb.hh"
34 #include "Camera.hh"
35 #include "Deserializer.hh"
36 #include "Entity.hh"
37 #include "Math.hh"
38 #include "Mippleton.hh"
39 #include "Octree.hh"
40 #include "OpenGL.hh"
41 #include "Scene.hh"
42 #include "Serializable.hh"
43 #include "Tilemap.hh"
44
45
46 namespace Mf {
47
48
49 class Scene::SceneImpl : public Mippleton<SceneImpl>
50 {
51 class Quad : public Entity
52 {
53 public:
54 Quad(const Vector3 vertices[4], const std::string& texture,
55 Tilemap::Index tileIndex) :
56 tilemap_(texture),
57 detail_(0),
58 blending_(false),
59 fog_(false)
60 {
61 for (int i = 0, num = 0; i < 4; ++i)
62 {
63 for (int j = 0; j < 3; ++j, ++num)
64 {
65 vertices_[num] = vertices[i][j];
66 }
67 }
68
69 if (!tilemap_.getTileCoords(tileIndex, texCoords_))
70 {
71 std::cerr << "no coords for tile's texture" << std::endl;
72 }
73 }
74
75 void setDetail(long detail)
76 {
77 detail_ = detail;
78 }
79
80 void setBlending(bool blending)
81 {
82 blending_ = blending;
83 }
84
85 void setFog(bool fog)
86 {
87 fog_ = fog;
88 }
89
90 void draw(Scalar alpha = 0.0) const
91 {
92 if (blending_)
93 {
94 glEnable(GL_BLEND);
95 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
96 }
97
98 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
99 tilemap_.bind();
100
101 //glEnableClientState(GL_VERTEX_ARRAY);
102 //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
103
104 //glVertexPointer(3, GL_SCALAR, 0, vertices_);
105 //glTexCoordPointer(2, GL_SCALAR, 0, texCoords_);
106
107 //glDrawArrays(GL_TRIANGLE_FAN, 0, sizeof(vertices_));
108
109 //glDisableClientState(GL_VERTEX_ARRAY);
110 //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
111
112 glBegin(GL_TRIANGLE_FAN);
113 glTexCoord2f(texCoords_[0], texCoords_[1]);
114 glVertex3v(vertices_);
115 glTexCoord2f(texCoords_[2], texCoords_[3]);
116 glVertex3v(vertices_+3);
117 glTexCoord2f(texCoords_[4], texCoords_[5]);
118 glVertex3v(vertices_+6);
119 glTexCoord2f(texCoords_[6], texCoords_[7]);
120 glVertex3v(vertices_+9);
121 glEnd();
122
123 glDisable(GL_BLEND);
124 }
125
126 bool isVisible(const Camera& cam) const
127 {
128 return aabb_.isVisible(cam);
129 }
130
131 private:
132 Scalar vertices_[12];
133 Scalar texCoords_[8];
134
135 Tilemap tilemap_;
136
137 long detail_;
138 bool blending_;
139 bool fog_;
140 };
141
142
143 static void loadBox(Aabb& theBox, SerializablePtr obj)
144 {
145 std::vector<SerializablePtr> numbers;
146
147 if (obj->get(numbers) && numbers.size() == 6)
148 {
149 double num;
150
151 if (numbers[0]->getNumber(num)) theBox.min[0] = Scalar(num);
152 if (numbers[1]->getNumber(num)) theBox.min[1] = Scalar(num);
153 if (numbers[2]->getNumber(num)) theBox.min[2] = Scalar(num);
154 if (numbers[3]->getNumber(num)) theBox.max[0] = Scalar(num);
155 if (numbers[4]->getNumber(num)) theBox.max[1] = Scalar(num);
156 if (numbers[5]->getNumber(num)) theBox.max[2] = Scalar(num);
157 }
158 }
159
160 public:
161 SceneImpl(const std::string& name) :
162 Mippleton<SceneImpl>(name)
163 {
164 loadFromFile();
165 }
166
167
168 void loadInstructions(SerializablePtr root)
169 {
170 std::vector<SerializablePtr> rootObj;
171 std::vector<SerializablePtr>::iterator it;
172
173 if (!root->get(rootObj))
174 {
175 std::cerr << "error loading scene instructions" << std::endl;
176 return;
177 }
178
179 Matrix4 transform;
180 std::string texture;
181
182 for (it = rootObj.begin(); it != rootObj.end(); ++it)
183 {
184 std::string instruction;
185
186 if ((*it)->get(instruction))
187 {
188 if (instruction == "reset_transform")
189 {
190 transform.identity();
191 }
192 else if (instruction == "translate")
193 {
194 std::vector<SerializablePtr> values;
195
196 ++it;
197 if ((*it)->get(values))
198 {
199 Vector3 vec;
200
201 for (size_t i = 0; i < values.size(); ++i)
202 {
203 double value;
204
205 if (values[i]->getNumber(value))
206 {
207 vec[i] = value;
208 }
209 }
210
211 Matrix4 translation;
212 cml::matrix_translation(translation, vec);
213 transform = translation * transform;
214 }
215 }
216 else if (instruction == "scale")
217 {
218 std::vector<SerializablePtr> values;
219
220 ++it;
221 if ((*it)->get(values))
222 {
223 if (values.size() == 1)
224 {
225 double value = 1.0;
226
227 values[0]->getNumber(value);
228
229 Matrix4 scaling;
230 cml::matrix_uniform_scale(scaling,
231 Scalar(value));
232 transform = scaling * transform;
233 }
234 else if (values.size() == 3)
235 {
236 Vector3 vec;
237
238 for (size_t i = 0; i < values.size(); ++i)
239 {
240 double value;
241
242 if (values[i]->getNumber(value))
243 {
244 vec[i] = value;
245 }
246 }
247
248 Matrix4 scaling;
249 cml::matrix_scale(scaling, vec);
250 transform = scaling * transform;
251 }
252 }
253 }
254 else if (instruction == "rotate")
255 {
256 std::vector<SerializablePtr> values;
257
258 ++it;
259 if ((*it)->get(values))
260 {
261 if (values.size() == 2)
262 {
263 std::string axis;
264 size_t index = 0;
265 double value = 0.0;
266
267 if (values[0]->get(axis))
268 {
269 if (axis == "x") index = 0;
270 else if (axis == "y") index = 1;
271 else if (axis == "z") index = 2;
272
273 values[1]->getNumber(value);
274 }
275
276 cml::matrix_rotate_about_world_axis(transform,
277 index, cml::rad(Scalar(value)));
278 }
279 }
280 }
281 else if (instruction == "texture")
282 {
283 ++it;
284 (*it)->get(texture);
285 }
286 else if (instruction == "tilemap")
287 {
288 ++it;
289 loadTilemap(*it, transform, texture);
290 }
291 else if (instruction == "billboard")
292 {
293 ++it;
294 loadBillboard(*it, transform, texture);
295 }
296 }
297 }
298 }
299
300
301 void loadTilemap(SerializablePtr root, const Matrix4& transform,
302 const std::string& texture)
303 {
304 std::map<std::string,SerializablePtr> rootObj;
305 std::map<std::string,SerializablePtr>::iterator it;
306
307 if (!root->get(rootObj))
308 {
309 std::cerr << "error loading scene tilemap object" << std::endl;
310 return;
311 }
312
313 long width = 1;
314 long height = 1;
315 std::vector< std::vector<Tilemap::Index> > indices;
316
317 if ((it = rootObj.find("width")) != rootObj.end())
318 {
319 (*it).second->get(width);
320 }
321 else
322 {
323 std::cerr << "width is a required field of a tilemap" << std::endl;
324 return;
325 }
326
327 std::vector<SerializablePtr> tiles;
328
329 if ((it = rootObj.find("tiles")) != rootObj.end() &&
330 (*it).second->get(tiles) &&
331 tiles.size() % width == 0)
332 {
333 std::vector<SerializablePtr>::iterator jt;
334 int w, h;
335
336 height = tiles.size() / width;
337 indices.resize(height);
338
339 // the indices are stored upside-down in the scene file so that they
340 // are easier to edit as text, so we'll need to load them last row
341 // first
342
343 for (h = height - 1, jt = tiles.begin(); jt != tiles.end(); --h)
344 {
345 std::vector<Tilemap::Index> row;
346
347 for (w = 0; w < width && jt != tiles.end(); ++w, ++jt)
348 {
349 long index;
350
351 if ((*jt)->get(index))
352 {
353 row.push_back(Tilemap::Index(index));
354 }
355 }
356
357 indices[h] = row;
358 }
359 }
360 else
361 {
362 std::cerr << "error loading tiles from tilemap object" << std::endl;
363 return;
364 }
365
366 Vector4 vertices[height+1][width+1];
367
368 Matrix4 transposedTransform = transform;
369 transposedTransform.transpose();
370
371 for (int h = 0; h <= height; ++h)
372 {
373 for (int w = 0; w <= width; ++w)
374 {
375 vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) *
376 transposedTransform;
377 }
378 }
379
380 for (int h = 0; h < height; ++h)
381 {
382 for (int w = 0; w < width; ++w)
383 {
384 if (indices[h][w] == Tilemap::NO_TILE) continue;
385
386 Vector3 quadVertices[4];
387
388 demoteVector(quadVertices[0], vertices[h][w]);
389 demoteVector(quadVertices[1], vertices[h][w+1]);
390 demoteVector(quadVertices[2], vertices[h+1][w+1]);
391 demoteVector(quadVertices[3], vertices[h+1][w]);
392
393 Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
394 boost::shared_ptr<Quad> quadPtr(quad);
395
396 objects.push_back(quadPtr);
397 }
398 }
399 }
400
401 void loadBillboard(SerializablePtr root, const Matrix4& transform,
402 const std::string& texture)
403 {
404 std::map<std::string,SerializablePtr> rootObj;
405 std::map<std::string,SerializablePtr>::iterator it;
406
407 if (!root->get(rootObj))
408 {
409 std::cerr << "error loading scene billboard object" << std::endl;
410 return;
411 }
412
413 Tilemap::Index index = 0;
414 long width = 1;
415 bool blending = false;
416 bool fog = false;
417
418 if ((it = rootObj.find("tile")) != rootObj.end())
419 {
420 long value;
421 if ((*it).second->get(value))
422 {
423 index = Tilemap::Index(value);
424 }
425 }
426
427 if ((it = rootObj.find("u_scale")) != rootObj.end())
428 {
429 (*it).second->get(width);
430 }
431
432 if ((it = rootObj.find("blend")) != rootObj.end())
433 {
434 (*it).second->get(blending);
435 }
436
437 if ((it = rootObj.find("fog")) != rootObj.end())
438 {
439 (*it).second->get(fog);
440 }
441
442
443 Vector4 vertices[2][width+1];
444
445 Matrix4 transposedTransform = transform;
446 transposedTransform.transpose();
447
448 Scalar xf;
449 Scalar increment = 1.0 / Scalar(width);
450
451 for (int h = 0; h <= 1; ++h)
452 {
453 xf = 0.0;
454 for (int w = 0; w <= width; ++w, xf += increment)
455 {
456 vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) *
457 transposedTransform;
458 }
459 }
460
461 for (int w = 0; w < width; ++w)
462 {
463 Vector3 quadVertices[4];
464
465 demoteVector(quadVertices[0], vertices[0][w]);
466 demoteVector(quadVertices[1], vertices[0][w+1]);
467 demoteVector(quadVertices[2], vertices[1][w+1]);
468 demoteVector(quadVertices[3], vertices[1][w]);
469
470 Quad* quad = new Quad(quadVertices, texture, index);
471 quad->setBlending(blending);
472 quad->setFog(fog);
473
474 boost::shared_ptr<Quad> quadPtr(quad);
475
476 objects.push_back(quadPtr);
477 }
478 }
479
480
481 void loadFromFile()
482 {
483 std::string filePath = Scene::getPathToResource(getName());
484
485 Deserializer deserializer(filePath, true);
486 SerializablePtr root = deserializer.deserialize();
487
488 std::map<std::string,SerializablePtr> rootObj;
489 std::map<std::string,SerializablePtr>::iterator it;
490
491 if (!root || !root->get(rootObj))
492 {
493 std::cerr << "error loading scene file" << std::endl;
494 return;
495 }
496
497 if ((it = rootObj.find("playfield_bounds")) != rootObj.end())
498 {
499 loadBox(playfieldBounds, (*it).second);
500 }
501 if ((it = rootObj.find("maximum_bounds")) != rootObj.end())
502 {
503 loadBox(maximumBounds, (*it).second);
504 }
505 if ((it = rootObj.find("instructions")) != rootObj.end())
506 {
507 loadInstructions((*it).second);
508 }
509 }
510
511
512 void draw(Scalar alpha)
513 {
514 QuadVector::iterator it;
515
516 for (it = objects.begin(); it != objects.end(); ++it)
517 {
518 //std::cout << "draw object";
519 (*it)->draw(alpha);
520 }
521
522 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
523
524 glBindTexture(GL_TEXTURE_2D, 0);
525 glColor3f(0.0f, 1.0f, 0.0f);
526 playfieldBounds.draw();
527 glColor3f(0.0f, 0.0f, 1.0f);
528 maximumBounds.draw();
529
530 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
531 }
532
533
534 Aabb playfieldBounds;
535 Aabb maximumBounds;
536
537 typedef std::vector< boost::shared_ptr<Quad> > QuadVector;
538 QuadVector objects;
539 };
540
541
542 Scene::Scene(const std::string& name) :
543 // pass through
544 impl_(Scene::SceneImpl::retain(name), &Scene::SceneImpl::release) {}
545
546
547 void Scene::draw(Scalar alpha) const
548 {
549 // pass through
550 impl_->draw(alpha);
551 }
552
553 void Scene::refresh()
554 {
555 impl_->objects.clear();
556 impl_->loadFromFile();
557 }
558
559
560 /**
561 * Specialized search location for scene files. They can be found in the
562 * "scenes" subdirectory of any of the searched directories.
563 */
564
565 std::string Scene::getPathToResource(const std::string& name)
566 {
567 return Resource::getPathToResource("scenes/" + name + ".json");
568 }
569
570
571 } // namespace Mf
572
573 /** vim: set ts=4 sw=4 tw=80: *************************************************/
574
This page took 0.062753 seconds and 4 git commands to generate.