]> Dogcows Code - chaz/yoink/blob - src/Moof/Scene.cc
418c0512e3c690e4f29406181cac8346c67ada80
[chaz/yoink] / src / Moof / Scene.cc
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
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.
15
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.
26
27 *******************************************************************************/
28
29 #include <map>
30 #include <vector>
31
32 #include "Aabb.hh"
33 #include "Camera.hh"
34 #include "Deserializer.hh"
35 #include "Entity.hh"
36 #include "Log.hh"
37 #include "Math.hh"
38 #include "Scene.hh"
39 #include "Serializable.hh"
40 #include "Tilemap.hh"
41
42
43 namespace Mf {
44
45
46 static void loadBox(Aabb& theBox, SerializableP obj)
47 {
48 Serializable::Array numbers;
49
50 if (obj->get(numbers) && numbers.size() == 6)
51 {
52 Serializable::Float num;
53
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);
60 }
61 }
62
63
64 static void loadTilemap(SerializableP root, const Matrix4& transform,
65 const std::string& texture, OctreeP octree)
66 {
67 Serializable::Map rootObj;
68 Serializable::Map::iterator it;
69
70 if (!root->get(rootObj))
71 {
72 logError("invalid tilemap instruction");
73 return;
74 }
75
76 long width = 1;
77 long height = 1;
78 std::vector< std::vector<Tilemap::Index> > indices;
79
80 if ((it = rootObj.find("width")) != rootObj.end())
81 {
82 (*it).second->get(width);
83 }
84 else
85 {
86 logError("missing required field width for tilemap instruction");
87 return;
88 }
89
90 Serializable::Array tiles;
91
92 if ((it = rootObj.find("tiles")) != rootObj.end() &&
93 (*it).second->get(tiles) &&
94 tiles.size() % width == 0)
95 {
96 Serializable::Array::iterator jt;
97 int w, h;
98
99 height = tiles.size() / width;
100 indices.resize(height);
101
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
104 // first
105
106 for (h = height - 1, jt = tiles.begin(); jt != tiles.end(); --h)
107 {
108 std::vector<Tilemap::Index> row;
109
110 for (w = 0; w < width && jt != tiles.end(); ++w, ++jt)
111 {
112 Serializable::Integer index;
113
114 if ((*jt)->get(index))
115 {
116 row.push_back(Tilemap::Index(index));
117 }
118 }
119
120 indices[h] = row;
121 }
122 }
123 else
124 {
125 logError("invalid tiles in tilemap instruction");
126 return;
127 }
128
129 Vector4 vertices[height+1][width+1];
130
131 Matrix4 transposedTransform = transform;
132 transposedTransform.transpose();
133
134 for (int h = 0; h <= height; ++h)
135 {
136 for (int w = 0; w <= width; ++w)
137 {
138 vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) *
139 transposedTransform;
140 }
141 }
142
143 for (int h = 0; h < height; ++h)
144 {
145 for (int w = 0; w < width; ++w)
146 {
147 if (indices[h][w] == Tilemap::NO_TILE) continue;
148
149 Vector3 quadVertices[4];
150
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]);
155
156 Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
157 boost::shared_ptr<Quad> quadPtr(quad);
158
159 octree->insert(quadPtr);
160 }
161 }
162 }
163
164 static void loadBillboard(SerializableP root, const Matrix4& transform,
165 const std::string& texture, OctreeP octree)
166 {
167 Serializable::Map rootObj;
168 Serializable::Map::iterator it;
169
170 Tilemap::Index index = 0;
171 long width = 1;
172 bool blending = false;
173 bool fog = false;
174
175 if (root->get(rootObj))
176 {
177 if ((it = rootObj.find("tile")) != rootObj.end())
178 {
179 Serializable::Integer value;
180 if ((*it).second->get(value))
181 {
182 index = Tilemap::Index(value);
183 }
184 }
185
186 if ((it = rootObj.find("u_scale")) != rootObj.end())
187 {
188 (*it).second->get(width);
189 }
190
191 if ((it = rootObj.find("blend")) != rootObj.end())
192 {
193 (*it).second->get(blending);
194 }
195
196 if ((it = rootObj.find("fog")) != rootObj.end())
197 {
198 (*it).second->get(fog);
199 }
200 }
201
202
203 Vector4 vertices[2][width+1];
204
205 Matrix4 transposedTransform = transform;
206 transposedTransform.transpose();
207
208 Scalar xf;
209 Scalar increment = 1.0 / Scalar(width);
210
211 for (int h = 0; h <= 1; ++h)
212 {
213 xf = 0.0;
214 for (int w = 0; w <= width; ++w, xf += increment)
215 {
216 vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) *
217 transposedTransform;
218 }
219 }
220
221 for (int w = 0; w < width; ++w)
222 {
223 Vector3 quadVertices[4];
224
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]);
229
230 Quad* quad = new Quad(quadVertices, texture, index);
231 quad->setBlending(blending);
232 quad->setFog(fog);
233
234 boost::shared_ptr<Quad> quadPtr(quad);
235
236 octree->insert(quadPtr);
237 }
238 }
239
240
241 static void loadInstructions(SerializableP root, OctreeP octree)
242 {
243 Serializable::Array rootObj;
244 Serializable::Array::iterator it;
245
246 if (!root->get(rootObj))
247 {
248 logError("scene instructions must be an array");
249 return;
250 }
251
252 Matrix4 transform;
253 std::string texture;
254
255 for (it = rootObj.begin(); it != rootObj.end(); ++it)
256 {
257 std::string instruction;
258
259 if ((*it)->get(instruction))
260 {
261 if (instruction == "reset_transform")
262 {
263 transform.identity();
264 }
265 else if (instruction == "translate")
266 {
267 Serializable::Array values;
268
269 ++it;
270 if ((*it)->get(values))
271 {
272 Vector3 vec;
273
274 for (size_t i = 0; i < values.size(); ++i)
275 {
276 Serializable::Float value;
277
278 if (values[i]->getNumber(value))
279 {
280 vec[i] = value;
281 }
282 }
283
284 Matrix4 translation;
285 cml::matrix_translation(translation, vec);
286 transform = translation * transform;
287 }
288 }
289 else if (instruction == "scale")
290 {
291 Serializable::Array values;
292
293 ++it;
294 if ((*it)->get(values))
295 {
296 if (values.size() == 1)
297 {
298 Serializable::Float value = 1.0;
299
300 values[0]->getNumber(value);
301
302 Matrix4 scaling;
303 cml::matrix_uniform_scale(scaling,
304 Scalar(value));
305 transform = scaling * transform;
306 }
307 else if (values.size() == 3)
308 {
309 Vector3 vec;
310
311 for (size_t i = 0; i < values.size(); ++i)
312 {
313 Serializable::Float value;
314
315 if (values[i]->getNumber(value))
316 {
317 vec[i] = value;
318 }
319 }
320
321 Matrix4 scaling;
322 cml::matrix_scale(scaling, vec);
323 transform = scaling * transform;
324 }
325 }
326 }
327 else if (instruction == "rotate")
328 {
329 Serializable::Array values;
330
331 ++it;
332 if ((*it)->get(values))
333 {
334 if (values.size() == 2)
335 {
336 std::string axis;
337 size_t index = 0;
338 Serializable::Float value = 0.0;
339
340 if (values[0]->get(axis))
341 {
342 if (axis == "x") index = 0;
343 else if (axis == "y") index = 1;
344 else if (axis == "z") index = 2;
345
346 values[1]->getNumber(value);
347 }
348
349 cml::matrix_rotate_about_world_axis(transform,
350 index, cml::rad(Scalar(value)));
351 }
352 }
353 }
354 else if (instruction == "texture")
355 {
356 ++it;
357 (*it)->get(texture);
358 }
359 else if (instruction == "tilemap")
360 {
361 ++it;
362 loadTilemap(*it, transform, texture, octree);
363 }
364 else if (instruction == "billboard")
365 {
366 ++it;
367 loadBillboard(*it, transform, texture, octree);
368 }
369 }
370 }
371 }
372
373
374 static std::string getPath(const std::string& name)
375 {
376 return Resource::getPath("scenes/" + name + ".json");
377 }
378
379 OctreeP loadScene(const std::string& name)
380 {
381 std::string filePath = getPath(name);
382
383 Deserializer deserializer(filePath, true);
384 SerializableP root = deserializer.deserialize();
385
386 Serializable::Map rootObj;
387 Serializable::Map::iterator it;
388
389 if (!root || !root->get(rootObj))
390 {
391 logError("no root map in scene file");
392 return OctreeP();
393 }
394
395 Aabb playfieldBounds;
396 Aabb maximumBounds;
397
398 if ((it = rootObj.find("playfield_bounds")) != rootObj.end())
399 {
400 loadBox(playfieldBounds, (*it).second);
401 }
402 if ((it = rootObj.find("maximum_bounds")) != rootObj.end())
403 {
404 loadBox(maximumBounds, (*it).second);
405 }
406 else
407 {
408 logError("missing required maximum bounds");
409 return OctreeP();
410 }
411
412 // create the tree to store the quads
413 OctreeP octree = Octree::alloc(maximumBounds);
414
415 if ((it = rootObj.find("instructions")) != rootObj.end())
416 {
417 loadInstructions((*it).second, octree);
418 }
419
420 octree->sort();
421
422 return octree;
423 }
424
425
426 } // namespace Mf
427
428 /** vim: set ts=4 sw=4 tw=80: *************************************************/
429
This page took 0.049643 seconds and 3 git commands to generate.