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