~ubuntu-branches/ubuntu/precise/frogatto/precise

« back to all changes in this revision

Viewing changes to src/gui_formula_functions.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Dmitry E. Oboukhov
  • Date: 2010-07-21 16:21:45 UTC
  • Revision ID: james.westby@ubuntu.com-20100721162145-zid0u93fm3xz73gh
Tags: upstream-1.0+dfsg1
ImportĀ upstreamĀ versionĀ 1.0+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <boost/bind.hpp>
 
2
#include <boost/function.hpp>
 
3
#include <boost/shared_ptr.hpp>
 
4
 
 
5
#include <assert.h>
 
6
#include <map>
 
7
 
 
8
#include "asserts.hpp"
 
9
#include "custom_object.hpp"
 
10
#include "custom_object_callable.hpp"
 
11
#include "custom_object_functions.hpp"
 
12
#include "custom_object_type.hpp"
 
13
#include "draw_number.hpp"
 
14
#include "formula.hpp"
 
15
#include "formula_callable_definition.hpp"
 
16
#include "frame.hpp"
 
17
#include "graphical_font.hpp"
 
18
#include "gui_formula_functions.hpp"
 
19
#include "iphone_controls.hpp"
 
20
#include "level.hpp"
 
21
#include "preferences.hpp"
 
22
#include "raster.hpp"
 
23
#include "unit_test.hpp"
 
24
#include "wml_node.hpp"
 
25
#include "wml_parser.hpp"
 
26
#include "wml_utils.hpp"
 
27
 
 
28
using namespace game_logic;
 
29
 
 
30
namespace {
 
31
 
 
32
typedef boost::function<void (const gui_algorithm* algo)> gui_command_function;
 
33
 
 
34
class gui_command : public formula_callable {
 
35
        variant get_value(const std::string& key) const { return variant(); }
 
36
public:
 
37
 
 
38
        virtual void execute(const gui_algorithm& algo) = 0;
 
39
};
 
40
 
 
41
class draw_text_command : public gui_command {
 
42
        const_graphical_font_ptr font_;
 
43
        std::string text_;
 
44
        int x_, y_;
 
45
public:
 
46
        draw_text_command(const_graphical_font_ptr font, const std::string& text, int x, int y)
 
47
          : font_(font), text_(text), x_(x), y_(y)
 
48
        {}
 
49
 
 
50
        void execute(const gui_algorithm& algo) {
 
51
                font_->draw(x_, y_, text_);
 
52
        }
 
53
};
 
54
 
 
55
class draw_text_function : public function_expression {
 
56
public:
 
57
        explicit draw_text_function(const args_list& args)
 
58
         : function_expression("draw_text", args, 3, 4)
 
59
        {}
 
60
private:
 
61
        variant execute(const formula_callable& variables) const {
 
62
                std::string font = "default";
 
63
 
 
64
                int arg = 0;
 
65
                if(args().size() == 4) {
 
66
                        font = args()[arg++]->evaluate(variables).as_string();
 
67
                }
 
68
 
 
69
                std::string text = args()[arg++]->evaluate(variables).as_string();
 
70
                const int x = args()[arg++]->evaluate(variables).as_int();
 
71
                const int y = args()[arg++]->evaluate(variables).as_int();
 
72
                return variant(new draw_text_command(graphical_font::get(font), text, x, y));
 
73
        }
 
74
};
 
75
 
 
76
class draw_number_command : public gui_command {
 
77
        graphics::blit_queue blit_;
 
78
public:
 
79
        draw_number_command(int number, int places, int x, int y)
 
80
        {
 
81
                queue_draw_number(blit_, number, places, x, y);
 
82
        }
 
83
 
 
84
        void execute(const gui_algorithm& algo) {
 
85
                blit_.do_blit();
 
86
        }
 
87
};
 
88
 
 
89
class draw_number_function : public function_expression {
 
90
public:
 
91
        explicit draw_number_function(const args_list& args)
 
92
          : function_expression("draw_number", args, 4, 4)
 
93
        {}
 
94
private:
 
95
        variant execute(const formula_callable& variables) const {
 
96
                static cache_entry cache[4];
 
97
                static int cache_loc;
 
98
 
 
99
                const int number = args()[0]->evaluate(variables).as_int();
 
100
                const int places = args()[1]->evaluate(variables).as_int();
 
101
                const int x = args()[2]->evaluate(variables).as_int();
 
102
                const int y = args()[3]->evaluate(variables).as_int();
 
103
                for(int n = 0; n != sizeof(cache)/sizeof(*cache); ++n) {
 
104
                        if(x == cache[n].x && y == cache[n].y && number == cache[n].number && places == cache[n].places) {
 
105
                                return cache[n].result;
 
106
                        }
 
107
                }
 
108
                const int n = cache_loc++%(sizeof(cache)/sizeof(*cache));
 
109
                cache[n].x = x;
 
110
                cache[n].y = y;
 
111
                cache[n].number = number;
 
112
                cache[n].places = places;
 
113
                cache[n].result = variant(new draw_number_command(number, places, x, y));
 
114
                return cache[n].result;
 
115
        }
 
116
 
 
117
        struct cache_entry {
 
118
                cache_entry() : x(-1), y(-1) {}
 
119
                int number, places, x, y;
 
120
                variant result;
 
121
        };
 
122
 
 
123
};
 
124
 
 
125
class draw_animation_area_command : public gui_command {
 
126
        frame_ptr frame_;
 
127
        int x_, y_;
 
128
        rect area_;
 
129
 
 
130
        variant get_value(const std::string& key) const { return variant(); }
 
131
public:
 
132
        draw_animation_area_command(const frame_ptr& f, int x, int y, const rect& area)
 
133
          : frame_(f), x_(x), y_(y), area_(area)
 
134
        {}
 
135
 
 
136
        void execute(const gui_algorithm& algo) {
 
137
                frame_->draw(x_, y_, area_);
 
138
        }
 
139
};
 
140
 
 
141
class draw_animation_area_function : public function_expression {
 
142
public:
 
143
        draw_animation_area_function(gui_algorithm* algo, const args_list& args)
 
144
          : function_expression("draw_animation_area", args, 4, 7), algo_(algo)
 
145
        {}
 
146
 
 
147
        gui_algorithm* algo_;
 
148
private:
 
149
        variant execute(const formula_callable& variables) const {
 
150
                variant anim = args()[0]->evaluate(variables);
 
151
                const frame_ptr f = algo_->get_frame(anim.as_string());
 
152
                if(!f) {
 
153
                        return variant();
 
154
                }
 
155
 
 
156
                const int x = args()[1]->evaluate(variables).as_int();
 
157
                const int y = args()[2]->evaluate(variables).as_int();
 
158
 
 
159
                int vals[4];
 
160
                for(int n = 0; n != args().size() - 3; ++n) {
 
161
                        vals[n] = args()[n+3]->evaluate(variables).as_int();
 
162
                }
 
163
 
 
164
                rect area;
 
165
                if(args().size() == 4) {
 
166
                        area = rect(0, 0, vals[0], f->height()/2);
 
167
                } else if(args().size() == 5) {
 
168
                        area = rect(0, 0, vals[0], vals[1]);
 
169
                                          
 
170
                } else {
 
171
                        ASSERT_EQ(args().size(), 7);
 
172
                        area = rect(vals[0], vals[1], vals[2], vals[3]);
 
173
                }
 
174
 
 
175
                return variant(new draw_animation_area_command(f, x, y, area));
 
176
        }
 
177
};
 
178
 
 
179
class draw_animation_command : public gui_command {
 
180
        graphics::blit_queue blit_;
 
181
        variant get_value(const std::string& key) const { return variant(); }
 
182
public:
 
183
        draw_animation_command(const frame_ptr& f, int x, int y)
 
184
        {
 
185
                f->draw_into_blit_queue(blit_, x, y);
 
186
        }
 
187
 
 
188
        void execute(const gui_algorithm& algo) {
 
189
                blit_.do_blit();
 
190
        }
 
191
};
 
192
 
 
193
class draw_animation_function : public function_expression {
 
194
public:
 
195
        draw_animation_function(gui_algorithm* algo, const args_list& args)
 
196
          : function_expression("draw_animation", args, 3, 3), algo_(algo)
 
197
        {}
 
198
 
 
199
        gui_algorithm* algo_;
 
200
private:
 
201
        variant execute(const formula_callable& variables) const {
 
202
                variant anim = args()[0]->evaluate(variables);
 
203
                const frame_ptr f = algo_->get_frame(anim.as_string());
 
204
                if(!f) {
 
205
                        return variant();
 
206
                }
 
207
 
 
208
                const int x = args()[1]->evaluate(variables).as_int();
 
209
                const int y = args()[2]->evaluate(variables).as_int();
 
210
 
 
211
                return variant(new draw_animation_command(f, x, y));
 
212
        }
 
213
};
 
214
 
 
215
class color_command : public gui_command {
 
216
        unsigned char r_, g_, b_, a_;
 
217
public:
 
218
        color_command(int r, int g, int b, int a) : r_(r), g_(g), b_(b), a_(a)
 
219
        {}
 
220
 
 
221
        void execute(const gui_algorithm& algo) {
 
222
                glColor4ub(r_, g_, b_, a_);
 
223
        }
 
224
};
 
225
 
 
226
class color_function : public function_expression {
 
227
public:
 
228
        explicit color_function(const args_list& args)
 
229
          : function_expression("color", args, 4, 4)
 
230
        {}
 
231
private:
 
232
        variant execute(const formula_callable& variables) const {
 
233
                return variant(new color_command(
 
234
                         args()[0]->evaluate(variables).as_int(),
 
235
                         args()[1]->evaluate(variables).as_int(),
 
236
                         args()[2]->evaluate(variables).as_int(),
 
237
                         args()[3]->evaluate(variables).as_int()));
 
238
        }
 
239
};
 
240
 
 
241
class gui_command_function_symbol_table : public function_symbol_table
 
242
{
 
243
        gui_algorithm* algo_;
 
244
public:
 
245
        gui_command_function_symbol_table(gui_algorithm* algo) : algo_(algo)
 
246
        {}
 
247
 
 
248
        expression_ptr create_function(
 
249
                                   const std::string& fn,
 
250
                                   const std::vector<expression_ptr>& args,
 
251
                                                           const formula_callable_definition* callable_def) const
 
252
        {
 
253
                if(fn == "draw_animation") {
 
254
                        return expression_ptr(new draw_animation_function(algo_, args));
 
255
                } else if(fn == "draw_animation_area") {
 
256
                        return expression_ptr(new draw_animation_area_function(algo_, args));
 
257
                } else if(fn == "draw_number") {
 
258
                        return expression_ptr(new draw_number_function(args));
 
259
                } else if(fn == "draw_text") {
 
260
                        return expression_ptr(new draw_text_function(args));
 
261
                } else if(fn == "color") {
 
262
                        return expression_ptr(new color_function(args));
 
263
                }
 
264
 
 
265
                return function_symbol_table::create_function(fn, args, callable_def);
 
266
        }
 
267
};
 
268
 
 
269
const std::string AlgorithmProperties[] = {
 
270
        "level", "object", "cycle", "screen_width", "screen_height",
 
271
};
 
272
 
 
273
enum ALGORITHM_PROPERTY_ID {
 
274
        ALGO_LEVEL, ALGO_OBJECT, ALGO_CYCLE, ALGO_SCREEN_WIDTH, ALGO_SCREEN_HEIGHT,
 
275
};
 
276
 
 
277
class gui_algorithm_definition : public game_logic::formula_callable_definition
 
278
{
 
279
public:
 
280
        static const gui_algorithm_definition& instance() {
 
281
                static const gui_algorithm_definition def;
 
282
                return def;
 
283
        }
 
284
 
 
285
        gui_algorithm_definition() {
 
286
                for(int n = 0; n != sizeof(AlgorithmProperties)/sizeof(*AlgorithmProperties); ++n) {
 
287
                        entries_.push_back(entry(AlgorithmProperties[n]));
 
288
                        keys_to_slots_[AlgorithmProperties[n]] = n;
 
289
                }
 
290
 
 
291
                entries_[ALGO_OBJECT].type_definition = &custom_object_type::get("dummy_gui_object")->callable_definition();
 
292
                entries_[ALGO_LEVEL].type_definition = &level::get_formula_definition();
 
293
        }
 
294
 
 
295
        int get_slot(const std::string& key) const {
 
296
                std::map<std::string, int>::const_iterator i = keys_to_slots_.find(key);
 
297
                if(i == keys_to_slots_.end()) {
 
298
                        return -1;
 
299
                }
 
300
 
 
301
                return i->second;
 
302
        }
 
303
 
 
304
        const entry* get_entry(int slot) const {
 
305
                if(slot < 0 || slot >= entries_.size()) {
 
306
                        return NULL;
 
307
                }
 
308
 
 
309
                return &entries_[slot];
 
310
        }
 
311
 
 
312
        int num_slots() const {
 
313
                return entries_.size();
 
314
        }
 
315
private:
 
316
        std::vector<entry> entries_;
 
317
        std::map<std::string, int> keys_to_slots_;
 
318
};
 
319
 
 
320
} // namespace
 
321
 
 
322
gui_algorithm::gui_algorithm(wml::const_node_ptr node)
 
323
          : lvl_(NULL),
 
324
          process_formula_(formula::create_optional_formula(node->attr("on_process"), &get_custom_object_functions_symbol_table(), &gui_algorithm_definition::instance())),
 
325
          cycle_(0), object_(new custom_object("dummy_gui_object", 0, 0, true))
 
326
{
 
327
        gui_command_function_symbol_table symbols(this);
 
328
 
 
329
        object_->add_ref();
 
330
        FOREACH_WML_CHILD(frame_node, node, "animation") {
 
331
                frame_ptr f(new frame(frame_node));
 
332
                frames_[frame_node->attr("id")] = f;
 
333
        }
 
334
 
 
335
        draw_formula_ = formula::create_optional_formula(node->attr("on_draw"), &symbols, &gui_algorithm_definition::instance());
 
336
}
 
337
 
 
338
gui_algorithm::~gui_algorithm()
 
339
{
 
340
}
 
341
 
 
342
gui_algorithm_ptr gui_algorithm::get(const std::string& key) {
 
343
        static std::map<std::string, gui_algorithm_ptr> algorithms;
 
344
        gui_algorithm_ptr& ptr = algorithms[key];
 
345
        if(!ptr) {
 
346
                ptr = create(key);
 
347
        }
 
348
 
 
349
        return ptr;
 
350
}
 
351
 
 
352
void gui_algorithm::new_level() {
 
353
        cycle_ = 0;
 
354
        object_ = boost::intrusive_ptr<custom_object>(new custom_object("dummy_gui_object", 0, 0, true));
 
355
}
 
356
 
 
357
void gui_algorithm::process(level& lvl) {
 
358
        lvl_ = &lvl;
 
359
        ++cycle_;
 
360
        if((cycle_%2) == 0 && process_formula_) {
 
361
                object_->set_level(lvl);
 
362
                variant result = process_formula_->execute(*this);
 
363
                object_->execute_command(result);
 
364
        }
 
365
}
 
366
 
 
367
void gui_algorithm::draw(const level& lvl) {
 
368
        lvl_ = &lvl;
 
369
 
 
370
        if((cycle_%2) == 0) {
 
371
                cached_draw_commands_ = variant();
 
372
        }
 
373
 
 
374
        if(cached_draw_commands_.is_null() && draw_formula_) {
 
375
                cached_draw_commands_ = draw_formula_->execute(*this);
 
376
        }
 
377
 
 
378
        execute_command(cached_draw_commands_);
 
379
 
 
380
        glColor4ub(255, 255, 255, 255);
 
381
 
 
382
        iphone_controls::draw();
 
383
}
 
384
 
 
385
void gui_algorithm::execute_command(variant v) {
 
386
        if(v.is_list()) {
 
387
                const int num_elements = v.num_elements();
 
388
                for(int n = 0; n != num_elements; ++n) {
 
389
                        execute_command(v[n]);
 
390
                }
 
391
 
 
392
                return;
 
393
        }
 
394
 
 
395
        gui_command* cmd = v.try_convert<gui_command>();
 
396
        if(cmd) {
 
397
                cmd->execute(*this);
 
398
        }
 
399
}
 
400
 
 
401
gui_algorithm_ptr gui_algorithm::create(const std::string& key) {
 
402
        static const std::string path = preferences::load_compiled() ? "data/compiled/gui/" : "data/gui/";
 
403
        return gui_algorithm_ptr(new gui_algorithm(wml::parse_wml_from_file(path + key + ".cfg")));
 
404
}
 
405
 
 
406
void gui_algorithm::draw_animation(const std::string& object_name, const std::string& anim, int x, int y, int cycle) const {
 
407
        const frame* f = NULL;
 
408
        if(object_name.empty() == false) {
 
409
                const_custom_object_type_ptr obj = custom_object_type::get(object_name);
 
410
                if(obj) {
 
411
                        f = &obj->get_frame(anim);
 
412
                }
 
413
        }
 
414
 
 
415
        if(!f) {
 
416
                const std::map<std::string, frame_ptr>::const_iterator itor = frames_.find(anim);
 
417
                if(itor != frames_.end()) {
 
418
                        f = itor->second.get();
 
419
                }
 
420
        }
 
421
 
 
422
        if(f) {
 
423
                if(cycle == -1) {
 
424
                        cycle = cycle_%f->duration();
 
425
                }
 
426
 
 
427
                f->draw(x, y, true, false, cycle);
 
428
        }
 
429
}
 
430
 
 
431
void gui_algorithm::color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) const
 
432
{
 
433
        glColor4ub(r, g, b, a);
 
434
}
 
435
 
 
436
frame_ptr gui_algorithm::get_frame(const std::string& id) const
 
437
{
 
438
        const std::map<std::string, frame_ptr>::const_iterator itor = frames_.find(id);
 
439
        if(itor != frames_.end()) {
 
440
                return itor->second;
 
441
        } else {
 
442
                return frame_ptr();
 
443
        }
 
444
}
 
445
 
 
446
variant gui_algorithm::get_value(const std::string& key) const
 
447
{
 
448
        if(key == "level") {
 
449
                return variant(lvl_);
 
450
        } else if(key == "object") {
 
451
                return variant(object_.get());
 
452
        } else if(key == "cycle") {
 
453
                return variant(cycle_);
 
454
        } else if(key == "screen_width") {
 
455
                return variant(graphics::screen_width());
 
456
        } else if(key == "screen_height") {
 
457
                return variant(graphics::screen_height());
 
458
        } else {
 
459
                return variant();
 
460
        }
 
461
}
 
462
 
 
463
variant gui_algorithm::get_value_by_slot(int slot) const
 
464
{
 
465
        switch(slot) {
 
466
        case ALGO_LEVEL:
 
467
                return variant(lvl_);
 
468
        case ALGO_OBJECT:
 
469
                return variant(object_.get());
 
470
        case ALGO_CYCLE:
 
471
                return variant(cycle_);
 
472
        case ALGO_SCREEN_WIDTH:
 
473
                return variant(graphics::screen_width());
 
474
        case ALGO_SCREEN_HEIGHT:
 
475
                return variant(graphics::screen_height());
 
476
        }
 
477
 
 
478
        return variant();
 
479
}
 
480
 
 
481
#include "level.hpp"
 
482
 
 
483
BENCHMARK(gui_algorithm_bench)
 
484
{
 
485
        static boost::intrusive_ptr<level> lvl;
 
486
        if(!lvl) {
 
487
                lvl = boost::intrusive_ptr<level>(new level("titlescreen.cfg"));
 
488
                lvl->finish_loading();
 
489
                lvl->set_as_current_level();
 
490
        }
 
491
 
 
492
        static gui_algorithm_ptr gui(gui_algorithm::get("default"));
 
493
        BENCHMARK_LOOP {
 
494
                gui->draw(*lvl);
 
495
        }
 
496
}