]> Dogcows Code - chaz/yoink/blob - src/Moof/Scene.cc
new lua scripting for scene loading
[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 "Entity.hh"
35 #include "Log.hh"
36 #include "Math.hh"
37 #include "Scene.hh"
38 #include "Script.hh"
39 #include "Settings.hh"
40 #include "Tilemap.hh"
41
42
43 namespace Mf {
44
45
46 static std::string getPath(const std::string& name)
47 {
48 return Resource::getPath("scenes/" + name + ".lua");
49 }
50
51
52 struct Meh
53 {
54 Matrix4 transform;
55 std::string texture;
56
57 OctreeP octree;
58
59 Meh()
60 {
61 octree = Octree::alloc(Aabb());
62 }
63
64 static int loadBox(Script& script, Aabb& aabb)
65 {
66 Script::Value table[] = {script[1], script[2]};
67
68 if (!table[0].isTable() || !table[1].isTable())
69 {
70 logWarning("wrong arguments to setPlayfieldBounds; ignoring...");
71 return 0;
72 }
73
74 for (int i = 0; i <= 1; ++i)
75 {
76 for (int j = 1; j <= 3; ++j)
77 {
78 script.push((long)j);
79 table[i].pushField();
80 }
81 }
82
83 script[3].get(aabb.min[0]);
84 script[4].get(aabb.min[1]);
85 script[5].get(aabb.min[2]);
86 script[6].get(aabb.max[0]);
87 script[7].get(aabb.max[1]);
88 script[8].get(aabb.max[2]);
89
90 return 0;
91 }
92
93 int setPlayfieldBounds(Script& script)
94 {
95 Aabb bounds;
96 return loadBox(script, bounds);
97 }
98
99 int setMaximumBounds(Script& script)
100 {
101 Aabb bounds;
102 int ret = loadBox(script, bounds);
103 octree = Octree::alloc(bounds);
104 return ret;
105 }
106
107 int resetTransform(Script& script)
108 {
109 transform.identity();
110 return 0;
111 }
112
113 int translate(Script& script)
114 {
115 Script::Value x = script[1];
116 Script::Value y = script[2];
117 Script::Value z = script[3];
118
119 if (!x.isNumber() || !y.isNumber() || !z.isNumber())
120 {
121 logWarning("wrong arguments to translate; ignoring...");
122 return 0;
123 }
124
125 Vector3 vec;
126 x.get(vec[0]);
127 y.get(vec[1]);
128 z.get(vec[2]);
129
130 Matrix4 translation;
131 cml::matrix_translation(translation, vec);
132 transform = translation * transform;
133
134 return 0;
135 }
136
137 int scale(Script& script)
138 {
139 if (script.getSize() == 3)
140 {
141 Vector3 vec;
142 script[1].get(vec[0]);
143 script[2].get(vec[1]);
144 script[3].get(vec[2]);
145
146 Matrix4 scaling;
147 cml::matrix_scale(scaling, vec);
148 transform = scaling * transform;
149 }
150 else if (script.getSize() == 1)
151 {
152 Scalar value = 1.0;
153 script[1].get(value);
154
155 Matrix4 scaling;
156 cml::matrix_uniform_scale(scaling,
157 Scalar(value));
158 transform = scaling * transform;
159 }
160 else
161 {
162 logWarning("wrong arguments to scale; ignoring...");
163 }
164
165 return 0;
166 }
167
168 int rotate(Script& script)
169 {
170 Script::Value a = script[1];
171 Script::Value d = script[2];
172
173 if (!a.isString() || !d.isNumber())
174 {
175 logWarning("wrong arguments to rotate; ignoring...");
176 return 0;
177 }
178
179 std::string axis;
180 a.get(axis);
181
182 size_t index = 0;
183 if (axis == "x") index = 0;
184 else if (axis == "y") index = 1;
185 else if (axis == "z") index = 2;
186
187 Scalar value;
188 d.get(value);
189
190 cml::matrix_rotate_about_world_axis(transform,
191 index, cml::rad(Scalar(value)));
192
193 return 0;
194 }
195
196 int setTexture(Script& script)
197 {
198 Script::Value t = script[1];
199
200 if (t.isString()) t.get(texture);
201 else logWarning("wrong arguments to setTexture; ignoring...");
202
203 return 0;
204 }
205
206 int makeTilemap(Script& script)
207 {
208 Script::Value table = script[1];
209 Script::Value top = script[-1];
210
211 if (!table.isTable())
212 {
213 logWarning("wrong arguments to makeTilemap; ignoring...");
214 return 0;
215 }
216
217 long width = 1;
218 long height = 1;
219
220 table.pushField("width");
221 top.get(width);
222
223 long nTiles = 0;
224
225 table.pushField("tiles");
226 Script::Value tiles = script.getTop();
227 nTiles = tiles.getLength();
228
229 std::vector< std::vector<Tilemap::Index> > indices;
230
231 if (nTiles % width == 0)
232 {
233 int i, w, h;
234
235 height = nTiles / width;
236 indices.resize(height);
237
238 // the indices are stored upside-down in the scene file so that they
239 // are easier to edit as text, so we'll need to load them last row
240 // first
241
242 i = 1;
243 for (h = height - 1; h >= 0; --h)
244 {
245 std::vector<Tilemap::Index> row;
246
247 for (w = 0; w < width; ++w, ++i)
248 {
249 script.checkStack(2);
250 script.push(long(i));
251 tiles.pushField();
252
253 long index;
254 top.get(index);
255
256 row.push_back(Tilemap::Index(index));
257 }
258
259 indices[h] = row;
260 }
261 }
262 else
263 {
264 logError("invalid tiles in tilemap instruction");
265 return 0;
266 }
267
268 Vector4 vertices[height+1][width+1];
269
270 Matrix4 transposedTransform = transform;
271 transposedTransform.transpose();
272
273 for (int h = 0; h <= height; ++h)
274 {
275 for (int w = 0; w <= width; ++w)
276 {
277 vertices[h][w] = Vector4(Scalar(w), Scalar(h), 0.0, 1.0) *
278 transposedTransform;
279 }
280 }
281
282 for (int h = 0; h < height; ++h)
283 {
284 for (int w = 0; w < width; ++w)
285 {
286 if (indices[h][w] == Tilemap::NO_TILE) continue;
287
288 Vector3 quadVertices[4];
289
290 demoteVector(quadVertices[0], vertices[h][w]);
291 demoteVector(quadVertices[1], vertices[h][w+1]);
292 demoteVector(quadVertices[2], vertices[h+1][w+1]);
293 demoteVector(quadVertices[3], vertices[h+1][w]);
294
295 Quad* quad = new Quad(quadVertices, texture, indices[h][w]);
296 boost::shared_ptr<Quad> quadPtr(quad);
297
298 octree->insert(quadPtr);
299 }
300 }
301
302 return 0;
303 }
304
305 int makeBillboard(Script& script)
306 {
307 Script::Value table = script[1];
308 Script::Value top = script[-1];
309
310 long index = 0;
311 long width = 1;
312 bool blending = false;
313 bool fog = false;
314
315 if (table.isTable())
316 {
317 table.pushField("tile");
318 if (top.isNumber()) top.get(index);
319
320 table.pushField("u_scale");
321 if (top.isNumber()) top.get(width);
322
323 table.pushField("blend");
324 if (top.isBoolean()) top.get(blending);
325
326 table.pushField("fog");
327 if (top.isBoolean()) top.get(fog);
328 }
329
330 Vector4 vertices[2][width+1];
331
332 Matrix4 transposedTransform = transform;
333 transposedTransform.transpose();
334
335 Scalar xf;
336 Scalar increment = 1.0 / Scalar(width);
337
338 for (int h = 0; h <= 1; ++h)
339 {
340 xf = 0.0;
341 for (int w = 0; w <= width; ++w, xf += increment)
342 {
343 vertices[h][w] = Vector4(xf, Scalar(h), 0.0, 1.0) *
344 transposedTransform;
345 }
346 }
347
348 for (int w = 0; w < width; ++w)
349 {
350 Vector3 quadVertices[4];
351
352 demoteVector(quadVertices[0], vertices[0][w]);
353 demoteVector(quadVertices[1], vertices[0][w+1]);
354 demoteVector(quadVertices[2], vertices[1][w+1]);
355 demoteVector(quadVertices[3], vertices[1][w]);
356
357 Quad* quad = new Quad(quadVertices, texture, Tilemap::Index(index));
358 quad->setBlending(blending);
359 quad->setFog(fog);
360
361 boost::shared_ptr<Quad> quadPtr(quad);
362
363 octree->insert(quadPtr);
364 }
365
366 return 0;
367 }
368 };
369
370
371 static int luaPrint(Script& script)
372 {
373 Script::Value param = script[1];
374
375 while (!param.isNone())
376 {
377 if (param.isString())
378 {
379 std::string str;
380 param.get(str);
381 logInfo("lua: %s", str.c_str());
382 }
383 else if (param.isBoolean())
384 {
385 if (param) logInfo("lua: true");
386 else logInfo("lua: false");
387
388 }
389 else if (param.isNil())
390 {
391 logInfo("lua: nil");
392 }
393 else
394 {
395 logInfo("lua: %s (%X)", param.getTypeName().c_str(),
396 param.getIdentifier());
397 }
398
399 param.index++;
400 }
401
402 return 0;
403 }
404
405 static void importScriptBindings(Script& script, Meh& scene)
406 {
407 script.importFunction("SetPlayfieldBounds",
408 boost::bind(&Meh::setPlayfieldBounds, &scene, _1));
409 script.importFunction("SetMaximumBounds",
410 boost::bind(&Meh::setMaximumBounds, &scene, _1));
411 script.importFunction("ResetTransform",
412 boost::bind(&Meh::resetTransform, &scene, _1));
413 script.importFunction("Translate",
414 boost::bind(&Meh::translate, &scene, _1));
415 script.importFunction("Scale",
416 boost::bind(&Meh::scale, &scene, _1));
417 script.importFunction("Rotate",
418 boost::bind(&Meh::rotate, &scene, _1));
419 script.importFunction("SetTexture",
420 boost::bind(&Meh::setTexture, &scene, _1));
421 script.importFunction("MakeTilemap",
422 boost::bind(&Meh::makeTilemap, &scene, _1));
423 script.importFunction("MakeBillboard",
424 boost::bind(&Meh::makeBillboard, &scene, _1));
425 script.importFunction("print", luaPrint);
426 }
427
428
429 OctreeP loadScene(const std::string& name)
430 {
431 std::string filePath = getPath(name);
432
433 Script script;
434 script.importStandardLibraries();
435
436 Meh cool;
437 importScriptBindings(script, cool);
438
439 long detail = 3;
440 Settings::getInstance().getNumber("game.detail", detail);
441
442 script.push(detail);
443 script.set("detail");
444
445 logInfo("doing file...");
446 if (script.doFile(filePath) != 0)
447 {
448 std::string str;
449 script[-1].get(str);
450 logError("lua error: %s", str.c_str());
451 }
452 logInfo("done");
453
454 cool.octree->sort();
455 return cool.octree;
456 }
457
458
459 } // namespace Mf
460
461 /** vim: set ts=4 sw=4 tw=80: *************************************************/
462
This page took 0.049699 seconds and 4 git commands to generate.