1
#include <boost/bind.hpp>
2
#include <boost/function.hpp>
3
#include <boost/shared_ptr.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"
17
#include "graphical_font.hpp"
18
#include "gui_formula_functions.hpp"
19
#include "iphone_controls.hpp"
21
#include "preferences.hpp"
23
#include "unit_test.hpp"
24
#include "wml_node.hpp"
25
#include "wml_parser.hpp"
26
#include "wml_utils.hpp"
28
using namespace game_logic;
32
typedef boost::function<void (const gui_algorithm* algo)> gui_command_function;
34
class gui_command : public formula_callable {
35
variant get_value(const std::string& key) const { return variant(); }
38
virtual void execute(const gui_algorithm& algo) = 0;
41
class draw_text_command : public gui_command {
42
const_graphical_font_ptr font_;
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)
50
void execute(const gui_algorithm& algo) {
51
font_->draw(x_, y_, text_);
55
class draw_text_function : public function_expression {
57
explicit draw_text_function(const args_list& args)
58
: function_expression("draw_text", args, 3, 4)
61
variant execute(const formula_callable& variables) const {
62
std::string font = "default";
65
if(args().size() == 4) {
66
font = args()[arg++]->evaluate(variables).as_string();
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));
76
class draw_number_command : public gui_command {
77
graphics::blit_queue blit_;
79
draw_number_command(int number, int places, int x, int y)
81
queue_draw_number(blit_, number, places, x, y);
84
void execute(const gui_algorithm& algo) {
89
class draw_number_function : public function_expression {
91
explicit draw_number_function(const args_list& args)
92
: function_expression("draw_number", args, 4, 4)
95
variant execute(const formula_callable& variables) const {
96
static cache_entry cache[4];
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;
108
const int n = cache_loc++%(sizeof(cache)/sizeof(*cache));
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;
118
cache_entry() : x(-1), y(-1) {}
119
int number, places, x, y;
125
class draw_animation_area_command : public gui_command {
130
variant get_value(const std::string& key) const { return variant(); }
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)
136
void execute(const gui_algorithm& algo) {
137
frame_->draw(x_, y_, area_);
141
class draw_animation_area_function : public function_expression {
143
draw_animation_area_function(gui_algorithm* algo, const args_list& args)
144
: function_expression("draw_animation_area", args, 4, 7), algo_(algo)
147
gui_algorithm* algo_;
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());
156
const int x = args()[1]->evaluate(variables).as_int();
157
const int y = args()[2]->evaluate(variables).as_int();
160
for(int n = 0; n != args().size() - 3; ++n) {
161
vals[n] = args()[n+3]->evaluate(variables).as_int();
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]);
171
ASSERT_EQ(args().size(), 7);
172
area = rect(vals[0], vals[1], vals[2], vals[3]);
175
return variant(new draw_animation_area_command(f, x, y, area));
179
class draw_animation_command : public gui_command {
180
graphics::blit_queue blit_;
181
variant get_value(const std::string& key) const { return variant(); }
183
draw_animation_command(const frame_ptr& f, int x, int y)
185
f->draw_into_blit_queue(blit_, x, y);
188
void execute(const gui_algorithm& algo) {
193
class draw_animation_function : public function_expression {
195
draw_animation_function(gui_algorithm* algo, const args_list& args)
196
: function_expression("draw_animation", args, 3, 3), algo_(algo)
199
gui_algorithm* algo_;
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());
208
const int x = args()[1]->evaluate(variables).as_int();
209
const int y = args()[2]->evaluate(variables).as_int();
211
return variant(new draw_animation_command(f, x, y));
215
class color_command : public gui_command {
216
unsigned char r_, g_, b_, a_;
218
color_command(int r, int g, int b, int a) : r_(r), g_(g), b_(b), a_(a)
221
void execute(const gui_algorithm& algo) {
222
glColor4ub(r_, g_, b_, a_);
226
class color_function : public function_expression {
228
explicit color_function(const args_list& args)
229
: function_expression("color", args, 4, 4)
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()));
241
class gui_command_function_symbol_table : public function_symbol_table
243
gui_algorithm* algo_;
245
gui_command_function_symbol_table(gui_algorithm* algo) : algo_(algo)
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
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));
265
return function_symbol_table::create_function(fn, args, callable_def);
269
const std::string AlgorithmProperties[] = {
270
"level", "object", "cycle", "screen_width", "screen_height",
273
enum ALGORITHM_PROPERTY_ID {
274
ALGO_LEVEL, ALGO_OBJECT, ALGO_CYCLE, ALGO_SCREEN_WIDTH, ALGO_SCREEN_HEIGHT,
277
class gui_algorithm_definition : public game_logic::formula_callable_definition
280
static const gui_algorithm_definition& instance() {
281
static const gui_algorithm_definition def;
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;
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();
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()) {
304
const entry* get_entry(int slot) const {
305
if(slot < 0 || slot >= entries_.size()) {
309
return &entries_[slot];
312
int num_slots() const {
313
return entries_.size();
316
std::vector<entry> entries_;
317
std::map<std::string, int> keys_to_slots_;
322
gui_algorithm::gui_algorithm(wml::const_node_ptr node)
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))
327
gui_command_function_symbol_table symbols(this);
330
FOREACH_WML_CHILD(frame_node, node, "animation") {
331
frame_ptr f(new frame(frame_node));
332
frames_[frame_node->attr("id")] = f;
335
draw_formula_ = formula::create_optional_formula(node->attr("on_draw"), &symbols, &gui_algorithm_definition::instance());
338
gui_algorithm::~gui_algorithm()
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];
352
void gui_algorithm::new_level() {
354
object_ = boost::intrusive_ptr<custom_object>(new custom_object("dummy_gui_object", 0, 0, true));
357
void gui_algorithm::process(level& lvl) {
360
if((cycle_%2) == 0 && process_formula_) {
361
object_->set_level(lvl);
362
variant result = process_formula_->execute(*this);
363
object_->execute_command(result);
367
void gui_algorithm::draw(const level& lvl) {
370
if((cycle_%2) == 0) {
371
cached_draw_commands_ = variant();
374
if(cached_draw_commands_.is_null() && draw_formula_) {
375
cached_draw_commands_ = draw_formula_->execute(*this);
378
execute_command(cached_draw_commands_);
380
glColor4ub(255, 255, 255, 255);
382
iphone_controls::draw();
385
void gui_algorithm::execute_command(variant v) {
387
const int num_elements = v.num_elements();
388
for(int n = 0; n != num_elements; ++n) {
389
execute_command(v[n]);
395
gui_command* cmd = v.try_convert<gui_command>();
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")));
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);
411
f = &obj->get_frame(anim);
416
const std::map<std::string, frame_ptr>::const_iterator itor = frames_.find(anim);
417
if(itor != frames_.end()) {
418
f = itor->second.get();
424
cycle = cycle_%f->duration();
427
f->draw(x, y, true, false, cycle);
431
void gui_algorithm::color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) const
433
glColor4ub(r, g, b, a);
436
frame_ptr gui_algorithm::get_frame(const std::string& id) const
438
const std::map<std::string, frame_ptr>::const_iterator itor = frames_.find(id);
439
if(itor != frames_.end()) {
446
variant gui_algorithm::get_value(const std::string& key) const
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());
463
variant gui_algorithm::get_value_by_slot(int slot) const
467
return variant(lvl_);
469
return variant(object_.get());
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());
483
BENCHMARK(gui_algorithm_bench)
485
static boost::intrusive_ptr<level> lvl;
487
lvl = boost::intrusive_ptr<level>(new level("titlescreen.cfg"));
488
lvl->finish_loading();
489
lvl->set_as_current_level();
492
static gui_algorithm_ptr gui(gui_algorithm::get("default"));