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"
39 #include "Serializable.hh"
46 static void loadBox(Aabb
& theBox
, SerializableP obj
)
48 Serializable::Array numbers
;
50 if (obj
->get(numbers
) && numbers
.size() == 6)
52 Serializable::Float num
;
54 if (numbers
[0]->getNumber(num
)) theBox
.min
[0] = Scalar(num
);
55 if (numbers
[1]->getNumber(num
)) theBox
.min
[1] = Scalar(num
);
56 if (numbers
[2]->getNumber(num
)) theBox
.min
[2] = Scalar(num
);
57 if (numbers
[3]->getNumber(num
)) theBox
.max
[0] = Scalar(num
);
58 if (numbers
[4]->getNumber(num
)) theBox
.max
[1] = Scalar(num
);
59 if (numbers
[5]->getNumber(num
)) theBox
.max
[2] = Scalar(num
);
64 static void loadTilemap(SerializableP root
, const Matrix4
& transform
,
65 const std::string
& texture
, OctreeP octree
)
67 Serializable::Map rootObj
;
68 Serializable::Map::iterator it
;
70 if (!root
->get(rootObj
))
72 logError("invalid tilemap instruction");
78 std::vector
< std::vector
<Tilemap::Index
> > indices
;
80 if ((it
= rootObj
.find("width")) != rootObj
.end())
82 (*it
).second
->get(width
);
86 logError("missing required field width for tilemap instruction");
90 Serializable::Array tiles
;
92 if ((it
= rootObj
.find("tiles")) != rootObj
.end() &&
93 (*it
).second
->get(tiles
) &&
94 tiles
.size() % width
== 0)
96 Serializable::Array::iterator jt
;
99 height
= tiles
.size() / width
;
100 indices
.resize(height
);
102 // the indices are stored upside-down in the scene file so that they
103 // are easier to edit as text, so we'll need to load them last row
106 for (h
= height
- 1, jt
= tiles
.begin(); jt
!= tiles
.end(); --h
)
108 std::vector
<Tilemap::Index
> row
;
110 for (w
= 0; w
< width
&& jt
!= tiles
.end(); ++w
, ++jt
)
112 Serializable::Integer index
;
114 if ((*jt
)->get(index
))
116 row
.push_back(Tilemap::Index(index
));
125 logError("invalid tiles in tilemap instruction");
129 Vector4 vertices
[height
+1][width
+1];
131 Matrix4 transposedTransform
= transform
;
132 transposedTransform
.transpose();
134 for (int h
= 0; h
<= height
; ++h
)
136 for (int w
= 0; w
<= width
; ++w
)
138 vertices
[h
][w
] = Vector4(Scalar(w
), Scalar(h
), 0.0, 1.0) *
143 for (int h
= 0; h
< height
; ++h
)
145 for (int w
= 0; w
< width
; ++w
)
147 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
149 Vector3 quadVertices
[4];
151 demoteVector(quadVertices
[0], vertices
[h
][w
]);
152 demoteVector(quadVertices
[1], vertices
[h
][w
+1]);
153 demoteVector(quadVertices
[2], vertices
[h
+1][w
+1]);
154 demoteVector(quadVertices
[3], vertices
[h
+1][w
]);
156 Quad
* quad
= new Quad(quadVertices
, texture
, indices
[h
][w
]);
157 boost::shared_ptr
<Quad
> quadPtr(quad
);
159 octree
->insert(quadPtr
);
164 static void loadBillboard(SerializableP root
, const Matrix4
& transform
,
165 const std::string
& texture
, OctreeP octree
)
167 Serializable::Map rootObj
;
168 Serializable::Map::iterator it
;
170 Tilemap::Index index
= 0;
172 bool blending
= false;
175 if (root
->get(rootObj
))
177 if ((it
= rootObj
.find("tile")) != rootObj
.end())
179 Serializable::Integer value
;
180 if ((*it
).second
->get(value
))
182 index
= Tilemap::Index(value
);
186 if ((it
= rootObj
.find("u_scale")) != rootObj
.end())
188 (*it
).second
->get(width
);
191 if ((it
= rootObj
.find("blend")) != rootObj
.end())
193 (*it
).second
->get(blending
);
196 if ((it
= rootObj
.find("fog")) != rootObj
.end())
198 (*it
).second
->get(fog
);
203 Vector4 vertices
[2][width
+1];
205 Matrix4 transposedTransform
= transform
;
206 transposedTransform
.transpose();
209 Scalar increment
= 1.0 / Scalar(width
);
211 for (int h
= 0; h
<= 1; ++h
)
214 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
216 vertices
[h
][w
] = Vector4(xf
, Scalar(h
), 0.0, 1.0) *
221 for (int w
= 0; w
< width
; ++w
)
223 Vector3 quadVertices
[4];
225 demoteVector(quadVertices
[0], vertices
[0][w
]);
226 demoteVector(quadVertices
[1], vertices
[0][w
+1]);
227 demoteVector(quadVertices
[2], vertices
[1][w
+1]);
228 demoteVector(quadVertices
[3], vertices
[1][w
]);
230 Quad
* quad
= new Quad(quadVertices
, texture
, index
);
231 quad
->setBlending(blending
);
234 boost::shared_ptr
<Quad
> quadPtr(quad
);
236 octree
->insert(quadPtr
);
241 static void loadInstructions(SerializableP root
, OctreeP octree
)
243 Serializable::Array rootObj
;
244 Serializable::Array::iterator it
;
246 if (!root
->get(rootObj
))
248 logError("scene instructions must be an array");
255 for (it
= rootObj
.begin(); it
!= rootObj
.end(); ++it
)
257 std::string instruction
;
259 if ((*it
)->get(instruction
))
261 if (instruction
== "reset_transform")
263 transform
.identity();
265 else if (instruction
== "translate")
267 Serializable::Array values
;
270 if ((*it
)->get(values
))
274 for (size_t i
= 0; i
< values
.size(); ++i
)
276 Serializable::Float value
;
278 if (values
[i
]->getNumber(value
))
285 cml::matrix_translation(translation
, vec
);
286 transform
= translation
* transform
;
289 else if (instruction
== "scale")
291 Serializable::Array values
;
294 if ((*it
)->get(values
))
296 if (values
.size() == 1)
298 Serializable::Float value
= 1.0;
300 values
[0]->getNumber(value
);
303 cml::matrix_uniform_scale(scaling
,
305 transform
= scaling
* transform
;
307 else if (values
.size() == 3)
311 for (size_t i
= 0; i
< values
.size(); ++i
)
313 Serializable::Float value
;
315 if (values
[i
]->getNumber(value
))
322 cml::matrix_scale(scaling
, vec
);
323 transform
= scaling
* transform
;
327 else if (instruction
== "rotate")
329 Serializable::Array values
;
332 if ((*it
)->get(values
))
334 if (values
.size() == 2)
338 Serializable::Float value
= 0.0;
340 if (values
[0]->get(axis
))
342 if (axis
== "x") index
= 0;
343 else if (axis
== "y") index
= 1;
344 else if (axis
== "z") index
= 2;
346 values
[1]->getNumber(value
);
349 cml::matrix_rotate_about_world_axis(transform
,
350 index
, cml::rad(Scalar(value
)));
354 else if (instruction
== "texture")
359 else if (instruction
== "tilemap")
362 loadTilemap(*it
, transform
, texture
, octree
);
364 else if (instruction
== "billboard")
367 loadBillboard(*it
, transform
, texture
, octree
);
374 static std::string
getPath(const std::string
& name
)
376 return Resource::getPath("scenes/" + name
+ ".json");
379 OctreeP
loadScene(const std::string
& name
)
381 std::string filePath
= getPath(name
);
383 Deserializer
deserializer(filePath
, true);
384 SerializableP root
= deserializer
.deserialize();
386 Serializable::Map rootObj
;
387 Serializable::Map::iterator it
;
389 if (!root
|| !root
->get(rootObj
))
391 logError("no root map in scene file");
395 Aabb playfieldBounds
;
398 if ((it
= rootObj
.find("playfield_bounds")) != rootObj
.end())
400 loadBox(playfieldBounds
, (*it
).second
);
402 if ((it
= rootObj
.find("maximum_bounds")) != rootObj
.end())
404 loadBox(maximumBounds
, (*it
).second
);
408 logError("missing required maximum bounds");
412 // create the tree to store the quads
413 OctreeP octree
= Octree::alloc(maximumBounds
);
415 if ((it
= rootObj
.find("instructions")) != rootObj
.end())
417 loadInstructions((*it
).second
, octree
);
428 /** vim: set ts=4 sw=4 tw=80: *************************************************/