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
, SerializableP obj
)
138 Serializable::Array numbers
;
140 if (obj
->get(numbers
) && numbers
.size() == 6)
142 Serializable::Float num
;
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(SerializableP root
)
163 Serializable::Array rootObj
;
164 Serializable::Array::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 Serializable::Array values
;
190 if ((*it
)->get(values
))
194 for (size_t i
= 0; i
< values
.size(); ++i
)
196 Serializable::Float value
;
198 if (values
[i
]->getNumber(value
))
205 cml::matrix_translation(translation
, vec
);
206 transform
= translation
* transform
;
209 else if (instruction
== "scale")
211 Serializable::Array values
;
214 if ((*it
)->get(values
))
216 if (values
.size() == 1)
218 Serializable::Float value
= 1.0;
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
)
233 Serializable::Float value
;
235 if (values
[i
]->getNumber(value
))
242 cml::matrix_scale(scaling
, vec
);
243 transform
= scaling
* transform
;
247 else if (instruction
== "rotate")
249 Serializable::Array values
;
252 if ((*it
)->get(values
))
254 if (values
.size() == 2)
258 Serializable::Float value
= 0.0;
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(SerializableP root
, const Matrix4
& transform
,
295 const std::string
& texture
)
297 Serializable::Map rootObj
;
298 Serializable::Map::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 Serializable::Array tiles
;
322 if ((it
= rootObj
.find("tiles")) != rootObj
.end() &&
323 (*it
).second
->get(tiles
) &&
324 tiles
.size() % width
== 0)
326 Serializable::Array::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
)
342 Serializable::Integer index
;
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(SerializableP root
, const Matrix4
& transform
,
395 const std::string
& texture
)
397 Serializable::Map rootObj
;
398 Serializable::Map::iterator it
;
400 Tilemap::Index index
= 0;
402 bool blending
= false;
405 if (root
->get(rootObj
))
407 if ((it
= rootObj
.find("tile")) != rootObj
.end())
409 Serializable::Integer value
;
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 SerializableP root
= deserializer
.deserialize();
478 Serializable::Map rootObj
;
479 Serializable::Map::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
= Octree::alloc(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 OctreeP
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: *************************************************/