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 *******************************************************************************/
34 #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 logWarning("no index %d in texture %s", tileIndex
,
73 texCoords_
[0] = texCoords_
[1] =
74 texCoords_
[3] = texCoords_
[6] = 0.0;
75 texCoords_
[2] = texCoords_
[4] =
76 texCoords_
[5] = texCoords_
[7] = 1.0;
79 aabb_
.encloseVertices(vertices
, 4);
80 sphere_
.point
= aabb_
.getCenter();
81 sphere_
.radius
= (aabb_
.min
- sphere_
.point
).length();
84 void setDetail(long detail
)
89 void setBlending(bool blending
)
99 void draw(Scalar alpha
= 0.0) const
104 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
110 glFogi(GL_FOG_MODE
, GL_LINEAR
);
113 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
116 glVertexPointer(3, GL_SCALAR
, 0, vertices_
);
117 glTexCoordPointer(2, GL_SCALAR
, 0, texCoords_
);
119 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
125 bool isVisible(const Camera
& cam
) const
127 return sphere_
.isVisible(cam
);
131 Scalar vertices_
[12];
132 Scalar texCoords_
[8];
142 static void loadBox(Aabb
& theBox
, SerializableP obj
)
144 Serializable::Array numbers
;
146 if (obj
->get(numbers
) && numbers
.size() == 6)
148 Serializable::Float num
;
150 if (numbers
[0]->getNumber(num
)) theBox
.min
[0] = Scalar(num
);
151 if (numbers
[1]->getNumber(num
)) theBox
.min
[1] = Scalar(num
);
152 if (numbers
[2]->getNumber(num
)) theBox
.min
[2] = Scalar(num
);
153 if (numbers
[3]->getNumber(num
)) theBox
.max
[0] = Scalar(num
);
154 if (numbers
[4]->getNumber(num
)) theBox
.max
[1] = Scalar(num
);
155 if (numbers
[5]->getNumber(num
)) theBox
.max
[2] = Scalar(num
);
160 Impl(const std::string
& name
) :
161 Mippleton
<Impl
>(name
)
167 void loadInstructions(SerializableP root
)
169 Serializable::Array rootObj
;
170 Serializable::Array::iterator it
;
172 if (!root
->get(rootObj
))
174 logError("scene instructions must be an array");
181 for (it
= rootObj
.begin(); it
!= rootObj
.end(); ++it
)
183 std::string instruction
;
185 if ((*it
)->get(instruction
))
187 if (instruction
== "reset_transform")
189 transform
.identity();
191 else if (instruction
== "translate")
193 Serializable::Array values
;
196 if ((*it
)->get(values
))
200 for (size_t i
= 0; i
< values
.size(); ++i
)
202 Serializable::Float value
;
204 if (values
[i
]->getNumber(value
))
211 cml::matrix_translation(translation
, vec
);
212 transform
= translation
* transform
;
215 else if (instruction
== "scale")
217 Serializable::Array values
;
220 if ((*it
)->get(values
))
222 if (values
.size() == 1)
224 Serializable::Float value
= 1.0;
226 values
[0]->getNumber(value
);
229 cml::matrix_uniform_scale(scaling
,
231 transform
= scaling
* transform
;
233 else if (values
.size() == 3)
237 for (size_t i
= 0; i
< values
.size(); ++i
)
239 Serializable::Float value
;
241 if (values
[i
]->getNumber(value
))
248 cml::matrix_scale(scaling
, vec
);
249 transform
= scaling
* transform
;
253 else if (instruction
== "rotate")
255 Serializable::Array values
;
258 if ((*it
)->get(values
))
260 if (values
.size() == 2)
264 Serializable::Float value
= 0.0;
266 if (values
[0]->get(axis
))
268 if (axis
== "x") index
= 0;
269 else if (axis
== "y") index
= 1;
270 else if (axis
== "z") index
= 2;
272 values
[1]->getNumber(value
);
275 cml::matrix_rotate_about_world_axis(transform
,
276 index
, cml::rad(Scalar(value
)));
280 else if (instruction
== "texture")
285 else if (instruction
== "tilemap")
288 loadTilemap(*it
, transform
, texture
);
290 else if (instruction
== "billboard")
293 loadBillboard(*it
, transform
, texture
);
300 void loadTilemap(SerializableP root
, const Matrix4
& transform
,
301 const std::string
& texture
)
303 Serializable::Map rootObj
;
304 Serializable::Map::iterator it
;
306 if (!root
->get(rootObj
))
308 logError("invalid tilemap instruction");
314 std::vector
< std::vector
<Tilemap::Index
> > indices
;
316 if ((it
= rootObj
.find("width")) != rootObj
.end())
318 (*it
).second
->get(width
);
322 logError("missing required field width for tilemap instruction");
326 Serializable::Array tiles
;
328 if ((it
= rootObj
.find("tiles")) != rootObj
.end() &&
329 (*it
).second
->get(tiles
) &&
330 tiles
.size() % width
== 0)
332 Serializable::Array::iterator jt
;
335 height
= tiles
.size() / width
;
336 indices
.resize(height
);
338 // the indices are stored upside-down in the scene file so that they
339 // are easier to edit as text, so we'll need to load them last row
342 for (h
= height
- 1, jt
= tiles
.begin(); jt
!= tiles
.end(); --h
)
344 std::vector
<Tilemap::Index
> row
;
346 for (w
= 0; w
< width
&& jt
!= tiles
.end(); ++w
, ++jt
)
348 Serializable::Integer index
;
350 if ((*jt
)->get(index
))
352 row
.push_back(Tilemap::Index(index
));
361 logError("invalid tiles in tilemap instruction");
365 Vector4 vertices
[height
+1][width
+1];
367 Matrix4 transposedTransform
= transform
;
368 transposedTransform
.transpose();
370 for (int h
= 0; h
<= height
; ++h
)
372 for (int w
= 0; w
<= width
; ++w
)
374 vertices
[h
][w
] = Vector4(Scalar(w
), Scalar(h
), 0.0, 1.0) *
379 for (int h
= 0; h
< height
; ++h
)
381 for (int w
= 0; w
< width
; ++w
)
383 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
385 Vector3 quadVertices
[4];
387 demoteVector(quadVertices
[0], vertices
[h
][w
]);
388 demoteVector(quadVertices
[1], vertices
[h
][w
+1]);
389 demoteVector(quadVertices
[2], vertices
[h
+1][w
+1]);
390 demoteVector(quadVertices
[3], vertices
[h
+1][w
]);
392 Quad
* quad
= new Quad(quadVertices
, texture
, indices
[h
][w
]);
393 boost::shared_ptr
<Quad
> quadPtr(quad
);
395 octree
->insert(quadPtr
);
400 void loadBillboard(SerializableP root
, const Matrix4
& transform
,
401 const std::string
& texture
)
403 Serializable::Map rootObj
;
404 Serializable::Map::iterator it
;
406 Tilemap::Index index
= 0;
408 bool blending
= false;
411 if (root
->get(rootObj
))
413 if ((it
= rootObj
.find("tile")) != rootObj
.end())
415 Serializable::Integer value
;
416 if ((*it
).second
->get(value
))
418 index
= Tilemap::Index(value
);
422 if ((it
= rootObj
.find("u_scale")) != rootObj
.end())
424 (*it
).second
->get(width
);
427 if ((it
= rootObj
.find("blend")) != rootObj
.end())
429 (*it
).second
->get(blending
);
432 if ((it
= rootObj
.find("fog")) != rootObj
.end())
434 (*it
).second
->get(fog
);
439 Vector4 vertices
[2][width
+1];
441 Matrix4 transposedTransform
= transform
;
442 transposedTransform
.transpose();
445 Scalar increment
= 1.0 / Scalar(width
);
447 for (int h
= 0; h
<= 1; ++h
)
450 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
452 vertices
[h
][w
] = Vector4(xf
, Scalar(h
), 0.0, 1.0) *
457 for (int w
= 0; w
< width
; ++w
)
459 Vector3 quadVertices
[4];
461 demoteVector(quadVertices
[0], vertices
[0][w
]);
462 demoteVector(quadVertices
[1], vertices
[0][w
+1]);
463 demoteVector(quadVertices
[2], vertices
[1][w
+1]);
464 demoteVector(quadVertices
[3], vertices
[1][w
]);
466 Quad
* quad
= new Quad(quadVertices
, texture
, index
);
467 quad
->setBlending(blending
);
470 boost::shared_ptr
<Quad
> quadPtr(quad
);
472 octree
->insert(quadPtr
);
479 std::string filePath
= Scene::getPath(getName());
481 Deserializer
deserializer(filePath
, true);
482 SerializableP root
= deserializer
.deserialize();
484 Serializable::Map rootObj
;
485 Serializable::Map::iterator it
;
487 if (!root
|| !root
->get(rootObj
))
489 logError("no root map in scene file");
493 if ((it
= rootObj
.find("playfield_bounds")) != rootObj
.end())
495 loadBox(playfieldBounds
, (*it
).second
);
497 if ((it
= rootObj
.find("maximum_bounds")) != rootObj
.end())
499 loadBox(maximumBounds
, (*it
).second
);
503 logError("missing required maximum bounds");
507 // create the tree to store the quads
508 octree
= Octree::alloc(maximumBounds
);
510 if ((it
= rootObj
.find("instructions")) != rootObj
.end())
512 loadInstructions((*it
).second
);
521 void draw(Scalar alpha
, const Camera
& cam
) const
523 glEnableClientState(GL_VERTEX_ARRAY
);
524 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
526 octree
->drawIfVisible(alpha
, cam
);
528 //glDisableClientState(GL_VERTEX_ARRAY);
529 //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
531 //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
533 //Texture::resetBind();
534 //glColor3f(0.0f, 1.0f, 0.0f);
535 //playfieldBounds.draw();
536 //glColor3f(0.0f, 0.0f, 1.0f);
537 //maximumBounds.draw();
539 //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
543 Aabb playfieldBounds
;
550 Scene::Scene(const std::string
& name
) :
552 impl_(Scene::Impl::getInstance(name
)) {}
555 void Scene::draw(Scalar alpha
, const Camera
& cam
) const
558 impl_
->draw(alpha
, cam
);
561 void Scene::refresh()
563 //impl_->objects.clear();
564 impl_
->loadFromFile();
568 OctreeP
Scene::getOctree() const
571 return impl_
->octree
;
575 * Specialized search location for scene files. They can be found in the
576 * "scenes" subdirectory of any of the searched directories.
579 std::string
Scene::getPath(const std::string
& name
)
581 return Resource::getPath("scenes/" + name
+ ".json");
587 /** vim: set ts=4 sw=4 tw=80: *************************************************/