2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
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.
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.
27 *******************************************************************************/
35 #include "Deserializer.hh"
38 #include "Mippleton.hh"
42 #include "Serializable.hh"
49 class Scene::SceneImpl
: public Mippleton
<SceneImpl
>
51 class Quad
: public Entity
54 Quad(const Vector3 vertices
[4], const std::string
& texture
,
55 Tilemap::Index tileIndex
) :
61 for (int i
= 0, num
= 0; i
< 4; ++i
)
63 for (int j
= 0; j
< 3; ++j
, ++num
)
65 vertices_
[num
] = vertices
[i
][j
];
69 if (!tilemap_
.getTileCoords(tileIndex
, texCoords_
))
71 std::cerr
<< "no coords for tile's texture" << std::endl
;
74 aabb_
.encloseVertices(vertices
, 4);
75 sphere_
.point
= aabb_
.getCenter();
76 sphere_
.radius
= (aabb_
.min
- sphere_
.point
).length();
79 void setDetail(long detail
)
84 void setBlending(bool blending
)
94 void draw(Scalar alpha
= 0.0) const
99 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
102 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
105 glVertexPointer(3, GL_SCALAR
, 0, vertices_
);
106 glTexCoordPointer(2, GL_SCALAR
, 0, texCoords_
);
108 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
113 bool isVisible(const Camera
& cam
) const
115 return sphere_
.isVisible(cam
);
119 Scalar vertices_
[12];
120 Scalar texCoords_
[8];
130 static void loadBox(Aabb
& theBox
, SerializablePtr obj
)
132 std::vector
<SerializablePtr
> numbers
;
134 if (obj
->get(numbers
) && numbers
.size() == 6)
138 if (numbers
[0]->getNumber(num
)) theBox
.min
[0] = Scalar(num
);
139 if (numbers
[1]->getNumber(num
)) theBox
.min
[1] = Scalar(num
);
140 if (numbers
[2]->getNumber(num
)) theBox
.min
[2] = Scalar(num
);
141 if (numbers
[3]->getNumber(num
)) theBox
.max
[0] = Scalar(num
);
142 if (numbers
[4]->getNumber(num
)) theBox
.max
[1] = Scalar(num
);
143 if (numbers
[5]->getNumber(num
)) theBox
.max
[2] = Scalar(num
);
148 SceneImpl(const std::string
& name
) :
149 Mippleton
<SceneImpl
>(name
)
155 void loadInstructions(SerializablePtr root
)
157 std::vector
<SerializablePtr
> rootObj
;
158 std::vector
<SerializablePtr
>::iterator it
;
160 if (!root
->get(rootObj
))
162 std::cerr
<< "error loading scene instructions" << std::endl
;
169 for (it
= rootObj
.begin(); it
!= rootObj
.end(); ++it
)
171 std::string instruction
;
173 if ((*it
)->get(instruction
))
175 if (instruction
== "reset_transform")
177 transform
.identity();
179 else if (instruction
== "translate")
181 std::vector
<SerializablePtr
> values
;
184 if ((*it
)->get(values
))
188 for (size_t i
= 0; i
< values
.size(); ++i
)
192 if (values
[i
]->getNumber(value
))
199 cml::matrix_translation(translation
, vec
);
200 transform
= translation
* transform
;
203 else if (instruction
== "scale")
205 std::vector
<SerializablePtr
> values
;
208 if ((*it
)->get(values
))
210 if (values
.size() == 1)
214 values
[0]->getNumber(value
);
217 cml::matrix_uniform_scale(scaling
,
219 transform
= scaling
* transform
;
221 else if (values
.size() == 3)
225 for (size_t i
= 0; i
< values
.size(); ++i
)
229 if (values
[i
]->getNumber(value
))
236 cml::matrix_scale(scaling
, vec
);
237 transform
= scaling
* transform
;
241 else if (instruction
== "rotate")
243 std::vector
<SerializablePtr
> values
;
246 if ((*it
)->get(values
))
248 if (values
.size() == 2)
254 if (values
[0]->get(axis
))
256 if (axis
== "x") index
= 0;
257 else if (axis
== "y") index
= 1;
258 else if (axis
== "z") index
= 2;
260 values
[1]->getNumber(value
);
263 cml::matrix_rotate_about_world_axis(transform
,
264 index
, cml::rad(Scalar(value
)));
268 else if (instruction
== "texture")
273 else if (instruction
== "tilemap")
276 loadTilemap(*it
, transform
, texture
);
278 else if (instruction
== "billboard")
281 loadBillboard(*it
, transform
, texture
);
288 void loadTilemap(SerializablePtr root
, const Matrix4
& transform
,
289 const std::string
& texture
)
291 std::map
<std::string
,SerializablePtr
> rootObj
;
292 std::map
<std::string
,SerializablePtr
>::iterator it
;
294 if (!root
->get(rootObj
))
296 std::cerr
<< "error loading scene tilemap object" << std::endl
;
302 std::vector
< std::vector
<Tilemap::Index
> > indices
;
304 if ((it
= rootObj
.find("width")) != rootObj
.end())
306 (*it
).second
->get(width
);
310 std::cerr
<< "width is a required field of a tilemap" << std::endl
;
314 std::vector
<SerializablePtr
> tiles
;
316 if ((it
= rootObj
.find("tiles")) != rootObj
.end() &&
317 (*it
).second
->get(tiles
) &&
318 tiles
.size() % width
== 0)
320 std::vector
<SerializablePtr
>::iterator jt
;
323 height
= tiles
.size() / width
;
324 indices
.resize(height
);
326 // the indices are stored upside-down in the scene file so that they
327 // are easier to edit as text, so we'll need to load them last row
330 for (h
= height
- 1, jt
= tiles
.begin(); jt
!= tiles
.end(); --h
)
332 std::vector
<Tilemap::Index
> row
;
334 for (w
= 0; w
< width
&& jt
!= tiles
.end(); ++w
, ++jt
)
338 if ((*jt
)->get(index
))
340 row
.push_back(Tilemap::Index(index
));
349 std::cerr
<< "error loading tiles from tilemap object" << std::endl
;
353 Vector4 vertices
[height
+1][width
+1];
355 Matrix4 transposedTransform
= transform
;
356 transposedTransform
.transpose();
358 for (int h
= 0; h
<= height
; ++h
)
360 for (int w
= 0; w
<= width
; ++w
)
362 vertices
[h
][w
] = Vector4(Scalar(w
), Scalar(h
), 0.0, 1.0) *
367 for (int h
= 0; h
< height
; ++h
)
369 for (int w
= 0; w
< width
; ++w
)
371 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
373 Vector3 quadVertices
[4];
375 demoteVector(quadVertices
[0], vertices
[h
][w
]);
376 demoteVector(quadVertices
[1], vertices
[h
][w
+1]);
377 demoteVector(quadVertices
[2], vertices
[h
+1][w
+1]);
378 demoteVector(quadVertices
[3], vertices
[h
+1][w
]);
380 Quad
* quad
= new Quad(quadVertices
, texture
, indices
[h
][w
]);
381 boost::shared_ptr
<Quad
> quadPtr(quad
);
383 //objects.push_back(quadPtr);
384 octree
->insert(quadPtr
);
389 void loadBillboard(SerializablePtr root
, const Matrix4
& transform
,
390 const std::string
& texture
)
392 std::map
<std::string
,SerializablePtr
> rootObj
;
393 std::map
<std::string
,SerializablePtr
>::iterator it
;
395 if (!root
->get(rootObj
))
397 std::cerr
<< "error loading scene billboard object" << std::endl
;
401 Tilemap::Index index
= 0;
403 bool blending
= false;
406 if ((it
= rootObj
.find("tile")) != rootObj
.end())
409 if ((*it
).second
->get(value
))
411 index
= Tilemap::Index(value
);
415 if ((it
= rootObj
.find("u_scale")) != rootObj
.end())
417 (*it
).second
->get(width
);
420 if ((it
= rootObj
.find("blend")) != rootObj
.end())
422 (*it
).second
->get(blending
);
425 if ((it
= rootObj
.find("fog")) != rootObj
.end())
427 (*it
).second
->get(fog
);
431 Vector4 vertices
[2][width
+1];
433 Matrix4 transposedTransform
= transform
;
434 transposedTransform
.transpose();
437 Scalar increment
= 1.0 / Scalar(width
);
439 for (int h
= 0; h
<= 1; ++h
)
442 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
444 vertices
[h
][w
] = Vector4(xf
, Scalar(h
), 0.0, 1.0) *
449 for (int w
= 0; w
< width
; ++w
)
451 Vector3 quadVertices
[4];
453 demoteVector(quadVertices
[0], vertices
[0][w
]);
454 demoteVector(quadVertices
[1], vertices
[0][w
+1]);
455 demoteVector(quadVertices
[2], vertices
[1][w
+1]);
456 demoteVector(quadVertices
[3], vertices
[1][w
]);
458 Quad
* quad
= new Quad(quadVertices
, texture
, index
);
459 quad
->setBlending(blending
);
462 boost::shared_ptr
<Quad
> quadPtr(quad
);
464 //objects.push_back(quad_Ptr);
465 octree
->insert(quadPtr
);
472 std::string filePath
= Scene::getPathToResource(getName());
474 Deserializer
deserializer(filePath
, true);
475 SerializablePtr root
= deserializer
.deserialize();
477 std::map
<std::string
,SerializablePtr
> rootObj
;
478 std::map
<std::string
,SerializablePtr
>::iterator it
;
480 if (!root
|| !root
->get(rootObj
))
482 std::cerr
<< "error loading scene file" << std::endl
;
486 if ((it
= rootObj
.find("playfield_bounds")) != rootObj
.end())
488 loadBox(playfieldBounds
, (*it
).second
);
490 if ((it
= rootObj
.find("maximum_bounds")) != rootObj
.end())
492 loadBox(maximumBounds
, (*it
).second
);
496 std::cerr
<< "maximum bounds required in scene" << std::endl
;
500 //OctreeNode rootNode(maximumBounds);
501 octree
= OctreePtr(new Octree(maximumBounds
));
503 if ((it
= rootObj
.find("instructions")) != rootObj
.end())
505 loadInstructions((*it
).second
);
510 void draw(Scalar alpha
, const Camera
& cam
) const
512 //QuadVector::const_iterator it;
514 glEnableClientState(GL_VERTEX_ARRAY
);
515 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
517 octree
->drawIfVisible(alpha
, cam
);
519 //int objectsDrawn = 0;
521 //for (it = objects.begin(); it != objects.end(); ++it)
523 //if ((*it)->isVisible(cam))
525 ////std::cout << "draw object";
532 //std::cout << objectsDrawn << std::endl;
534 glDisableClientState(GL_VERTEX_ARRAY
);
535 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
537 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
539 Texture::resetBind();
540 glColor3f(0.0f
, 1.0f
, 0.0f
);
541 playfieldBounds
.draw();
542 glColor3f(0.0f
, 0.0f
, 1.0f
);
543 maximumBounds
.draw();
545 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
549 Aabb playfieldBounds
;
552 //typedef std::vector< boost::shared_ptr<Quad> > QuadVector;
553 //QuadVector objects;
558 Scene::Scene(const std::string
& name
) :
560 impl_(Scene::SceneImpl::retain(name
), &Scene::SceneImpl::release
) {}
563 void Scene::draw(Scalar alpha
, const Camera
& cam
) const
566 impl_
->draw(alpha
, cam
);
569 void Scene::refresh()
571 //impl_->objects.clear();
572 impl_
->loadFromFile();
577 * Specialized search location for scene files. They can be found in the
578 * "scenes" subdirectory of any of the searched directories.
581 std::string
Scene::getPathToResource(const std::string
& name
)
583 return Resource::getPathToResource("scenes/" + name
+ ".json");
589 /** vim: set ts=4 sw=4 tw=80: *************************************************/