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
;
75 void setDetail(long detail
)
80 void setBlending(bool blending
)
90 void draw(Scalar alpha
= 0.0) const
95 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
98 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
101 //glEnableClientState(GL_VERTEX_ARRAY);
102 //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
104 //glVertexPointer(3, GL_SCALAR, 0, vertices_);
105 //glTexCoordPointer(2, GL_SCALAR, 0, texCoords_);
107 //glDrawArrays(GL_TRIANGLE_FAN, 0, sizeof(vertices_));
109 //glDisableClientState(GL_VERTEX_ARRAY);
110 //glDisableClientState(GL_TEXTURE_COORD_ARRAY);
112 glBegin(GL_TRIANGLE_FAN
);
113 glTexCoord2f(texCoords_
[0], texCoords_
[1]);
114 glVertex3v(vertices_
);
115 glTexCoord2f(texCoords_
[2], texCoords_
[3]);
116 glVertex3v(vertices_
+3);
117 glTexCoord2f(texCoords_
[4], texCoords_
[5]);
118 glVertex3v(vertices_
+6);
119 glTexCoord2f(texCoords_
[6], texCoords_
[7]);
120 glVertex3v(vertices_
+9);
126 bool isVisible(const Camera
& cam
) const
128 return aabb_
.isVisible(cam
);
132 Scalar vertices_
[12];
133 Scalar texCoords_
[8];
143 static void loadBox(Aabb
& theBox
, SerializablePtr obj
)
145 std::vector
<SerializablePtr
> numbers
;
147 if (obj
->get(numbers
) && numbers
.size() == 6)
151 if (numbers
[0]->getNumber(num
)) theBox
.min
[0] = Scalar(num
);
152 if (numbers
[1]->getNumber(num
)) theBox
.min
[1] = Scalar(num
);
153 if (numbers
[2]->getNumber(num
)) theBox
.min
[2] = Scalar(num
);
154 if (numbers
[3]->getNumber(num
)) theBox
.max
[0] = Scalar(num
);
155 if (numbers
[4]->getNumber(num
)) theBox
.max
[1] = Scalar(num
);
156 if (numbers
[5]->getNumber(num
)) theBox
.max
[2] = Scalar(num
);
161 SceneImpl(const std::string
& name
) :
162 Mippleton
<SceneImpl
>(name
)
168 void loadInstructions(SerializablePtr root
)
170 std::vector
<SerializablePtr
> rootObj
;
171 std::vector
<SerializablePtr
>::iterator it
;
173 if (!root
->get(rootObj
))
175 std::cerr
<< "error loading scene instructions" << std::endl
;
182 for (it
= rootObj
.begin(); it
!= rootObj
.end(); ++it
)
184 std::string instruction
;
186 if ((*it
)->get(instruction
))
188 if (instruction
== "reset_transform")
190 transform
.identity();
192 else if (instruction
== "translate")
194 std::vector
<SerializablePtr
> values
;
197 if ((*it
)->get(values
))
201 for (size_t i
= 0; i
< values
.size(); ++i
)
205 if (values
[i
]->getNumber(value
))
212 cml::matrix_translation(translation
, vec
);
213 transform
= translation
* transform
;
216 else if (instruction
== "scale")
218 std::vector
<SerializablePtr
> values
;
221 if ((*it
)->get(values
))
223 if (values
.size() == 1)
227 values
[0]->getNumber(value
);
230 cml::matrix_uniform_scale(scaling
,
232 transform
= scaling
* transform
;
234 else if (values
.size() == 3)
238 for (size_t i
= 0; i
< values
.size(); ++i
)
242 if (values
[i
]->getNumber(value
))
249 cml::matrix_scale(scaling
, vec
);
250 transform
= scaling
* transform
;
254 else if (instruction
== "rotate")
256 std::vector
<SerializablePtr
> values
;
259 if ((*it
)->get(values
))
261 if (values
.size() == 2)
267 if (values
[0]->get(axis
))
269 if (axis
== "x") index
= 0;
270 else if (axis
== "y") index
= 1;
271 else if (axis
== "z") index
= 2;
273 values
[1]->getNumber(value
);
276 cml::matrix_rotate_about_world_axis(transform
,
277 index
, cml::rad(Scalar(value
)));
281 else if (instruction
== "texture")
286 else if (instruction
== "tilemap")
289 loadTilemap(*it
, transform
, texture
);
291 else if (instruction
== "billboard")
294 loadBillboard(*it
, transform
, texture
);
301 void loadTilemap(SerializablePtr root
, const Matrix4
& transform
,
302 const std::string
& texture
)
304 std::map
<std::string
,SerializablePtr
> rootObj
;
305 std::map
<std::string
,SerializablePtr
>::iterator it
;
307 if (!root
->get(rootObj
))
309 std::cerr
<< "error loading scene tilemap object" << std::endl
;
315 std::vector
< std::vector
<Tilemap::Index
> > indices
;
317 if ((it
= rootObj
.find("width")) != rootObj
.end())
319 (*it
).second
->get(width
);
323 std::cerr
<< "width is a required field of a tilemap" << std::endl
;
327 std::vector
<SerializablePtr
> tiles
;
329 if ((it
= rootObj
.find("tiles")) != rootObj
.end() &&
330 (*it
).second
->get(tiles
) &&
331 tiles
.size() % width
== 0)
333 std::vector
<SerializablePtr
>::iterator jt
;
336 height
= tiles
.size() / width
;
337 indices
.resize(height
);
339 // the indices are stored upside-down in the scene file so that they
340 // are easier to edit as text, so we'll need to load them last row
343 for (h
= height
- 1, jt
= tiles
.begin(); jt
!= tiles
.end(); --h
)
345 std::vector
<Tilemap::Index
> row
;
347 for (w
= 0; w
< width
&& jt
!= tiles
.end(); ++w
, ++jt
)
351 if ((*jt
)->get(index
))
353 row
.push_back(Tilemap::Index(index
));
362 std::cerr
<< "error loading tiles from tilemap object" << std::endl
;
366 Vector4 vertices
[height
+1][width
+1];
368 Matrix4 transposedTransform
= transform
;
369 transposedTransform
.transpose();
371 for (int h
= 0; h
<= height
; ++h
)
373 for (int w
= 0; w
<= width
; ++w
)
375 vertices
[h
][w
] = Vector4(Scalar(w
), Scalar(h
), 0.0, 1.0) *
380 for (int h
= 0; h
< height
; ++h
)
382 for (int w
= 0; w
< width
; ++w
)
384 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
386 Vector3 quadVertices
[4];
388 demoteVector(quadVertices
[0], vertices
[h
][w
]);
389 demoteVector(quadVertices
[1], vertices
[h
][w
+1]);
390 demoteVector(quadVertices
[2], vertices
[h
+1][w
+1]);
391 demoteVector(quadVertices
[3], vertices
[h
+1][w
]);
393 Quad
* quad
= new Quad(quadVertices
, texture
, indices
[h
][w
]);
394 boost::shared_ptr
<Quad
> quadPtr(quad
);
396 objects
.push_back(quadPtr
);
401 void loadBillboard(SerializablePtr root
, const Matrix4
& transform
,
402 const std::string
& texture
)
404 std::map
<std::string
,SerializablePtr
> rootObj
;
405 std::map
<std::string
,SerializablePtr
>::iterator it
;
407 if (!root
->get(rootObj
))
409 std::cerr
<< "error loading scene billboard object" << std::endl
;
413 Tilemap::Index index
= 0;
415 bool blending
= false;
418 if ((it
= rootObj
.find("tile")) != rootObj
.end())
421 if ((*it
).second
->get(value
))
423 index
= Tilemap::Index(value
);
427 if ((it
= rootObj
.find("u_scale")) != rootObj
.end())
429 (*it
).second
->get(width
);
432 if ((it
= rootObj
.find("blend")) != rootObj
.end())
434 (*it
).second
->get(blending
);
437 if ((it
= rootObj
.find("fog")) != rootObj
.end())
439 (*it
).second
->get(fog
);
443 Vector4 vertices
[2][width
+1];
445 Matrix4 transposedTransform
= transform
;
446 transposedTransform
.transpose();
449 Scalar increment
= 1.0 / Scalar(width
);
451 for (int h
= 0; h
<= 1; ++h
)
454 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
456 vertices
[h
][w
] = Vector4(xf
, Scalar(h
), 0.0, 1.0) *
461 for (int w
= 0; w
< width
; ++w
)
463 Vector3 quadVertices
[4];
465 demoteVector(quadVertices
[0], vertices
[0][w
]);
466 demoteVector(quadVertices
[1], vertices
[0][w
+1]);
467 demoteVector(quadVertices
[2], vertices
[1][w
+1]);
468 demoteVector(quadVertices
[3], vertices
[1][w
]);
470 Quad
* quad
= new Quad(quadVertices
, texture
, index
);
471 quad
->setBlending(blending
);
474 boost::shared_ptr
<Quad
> quadPtr(quad
);
476 objects
.push_back(quadPtr
);
483 std::string filePath
= Scene::getPathToResource(getName());
485 Deserializer
deserializer(filePath
, true);
486 SerializablePtr root
= deserializer
.deserialize();
488 std::map
<std::string
,SerializablePtr
> rootObj
;
489 std::map
<std::string
,SerializablePtr
>::iterator it
;
491 if (!root
|| !root
->get(rootObj
))
493 std::cerr
<< "error loading scene file" << std::endl
;
497 if ((it
= rootObj
.find("playfield_bounds")) != rootObj
.end())
499 loadBox(playfieldBounds
, (*it
).second
);
501 if ((it
= rootObj
.find("maximum_bounds")) != rootObj
.end())
503 loadBox(maximumBounds
, (*it
).second
);
505 if ((it
= rootObj
.find("instructions")) != rootObj
.end())
507 loadInstructions((*it
).second
);
512 void draw(Scalar alpha
)
514 QuadVector::iterator it
;
516 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
518 //std::cout << "draw object";
522 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
524 glBindTexture(GL_TEXTURE_2D
, 0);
525 glColor3f(0.0f
, 1.0f
, 0.0f
);
526 playfieldBounds
.draw();
527 glColor3f(0.0f
, 0.0f
, 1.0f
);
528 maximumBounds
.draw();
530 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
534 Aabb playfieldBounds
;
537 typedef std::vector
< boost::shared_ptr
<Quad
> > QuadVector
;
542 Scene::Scene(const std::string
& name
) :
544 impl_(Scene::SceneImpl::retain(name
), &Scene::SceneImpl::release
) {}
547 void Scene::draw(Scalar alpha
) const
553 void Scene::refresh()
555 impl_
->objects
.clear();
556 impl_
->loadFromFile();
561 * Specialized search location for scene files. They can be found in the
562 * "scenes" subdirectory of any of the searched directories.
565 std::string
Scene::getPathToResource(const std::string
& name
)
567 return Resource::getPathToResource("scenes/" + name
+ ".json");
573 /** vim: set ts=4 sw=4 tw=80: *************************************************/