1 #include <iostream>
2 #include <algorithm>
3 #include <string>
4 #include "graphics.hpp"
5 
6 #include <boost/regex.hpp>
7 #include <boost/lexical_cast.hpp>
8 
9 #include "controls.hpp"
10 #include "difficulty.hpp"
11 #include "filesystem.hpp"
12 #include "formatter.hpp"
13 #include "formula_callable.hpp"
14 #include "game_registry.hpp"
15 #include "json_parser.hpp"
16 #include "module.hpp"
17 #include "preferences.hpp"
18 #include "sound.hpp"
19 #include "sys.hpp"
20 #include "variant_utils.hpp"
21 
22 #include <time.h>
23 
24 #define SAVE_FILENAME					"save.cfg"
25 #define AUTOSAVE_FILENAME				"autosave.cfg"
26 
27 #ifdef _WINDOWS
28 #define WIN32_LEAN_AND_MEAN
29 #include <windows.h>
30 #include <shlobj.h>
31 #include <shlwapi.h>
32 
33 class WindowsPrefs
34 	{
35 	public:
GetPreferencePath()36 		std::string GetPreferencePath()   { if (State* i = Instance()) return i->GetPreferencePath(); }
GetSaveFilePath()37 		std::string GetSaveFilePath()     { if (State* i = Instance()) return i->GetSaveFilePath(); }
GetAutoSaveFilePath()38 		std::string GetAutoSaveFilePath() { if (State* i = Instance()) return i->GetAutoSaveFilePath(); }
39 
40 	private:
41 		struct State
42 		{
43 		private:
44 			std::string preferences_path;
45 			std::string save_file_path;
46 			std::string auto_save_file_path;
47 		public:
State()48 			State::State()
49 			{
50 				this->preferences_path = GetAppDataPath() + "/" + module::get_module_name() + "/";
51 				this->save_file_path = this->preferences_path + SAVE_FILENAME;
52 				this->auto_save_file_path = this->preferences_path + AUTOSAVE_FILENAME;
53 			}
GetPreferencePathWindowsPrefs::State54 			std::string GetPreferencePath()
55 			{
56 				return this->preferences_path;
57 			};
58 
GetSaveFilePathWindowsPrefs::State59 			std::string GetSaveFilePath()
60 			{
61 				return this->save_file_path;
62 			}
63 
GetAutoSaveFilePathWindowsPrefs::State64 			std::string GetAutoSaveFilePath()
65 			{
66 				return this->auto_save_file_path;
67 			}
68 		};
69 
70 		static State* Instance();
71 		static void CleanUp();
72 
73 		static bool MDestroyed;
74 		static State* MInstance;
75 	};
76 
GetAppDataPath()77 std::string GetAppDataPath() {
78 	char szPath[ MAX_PATH ];
79 	if(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, szPath)))
80 	{
81 		return std::string(szPath);
82 	}
83 	return std::string();
84 }
85 
86 bool WindowsPrefs::MDestroyed = false;
87 WindowsPrefs::State* WindowsPrefs::MInstance = 0;
88 
Instance()89 WindowsPrefs::State* WindowsPrefs::Instance()
90 {
91 	if( !MDestroyed && !MInstance ) {
92 		MInstance = new State();
93 		atexit( &CleanUp );
94 	}
95 	return MInstance;
96 }
97 
CleanUp()98 void WindowsPrefs::CleanUp()
99 {
100 	delete MInstance;
101 	MInstance = 0;
102 	MDestroyed = true;
103 }
104 
105 WindowsPrefs winPrefs;
106 #endif // _WINDOWS
107 
108 
109 namespace preferences {
version()110 	const std::string& version() {
111 		static const std::string Version = "1.3";
112 		return Version;
113 	}
114 
version_decimal()115 	const variant& version_decimal() {
116 		static const variant versiond = variant(decimal::from_string(version()));
117 		return versiond;
118 	}
119 
120 	namespace {
121 		int unique_user_id = 0;
122 
123 		int screen_editor_mode = 0;
124 
125 		bool no_sound_ = false;
126 		bool no_music_ = false;
127 		bool show_debug_hitboxes_ = false;
128 		bool show_iphone_controls_ = false;
129 		bool use_pretty_scaling_ = false;
130 		bool fullscreen_ = false;
131 		bool resizable_ = false;
132 		bool proportional_resize_ = false;
133 		bool debug_ = true;
134 		bool reverse_ab_ = false;
135 		bool show_fps_ = false;
136 		int frame_time_millis_ = 20;
137 		bool no_iphone_controls_ = false;
138 		bool allow_autopause_ = false;
139 
140 		std::string level_path_ = "data/level/";
141 		bool level_path_set_ = false;
142 
143 		bool relay_through_server_ = false;
144 
145 		std::string control_scheme_ = "iphone_2d";
146 
147 		bool record_history_ = false;
148 
149 		bool edit_on_start_ = false;
150 
151 		variant external_code_editor_;
152 
153 		int force_difficulty_ = INT_MIN;
154 
155 		uri::uri tbs_uri_ = uri::uri::parse("http://localhost:23456");
156 
157 		std::string username_;
158 		std::string password_;
159 
160 #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
161 
162 #ifndef PREFERENCES_PATH
163 #define PREFERENCES_PATH "../Documents/"
164 #endif
165 		bool send_stats_ = false;
166 
167 		bool sim_iphone_ = true;
168 
169 		int virtual_screen_width_ = 960;
170 		int virtual_screen_height_ = 640;
171 
172 		int actual_screen_width_ = 320;
173 		int actual_screen_height_ = 480;
174 
175 		bool screen_rotated_ = true;
176 
177 		bool use_joystick_ = false;
178 
179 		bool load_compiled_ = true;
180 
181 		bool use_16bpp_textures_ = false;
182 #elif defined(TARGET_OS_HARMATTAN)
183 
184 		bool send_stats_ = false;
185 
186 		bool sim_iphone_ = false;
187 
188 #ifndef PREFERENCES_PATH
189 #define PREFERENCES_PATH "~/.frogatto/"
190 #endif
191 		int virtual_screen_width_ = 854;
192 		int virtual_screen_height_ = 480;
193 
194 		int actual_screen_width_ = 854;
195 		int actual_screen_height_ = 480;
196 
197 		bool screen_rotated_ = false;
198 
199 		bool use_joystick_ = true;
200 
201 		bool load_compiled_ = true;
202 
203 		bool use_fbo_ = true;
204 		bool use_bequ_ = true;
205 
206 		bool use_16bpp_textures_ = true;
207 #elif defined(__ANDROID__)
208 
209 #ifndef PREFERENCES_PATH
210 #define PREFERENCES_PATH ".frogatto/"
211 #endif
212 
213 		bool send_stats_ = false;
214 		bool sim_iphone_ = false;
215 		int virtual_screen_width_ = 800;
216 		int virtual_screen_height_ = 480;
217 
218 		int actual_screen_width_ = 800;
219 		int actual_screen_height_ = 480;
220 
221 		bool screen_rotated_ = false;
222 
223 		bool use_joystick_ = true;
224 
225 		bool load_compiled_ = true;
226 
227 		bool use_fbo_ = true;
228 		bool use_bequ_ = true;
229 
230 		bool use_16bpp_textures_ = true;
231 #elif defined(TARGET_BLACKBERRY)
232 
233 #ifndef PREFERENCES_PATH
234 #define PREFERENCES_PATH "~/.frogatto/"
235 #endif
236 		bool send_stats_ = true;
237 		bool sim_iphone_ = false;
238 		bool use_joystick_ = true;
239 		bool screen_rotated_ = false;
240 		int virtual_screen_width_ = 1024;
241 		int virtual_screen_height_ = 600;
242 		int actual_screen_width_ = 1024;
243 		int actual_screen_height_ = 600;
244 		bool load_compiled_ = true;
245 		bool use_fbo_ = true;
246 		bool use_bequ_ = true;
247 		bool use_16bpp_textures_ = false;
248 
249 #else
250 
251 #if defined(_WINDOWS)
252 #define PREFERENCES_PATH ""
253 #endif // _WINDOWS
254 
255 #ifndef NO_UPLOAD_STATS
256 		bool send_stats_ = true;
257 #else
258 		bool send_stats_ = false;
259 #endif
260 
261 		bool sim_iphone_ = false;
262 
263 #ifndef PREFERENCES_PATH
264 #define PREFERENCES_PATH "~/.frogatto/"
265 #endif
266 		bool screen_rotated_ = false;
267 
268 		bool use_joystick_ = true;
269 
270 #if defined(TARGET_TEGRA)
271 		int virtual_screen_width_ = 1024;
272 		int virtual_screen_height_ = 600;
273 
274 		int actual_screen_width_ = 1024;
275 		int actual_screen_height_ = 600;
276 
277 		bool load_compiled_ = true;
278 		bool use_fbo_ = true;
279 		bool use_bequ_ = true;
280 #else
281 		int virtual_screen_width_ = 800;
282 		int virtual_screen_height_ = 600;
283 
284 		int actual_screen_width_ = 800;
285 		int actual_screen_height_ = 600;
286 
287 		bool load_compiled_ = false;
288 #endif
289 
290 #if defined(TARGET_PANDORA)
291         bool use_fbo_ = true;
292         bool use_bequ_ = true;
293 #endif
294 
295 		bool use_16bpp_textures_ = false;
296 #endif
297 
298 		std::string preferences_path_ = PREFERENCES_PATH;
299 		std::string save_file_path_ = PREFERENCES_PATH SAVE_FILENAME;
300 		std::string auto_save_file_path_ = PREFERENCES_PATH AUTOSAVE_FILENAME;
301 
302 #ifdef __APPLE__
303 #include "TargetConditionals.h"
304 #if TARGET_OS_MAC
305 		bool editor_save_to_user_preferences_ = true;
306 #endif
307 #else
308 		bool editor_save_to_user_preferences_ = false;
309 #endif
310 
311 		bool force_no_npot_textures_ = false;
312 
313 		bool run_failing_unit_tests_ = false;
314 		bool serialize_bad_objects_ = false;
315 	}
316 
get_unique_user_id()317 	int get_unique_user_id() {
318 		if(unique_user_id == 0) {
319 			time_t t1;
320 			time(&t1);
321 			int tm = t1;
322 			unique_user_id = tm^rand();
323 		}
324 
325 		return unique_user_id;
326 	}
327 
328 	int xypos_draw_mask = actual_screen_width_ < virtual_screen_width_ ? ~1 : ~0;
double_scale()329 	bool double_scale() {
330 		return xypos_draw_mask&1;
331 	}
332 	bool compiling_tiles = false;
333 
334 	namespace {
recalculate_draw_mask()335 		void recalculate_draw_mask() {
336 			xypos_draw_mask = actual_screen_width_ < virtual_screen_width_ ? ~1 : ~0;
337 		}
338 	}
339 
no_sound()340 	bool no_sound() {
341 		return no_sound_;
342 	}
343 
no_music()344 	bool no_music() {
345 		return no_music_;
346 	}
347 
setup_preferences_dir()348 	bool setup_preferences_dir()
349 	{
350 		return !sys::get_dir(user_data_path()).empty();
351 	}
352 
set_preferences_path_from_module(const std::string & name)353 	void set_preferences_path_from_module( const std::string& name)
354 	{
355 #ifdef _WINDOWS
356 		preferences::set_preferences_path(GetAppDataPath() + "/" + name + "/");
357 #elif defined(__ANDROID__)
358 		preferences::set_preferences_path("." + name + "/");
359 #elif __APPLE__
360 #include "TargetConditionals.h"
361 #if TARGET_OS_MAC
362 		preferences::set_preferences_path("~/Library/Application Support/" + name + "/");
363 		//preferences::set_preferences_path(std::string(getenv("HOME")) + "/Library/Application Support/" + name + "/");
364 #endif
365 #else
366 		preferences::set_preferences_path("~/." + name + "/");
367 #endif
368 		save_file_path_ = preferences_path_ + SAVE_FILENAME;
369 		auto_save_file_path_ = preferences_path_ + AUTOSAVE_FILENAME;
370 	}
371 
set_preferences_path(const std::string & path)372 	void set_preferences_path(const std::string& path)
373 	{
374 		std::cerr << "SET PREFERENCES PATH: " << path << "\n";
375 		preferences_path_ = path;
376 		if(preferences_path_[preferences_path_.length()-1] != '/') {
377 			preferences_path_ += '/';
378 		}
379 
380 		save_file_path_ = preferences_path_ + SAVE_FILENAME;
381 		auto_save_file_path_ = preferences_path_ + AUTOSAVE_FILENAME;
382 	}
383 
level_path()384 	const std::string& level_path() {
385 		return level_path_;
386 	}
387 
is_level_path_set()388 	bool is_level_path_set() {
389 		return level_path_set_;
390 	}
391 
save_file_path()392 	const char *save_file_path() {
393 		std::cerr << "GET SAVE FILE PATH: " << save_file_path_ << std::endl;
394 		return save_file_path_.c_str();
395 	}
396 
auto_save_file_path()397 	const char *auto_save_file_path() {
398 		std::cerr << "GET AUTOSAVE FILE PATH: " << auto_save_file_path_ << std::endl;
399 		return auto_save_file_path_.c_str();
400 	}
401 
user_data_path()402 	const char *user_data_path() {
403 		return preferences_path_.c_str();
404 	}
405 
editor_save_to_user_preferences()406 	bool editor_save_to_user_preferences() {
407 		return editor_save_to_user_preferences_;
408 	}
409 
410 	namespace {
expand_path(std::string & str)411 		void expand_path(std::string& str) {
412 			if(!str.empty() && str[0] == '~') {
413 #if defined(TARGET_PANDORA)
414 				str = std::string(getenv("PWD")) + std::string(str.begin()+1, str.end());
415 #else
416 				str = std::string(getenv("HOME")) + std::string(str.begin()+1, str.end());
417 #endif
418 			}
419 		}
420 	}
421 
dlc_path()422 	std::string dlc_path() {
423 		std::string result(std::string(PREFERENCES_PATH) + "/dlc");
424 		expand_path(result);
425 		return result;
426 	}
427 
expand_data_paths()428 	void expand_data_paths() {
429 		expand_path(level_path_);
430 		expand_path(save_file_path_);
431 		expand_path(auto_save_file_path_);
432 		expand_path(preferences_path_);
433 		std::cerr << "EXPAND DATA PATHS\n";
434 	}
435 
set_save_slot(const std::string & fname)436 	void set_save_slot(const std::string& fname) {
437 		save_file_path_ = std::string(user_data_path()) + fname;
438 		std::cerr << "SET SAVE FILE PATH TO " << save_file_path_ << "\n";
439 	}
440 
show_debug_hitboxes()441 	bool show_debug_hitboxes() {
442 		return show_debug_hitboxes_;
443 	}
444 
toogle_debug_hitboxes()445 	bool toogle_debug_hitboxes() {
446 		bool shown = show_debug_hitboxes_;
447 		show_debug_hitboxes_ = !show_debug_hitboxes_;
448 		return shown;
449 	}
450 
show_iphone_controls()451 	bool show_iphone_controls() {
452 		return show_iphone_controls_;
453 	}
454 
use_pretty_scaling()455 	bool use_pretty_scaling() {
456 		return use_pretty_scaling_;
457 	}
458 
set_use_pretty_scaling(bool value)459 	void set_use_pretty_scaling(bool value) {
460 		use_pretty_scaling_ = value;
461 	}
462 
fullscreen()463 	bool fullscreen() {
464 		return fullscreen_;
465 	}
466 
set_fullscreen(bool value)467 	void set_fullscreen(bool value) {
468 		fullscreen_ = value;
469 	}
470 
resizable()471 	bool resizable() {
472 		return resizable_;
473 	}
474 
no_iphone_controls()475 	bool no_iphone_controls() {
476 		return no_iphone_controls_;
477 	}
478 
proportional_resize()479 	bool proportional_resize() {
480 		return proportional_resize_;
481 	}
482 
reverse_ab()483 	bool reverse_ab() {
484 		return reverse_ab_;
485 	}
486 
set_reverse_ab(bool value)487 	void set_reverse_ab(bool value) {
488 		reverse_ab_ = value;
489 	}
490 
control_scheme()491 	const std::string& control_scheme()
492 	{
493 		return control_scheme_;
494 	}
495 
set_control_scheme(const std::string & scheme)496 	void set_control_scheme(const std::string& scheme)
497 	{
498 		control_scheme_ = scheme;
499 	}
500 
set_widescreen()501 	void set_widescreen()
502 	{
503 		virtual_screen_width_ = (virtual_screen_height_*16)/9;
504 		actual_screen_width_ = (actual_screen_height_*16)/9;
505 		recalculate_draw_mask();
506 	}
507 
virtual_screen_width()508 	int virtual_screen_width()
509 	{
510 		return virtual_screen_width_;
511 	}
512 
virtual_screen_height()513 	int virtual_screen_height()
514 	{
515 		return virtual_screen_height_;
516 	}
517 
set_virtual_screen_width(int width)518 	void set_virtual_screen_width (int width)
519 	{
520 		virtual_screen_width_ = width;
521 		recalculate_draw_mask();
522 	}
523 
set_virtual_screen_height(int height)524 	void set_virtual_screen_height (int height)
525 	{
526 		virtual_screen_height_ = height;
527 	}
528 
actual_screen_width()529 	int actual_screen_width()
530 	{
531 		return actual_screen_width_;
532 	}
533 
actual_screen_height()534 	int actual_screen_height()
535 	{
536 		return actual_screen_height_;
537 	}
538 
set_actual_screen_width(int width)539 	void set_actual_screen_width(int width)
540 	{
541 		actual_screen_width_ = width;
542 		if(screen_editor_mode) {
543 			virtual_screen_width_ = actual_screen_width_;
544 		}
545 		recalculate_draw_mask();
546 	}
547 
set_actual_screen_height(int height)548 	void set_actual_screen_height(int height)
549 	{
550 		actual_screen_height_ = height;
551 		if(screen_editor_mode) {
552 			virtual_screen_height_ = actual_screen_height_;
553 		}
554 	}
555 
load_compiled()556 	bool load_compiled()
557 	{
558 		return load_compiled_;
559 	}
560 
set_load_compiled(bool value)561 	void set_load_compiled(bool value)
562 	{
563 		load_compiled_ = value;
564 	}
565 
allow_autopause()566 	bool allow_autopause()
567 	{
568 		return allow_autopause_;
569 	}
570 
edit_on_start()571 	bool edit_on_start()
572 	{
573 		return edit_on_start_;
574 	}
575 
set_edit_on_start(bool value)576 	void set_edit_on_start(bool value)
577 	{
578 		edit_on_start_ = value;
579 	}
580 
get_tbs_uri()581 	uri::uri get_tbs_uri()
582 	{
583 		return tbs_uri_;
584 	}
585 
get_username()586 	std::string get_username()
587 	{
588 		return username_;
589 	}
590 
get_password()591 	std::string get_password()
592 	{
593 		return password_;
594 	}
595 
596 #if defined(TARGET_OS_HARMATTAN) || defined(TARGET_PANDORA) || defined(TARGET_TEGRA) || defined(TARGET_BLACKBERRY)
use_fbo()597 	bool use_fbo()
598 	{
599 		return use_fbo_;
600 	}
601 
use_bequ()602 	bool use_bequ()
603 	{
604 		return use_bequ_;
605 	}
606 
set_fbo(bool value)607     void set_fbo( bool value )
608     {
609 		use_fbo_ = value;
610     }
611 
set_bequ(bool value)612     void set_bequ( bool value )
613     {
614 		use_bequ_ = value;
615     }
616 #endif
617 
force_no_npot_textures()618 	bool force_no_npot_textures()
619 	{
620 		return force_no_npot_textures_;
621 	}
622 
screen_rotated()623 	bool screen_rotated()
624 	{
625 		return screen_rotated_;
626 	}
627 
debug()628 	bool debug()
629 	{
630 		return debug_;
631 	}
632 
show_fps()633 	bool show_fps()
634 	{
635 		return show_fps_;
636 	}
637 
frame_time_millis()638 	int frame_time_millis()
639 	{
640 		return frame_time_millis_;
641 	}
642 
use_joystick()643 	bool use_joystick()
644 	{
645 		return use_joystick_;
646 	}
647 
registry()648 	game_logic::formula_callable* registry()
649 	{
650 		return &game_registry::instance();
651 	}
652 
load_preferences()653 	void load_preferences()
654 	{
655 		std::string path;
656 		if(preferences_path_.empty()) {
657 #if defined( _WINDOWS )
658 			preferences_path_ = winPrefs.GetPreferencePath();
659 			save_file_path_ = winPrefs.GetSaveFilePath();
660 			auto_save_file_path_ = winPrefs.GetAutoSaveFilePath();
661 			path = preferences_path_;
662 #else
663 			path = PREFERENCES_PATH;
664 #endif // defined( _WINDOWS )
665 		} else {
666 			path = preferences_path_;
667 		}
668 		expand_path(path);
669 		if(!sys::file_exists(path + "preferences.cfg")) {
670 			return;
671 		}
672 
673 		variant node;
674 
675 		try {
676 			node = json::parse_from_file(path + "preferences.cfg");
677 		} catch(json::parse_error&) {
678 			return;
679 		}
680 
681 		unique_user_id = node["user_id"].as_int(0);
682 
683 		use_joystick_ = node["joystick"].as_bool(use_joystick_);
684 		variant show_control_rects = node["show_iphone_controls"];
685 		if(show_control_rects.is_null() == false) {
686 			show_iphone_controls_ = show_control_rects.as_bool(show_iphone_controls_);
687 		}
688 
689 		no_sound_ = node["no_sound"].as_bool(no_sound_);
690 		no_music_ = node["no_music"].as_bool(no_music_);
691 		reverse_ab_ = node["reverse_ab"].as_bool(reverse_ab_);
692 		allow_autopause_ = node["allow_autopause"].as_bool(allow_autopause_);
693 
694 		sound::set_music_volume(node["music_volume"].as_int(1000)/1000.0);
695 		sound::set_sound_volume(node["sound_volume"].as_int(1000)/1000.0);
696 
697 		const variant registry_node = node["registry"];
698 		if(registry_node.is_null() == false) {
699 			game_registry::instance().set_contents(registry_node);
700 		}
701 
702 		if(node["code_editor"].is_map()) {
703 			external_code_editor_ = node["code_editor"];
704 		}
705 
706 #if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
707 		controls::set_sdlkey(controls::CONTROL_UP, static_cast<SDLKey>(node["key_up"].as_int(SDLK_UP)));
708 		controls::set_sdlkey(controls::CONTROL_DOWN, static_cast<SDLKey>(node["key_down"].as_int(SDLK_DOWN)));
709 		controls::set_sdlkey(controls::CONTROL_LEFT, static_cast<SDLKey>(node["key_left"].as_int(SDLK_LEFT)));
710 		controls::set_sdlkey(controls::CONTROL_RIGHT, static_cast<SDLKey>(node["key_right"].as_int(SDLK_RIGHT)));
711 		controls::set_sdlkey(controls::CONTROL_ATTACK, static_cast<SDLKey>(node["key_attack"].as_int(SDLK_d)));
712 		controls::set_sdlkey(controls::CONTROL_JUMP, static_cast<SDLKey>(node["key_jump"].as_int(SDLK_a)));
713 		controls::set_sdlkey(controls::CONTROL_TONGUE, static_cast<SDLKey>(node["key_tongue"].as_int(SDLK_s)));
714 #endif
715 	}
716 
save_preferences()717 	void save_preferences()
718 	{
719 		variant_builder node;
720 		node.add("user_id", get_unique_user_id());
721 		node.add("no_sound", variant::from_bool(no_sound_));
722 		node.add("no_music", variant::from_bool(no_music_));
723 		node.add("allow_autopause", variant::from_bool(allow_autopause_));
724 		node.add("reverse_ab", variant::from_bool(reverse_ab_));
725 		node.add("joystick", variant::from_bool(use_joystick_));
726 		node.add("sound_volume", static_cast<int>(sound::get_sound_volume()*1000));
727 		node.add("music_volume", static_cast<int>(sound::get_music_volume()*1000));
728 		node.add("key_up", controls::get_sdlkey(controls::CONTROL_UP));
729 		node.add("key_down", controls::get_sdlkey(controls::CONTROL_DOWN));
730 		node.add("key_left", controls::get_sdlkey(controls::CONTROL_LEFT));
731 		node.add("key_right", controls::get_sdlkey(controls::CONTROL_RIGHT));
732 		node.add("key_attack", controls::get_sdlkey(controls::CONTROL_ATTACK));
733 		node.add("key_jump", controls::get_sdlkey(controls::CONTROL_JUMP));
734 		node.add("key_tongue", controls::get_sdlkey(controls::CONTROL_TONGUE));
735 		node.add("show_iphone_controls", variant::from_bool(show_iphone_controls_));
736 
737 		if(external_code_editor_.is_null() == false) {
738 			node.add("code_editor", external_code_editor_);
739 		}
740 
741 		node.add("registry", game_registry::instance().write_contents());
742 
743 		std::cerr << "WRITE PREFS: " << (preferences_path_ + "preferences.cfg") << std::endl;
744 		sys::write_file(preferences_path_ + "preferences.cfg", node.build().write_json());
745 	}
746 
editor_screen_size_scope()747 	editor_screen_size_scope::editor_screen_size_scope() : width_(virtual_screen_width_), height_(virtual_screen_height_) {
748 		++screen_editor_mode;
749 		virtual_screen_width_ = actual_screen_width_;
750 		virtual_screen_height_ = actual_screen_height_;
751 	}
752 
~editor_screen_size_scope()753 	editor_screen_size_scope::~editor_screen_size_scope() {
754 		virtual_screen_width_ = width_;
755 		virtual_screen_height_ = height_;
756 		--screen_editor_mode;
757 	}
758 
parse_arg(const char * arg)759 	bool parse_arg(const char* arg) {
760 		const std::string s(arg);
761 
762 		std::string arg_name, arg_value;
763 		std::string::const_iterator equal = std::find(s.begin(), s.end(), '=');
764 		if(equal != s.end()) {
765 			arg_name = std::string(s.begin(), equal);
766 			arg_value = std::string(equal+1, s.end());
767 		}
768 
769 		if(arg_name == "--level-path") {
770 			level_path_ = arg_value + "/";
771 			level_path_set_ = true;
772 		} else if(s == "--editor_save_to_user_preferences") {
773 			editor_save_to_user_preferences_ = true;
774 		} else if(s == "--show-hitboxes") {
775 			show_debug_hitboxes_ = true;
776 		} else if(s == "--show-controls") {
777 			show_iphone_controls_ = true;
778 		} else if(s == "--scale") {
779 			set_use_pretty_scaling(true);
780 		} else if(s == "--no-sound") {
781 			no_sound_ = true;
782 		} else if(s == "--no-music") {
783 			no_music_ = true;
784 		} else if(s == "--sound") {
785 			no_sound_ = false;
786 		} else if(s == "--music") {
787 			no_music_ = false;
788 		} else if(s == "--fullscreen") {
789 			fullscreen_ = true;
790 		} else if(s == "--windowed") {
791 			fullscreen_ = false;
792 		} else if(s == "--proportional-resize") {
793 			resizable_ = true;
794 			proportional_resize_ = true;
795 		} else if(s == "--resizable") {
796 			resizable_ = true;
797 		} else if(s == "--no-resizable") {
798 			resizable_ = false;
799 		} else if(s == "--widescreen") {
800 			set_widescreen();
801 		} else if(s == "--bigscreen") {
802 			virtual_screen_width_ = actual_screen_width_;
803 			virtual_screen_height_ = actual_screen_height_;
804 		} else if(s == "--potonly") {
805 			force_no_npot_textures_ = true;
806 		} else if(s == "--textures16") {
807 			use_16bpp_textures_ = true;
808 		} else if(s == "--textures32") {
809 			use_16bpp_textures_ = false;
810 		} else if(arg_name == "--textures32_if_kb_memory_at_least") {
811 			const int memory_required = atoi(arg_value.c_str());
812 			sys::available_memory_info mem_info;
813 			const bool result = sys::get_available_memory(&mem_info);
814 			if(result) {
815 				use_16bpp_textures_ = mem_info.mem_total_kb < memory_required;
816 				std::cerr << "USING " << (use_16bpp_textures_ ? 16 : 32) << "bpp TEXTURES BECAUSE SYSTEM HAS " << mem_info.mem_total_kb << "KB AND " << memory_required << "KB REQUIRED FOR 32bpp TEXTURES\n";
817 			} else {
818 				use_16bpp_textures_ = true;
819 				std::cerr << "USING 16bpp TEXTURES BECAUSE WE COULD NOT DISCOVER HOW MUCH MEMORY THE SYSTEM HAS\n";
820 			}
821 		} else if(s == "--debug") {
822 			debug_ = true;
823 		} else if(s == "--no-debug") {
824 			debug_ = false;
825 		} else if(s == "--simiphone") {
826 			sim_iphone_ = true;
827 
828 			virtual_screen_width_ = 960;
829 			virtual_screen_height_ = 640;
830 
831 			actual_screen_width_ = 480;
832 			actual_screen_height_ = 320;
833 			use_16bpp_textures_ = true;
834 
835 			recalculate_draw_mask();
836 		} else if(s == "--simipad") {
837 			sim_iphone_ = true;
838 			control_scheme_ = "ipad_2d";
839 
840 			virtual_screen_width_ = 1024;
841 			virtual_screen_height_ = 768;
842 
843 			actual_screen_width_ = 1024;
844 			actual_screen_height_ = 768;
845 
846 			recalculate_draw_mask();
847 		} else if(s == "--no-iphone-controls") {
848 			no_iphone_controls_ = true;
849 		} else if(s == "--wvga") {
850 			virtual_screen_width_ = 800;
851 			virtual_screen_height_ = 480;
852 
853 			actual_screen_width_ = 800;
854 			actual_screen_height_ = 480;
855 
856 			recalculate_draw_mask();
857 		} else if(s == "--native") {
858 			virtual_screen_width_ = (actual_screen_width_) * 2;
859 			virtual_screen_height_ = (actual_screen_height_) * 2;
860 			recalculate_draw_mask();
861 		} else if(s == "--fps") {
862 			show_fps_ = true;
863 		} else if(s == "--no-fps") {
864 			show_fps_ = false;
865 		} else if(arg_name == "--set-fps" && !arg_value.empty()) {
866 			frame_time_millis_ = 1000/boost::lexical_cast<int, std::string>(arg_value);
867 			std::cerr << "FPS: " << arg_value << " = " << frame_time_millis_ << "ms/frame\n";
868 		} else if(arg_name == "--config-path" && !arg_value.empty()) {
869 			set_preferences_path(arg_value);
870 		} else if(s == "--send-stats") {
871 			send_stats_ = true;
872 		} else if(s == "--no-send-stats") {
873 			send_stats_ = false;
874 		} else if(s == "--time-travel") {
875 			record_history_ = true;
876 		} else if(s == "--joystick") {
877 			use_joystick_ = true;
878 		} else if(s == "--no-joystick") {
879 			use_joystick_ = false;
880 		} else if(arg_name == "--server") {
881 			tbs_uri_ = uri::uri::parse(arg_value);
882 		} else if(arg_name == "--user") {
883 			username_ = arg_value;
884 		} else if(arg_name == "--pass") {
885 			password_ = arg_value;
886 		} else if(s == "--relay") {
887 			relay_through_server_ = true;
888 		} else if(s == "--failing-tests") {
889 			run_failing_unit_tests_ = true;
890 		} else if(s == "--serialize-bad-objects") {
891 			serialize_bad_objects_ = true;
892 		} else if(s == "--no-autopause") {
893 			allow_autopause_ = false;
894 		} else if(s == "--autopause") {
895 			allow_autopause_ = true;
896 		} else if(arg_name == "--difficulty" && !arg_value.empty()) {
897 			if(boost::regex_match(arg_value, boost::regex("-?[0-9]+"))) {
898 				force_difficulty_ = boost::lexical_cast<int>(arg_value);
899 			} else {
900 				force_difficulty_ = difficulty::from_string(arg_value);
901 			}
902 		} else {
903 			return false;
904 		}
905 
906 		return true;
907 	}
908 
use_16bpp_textures()909 	bool use_16bpp_textures() {
910 		return use_16bpp_textures_;
911 	}
912 
sim_iphone()913 	bool sim_iphone() {
914 		return sim_iphone_;
915 	}
916 
send_stats()917 	bool send_stats() {
918 		return send_stats_;
919 	}
920 
force_difficulty()921 	int force_difficulty() {
922 		return force_difficulty_;
923 	}
924 
record_history()925 	bool record_history() {
926 		return record_history_;
927 	}
928 
set_record_history(bool value)929 	void set_record_history(bool value) {
930 		record_history_ = value;
931 	}
932 
relay_through_server()933 	bool relay_through_server() {
934 		return relay_through_server_;
935 	}
936 
external_code_editor()937 	variant external_code_editor() {
938 		return external_code_editor_;
939 	}
940 
set_relay_through_server(bool value)941 	void set_relay_through_server(bool value) {
942 		relay_through_server_ = value;
943 	}
944 
run_failing_unit_tests()945 	bool run_failing_unit_tests() {
946 		return run_failing_unit_tests_;
947 	}
948 
serialize_bad_objects()949 	bool serialize_bad_objects() {
950 		return serialize_bad_objects_;
951 	}
952 
953 #if defined(TARGET_OS_HARMATTAN) || defined(TARGET_PANDORA) || defined(TARGET_TEGRA) || defined(TARGET_BLACKBERRY)
954 	PFNGLBLENDEQUATIONOESPROC           glBlendEquationOES;
955 	PFNGLGENFRAMEBUFFERSOESPROC         glGenFramebuffersOES;
956 	PFNGLBINDFRAMEBUFFEROESPROC         glBindFramebufferOES;
957 	PFNGLFRAMEBUFFERTEXTURE2DOESPROC    glFramebufferTexture2DOES;
958 	PFNGLCHECKFRAMEBUFFERSTATUSOESPROC  glCheckFramebufferStatusOES;
959 
init_oes(void)960 	void init_oes( void )
961 	{
962 		int retry;
963 		const GLubyte* pszGLExtensions = NULL;
964 
965 		glBlendEquationOES          = NULL;
966 		glGenFramebuffersOES        = NULL;
967 		glBindFramebufferOES        = NULL;
968 		glFramebufferTexture2DOES   = NULL;
969 		glCheckFramebufferStatusOES = NULL;
970 
971 		/* Retrieve GL extension string */
972 		pszGLExtensions = glGetString(GL_EXTENSIONS);
973 
974 		// Blend subtract Functions
975 		if(preferences::use_bequ())
976 		{
977 			/* GL_OES_framebuffer_object */
978 			if (strstr((char *)pszGLExtensions, "GL_OES_blend_subtract"))
979 			{
980 				for (retry=1; retry<4; retry++)
981 				{
982 					glBlendEquationOES = (PFNGLBLENDEQUATIONOESPROC)eglGetProcAddress("glBlendEquationOES");
983 					if (glBlendEquationOES!=NULL) {
984 						std::cerr << "glBlendEquationOES was set correctly\n";
985 						break;
986 					}
987 					else
988 					{
989 						std::cerr << "glBlendEquationOES was set to NULL by eglGetProcAddress retry #" << retry << "\n";
990 					}
991 				}
992 			}
993 			else
994 			{
995 				glBlendEquationOES = NULL;
996 			}
997 		}
998 		else
999 		{
1000 			glBlendEquationOES = NULL;
1001 		}
1002 
1003 		// FBO Functions
1004 		if(preferences::use_fbo())
1005 		{
1006 			/* GL_OES_framebuffer_object */
1007 			if (strstr((char *)pszGLExtensions, "GL_OES_framebuffer_object"))
1008 			{
1009 				for (retry=1; retry<4; retry++)
1010 				{
1011 					glGenFramebuffersOES        = (PFNGLGENFRAMEBUFFERSOESPROC)eglGetProcAddress("glGenFramebuffersOES");
1012 					if (glGenFramebuffersOES!=NULL) {
1013 						std::cerr << "glGenFramebuffersOES was set correctly\n";
1014 						break;
1015 					}
1016 					else
1017 					{
1018 						std::cerr << "glGenFramebuffersOES was set to NULL by eglGetProcAddress retry #" << retry << "\n";
1019 					}
1020 				}
1021 				for (retry=1; retry<4; retry++)
1022 				{
1023 					glBindFramebufferOES        = (PFNGLBINDFRAMEBUFFEROESPROC)eglGetProcAddress("glBindFramebufferOES");
1024 					if (glBindFramebufferOES!=NULL) {
1025 						std::cerr << "glBindFramebufferOES was set correctly\n";
1026 						break;
1027 					}
1028 					else
1029 					{
1030 						std::cerr << "glBindFramebufferOES was set to NULL by eglGetProcAddress retry #" << retry << "\n";
1031 					}
1032 				}
1033 				for (retry=1; retry<4; retry++)
1034 				{
1035 					glFramebufferTexture2DOES   = (PFNGLFRAMEBUFFERTEXTURE2DOESPROC)eglGetProcAddress("glFramebufferTexture2DOES");
1036 					if (glFramebufferTexture2DOES!=NULL) {
1037 						std::cerr << "glFramebufferTexture2DOES was set correctly\n";
1038 						break;
1039 					}
1040 					else
1041 					{
1042 						std::cerr << "glFramebufferTexture2DOES was set to NULL by eglGetProcAddress retry #" << retry << "\n";
1043 					}
1044 				}
1045 				for (retry=1; retry<4; retry++)
1046 				{
1047 					glCheckFramebufferStatusOES = (PFNGLCHECKFRAMEBUFFERSTATUSOESPROC)eglGetProcAddress("glCheckFramebufferStatusOES");
1048 					if (glCheckFramebufferStatusOES!=NULL) {
1049 						std::cerr << "glCheckFramebufferStatusOES was set correctly\n";
1050 						break;
1051 					}
1052 					else
1053 					{
1054 						std::cerr << "glCheckFramebufferStatusOES was set to NULL by eglGetProcAddress retry #" << retry << "\n";
1055 					}
1056 				}
1057 			}
1058 			else
1059 			{
1060 				glGenFramebuffersOES        = NULL;
1061 				glBindFramebufferOES        = NULL;
1062 				glFramebufferTexture2DOES   = NULL;
1063 				glCheckFramebufferStatusOES = NULL;
1064 			}
1065 		}
1066 		else
1067 		{
1068 			glGenFramebuffersOES        = NULL;
1069 			glBindFramebufferOES        = NULL;
1070 			glFramebufferTexture2DOES   = NULL;
1071 			glCheckFramebufferStatusOES = NULL;
1072 		}
1073 	}
1074 #endif
1075 	}
1076