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"
41 #include "Serializable.hh"
48 class Scene::Impl
: public Mippleton
<Impl
>
50 class Quad
: public Entity
53 Quad(const Vector3 vertices
[4], const std::string
& texture
,
54 Tilemap::Index tileIndex
) :
60 for (int i
= 0, num
= 0; i
< 4; ++i
)
62 for (int j
= 0; j
< 3; ++j
, ++num
)
64 vertices_
[num
] = vertices
[i
][j
];
68 if (!tilemap_
.getTileCoords(tileIndex
, texCoords_
))
70 std::cerr
<< "no coords for tile's texture" << std::endl
;
73 aabb_
.encloseVertices(vertices
, 4);
74 sphere_
.point
= aabb_
.getCenter();
75 sphere_
.radius
= (aabb_
.min
- sphere_
.point
).length();
78 void setDetail(long detail
)
83 void setBlending(bool blending
)
93 void draw(Scalar alpha
= 0.0) const
98 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
104 glFogi(GL_FOG_MODE
, GL_LINEAR
);
107 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
110 glVertexPointer(3, GL_SCALAR
, 0, vertices_
);
111 glTexCoordPointer(2, GL_SCALAR
, 0, texCoords_
);
113 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
119 bool isVisible(const Camera
& cam
) const
121 return sphere_
.isVisible(cam
);
125 Scalar vertices_
[12];
126 Scalar texCoords_
[8];
136 static void loadBox(Aabb
& theBox
, SerializablePtr obj
)
138 std::vector
<SerializablePtr
> numbers
;
140 if (obj
->get(numbers
) && numbers
.size() == 6)
144 if (numbers
[0]->getNumber(num
)) theBox
.min
[0] = Scalar(num
);
145 if (numbers
[1]->getNumber(num
)) theBox
.min
[1] = Scalar(num
);
146 if (numbers
[2]->getNumber(num
)) theBox
.min
[2] = Scalar(num
);
147 if (numbers
[3]->getNumber(num
)) theBox
.max
[0] = Scalar(num
);
148 if (numbers
[4]->getNumber(num
)) theBox
.max
[1] = Scalar(num
);
149 if (numbers
[5]->getNumber(num
)) theBox
.max
[2] = Scalar(num
);
154 Impl(const std::string
& name
) :
155 Mippleton
<Impl
>(name
)
161 void loadInstructions(SerializablePtr root
)
163 std::vector
<SerializablePtr
> rootObj
;
164 std::vector
<SerializablePtr
>::iterator it
;
166 if (!root
->get(rootObj
))
168 std::cerr
<< "error loading scene instructions" << std::endl
;
175 for (it
= rootObj
.begin(); it
!= rootObj
.end(); ++it
)
177 std::string instruction
;
179 if ((*it
)->get(instruction
))
181 if (instruction
== "reset_transform")
183 transform
.identity();
185 else if (instruction
== "translate")
187 std::vector
<SerializablePtr
> values
;
190 if ((*it
)->get(values
))
194 for (size_t i
= 0; i
< values
.size(); ++i
)
198 if (values
[i
]->getNumber(value
))
205 cml::matrix_translation(translation
, vec
);
206 transform
= translation
* transform
;
209 else if (instruction
== "scale")
211 std::vector
<SerializablePtr
> values
;
214 if ((*it
)->get(values
))
216 if (values
.size() == 1)
220 values
[0]->getNumber(value
);
223 cml::matrix_uniform_scale(scaling
,
225 transform
= scaling
* transform
;
227 else if (values
.size() == 3)
231 for (size_t i
= 0; i
< values
.size(); ++i
)
235 if (values
[i
]->getNumber(value
))
242 cml::matrix_scale(scaling
, vec
);
243 transform
= scaling
* transform
;
247 else if (instruction
== "rotate")
249 std::vector
<SerializablePtr
> values
;
252 if ((*it
)->get(values
))
254 if (values
.size() == 2)
260 if (values
[0]->get(axis
))
262 if (axis
== "x") index
= 0;
263 else if (axis
== "y") index
= 1;
264 else if (axis
== "z") index
= 2;
266 values
[1]->getNumber(value
);
269 cml::matrix_rotate_about_world_axis(transform
,
270 index
, cml::rad(Scalar(value
)));
274 else if (instruction
== "texture")
279 else if (instruction
== "tilemap")
282 loadTilemap(*it
, transform
, texture
);
284 else if (instruction
== "billboard")
287 loadBillboard(*it
, transform
, texture
);
294 void loadTilemap(SerializablePtr root
, const Matrix4
& transform
,
295 const std::string
& texture
)
297 std::map
<std::string
,SerializablePtr
> rootObj
;
298 std::map
<std::string
,SerializablePtr
>::iterator it
;
300 if (!root
->get(rootObj
))
302 std::cerr
<< "error loading scene tilemap object" << std::endl
;
308 std::vector
< std::vector
<Tilemap::Index
> > indices
;
310 if ((it
= rootObj
.find("width")) != rootObj
.end())
312 (*it
).second
->get(width
);
316 std::cerr
<< "width is a required field of a tilemap" << std::endl
;
320 std::vector
<SerializablePtr
> tiles
;
322 if ((it
= rootObj
.find("tiles")) != rootObj
.end() &&
323 (*it
).second
->get(tiles
) &&
324 tiles
.size() % width
== 0)
326 std::vector
<SerializablePtr
>::iterator jt
;
329 height
= tiles
.size() / width
;
330 indices
.resize(height
);
332 // the indices are stored upside-down in the scene file so that they
333 // are easier to edit as text, so we'll need to load them last row
336 for (h
= height
- 1, jt
= tiles
.begin(); jt
!= tiles
.end(); --h
)
338 std::vector
<Tilemap::Index
> row
;
340 for (w
= 0; w
< width
&& jt
!= tiles
.end(); ++w
, ++jt
)
344 if ((*jt
)->get(index
))
346 row
.push_back(Tilemap::Index(index
));
355 std::cerr
<< "error loading tiles from tilemap object" << std::endl
;
359 Vector4 vertices
[height
+1][width
+1];
361 Matrix4 transposedTransform
= transform
;
362 transposedTransform
.transpose();
364 for (int h
= 0; h
<= height
; ++h
)
366 for (int w
= 0; w
<= width
; ++w
)
368 vertices
[h
][w
] = Vector4(Scalar(w
), Scalar(h
), 0.0, 1.0) *
373 for (int h
= 0; h
< height
; ++h
)
375 for (int w
= 0; w
< width
; ++w
)
377 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
379 Vector3 quadVertices
[4];
381 demoteVector(quadVertices
[0], vertices
[h
][w
]);
382 demoteVector(quadVertices
[1], vertices
[h
][w
+1]);
383 demoteVector(quadVertices
[2], vertices
[h
+1][w
+1]);
384 demoteVector(quadVertices
[3], vertices
[h
+1][w
]);
386 Quad
* quad
= new Quad(quadVertices
, texture
, indices
[h
][w
]);
387 boost::shared_ptr
<Quad
> quadPtr(quad
);
389 octree
->insert(quadPtr
);
394 void loadBillboard(SerializablePtr root
, const Matrix4
& transform
,
395 const std::string
& texture
)
397 std::map
<std::string
,SerializablePtr
> rootObj
;
398 std::map
<std::string
,SerializablePtr
>::iterator it
;
400 Tilemap::Index index
= 0;
402 bool blending
= false;
405 if (root
->get(rootObj
))
407 if ((it
= rootObj
.find("tile")) != rootObj
.end())
410 if ((*it
).second
->get(value
))
412 index
= Tilemap::Index(value
);
416 if ((it
= rootObj
.find("u_scale")) != rootObj
.end())
418 (*it
).second
->get(width
);
421 if ((it
= rootObj
.find("blend")) != rootObj
.end())
423 (*it
).second
->get(blending
);
426 if ((it
= rootObj
.find("fog")) != rootObj
.end())
428 (*it
).second
->get(fog
);
433 Vector4 vertices
[2][width
+1];
435 Matrix4 transposedTransform
= transform
;
436 transposedTransform
.transpose();
439 Scalar increment
= 1.0 / Scalar(width
);
441 for (int h
= 0; h
<= 1; ++h
)
444 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
446 vertices
[h
][w
] = Vector4(xf
, Scalar(h
), 0.0, 1.0) *
451 for (int w
= 0; w
< width
; ++w
)
453 Vector3 quadVertices
[4];
455 demoteVector(quadVertices
[0], vertices
[0][w
]);
456 demoteVector(quadVertices
[1], vertices
[0][w
+1]);
457 demoteVector(quadVertices
[2], vertices
[1][w
+1]);
458 demoteVector(quadVertices
[3], vertices
[1][w
]);
460 Quad
* quad
= new Quad(quadVertices
, texture
, index
);
461 quad
->setBlending(blending
);
464 boost::shared_ptr
<Quad
> quadPtr(quad
);
466 octree
->insert(quadPtr
);
473 std::string filePath
= Scene::getPath(getName());
475 Deserializer
deserializer(filePath
, true);
476 SerializablePtr root
= deserializer
.deserialize();
478 std::map
<std::string
,SerializablePtr
> rootObj
;
479 std::map
<std::string
,SerializablePtr
>::iterator it
;
481 if (!root
|| !root
->get(rootObj
))
483 std::cerr
<< "error loading scene file" << std::endl
;
487 if ((it
= rootObj
.find("playfield_bounds")) != rootObj
.end())
489 loadBox(playfieldBounds
, (*it
).second
);
491 if ((it
= rootObj
.find("maximum_bounds")) != rootObj
.end())
493 loadBox(maximumBounds
, (*it
).second
);
497 std::cerr
<< "maximum bounds required in scene" << std::endl
;
501 // create the tree to store the quads
502 octree
= OctreePtr(new Octree(maximumBounds
));
504 if ((it
= rootObj
.find("instructions")) != rootObj
.end())
506 loadInstructions((*it
).second
);
513 void draw(Scalar alpha
, const Camera
& cam
) const
515 glEnableClientState(GL_VERTEX_ARRAY
);
516 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
518 octree
->drawIfVisible(alpha
, cam
);
520 //glDisableClientState(GL_VERTEX_ARRAY);
521 //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
523 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
525 //Texture::resetBind();
526 //glColor3f(0.0f, 1.0f, 0.0f);
527 //playfieldBounds.draw();
528 //glColor3f(0.0f, 0.0f, 1.0f);
529 //maximumBounds.draw();
531 //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
535 Aabb playfieldBounds
;
542 Scene::Scene(const std::string
& name
) :
544 impl_(Scene::Impl::getInstance(name
)) {}
547 void Scene::draw(Scalar alpha
, const Camera
& cam
) const
550 impl_
->draw(alpha
, cam
);
553 void Scene::refresh()
555 //impl_->objects.clear();
556 impl_
->loadFromFile();
560 OctreePtr
Scene::getOctree() const
563 return impl_
->octree
;
567 * Specialized search location for scene files. They can be found in the
568 * "scenes" subdirectory of any of the searched directories.
571 std::string
Scene::getPath(const std::string
& name
)
573 return Resource::getPath("scenes/" + name
+ ".json");
579 /** vim: set ts=4 sw=4 tw=80: *************************************************/