summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/SCsub2
-rw-r--r--main/input_default.cpp72
-rw-r--r--main/input_default.h16
-rw-r--r--main/main.cpp287
-rw-r--r--main/main.h2
-rw-r--r--main/performance.cpp14
-rw-r--r--main/performance.h4
-rw-r--r--main/splash.h2
-rw-r--r--main/tests/SCsub14
-rw-r--r--main/tests/test_containers.cpp106
-rw-r--r--main/tests/test_containers.h43
-rw-r--r--main/tests/test_gdscript.cpp1065
-rw-r--r--main/tests/test_gdscript.h47
-rw-r--r--main/tests/test_gui.cpp402
-rw-r--r--main/tests/test_gui.h44
-rw-r--r--main/tests/test_image.cpp77
-rw-r--r--main/tests/test_image.h44
-rw-r--r--main/tests/test_io.cpp208
-rw-r--r--main/tests/test_io.h44
-rw-r--r--main/tests/test_main.cpp166
-rw-r--r--main/tests/test_main.h41
-rw-r--r--main/tests/test_math.cpp816
-rw-r--r--main/tests/test_math.h40
-rw-r--r--main/tests/test_physics.cpp644
-rw-r--r--main/tests/test_physics.h44
-rw-r--r--main/tests/test_physics_2d.cpp471
-rw-r--r--main/tests/test_physics_2d.h41
-rw-r--r--main/tests/test_render.cpp262
-rw-r--r--main/tests/test_render.h44
-rw-r--r--main/tests/test_shader_lang.cpp361
-rw-r--r--main/tests/test_shader_lang.h40
-rw-r--r--main/tests/test_sound.cpp95
-rw-r--r--main/tests/test_sound.h40
-rw-r--r--main/tests/test_string.cpp959
-rw-r--r--main/tests/test_string.h44
35 files changed, 6423 insertions, 178 deletions
diff --git a/main/SCsub b/main/SCsub
index a83563f44d..a09b7c4396 100644
--- a/main/SCsub
+++ b/main/SCsub
@@ -7,6 +7,8 @@ env.add_source_files(env.main_sources, "*.cpp")
Export('env')
+SConscript('tests/SCsub')
+
lib = env.Library("main", env.main_sources)
env.Prepend(LIBS=[lib])
diff --git a/main/input_default.cpp b/main/input_default.cpp
index c60fcd2243..50b0006438 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -126,16 +126,16 @@ bool InputDefault::is_action_pressed(const StringName& p_action) const{
if(mouse_button_mask&(1<<iemb.button_index))
return true;
} break;
- case InputEvent::JOYSTICK_BUTTON: {
+ case InputEvent::JOYPAD_BUTTON: {
- const InputEventJoystickButton &iejb=E->get().joy_button;
+ const InputEventJoypadButton &iejb=E->get().joy_button;
int c = _combine_device(iejb.button_index,device);
if (joy_buttons_pressed.has(c))
return true;
} break;
- case InputEvent::JOYSTICK_MOTION: {
+ case InputEvent::JOYPAD_MOTION: {
- const InputEventJoystickMotion &iejm=E->get().joy_motion;
+ const InputEventJoypadMotion &iejm=E->get().joy_motion;
int c = _combine_device(iejm.axis,device);
if (_joy_axis.has(c)) {
if (iejm.axis_value < 0) {
@@ -158,10 +158,10 @@ bool InputDefault::is_action_just_pressed(const StringName& p_action) const {
if (!E)
return false;
- if (OS::get_singleton()->is_in_fixed_frame()) {
- return E->get().pressed && E->get().fixed_frame==OS::get_singleton()->get_fixed_frames();
+ if (Engine::get_singleton()->is_in_fixed_frame()) {
+ return E->get().pressed && E->get().fixed_frame==Engine::get_singleton()->get_fixed_frames();
} else {
- return E->get().pressed && E->get().idle_frame==OS::get_singleton()->get_idle_frames();
+ return E->get().pressed && E->get().idle_frame==Engine::get_singleton()->get_idle_frames();
}
}
@@ -171,10 +171,10 @@ bool InputDefault::is_action_just_released(const StringName& p_action) const{
if (!E)
return false;
- if (OS::get_singleton()->is_in_fixed_frame()) {
- return !E->get().pressed && E->get().fixed_frame==OS::get_singleton()->get_fixed_frames();
+ if (Engine::get_singleton()->is_in_fixed_frame()) {
+ return !E->get().pressed && E->get().fixed_frame==Engine::get_singleton()->get_fixed_frames();
} else {
- return !E->get().pressed && E->get().idle_frame==OS::get_singleton()->get_idle_frames();
+ return !E->get().pressed && E->get().idle_frame==Engine::get_singleton()->get_idle_frames();
}
}
@@ -235,7 +235,7 @@ static String _hex_str(uint8_t p_byte) {
void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
_THREAD_SAFE_METHOD_
- Joystick js;
+ Joypad js;
js.name = p_connected ? p_name : "";
js.uid = p_connected ? p_guid : "";
js.mapping = -1;
@@ -307,7 +307,7 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
if (p_event.key.scancode==0)
break;
- // print_line(p_event);
+ //print_line(p_event);
if (p_event.key.pressed)
keys_pressed.insert(p_event.key.scancode);
@@ -356,7 +356,7 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
}
} break;
- case InputEvent::JOYSTICK_BUTTON: {
+ case InputEvent::JOYPAD_BUTTON: {
int c = _combine_device(p_event.joy_button.button_index,p_event.device);
@@ -365,7 +365,7 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
else
joy_buttons_pressed.erase(c);
} break;
- case InputEvent::JOYSTICK_MOTION: {
+ case InputEvent::JOYPAD_MOTION: {
set_joy_axis(p_event.device, p_event.joy_motion.axis, p_event.joy_motion.axis_value);
} break;
@@ -377,13 +377,13 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
if (InputMap::get_singleton()->event_is_action(p_event,E->key())) {
- Action action;
- action.fixed_frame=OS::get_singleton()->get_fixed_frames();
- action.idle_frame=OS::get_singleton()->get_idle_frames();
- action.pressed=p_event.is_pressed();
-
- action_state[E->key()]=action;
-
+ if(is_action_pressed(E->key()) != p_event.is_pressed()) {
+ Action action;
+ action.fixed_frame=Engine::get_singleton()->get_fixed_frames();
+ action.idle_frame=Engine::get_singleton()->get_idle_frames();
+ action.pressed=p_event.is_pressed();
+ action_state[E->key()]=action;
+ }
}
}
}
@@ -465,7 +465,7 @@ Point2 InputDefault::get_mouse_pos() const {
return mouse_pos;
}
-Point2 InputDefault::get_mouse_speed() const {
+Point2 InputDefault::get_last_mouse_speed() const {
return mouse_speed_track.speed;
}
@@ -490,8 +490,8 @@ void InputDefault::action_press(const StringName& p_action) {
Action action;
- action.fixed_frame=OS::get_singleton()->get_fixed_frames();
- action.idle_frame=OS::get_singleton()->get_idle_frames();
+ action.fixed_frame=Engine::get_singleton()->get_fixed_frames();
+ action.idle_frame=Engine::get_singleton()->get_idle_frames();
action.pressed=true;
action_state[p_action]=action;
@@ -502,8 +502,8 @@ void InputDefault::action_release(const StringName& p_action){
Action action;
- action.fixed_frame=OS::get_singleton()->get_fixed_frames();
- action.idle_frame=OS::get_singleton()->get_idle_frames();
+ action.fixed_frame=Engine::get_singleton()->get_fixed_frames();
+ action.idle_frame=Engine::get_singleton()->get_idle_frames();
action.pressed=false;
action_state[p_action]=action;
@@ -739,8 +739,8 @@ static const char *s_ControllerMappings [] =
"c2a94d6963726f736f66742058626f78,Wireless X360 Controller,leftx:a0,lefty:a1,dpdown:b14,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:b11,lefttrigger:a2,x:b2,dpup:b13,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:b12,righttrigger:a5,b:b1,",
#endif
- #ifdef WINRT_ENABLED
- "__WINRT_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,",
+ #ifdef UWP_ENABLED
+ "__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,",
#endif
NULL
};
@@ -791,7 +791,7 @@ InputDefault::InputDefault() {
uint32_t InputDefault::joy_button(uint32_t p_last_id, int p_device, int p_button, bool p_pressed) {
_THREAD_SAFE_METHOD_;
- Joystick& joy = joy_names[p_device];
+ Joypad& joy = joy_names[p_device];
//printf("got button %i, mapping is %i\n", p_button, joy.mapping);
if (joy.last_buttons[p_button] == p_pressed) {
return p_last_id;
@@ -831,7 +831,7 @@ uint32_t InputDefault::joy_axis(uint32_t p_last_id, int p_device, int p_axis, co
_THREAD_SAFE_METHOD_;
- Joystick& joy = joy_names[p_device];
+ Joypad& joy = joy_names[p_device];
if (joy.last_axis[p_axis] == p_value.value) {
return p_last_id;
@@ -935,7 +935,7 @@ uint32_t InputDefault::joy_axis(uint32_t p_last_id, int p_device, int p_axis, co
uint32_t InputDefault::joy_hat(uint32_t p_last_id, int p_device, int p_val) {
_THREAD_SAFE_METHOD_;
- const Joystick& joy = joy_names[p_device];
+ const Joypad& joy = joy_names[p_device];
JoyEvent* map;
@@ -969,7 +969,7 @@ uint32_t InputDefault::joy_hat(uint32_t p_last_id, int p_device, int p_val) {
uint32_t InputDefault::_button_event(uint32_t p_last_id, int p_device, int p_index, bool p_pressed) {
InputEvent ievent;
- ievent.type = InputEvent::JOYSTICK_BUTTON;
+ ievent.type = InputEvent::JOYPAD_BUTTON;
ievent.device = p_device;
ievent.ID = ++p_last_id;
ievent.joy_button.button_index = p_index;
@@ -983,7 +983,7 @@ uint32_t InputDefault::_button_event(uint32_t p_last_id, int p_device, int p_ind
uint32_t InputDefault::_axis_event(uint32_t p_last_id, int p_device, int p_axis, float p_value) {
InputEvent ievent;
- ievent.type = InputEvent::JOYSTICK_MOTION;
+ ievent.type = InputEvent::JOYPAD_MOTION;
ievent.device = p_device;
ievent.ID = ++p_last_id;
ievent.joy_motion.axis = p_axis;
@@ -1148,9 +1148,9 @@ String InputDefault::get_joy_guid_remapped(int p_device) const {
return joy_names[p_device].uid;
}
-Array InputDefault::get_connected_joysticks() {
+Array InputDefault::get_connected_joypads() {
Array ret;
- Map<int, Joystick>::Element *elem = joy_names.front();
+ Map<int, Joypad>::Element *elem = joy_names.front();
while (elem) {
if (elem->get().connected) {
ret.push_back(elem->key());
diff --git a/main/input_default.h b/main/input_default.h
index 2db6d28abf..cab505644d 100644
--- a/main/input_default.h
+++ b/main/input_default.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@
class InputDefault : public Input {
- OBJ_TYPE( InputDefault, Input );
+ GDCLASS( InputDefault, Input );
_THREAD_SAFE_CLASS_
int mouse_button_mask;
@@ -84,7 +84,7 @@ class InputDefault : public Input {
SpeedTrack();
};
- struct Joystick {
+ struct Joypad {
StringName name;
StringName uid;
bool connected;
@@ -95,7 +95,7 @@ class InputDefault : public Input {
int mapping;
int hat_current;
- Joystick() {
+ Joypad() {
for (int i = 0; i < JOY_AXIS_MAX; i++) {
@@ -114,7 +114,7 @@ class InputDefault : public Input {
};
SpeedTrack mouse_speed_track;
- Map<int, Joystick> joy_names;
+ Map<int, Joypad> joy_names;
int fallback_mapping;
RES custom_cursor;
public:
@@ -184,19 +184,19 @@ public:
virtual float get_joy_axis(int p_device,int p_axis) const;
String get_joy_name(int p_idx);
- virtual Array get_connected_joysticks();
+ virtual Array get_connected_joypads();
virtual Vector2 get_joy_vibration_strength(int p_device);
virtual float get_joy_vibration_duration(int p_device);
virtual uint64_t get_joy_vibration_timestamp(int p_device);
void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
- void parse_joystick_mapping(String p_mapping, bool p_update_existing);
+ void parse_joypad_mapping(String p_mapping, bool p_update_existing);
virtual Vector3 get_accelerometer() const;
virtual Vector3 get_magnetometer() const;
virtual Vector3 get_gyroscope() const;
virtual Point2 get_mouse_pos() const;
- virtual Point2 get_mouse_speed() const;
+ virtual Point2 get_last_mouse_speed() const;
virtual int get_mouse_button_mask() const;
virtual void warp_mouse_pos(const Vector2& p_to);
diff --git a/main/main.cpp b/main/main.cpp
index 912e8adf4f..e535da3e28 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,7 +47,7 @@
#include "script_language.h"
#include "io/resource_loader.h"
-#include "bin/tests/test_main.h"
+#include "main/tests/test_main.h"
#include "os/dir_access.h"
#include "core/io/ip.h"
#include "scene/resources/packed_scene.h"
@@ -78,7 +78,8 @@
#include "main/input_default.h"
#include "performance.h"
-static Globals *globals=NULL;
+static GlobalConfig *globals=NULL;
+static Engine *engine=NULL;
static InputMap *input_map=NULL;
static bool _start_success=false;
static ScriptDebugger *script_debugger=NULL;
@@ -127,7 +128,7 @@ static String unescape_cmdline(const String& p_str) {
void Main::print_help(const char* p_binary) {
- OS::get_singleton()->print(VERSION_FULL_NAME" (c) 2008-2016 Juan Linietsky, Ariel Manzur.\n");
+ OS::get_singleton()->print(VERSION_FULL_NAME" (c) 2008-2017 Juan Linietsky, Ariel Manzur.\n");
OS::get_singleton()->print("Usage: %s [options] [scene]\n",p_binary);
OS::get_singleton()->print("Options:\n");
OS::get_singleton()->print("\t-path [dir] : Path to a game, containing engine.cfg\n");
@@ -159,7 +160,7 @@ void Main::print_help(const char* p_binary) {
OS::get_singleton()->print("%s",OS::get_singleton()->get_video_driver_name(i));
}
OS::get_singleton()->print(")\n");
- OS::get_singleton()->print("\t-ldpi\t : Force low-dpi mode (OSX Only)");
+ OS::get_singleton()->print("\t-ldpi\t : Force low-dpi mode (OSX Only)\n");
OS::get_singleton()->print("\t-ad DRIVER\t : Audio Driver (");
for (int i=0;i<OS::get_singleton()->get_audio_driver_count();i++) {
@@ -169,8 +170,7 @@ void Main::print_help(const char* p_binary) {
OS::get_singleton()->print("%s",OS::get_singleton()->get_audio_driver_name(i));
}
OS::get_singleton()->print(")\n");
- OS::get_singleton()->print("\t-rthread <mode>\t : Render Thread Mode ('unsafe', 'safe', 'separate).");
- OS::get_singleton()->print(")\n");
+ OS::get_singleton()->print("\t-rthread <mode>\t : Render Thread Mode ('unsafe', 'safe', 'separate').\n");
OS::get_singleton()->print("\t-s,-script [script] : Run a script.\n");
OS::get_singleton()->print("\t-d,-debug : Debug (local stdout debugger).\n");
OS::get_singleton()->print("\t-rdebug ADDRESS : Remote debug (<ip>:<port> host address).\n");
@@ -196,7 +196,10 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
RID_OwnerBase::init_rid();
OS::get_singleton()->initialize_core();
- ObjectTypeDB::init();
+
+ engine = memnew( Engine );
+
+ ClassDB::init();
MAIN_PRINT("Main: Initialize CORE");
@@ -208,14 +211,15 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
Thread::_main_thread_id = Thread::get_caller_ID();
- globals = memnew( Globals );
+ globals = memnew( GlobalConfig );
input_map = memnew( InputMap );
+ register_core_settings(); //here globals is present
path_remap = memnew( PathRemap );
translation_server = memnew( TranslationServer );
performance = memnew( Performance );
- globals->add_singleton(Globals::Singleton("Performance",performance));
+ globals->add_singleton(GlobalConfig::Singleton("Performance",performance));
MAIN_PRINT("Main: Parse CMDLine");
@@ -235,7 +239,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
while (I) {
I->get()=unescape_cmdline(I->get().strip_escapes());
-// print_line("CMD: "+I->get());
+ //print_line("CMD: "+I->get());
I=I->next();
}
@@ -499,7 +503,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (I->next()) {
- OS::get_singleton()->set_time_scale(I->next()->get().to_double());
+ Engine::get_singleton()->set_time_scale(I->next()->get().to_double());
N=I->next()->next();
} else {
goto error;
@@ -539,7 +543,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (I->next()) {
- Globals::get_singleton()->set("editor_scene",game_path=I->next()->get());
+ GlobalConfig::get_singleton()->set("editor_scene",game_path=I->next()->get());
} else {
goto error;
@@ -563,7 +567,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (I->next()) {
int editor_pid=I->next()->get().to_int();
- Globals::get_singleton()->set("editor_pid",editor_pid);
+ GlobalConfig::get_singleton()->set("editor_pid",editor_pid);
N=I->next()->next();
} else {
goto error;
@@ -593,11 +597,13 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
- GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048);
+ GLOBAL_DEF("network/debug/max_remote_stdout_chars_per_second",2048);
+ GLOBAL_DEF("network/debug/remote_port",6007);
+
if (debug_mode == "remote") {
ScriptDebuggerRemote *sdr = memnew( ScriptDebuggerRemote );
- uint16_t debug_port = GLOBAL_DEF("debug/remote_port",6007);
+ uint16_t debug_port = GLOBAL_GET("network/debug/remote_port");
if (debug_host.find(":")!=-1) {
debug_port=debug_host.get_slicec(':',1).to_int();
debug_host=debug_host.get_slicec(':',0);
@@ -615,6 +621,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
+ FileAccessNetwork::configure();
if (remotefs!="") {
@@ -679,10 +686,10 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
use_custom_res=false;
}
- if (bool(Globals::get_singleton()->get("application/disable_stdout"))) {
+ if (bool(GlobalConfig::get_singleton()->get("application/disable_stdout"))) {
quiet_stdout=true;
}
- if (bool(Globals::get_singleton()->get("application/disable_stderr"))) {
+ if (bool(GlobalConfig::get_singleton()->get("application/disable_stderr"))) {
_print_error_enabled = false;
};
@@ -693,7 +700,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
#ifdef TOOLS_ENABLED
- if (main_args.size()==0 && (!Globals::get_singleton()->has("application/main_loop_type")) && (!Globals::get_singleton()->has("application/main_scene") || String(Globals::get_singleton()->get("application/main_scene"))==""))
+ if (main_args.size()==0 && (!GlobalConfig::get_singleton()->has("application/main_loop_type")) && (!GlobalConfig::get_singleton()->has("application/main_scene") || String(GlobalConfig::get_singleton()->get("application/main_scene"))==""))
use_custom_res=false; //project manager (run without arguments)
#endif
@@ -704,25 +711,25 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
input_map->load_from_globals(); //keys for game
if (video_driver=="") // specified in engine.cfg
- video_driver=_GLOBAL_DEF("display/driver",Variant((const char*)OS::get_singleton()->get_video_driver_name(0)));
+ video_driver=GLOBAL_DEF("display/driver/name",Variant((const char*)OS::get_singleton()->get_video_driver_name(0)));
- if (!force_res && use_custom_res && globals->has("display/width"))
- video_mode.width=globals->get("display/width");
- if (!force_res &&use_custom_res && globals->has("display/height"))
- video_mode.height=globals->get("display/height");
- if (!editor && (!bool(globals->get("display/allow_hidpi")) || force_lowdpi)) {
+ if (!force_res && use_custom_res && globals->has("display/window/width"))
+ video_mode.width=globals->get("display/window/width");
+ if (!force_res &&use_custom_res && globals->has("display/window/height"))
+ video_mode.height=globals->get("display/window/height");
+ if (!editor && (!bool(globals->get("display/window/allow_hidpi")) || force_lowdpi)) {
OS::get_singleton()->_allow_hidpi=false;
}
- if (use_custom_res && globals->has("display/fullscreen"))
- video_mode.fullscreen=globals->get("display/fullscreen");
- if (use_custom_res && globals->has("display/resizable"))
- video_mode.resizable=globals->get("display/resizable");
- if (use_custom_res && globals->has("display/borderless_window"))
- video_mode.borderless_window = globals->get("display/borderless_window");
-
- if (!force_res && use_custom_res && globals->has("display/test_width") && globals->has("display/test_height")) {
- int tw = globals->get("display/test_width");
- int th = globals->get("display/test_height");
+ if (use_custom_res && globals->has("display/window/fullscreen"))
+ video_mode.fullscreen=globals->get("display/window/fullscreen");
+ if (use_custom_res && globals->has("display/window/resizable"))
+ video_mode.resizable=globals->get("display/window/resizable");
+ if (use_custom_res && globals->has("display/window/borderless"))
+ video_mode.borderless_window = globals->get("display/window/borderless");
+
+ if (!force_res && use_custom_res && globals->has("display/window/test_width") && globals->has("display/window/test_height")) {
+ int tw = globals->get("display/window/test_width");
+ int th = globals->get("display/window/test_height");
if (tw>0 && th>0) {
video_mode.width=tw;
video_mode.height=th;
@@ -730,19 +737,19 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
- GLOBAL_DEF("display/width",video_mode.width);
- GLOBAL_DEF("display/height",video_mode.height);
- GLOBAL_DEF("display/allow_hidpi",false);
- GLOBAL_DEF("display/fullscreen",video_mode.fullscreen);
- GLOBAL_DEF("display/resizable",video_mode.resizable);
- GLOBAL_DEF("display/borderless_window", video_mode.borderless_window);
- use_vsync = GLOBAL_DEF("display/use_vsync", use_vsync);
- GLOBAL_DEF("display/test_width",0);
- GLOBAL_DEF("display/test_height",0);
- OS::get_singleton()->_pixel_snap=GLOBAL_DEF("display/use_2d_pixel_snap",false);
- OS::get_singleton()->_keep_screen_on=GLOBAL_DEF("display/keep_screen_on",true);
+ GLOBAL_DEF("display/window/width",video_mode.width);
+ GLOBAL_DEF("display/window/height",video_mode.height);
+ GLOBAL_DEF("display/window/allow_hidpi",false);
+ GLOBAL_DEF("display/window/fullscreen",video_mode.fullscreen);
+ GLOBAL_DEF("display/window/resizable",video_mode.resizable);
+ GLOBAL_DEF("display/window/borderless", video_mode.borderless_window);
+ use_vsync = GLOBAL_DEF("display/window/use_vsync", use_vsync);
+ GLOBAL_DEF("display/window/test_width",0);
+ GLOBAL_DEF("display/window/test_height",0);
+ Engine::get_singleton()->_pixel_snap=GLOBAL_DEF("rendering/2d/use_pixel_snap",false);
+ OS::get_singleton()->_keep_screen_on=GLOBAL_DEF("display/energy_saving/keep_screen_on",true);
if (rtm==-1) {
- rtm=GLOBAL_DEF("render/thread_model",OS::RENDER_THREAD_SAFE);
+ rtm=GLOBAL_DEF("rendering/threads/thread_model",OS::RENDER_THREAD_SAFE);
if (rtm>=1) //hack for now
rtm=1;
@@ -797,7 +804,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
{
- String orientation = GLOBAL_DEF("display/orientation","landscape");
+ String orientation = GLOBAL_DEF("display/handheld/orientation","landscape");
if (orientation=="portrait")
OS::get_singleton()->set_screen_orientation(OS::SCREEN_PORTRAIT);
@@ -816,21 +823,23 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
- OS::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/fixed_fps",60));
- OS::get_singleton()->set_target_fps(GLOBAL_DEF("debug/force_fps",0));
+ Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/fixed_fps",60));
+ Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/fps/force_fps",0));
+
+ GLOBAL_DEF("debug/stdout/print_fps", OS::get_singleton()->is_stdout_verbose());
if (!OS::get_singleton()->_verbose_stdout) //overrided
- OS::get_singleton()->_verbose_stdout=GLOBAL_DEF("debug/verbose_stdout",false);
+ OS::get_singleton()->_verbose_stdout=GLOBAL_DEF("debug/stdout/verbose_stdout",false);
if (frame_delay==0) {
frame_delay=GLOBAL_DEF("application/frame_delay_msec",0);
}
- OS::get_singleton()->set_frame_delay(frame_delay);
+ Engine::get_singleton()->set_frame_delay(frame_delay);
message_queue = memnew( MessageQueue );
- Globals::get_singleton()->register_global_defaults();
+ GlobalConfig::get_singleton()->register_global_defaults();
if (p_second_phase)
return setup2();
@@ -857,6 +866,8 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
memdelete( translation_server );
if (globals)
memdelete(globals);
+ if (engine)
+ memdelete(engine);
if (script_debugger)
memdelete(script_debugger);
if (packed_data)
@@ -868,10 +879,12 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
// Note 1: *zip_packed_data live into *packed_data
// Note 2: PackedData::~PackedData destroy this.
-//#ifdef MINIZIP_ENABLED
-// if (zip_packed_data)
-// memdelete( zip_packed_data );
-//#endif
+/*
+#ifdef MINIZIP_ENABLED
+ if (zip_packed_data)
+ memdelete( zip_packed_data );
+#endif
+*/
unregister_core_driver_types();
unregister_core_types();
@@ -919,10 +932,13 @@ Error Main::setup2() {
path_remap->load_remaps();
+ Color clear = GLOBAL_DEF("rendering/viewport/default_clear_color",Color(0.3,0.3,0.3));
+ VisualServer::get_singleton()->set_default_clear_color(clear);
+
if (show_logo) { //boot logo!
String boot_logo_path=GLOBAL_DEF("application/boot_splash",String());
bool boot_logo_scale=GLOBAL_DEF("application/boot_splash_fullsize",true);
- Globals::get_singleton()->set_custom_property_info("application/boot_splash",PropertyInfo(Variant::STRING,"application/boot_splash",PROPERTY_HINT_FILE,"*.png"));
+ GlobalConfig::get_singleton()->set_custom_property_info("application/boot_splash",PropertyInfo(Variant::STRING,"application/boot_splash",PROPERTY_HINT_FILE,"*.png"));
Image boot_logo;
@@ -937,13 +953,11 @@ Error Main::setup2() {
if (!boot_logo.empty()) {
OS::get_singleton()->_msec_splash=OS::get_singleton()->get_ticks_msec();
- Color clear = GLOBAL_DEF("render/default_clear_color",Color(0.3,0.3,0.3));
- VisualServer::get_singleton()->set_default_clear_color(clear);
Color boot_bg = GLOBAL_DEF("application/boot_bg_color", clear);
VisualServer::get_singleton()->set_boot_image(boot_logo, boot_bg,boot_logo_scale);
#ifndef TOOLS_ENABLED
//no tools, so free the boot logo (no longer needed)
- // Globals::get_singleton()->set("application/boot_logo",Image());
+ //GlobalConfig::get_singleton()->set("application/boot_logo",Image());
#endif
} else {
@@ -964,13 +978,13 @@ Error Main::setup2() {
}
MAIN_PRINT("Main: DCC");
- VisualServer::get_singleton()->set_default_clear_color(GLOBAL_DEF("render/default_clear_color",Color(0.3,0.3,0.3)));
+ VisualServer::get_singleton()->set_default_clear_color(GLOBAL_DEF("rendering/viewport/default_clear_color",Color(0.3,0.3,0.3)));
MAIN_PRINT("Main: END");
GLOBAL_DEF("application/icon",String());
- Globals::get_singleton()->set_custom_property_info("application/icon",PropertyInfo(Variant::STRING,"application/icon",PROPERTY_HINT_FILE,"*.png,*.webp"));
+ GlobalConfig::get_singleton()->set_custom_property_info("application/icon",PropertyInfo(Variant::STRING,"application/icon",PROPERTY_HINT_FILE,"*.png,*.webp"));
- if (bool(GLOBAL_DEF("display/emulate_touchscreen",false))) {
+ if (bool(GLOBAL_DEF("display/handheld/emulate_touchscreen",false))) {
if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton() && !editor) {
//only if no touchscreen ui hint, set emulation
InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();
@@ -988,25 +1002,25 @@ Error Main::setup2() {
register_scene_types();
register_server_types();
- GLOBAL_DEF("display/custom_mouse_cursor",String());
- GLOBAL_DEF("display/custom_mouse_cursor_hotspot",Vector2());
- Globals::get_singleton()->set_custom_property_info("display/custom_mouse_cursor",PropertyInfo(Variant::STRING,"display/custom_mouse_cursor",PROPERTY_HINT_FILE,"*.png,*.webp"));
+ GLOBAL_DEF("display/mouse_cursor/custom_image",String());
+ GLOBAL_DEF("display/mouse_cursor/custom_image_hotspot",Vector2());
+ GlobalConfig::get_singleton()->set_custom_property_info("display/mouse_cursor/custom_image",PropertyInfo(Variant::STRING,"display/mouse_cursor/custom_image",PROPERTY_HINT_FILE,"*.png,*.webp"));
- if (String(Globals::get_singleton()->get("display/custom_mouse_cursor"))!=String()) {
+ if (String(GlobalConfig::get_singleton()->get("display/mouse_cursor/custom_image"))!=String()) {
//print_line("use custom cursor");
- Ref<Texture> cursor=ResourceLoader::load(Globals::get_singleton()->get("display/custom_mouse_cursor"));
+ Ref<Texture> cursor=ResourceLoader::load(GlobalConfig::get_singleton()->get("display/mouse_cursor/custom_image"));
if (cursor.is_valid()) {
- // print_line("loaded ok");
- Vector2 hotspot = Globals::get_singleton()->get("display/custom_mouse_cursor_hotspot");
+ //print_line("loaded ok");
+ Vector2 hotspot = GlobalConfig::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
Input::get_singleton()->set_custom_mouse_cursor(cursor,hotspot);
}
}
#ifdef TOOLS_ENABLED
- ObjectTypeDB::set_current_api(ObjectTypeDB::API_EDITOR);
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
EditorNode::register_editor_types();
- ObjectTypeDB::set_current_api(ObjectTypeDB::API_CORE);
+ ClassDB::set_current_api(ClassDB::API_CORE);
#endif
@@ -1034,8 +1048,12 @@ Error Main::setup2() {
_start_success=true;
locale=String();
- ObjectTypeDB::set_current_api(ObjectTypeDB::API_NONE); //no more api is registered at this point
+ ClassDB::set_current_api(ClassDB::API_NONE); //no more api is registered at this point
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_line("CORE API HASH: "+itos(ClassDB::get_api_hash(ClassDB::API_CORE)));
+ print_line("EDITOR API HASH: "+itos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
+ }
MAIN_PRINT("Main: Done");
return OK;
@@ -1086,7 +1104,7 @@ bool Main::start() {
} else if (args[i]=="-script" || args[i]=="-s") {
script=args[i+1];
} else if (args[i]=="-level" || args[i]=="-l") {
- OS::get_singleton()->_custom_level=args[i+1];
+ Engine::get_singleton()->_custom_level=args[i+1];
} else if (args[i]=="-test") {
test=args[i+1];
} else if (args[i]=="-optimize") {
@@ -1119,8 +1137,7 @@ bool Main::start() {
}
}
- if (editor)
- Globals::get_singleton()->set("editor_active",true);
+ GLOBAL_DEF("editor/active",editor);
String main_loop_type;
@@ -1191,7 +1208,7 @@ bool Main::start() {
StringName instance_type=script_res->get_instance_base_type();
- Object *obj = ObjectTypeDB::instance(instance_type);
+ Object *obj = ClassDB::instance(instance_type);
MainLoop *script_loop = obj?obj->cast_to<MainLoop>():NULL;
if (!script_loop) {
if (obj)
@@ -1216,12 +1233,12 @@ bool Main::start() {
main_loop_type="SceneTree";
if (!main_loop) {
- if (!ObjectTypeDB::type_exists(main_loop_type)) {
+ if (!ClassDB::class_exists(main_loop_type)) {
OS::get_singleton()->alert("godot: error: MainLoop type doesn't exist: "+main_loop_type);
return false;
} else {
- Object *ml = ObjectTypeDB::instance(main_loop_type);
+ Object *ml = ClassDB::instance(main_loop_type);
if (!ml) {
ERR_EXPLAIN("Can't instance MainLoop type");
ERR_FAIL_V(false);
@@ -1238,7 +1255,7 @@ bool Main::start() {
}
}
- if (main_loop->is_type("SceneTree")) {
+ if (main_loop->is_class("SceneTree")) {
SceneTree *sml = main_loop->cast_to<SceneTree>();
@@ -1271,9 +1288,9 @@ bool Main::start() {
if (!editor) {
//standard helpers that can be changed from main config
- String stretch_mode = GLOBAL_DEF("display/stretch_mode","disabled");
- String stretch_aspect = GLOBAL_DEF("display/stretch_aspect","ignore");
- Size2i stretch_size = Size2(GLOBAL_DEF("display/width",0),GLOBAL_DEF("display/height",0));
+ String stretch_mode = GLOBAL_DEF("display/stretch/mode","disabled");
+ String stretch_aspect = GLOBAL_DEF("display/stretch/aspect","ignore");
+ Size2i stretch_size = Size2(GLOBAL_DEF("display/screen/width",0),GLOBAL_DEF("display/screen/height",0));
SceneTree::StretchMode sml_sm=SceneTree::STRETCH_MODE_DISABLED;
if (stretch_mode=="2d")
@@ -1292,19 +1309,42 @@ bool Main::start() {
sml->set_screen_stretch(sml_sm,sml_aspect,stretch_size);
sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true));
- String appname = Globals::get_singleton()->get("application/name");
+ sml->set_quit_on_go_back(GLOBAL_DEF("application/quit_on_go_back",true));
+ String appname = GlobalConfig::get_singleton()->get("application/name");
appname = TranslationServer::get_singleton()->translate(appname);
OS::get_singleton()->set_window_title(appname);
+ int shadow_atlas_size = GLOBAL_DEF("rendering/shadow_atlas/size",2048);
+ int shadow_atlas_q0_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2);
+ int shadow_atlas_q1_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2);
+ int shadow_atlas_q2_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3);
+ int shadow_atlas_q3_subdiv = GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4);
+
+ sml->get_root()->set_shadow_atlas_size(shadow_atlas_size);
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(0,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q0_subdiv));
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(1,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q1_subdiv));
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(2,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q2_subdiv));
+ sml->get_root()->set_shadow_atlas_quadrant_subdiv(3,Viewport::ShadowAtlasQuadrantSubdiv(shadow_atlas_q3_subdiv));
} else {
- GLOBAL_DEF("display/stretch_mode","disabled");
- Globals::get_singleton()->set_custom_property_info("display/stretch_mode",PropertyInfo(Variant::STRING,"display/stretch_mode",PROPERTY_HINT_ENUM,"disabled,2d,viewport"));
- GLOBAL_DEF("display/stretch_aspect","ignore");
- Globals::get_singleton()->set_custom_property_info("display/stretch_aspect",PropertyInfo(Variant::STRING,"display/stretch_aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height"));
+ GLOBAL_DEF("display/stretch/mode","disabled");
+ GlobalConfig::get_singleton()->set_custom_property_info("display/stretch/mode",PropertyInfo(Variant::STRING,"display/stretch/mode",PROPERTY_HINT_ENUM,"disabled,2d,viewport"));
+ GLOBAL_DEF("display/stretch/aspect","ignore");
+ GlobalConfig::get_singleton()->set_custom_property_info("display/stretch/aspect",PropertyInfo(Variant::STRING,"display/stretch/aspect",PROPERTY_HINT_ENUM,"ignore,keep,keep_width,keep_height"));
sml->set_auto_accept_quit(GLOBAL_DEF("application/auto_accept_quit",true));
-
-
+ sml->set_quit_on_go_back(GLOBAL_DEF("application/quit_on_go_back",true));
+
+ GLOBAL_DEF("rendering/shadow_atlas/size",2048);
+ GlobalConfig::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size",PropertyInfo(Variant::INT,"rendering/shadow_atlas/size",PROPERTY_HINT_RANGE,"256,16384"));
+
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_0_subdiv",2);
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_1_subdiv",2);
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_2_subdiv",3);
+ GLOBAL_DEF("rendering/shadow_atlas/quadrant_3_subdiv",4);
+ GlobalConfig::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_0_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_0_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ GlobalConfig::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_1_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_1_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ GlobalConfig::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_2_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_2_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
+ GlobalConfig::get_singleton()->set_custom_property_info("rendering/shadow_atlas/quadrant_3_subdiv",PropertyInfo(Variant::INT,"rendering/shadow_atlas/quadrant_3_subdiv",PROPERTY_HINT_ENUM,"Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"));
}
@@ -1318,7 +1358,7 @@ bool Main::start() {
if (!absolute) {
- if (Globals::get_singleton()->is_using_datapack()) {
+ if (GlobalConfig::get_singleton()->is_using_datapack()) {
local_game_path="res://"+local_game_path;
@@ -1342,7 +1382,7 @@ bool Main::start() {
}
}
- local_game_path=Globals::get_singleton()->localize_path(local_game_path);
+ local_game_path=GlobalConfig::get_singleton()->localize_path(local_game_path);
#ifdef TOOLS_ENABLED
if (editor) {
@@ -1386,7 +1426,7 @@ bool Main::start() {
if (game_path!="" || script!="") {
//autoload
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
//first pass, add the constants so they exist before any script is loaded
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -1395,7 +1435,7 @@ bool Main::start() {
if (!s.begins_with("autoload/"))
continue;
String name = s.get_slicec('/',1);
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
bool global_var=false;
if (path.begins_with("*")) {
global_var=true;
@@ -1417,7 +1457,7 @@ bool Main::start() {
if (!s.begins_with("autoload/"))
continue;
String name = s.get_slicec('/',1);
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
bool global_var=false;
if (path.begins_with("*")) {
global_var=true;
@@ -1428,17 +1468,17 @@ bool Main::start() {
ERR_EXPLAIN("Can't autoload: "+path);
ERR_CONTINUE(res.is_null());
Node *n=NULL;
- if (res->is_type("PackedScene")) {
+ if (res->is_class("PackedScene")) {
Ref<PackedScene> ps = res;
n=ps->instance();
- } else if (res->is_type("Script")) {
+ } else if (res->is_class("Script")) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
- bool valid_type = ObjectTypeDB::is_type(ibt,"Node");
+ bool valid_type = ClassDB::is_parent_class(ibt,"Node");
ERR_EXPLAIN("Script does not inherit a Node: "+path);
ERR_CONTINUE( !valid_type );
- Object *obj = ObjectTypeDB::instance(ibt);
+ Object *obj = ClassDB::instance(ibt);
ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: "+String(ibt));
ERR_CONTINUE( obj==NULL );
@@ -1547,11 +1587,12 @@ bool Main::iteration() {
uint64_t ticks_elapsed=ticks-last_ticks;
double step=(double)ticks_elapsed / 1000000.0;
- float frame_slice=1.0/OS::get_singleton()->get_iterations_per_second();
-
-// if (time_accum+step < frame_slice)
-// return false;
+ float frame_slice=1.0/Engine::get_singleton()->get_iterations_per_second();
+ /*
+ if (time_accum+step < frame_slice)
+ return false;
+ */
uint64_t fixed_process_ticks=0;
uint64_t idle_process_ticks=0;
@@ -1565,13 +1606,13 @@ bool Main::iteration() {
time_accum+=step;
- float time_scale = OS::get_singleton()->get_time_scale();
+ float time_scale = Engine::get_singleton()->get_time_scale();
bool exit=false;
int iters = 0;
- OS::get_singleton()->_in_fixed=true;
+ Engine::get_singleton()->_in_fixed=true;
while(time_accum>frame_slice) {
@@ -1597,16 +1638,18 @@ bool Main::iteration() {
time_accum-=frame_slice;
message_queue->flush();
- //if (AudioServer::get_singleton())
- // AudioServer::get_singleton()->update();
+ /*
+ if (AudioServer::get_singleton())
+ AudioServer::get_singleton()->update();
+ */
fixed_process_ticks=MAX(fixed_process_ticks,OS::get_singleton()->get_ticks_usec()-fixed_begin); // keep the largest one for reference
fixed_process_max=MAX(OS::get_singleton()->get_ticks_usec()-fixed_begin,fixed_process_max);
iters++;
- OS::get_singleton()->_fixed_frames++;
+ Engine::get_singleton()->_fixed_frames++;
}
- OS::get_singleton()->_in_fixed=false;
+ Engine::get_singleton()->_in_fixed=false;
uint64_t idle_begin = OS::get_singleton()->get_ticks_usec();
@@ -1626,11 +1669,11 @@ bool Main::iteration() {
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
if (VisualServer::get_singleton()->has_changed()) {
VisualServer::get_singleton()->draw(); // flush visual commands
- OS::get_singleton()->frames_drawn++;
+ Engine::get_singleton()->frames_drawn++;
}
} else {
VisualServer::get_singleton()->draw(); // flush visual commands
- OS::get_singleton()->frames_drawn++;
+ Engine::get_singleton()->frames_drawn++;
force_redraw_requested = false;
}
}
@@ -1654,26 +1697,22 @@ bool Main::iteration() {
}
- // x11_delay_usec(10000);
+ //x11_delay_usec(10000);
frames++;
- OS::get_singleton()->_idle_frames++;
+ Engine::get_singleton()->_idle_frames++;
if (frame>1000000) {
- if (GLOBAL_DEF("debug/print_fps", OS::get_singleton()->is_stdout_verbose())) {
+ if (GLOBAL_DEF("debug/stdout/print_fps", OS::get_singleton()->is_stdout_verbose())) {
print_line("FPS: "+itos(frames));
};
- OS::get_singleton()->_fps=frames;
+ Engine::get_singleton()->_fps=frames;
performance->set_process_time(USEC_TO_SEC(idle_process_max));
performance->set_fixed_process_time(USEC_TO_SEC(fixed_process_max));
idle_process_max=0;
fixed_process_max=0;
- if (GLOBAL_DEF("debug/print_metrics", false)) {
-
- //PerformanceMetrics::print();
- };
frame%=1000000;
frames=0;
@@ -1682,12 +1721,12 @@ bool Main::iteration() {
if (OS::get_singleton()->is_in_low_processor_usage_mode() || !OS::get_singleton()->can_draw())
OS::get_singleton()->delay_usec(16600); //apply some delay to force idle time (results in about 60 FPS max)
else {
- uint32_t frame_delay = OS::get_singleton()->get_frame_delay();
+ uint32_t frame_delay = Engine::get_singleton()->get_frame_delay();
if (frame_delay)
- OS::get_singleton()->delay_usec( OS::get_singleton()->get_frame_delay()*1000 );
+ OS::get_singleton()->delay_usec( Engine::get_singleton()->get_frame_delay()*1000 );
}
- int target_fps = OS::get_singleton()->get_target_fps();
+ int target_fps = Engine::get_singleton()->get_target_fps();
if (target_fps>0) {
uint64_t time_step = 1000000L/target_fps;
target_ticks += time_step;
@@ -1749,6 +1788,8 @@ void Main::cleanup() {
memdelete(path_remap);
if (globals)
memdelete(globals);
+ if (engine)
+ memdelete(engine);
diff --git a/main/main.h b/main/main.h
index bc8b18776e..42c8a984bf 100644
--- a/main/main.h
+++ b/main/main.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/main/performance.cpp b/main/performance.cpp
index 13ae0504f6..91df55a21c 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,7 @@ Performance *Performance::singleton=NULL;
void Performance::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("get_monitor","monitor"),&Performance::get_monitor);
+ ClassDB::bind_method(_MD("get_monitor","monitor"),&Performance::get_monitor);
BIND_CONSTANT( TIME_FPS );
BIND_CONSTANT( TIME_PROCESS );
@@ -118,13 +118,13 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
float Performance::get_monitor(Monitor p_monitor) const {
switch(p_monitor) {
- case TIME_FPS: return OS::get_singleton()->get_frames_per_second();
+ case TIME_FPS: return Engine::get_singleton()->get_frames_per_second();
case TIME_PROCESS: return _process_time;
case TIME_FIXED_PROCESS: return _fixed_process_time;
- case MEMORY_STATIC: return Memory::get_static_mem_usage();
- case MEMORY_DYNAMIC: return Memory::get_dynamic_mem_usage();
- case MEMORY_STATIC_MAX: return Memory::get_static_mem_max_usage();
- case MEMORY_DYNAMIC_MAX: return Memory::get_dynamic_mem_available();
+ case MEMORY_STATIC: return Memory::get_mem_usage();
+ case MEMORY_DYNAMIC: return MemoryPool::total_memory;
+ case MEMORY_STATIC_MAX: return MemoryPool::max_memory;
+ case MEMORY_DYNAMIC_MAX: return 0;
case MEMORY_MESSAGE_BUFFER_MAX: return MessageQueue::get_singleton()->get_max_buffer_usage();
case OBJECT_COUNT: return ObjectDB::get_object_count();
case OBJECT_RESOURCE_COUNT: return ResourceCache::get_cached_resource_count();
diff --git a/main/performance.h b/main/performance.h
index 81e42710ca..8b5626b681 100644
--- a/main/performance.h
+++ b/main/performance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,7 +37,7 @@
class Performance : public Object {
- OBJ_TYPE(Performance,Object);
+ GDCLASS(Performance,Object);
static Performance *singleton;
static void _bind_methods();
diff --git a/main/splash.h b/main/splash.h
index b96aff8754..3423f1b932 100644
--- a/main/splash.h
+++ b/main/splash.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/main/tests/SCsub b/main/tests/SCsub
new file mode 100644
index 0000000000..03495c0649
--- /dev/null
+++ b/main/tests/SCsub
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+
+Import('env')
+
+env.tests_sources = []
+env.add_source_files(env.tests_sources, "*.cpp")
+
+Export('env')
+
+# SConscript('math/SCsub');
+
+lib = env.Library("tests", env.tests_sources)
+
+env.Prepend(LIBS=[lib])
diff --git a/main/tests/test_containers.cpp b/main/tests/test_containers.cpp
new file mode 100644
index 0000000000..2711d107e4
--- /dev/null
+++ b/main/tests/test_containers.cpp
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* test_containers.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_containers.h"
+#include "dvector.h"
+#include "set.h"
+#include "print_string.h"
+#include "math_funcs.h"
+#include "servers/visual/default_mouse_cursor.xpm"
+
+#include "variant.h"
+#include "list.h"
+#include "image.h"
+
+namespace TestContainers {
+
+MainLoop * test() {
+
+
+ /*
+ HashMap<int,int> int_map;
+
+ for (int i=0;i<68000;i++) {
+
+ int num=(int)Math::random(0,1024);
+ int_map[i]=num;
+ }
+ */
+
+
+ {
+
+ Image img;
+ img.create(default_mouse_cursor_xpm);
+
+ {
+ for (int i=0; i<8; i++) {
+
+ Image mipmap;
+ //img.make_mipmap(mipmap);
+ img = mipmap;
+ if (img.get_width() <= 4) break;
+ };
+ };
+
+ };
+
+#if 0
+ Set<int> set;
+
+ print_line("Begin Insert");
+ for (int i=0;i<1100;i++) {
+
+ int num=i;//(int)Math::random(0,1024);
+ //print_line("inserting "+itos(num));
+ set.insert( num );
+ }
+
+ /*
+ for (int i=0;i<400;i++) {
+
+ int num=(int)Math::random(0,1024);
+ set.erase(num);
+ }
+ */
+ //set.print_tree();
+
+ for(Set<int>::Element *I=set.front();I;I=I->next()) {
+
+ print_line("inserted "+itos(I->get())+" prev is "+itos(I->prev()?I->prev()->get():-100));
+
+ }
+
+ print_line("depth is "+itos(set.calculate_depth()));
+ print_line("Insert Success");
+#endif
+
+ return NULL;
+}
+
+}
diff --git a/main/tests/test_containers.h b/main/tests/test_containers.h
new file mode 100644
index 0000000000..72d5c0ff7a
--- /dev/null
+++ b/main/tests/test_containers.h
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* test_containers.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_CONTAINERS_H
+#define TEST_CONTAINERS_H
+
+#include "os/main_loop.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+namespace TestContainers {
+
+MainLoop * test();
+
+}
+
+#endif
diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp
new file mode 100644
index 0000000000..4f4e76d517
--- /dev/null
+++ b/main/tests/test_gdscript.cpp
@@ -0,0 +1,1065 @@
+/*************************************************************************/
+/* test_gdscript.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_gdscript.h"
+
+
+#include "os/main_loop.h"
+#include "os/os.h"
+#include "os/file_access.h"
+
+#ifdef GDSCRIPT_ENABLED
+
+#include "modules/gdscript/gd_tokenizer.h"
+#include "modules/gdscript/gd_parser.h"
+#include "modules/gdscript/gd_compiler.h"
+#include "modules/gdscript/gd_script.h"
+
+
+namespace TestGDScript {
+
+
+static void _print_indent(int p_ident,const String& p_text) {
+
+ String txt;
+ for(int i=0;i<p_ident;i++) {
+ txt+='\t';
+ }
+
+ print_line(txt+p_text);
+}
+
+static String _parser_extends(const GDParser::ClassNode *p_class) {
+
+ String txt="extends ";
+ if (String(p_class->extends_file)!="") {
+ txt+="\""+p_class->extends_file+"\"";
+ if (p_class->extends_class.size())
+ txt+=".";
+ }
+
+ for(int i=0;i<p_class->extends_class.size();i++) {
+
+ if (i!=0)
+ txt+=".";
+
+ txt+=p_class->extends_class[i];
+ }
+
+ return txt;
+}
+
+static String _parser_expr(const GDParser::Node *p_expr) {
+
+ String txt;
+ switch(p_expr->type) {
+
+ case GDParser::Node::TYPE_IDENTIFIER: {
+
+ const GDParser::IdentifierNode *id_node = static_cast<const GDParser::IdentifierNode *>(p_expr);
+ txt=id_node->name;
+ } break;
+ case GDParser::Node::TYPE_CONSTANT: {
+ const GDParser::ConstantNode *c_node = static_cast<const GDParser::ConstantNode *>(p_expr);
+ if (c_node->value.get_type()==Variant::STRING)
+ txt="\""+String(c_node->value)+"\"";
+ else
+ txt=c_node->value;
+
+ } break;
+ case GDParser::Node::TYPE_SELF: {
+ txt="self";
+ } break;
+ case GDParser::Node::TYPE_ARRAY: {
+ const GDParser::ArrayNode *arr_node = static_cast<const GDParser::ArrayNode *>(p_expr);
+ txt+="[";
+ for(int i=0;i<arr_node->elements.size();i++) {
+
+ if (i>0)
+ txt+=", ";
+ txt+=_parser_expr(arr_node->elements[i]);
+ }
+ txt+="]";
+ } break;
+ case GDParser::Node::TYPE_DICTIONARY: {
+ const GDParser::DictionaryNode *dict_node = static_cast<const GDParser::DictionaryNode *>(p_expr);
+ txt+="{";
+ for(int i=0;i<dict_node->elements.size();i++) {
+
+ if (i>0)
+ txt+=", ";
+
+ const GDParser::DictionaryNode::Pair &p = dict_node->elements[i];
+ txt+=_parser_expr(p.key);
+ txt+=":";
+ txt+=_parser_expr(p.value);
+ }
+ txt+="}";
+ } break;
+ case GDParser::Node::TYPE_OPERATOR: {
+
+ const GDParser::OperatorNode *c_node = static_cast<const GDParser::OperatorNode *>(p_expr);
+ switch(c_node->op) {
+
+ case GDParser::OperatorNode::OP_PARENT_CALL:
+ txt+=".";
+ case GDParser::OperatorNode::OP_CALL: {
+
+ ERR_FAIL_COND_V(c_node->arguments.size()<1,"");
+ String func_name;
+ const GDParser::Node *nfunc = c_node->arguments[0];
+ int arg_ofs=0;
+ if (nfunc->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+
+ const GDParser::BuiltInFunctionNode *bif_node = static_cast<const GDParser::BuiltInFunctionNode *>(nfunc);
+ func_name=GDFunctions::get_func_name(bif_node->function);
+ arg_ofs=1;
+ } else if (nfunc->type==GDParser::Node::TYPE_TYPE) {
+
+ const GDParser::TypeNode *t_node = static_cast<const GDParser::TypeNode *>(nfunc);
+ func_name=Variant::get_type_name(t_node->vtype);
+ arg_ofs=1;
+ } else {
+
+ ERR_FAIL_COND_V(c_node->arguments.size()<2,"");
+ nfunc = c_node->arguments[1];
+ ERR_FAIL_COND_V(nfunc->type!=GDParser::Node::TYPE_IDENTIFIER,"");
+
+ if (c_node->arguments[0]->type!=GDParser::Node::TYPE_SELF)
+ func_name=_parser_expr(c_node->arguments[0])+".";
+
+ func_name+=_parser_expr(nfunc);
+ arg_ofs=2;
+ }
+
+ txt+=func_name+"(";
+
+ for(int i=arg_ofs;i<c_node->arguments.size();i++) {
+
+ const GDParser::Node *arg=c_node->arguments[i];
+ if (i>arg_ofs)
+ txt+=", ";
+ txt+=_parser_expr(arg);
+ }
+
+ txt+=")";
+
+ } break;
+ case GDParser::OperatorNode::OP_INDEX: {
+
+ ERR_FAIL_COND_V(c_node->arguments.size()!=2,"");
+
+ //index with []
+ txt=_parser_expr(c_node->arguments[0])+"["+_parser_expr(c_node->arguments[1])+"]";
+
+ } break;
+ case GDParser::OperatorNode::OP_INDEX_NAMED: {
+
+ ERR_FAIL_COND_V(c_node->arguments.size()!=2,"");
+
+ txt=_parser_expr(c_node->arguments[0])+"."+_parser_expr(c_node->arguments[1]);
+
+ } break;
+ case GDParser::OperatorNode::OP_NEG: { txt="-"+_parser_expr(c_node->arguments[0]); } break;
+ case GDParser::OperatorNode::OP_NOT: { txt="not "+_parser_expr(c_node->arguments[0]); } break;
+ case GDParser::OperatorNode::OP_BIT_INVERT: { txt="~"+_parser_expr(c_node->arguments[0]); } break;
+ case GDParser::OperatorNode::OP_PREINC: {} break;
+ case GDParser::OperatorNode::OP_PREDEC: {} break;
+ case GDParser::OperatorNode::OP_INC: {} break;
+ case GDParser::OperatorNode::OP_DEC: {} break;
+ case GDParser::OperatorNode::OP_IN: { txt=_parser_expr(c_node->arguments[0])+" in "+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_EQUAL: { txt=_parser_expr(c_node->arguments[0])+"=="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_NOT_EQUAL: { txt=_parser_expr(c_node->arguments[0])+"!="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_LESS: { txt=_parser_expr(c_node->arguments[0])+"<"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_LESS_EQUAL: { txt=_parser_expr(c_node->arguments[0])+"<="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_GREATER: { txt=_parser_expr(c_node->arguments[0])+">"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_GREATER_EQUAL: { txt=_parser_expr(c_node->arguments[0])+">="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_AND: { txt=_parser_expr(c_node->arguments[0])+" and "+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_OR: { txt=_parser_expr(c_node->arguments[0])+" or "+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ADD: { txt=_parser_expr(c_node->arguments[0])+"+"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_SUB: { txt=_parser_expr(c_node->arguments[0])+"-"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_MUL: { txt=_parser_expr(c_node->arguments[0])+"*"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_DIV: { txt=_parser_expr(c_node->arguments[0])+"/"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_MOD: { txt=_parser_expr(c_node->arguments[0])+"%"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_SHIFT_LEFT: { txt=_parser_expr(c_node->arguments[0])+"<<"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_SHIFT_RIGHT: { txt=_parser_expr(c_node->arguments[0])+">>"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN: { txt=_parser_expr(c_node->arguments[0])+"="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_ADD: { txt=_parser_expr(c_node->arguments[0])+"+="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_SUB: { txt=_parser_expr(c_node->arguments[0])+"-="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_MUL: { txt=_parser_expr(c_node->arguments[0])+"*="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_DIV: { txt=_parser_expr(c_node->arguments[0])+"/="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_MOD: { txt=_parser_expr(c_node->arguments[0])+"%="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT:{ txt=_parser_expr(c_node->arguments[0])+"<<="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: { txt=_parser_expr(c_node->arguments[0])+">>="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: { txt=_parser_expr(c_node->arguments[0])+"&="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: { txt=_parser_expr(c_node->arguments[0])+"|="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: { txt=_parser_expr(c_node->arguments[0])+"^="+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_BIT_AND: { txt=_parser_expr(c_node->arguments[0])+"&"+_parser_expr(c_node->arguments[1]); } break;;
+ case GDParser::OperatorNode::OP_BIT_OR: { txt=_parser_expr(c_node->arguments[0])+"|"+_parser_expr(c_node->arguments[1]); } break;
+ case GDParser::OperatorNode::OP_BIT_XOR: { txt=_parser_expr(c_node->arguments[0])+"^"+_parser_expr(c_node->arguments[1]); } break;
+ default: {}
+
+ }
+
+ } break;
+ case GDParser::Node::TYPE_NEWLINE: {
+
+ //skippie
+ } break;
+ default: {
+
+ String error="Parser bug at "+itos(p_expr->line)+", invalid expression type: "+itos(p_expr->type);
+ ERR_EXPLAIN(error);
+ ERR_FAIL_V("");
+
+ }
+
+ }
+
+ return txt;
+ //return "("+txt+")";
+}
+
+
+static void _parser_show_block(const GDParser::BlockNode *p_block,int p_indent) {
+
+ for(int i=0;i<p_block->statements.size();i++) {
+
+ const GDParser::Node *statement=p_block->statements[i];
+
+ switch(statement->type) {
+
+ case GDParser::Node::TYPE_CONTROL_FLOW: {
+
+ const GDParser::ControlFlowNode *cf_node = static_cast<const GDParser::ControlFlowNode *>(statement);
+ switch(cf_node->cf_type) {
+
+ case GDParser::ControlFlowNode::CF_IF: {
+
+ ERR_FAIL_COND(cf_node->arguments.size()!=1);
+ String txt;
+ txt+="if ";
+ txt+=_parser_expr(cf_node->arguments[0]);
+ txt+=":";
+ _print_indent(p_indent,txt);
+ ERR_FAIL_COND(!cf_node->body);
+ _parser_show_block(cf_node->body,p_indent+1);
+ if (cf_node->body_else) {
+ _print_indent(p_indent,"else:");
+ _parser_show_block(cf_node->body_else,p_indent+1);
+ }
+
+ } break;
+ case GDParser::ControlFlowNode::CF_FOR: {
+ ERR_FAIL_COND(cf_node->arguments.size()!=2);
+ String txt;
+ txt+="for ";
+ txt+=_parser_expr(cf_node->arguments[0]);
+ txt+=" in ";
+ txt+=_parser_expr(cf_node->arguments[1]);
+ txt+=":";
+ _print_indent(p_indent,txt);
+ ERR_FAIL_COND(!cf_node->body);
+ _parser_show_block(cf_node->body,p_indent+1);
+
+ } break;
+ case GDParser::ControlFlowNode::CF_WHILE: {
+
+ ERR_FAIL_COND(cf_node->arguments.size()!=1);
+ String txt;
+ txt+="while ";
+ txt+=_parser_expr(cf_node->arguments[0]);
+ txt+=":";
+ _print_indent(p_indent,txt);
+ ERR_FAIL_COND(!cf_node->body);
+ _parser_show_block(cf_node->body,p_indent+1);
+
+ } break;
+ case GDParser::ControlFlowNode::CF_SWITCH: {
+
+ } break;
+ case GDParser::ControlFlowNode::CF_CONTINUE: {
+
+ _print_indent(p_indent,"continue");
+ } break;
+ case GDParser::ControlFlowNode::CF_BREAK: {
+
+ _print_indent(p_indent,"break");
+ } break;
+ case GDParser::ControlFlowNode::CF_RETURN: {
+
+ if (cf_node->arguments.size())
+ _print_indent(p_indent,"return "+_parser_expr(cf_node->arguments[0]));
+ else
+ _print_indent(p_indent,"return ");
+ } break;
+ }
+
+ } break;
+ case GDParser::Node::TYPE_LOCAL_VAR: {
+
+ const GDParser::LocalVarNode *lv_node = static_cast<const GDParser::LocalVarNode *>(statement);
+ _print_indent(p_indent,"var "+String(lv_node->name));
+ } break;
+ default: {
+ //expression i guess
+ _print_indent(p_indent,_parser_expr(statement));
+
+ }
+ }
+ }
+}
+
+static void _parser_show_function(const GDParser::FunctionNode *p_func,int p_indent,GDParser::BlockNode *p_initializer=NULL) {
+
+ String txt;
+ if (p_func->_static)
+ txt="static ";
+ txt+="func ";
+ if (p_func->name=="") // initializer
+ txt+="[built-in-initializer]";
+ else
+ txt+=String(p_func->name);
+ txt+="(";
+
+ for(int i=0;i<p_func->arguments.size();i++) {
+
+ if (i!=0)
+ txt+=", ";
+ txt+="var "+String(p_func->arguments[i]);
+ if (i>=(p_func->arguments.size()-p_func->default_values.size())) {
+ int defarg = i - (p_func->arguments.size() - p_func->default_values.size());
+ txt+="=";
+ txt+=_parser_expr(p_func->default_values[defarg]);
+ }
+ }
+
+ txt+=")";
+
+ //todo constructor check!
+
+ txt+=":";
+
+ _print_indent(p_indent,txt);
+ if (p_initializer)
+ _parser_show_block(p_initializer,p_indent+1);
+ _parser_show_block(p_func->body,p_indent+1);
+}
+
+static void _parser_show_class(const GDParser::ClassNode *p_class,int p_indent,const Vector<String>& p_code) {
+
+ if (p_indent==0 && (String(p_class->extends_file)!="" || p_class->extends_class.size())) {
+
+ _print_indent(p_indent,_parser_extends(p_class));
+ print_line("\n");
+
+ }
+
+ for(int i=0;i<p_class->subclasses.size();i++) {
+
+
+ const GDParser::ClassNode *subclass=p_class->subclasses[i];
+ String line="class "+subclass->name;
+ if (String(subclass->extends_file)!="" || subclass->extends_class.size())
+ line+=" "+_parser_extends(subclass);
+ line+=":";
+ _print_indent(p_indent,line);
+ _parser_show_class(subclass,p_indent+1,p_code);
+ print_line("\n");
+ }
+
+
+ for(int i=0;i<p_class->constant_expressions.size();i++) {
+
+ const GDParser::ClassNode::Constant &constant=p_class->constant_expressions[i];
+ _print_indent(p_indent,"const "+String(constant.identifier)+"="+_parser_expr(constant.expression));
+ }
+
+
+ for(int i=0;i<p_class->variables.size();i++) {
+
+ const GDParser::ClassNode::Member &m=p_class->variables[i];
+
+ _print_indent(p_indent,"var "+String(m.identifier));
+
+ }
+
+ print_line("\n");
+
+ for(int i=0;i<p_class->static_functions.size();i++) {
+
+ _parser_show_function(p_class->static_functions[i],p_indent);
+ print_line("\n");
+
+ }
+
+ for(int i=0;i<p_class->functions.size();i++) {
+
+ if (String(p_class->functions[i]->name)=="_init") {
+ _parser_show_function(p_class->functions[i],p_indent,p_class->initializer);
+ } else
+ _parser_show_function(p_class->functions[i],p_indent);
+ print_line("\n");
+
+ }
+ //_parser_show_function(p_class->initializer,p_indent);
+ print_line("\n");
+
+
+}
+
+
+static String _disassemble_addr(const Ref<GDScript>& p_script,const GDFunction& func, int p_addr) {
+
+ int addr=p_addr&GDFunction::ADDR_MASK;
+
+ switch(p_addr>>GDFunction::ADDR_BITS) {
+
+ case GDFunction::ADDR_TYPE_SELF: {
+ return "self";
+ } break;
+ case GDFunction::ADDR_TYPE_CLASS: {
+ return "class";
+ } break;
+ case GDFunction::ADDR_TYPE_MEMBER: {
+
+ return "member("+p_script->debug_get_member_by_index(addr)+")";
+ } break;
+ case GDFunction::ADDR_TYPE_CLASS_CONSTANT: {
+
+ return "class_const("+func.get_global_name(addr)+")";
+ } break;
+ case GDFunction::ADDR_TYPE_LOCAL_CONSTANT: {
+
+ Variant v=func.get_constant(addr);
+ String txt;
+ if (v.get_type()==Variant::STRING || v.get_type()==Variant::NODE_PATH)
+ txt="\""+String(v)+"\"";
+ else
+ txt=v;
+ return "const("+txt+")";
+ } break;
+ case GDFunction::ADDR_TYPE_STACK: {
+
+ return "stack("+itos(addr)+")";
+ } break;
+ case GDFunction::ADDR_TYPE_STACK_VARIABLE: {
+
+ return "var_stack("+itos(addr)+")";
+ } break;
+ case GDFunction::ADDR_TYPE_GLOBAL: {
+
+ return "global("+func.get_global_name(addr)+")";
+ } break;
+ case GDFunction::ADDR_TYPE_NIL: {
+ return "nil";
+ } break;
+
+ }
+
+ return "<err>";
+}
+
+static void _disassemble_class(const Ref<GDScript>& p_class,const Vector<String>& p_code) {
+
+
+ const Map<StringName,GDFunction*>& mf = p_class->debug_get_member_functions();
+
+ for(const Map<StringName,GDFunction*>::Element *E=mf.front();E;E=E->next()) {
+
+
+ const GDFunction &func=*E->get();
+ const int *code = func.get_code();
+ int codelen=func.get_code_size();
+ String defargs;
+ if (func.get_default_argument_count()) {
+ defargs="defarg at: ";
+ for(int i=0;i<func.get_default_argument_count();i++) {
+
+ if (i>0)
+ defargs+=",";
+ defargs+=itos(func.get_default_argument_addr(i));
+ }
+ defargs+=" ";
+ }
+ print_line("== function "+String(func.get_name())+"() :: stack size: "+itos(func.get_max_stack_size())+" "+defargs+"==");
+
+#define DADDR(m_ip) (_disassemble_addr(p_class,func,code[ip+m_ip]))
+
+ for(int ip=0;ip<codelen;) {
+
+
+ int incr=0;
+ String txt=itos(ip)+" ";
+
+ switch(code[ip]) {
+
+ case GDFunction::OPCODE_OPERATOR: {
+
+ int op = code[ip+1];
+ txt+="op ";
+
+ String opname = Variant::get_operator_name(Variant::Operator(op));
+
+ txt+=DADDR(4);
+ txt+=" = ";
+ txt+=DADDR(2);
+ txt+=" "+opname+" ";
+ txt+=DADDR(3);
+ incr+=5;
+
+ } break;
+ case GDFunction::OPCODE_SET: {
+
+ txt+="set ";
+ txt+=DADDR(1);
+ txt+="[";
+ txt+=DADDR(2);
+ txt+="]=";
+ txt+=DADDR(3);
+ incr+=4;
+
+ } break;
+ case GDFunction::OPCODE_GET: {
+
+ txt+=" get ";
+ txt+=DADDR(3);
+ txt+="=";
+ txt+=DADDR(1);
+ txt+="[";
+ txt+=DADDR(2);
+ txt+="]";
+ incr+=4;
+
+ } break;
+ case GDFunction::OPCODE_SET_NAMED: {
+
+ txt+=" set_named ";
+ txt+=DADDR(1);
+ txt+="[\"";
+ txt+=func.get_global_name(code[ip+2]);
+ txt+="\"]=";
+ txt+=DADDR(3);
+ incr+=4;
+
+
+ } break;
+ case GDFunction::OPCODE_GET_NAMED: {
+
+ txt+=" get_named ";
+ txt+=DADDR(3);
+ txt+="=";
+ txt+=DADDR(1);
+ txt+="[\"";
+ txt+=func.get_global_name(code[ip+2]);
+ txt+="\"]";
+ incr+=4;
+
+ } break;
+ case GDFunction::OPCODE_SET_MEMBER: {
+
+ txt+=" set_member ";
+ txt+="[\"";
+ txt+=func.get_global_name(code[ip+1]);
+ txt+="\"]=";
+ txt+=DADDR(2);
+ incr+=3;
+
+
+ } break;
+ case GDFunction::OPCODE_GET_MEMBER: {
+
+ txt+=" get_member ";
+ txt+=DADDR(2);
+ txt+="=";
+ txt+="[\"";
+ txt+=func.get_global_name(code[ip+1]);
+ txt+="\"]";
+ incr+=3;
+
+ } break;
+ case GDFunction::OPCODE_ASSIGN: {
+
+ txt+=" assign ";
+ txt+=DADDR(1);
+ txt+="=";
+ txt+=DADDR(2);
+ incr+=3;
+
+
+ } break;
+ case GDFunction::OPCODE_ASSIGN_TRUE: {
+
+ txt+=" assign ";
+ txt+=DADDR(1);
+ txt+="= true";
+ incr+=2;
+
+ } break;
+ case GDFunction::OPCODE_ASSIGN_FALSE: {
+
+ txt+=" assign ";
+ txt+=DADDR(1);
+ txt+="= false";
+ incr+=2;
+
+ } break;
+ case GDFunction::OPCODE_CONSTRUCT: {
+
+ Variant::Type t=Variant::Type(code[ip+1]);
+ int argc=code[ip+2];
+
+ txt+=" construct ";
+ txt+=DADDR(3+argc);
+ txt+=" = ";
+
+ txt+=Variant::get_type_name(t)+"(";
+ for(int i=0;i<argc;i++) {
+
+ if (i>0)
+ txt+=", ";
+ txt+=DADDR(i+3);
+ }
+ txt+=")";
+
+ incr=4+argc;
+
+ } break;
+ case GDFunction::OPCODE_CONSTRUCT_ARRAY: {
+
+ int argc=code[ip+1];
+ txt+=" make_array ";
+ txt+=DADDR(2+argc);
+ txt+=" = [ ";
+
+ for(int i=0;i<argc;i++) {
+ if (i>0)
+ txt+=", ";
+ txt+=DADDR(2+i);
+ }
+
+ txt+="]";
+
+ incr+=3+argc;
+
+ } break;
+ case GDFunction::OPCODE_CONSTRUCT_DICTIONARY: {
+
+ int argc=code[ip+1];
+ txt+=" make_dict ";
+ txt+=DADDR(2+argc*2);
+ txt+=" = { ";
+
+ for(int i=0;i<argc;i++) {
+ if (i>0)
+ txt+=", ";
+ txt+=DADDR(2+i*2+0);
+ txt+=":";
+ txt+=DADDR(2+i*2+1);
+ }
+
+ txt+="}";
+
+ incr+=3+argc*2;
+
+ } break;
+
+ case GDFunction::OPCODE_CALL:
+ case GDFunction::OPCODE_CALL_RETURN: {
+
+ bool ret=code[ip]==GDFunction::OPCODE_CALL_RETURN;
+
+ if (ret)
+ txt+=" call-ret ";
+ else
+ txt+=" call ";
+
+
+ int argc=code[ip+1];
+ if (ret) {
+ txt+=DADDR(4+argc)+"=";
+ }
+
+ txt+=DADDR(2)+".";
+ txt+=String(func.get_global_name(code[ip+3]));
+ txt+="(";
+
+ for(int i=0;i<argc;i++) {
+ if (i>0)
+ txt+=", ";
+ txt+=DADDR(4+i);
+ }
+ txt+=")";
+
+
+ incr=5+argc;
+
+ } break;
+ case GDFunction::OPCODE_CALL_BUILT_IN: {
+
+ txt+=" call-built-in ";
+
+ int argc=code[ip+2];
+ txt+=DADDR(3+argc)+"=";
+
+ txt+=GDFunctions::get_func_name(GDFunctions::Function(code[ip+1]));
+ txt+="(";
+
+ for(int i=0;i<argc;i++) {
+ if (i>0)
+ txt+=", ";
+ txt+=DADDR(3+i);
+ }
+ txt+=")";
+
+
+ incr=4+argc;
+
+ } break;
+ case GDFunction::OPCODE_CALL_SELF_BASE: {
+
+ txt+=" call-self-base ";
+
+ int argc=code[ip+2];
+ txt+=DADDR(3+argc)+"=";
+
+ txt+=func.get_global_name(code[ip+1]);
+ txt+="(";
+
+ for(int i=0;i<argc;i++) {
+ if (i>0)
+ txt+=", ";
+ txt+=DADDR(3+i);
+ }
+ txt+=")";
+
+
+ incr=4+argc;
+
+ } break;
+ case GDFunction::OPCODE_YIELD: {
+
+ txt+=" yield ";
+ incr=1;
+
+ } break;
+ case GDFunction::OPCODE_YIELD_SIGNAL: {
+
+ txt+=" yield_signal ";
+ txt+=DADDR(1);
+ txt+=",";
+ txt+=DADDR(2);
+ incr=3;
+ } break;
+ case GDFunction::OPCODE_YIELD_RESUME: {
+
+ txt+=" yield resume: ";
+ txt+=DADDR(1);
+ incr=2;
+ } break;
+ case GDFunction::OPCODE_JUMP: {
+
+ txt+=" jump ";
+ txt+=itos(code[ip+1]);
+
+ incr=2;
+
+ } break;
+ case GDFunction::OPCODE_JUMP_IF: {
+
+
+ txt+=" jump-if ";
+ txt+=DADDR(1);
+ txt+=" to ";
+ txt+=itos(code[ip+2]);
+
+ incr=3;
+ } break;
+ case GDFunction::OPCODE_JUMP_IF_NOT: {
+
+
+ txt+=" jump-if-not ";
+ txt+=DADDR(1);
+ txt+=" to ";
+ txt+=itos(code[ip+2]);
+
+ incr=3;
+ } break;
+ case GDFunction::OPCODE_JUMP_TO_DEF_ARGUMENT: {
+
+
+ txt+=" jump-to-default-argument ";
+ incr=1;
+ } break;
+ case GDFunction::OPCODE_RETURN: {
+
+ txt+=" return ";
+ txt+=DADDR(1);
+
+ incr=2;
+
+ } break;
+ case GDFunction::OPCODE_ITERATE_BEGIN: {
+
+ txt+=" for-init "+DADDR(4)+" in "+DADDR(2)+" counter "+DADDR(1)+" end "+itos(code[ip+3]);
+ incr+=5;
+
+ } break;
+ case GDFunction::OPCODE_ITERATE: {
+
+ txt+=" for-loop "+DADDR(4)+" in "+DADDR(2)+" counter "+DADDR(1)+" end "+itos(code[ip+3]);
+ incr+=5;
+
+ } break;
+ case GDFunction::OPCODE_LINE: {
+
+
+
+ int line = code[ip+1]-1;
+ if (line>=0 && line <p_code.size())
+ txt="\n"+itos(line+1)+": "+p_code[line]+"\n";
+ else
+ txt="";
+ incr+=2;
+ } break;
+ case GDFunction::OPCODE_END: {
+
+ txt+=" end";
+ incr+=1;
+ } break;
+ case GDFunction::OPCODE_ASSERT: {
+
+ txt+=" assert ";
+ txt+=DADDR(1);
+ incr+=2;
+
+ } break;
+
+ }
+
+ if (incr==0) {
+
+ ERR_EXPLAIN("unhandled opcode: "+itos(code[ip]));
+ ERR_BREAK(incr==0);
+ }
+
+ ip+=incr;
+ if (txt!="")
+ print_line(txt);
+ }
+ }
+}
+
+MainLoop* test(TestType p_test) {
+
+ List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
+
+ if (cmdlargs.empty()) {
+ //try editor!
+ return NULL;
+ }
+
+ String test = cmdlargs.back()->get();
+
+ FileAccess *fa = FileAccess::open(test,FileAccess::READ);
+
+ if (!fa) {
+ ERR_EXPLAIN("Could not open file: "+test);
+ ERR_FAIL_V(NULL);
+ }
+
+
+ Vector<uint8_t> buf;
+ int flen = fa->get_len();
+ buf.resize(fa->get_len()+1);
+ fa->get_buffer(&buf[0],flen);
+ buf[flen]=0;
+
+ String code;
+ code.parse_utf8((const char*)&buf[0]);
+
+ Vector<String> lines;
+ int last=0;
+
+ for(int i=0;i<=code.length();i++) {
+
+ if (code[i]=='\n' || code[i]==0) {
+
+ lines.push_back(code.substr(last,i-last));
+ last=i+1;
+ }
+ }
+
+
+ if (p_test==TEST_TOKENIZER) {
+
+ GDTokenizerText tk;
+ tk.set_code(code);
+ int line=-1;
+ while(tk.get_token()!=GDTokenizer::TK_EOF) {
+
+
+ String text;
+ if (tk.get_token()==GDTokenizer::TK_IDENTIFIER)
+ text="'"+tk.get_token_identifier()+"' (identifier)";
+ else if (tk.get_token()==GDTokenizer::TK_CONSTANT) {
+ Variant c= tk.get_token_constant();
+ if (c.get_type()==Variant::STRING)
+ text="\""+String(c)+"\"";
+ else
+ text=c;
+
+ text=text+" ("+Variant::get_type_name(c.get_type())+" constant)";
+ } else if (tk.get_token()==GDTokenizer::TK_ERROR)
+ text="ERROR: "+tk.get_token_error();
+ else if (tk.get_token()==GDTokenizer::TK_NEWLINE)
+ text="newline ("+itos(tk.get_token_line())+") + indent: "+itos(tk.get_token_line_indent());
+ else if (tk.get_token()==GDTokenizer::TK_BUILT_IN_FUNC)
+ text="'"+String(GDFunctions::get_func_name(tk.get_token_built_in_func()))+"' (built-in function)";
+ else
+ text=tk.get_token_name(tk.get_token());
+
+
+ if (tk.get_token_line()!=line) {
+ int from=line+1;
+ line = tk.get_token_line();;
+
+ for(int i=from;i<=line;i++) {
+ int l=i-1;
+ if (l>=0 && l<lines.size()) {
+ print_line("\n"+itos(i)+": "+lines[l]+"\n");
+ }
+ }
+ }
+ print_line("\t("+itos(tk.get_token_column())+"): "+text);
+ tk.advance();
+
+ }
+ }
+
+ if (p_test==TEST_PARSER) {
+
+
+ GDParser parser;
+ Error err = parser.parse(code);
+ if (err) {
+ print_line("Parse Error:\n"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error());
+ memdelete(fa);
+ return NULL;
+
+ }
+
+ const GDParser::Node* root = parser.get_parse_tree();
+ ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,NULL);
+ const GDParser::ClassNode *cnode=static_cast<const GDParser::ClassNode*>(root);
+
+ _parser_show_class(cnode,0,lines);
+
+ }
+
+ if (p_test==TEST_COMPILER) {
+
+
+ GDParser parser;
+
+ Error err = parser.parse(code);
+ if (err) {
+ print_line("Parse Error:\n"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error());
+ memdelete(fa);
+ return NULL;
+
+ }
+
+ GDScript *script = memnew( GDScript );
+
+ GDCompiler gdc;
+ err = gdc.compile(&parser,script);
+ if (err) {
+
+ print_line("Compile Error:\n"+itos(gdc.get_error_line())+":"+itos(gdc.get_error_column())+":"+gdc.get_error());
+ memdelete(script);
+ return NULL;
+
+ }
+
+
+ Ref<GDScript> gds =Ref<GDScript>( script );
+
+ Ref<GDScript> current=gds;
+
+ while(current.is_valid()) {
+
+ print_line("** CLASS **");
+ _disassemble_class(current,lines);
+
+ current=current->get_base();
+ }
+
+
+
+
+ } else if (p_test==TEST_BYTECODE) {
+
+ Vector<uint8_t> buf = GDTokenizerBuffer::parse_code_string(code);
+ String dst = test.get_basename()+".gdc";
+ FileAccess *fw = FileAccess::open(dst,FileAccess::WRITE);
+ fw->store_buffer(buf.ptr(),buf.size());
+ memdelete(fw);
+ }
+
+
+#if 0
+ Parser parser;
+ Error err = parser.parse(code);
+ if (err) {
+ print_line("error:"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error());
+ } else {
+ print_line("Parse O-K!");
+ }
+#endif
+
+
+
+ memdelete(fa);
+
+ return NULL;
+}
+
+}
+
+#else
+
+namespace TestGDScript {
+
+MainLoop* test(TestType p_test) {
+
+ return NULL;
+}
+}
+
+#endif
diff --git a/main/tests/test_gdscript.h b/main/tests/test_gdscript.h
new file mode 100644
index 0000000000..225654e2a8
--- /dev/null
+++ b/main/tests/test_gdscript.h
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* test_gdscript.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_GDSCRIPT_H
+#define TEST_GDSCRIPT_H
+
+#include "os/main_loop.h"
+
+namespace TestGDScript {
+
+enum TestType {
+ TEST_TOKENIZER,
+ TEST_PARSER,
+ TEST_COMPILER,
+ TEST_BYTECODE,
+};
+
+MainLoop* test(TestType p_type);
+
+}
+
+#endif // TEST_GDSCRIPT_H
diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp
new file mode 100644
index 0000000000..b0ebc20180
--- /dev/null
+++ b/main/tests/test_gui.cpp
@@ -0,0 +1,402 @@
+/*************************************************************************/
+/* test_gui.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef _3D_DISABLED
+
+#include "test_gui.h"
+
+#include "scene/main/scene_main_loop.h"
+#include "os/os.h"
+#include "scene/gui/control.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/scroll_bar.h"
+#include "scene/gui/popup_menu.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/spin_box.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/progress_bar.h"
+#include "scene/gui/panel.h"
+#include "scene/gui/tab_container.h"
+#include "scene/gui/tree.h"
+#include "scene/gui/rich_text_label.h"
+#include "scene/gui/texture_rect.h"
+#include "io/image_loader.h"
+#include "print_string.h"
+#include "scene/2d/sprite.h"
+
+#include "scene/main/viewport.h"
+#include "scene/3d/camera.h"
+#include "scene/3d/test_cube.h"
+
+namespace TestGUI {
+
+
+class TestMainLoop : public SceneTree {
+
+
+ Control *control;
+
+public:
+
+ virtual void request_quit() {
+
+ quit();
+
+ }
+ virtual void init() {
+
+ SceneTree::init();
+
+
+#if 0
+
+
+ Viewport *vp = memnew( Viewport );
+ vp->set_world( Ref<World>( memnew( World )));
+ get_root()->add_child(vp);
+
+ vp->set_rect(Rect2(0,0,256,256));
+ vp->set_as_render_target(true);
+ vp->set_render_target_update_mode(Viewport::RENDER_TARGET_UPDATE_ALWAYS);
+
+
+ Camera *camera = memnew( Camera );
+ vp->add_child(camera);
+ camera->make_current();
+
+ TestCube *testcube = memnew( TestCube );
+ vp->add_child(testcube);
+ testcube->set_transform(Transform( Basis().rotated(Vector3(0,1,0),Math_PI*0.25), Vector3(0,0,-8)));
+
+ Sprite *sp = memnew( Sprite );
+ sp->set_texture( vp->get_render_target_texture() );
+ //sp->set_texture( ResourceLoader::load("res://ball.png") );
+ sp->set_pos(Point2(300,300));
+ get_root()->add_child(sp);
+
+
+ return;
+#endif
+
+ Panel * frame = memnew( Panel );
+ frame->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END );
+ frame->set_anchor( MARGIN_BOTTOM, Control::ANCHOR_END );
+ frame->set_end( Point2(0,0) );
+
+ Ref<Theme> t = memnew( Theme );
+ frame->set_theme(t);
+
+ get_root()->add_child( frame );
+
+ Label *label = memnew( Label );
+
+ label->set_pos( Point2( 80,90 ) );
+ label->set_size( Point2( 170,80 ) );
+ label->set_align( Label::ALIGN_FILL );
+ //label->set_text("There");
+ label->set_text("There was once upon a time a beautiful unicorn that loved to play with little girls...");
+
+ frame->add_child(label);
+
+ Button *button = memnew( Button );
+
+ button->set_pos( Point2( 20,20 ) );
+ button->set_size( Point2( 1,1 ) );
+ button->set_text("This is a biggie button");
+
+
+ frame->add_child( button );
+
+
+#if 0
+ Sprite *tf = memnew( Sprite );
+ frame->add_child(tf);
+ Image img;
+ ImageLoader::load_image("LarvoClub.png",&img);
+
+ img.resize(512,512);
+ img.generate_mipmaps();
+ img.compress(Image::COMPRESS_PVRTC4);
+ Ref<ImageTexture> tt = memnew( ImageTexture );
+ tt->create_from_image(img);
+ tf->set_texture(tt);
+ tf->set_pos(Point2(50,50));
+ //tf->set_scale(Point2(0.3,0.3));
+
+
+ return;
+#endif
+
+ Tree * tree = memnew( Tree );
+ tree->set_columns(2);
+
+ tree->set_pos( Point2( 230,210 ) );
+ tree->set_size( Point2( 150,250 ) );
+
+
+ TreeItem *item = tree->create_item();
+ item->set_editable(0,true);
+ item->set_text(0,"root");
+ item = tree->create_item( tree->get_root() );
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_editable(0,true);
+ item->set_text(0,"check");
+ item->set_cell_mode(1, TreeItem::CELL_MODE_CHECK);
+ item->set_editable(1,true);
+ item->set_text(1,"check2");
+ item = tree->create_item( tree->get_root() );
+ item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(0,true);
+ item->set_range_config(0,0,20,0.1);
+ item->set_range(0,2);
+ item->add_button(0,Theme::get_default()->get_icon("folder","FileDialog"));
+ item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(1,true);
+ item->set_range_config(1,0,20,0.1);
+ item->set_range(1,3);
+
+ item = tree->create_item( tree->get_root() );
+ item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(0,true);
+ item->set_text(0,"Have,Many,Several,Options!");
+ item->set_range(0,2);
+
+ item = tree->create_item( item );
+ item->set_editable(0,true);
+ item->set_text(0,"Gershwin!");
+
+ frame->add_child(tree);
+
+ //control = memnew( Control );
+ //root->add_child( control );
+
+
+
+ LineEdit *line_edit = memnew( LineEdit );
+
+ line_edit->set_pos( Point2( 30,190 ) );
+ line_edit->set_size( Point2( 180,1 ) );
+
+ frame->add_child(line_edit);
+
+ HScrollBar *hscroll = memnew( HScrollBar );
+
+ hscroll->set_pos( Point2( 30,290 ) );
+ hscroll->set_size( Point2( 180,1 ) );
+ hscroll->set_max(10);
+ hscroll->set_page(4);
+
+ frame->add_child(hscroll);
+
+
+
+ SpinBox *spin = memnew( SpinBox );
+
+ spin->set_pos( Point2( 30,260 ) );
+ spin->set_size( Point2( 120,1 ) );
+
+ frame->add_child(spin);
+ hscroll->share(spin);
+
+ ProgressBar *progress = memnew( ProgressBar );
+
+ progress->set_pos( Point2( 30,330 ) );
+ progress->set_size( Point2( 120,1 ) );
+
+ frame->add_child(progress);
+ hscroll->share(progress);
+
+ MenuButton *menu_button = memnew( MenuButton );
+
+ menu_button->set_text("I'm a menu!");
+ menu_button->set_pos( Point2( 30,380 ) );
+ menu_button->set_size( Point2( 1,1 ) );
+
+ frame->add_child(menu_button);
+
+ PopupMenu *popup = menu_button->get_popup();
+
+ popup->add_item("Hello, testing");
+ popup->add_item("My Dearest");
+ popup->add_separator();
+ popup->add_item("Popup");
+ popup->add_check_item("Check Popup");
+ popup->set_item_checked(4,true);
+
+ OptionButton *options = memnew( OptionButton );
+
+ options->add_item("Hello, testing");
+ options->add_item("My Dearest");
+
+ options->set_pos( Point2( 230,180 ) );
+ options->set_size( Point2( 1,1 ) );
+
+ frame->add_child(options);
+
+ /*
+ Tree * tree = memnew( Tree );
+ tree->set_columns(2);
+
+ tree->set_pos( Point2( 230,210 ) );
+ tree->set_size( Point2( 150,250 ) );
+
+
+ TreeItem *item = tree->create_item();
+ item->set_editable(0,true);
+ item->set_text(0,"root");
+ item = tree->create_item( tree->get_root() );
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_editable(0,true);
+ item->set_text(0,"check");
+ item = tree->create_item( tree->get_root() );
+ item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(0,true);
+ item->set_range_config(0,0,20,0.1);
+ item->set_range(0,2);
+ item->add_button(0,Theme::get_default()->get_icon("folder","FileDialog"));
+ item = tree->create_item( tree->get_root() );
+ item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE);
+ item->set_editable(0,true);
+ item->set_text(0,"Have,Many,Several,Options!");
+ item->set_range(0,2);
+
+ frame->add_child(tree);
+*/
+
+
+ RichTextLabel *richtext = memnew( RichTextLabel );
+
+ richtext->set_pos( Point2( 600,210 ) );
+ richtext->set_size( Point2( 180,250 ) );
+ richtext->set_anchor_and_margin(MARGIN_RIGHT,Control::ANCHOR_END,20);
+
+ frame->add_child(richtext);
+
+
+ richtext->add_text("Hello, My Friends!\n\nWelcome to the amazing world of ");
+
+ richtext->add_newline();
+ richtext->add_newline();
+
+ richtext->push_color(Color(1,0.5,0.5));
+ richtext->add_text("leprechauns");
+ richtext->pop();
+
+ richtext->add_text(" and ");
+ richtext->push_color(Color(0,1.0,0.5));
+ richtext->add_text("faeries.\n");
+ richtext->pop();
+ richtext->add_text("In this new episode, we will attemp to ");
+ richtext->push_font(richtext->get_font("mono_font","Fonts"));
+ richtext->push_color(Color(0.7,0.5,1.0));
+ richtext->add_text("deliver something nice");
+ richtext->pop();
+ richtext->pop();
+ richtext->add_text(" to all the viewers! Unfortunately, I need to ");
+ richtext->push_underline();
+ richtext->add_text("keep writing a lot of text");
+ richtext->pop();
+ richtext->add_text(" so the label control overflows and the scrollbar appears.\n");
+ //richtext->push_indent(1);
+ //richtext->add_text("By the way, testing indent levels! Yohohoho! Everything should appear to the right sightly here!\n");
+ //richtext->pop();
+ richtext->push_meta("http://www.scrollingcapabilities.xz");
+ richtext->add_text("This allows to test for the scrolling capabilities ");
+ richtext->pop();
+ richtext->add_text("of the rich text label for huge text (not like this text will really be huge but, you know).\nAs long as it is so long that it will work nicely for a test/demo, then it's welcomed in my book...\nChanging subject, the day is cloudy today and I'm wondering if I'll get che chance to travel somewhere nice. Sometimes, watching the clouds from satellite images may give a nice insight about how pressure zones in our planet work, althogh it also makes it pretty obvious to see why most weather forecasts get it wrong so often.\nClouds are so difficult to predict!\nBut it's pretty cool how our civilization has adapted to having water falling from the sky each time it rains...");
+ //richtext->add_text("Hello!\nGorgeous..");
+
+
+ //richtext->push_meta("http://www.scrollingcapabilities.xz");
+ ///richtext->add_text("Hello!\n");
+ //richtext->pop();
+
+ richtext->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
+
+
+ TabContainer * tabc = memnew( TabContainer );
+
+ Control *ctl= memnew( Control );
+ ctl->set_name("tab 1");
+ tabc->add_child(ctl);
+
+ ctl= memnew( Control );
+ ctl->set_name("tab 2");
+ tabc->add_child(ctl);
+ label = memnew( Label );
+ label->set_text("Some Label");
+ label->set_pos( Point2(20,20) );
+ ctl->add_child(label);;
+
+ ctl= memnew( Control );
+ ctl->set_name("tab 3");
+ button = memnew( Button );
+ button->set_text("Some Button");
+ button->set_pos( Point2(30,50) );
+ ctl->add_child(button);;
+
+ tabc->add_child(ctl);
+
+ frame->add_child(tabc);
+
+ tabc->set_pos( Point2( 400,210 ) );
+ tabc->set_size( Point2( 180,250 ) );
+
+
+ /*Ref<ImageTexture> text = memnew( ImageTexture );
+ text->load("test_data/concave.png");
+
+ Sprite* sprite = memnew(Sprite);
+ sprite->set_texture(text);
+ sprite->set_pos(Point2(300, 300));
+ frame->add_child(sprite);
+ sprite->show();
+
+ Sprite* sprite2 = memnew(Sprite);
+ sprite->set_texture(text);
+ sprite->add_child(sprite2);
+ sprite2->set_pos(Point2(50, 50));
+ sprite2->show();*/
+ }
+
+
+
+};
+
+
+MainLoop* test() {
+
+
+ return memnew( TestMainLoop );
+}
+
+}
+
+#endif
diff --git a/main/tests/test_gui.h b/main/tests/test_gui.h
new file mode 100644
index 0000000000..5526320b0c
--- /dev/null
+++ b/main/tests/test_gui.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* test_gui.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_GUI_H
+#define TEST_GUI_H
+
+#include "os/main_loop.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+namespace TestGUI {
+
+MainLoop* test();
+
+}
+
+
+#endif
diff --git a/main/tests/test_image.cpp b/main/tests/test_image.cpp
new file mode 100644
index 0000000000..bf9851cf01
--- /dev/null
+++ b/main/tests/test_image.cpp
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* test_image.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_image.h"
+#include "os/main_loop.h"
+#include "math_funcs.h"
+#include "print_string.h"
+#include "io/image_loader.h"
+namespace TestImage {
+
+
+class TestMainLoop : public MainLoop {
+
+ bool quit;
+public:
+ virtual void input_event(const InputEvent& p_event) {
+
+
+ }
+
+ virtual void init() {
+
+ quit=false;
+ }
+ virtual bool iteration(float p_time) {
+
+ return quit;
+ }
+
+ virtual bool idle(float p_time) {
+ return quit;
+ }
+
+ virtual void finish() {
+
+ }
+
+};
+
+
+MainLoop* test() {
+
+ Image img;
+ ImageLoader::load_image("as1.png",&img);
+
+ img.resize(512,512);
+
+ return memnew( TestMainLoop );
+
+}
+
+}
diff --git a/main/tests/test_image.h b/main/tests/test_image.h
new file mode 100644
index 0000000000..09b33e799e
--- /dev/null
+++ b/main/tests/test_image.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* test_image.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_IMAGE_H
+#define TEST_IMAGE_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+#include "os/main_loop.h"
+
+namespace TestImage {
+
+MainLoop* test();
+
+}
+
+#endif
diff --git a/main/tests/test_io.cpp b/main/tests/test_io.cpp
new file mode 100644
index 0000000000..42664e73cd
--- /dev/null
+++ b/main/tests/test_io.cpp
@@ -0,0 +1,208 @@
+/*************************************************************************/
+/* test_io.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_io.h"
+
+#ifdef MINIZIP_ENABLED
+
+
+
+#include "os/main_loop.h"
+#include "os/os.h"
+#include "scene/resources/texture.h"
+#include "print_string.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/dir_access.h"
+#include "core/globals.h"
+
+#include "io/file_access_memory.h"
+
+namespace TestIO {
+
+
+class TestMainLoop : public MainLoop {
+
+
+ bool quit;
+
+public:
+ virtual void input_event(const InputEvent& p_event) {
+
+
+ }
+ virtual bool idle(float p_time) {
+ return false;
+ }
+
+ virtual void request_quit() {
+
+ quit=true;
+
+ }
+ virtual void init() {
+
+ quit=true;
+ }
+ virtual bool iteration(float p_time) {
+
+ return quit;
+ }
+ virtual void finish() {
+
+ }
+
+
+};
+
+
+MainLoop* test() {
+
+ print_line("this is test io");
+ DirAccess* da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->change_dir(".");
+ print_line("Opening current dir "+ da->get_current_dir());
+ String entry;
+ da->list_dir_begin();
+ while ( (entry = da->get_next()) != "") {
+
+ print_line("entry "+entry+" is dir: " + Variant(da->current_is_dir()));
+ };
+ da->list_dir_end();
+
+ RES texture = ResourceLoader::load("test_data/rock.png");
+ ERR_FAIL_COND_V(texture.is_null(), NULL);
+
+ ResourceSaver::save("test_data/rock.xml",texture);
+
+ print_line("localize paths");
+ print_line(GlobalConfig::get_singleton()->localize_path("algo.xml"));
+ print_line(GlobalConfig::get_singleton()->localize_path("c:\\windows\\algo.xml"));
+ print_line(GlobalConfig::get_singleton()->localize_path(GlobalConfig::get_singleton()->get_resource_path()+"/something/something.xml"));
+ print_line(GlobalConfig::get_singleton()->localize_path("somedir/algo.xml"));
+
+ {
+
+ FileAccess* z = FileAccess::open("test_data/archive.zip", FileAccess::READ);
+ int len = z->get_len();
+ Vector<uint8_t> zip;
+ zip.resize(len);
+ z->get_buffer(&zip[0], len);
+ z->close();
+ memdelete(z);
+
+ FileAccessMemory::register_file("a_package", zip);
+ FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_FILESYSTEM);
+ FileAccess::make_default<FileAccessMemory>(FileAccess::ACCESS_USERDATA);
+
+ print_line("archive test");
+#if 0
+ Archive arch;
+
+ Archive::get_singleton()->add_package("a_package");
+ FileAccessArchive f;
+
+ print_line("opening for read");
+ f._open("file.txt", FileAccess::READ);
+ int pos = f.get_pos();
+ printf("file has %i bytes, initial pos %i\n", (int)f.get_len(), pos);
+
+ do {
+ printf("%c", f.get_8());
+
+ } while (!f.eof_reached());
+
+ print_line("opening for stored seek");
+ f.open("seek.bin", FileAccess::READ);
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ f.seek(128);
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+
+ print_line("opening for deflated seek");
+ f.open("seek_deflated.bin", FileAccess::READ);
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ f.seek(128);
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ f.seek(256);
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ f.seek(4);
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+ pos = f.get_pos();
+ printf("byte at pos %i is %i\n", pos, (int)f.get_8());
+
+ f.close();
+
+ DirAccessArchive d;
+ String dir = "../blah1/blah2/blahask/../blah3/.//blah4/";
+ printf("changing dir to %s\n", dir.utf8().get_data());
+ d.change_dir(dir);
+ printf("current dir is %s\n", d.get_current_dir().utf8().get_data());
+
+ FileAccessMemory::cleanup();
+#endif
+ };
+
+ print_line("test done");
+
+
+ return memnew( TestMainLoop );
+
+}
+
+}
+
+#else
+
+namespace TestIO {
+
+
+MainLoop* test() {
+
+ return NULL;
+}
+
+}
+#endif
+
diff --git a/main/tests/test_io.h b/main/tests/test_io.h
new file mode 100644
index 0000000000..c839590ab9
--- /dev/null
+++ b/main/tests/test_io.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* test_io.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_IO_H
+#define TEST_IO_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+#include "os/main_loop.h"
+
+namespace TestIO {
+
+MainLoop* test();
+
+}
+
+#endif
diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp
new file mode 100644
index 0000000000..1f7f2d7dda
--- /dev/null
+++ b/main/tests/test_main.cpp
@@ -0,0 +1,166 @@
+/*************************************************************************/
+/* test_main.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "list.h"
+#include "os/main_loop.h"
+
+#ifdef DEBUG_ENABLED
+
+#include "test_string.h"
+#include "test_containers.h"
+#include "test_math.h"
+#include "test_gui.h"
+#include "test_render.h"
+#include "test_sound.h"
+#include "test_physics.h"
+#include "test_physics_2d.h"
+
+#include "test_io.h"
+#include "test_shader_lang.h"
+#include "test_gdscript.h"
+#include "test_image.h"
+
+
+const char ** tests_get_names() {
+
+ static const char* test_names[]={
+ "string",
+ "containers",
+ "math",
+ "render",
+ "multimesh",
+ "gui",
+ "io",
+ "shaderlang",
+ "physics",
+ NULL
+ };
+
+ return test_names;
+}
+
+MainLoop* test_main(String p_test,const List<String>& p_args) {
+
+
+ if (p_test=="string") {
+
+ return TestString::test();
+ }
+
+ if (p_test=="containers") {
+
+ return TestContainers::test();
+ }
+
+ if (p_test=="math") {
+
+ return TestMath::test();
+ }
+
+ if (p_test=="physics") {
+
+ return TestPhysics::test();
+ }
+
+ if (p_test=="physics_2d") {
+
+ return TestPhysics2D::test();
+ }
+
+ if (p_test=="render") {
+
+ return TestRender::test();
+ }
+
+ #ifndef _3D_DISABLED
+ if (p_test=="gui") {
+
+ return TestGUI::test();
+ }
+ #endif
+
+ if (p_test=="sound") {
+
+ return TestSound::test();
+ }
+
+ if (p_test=="io") {
+
+ return TestIO::test();
+ }
+
+ if (p_test=="shaderlang") {
+
+ return TestShaderLang::test();
+ }
+
+ if (p_test=="gd_tokenizer") {
+
+ return TestGDScript::test(TestGDScript::TEST_TOKENIZER);
+ }
+
+ if (p_test=="gd_parser") {
+
+ return TestGDScript::test(TestGDScript::TEST_PARSER);
+ }
+
+ if (p_test=="gd_compiler") {
+
+ return TestGDScript::test(TestGDScript::TEST_COMPILER);
+ }
+
+ if (p_test=="gd_bytecode") {
+
+ return TestGDScript::test(TestGDScript::TEST_BYTECODE);
+ }
+
+ if (p_test=="image") {
+
+ return TestImage::test();
+ }
+
+ return NULL;
+}
+
+#else
+
+const char ** tests_get_names() {
+
+ static const char* test_names[]={
+ NULL
+ };
+
+ return test_names;
+}
+
+MainLoop* test_main(String p_test,const List<String>& p_args) {
+
+ return NULL;
+}
+
+#endif
diff --git a/main/tests/test_main.h b/main/tests/test_main.h
new file mode 100644
index 0000000000..c8d571a7dd
--- /dev/null
+++ b/main/tests/test_main.h
@@ -0,0 +1,41 @@
+/*************************************************************************/
+/* test_main.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_MAIN_H
+#define TEST_MAIN_H
+
+#include "ustring.h"
+#include "list.h"
+
+const char ** tests_get_names();
+MainLoop* test_main(String p_test,const List<String>& p_args);
+
+
+#endif
+
+
diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp
new file mode 100644
index 0000000000..89513b81d9
--- /dev/null
+++ b/main/tests/test_math.cpp
@@ -0,0 +1,816 @@
+/*************************************************************************/
+/* test_math.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_math.h"
+#include "ustring.h"
+#include "print_string.h"
+#include "transform.h"
+#include "matrix3.h"
+#include "math_funcs.h"
+#include "camera_matrix.h"
+#include "scene/main/node.h"
+#include "variant.h"
+#include "servers/visual/shader_language.h"
+#include "os/keyboard.h"
+#include "scene/resources/texture.h"
+#include "vmap.h"
+#include "os/os.h"
+#include "os/file_access.h"
+
+#include "method_ptrcall.h"
+
+namespace TestMath {
+
+
+class GetClassAndNamespace {
+
+ String code;
+ int idx;
+ int line;
+ String error_str;
+ bool error;
+ Variant value;
+
+ String class_name;
+
+ enum Token {
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_PERIOD,
+ TK_COLON,
+ TK_COMMA,
+ TK_SYMBOL,
+ TK_IDENTIFIER,
+ TK_STRING,
+ TK_NUMBER,
+ TK_EOF,
+ TK_ERROR
+ };
+
+
+ Token get_token() {
+
+ while (true) {
+ switch(code[idx]) {
+
+ case '\n': {
+
+ line++;
+ idx++;
+ break;
+ };
+ case 0: {
+ return TK_EOF;
+
+ } break;
+ case '{': {
+
+ idx++;
+ return TK_CURLY_BRACKET_OPEN;
+ };
+ case '}': {
+
+ idx++;
+ return TK_CURLY_BRACKET_CLOSE;
+ };
+ case '[': {
+
+ idx++;
+ return TK_BRACKET_OPEN;
+ };
+ case ']': {
+
+ idx++;
+ return TK_BRACKET_CLOSE;
+ };
+ case ':': {
+
+ idx++;
+ return TK_COLON;
+ };
+ case ',': {
+
+ idx++;
+ return TK_COMMA;
+ };
+ case '.': {
+
+ idx++;
+ return TK_PERIOD;
+ };
+ case '#': {
+ //compiler directive
+ while(code[idx]!='\n' && code[idx]!=0) {
+ idx++;
+ }
+ continue;
+ } break;
+ case '/': {
+
+
+ switch(code[idx+1]) {
+ case '*': { // block comment
+
+ idx+=2;
+ while(true) {
+ if (code[idx]==0) {
+ error_str="Unterminated comment";
+ error=true;
+ return TK_ERROR;
+ } if (code[idx]=='*' &&code[idx+1]=='/') {
+
+ idx+=2;
+ break;
+ } if (code[idx]=='\n') {
+ line++;
+ }
+
+ idx++;
+ }
+
+ } break;
+ case '/': { // line comment skip
+
+ while(code[idx]!='\n' && code[idx]!=0) {
+ idx++;
+ }
+
+ } break;
+ default: {
+ value="/";
+ idx++;
+ return TK_SYMBOL;
+ }
+
+ }
+
+ continue; // a comment
+ } break;
+ case '\'':
+ case '"': {
+
+ CharType begin_str = code[idx];
+ idx++;
+ String tk_string=String();
+ while(true) {
+ if (code[idx]==0) {
+ error_str="Unterminated String";
+ error=true;
+ return TK_ERROR;
+ } else if (code[idx]==begin_str) {
+ idx++;
+ break;
+ } else if (code[idx]=='\\') {
+ //escaped characters...
+ idx++;
+ CharType next = code[idx];
+ if (next==0) {
+ error_str="Unterminated String";
+ error=true;
+ return TK_ERROR;
+ }
+ CharType res=0;
+
+ switch(next) {
+
+ case 'b': res=8; break;
+ case 't': res=9; break;
+ case 'n': res=10; break;
+ case 'f': res=12; break;
+ case 'r': res=13; break;
+ /* too much, not needed for now
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+
+
+ for(int j=0;j<4;j++) {
+ CharType c = code[idx+j+1];
+ if (c==0) {
+ r_err_str="Unterminated String";
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
+
+ r_err_str="Malformed hex constant in string";
+ return ERR_PARSE_ERROR;
+ }
+ CharType v;
+ if (c>='0' && c<='9') {
+ v=c-'0';
+ } else if (c>='a' && c<='f') {
+ v=c-'a';
+ v+=10;
+ } else if (c>='A' && c<='F') {
+ v=c-'A';
+ v+=10;
+ } else {
+ ERR_PRINT("BUG");
+ v=0;
+ }
+
+ res<<=4;
+ res|=v;
+
+
+ }
+ idx+=4; //will add at the end anyway
+
+
+ } break;*/
+ case '\"': res='\"'; break;
+ case '\\': res='\\'; break;
+ //case '/': res='/'; break;
+ default: {
+ res = next;
+ //r_err_str="Invalid escape sequence";
+ //return ERR_PARSE_ERROR;
+ } break;
+ }
+
+ tk_string+=res;
+
+ } else {
+ if (code[idx]=='\n')
+ line++;
+ tk_string+=code[idx];
+ }
+ idx++;
+ }
+
+ value=tk_string;
+
+ return TK_STRING;
+
+ } break;
+ default: {
+
+ if (code[idx]<=32) {
+ idx++;
+ break;
+ }
+
+ if ( (code[idx]>=33 && code[idx]<=47) || (code[idx]>=58 && code[idx]<=64) || (code[idx]>=91 && code[idx]<=96) || (code[idx]>=123 && code[idx]<=127)){
+ value=String::chr(code[idx]);
+ idx++;
+ return TK_SYMBOL;
+ }
+
+ if (code[idx]=='-' || (code[idx]>='0' && code[idx]<='9')) {
+ //a number
+ const CharType *rptr;
+ double number = String::to_double(&code[idx],&rptr);
+ idx+=(rptr - &code[idx]);
+ value=number;
+ return TK_NUMBER;
+
+ } else if ((code[idx]>='A' && code[idx]<='Z') || (code[idx]>='a' && code[idx]<='z') || code[idx]>127) {
+
+ String id;
+
+ while((code[idx]>='A' && code[idx]<='Z') || (code[idx]>='a' && code[idx]<='z') || code[idx]>127) {
+
+ id+=code[idx];
+ idx++;
+ }
+
+ value=id;
+ return TK_IDENTIFIER;
+ } else {
+ error_str="Unexpected character.";
+ error=true;
+ return TK_ERROR;
+ }
+ }
+
+ }
+ }
+ }
+
+public:
+ Error parse(const String& p_code,const String& p_known_class_name=String()) {
+
+ code=p_code;
+ idx=0;
+ line=0;
+ error_str=String();
+ error=false;
+ value=Variant();
+ class_name=String();
+
+ bool use_next_class=false;
+ Token tk = get_token();
+
+ Map<int,String> namespace_stack;
+ int curly_stack=0;
+
+
+ while(!error || tk!=TK_EOF) {
+
+ if (tk==TK_BRACKET_OPEN) {
+ tk = get_token();
+ if (tk==TK_IDENTIFIER && String(value)=="ScriptClass") {
+ if (get_token()==TK_BRACKET_CLOSE) {
+ use_next_class=true;
+ }
+ }
+ } else if (tk==TK_IDENTIFIER && String(value)=="class") {
+ tk = get_token();
+ if (tk==TK_IDENTIFIER) {
+ String name = value;
+ if (use_next_class || p_known_class_name==name) {
+ for (Map<int,String>::Element *E=namespace_stack.front();E;E=E->next()) {
+ class_name+=E->get()+".";
+ }
+ class_name+=String(value);
+ break;
+ }
+ }
+
+ } else if (tk==TK_IDENTIFIER && String(value)=="namespace") {
+ String name;
+ int at_level = curly_stack;
+ while(true) {
+ tk = get_token();
+ if (tk==TK_IDENTIFIER) {
+ name+=String(value);
+ }
+
+ tk = get_token();
+ if (tk==TK_PERIOD) {
+ name+=".";
+ } else if (tk==TK_CURLY_BRACKET_OPEN) {
+ curly_stack++;
+ break;
+ } else {
+ break; //whathever else
+ }
+
+ }
+
+ if (name!=String()) {
+ namespace_stack[at_level]=name;
+ }
+
+ } else if (tk==TK_CURLY_BRACKET_OPEN) {
+ curly_stack++;
+ } else if (tk==TK_CURLY_BRACKET_CLOSE) {
+ curly_stack--;
+ if (namespace_stack.has(curly_stack)) {
+ namespace_stack.erase(curly_stack);
+ }
+ }
+
+ tk = get_token();
+ }
+
+ if (error)
+ return ERR_PARSE_ERROR;
+
+
+
+ return OK;
+
+ }
+
+ String get_error() {
+ return error_str;
+ }
+
+ String get_class() {
+ return class_name;
+ }
+
+};
+
+
+void test_vec(Plane p_vec) {
+
+
+ CameraMatrix cm;
+ cm.set_perspective(45,1,0,100);
+ Plane v0=cm.xform4(p_vec);
+
+ print_line("out: "+v0);
+ v0.normal.z = (v0.d/100.0 *2.0-1.0) * v0.d;
+ print_line("out_F: "+v0);
+
+
+/*v0: 0, 0, -0.1, 0.1
+v1: 0, 0, 0, 0.1
+fix: 0, 0, 0, 0.1
+v0: 0, 0, 1.302803, 1.5
+v1: 0, 0, 1.401401, 1.5
+fix: 0, 0, 1.401401, 1.5
+v0: 0, 0, 25.851850, 26
+v1: 0, 0, 25.925926, 26
+fix: 0, 0, 25.925924, 26
+v0: 0, 0, 49.899902, 50
+v1: 0, 0, 49.949947, 50
+fix: 0, 0, 49.949951, 50
+v0: 0, 0, 100, 100
+v1: 0, 0, 100, 100
+fix: 0, 0, 100, 100
+*/
+
+
+}
+
+uint32_t ihash( uint32_t a)
+{
+ a = (a+0x7ed55d16) + (a<<12);
+ a = (a^0xc761c23c) ^ (a>>19);
+ a = (a+0x165667b1) + (a<<5);
+ a = (a+0xd3a2646c) ^ (a<<9);
+ a = (a+0xfd7046c5) + (a<<3);
+ a = (a^0xb55a4f09) ^ (a>>16);
+ return a;
+}
+
+uint32_t ihash2( uint32_t a) {
+ a = (a ^ 61) ^ (a >> 16);
+ a = a + (a << 3);
+ a = a ^ (a >> 4);
+ a = a * 0x27d4eb2d;
+ a = a ^ (a >> 15);
+ return a;
+}
+
+uint32_t ihash3( uint32_t a)
+{
+ a = (a+0x479ab41d) + (a<<8);
+ a = (a^0xe4aa10ce) ^ (a>>5);
+ a = (a+0x9942f0a6) - (a<<14);
+ a = (a^0x5aedd67d) ^ (a>>3);
+ a = (a+0x17bea992) + (a<<7);
+ return a;
+}
+
+
+
+
+MainLoop* test() {
+
+
+ print_line("Dvectors: "+itos(MemoryPool::allocs_used));
+ print_line("Mem used: "+itos(MemoryPool::total_memory));
+ print_line("MAx mem used: "+itos(MemoryPool::max_memory));
+
+ PoolVector<int> ints;
+ ints.resize(20);
+
+ {
+ PoolVector<int>::Write w;
+ w = ints.write();
+ for(int i=0;i<ints.size();i++) {
+ w[i]=i;
+ }
+ }
+
+ PoolVector<int> posho = ints;
+
+ {
+ PoolVector<int>::Read r = posho.read();
+ for(int i=0;i<posho.size();i++) {
+ print_line(itos(i)+" : " +itos(r[i]));
+ }
+ }
+
+ print_line("later Dvectors: "+itos(MemoryPool::allocs_used));
+ print_line("later Mem used: "+itos(MemoryPool::total_memory));
+ print_line("Mlater Ax mem used: "+itos(MemoryPool::max_memory));
+
+
+ return NULL;
+
+ List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
+
+ if (cmdlargs.empty()) {
+ //try editor!
+ return NULL;
+ }
+
+ String test = cmdlargs.back()->get();
+
+ FileAccess *fa = FileAccess::open(test,FileAccess::READ);
+
+ if (!fa) {
+ ERR_EXPLAIN("Could not open file: "+test);
+ ERR_FAIL_V(NULL);
+ }
+
+
+ Vector<uint8_t> buf;
+ int flen = fa->get_len();
+ buf.resize(fa->get_len()+1);
+ fa->get_buffer(&buf[0],flen);
+ buf[flen]=0;
+
+
+ String code;
+ code.parse_utf8((const char*)&buf[0]);
+
+ GetClassAndNamespace getclass;
+ if (getclass.parse(code)) {
+ print_line("Parse error: "+getclass.get_error());
+ } else {
+ print_line("Found class: "+getclass.get_class());
+ }
+
+ return NULL;
+
+ {
+
+ Vector<int> hashes;
+ List<StringName> tl;
+ ClassDB::get_class_list(&tl);
+
+
+ for (List<StringName>::Element *E=tl.front();E;E=E->next()) {
+
+ Vector<uint8_t> m5b = E->get().operator String().md5_buffer();
+ hashes.push_back(hashes.size());
+
+ }
+
+ //hashes.resize(50);
+
+ for(int i=nearest_shift(hashes.size());i<20;i++) {
+
+ bool success=true;
+ for(int s=0;s<10000;s++) {
+ Set<uint32_t> existing;
+ success=true;
+
+ for(int j=0;j<hashes.size();j++) {
+
+ uint32_t eh = ihash2(ihash3(hashes[j]+ihash(s)+s))&((1<<i)-1);
+ if (existing.has(eh)) {
+ success=false;
+ break;
+ }
+ existing.insert(eh);
+ }
+
+ if (success) {
+ print_line("success at "+itos(i)+"/"+itos(nearest_shift(hashes.size()))+" shift "+itos(s));
+ break;
+ }
+ }
+ if (success)
+ break;
+ }
+
+ print_line("DONE");
+
+
+
+ return NULL;
+ }
+ {
+
+
+ //print_line("NUM: "+itos(237641278346127));
+ print_line("NUM: "+itos(-128));
+ return NULL;
+
+ }
+
+
+ {
+ Vector3 v(1,2,3);
+ v.normalize();
+ float a=0.3;
+
+ //Quat q(v,a);
+ Basis m(v,a);
+
+ Vector3 v2(7,3,1);
+ v2.normalize();
+ float a2=0.8;
+
+ //Quat q(v,a);
+ Basis m2(v2,a2);
+
+ Quat q=m;
+ Quat q2=m2;
+
+ Basis m3 = m.inverse() * m2;
+ Quat q3 = (q.inverse() * q2);//.normalized();
+
+ print_line(Quat(m3));
+ print_line(q3);
+
+ print_line("before v: "+v+" a: "+rtos(a));
+ q.get_axis_and_angle(v,a);
+ print_line("after v: "+v+" a: "+rtos(a));
+ }
+
+ return NULL;
+ String ret;
+
+ List<String> args;
+ args.push_back("-l");
+ Error err = OS::get_singleton()->execute("/bin/ls",args,true,NULL,&ret);
+ print_line("error: "+itos(err));
+ print_line(ret);
+
+ return NULL;
+ Basis m3;
+ m3.rotate(Vector3(1,0,0),0.2);
+ m3.rotate(Vector3(0,1,0),1.77);
+ m3.rotate(Vector3(0,0,1),212);
+ Basis m32;
+ m32.set_euler(m3.get_euler());
+ print_line("ELEULEEEEEEEEEEEEEEEEEER: "+m3.get_euler()+" vs "+m32.get_euler());
+
+
+ return NULL;
+
+ {
+
+ Dictionary d;
+ d["momo"]=1;
+ Dictionary b=d;
+ b["44"]=4;
+ }
+
+
+
+ return NULL;
+ print_line("inters: "+rtos(Geometry::segment_intersects_circle(Vector2(-5,0),Vector2(-2,0),Vector2(),1.0)));
+
+
+
+ print_line("cross: "+Vector3(1,2,3).cross(Vector3(4,5,7)));
+ print_line("dot: "+rtos(Vector3(1,2,3).dot(Vector3(4,5,7))));
+ print_line("abs: "+Vector3(-1,2,-3).abs());
+ print_line("distance_to: "+rtos(Vector3(1,2,3).distance_to(Vector3(4,5,7))));
+ print_line("distance_squared_to: "+rtos(Vector3(1,2,3).distance_squared_to(Vector3(4,5,7))));
+ print_line("plus: "+(Vector3(1,2,3)+Vector3(Vector3(4,5,7))));
+ print_line("minus: "+(Vector3(1,2,3)-Vector3(Vector3(4,5,7))));
+ print_line("mul: "+(Vector3(1,2,3)*Vector3(Vector3(4,5,7))));
+ print_line("div: "+(Vector3(1,2,3)/Vector3(Vector3(4,5,7))));
+ print_line("mul scalar: "+(Vector3(1,2,3)*2));
+ print_line("premul scalar: "+(2*Vector3(1,2,3)));
+ print_line("div scalar: "+(Vector3(1,2,3)/3.0));
+ print_line("length: "+rtos(Vector3(1,2,3).length()));
+ print_line("length squared: "+rtos(Vector3(1,2,3).length_squared()));
+ print_line("normalized: "+Vector3(1,2,3).normalized());
+ print_line("inverse: "+Vector3(1,2,3).inverse());
+
+ {
+ Vector3 v(4,5,7);
+ v.normalize();
+ print_line("normalize: "+v);
+ }
+
+ {
+ Vector3 v(4,5,7);
+ v+=Vector3(1,2,3);
+ print_line("+=: "+v);
+ }
+
+ {
+ Vector3 v(4,5,7);
+ v-=Vector3(1,2,3);
+ print_line("-=: "+v);
+ }
+
+ {
+ Vector3 v(4,5,7);
+ v*=Vector3(1,2,3);
+ print_line("*=: "+v);
+ }
+
+ {
+ Vector3 v(4,5,7);
+ v/=Vector3(1,2,3);
+ print_line("/=: "+v);
+ }
+
+ {
+ Vector3 v(4,5,7);
+ v*=2.0;
+ print_line("scalar *=: "+v);
+ }
+
+ {
+ Vector3 v(4,5,7);
+ v/=2.0;
+ print_line("scalar /=: "+v);
+ }
+
+
+
+#if 0
+ print_line(String("C:\\momo\\.\\popo\\..\\gongo").simplify_path());
+ print_line(String("res://../popo/..//gongo").simplify_path());
+ print_line(String("res://..").simplify_path());
+
+
+ PoolVector<uint8_t> a;
+ PoolVector<uint8_t> b;
+
+ a.resize(20);
+ b=a;
+ b.resize(30);
+ a=b;
+#endif
+
+#if 0
+ String za = String::utf8("á");
+ printf("unicode: %x\n",za[0]);
+ CharString cs=za.utf8();
+ for(int i=0;i<cs.size();i++) {
+ uint32_t v = uint8_t(cs[i]);
+ printf("%i - %x\n",i,v);
+ }
+ return NULL;
+
+ print_line(String("C:\\window\\system\\momo").path_to("C:\\window\\momonga"));
+ print_line(String("res://momo/sampler").path_to("res://pindonga"));
+ print_line(String("/margarito/terere").path_to("/margarito/pilates"));
+ print_line(String("/algo").path_to("/algo"));
+ print_line(String("c:").path_to("c:\\"));
+ print_line(String("/").path_to("/"));
+
+
+ print_line(itos(sizeof(Variant)));
+ return NULL;
+
+ Vector<StringName> path;
+ path.push_back("three");
+ path.push_back("two");
+ path.push_back("one");
+ path.push_back("comeon");
+ path.revert();
+
+ NodePath np(path,true);
+
+ print_line(np);
+
+
+ return NULL;
+
+ bool a=2;
+
+ print_line(Variant(a));
+
+
+ Transform2D mat2_1;
+ mat2_1.rotate(0.5);
+ Transform2D mat2_2;
+ mat2_2.translate(Vector2(1,2));
+ Transform2D mat2_3 = mat2_1 * mat2_2;
+ mat2_3.affine_invert();
+
+ print_line(mat2_3.elements[0]);
+ print_line(mat2_3.elements[1]);
+ print_line(mat2_3.elements[2]);
+
+
+
+ Transform mat3_1;
+ mat3_1.basis.rotate(Vector3(0,0,1),0.5);
+ Transform mat3_2;
+ mat3_2.translate(Vector3(1,2,0));
+ Transform mat3_3 = mat3_1 * mat3_2;
+ mat3_3.affine_invert();
+
+ print_line(mat3_3.basis.get_axis(0));
+ print_line(mat3_3.basis.get_axis(1));
+ print_line(mat3_3.origin);
+
+#endif
+ return NULL;
+
+}
+
+}
diff --git a/main/tests/test_math.h b/main/tests/test_math.h
new file mode 100644
index 0000000000..492c3a1837
--- /dev/null
+++ b/main/tests/test_math.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* test_math.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_MATH_H
+#define TEST_MATH_H
+
+#include "os/main_loop.h"
+
+namespace TestMath {
+
+MainLoop* test();
+
+}
+
+#endif
diff --git a/main/tests/test_physics.cpp b/main/tests/test_physics.cpp
new file mode 100644
index 0000000000..ea98da34ca
--- /dev/null
+++ b/main/tests/test_physics.cpp
@@ -0,0 +1,644 @@
+/*************************************************************************/
+/* test_physics.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_physics.h"
+
+
+#include "servers/visual_server.h"
+#include "servers/physics_server.h"
+#include "os/main_loop.h"
+#include "math_funcs.h"
+#include "print_string.h"
+#include "map.h"
+#include "os/os.h"
+#include "quick_hull.h"
+
+class TestPhysicsMainLoop : public MainLoop {
+
+ GDCLASS( TestPhysicsMainLoop, MainLoop );
+
+ enum {
+ LINK_COUNT = 20,
+ };
+
+ RID test_cube;
+
+ RID plane;
+ RID sphere;
+ RID light;
+ RID camera;
+ RID mover;
+ RID scenario;
+ RID space;
+
+ RID character;
+
+ float ofs_x,ofs_y;
+
+ Point2 joy_direction;
+
+ List<RID> bodies;
+ Map<PhysicsServer::ShapeType,RID> type_shape_map;
+ Map<PhysicsServer::ShapeType,RID> type_mesh_map;
+
+ void body_changed_transform(Object *p_state, RID p_visual_instance) {
+
+ PhysicsDirectBodyState *state = (PhysicsDirectBodyState*)p_state;
+ VisualServer *vs=VisualServer::get_singleton();
+ Transform t=state->get_transform();
+ //t.basis.scale( Vector3(1.0,0.5,0.2) );
+ vs->instance_set_transform(p_visual_instance,t);
+ }
+
+ bool quit;
+
+protected:
+
+ static void _bind_methods() {
+
+ ClassDB::bind_method("body_changed_transform",&TestPhysicsMainLoop::body_changed_transform);
+ }
+
+ RID create_body(PhysicsServer::ShapeType p_shape, PhysicsServer::BodyMode p_body,const Transform p_location,bool p_active_default=true,const Transform&p_shape_xform=Transform()) {
+
+ VisualServer *vs=VisualServer::get_singleton();
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+
+ RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape],scenario);
+ RID body = ps->body_create(p_body,!p_active_default);
+ ps->body_set_space(body,space);
+ ps->body_set_param(body,PhysicsServer::BODY_PARAM_BOUNCE,0.0);
+ //todo set space
+ ps->body_add_shape(body,type_shape_map[p_shape]);
+ ps->body_set_force_integration_callback(body,this,"body_changed_transform",mesh_instance);
+
+ ps->body_set_state( body, PhysicsServer::BODY_STATE_TRANSFORM,p_location);
+ bodies.push_back(body);
+
+ if (p_body==PhysicsServer::BODY_MODE_STATIC) {
+
+ vs->instance_set_transform(mesh_instance,p_location);
+ }
+ return body;
+ }
+
+ RID create_static_plane(const Plane& p_plane) {
+
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+
+ RID plane_shape = ps->shape_create(PhysicsServer::SHAPE_PLANE);;
+ ps->shape_set_data( plane_shape, p_plane );
+
+ RID b = ps->body_create( PhysicsServer::BODY_MODE_STATIC );
+ ps->body_set_space(b,space);
+ //todo set space
+ ps->body_add_shape(b, plane_shape);
+ return b;
+
+ }
+
+ void configure_body(RID p_body,float p_mass, float p_friction, float p_bounce) {
+
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+ ps->body_set_param( p_body, PhysicsServer::BODY_PARAM_MASS, p_mass );
+ ps->body_set_param( p_body, PhysicsServer::BODY_PARAM_FRICTION, p_friction );
+ ps->body_set_param( p_body, PhysicsServer::BODY_PARAM_BOUNCE, p_bounce );
+
+ }
+
+ void init_shapes() {
+
+ VisualServer *vs=VisualServer::get_singleton();
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+
+ /* SPHERE SHAPE */
+ RID sphere_mesh = vs->make_sphere_mesh(10,20,0.5);
+ type_mesh_map[PhysicsServer::SHAPE_SPHERE]=sphere_mesh;
+
+ RID sphere_shape=ps->shape_create(PhysicsServer::SHAPE_SPHERE);
+ ps->shape_set_data( sphere_shape, 0.5 );
+ type_shape_map[PhysicsServer::SHAPE_SPHERE]=sphere_shape;
+
+ /* BOX SHAPE */
+
+ PoolVector<Plane> box_planes = Geometry::build_box_planes(Vector3(0.5,0.5,0.5));
+ RID box_mesh = vs->mesh_create();
+ Geometry::MeshData box_data = Geometry::build_convex_mesh(box_planes);
+ vs->mesh_add_surface_from_mesh_data(box_mesh,box_data);
+ type_mesh_map[PhysicsServer::SHAPE_BOX]=box_mesh;
+
+ RID box_shape=ps->shape_create(PhysicsServer::SHAPE_BOX);
+ ps->shape_set_data( box_shape, Vector3(0.5,0.5,0.5) );
+ type_shape_map[PhysicsServer::SHAPE_BOX]=box_shape;
+
+
+ /* CAPSULE SHAPE */
+
+ PoolVector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5,0.7,12,Vector3::AXIS_Z);
+
+ RID capsule_mesh = vs->mesh_create();
+ Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
+ vs->mesh_add_surface_from_mesh_data(capsule_mesh,capsule_data);
+
+ type_mesh_map[PhysicsServer::SHAPE_CAPSULE]=capsule_mesh;
+
+ RID capsule_shape=ps->shape_create(PhysicsServer::SHAPE_CAPSULE);
+ Dictionary capsule_params;
+ capsule_params["radius"]=0.5;
+ capsule_params["height"]=1.4;
+ ps->shape_set_data( capsule_shape, capsule_params );
+ type_shape_map[PhysicsServer::SHAPE_CAPSULE]=capsule_shape;
+
+ /* CONVEX SHAPE */
+
+ PoolVector<Plane> convex_planes = Geometry::build_cylinder_planes(0.5,0.7,5,Vector3::AXIS_Z);
+
+ RID convex_mesh = vs->mesh_create();
+ Geometry::MeshData convex_data = Geometry::build_convex_mesh(convex_planes);
+ QuickHull::build(convex_data.vertices,convex_data);
+ vs->mesh_add_surface_from_mesh_data(convex_mesh,convex_data);
+
+ type_mesh_map[PhysicsServer::SHAPE_CONVEX_POLYGON]=convex_mesh;
+
+ RID convex_shape=ps->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON);
+ ps->shape_set_data( convex_shape, convex_data.vertices );
+ type_shape_map[PhysicsServer::SHAPE_CONVEX_POLYGON]=convex_shape;
+
+ }
+
+ void make_trimesh(Vector<Vector3> p_faces,const Transform& p_xform=Transform()) {
+
+ VisualServer *vs=VisualServer::get_singleton();
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+ RID trimesh_shape = ps->shape_create(PhysicsServer::SHAPE_CONCAVE_POLYGON);
+ ps->shape_set_data(trimesh_shape, p_faces);
+ p_faces=ps->shape_get_data(trimesh_shape); // optimized one
+ Vector<Vector3> normals; // for drawing
+ for (int i=0;i<p_faces.size()/3;i++) {
+
+ Plane p( p_faces[i*3+0],p_faces[i*3+1], p_faces[i*3+2] );
+ normals.push_back(p.normal);
+ normals.push_back(p.normal);
+ normals.push_back(p.normal);
+ }
+
+ RID trimesh_mesh = vs->mesh_create();
+ Array d;
+ d.resize(VS::ARRAY_MAX);
+ d[VS::ARRAY_VERTEX]=p_faces;
+ d[VS::ARRAY_NORMAL]=normals;
+ vs->mesh_add_surface_from_arrays(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, d );
+ //vs->material_set_flag( trimesh_mat, VisualServer::MATERIAL_FLAG_UNSHADED,true);
+
+
+ RID triins = vs->instance_create2(trimesh_mesh,scenario);
+
+
+ RID tribody = ps->body_create( PhysicsServer::BODY_MODE_STATIC);
+ ps->body_set_space(tribody,space);
+ //todo set space
+ ps->body_add_shape(tribody, trimesh_shape);
+ Transform tritrans = p_xform;
+ ps->body_set_state( tribody, PhysicsServer::BODY_STATE_TRANSFORM, tritrans );
+ vs->instance_set_transform( triins, tritrans );
+ //RID trimesh_material = vs->fixed_material_create();
+ //vs->material_generate( trimesh_material, Color(0.2,0.4,0.6) );
+ //vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_material );
+
+ }
+
+ void make_grid(int p_width,int p_height,float p_cellsize,float p_cellheight,const Transform& p_xform=Transform()) {
+
+ Vector< Vector< float > > grid;
+
+ grid.resize(p_width);
+
+ for (int i=0;i<p_width;i++) {
+
+ grid[i].resize(p_height);
+
+ for (int j=0;j<p_height;j++) {
+
+ grid[i][j]=1.0+Math::random(-p_cellheight, p_cellheight );
+ }
+ }
+
+ Vector<Vector3> faces;
+
+ for (int i=1;i<p_width;i++) {
+
+ for (int j=1;j<p_height;j++) {
+
+
+#define MAKE_VERTEX(m_x,m_z)\
+ faces.push_back( Vector3( (m_x-p_width/2)*p_cellsize, grid[m_x][m_z], (m_z-p_height/2)*p_cellsize ) )
+
+ MAKE_VERTEX(i,j-1);
+ MAKE_VERTEX(i,j);
+ MAKE_VERTEX(i-1,j);
+
+ MAKE_VERTEX(i-1,j-1);
+ MAKE_VERTEX(i,j-1);
+ MAKE_VERTEX(i-1,j);
+
+ }
+ }
+
+ make_trimesh(faces,p_xform);
+
+ }
+
+
+public:
+ virtual void input_event(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&4) {
+
+ ofs_y-=p_event.mouse_motion.relative_y/200.0;
+ ofs_x+=p_event.mouse_motion.relative_x/200.0;
+
+ }
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask&1) {
+
+ float y=-p_event.mouse_motion.relative_y/20.0;
+ float x=p_event.mouse_motion.relative_x/20.0;
+
+ if (mover.is_valid()) {
+
+
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+ Transform t = ps->body_get_state(mover,PhysicsServer::BODY_STATE_TRANSFORM);
+ t.origin+=Vector3(x,y,0);
+
+ ps->body_set_state(mover,PhysicsServer::BODY_STATE_TRANSFORM,t);
+ }
+
+ }
+
+ if (p_event.type == InputEvent::JOYPAD_MOTION) {
+
+ if (p_event.joy_motion.axis == 0) {
+
+ joy_direction.x = p_event.joy_motion.axis_value;
+ };
+
+ if (p_event.joy_motion.axis == 1) {
+
+ joy_direction.y = p_event.joy_motion.axis_value;
+ };
+ };
+ }
+
+ virtual void request_quit() {
+
+ quit=true;
+ }
+ virtual void init() {
+
+ ofs_x=ofs_y=0;
+ init_shapes();
+
+ PhysicsServer *ps = PhysicsServer::get_singleton();
+ space=ps->space_create();
+ ps->space_set_active(space,true);
+
+ VisualServer *vs=VisualServer::get_singleton();
+
+ /* LIGHT */
+ RID lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
+ //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
+ scenario = vs->scenario_create();
+ vs->light_set_shadow(lightaux,true);
+ light = vs->instance_create2( lightaux,scenario );
+ Transform t;
+ t.rotate(Vector3(1.0,0,0),0.6);
+ vs->instance_set_transform(light,t);
+
+
+
+ /* CAMERA */
+
+ camera = vs->camera_create();
+ RID viewport = vs->viewport_create();
+ vs->viewport_attach_camera( viewport, camera );
+ vs->viewport_attach_to_screen(viewport);
+ vs->viewport_set_scenario( viewport, scenario );
+
+ vs->camera_set_perspective(camera,60,0.1,40.0);
+ vs->camera_set_transform(camera,Transform( Basis(), Vector3(0,9,12)));
+ //vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME);
+
+ Transform gxf;
+ gxf.basis.scale(Vector3(1.4,0.4,1.4));
+ gxf.origin=Vector3(-2,1,-2);
+ make_grid(5,5,2.5,1,gxf);
+ //create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_STATIC,gxf);
+ //create_static_plane( Plane( Vector3(0,1,0), -2) );
+ //test_joint();
+ test_fall();
+ //test_joint();
+
+
+/*
+ Vector<Vector3> faces;
+ faces.push_back( Vector3(10,0,-5) );
+ faces.push_back( Vector3(0,0,10) );
+ faces.push_back( Vector3(-10,-0.2,-5) );
+ make_trimesh(faces);
+*/
+ /* Make Trimesh */
+ quit=false;
+ return;
+
+#if 0
+#define GRID_SIZE 5
+
+ float grid[GRID_SIZE][GRID_SIZE];
+
+ for (int i=0;i<GRID_SIZE;i++) {
+
+ for (int j=0;j<GRID_SIZE;j++) {
+
+ grid[j][i]=Math::random(0.0, 1.0 );
+ }
+ }
+
+ Vector<Vector3> faces;
+
+ for (int i=1;i<GRID_SIZE;i++) {
+
+ for (int j=1;j<GRID_SIZE;j++) {
+
+
+#define MAKE_VERTEX(m_x,m_z)\
+ faces.push_back( Vector3( m_x-GRID_SIZE/2.0, grid[m_x][m_z], m_z-GRID_SIZE/2.0 )*3.0 )
+
+ MAKE_VERTEX(i,j-1);
+ MAKE_VERTEX(i,j);
+ MAKE_VERTEX(i-1,j);
+
+ MAKE_VERTEX(i-1,j-1);
+ MAKE_VERTEX(i,j-1);
+ MAKE_VERTEX(i-1,j);
+
+ }
+ }
+ /*
+ faces.clear();
+ faces.push_back( Vector3(0,0,-5) );
+ faces.push_back( Vector3(1,0,-1) );
+ faces.push_back( Vector3(-1,-0,-1) );
+ */
+
+ RID trimesh_shape = ps->shape_create();
+ ps->shape_set_data(trimesh_shape, PhysicsServer::SHAPE_CONCAVE_POLYGON,faces);
+ faces=ps->shape_get_shape(trimesh_shape, 0);
+ Vector<Vector3> normals; // for drawing
+ for (int i=0;i<faces.size()/3;i++) {
+
+ Plane p( faces[i*3+0],faces[i*3+1], faces[i*3+2] );
+ normals.push_back(p.normal);
+ normals.push_back(p.normal);
+ normals.push_back(p.normal);
+ }
+
+ RID trimesh_mesh = vs->mesh_create();
+ vs->mesh_add_surface(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, VS::ARRAY_FORMAT_VERTEX|VS::ARRAY_FORMAT_NORMAL, faces.size() );
+ vs->mesh_surface_set_array(trimesh_mesh,0,VS::ARRAY_VERTEX, faces );
+ vs->mesh_surface_set_array(trimesh_mesh,0,VS::ARRAY_NORMAL, normals );
+ RID trimesh_mat = vs->fixed_material_create();
+ vs->material_generate( trimesh_mat, Color(1.0,0.5,0.3) );
+ vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_mat );
+
+ RID triins = vs->instance_create2(trimesh_mesh);
+
+
+
+ RID tribody = ps->body_create( PhysicsServer::BODY_MODE_STATIC, trimesh_shape);
+ Transform tritrans = Transform( Basis(), Vector3(0,0,-2) );
+ ps->body_set_state( tribody, PhysicsServer::BODY_STATE_TRANSFORM, tritrans );
+ vs->instance_set_transform( triins, tritrans );
+ RID trimesh_material = vs->fixed_material_create();
+ vs->material_generate( trimesh_material, Color(0.2,0.4,0.6) );
+ vs->mesh_surface_set_material( trimesh_mesh, 0, trimesh_material );
+#endif
+ }
+ virtual bool iteration(float p_time) {
+
+ if (mover.is_valid()) {
+ static float joy_speed = 10;
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+ Transform t = ps->body_get_state(mover,PhysicsServer::BODY_STATE_TRANSFORM);
+ t.origin+=Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time,0);
+ ps->body_set_state(mover,PhysicsServer::BODY_STATE_TRANSFORM,t);
+ };
+
+
+ Transform cameratr;
+ cameratr.rotate(Vector3(0,1,0),ofs_x);
+ cameratr.rotate(Vector3(1,0,0),-ofs_y);
+ cameratr.translate(Vector3(0,2,8));
+ VisualServer *vs=VisualServer::get_singleton();
+ vs->camera_set_transform(camera,cameratr);
+
+ return quit;
+ }
+ virtual void finish() {
+
+ }
+
+ void test_joint() {
+#if 0
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+
+ mover = create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_STATIC,Transform(Basis(),Vector3(0,0,-24)));
+ RID b = create_body(PhysicsServer::SHAPE_CAPSULE,PhysicsServer::BODY_MODE_RIGID,Transform());
+
+ ps->joint_create_double_pin(b,Vector3(0,0,1.0),mover,Vector3(0,0,0));
+ ps->body_add_collision_exception(mover,b);
+
+
+ List<String> cmdline = OS::get_singleton()->get_cmdline_args();
+ int link_count = LINK_COUNT;
+ if (cmdline.size() > 0 && cmdline[cmdline.size()-1].to_int()) {
+ link_count = cmdline[cmdline.size()-1].to_int();
+ };
+
+ for(int i=0;i<link_count;i++) {
+
+ RID c = create_body(PhysicsServer::SHAPE_CAPSULE,PhysicsServer::BODY_MODE_RIGID,Transform());
+ ps->joint_create_double_pin(b,Vector3(0,0,-0.7),c,Vector3(0,0,0.7));
+ ps->body_add_collision_exception(c,b);
+ b=c;
+ }
+
+
+ create_static_plane(Plane(Vector3(0,1,0),-8));
+#endif
+ }
+
+ void test_hinge() {
+#if 0
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+
+
+ mover = create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_STATIC,Transform(Basis(),Vector3(0,0,-24)));
+ RID b = create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_RIGID,Transform());
+
+ ps->joint_create_double_hinge(b,Transform(Basis(),Vector3(1,1,1.0)),mover,Transform(Basis(),Vector3(0,0,0)));
+ ps->body_add_collision_exception(mover,b);
+
+/*
+ for(int i=0;i<20;i++) {
+
+ RID c = create_body(PhysicsServer::SHAPE_CAPSULE,PhysicsServer::BODY_MODE_RIGID,Transform());
+ ps->joint_create_double_hinge(b,Transform(Basis(),Vector3(0,0,-0.7)),c,Transform(Basis(),Vector3(0,0,0.7)));
+ ps->body_add_collision_exception(c,b);
+ b=c;
+ }
+
+*/
+ //create_static_plane(Plane(Vector3(0,1,0),-8));
+#endif
+ }
+
+ void test_character() {
+
+ VisualServer *vs=VisualServer::get_singleton();
+ PhysicsServer * ps = PhysicsServer::get_singleton();
+
+
+ PoolVector<Plane> capsule_planes = Geometry::build_capsule_planes(0.5,1,12,5,Vector3::AXIS_Y);
+
+ RID capsule_mesh = vs->mesh_create();
+ Geometry::MeshData capsule_data = Geometry::build_convex_mesh(capsule_planes);
+ vs->mesh_add_surface_from_mesh_data(capsule_mesh,capsule_data);
+ type_mesh_map[PhysicsServer::SHAPE_CAPSULE]=capsule_mesh;
+
+ RID capsule_shape=ps->shape_create(PhysicsServer::SHAPE_CAPSULE);
+ Dictionary capsule_params;
+ capsule_params["radius"]=0.5;
+ capsule_params["height"]=1;
+ Transform shape_xform;
+ shape_xform.rotate(Vector3(1,0,0),Math_PI/2.0);
+ //shape_xform.origin=Vector3(1,1,1);
+ ps->shape_set_data( capsule_shape, capsule_params);
+
+
+ RID mesh_instance = vs->instance_create2(capsule_mesh,scenario);
+ character = ps->body_create(PhysicsServer::BODY_MODE_CHARACTER);
+ ps->body_set_space(character,space);
+ //todo add space
+ ps->body_add_shape(character,capsule_shape);
+
+ ps->body_set_force_integration_callback(character,this,"body_changed_transform",mesh_instance);
+
+
+ ps->body_set_state( character, PhysicsServer::BODY_STATE_TRANSFORM,Transform(Basis(),Vector3(-2,5,-2)));
+ bodies.push_back(character);
+
+
+ }
+
+ void test_fall() {
+
+
+ for (int i=0;i<35;i++) {
+
+ static const PhysicsServer::ShapeType shape_idx[]={
+ PhysicsServer::SHAPE_CAPSULE,
+ PhysicsServer::SHAPE_BOX,
+ PhysicsServer::SHAPE_SPHERE,
+ PhysicsServer::SHAPE_CONVEX_POLYGON
+ };
+
+ PhysicsServer::ShapeType type=shape_idx[i%4];
+ //type=PhysicsServer::SHAPE_CONVEX_POLYGON;
+
+ Transform t;
+
+ t.origin=Vector3(0.0*i,3.5+1.1*i,0.7+0.0*i);
+ //t.origin=Vector3(-0.7+0.0*i,0.5+4.1*i,0);
+ t.basis.rotate(Vector3(0.2,-1,0),Math_PI/2*0.6);
+ //t.basis.rotate(Vector3(0,-1,0),Math_PI/4*i);
+ //t.basis.rotate(Vector3(0,-1,0),Math_PI/4*i);
+ //t.basis.rotate(Vector3(-1,0,0),Math_PI/4*i);
+
+
+ create_body(type,PhysicsServer::BODY_MODE_RIGID,t);
+ //RID b = create_body(type,i==0?PhysicsServer::BODY_MODE_STATIC:PhysicsServer::BODY_MODE_RIGID,t);
+
+ }
+
+ create_static_plane( Plane( Vector3(0,1,0), -1) );
+
+
+/*
+ create_static_plane( Plane( Vector3(1,0,0), -2) );
+ create_static_plane( Plane( Vector3(-1,0,0), -2) );
+ create_static_plane( Plane( Vector3(0,0,1), -2) );
+ create_static_plane( Plane( Vector3(0,0,-1), -2) );
+*/
+
+
+ }
+
+ void test_activate() {
+
+ create_body(PhysicsServer::SHAPE_BOX,PhysicsServer::BODY_MODE_RIGID,Transform(Basis(),Vector3(0,2,0)),true);
+ //create_body(PhysicsServer::SHAPE_SPHERE,PhysicsServer::BODY_MODE_RIGID,Transform(Basis(),Vector3(0,6,0)),true);
+ create_static_plane( Plane( Vector3(0,1,0), -1) );
+
+ }
+
+
+ virtual bool idle(float p_time) {
+ return false;
+ }
+
+
+
+
+
+
+
+ TestPhysicsMainLoop() {
+
+ }
+};
+
+namespace TestPhysics {
+
+MainLoop* test() {
+
+ return memnew( TestPhysicsMainLoop );
+
+}
+
+}
diff --git a/main/tests/test_physics.h b/main/tests/test_physics.h
new file mode 100644
index 0000000000..5b6a54f2d4
--- /dev/null
+++ b/main/tests/test_physics.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* test_physics.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_PHYSICS_H
+#define TEST_PHYSICS_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+#include "os/main_loop.h"
+
+namespace TestPhysics {
+
+MainLoop* test();
+
+}
+
+#endif
diff --git a/main/tests/test_physics_2d.cpp b/main/tests/test_physics_2d.cpp
new file mode 100644
index 0000000000..8a6a8c78f9
--- /dev/null
+++ b/main/tests/test_physics_2d.cpp
@@ -0,0 +1,471 @@
+/*************************************************************************/
+/* test_physics_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_physics_2d.h"
+#include "servers/visual_server.h"
+#include "servers/physics_2d_server.h"
+#include "os/main_loop.h"
+#include "print_string.h"
+#include "map.h"
+#include "scene/resources/texture.h"
+#include "os/os.h"
+
+static const unsigned char convex_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0xaa,0x69,0x71,0xde,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdb,0x6,0xa,0x3,0x13,0x31,0x66,0xa7,0xac,0x79,0x0,0x0,0x4,0xef,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x9b,0xdd,0x4e,0x2a,0x57,0x14,0xc7,0xf7,0x1e,0xc0,0x19,0x38,0x32,0x80,0xa,0x6a,0xda,0x18,0xa3,0xc6,0x47,0x50,0x7b,0xa1,0xd9,0x36,0x27,0x7e,0x44,0xed,0x45,0x4d,0x93,0x3e,0x40,0x1f,0x64,0x90,0xf4,0x1,0xbc,0xf0,0xc2,0x9c,0x57,0x30,0x4d,0xbc,0xa8,0x6d,0xc,0x69,0x26,0xb5,0x68,0x8b,0x35,0x7e,0x20,0xb4,0xf5,0x14,0xbf,0x51,0x3c,0x52,0xe,0xc,0xe,0xc8,0xf0,0xb1,0x7a,0x51,0x3d,0xb1,0x9e,0x19,0x1c,0x54,0x70,0x1c,0xdc,0x9,0x17,0x64,0x8,0xc9,0xff,0xb7,0xd6,0x7f,0xcd,0x3f,0x2b,0xd9,0x8,0xbd,0x9c,0xda,0x3e,0xf8,0x31,0xff,0xc,0x0,0x8,0x42,0x88,0x9c,0x9f,0x9f,0xbf,0xa,0x87,0xc3,0xad,0x7d,0x7d,0x7d,0x7f,0x23,0x84,0x78,0x8c,0x31,0xaf,0x55,0x0,0xc6,0xc7,0x14,0x1e,0x8f,0xc7,0xbf,0x38,0x3c,0x3c,0x6c,0x9b,0x9f,0x9f,0x6f,0xb8,0x82,0x9b,0xee,0xe8,0xe8,0xf8,0x12,0x0,0xbe,0xd3,0x2a,0x8,0xfc,0x50,0xd1,0xf9,0x7c,0x9e,0x8a,0x46,0xa3,0x5f,0x9d,0x9e,0x9e,0x7e,0xb2,0xb0,0xb0,0x60,0xe5,0x79,0x1e,0xf1,0xfc,0x7f,0x3a,0x9,0x21,0x88,0x10,0x82,0x26,0x26,0x26,0xde,0x77,0x75,0x75,0x85,0x59,0x96,0xfd,0x5e,0x6b,0x20,0xf0,0x7d,0x85,0x4b,0x92,0xf4,0xfa,0xe0,0xe0,0xe0,0xd3,0xb9,0xb9,0xb9,0x46,0x49,0x92,0xea,0x6f,0xa,0xbf,0x7d,0x8,0x21,0x68,0x70,0x70,0xb0,0x38,0x39,0x39,0x79,0xd6,0xd9,0xd9,0xb9,0xcf,0x30,0xcc,0xa2,0xd6,0xad,0x21,0x2b,0x1c,0x0,0x38,0x41,0x10,0xfc,0xdb,0xdb,0xdb,0x27,0x1e,0x8f,0x27,0x4b,0x8,0x1,0x84,0x90,0xea,0xf,0x21,0x4,0x3c,0x1e,0x4f,0x76,0x67,0x67,0x67,0x3f,0x9f,0xcf,0xff,0x7c,0x5,0xf3,0xd9,0x0,0xe0,0x2,0x81,0xc0,0xa9,0xdb,0xed,0x2e,0x94,0x2b,0x5c,0xe,0xc4,0xca,0xca,0x8a,0x18,0x8d,0x46,0x3,0x0,0xc0,0x69,0x1e,0x4,0x0,0x90,0x48,0x24,0x12,0xe4,0x38,0xee,0x41,0xc2,0x6f,0x43,0xe0,0x38,0xe,0xfc,0x7e,0xbf,0x10,0x8b,0xc5,0xd6,0x35,0xd,0x22,0x9b,0xcd,0x7a,0x96,0x97,0x97,0x33,0xf,0xad,0x7c,0x29,0x10,0x9b,0x9b,0x9b,0xef,0x2e,0x2e,0x2e,0x7e,0xd5,0x1c,0x8,0x0,0x20,0xe1,0x70,0x38,0xfc,0x98,0xd5,0x57,0x2,0xe1,0x76,0xbb,0xf3,0xa1,0x50,0xe8,0x38,0x9b,0xcd,0xfe,0xa2,0x9,0x8,0x0,0x40,0x2e,0x2f,0x2f,0x7d,0x4b,0x4b,0x4b,0xb9,0x4a,0x54,0x5f,0x9,0xc4,0xd2,0xd2,0x92,0xb4,0xb7,0xb7,0xf7,0x36,0x97,0xcb,0x4d,0x3d,0x29,0x8,0x0,0xe0,0x42,0xa1,0xd0,0x71,0xb5,0xc4,0xdf,0xb6,0xc5,0x93,0xe,0x4a,0x0,0x20,0xa9,0x54,0xea,0x37,0xb7,0xdb,0x5d,0xa8,0xa6,0x78,0x39,0x10,0x6b,0x6b,0x6b,0xf1,0x64,0x32,0xb9,0x5a,0x55,0x10,0x0,0xc0,0x6d,0x6c,0x6c,0x9c,0x57,0xbb,0xfa,0x25,0x40,0x14,0x3,0x81,0x40,0x34,0x93,0xc9,0x2c,0x57,0x1c,0x4,0x0,0x90,0x58,0x2c,0xb6,0x5e,0xe9,0xc1,0x77,0x1f,0x10,0x53,0x53,0x53,0x52,0xc5,0x83,0x14,0x0,0x70,0x7e,0xbf,0x5f,0xd0,0x42,0xf5,0x95,0x40,0xf8,0x7c,0xbe,0xcb,0xa3,0xa3,0xa3,0x3f,0x1e,0xbd,0x1b,0x0,0x80,0x1c,0x1f,0x1f,0x87,0xb4,0x56,0xfd,0xaa,0x5,0x29,0x51,0x14,0xbf,0xf5,0xf9,0x7c,0x97,0x5a,0xad,0xbe,0x12,0x88,0xf5,0xf5,0xf5,0xd8,0x83,0x83,0x54,0xb5,0x42,0x8f,0x66,0x83,0x94,0xd6,0xbd,0x5f,0xce,0x7c,0x38,0x3c,0x3c,0xfc,0xb3,0x50,0x28,0xb8,0xcb,0x2,0x1,0x0,0xdc,0xf4,0xf4,0xf4,0xfe,0x73,0x15,0x2f,0x17,0xa4,0x22,0x91,0x48,0x50,0xb5,0x2d,0x0,0x80,0x9b,0x99,0x99,0x79,0xfb,0xdc,0x1,0xc8,0x5,0xa9,0x44,0x22,0xf1,0xfb,0x9d,0x10,0x0,0x80,0x9b,0x9d,0x9d,0xd,0xea,0x5,0xc0,0xad,0xfd,0x43,0x1a,0x0,0xb8,0xdb,0x9a,0xa9,0x8f,0xb6,0xa4,0x46,0xa3,0xa4,0xb7,0xd5,0x37,0xcf,0xf3,0x68,0x75,0x75,0xf5,0x4c,0xee,0x99,0x1c,0x80,0x9c,0x1e,0xf7,0xff,0x16,0x8b,0x45,0x50,0x5,0xa0,0xb7,0xb7,0xb7,0x85,0x10,0xa2,0x2b,0xf1,0x84,0x10,0xd4,0xdf,0xdf,0x6f,0x57,0x3,0x80,0x37,0x18,0xc,0x5,0x3d,0x2,0xa0,0x69,0x3a,0x8b,0x10,0xe2,0x4b,0x2,0xc0,0x18,0xf3,0xc1,0x60,0x70,0x47,0x8f,0x16,0x38,0x3a,0x3a,0x5a,0x93,0x5b,0xc3,0x7f,0x64,0x81,0xba,0xba,0x3a,0x49,0x8f,0x0,0x1a,0x1a,0x1a,0xd4,0xcd,0x0,0x93,0xc9,0xa4,0xcb,0x21,0xe8,0x74,0x3a,0xd5,0x1,0xa0,0x69,0x5a,0x77,0x1d,0x80,0x31,0x2e,0x38,0x9d,0x4e,0xb1,0x66,0x1,0x30,0xc,0x23,0x28,0x3d,0x93,0x9b,0x1,0xb9,0x9a,0x6,0x60,0x36,0x9b,0x75,0xd7,0x1,0x4a,0x21,0xa8,0x26,0x0,0x94,0xa,0x41,0xb2,0x0,0x18,0x86,0xc9,0xe9,0xd,0x80,0x52,0x8,0x92,0x5,0x60,0xb1,0x58,0x74,0x67,0x1,0xa5,0x10,0xa4,0x4,0x40,0x77,0x43,0xd0,0xe1,0x70,0xa8,0x9f,0x1,0x14,0x45,0x1,0x45,0x51,0x79,0x3d,0x1,0x68,0x6e,0x6e,0x4e,0xaa,0x6,0x80,0x10,0x42,0x6,0x83,0x41,0x37,0x36,0x28,0x15,0x82,0x6a,0x2,0x0,0x4d,0xd3,0xa9,0x52,0xcf,0x95,0x0,0xe8,0x66,0xe,0x98,0xcd,0x66,0xa1,0x6c,0x0,0x7a,0x5a,0x8b,0x59,0x2c,0x96,0x64,0xcd,0x2,0xb8,0x2b,0x4,0xe9,0xde,0x2,0x77,0x85,0xa0,0x9a,0xb0,0x40,0xa9,0x10,0xa4,0x8,0xc0,0x64,0x32,0xe9,0x6,0x40,0xa9,0x10,0x54,0xaa,0x3,0x74,0xf3,0x16,0x70,0xb9,0x5c,0xe5,0x3,0xe8,0xe9,0xe9,0x69,0xd5,0xc3,0x66,0x18,0x63,0x5c,0x68,0x6a,0x6a,0x12,0xcb,0x5,0xa0,0x9b,0xd5,0x38,0x4d,0xd3,0x29,0x8a,0xa2,0xa0,0x2c,0x0,0x18,0x63,0x3e,0x14,0xa,0xfd,0x55,0xb,0x21,0x48,0xd1,0x2,0x7a,0x59,0x8d,0xdf,0x1b,0x80,0x1e,0x56,0xe3,0x84,0x10,0x34,0x30,0x30,0x60,0xbb,0xeb,0x77,0x46,0x5,0xef,0x48,0xcf,0x4d,0xec,0x8d,0x99,0x5,0xf5,0xf5,0xf5,0xef,0x46,0x47,0x47,0xb,0x2e,0x97,0xeb,0xbc,0x54,0x8,0x52,0x4,0xc0,0x30,0x8c,0xf4,0x5c,0x4,0x9b,0x4c,0xa6,0xf4,0xf8,0xf8,0xb8,0xc8,0xb2,0x6c,0x32,0x9d,0x4e,0xff,0xd4,0xdd,0xdd,0x7d,0x66,0x34,0x1a,0x8b,0xd7,0x3,0xfd,0xae,0x5b,0x29,0xb2,0x57,0x66,0xb6,0xb6,0xb6,0xde,0xc4,0xe3,0xf1,0x6f,0xae,0xaf,0xc1,0x28,0x5d,0x85,0x79,0x2,0xc1,0x60,0xb5,0x5a,0xa3,0xa3,0xa3,0xa3,0x45,0xab,0xd5,0x9a,0x2a,0x16,0x8b,0x8b,0x6d,0x6d,0x6d,0xef,0xd5,0x8a,0x55,0xd,0x20,0x91,0x48,0xbc,0x3e,0x38,0x38,0xf8,0xda,0x6e,0xb7,0xf7,0x5f,0x5c,0x5c,0xd4,0x7b,0xbd,0xde,0xbc,0x20,0x8,0xcd,0x85,0x42,0x81,0xfe,0xf0,0xae,0xac,0x10,0x98,0x9b,0xd5,0xc5,0x18,0x17,0x59,0x96,0x3d,0x1d,0x19,0x19,0x1,0x96,0x65,0x5,0x8a,0xa2,0x7e,0x6c,0x69,0x69,0x49,0x3d,0x44,0xb0,0x2a,0x0,0x1f,0xcc,0x74,0x75,0x41,0xea,0xfa,0x7b,0x32,0x99,0x64,0x76,0x77,0x77,0x5d,0xe,0x87,0xa3,0x5f,0x14,0xc5,0x57,0x57,0x60,0x5a,0x8b,0xc5,0xa2,0xf1,0xbe,0x50,0x6e,0xa,0x66,0x18,0x26,0x31,0x36,0x36,0x96,0x65,0x59,0x36,0x29,0x49,0x92,0xb7,0xbd,0xbd,0xfd,0x9f,0x72,0xda,0xf9,0xd1,0x1,0xa8,0x1,0x93,0xcf,0xe7,0xa9,0x93,0x93,0x13,0x1b,0x4d,0xd3,0x9f,0xb,0x82,0x60,0xf5,0x7a,0xbd,0xd9,0x54,0x2a,0xe5,0xcc,0x64,0x32,0xe,0xb9,0x6e,0xb9,0x16,0x8c,0x31,0x2e,0xda,0x6c,0xb6,0xc8,0xd0,0xd0,0x10,0x65,0xb3,0xd9,0x92,0x95,0xa8,0x6e,0xc5,0x0,0xa8,0xe9,0x96,0x68,0x34,0x6a,0xdd,0xdf,0xdf,0x6f,0x76,0xb9,0x5c,0x9f,0x89,0xa2,0x58,0xbf,0xb8,0xb8,0x8,0x26,0x93,0x29,0x3b,0x3c,0x3c,0x8c,0xed,0x76,0x7b,0xd2,0x68,0x34,0xfe,0xd0,0xd8,0xd8,0x98,0xae,0xb6,0xe0,0x8a,0x1,0x50,0xb,0xe6,0xa9,0x5,0xbf,0x9c,0x97,0xf3,0xff,0xf3,0x2f,0x6a,0x82,0x7f,0xf6,0x4e,0xca,0x1b,0xf5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+class TestPhysics2DMainLoop : public MainLoop {
+
+ GDCLASS( TestPhysics2DMainLoop, MainLoop );
+
+
+ RID circle_img;
+ RID circle_shape;
+ RID space;
+ RID canvas;
+ RID ray;
+ RID ray_query;
+ Transform2D view_xform;
+
+ Vector2 ray_from,ray_to;
+
+
+ struct BodyShapeData {
+
+ RID image;
+ RID shape;
+ };
+
+
+ BodyShapeData body_shape_data[6];
+
+
+ void _create_body_shape_data() {
+ VisualServer *vs = VisualServer::get_singleton();
+ Physics2DServer *ps = Physics2DServer::get_singleton();
+
+ // SEGMENT
+
+ {
+
+ PoolVector<uint8_t> pixels;
+ pixels.resize(32*2*2);
+ for(int i=0;i<2;i++) {
+
+ for(int j=0;j<32;j++) {
+
+ pixels.set(i*32*2+j*2+0,(j==0)?255:0);
+ pixels.set(i*32*2+j*2+1,255);
+ }
+ }
+
+ Image image(32,2,0,Image::FORMAT_LA8,pixels);
+
+ body_shape_data[Physics2DServer::SHAPE_SEGMENT].image=vs->texture_create_from_image(image);
+
+ RID segment_shape = ps->shape_create(Physics2DServer::SHAPE_SEGMENT);
+ Rect2 sg(Point2(-16,0),Point2(16,0));
+ ps->shape_set_data(segment_shape,sg);
+
+ body_shape_data[Physics2DServer::SHAPE_SEGMENT].shape = segment_shape;
+
+ }
+ // CIRCLE
+
+ {
+
+ PoolVector<uint8_t> pixels;
+ pixels.resize(32*32*2);
+ for(int i=0;i<32;i++) {
+
+ for(int j=0;j<32;j++) {
+
+ bool black=Vector2(i-16,j-16).length_squared() < 16*16;
+
+ pixels.set(i*32*2+j*2+0,(i==16 || j==16)?255:0);
+ pixels.set(i*32*2+j*2+1,black?255:0);
+ }
+ }
+
+ Image image(32,32,0,Image::FORMAT_LA8,pixels);
+
+ body_shape_data[Physics2DServer::SHAPE_CIRCLE].image=vs->texture_create_from_image(image);
+
+ RID circle_shape = ps->shape_create(Physics2DServer::SHAPE_CIRCLE);
+ ps->shape_set_data(circle_shape,16);
+
+ body_shape_data[Physics2DServer::SHAPE_CIRCLE].shape = circle_shape;
+
+ }
+
+ // BOX
+
+ {
+
+ PoolVector<uint8_t> pixels;
+ pixels.resize(32*32*2);
+ for(int i=0;i<32;i++) {
+
+ for(int j=0;j<32;j++) {
+
+ bool black=i>0 && i<31 && j>0 && j<31;
+
+ pixels.set(i*32*2+j*2+0,black?0:255);
+ pixels.set(i*32*2+j*2+1,255);
+ }
+ }
+
+ Image image(32,32,0,Image::FORMAT_LA8,pixels);
+
+ body_shape_data[Physics2DServer::SHAPE_RECTANGLE].image=vs->texture_create_from_image(image);
+
+ RID rectangle_shape = ps->shape_create(Physics2DServer::SHAPE_RECTANGLE);
+ ps->shape_set_data(rectangle_shape,Vector2(16,16));
+
+ body_shape_data[Physics2DServer::SHAPE_RECTANGLE].shape = rectangle_shape;
+
+ }
+
+
+ // CAPSULE
+
+ {
+
+ PoolVector<uint8_t> pixels;
+ pixels.resize(32*64*2);
+ for(int i=0;i<64;i++) {
+
+ for(int j=0;j<32;j++) {
+
+
+ int si = i>48 ? i - 32 : (i<16 ? i : 16);
+ bool black=Vector2(si-16,j-16).length_squared() < 16*16;
+
+ pixels.set(i*32*2+j*2+0,(i==16 || j==16 || i==48)?255:0);
+ pixels.set(i*32*2+j*2+1,black?255:0);
+
+ }
+ }
+
+ Image image(32,64,0,Image::FORMAT_LA8,pixels);
+
+ body_shape_data[Physics2DServer::SHAPE_CAPSULE].image=vs->texture_create_from_image(image);
+
+ RID capsule_shape = ps->shape_create(Physics2DServer::SHAPE_CAPSULE);
+ ps->shape_set_data(capsule_shape,Vector2(16,32));
+
+ body_shape_data[Physics2DServer::SHAPE_CAPSULE].shape = capsule_shape;
+
+ }
+
+ // CONVEX
+
+ {
+
+
+ Image image(convex_png);
+
+ body_shape_data[Physics2DServer::SHAPE_CUSTOM+1].image=vs->texture_create_from_image(image);
+
+ RID convex_polygon_shape = ps->shape_create(Physics2DServer::SHAPE_CONVEX_POLYGON);
+
+ PoolVector<Vector2> arr;
+ Point2 sb(32,32);
+ arr.push_back(Point2(20,3)-sb);
+ arr.push_back(Point2(58,23)-sb);
+ arr.push_back(Point2(55,54)-sb);
+ arr.push_back(Point2(27,60)-sb);
+ arr.push_back(Point2(5,56)-sb);
+ arr.push_back(Point2(4,20)-sb);
+ arr.push_back(Point2(11,7)-sb);
+ ps->shape_set_data(convex_polygon_shape,arr);
+
+ body_shape_data[Physics2DServer::SHAPE_CUSTOM+1].shape = convex_polygon_shape;
+
+ }
+
+
+ }
+
+
+
+
+ void _do_ray_query() {
+
+ /*
+ Physics2DServer *ps = Physics2DServer::get_singleton();
+ ps->query_intersection_segment(ray_query,ray_from,ray_to);
+ */
+
+ }
+
+protected:
+
+
+ void input_event(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON) {
+
+ const InputEventMouseButton &mb=p_event.mouse_button;
+
+ if (mb.pressed) {
+
+ Point2 p( mb.x, mb.y );
+
+ if (mb.button_index==1) {
+ ray_to=p;
+ _do_ray_query();
+ } else if (mb.button_index==2) {
+ ray_from=p;
+ _do_ray_query();
+ }
+
+ }
+ }
+ if (p_event.type==InputEvent::MOUSE_MOTION) {
+
+ const InputEventMouseMotion &mm=p_event.mouse_motion;
+
+ Point2 p( mm.x, mm.y );
+
+ if (mm.button_mask&BUTTON_MASK_LEFT) {
+ ray_to=p;
+ _do_ray_query();
+ } else if (mm.button_mask&BUTTON_MASK_RIGHT) {
+ ray_from=p;
+ _do_ray_query();
+ }
+ }
+ }
+
+ RID _add_body(Physics2DServer::ShapeType p_shape, const Transform2D& p_xform) {
+
+ VisualServer *vs = VisualServer::get_singleton();
+ Physics2DServer *ps = Physics2DServer::get_singleton();
+
+ RID body = ps->body_create();
+ ps->body_add_shape(body,body_shape_data[p_shape].shape);
+ ps->body_set_space(body,space);
+ ps->body_set_continuous_collision_detection_mode(body,Physics2DServer::CCD_MODE_CAST_SHAPE);
+ ps->body_set_state(body,Physics2DServer::BODY_STATE_TRANSFORM,p_xform);
+
+ //print_line("add body with xform: "+p_xform);
+ RID sprite = vs->canvas_item_create();
+ vs->canvas_item_set_parent(sprite,canvas);
+ vs->canvas_item_set_transform(sprite,p_xform);
+ Size2 imgsize( vs->texture_get_width(body_shape_data[p_shape].image),vs->texture_get_height(body_shape_data[p_shape].image) );
+ vs->canvas_item_add_texture_rect(sprite,Rect2(-imgsize/2.0,imgsize),body_shape_data[p_shape].image);
+
+ ps->body_set_force_integration_callback(body,this,"_body_moved",sprite);
+ //RID q = ps->query_create(this,"_body_moved",sprite);
+ //ps->query_body_state(q,body);
+
+ return body;
+ }
+
+ void _add_plane(const Vector2& p_normal, real_t p_d) {
+
+ Physics2DServer *ps = Physics2DServer::get_singleton();
+
+ Array arr;
+ arr.push_back(p_normal);
+ arr.push_back(p_d);
+
+ RID plane = ps->shape_create(Physics2DServer::SHAPE_LINE);
+ ps->shape_set_data(plane,arr);
+
+ RID plane_body = ps->body_create(Physics2DServer::BODY_MODE_STATIC);
+ ps->body_set_space(plane_body,space);
+ ps->body_add_shape(plane_body,plane);
+
+ }
+
+ void _add_concave(const Vector<Vector2>& p_points,const Transform2D& p_xform=Transform2D()) {
+
+ Physics2DServer *ps = Physics2DServer::get_singleton();
+ VisualServer *vs = VisualServer::get_singleton();
+
+ RID concave = ps->shape_create(Physics2DServer::SHAPE_CONCAVE_POLYGON);
+ ps->shape_set_data(concave,p_points);
+ RID body = ps->body_create(Physics2DServer::BODY_MODE_STATIC);
+ ps->body_set_space(body,space);
+ ps->body_add_shape(body,concave);
+ ps->body_set_state(body,Physics2DServer::BODY_STATE_TRANSFORM,p_xform);
+
+
+ RID sprite = vs->canvas_item_create();
+ vs->canvas_item_set_parent(sprite,canvas);
+ vs->canvas_item_set_transform(sprite,p_xform);
+ for(int i=0;i<p_points.size();i+=2) {
+ vs->canvas_item_add_line(sprite,p_points[i],p_points[i+1],Color(0,0,0),2);
+ }
+
+ }
+
+ void _body_moved(Object *p_state,RID p_sprite) {
+ Physics2DDirectBodyState *state=(Physics2DDirectBodyState *)p_state;
+ VisualServer::get_singleton()->canvas_item_set_transform(p_sprite,state->get_transform());
+ }
+
+ void _ray_query_callback(const RID& p_rid, ObjectID p_id, int p_shape, const Vector2& p_point, const Vector2& p_normal) {
+
+
+ Vector2 ray_end;
+
+ if (p_rid.is_valid()) {
+ ray_end=p_point;
+ } else {
+ ray_end=ray_to;
+ }
+
+ VisualServer *vs = VisualServer::get_singleton();
+
+ vs->canvas_item_clear(ray);
+ vs->canvas_item_add_line(ray,ray_from,ray_end,p_rid.is_valid()?Color(0,1,0.4):Color(1,0.4,0),2);
+ if (p_rid.is_valid())
+ vs->canvas_item_add_line(ray,ray_end,ray_end+p_normal*20,p_rid.is_valid()?Color(0,1,0.4):Color(1,0.4,0),2);
+
+ }
+
+ static void _bind_methods() {
+
+
+ ClassDB::bind_method(_MD("_body_moved"),&TestPhysics2DMainLoop::_body_moved);
+ ClassDB::bind_method(_MD("_ray_query_callback"),&TestPhysics2DMainLoop::_ray_query_callback);
+ }
+
+
+public:
+
+
+
+ virtual void init() {
+
+ VisualServer *vs = VisualServer::get_singleton();
+ Physics2DServer *ps = Physics2DServer::get_singleton();
+
+
+
+ space=ps->space_create();
+ ps->space_set_active(space,true);
+ ps->set_active(true);
+ ps->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,Vector2(0,1));
+ ps->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY,98);
+
+ {
+
+ RID vp = vs->viewport_create();
+ canvas = vs->canvas_create();
+ vs->viewport_attach_canvas(vp,canvas);
+ vs->viewport_attach_to_screen(vp,Rect2(Vector2(),OS::get_singleton()->get_window_size()));
+ Transform2D smaller;
+ //smaller.scale(Vector2(0.6,0.6));
+ //smaller.elements[2]=Vector2(100,0);
+
+ //view_xform = smaller;
+ vs->viewport_set_canvas_transform(vp,canvas,view_xform);
+
+ }
+
+ ray = vs->canvas_item_create();
+ vs->canvas_item_set_parent(ray,canvas);
+ //ray_query = ps->query_create(this,"_ray_query_callback",Variant());
+ //ps->query_intersection(ray_query,space);
+
+ _create_body_shape_data();
+
+ for(int i=0;i<32;i++) {
+
+ Physics2DServer::ShapeType types[4]={
+ Physics2DServer::SHAPE_CIRCLE,
+ Physics2DServer::SHAPE_CAPSULE,
+ Physics2DServer::SHAPE_RECTANGLE,
+ Physics2DServer::SHAPE_CONVEX_POLYGON,
+
+ };
+
+ Physics2DServer::ShapeType type = types[i%4];
+ //type=Physics2DServer::SHAPE_SEGMENT;
+ _add_body(type,Transform2D(i*0.8,Point2(152+i*40,100-40*i)));
+ /*
+ if (i==0)
+ ps->body_set_mode(b,Physics2DServer::BODY_MODE_STATIC);
+ */
+ }
+
+ //RID b= _add_body(Physics2DServer::SHAPE_CIRCLE,Transform2D(0,Point2(101,140)));
+ //ps->body_set_mode(b,Physics2DServer::BODY_MODE_STATIC);
+
+ Point2 prev;
+
+ Vector<Point2> parr;
+ for(int i=0;i<30;i++) {
+
+ Point2 p(i*60,Math::randf() * 70+340);
+ if (i>0) {
+ parr.push_back(prev);
+ parr.push_back(p);
+ }
+ prev=p;
+ }
+
+ _add_concave(parr);
+ //_add_plane(Vector2(0.0,-1).normalized(),-300);
+ //_add_plane(Vector2(1,0).normalized(),50);
+ //_add_plane(Vector2(-1,0).normalized(),-600);
+
+ }
+
+ virtual bool idle(float p_time) {
+
+
+ return false;
+ }
+ virtual void finish() {
+
+
+ }
+
+
+ TestPhysics2DMainLoop() {}
+
+};
+
+
+namespace TestPhysics2D {
+
+
+MainLoop* test() {
+
+
+ return memnew( TestPhysics2DMainLoop );
+}
+
+
+}
diff --git a/main/tests/test_physics_2d.h b/main/tests/test_physics_2d.h
new file mode 100644
index 0000000000..e2eb1f4023
--- /dev/null
+++ b/main/tests/test_physics_2d.h
@@ -0,0 +1,41 @@
+/*************************************************************************/
+/* test_physics_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_PHYSICS_2D_H
+#define TEST_PHYSICS_2D_H
+
+
+#include "os/main_loop.h"
+
+namespace TestPhysics2D {
+
+MainLoop* test();
+
+}
+
+#endif // TEST_PHYSICS_2D_H
diff --git a/main/tests/test_render.cpp b/main/tests/test_render.cpp
new file mode 100644
index 0000000000..7380c1ff6a
--- /dev/null
+++ b/main/tests/test_render.cpp
@@ -0,0 +1,262 @@
+/*************************************************************************/
+/* test_render.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_render.h"
+#include "servers/visual_server.h"
+#include "os/main_loop.h"
+#include "math_funcs.h"
+#include "print_string.h"
+#include "os/os.h"
+#include "quick_hull.h"
+#include "os/keyboard.h"
+
+#define OBJECT_COUNT 50
+
+namespace TestRender {
+
+
+class TestMainLoop : public MainLoop {
+
+
+ RID test_cube;
+ RID instance;
+ RID camera;
+ RID viewport;
+ RID light;
+ RID scenario;
+
+ struct InstanceInfo {
+
+ RID instance;
+ Transform base;
+ Vector3 rot_axis;
+ };
+
+ List<InstanceInfo> instances;
+
+ float ofs;
+ bool quit;
+protected:
+
+
+public:
+ virtual void input_event(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && p_event.key.pressed)
+ quit=true;
+ }
+
+ virtual void init() {
+
+
+ print_line("INITIALIZING TEST RENDER");
+ VisualServer *vs=VisualServer::get_singleton();
+ test_cube = vs->get_test_cube();
+ scenario = vs->scenario_create();
+
+
+
+
+
+
+ Vector<Vector3> vts;
+
+/*
+ PoolVector<Plane> sp = Geometry::build_sphere_planes(2,5,5);
+ Geometry::MeshData md2 = Geometry::build_convex_mesh(sp);
+ vts=md2.vertices;
+*/
+/*
+
+ static const int s = 20;
+ for(int i=0;i<s;i++) {
+ Basis rot(Vector3(0,1,0),i*Math_PI/s);
+
+ for(int j=0;j<s;j++) {
+ Vector3 v;
+ v.x=Math::sin(j*Math_PI*2/s);
+ v.y=Math::cos(j*Math_PI*2/s);
+
+ vts.push_back( rot.xform(v*2 ) );
+ }
+ }*/
+ /*for(int i=0;i<100;i++) {
+
+ vts.push_back( Vector3(Math::randf()*2-1.0,Math::randf()*2-1.0,Math::randf()*2-1.0).normalized()*2);
+ }*/
+ /*
+ vts.push_back(Vector3(0,0,1));
+ vts.push_back(Vector3(0,0,-1));
+ vts.push_back(Vector3(0,1,0));
+ vts.push_back(Vector3(0,-1,0));
+ vts.push_back(Vector3(1,0,0));
+ vts.push_back(Vector3(-1,0,0));*/
+
+ vts.push_back(Vector3(1,1,1));
+ vts.push_back(Vector3(1,-1,1));
+ vts.push_back(Vector3(-1,1,1));
+ vts.push_back(Vector3(-1,-1,1));
+ vts.push_back(Vector3(1,1,-1));
+ vts.push_back(Vector3(1,-1,-1));
+ vts.push_back(Vector3(-1,1,-1));
+ vts.push_back(Vector3(-1,-1,-1));
+
+ Geometry::MeshData md;
+ Error err = QuickHull::build(vts,md);
+ print_line("ERR: "+itos(err));
+ test_cube = vs->mesh_create();
+ vs->mesh_add_surface_from_mesh_data(test_cube,md);
+ //vs->scenario_set_debug(scenario,VS::SCENARIO_DEBUG_WIREFRAME);
+
+ /*
+ RID sm = vs->shader_create();
+ //vs->shader_set_fragment_code(sm,"OUT_ALPHA=mod(TIME,1);");
+ //vs->shader_set_vertex_code(sm,"OUT_VERTEX=IN_VERTEX*mod(TIME,1);");
+ vs->shader_set_fragment_code(sm,"OUT_DIFFUSE=vec3(1,0,1);OUT_GLOW=abs(sin(TIME));");
+ RID tcmat = vs->mesh_surface_get_material(test_cube,0);
+ vs->material_set_shader(tcmat,sm);
+ */
+
+
+ List<String> cmdline = OS::get_singleton()->get_cmdline_args();
+ int object_count = OBJECT_COUNT;
+ if (cmdline.size() > 0 && cmdline[cmdline.size()-1].to_int()) {
+ object_count = cmdline[cmdline.size()-1].to_int();
+ };
+
+ for (int i=0;i<object_count;i++) {
+
+ InstanceInfo ii;
+
+
+ ii.instance = vs->instance_create2( test_cube, scenario );
+
+
+ ii.base.translate( Math::random(-20,20), Math::random(-20,20),Math::random(-20,18) );
+ ii.base.rotate( Vector3(0,1,0), Math::randf() * Math_PI );
+ ii.base.rotate( Vector3(1,0,0), Math::randf() * Math_PI );
+ vs->instance_set_transform( ii.instance, ii.base );
+
+ ii.rot_axis = Vector3( Math::random(-1,1), Math::random(-1,1), Math::random(-1,1) ).normalized();
+
+ instances.push_back(ii);
+
+ }
+
+ camera = vs->camera_create();
+
+// vs->camera_set_perspective( camera, 60.0,0.1, 100.0 );
+
+ viewport = vs->viewport_create();
+ Size2i screen_size = OS::get_singleton()->get_window_size();
+ vs->viewport_set_size(viewport,screen_size.x,screen_size.y);
+ vs->viewport_attach_to_screen(viewport,Rect2(Vector2(),screen_size));
+ vs->viewport_set_active(viewport,true);
+ vs->viewport_attach_camera( viewport, camera );
+ vs->viewport_set_scenario( viewport, scenario );
+ vs->camera_set_transform(camera, Transform( Basis(), Vector3(0,3,30 ) ) );
+ vs->camera_set_perspective( camera, 60, 0.1, 1000);
+
+
+ /*
+ RID lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
+ vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_RADIUS, 80 );
+ vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ATTENUATION, 1 );
+ vs->light_set_var( lightaux, VisualServer::LIGHT_VAR_ENERGY, 1.5 );
+ light = vs->instance_create( lightaux );
+ */
+ RID lightaux;
+
+ lightaux = vs->light_create( VisualServer::LIGHT_DIRECTIONAL );
+ //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
+ vs->light_set_color( lightaux, Color(1.0,1.0,1.0) );
+ //vs->light_set_shadow( lightaux, true );
+ light = vs->instance_create2( lightaux, scenario );
+ Transform lla;
+ //lla.set_look_at(Vector3(),Vector3(1,-1,1),Vector3(0,1,0));
+ lla.set_look_at(Vector3(),Vector3(-0.000000,-0.836026,-0.548690),Vector3(0,1,0));
+
+ vs->instance_set_transform( light, lla );
+
+ lightaux = vs->light_create( VisualServer::LIGHT_OMNI );
+ //vs->light_set_color( lightaux, VisualServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) );
+ vs->light_set_color( lightaux, Color(1.0,1.0,0.0) );
+ vs->light_set_param( lightaux, VisualServer::LIGHT_PARAM_RANGE, 4 );
+ vs->light_set_param( lightaux, VisualServer::LIGHT_PARAM_ENERGY, 8 );
+ //vs->light_set_shadow( lightaux, true );
+ //light = vs->instance_create( lightaux );
+
+ ofs=0;
+ quit=false;
+ }
+ virtual bool iteration(float p_time) {
+
+ VisualServer *vs=VisualServer::get_singleton();
+ //Transform t;
+ //t.rotate(Vector3(0, 1, 0), ofs);
+ //t.translate(Vector3(0,0,20 ));
+ //vs->camera_set_transform(camera, t);
+
+ ofs+=p_time*0.05;
+
+ //return quit;
+
+ for(List<InstanceInfo>::Element *E=instances.front();E;E=E->next()) {
+
+ Transform pre( Basis(E->get().rot_axis, ofs), Vector3() );
+ vs->instance_set_transform( E->get().instance, pre * E->get().base );
+ /*
+ if( !E->next() ) {
+
+ vs->free( E->get().instance );
+ instances.erase(E );
+ }*/
+ }
+
+ return quit;
+ }
+
+ virtual bool idle(float p_time) {
+ return quit;
+ }
+
+
+ virtual void finish() {
+
+ }
+
+};
+
+
+MainLoop* test() {
+
+ return memnew( TestMainLoop );
+
+}
+
+}
diff --git a/main/tests/test_render.h b/main/tests/test_render.h
new file mode 100644
index 0000000000..6993e75b9f
--- /dev/null
+++ b/main/tests/test_render.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* test_render.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_RENDER_H
+#define TEST_RENDER_H
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+#include "os/main_loop.h"
+
+namespace TestRender {
+
+MainLoop* test();
+
+}
+
+#endif
diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp
new file mode 100644
index 0000000000..1a677bcbe2
--- /dev/null
+++ b/main/tests/test_shader_lang.cpp
@@ -0,0 +1,361 @@
+/*************************************************************************/
+/* test_shader_lang.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_shader_lang.h"
+
+
+#include "os/main_loop.h"
+#include "os/os.h"
+#include "os/file_access.h"
+
+#include "scene/gui/control.h"
+#include "scene/gui/text_edit.h"
+#include "print_string.h"
+#include "servers/visual/shader_language.h"
+//#include "drivers/gles2/shader_compiler_gles2.h"
+
+
+typedef ShaderLanguage SL;
+
+namespace TestShaderLang {
+
+
+static String _mktab(int p_level) {
+
+ String tb;
+ for(int i=0;i<p_level;i++) {
+ tb+="\t";
+ }
+
+ return tb;
+}
+
+static String _typestr(SL::DataType p_type) {
+
+ return ShaderLanguage::get_datatype_name(p_type);
+
+ return "";
+}
+
+
+static String _prestr(SL::DataPrecision p_pres) {
+
+
+ switch(p_pres) {
+ case SL::PRECISION_LOWP: return "lowp ";
+ case SL::PRECISION_MEDIUMP: return "mediump ";
+ case SL::PRECISION_HIGHP: return "highp ";
+ case SL::PRECISION_DEFAULT: return "";
+ }
+ return "";
+}
+
+
+static String _opstr(SL::Operator p_op) {
+
+ return ShaderLanguage::get_operator_text(p_op);
+
+
+}
+
+
+static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value>& p_values) {
+
+ switch(p_type) {
+ case SL::TYPE_BOOL: return p_values[0].boolean?"true":"false";
+ case SL::TYPE_BVEC2: return String()+"bvec2("+(p_values[0].boolean?"true":"false")+(p_values[1].boolean?"true":"false")+")";
+ case SL::TYPE_BVEC3: return String()+"bvec3("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+")";
+ case SL::TYPE_BVEC4: return String()+"bvec4("+(p_values[0].boolean?"true":"false")+","+(p_values[1].boolean?"true":"false")+","+(p_values[2].boolean?"true":"false")+","+(p_values[3].boolean?"true":"false")+")";
+ case SL::TYPE_INT: return rtos(p_values[0].sint);
+ case SL::TYPE_IVEC2: return String()+"ivec2("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+")";
+ case SL::TYPE_IVEC3: return String()+"ivec3("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+")";
+ case SL::TYPE_IVEC4: return String()+"ivec4("+rtos(p_values[0].sint)+","+rtos(p_values[1].sint)+","+rtos(p_values[2].sint)+","+rtos(p_values[3].sint)+")";
+ case SL::TYPE_UINT: return rtos(p_values[0].real);
+ case SL::TYPE_UVEC2: return String()+"uvec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")";
+ case SL::TYPE_UVEC3: return String()+"uvec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")";
+ case SL::TYPE_UVEC4: return String()+"uvec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")";
+ case SL::TYPE_FLOAT: return rtos(p_values[0].real);
+ case SL::TYPE_VEC2: return String()+"vec2("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+")";
+ case SL::TYPE_VEC3: return String()+"vec3("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+")";
+ case SL::TYPE_VEC4: return String()+"vec4("+rtos(p_values[0].real)+","+rtos(p_values[1].real)+","+rtos(p_values[2].real)+","+rtos(p_values[3].real)+")";
+ default: ERR_FAIL_V(String());
+ }
+}
+
+static String dump_node_code(SL::Node *p_node,int p_level) {
+
+ String code;
+
+ switch(p_node->type) {
+
+ case SL::Node::TYPE_SHADER: {
+
+ SL::ShaderNode *pnode=(SL::ShaderNode*)p_node;
+
+ for(Map<StringName,SL::ShaderNode::Uniform>::Element *E=pnode->uniforms.front();E;E=E->next()) {
+
+ String ucode="uniform ";
+ ucode+=_prestr(E->get().precission);
+ ucode+=_typestr(E->get().type);
+ ucode+=" "+String(E->key());
+
+ if (E->get().default_value.size()) {
+ ucode+=" = "+get_constant_text(E->get().type,E->get().default_value);
+ }
+
+ static const char*hint_name[SL::ShaderNode::Uniform::HINT_MAX]={
+ "",
+ "color",
+ "range",
+ "albedo",
+ "normal",
+ "black",
+ "white"
+ };
+
+ if (E->get().hint)
+ ucode+=" : "+String(hint_name[E->get().hint]);
+
+ code+=ucode+"\n";
+
+ }
+
+ for(Map<StringName,SL::ShaderNode::Varying>::Element *E=pnode->varyings.front();E;E=E->next()) {
+
+ String vcode="varying ";
+ vcode+=_prestr(E->get().precission);
+ vcode+=_typestr(E->get().type);
+ vcode+=" "+String(E->key());
+
+ code+=vcode+"\n";
+
+ }
+ for(int i=0;i<pnode->functions.size();i++) {
+
+ SL::FunctionNode *fnode=pnode->functions[i].function;
+
+ String header;
+ header=_typestr(fnode->return_type)+" "+fnode->name+"(";
+ for(int i=0;i<fnode->arguments.size();i++) {
+
+ if (i>0)
+ header+=", ";
+ header+=_prestr(fnode->arguments[i].precision)+_typestr(fnode->arguments[i].type)+" "+fnode->arguments[i].name;
+ }
+
+ header+=")\n";
+ code+=header;
+ code+=dump_node_code(fnode->body,p_level+1);
+ }
+
+ //code+=dump_node_code(pnode->body,p_level);
+ } break;
+ case SL::Node::TYPE_FUNCTION: {
+
+ } break;
+ case SL::Node::TYPE_BLOCK: {
+ SL::BlockNode *bnode=(SL::BlockNode*)p_node;
+
+ //variables
+ code+=_mktab(p_level-1)+"{\n";
+ for(Map<StringName,SL::BlockNode::Variable>::Element *E=bnode->variables.front();E;E=E->next()) {
+
+ code+=_mktab(p_level)+_prestr(E->get().precision)+_typestr(E->get().type)+" "+E->key()+";\n";
+ }
+
+ for(int i=0;i<bnode->statements.size();i++) {
+
+ String scode = dump_node_code(bnode->statements[i],p_level);
+
+ if (bnode->statements[i]->type==SL::Node::TYPE_CONTROL_FLOW || bnode->statements[i]->type==SL::Node::TYPE_CONTROL_FLOW) {
+ code+=scode; //use directly
+ } else {
+ code+=_mktab(p_level)+scode+";\n";
+ }
+ }
+ code+=_mktab(p_level-1)+"}\n";
+
+
+ } break;
+ case SL::Node::TYPE_VARIABLE: {
+ SL::VariableNode *vnode=(SL::VariableNode*)p_node;
+ code=vnode->name;
+
+ } break;
+ case SL::Node::TYPE_CONSTANT: {
+ SL::ConstantNode *cnode=(SL::ConstantNode*)p_node;
+ return get_constant_text(cnode->datatype,cnode->values);
+
+ } break;
+ case SL::Node::TYPE_OPERATOR: {
+ SL::OperatorNode *onode=(SL::OperatorNode*)p_node;
+
+
+ switch(onode->op) {
+
+ case SL::OP_ASSIGN:
+ case SL::OP_ASSIGN_ADD:
+ case SL::OP_ASSIGN_SUB:
+ case SL::OP_ASSIGN_MUL:
+ case SL::OP_ASSIGN_DIV:
+ case SL::OP_ASSIGN_SHIFT_LEFT:
+ case SL::OP_ASSIGN_SHIFT_RIGHT:
+ case SL::OP_ASSIGN_MOD:
+ case SL::OP_ASSIGN_BIT_AND:
+ case SL::OP_ASSIGN_BIT_OR:
+ case SL::OP_ASSIGN_BIT_XOR:
+ code=dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level);
+ break;
+ case SL::OP_BIT_INVERT:
+ case SL::OP_NEGATE:
+ case SL::OP_NOT:
+ case SL::OP_DECREMENT:
+ case SL::OP_INCREMENT:
+ code=_opstr(onode->op)+dump_node_code(onode->arguments[0],p_level);
+ break;
+ case SL::OP_POST_DECREMENT:
+ case SL::OP_POST_INCREMENT:
+ code=dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op);
+ break;
+ case SL::OP_CALL:
+ case SL::OP_CONSTRUCT:
+ code=dump_node_code(onode->arguments[0],p_level)+"(";
+ for(int i=1;i<onode->arguments.size();i++) {
+ if (i>1)
+ code+=", ";
+ code+=dump_node_code(onode->arguments[i],p_level);
+ }
+ code+=")";
+ break;
+ default: {
+
+ code="("+dump_node_code(onode->arguments[0],p_level)+_opstr(onode->op)+dump_node_code(onode->arguments[1],p_level)+")";
+ break;
+
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_CONTROL_FLOW: {
+ SL::ControlFlowNode *cfnode=(SL::ControlFlowNode*)p_node;
+ if (cfnode->flow_op==SL::FLOW_OP_IF) {
+
+ code+=_mktab(p_level)+"if ("+dump_node_code(cfnode->expressions[0],p_level)+")\n";
+ code+=dump_node_code(cfnode->blocks[0],p_level+1);
+ if (cfnode->blocks.size()==2) {
+
+ code+=_mktab(p_level)+"else\n";
+ code+=dump_node_code(cfnode->blocks[1],p_level+1);
+ }
+
+
+ } else if (cfnode->flow_op==SL::FLOW_OP_RETURN) {
+
+ if (cfnode->blocks.size()) {
+ code="return "+dump_node_code(cfnode->blocks[0],p_level);
+ } else {
+ code="return";
+ }
+ }
+
+ } break;
+ case SL::Node::TYPE_MEMBER: {
+ SL::MemberNode *mnode=(SL::MemberNode*)p_node;
+ code=dump_node_code(mnode->owner,p_level)+"."+mnode->name;
+
+ } break;
+ }
+
+ return code;
+
+}
+
+static Error recreate_code(void *p_str,SL::ShaderNode *p_program) {
+
+
+ String *str=(String*)p_str;
+
+ *str=dump_node_code(p_program,0);
+
+ return OK;
+}
+
+
+MainLoop* test() {
+
+ List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
+
+ if (cmdlargs.empty()) {
+ //try editor!
+ print_line("usage: godot -test shader_lang <shader>");
+ return NULL;
+ }
+
+ String test = cmdlargs.back()->get();
+
+ FileAccess *fa = FileAccess::open(test,FileAccess::READ);
+
+ if (!fa) {
+ ERR_FAIL_V(NULL);
+ }
+
+ String code;
+
+ while(true) {
+ CharType c = fa->get_8();
+ if (fa->eof_reached())
+ break;
+ code+=c;
+ }
+
+ SL sl;
+ print_line("tokens:\n\n"+sl.token_debug(code));
+
+ Map<StringName,Map<StringName,SL::DataType> > dt;
+ dt["fragment"]["ALBEDO"]=SL::TYPE_VEC3;
+
+ Set<String> rm;
+ rm.insert("popo");
+
+ Error err = sl.compile(code,dt,rm);
+
+ if (err) {
+
+ print_line("Error at line: "+rtos(sl.get_error_line())+": "+sl.get_error_text());
+ return NULL;
+ } else {
+ String code;
+ recreate_code(&code,sl.get_shader());
+ print_line("code:\n\n"+code);
+ }
+
+ return NULL;
+}
+
+
+}
diff --git a/main/tests/test_shader_lang.h b/main/tests/test_shader_lang.h
new file mode 100644
index 0000000000..f129fb224a
--- /dev/null
+++ b/main/tests/test_shader_lang.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* test_shader_lang.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_SHADER_LANG_H
+#define TEST_SHADER_LANG_H
+
+#include "os/main_loop.h"
+
+namespace TestShaderLang {
+
+MainLoop* test();
+
+}
+
+#endif // TEST_SHADER_LANG_H
diff --git a/main/tests/test_sound.cpp b/main/tests/test_sound.cpp
new file mode 100644
index 0000000000..44cc117e02
--- /dev/null
+++ b/main/tests/test_sound.cpp
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* test_sound.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "test_sound.h"
+#include "servers/visual_server.h"
+#include "os/main_loop.h"
+#include "math_funcs.h"
+#include "scene/resources/sample.h"
+#include "io/resource_loader.h"
+#include "print_string.h"
+#include "servers/audio_server.h"
+#include "os/os.h"
+namespace TestSound {
+
+
+class TestMainLoop : public MainLoop {
+
+ bool quit;
+ Ref<Sample> sample;
+
+public:
+ virtual void input_event(const InputEvent& p_event) {
+
+
+ }
+ virtual void request_quit() {
+
+ quit=true;
+ }
+
+ virtual void init() {
+
+ List<String> cmdline = OS::get_singleton()->get_cmdline_args();
+ quit=false;
+ if (cmdline.size()) {
+
+ sample=ResourceLoader::load(cmdline.back()->get());
+ ERR_FAIL_COND(sample.is_null());
+ print_line("Sample loaded OK");
+ }
+
+ RID voice = AudioServer::get_singleton()->voice_create();
+ AudioServer::get_singleton()->voice_play( voice, sample->get_rid() );
+
+
+ }
+
+ virtual bool idle(float p_time) {
+ return false;
+ }
+
+
+ virtual bool iteration(float p_time) {
+
+ return quit;
+ }
+ virtual void finish() {
+
+ }
+
+};
+
+
+MainLoop* test() {
+
+ return memnew( TestMainLoop );
+
+}
+
+}
diff --git a/main/tests/test_sound.h b/main/tests/test_sound.h
new file mode 100644
index 0000000000..91b87a2261
--- /dev/null
+++ b/main/tests/test_sound.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* test_sound.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_SOUND_H
+#define TEST_SOUND_H
+
+#include "os/main_loop.h"
+
+namespace TestSound {
+
+MainLoop* test();
+
+}
+
+#endif // TEST_SOUND_H
diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp
new file mode 100644
index 0000000000..a4a8ceb072
--- /dev/null
+++ b/main/tests/test_string.cpp
@@ -0,0 +1,959 @@
+/*************************************************************************/
+/* test_string.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "ustring.h"
+#include <wchar.h>
+//#include "math_funcs.h"
+#include <stdio.h>
+#include "os/os.h"
+#include "core/io/ip_address.h"
+
+#include "test_string.h"
+
+namespace TestString {
+
+bool test_1() {
+
+ OS::get_singleton()->print("\n\nTest 1: Assign from cstr\n");
+
+ String s = "Hello";
+
+ OS::get_singleton()->print("\tExpected: Hello\n");
+ OS::get_singleton()->print("\tResulted: %ls\n",s.c_str());
+
+ return (wcscmp(s.c_str(),L"Hello")==0);
+
+}
+
+bool test_2() {
+
+ OS::get_singleton()->print("\n\nTest 2: Assign from string (operator=)\n");
+
+ String s = "Dolly";
+ String t = s;
+
+ OS::get_singleton()->print("\tExpected: Dolly\n");
+ OS::get_singleton()->print("\tResulted: %ls\n",t.c_str());
+
+ return (wcscmp(t.c_str(),L"Dolly")==0);
+
+}
+
+bool test_3() {
+
+ OS::get_singleton()->print("\n\nTest 3: Assign from c-string (copycon)\n");
+
+ String s("Sheep");
+ String t(s);
+
+ OS::get_singleton()->print("\tExpected: Sheep\n");
+ OS::get_singleton()->print("\tResulted: %ls\n",t.c_str());
+
+ return (wcscmp(t.c_str(),L"Sheep")==0);
+
+}
+
+bool test_4() {
+
+ OS::get_singleton()->print("\n\nTest 4: Assign from c-widechar (operator=)\n");
+
+ String s(L"Give me");
+
+ OS::get_singleton()->print("\tExpected: Give me\n");
+ OS::get_singleton()->print("\tResulted: %ls\n",s.c_str());
+
+ return (wcscmp(s.c_str(),L"Give me")==0);
+
+}
+
+bool test_5() {
+
+ OS::get_singleton()->print("\n\nTest 5: Assign from c-widechar (copycon)\n");
+
+ String s(L"Wool");
+
+ OS::get_singleton()->print("\tExpected: Wool\n");
+ OS::get_singleton()->print("\tResulted: %ls\n",s.c_str());
+
+ return (wcscmp(s.c_str(),L"Wool")==0);
+
+}
+
+bool test_6() {
+
+ OS::get_singleton()->print("\n\nTest 6: comparisons (equal)\n");
+
+
+ String s="Test Compare";
+
+ OS::get_singleton()->print("\tComparing to \"Test Compare\"\n");
+
+ if (! ( s=="Test Compare" ) )
+ return false;
+
+ if (! ( s==L"Test Compare" ) )
+ return false;
+
+ if (! ( s==String("Test Compare") ) )
+ return false;
+
+ return true;
+
+}
+
+bool test_7() {
+
+ OS::get_singleton()->print("\n\nTest 7: comparisons (unequal)\n");
+
+
+ String s="Test Compare";
+
+ OS::get_singleton()->print("\tComparing to \"Test Compare\"\n");
+
+ if (! ( s!="Peanut" ) )
+ return false;
+
+ if (! ( s!=L"Coconut" ) )
+ return false;
+
+ if (! ( s!=String("Butter") ) )
+ return false;
+
+ return true;
+
+}
+
+bool test_8() {
+
+ OS::get_singleton()->print("\n\nTest 8: comparisons (operator<)\n");
+
+
+ String s="Bees";
+
+ OS::get_singleton()->print("\tComparing to \"Bees\"\n");
+
+ if ( ! (s < "Elephant") )
+ return false;
+
+ if ( s < L"Amber" )
+ return false;
+
+ if ( s < String("Beatrix") )
+ return false;
+
+ return true;
+
+}
+
+bool test_9() {
+
+ OS::get_singleton()->print("\n\nTest 9: Concatenation\n");
+
+
+ String s;
+
+ s+="Have";
+ s+=' ';
+ s+='a';
+ s+=String(" ");
+ s = s + L"Nice";
+ s = s + " ";
+ s = s + String("Day");
+
+ OS::get_singleton()->print("\tComparing to \"Have a Nice Day\"\n");
+
+ return (s == "Have a Nice Day");
+
+}
+
+bool test_10() {
+
+ OS::get_singleton()->print("\n\nTest 10: Misc funcs (size/length/empty/etc)\n");
+
+ if (! String("").empty())
+ return false;
+
+ if (String("Mellon").size() != 7)
+ return false;
+
+ if (String("Oranges").length() != 7)
+ return false;
+
+ return true;
+
+}
+
+
+bool test_11() {
+
+ OS::get_singleton()->print("\n\nTest 11: Operator[]\n");
+
+ String a="Kugar Sane";
+
+ a[0]='S';
+ a[6]='C';
+
+ if (a != "Sugar Cane")
+ return false;
+
+ if (a[1]!='u')
+ return false;
+
+ return true;
+
+}
+
+bool test_12() {
+
+ OS::get_singleton()->print("\n\nTest 12: case functions\n");
+
+
+ String a="MoMoNgA";
+
+ if (a.to_upper() != "MOMONGA")
+ return false;
+
+ if (a.nocasecmp_to("momonga")!=0)
+ return false;
+
+ return true;
+
+}
+
+bool test_13() {
+
+ OS::get_singleton()->print("\n\nTest 13: UTF8\n");
+
+ /* how can i embed UTF in here? */
+
+ static const CharType ustr[] = { 0x304A , 0x360F, 0x3088, 0x3046, 0 };
+ //static const wchar_t ustr[] = { 'P', 0xCE, 'p',0xD3, 0 };
+ String s=ustr;
+
+ OS::get_singleton()->print("\tUnicode: %ls\n",ustr);
+ s.parse_utf8( s.utf8().get_data() );
+ OS::get_singleton()->print("\tConvert/Parse UTF8: %ls\n",s.c_str());
+
+ return (s==ustr);
+
+}
+
+bool test_14() {
+
+ OS::get_singleton()->print("\n\nTest 14: ASCII\n");
+
+ String s = L"Primero Leche";
+ OS::get_singleton()->print("\tAscii: %s\n",s.ascii().get_data());
+
+ String t=s.ascii().get_data();
+ return (s==t);
+
+}
+
+bool test_15() {
+
+ OS::get_singleton()->print("\n\nTest 15: substr\n");
+
+ String s="Killer Baby";
+ OS::get_singleton()->print("\tsubstr(3,4) of \"%ls\" is \"%ls\"\n",s.c_str(),s.substr(3,4).c_str());
+
+ return (s.substr(3,4)=="ler ");
+
+}
+
+bool test_16() {
+
+ OS::get_singleton()->print("\n\nTest 16: find\n");
+
+ String s="Pretty Woman";
+ OS::get_singleton()->print("\tString: %ls\n",s.c_str());
+ OS::get_singleton()->print("\t\"tty\" is at %i pos.\n",s.find("tty"));
+ OS::get_singleton()->print("\t\"Revenge of the Monster Truck\" is at %i pos.\n",s.find("Revenge of the Monster Truck"));
+
+ if (s.find("tty")!=3)
+ return false;
+
+ if (s.find("Revenge of the Monster Truck")!=-1)
+ return false;
+
+ return true;
+
+}
+
+bool test_17() {
+
+ OS::get_singleton()->print("\n\nTest 17: find no case\n");
+
+ String s="Pretty Whale";
+ OS::get_singleton()->print("\tString: %ls\n",s.c_str());
+ OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n",s.findn("WHA"));
+ OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n",s.findn("Revenge of the Monster Truck"));
+
+ if (s.findn("WHA")!=7)
+ return false;
+
+ if (s.findn("Revenge of the Monster SawFish")!=-1)
+ return false;
+
+ return true;
+
+}
+
+bool test_18() {
+
+ OS::get_singleton()->print("\n\nTest 18: find no case\n");
+
+ String s="Pretty Whale";
+ OS::get_singleton()->print("\tString: %ls\n",s.c_str());
+ OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n",s.findn("WHA"));
+ OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n",s.findn("Revenge of the Monster Truck"));
+
+ if (s.findn("WHA")!=7)
+ return false;
+
+ if (s.findn("Revenge of the Monster SawFish")!=-1)
+ return false;
+
+ return true;
+
+}
+
+bool test_19() {
+
+ OS::get_singleton()->print("\n\nTest 19: Search & replace\n");
+
+ String s="Happy Birthday, Anna!";
+ OS::get_singleton()->print("\tString: %ls\n",s.c_str());
+
+ s=s.replace("Birthday","Halloween");
+ OS::get_singleton()->print("\tReplaced Birthday/Halloween: %ls.\n",s.c_str());
+
+ return (s=="Happy Halloween, Anna!");
+
+}
+
+bool test_20() {
+
+ OS::get_singleton()->print("\n\nTest 20: Insertion\n");
+
+ String s="Who is Frederic?";
+
+ OS::get_singleton()->print("\tString: %ls\n",s.c_str());
+ s=s.insert( s.find("?")," Chopin" );
+ OS::get_singleton()->print("\tInserted Chopin: %ls.\n",s.c_str());
+
+ return (s=="Who is Frederic Chopin?");
+
+}
+
+bool test_21() {
+
+ OS::get_singleton()->print("\n\nTest 21: Number -> String\n");
+
+ OS::get_singleton()->print("\tPi is %f\n",33.141593);
+ OS::get_singleton()->print("\tPi String is %ls\n",String::num(3.141593).c_str());
+
+ return String::num(3.141593)=="3.141593";
+
+}
+
+bool test_22() {
+
+ OS::get_singleton()->print("\n\nTest 22: String -> Int\n");
+
+ static const char* nums[4]={ "1237461283", "- 22", "0", " - 1123412" };
+ static const int num[4]={ 1237461283, -22, 0, -1123412 };
+
+ for (int i=0;i<4;i++) {
+ OS::get_singleton()->print("\tString: \"%s\" as Int is %i\n",nums[i],String(nums[i]).to_int());
+
+ if (String(nums[i]).to_int()!=num[i])
+ return false;
+ }
+
+ return true;
+
+}
+
+bool test_23() {
+
+ OS::get_singleton()->print("\n\nTest 23: String -> Float\n");
+
+ static const char* nums[4]={ "-12348298412.2", "0.05", "2.0002", " -0.0001" };
+ static const double num[4]={ -12348298412.2, 0.05, 2.0002, -0.0001 };
+
+ for (int i=0;i<4;i++) {
+ OS::get_singleton()->print("\tString: \"%s\" as Float is %f\n",nums[i],String(nums[i]).to_double());
+
+ if ( ABS(String(nums[i]).to_double()-num[i])>0.00001)
+ return false;
+ }
+
+ return true;
+
+}
+
+
+bool test_24() {
+
+ OS::get_singleton()->print("\n\nTest 24: Slicing\n");
+
+ String s="Mars,Jupiter,Saturn,Uranus";
+
+ const char*slices[4]={"Mars","Jupiter","Saturn","Uranus"};
+
+ OS::get_singleton()->print("\tSlicing \"%ls\" by \"%s\"..\n",s.c_str(),",");
+
+ for (int i=0;i<s.get_slice_count(",");i++) {
+
+ OS::get_singleton()->print("\t\t%i- %ls\n",i+1,s.get_slice(",",i).c_str());
+
+
+ if (s.get_slice(",",i)!=slices[i])
+ return false;
+ }
+
+ return true;
+
+}
+
+bool test_25() {
+
+ OS::get_singleton()->print("\n\nTest 25: Erasing\n");
+
+ String s="Josephine is such a cute girl!";
+
+ OS::get_singleton()->print("\tString: %ls\n",s.c_str());
+ OS::get_singleton()->print("\tRemoving \"cute\"\n");
+
+ s.erase(s.find("cute "),String("cute ").length());
+ OS::get_singleton()->print("\tResult: %ls\n",s.c_str());
+
+
+ return (s=="Josephine is such a girl!");
+
+}
+
+bool test_26() {
+
+ //TODO: Do replacement RegEx test
+ return true;
+};
+
+struct test_27_data {
+ char const * data;
+ char const * begin;
+ bool expected;
+};
+
+bool test_27() {
+
+ OS::get_singleton()->print("\n\nTest 27: begins_with\n");
+ test_27_data tc[] = {
+ {"res://foobar", "res://", true},
+ {"res", "res://", false},
+ {"abc", "abc", true}
+ };
+ size_t count = sizeof(tc) / sizeof(tc[0]);
+ bool state = true;
+ for (size_t i = 0;state && i < count; ++i) {
+ String s = tc[i].data;
+ state = s.begins_with(tc[i].begin) == tc[i].expected;
+ if (state) {
+ String sb = tc[i].begin;
+ state = s.begins_with(sb) == tc[i].expected;
+ }
+ if (!state) {
+ OS::get_singleton()->print("\n\t Failure on:\n\t\tstring: ", tc[i].data, "\n\t\tbegin: ", tc[i].begin, "\n\t\texpected: ", tc[i].expected ? "true" : "false", "\n");
+ break;
+ }
+ };
+ return state;
+};
+
+
+bool test_28() {
+
+ OS::get_singleton()->print("\n\nTest 28: sprintf\n");
+
+ bool success, state = true;
+ char output_format[] = "\tTest:\t%ls => %ls (%s)\n";
+ String format, output;
+ Array args;
+ bool error;
+
+ // %%
+ format = "fish %% frog";
+ args.clear();
+ output = format.sprintf(args, &error);
+ success = (output == String("fish % frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ //////// INTS
+
+ // Int
+ format = "fish %d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int left padded with zeroes.
+ format = "fish %05d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 00005 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int left padded with spaces.
+ format = "fish %5d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int right padded with spaces.
+ format = "fish %-5d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int with sign (positive).
+ format = "fish %+d frog";
+ args.clear();
+ args.push_back(5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish +5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Negative int.
+ format = "fish %d frog";
+ args.clear();
+ args.push_back(-5);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish -5 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Hex (lower)
+ format = "fish %x frog";
+ args.clear();
+ args.push_back(45);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 2d frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Hex (upper)
+ format = "fish %X frog";
+ args.clear();
+ args.push_back(45);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 2D frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Octal
+ format = "fish %o frog";
+ args.clear();
+ args.push_back(99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 143 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ////// REALS
+
+ // Real
+ format = "fish %f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real left-padded
+ format = "fish %11f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real right-padded
+ format = "fish %-11f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real given int.
+ format = "fish %f frog";
+ args.clear();
+ args.push_back(99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.000000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with sign (positive).
+ format = "fish %+f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish +99.990000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with 1 decimals.
+ format = "fish %.1f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 100.0 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with 12 decimals.
+ format = "fish %.12f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990000000000 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Real with no decimals.
+ format = "fish %.f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 100 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ /////// Strings.
+
+ // String
+ format = "fish %s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // String left-padded
+ format = "fish %10s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // String right-padded
+ format = "fish %-10s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ///// Characters
+
+ // Character as string.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back("A");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish A frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Character as int.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back(65);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish A frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ///// Dynamic width
+
+ // String dynamic width
+ format = "fish %*s frog";
+ args.clear();
+ args.push_back(10);
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == String("fish cheese frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Int dynamic width
+ format = "fish %*d frog";
+ args.clear();
+ args.push_back(10);
+ args.push_back(99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Float dynamic width
+ format = "fish %*.*f frog";
+ args.clear();
+ args.push_back(10);
+ args.push_back(3);
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == String("fish 99.990 frog") && !error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ///// Errors
+
+ // More formats than arguments.
+ format = "fish %s %s frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "not enough arguments for format string" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // More arguments than formats.
+ format = "fish %s frog";
+ args.clear();
+ args.push_back("hello");
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "not all arguments converted during string formatting" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Incomplete format.
+ format = "fish %10";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "incomplete format" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Bad character in format string
+ format = "fish %&f frog";
+ args.clear();
+ args.push_back("cheese");
+ output = format.sprintf(args, &error);
+ success = (output == "unsupported format character" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Too many decimals.
+ format = "fish %2.2.2f frog";
+ args.clear();
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == "too many decimal points in format" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // * not a number
+ format = "fish %*f frog";
+ args.clear();
+ args.push_back("cheese");
+ args.push_back(99.99);
+ output = format.sprintf(args, &error);
+ success = (output == "* wants number" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Character too long.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back("sc");
+ output = format.sprintf(args, &error);
+ success = (output == "%c requires number or single-character string" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ // Character bad type.
+ format = "fish %c frog";
+ args.clear();
+ args.push_back(Array());
+ output = format.sprintf(args, &error);
+ success = (output == "%c requires number or single-character string" && error);
+ OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ return state;
+}
+
+bool test_29() {
+
+ bool error = false;
+ bool state = true;
+ bool success = false;
+
+ IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ OS::get_singleton()->print("ip0 is %ls\n", String(ip0).c_str());
+
+ IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
+ OS::get_singleton()->print("ip6 is %ls\n", String(ip).c_str());
+
+ IP_Address ip2("fe80::52e5:49ff:fe93:1baf");
+ OS::get_singleton()->print("ip6 is %ls\n", String(ip2).c_str());
+
+ IP_Address ip3("::ffff:192.168.0.1");
+ OS::get_singleton()->print("ip6 is %ls\n", String(ip3).c_str());
+
+ String ip4 = "192.168.0.1";
+ success = ip4.is_valid_ip_address();
+ OS::get_singleton()->print("Is valid ipv4: %ls, %s\n", ip4.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ip4 = "192.368.0.1";
+ success = (!ip4.is_valid_ip_address());
+ OS::get_singleton()->print("Is invalid ipv4: %ls, %s\n", ip4.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ String ip6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
+ success = ip6.is_valid_ip_address();
+ OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ip6 = "2001:0db8:85j3:0000:0000:8a2e:0370:7334";
+ success = (!ip6.is_valid_ip_address());
+ OS::get_singleton()->print("Is invalid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ip6 = "2001:0db8:85f345:0000:0000:8a2e:0370:7334";
+ success = (!ip6.is_valid_ip_address());
+ OS::get_singleton()->print("Is invalid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ip6 = "2001:0db8::0:8a2e:370:7334";
+ success = (ip6.is_valid_ip_address());
+ OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ ip6 = "::ffff:192.168.0.1";
+ success = (ip6.is_valid_ip_address());
+ OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
+ if (!success) state = false;
+
+ return state;
+};
+
+typedef bool (*TestFunc)(void);
+
+TestFunc test_funcs[] = {
+
+ test_1,
+ test_2,
+ test_3,
+ test_4,
+ test_5,
+ test_6,
+ test_7,
+ test_8,
+ test_9,
+ test_10,
+ test_11,
+ test_12,
+ test_13,
+ test_14,
+ test_15,
+ test_16,
+ test_17,
+ test_18,
+ test_19,
+ test_20,
+ test_21,
+ test_22,
+ test_23,
+ test_24,
+ test_25,
+ test_26,
+ test_27,
+ test_28,
+ test_29,
+ 0
+
+};
+
+MainLoop* test() {
+
+ /** A character length != wchar_t may be forced, so the tests wont work */
+
+ ERR_FAIL_COND_V( sizeof(CharType) != sizeof(wchar_t), NULL );
+
+ int count=0;
+ int passed=0;
+
+ while(true) {
+ if (!test_funcs[count])
+ break;
+ bool pass=test_funcs[count]();
+ if (pass)
+ passed++;
+ OS::get_singleton()->print("\t%s\n",pass?"PASS":"FAILED");
+
+ count++;
+ }
+
+ OS::get_singleton()->print("\n\n\n");
+ OS::get_singleton()->print("*************\n");
+ OS::get_singleton()->print("***TOTALS!***\n");
+ OS::get_singleton()->print("*************\n");
+
+ OS::get_singleton()->print("Passed %i of %i tests\n", passed, count);
+
+ return NULL;
+}
+
+}
diff --git a/main/tests/test_string.h b/main/tests/test_string.h
new file mode 100644
index 0000000000..7b3cd9a019
--- /dev/null
+++ b/main/tests/test_string.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* test_string.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef TEST_STRING_H
+#define TEST_STRING_H
+
+#include "ustring.h"
+#include "os/main_loop.h"
+
+namespace TestString {
+
+MainLoop* test();
+
+}
+
+
+#endif
+
+