summaryrefslogtreecommitdiff
path: root/main/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'main/main.cpp')
-rw-r--r--main/main.cpp303
1 files changed, 160 insertions, 143 deletions
diff --git a/main/main.cpp b/main/main.cpp
index 3542133719..2fd9cfa734 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -82,6 +82,8 @@
#include "version.h"
#include "version_hash.gen.h"
+#include "main/timer_sync.h"
+
static ProjectSettings *globals = NULL;
static Engine *engine = NULL;
static InputMap *input_map = NULL;
@@ -261,9 +263,10 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print("Standalone tools:\n");
OS::get_singleton()->print(" -s, --script <script> Run a script.\n");
+ OS::get_singleton()->print(" --check-only Only parse for errors and quit (use with --script).\n");
#ifdef TOOLS_ENABLED
- OS::get_singleton()->print(" --export <target> Export the project using the given export target.\n");
- OS::get_singleton()->print(" --export-debug Use together with --export, enables debug mode for the template.\n");
+ OS::get_singleton()->print(" --export <target> Export the project using the given export target. Export only main pack if path ends with .pck or .zip.\n");
+ OS::get_singleton()->print(" --export-debug <target> Like --export, but use debug template.\n");
OS::get_singleton()->print(" --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects).\n");
@@ -337,7 +340,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
String video_driver = "";
String audio_driver = "";
- String game_path = ".";
+ String project_path = ".";
bool upwards = false;
String debug_mode;
String debug_host;
@@ -536,6 +539,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--build-solutions") { // Build the scripting solution such C#
auto_build_solutions = true;
+ editor = true;
#endif
} else if (I->get() == "--no-window") { // disable window creation, Windows only
@@ -553,7 +557,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (OS::get_singleton()->set_cwd(p) == OK) {
//nothing
} else {
- game_path = I->next()->get(); //use game_path instead
+ project_path = I->next()->get(); //use project_path instead
}
N = I->next()->next();
} else {
@@ -576,7 +580,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (OS::get_singleton()->set_cwd(path) == OK) {
// path already specified, don't override
} else {
- game_path = path;
+ project_path = path;
}
#ifdef TOOLS_ENABLED
editor = true;
@@ -672,35 +676,20 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--disable-crash-handler") {
OS::get_singleton()->disable_crash_handler();
} else {
-
- //test for game path
- bool gpfound = false;
-
- if (!I->get().begins_with("-") && game_path == "") {
- DirAccess *da = DirAccess::open(I->get());
- if (da != NULL) {
- game_path = I->get();
- gpfound = true;
- memdelete(da);
- }
- }
-
- if (!gpfound) {
- main_args.push_back(I->get());
- }
+ main_args.push_back(I->get());
}
I = N;
}
- if (globals->setup(game_path, main_pack, upwards) == OK) {
+ if (globals->setup(project_path, main_pack, upwards) == OK) {
found_project = true;
} else {
#ifdef TOOLS_ENABLED
editor = false;
#else
- OS::get_singleton()->print("Error: Could not load game path '%s'.\n", game_path.ascii().get_data());
+ OS::get_singleton()->print("Error: Could not load game path '%s'.\n", project_path.ascii().get_data());
goto error;
#endif
@@ -726,10 +715,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
memdelete(sdr);
} else {
script_debugger = sdr;
+ sdr->set_allow_focus_steal_pid(allow_focus_steal_pid);
}
} else if (debug_mode == "local") {
script_debugger = memnew(ScriptDebuggerLocal);
+ OS::get_singleton()->initialize_debugging();
}
FileAccessNetwork::configure();
@@ -834,7 +825,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->set_cmdline(execpath, main_args);
GLOBAL_DEF("rendering/quality/driver/driver_name", "GLES3");
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_name", PropertyInfo(Variant::STRING, "rendering/quality/driver/driver_name", PROPERTY_HINT_ENUM, "GLES3,GLES2"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/driver/driver_name", PropertyInfo(Variant::STRING, "rendering/quality/driver/driver_name", PROPERTY_HINT_ENUM, "GLES2,GLES3"));
if (video_driver == "") {
video_driver = GLOBAL_GET("rendering/quality/driver/driver_name");
}
@@ -874,7 +865,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
}
+ OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/allow_per_pixel_transparency", false);
+
video_mode.use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true);
+ OS::get_singleton()->_use_vsync = video_mode.use_vsync;
+
+ video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency", false);
+ video_mode.layered_splash = GLOBAL_DEF("display/window/per_pixel_transparency_splash", false);
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2);
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3);
@@ -882,6 +879,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (editor || project_manager) {
// The editor and project manager always detect and use hiDPI if needed
OS::get_singleton()->_allow_hidpi = true;
+ OS::get_singleton()->_allow_layered = false;
}
Engine::get_singleton()->_pixel_snap = GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false);
@@ -916,7 +914,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (audio_driver == "") { // specified in project.godot
- audio_driver = GLOBAL_DEF("audio/driver", OS::get_singleton()->get_audio_driver_name(0));
+ audio_driver = GLOBAL_DEF_RST("audio/driver", OS::get_singleton()->get_audio_driver_name(0));
}
for (int i = 0; i < OS::get_singleton()->get_audio_driver_count(); i++) {
@@ -955,6 +953,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60));
+ Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
@@ -984,7 +983,7 @@ error:
video_driver = "";
audio_driver = "";
- game_path = "";
+ project_path = "";
args.clear();
main_args.clear();
@@ -1141,13 +1140,16 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
GLOBAL_DEF("application/config/icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp"));
- if (bool(GLOBAL_DEF("display/window/handheld/emulate_touchscreen", false))) {
- if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton() && !(editor || project_manager)) {
- //only if no touchscreen ui hint, set emulation
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
- if (id)
- id->set_emulate_touch(true);
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ if (id) {
+ if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
+ if (!OS::get_singleton()->has_touchscreen_ui_hint()) {
+ //only if no touchscreen ui hint, set emulation
+ id->set_emulate_touch_from_mouse(true);
+ }
}
+
+ id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF("input_devices/pointing/emulate_mouse_from_touch", true)));
}
MAIN_PRINT("Main: Load Remaps");
@@ -1178,10 +1180,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#endif
- if (allow_focus_steal_pid) {
- OS::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid);
- }
-
MAIN_PRINT("Main: Load Modules, Physics, Drivers, Scripts");
register_platform_apis();
@@ -1225,6 +1223,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
return OK;
}
+// everything the main loop needs to know about frame timings
+
+static MainTimerSync main_timer_sync;
+
bool Main::start() {
ERR_FAIL_COND_V(!_start_success, false);
@@ -1238,6 +1240,9 @@ bool Main::start() {
String test;
String _export_preset;
bool export_debug = false;
+ bool check_only = false;
+
+ main_timer_sync.init(OS::get_singleton()->get_ticks_usec());
List<String> args = OS::get_singleton()->get_cmdline_args();
for (int i = 0; i < args.size(); i++) {
@@ -1252,6 +1257,8 @@ bool Main::start() {
#endif
} else if (args[i].length() && args[i][0] != '-' && game_path == "") {
game_path = args[i];
+ } else if (args[i] == "--check-only") {
+ check_only = true;
}
//parameters that have an argument to the right
else if (i < (args.size() - 1)) {
@@ -1380,6 +1387,10 @@ bool Main::start() {
ERR_EXPLAIN("Can't load script: " + script);
ERR_FAIL_COND_V(script_res.is_null(), false);
+ if (check_only) {
+ return false;
+ }
+
if (script_res->can_instance() /*&& script_res->inherits_from("SceneTreeScripted")*/) {
StringName instance_type = script_res->get_instance_base_type();
@@ -1441,6 +1452,91 @@ bool Main::start() {
}
#endif
+ if (!project_manager && !editor) { // game
+ if (game_path != "" || script != "") {
+ //autoload
+ List<PropertyInfo> props;
+ ProjectSettings::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()) {
+
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ String name = s.get_slicec('/', 1);
+ String path = ProjectSettings::get_singleton()->get(s);
+ bool global_var = false;
+ if (path.begins_with("*")) {
+ global_var = true;
+ }
+
+ if (global_var) {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(name, Variant());
+ }
+ }
+ }
+
+ //second pass, load into global constants
+ List<Node *> to_add;
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ String name = s.get_slicec('/', 1);
+ String path = ProjectSettings::get_singleton()->get(s);
+ bool global_var = false;
+ if (path.begins_with("*")) {
+ global_var = true;
+ path = path.substr(1, path.length() - 1);
+ }
+
+ RES res = ResourceLoader::load(path);
+ ERR_EXPLAIN("Can't autoload: " + path);
+ ERR_CONTINUE(res.is_null());
+ Node *n = NULL;
+ if (res->is_class("PackedScene")) {
+ Ref<PackedScene> ps = res;
+ n = ps->instance();
+ } else if (res->is_class("Script")) {
+ Ref<Script> s = res;
+ StringName ibt = s->get_instance_base_type();
+ bool valid_type = ClassDB::is_parent_class(ibt, "Node");
+ ERR_EXPLAIN("Script does not inherit a Node: " + path);
+ ERR_CONTINUE(!valid_type);
+
+ Object *obj = ClassDB::instance(ibt);
+
+ ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt));
+ ERR_CONTINUE(obj == NULL);
+
+ n = Object::cast_to<Node>(obj);
+ n->set_script(s.get_ref_ptr());
+ }
+
+ ERR_EXPLAIN("Path in autoload not a node or script: " + path);
+ ERR_CONTINUE(!n);
+ n->set_name(name);
+
+ //defer so references are all valid on _ready()
+ to_add.push_back(n);
+
+ if (global_var) {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(name, n);
+ }
+ }
+ }
+
+ for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) {
+
+ sml->get_root()->add_child(E->get());
+ }
+ }
+ }
+
#ifdef TOOLS_ENABLED
EditorNode *editor_node = NULL;
@@ -1460,9 +1556,6 @@ bool Main::start() {
}
#endif
- {
- }
-
if (!editor && !project_manager) {
//standard helpers that can be changed from main config
@@ -1575,89 +1668,6 @@ bool Main::start() {
}
if (!project_manager && !editor) { // game
- if (game_path != "" || script != "") {
- //autoload
- List<PropertyInfo> props;
- ProjectSettings::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()) {
-
- String s = E->get().name;
- if (!s.begins_with("autoload/"))
- continue;
- String name = s.get_slicec('/', 1);
- String path = ProjectSettings::get_singleton()->get(s);
- bool global_var = false;
- if (path.begins_with("*")) {
- global_var = true;
- }
-
- if (global_var) {
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->add_global_constant(name, Variant());
- }
- }
- }
-
- //second pass, load into global constants
- List<Node *> to_add;
- for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
-
- String s = E->get().name;
- if (!s.begins_with("autoload/"))
- continue;
- String name = s.get_slicec('/', 1);
- String path = ProjectSettings::get_singleton()->get(s);
- bool global_var = false;
- if (path.begins_with("*")) {
- global_var = true;
- path = path.substr(1, path.length() - 1);
- }
-
- RES res = ResourceLoader::load(path);
- ERR_EXPLAIN("Can't autoload: " + path);
- ERR_CONTINUE(res.is_null());
- Node *n = NULL;
- if (res->is_class("PackedScene")) {
- Ref<PackedScene> ps = res;
- n = ps->instance();
- } else if (res->is_class("Script")) {
- Ref<Script> s = res;
- StringName ibt = s->get_instance_base_type();
- bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_EXPLAIN("Script does not inherit a Node: " + path);
- ERR_CONTINUE(!valid_type);
-
- Object *obj = ClassDB::instance(ibt);
-
- ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt));
- ERR_CONTINUE(obj == NULL);
-
- n = Object::cast_to<Node>(obj);
- n->set_script(s.get_ref_ptr());
- }
-
- ERR_EXPLAIN("Path in autoload not a node or script: " + path);
- ERR_CONTINUE(!n);
- n->set_name(name);
-
- //defer so references are all valid on _ready()
- to_add.push_back(n);
-
- if (global_var) {
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->add_global_constant(name, n);
- }
- }
- }
-
- for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) {
-
- sml->get_root()->add_child(E->get());
- }
- }
-
if (game_path != "") {
Node *scene = NULL;
Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path);
@@ -1704,7 +1714,6 @@ bool Main::start() {
uint64_t Main::last_ticks = 0;
uint64_t Main::target_ticks = 0;
-float Main::time_accum = 0;
uint32_t Main::frames = 0;
uint32_t Main::frame = 0;
bool Main::force_redraw_requested = false;
@@ -1717,14 +1726,19 @@ bool Main::iteration() {
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
Engine::get_singleton()->_frame_ticks = ticks;
+ main_timer_sync.set_cpu_ticks_usec(ticks);
+ main_timer_sync.set_fixed_fps(fixed_fps);
uint64_t ticks_elapsed = ticks - last_ticks;
- double step = (double)ticks_elapsed / 1000000.0;
- if (fixed_fps != -1)
- step = 1.0 / fixed_fps;
+ int physics_fps = Engine::get_singleton()->get_iterations_per_second();
+ float frame_slice = 1.0 / physics_fps;
+
+ float time_scale = Engine::get_singleton()->get_time_scale();
- float frame_slice = 1.0 / Engine::get_singleton()->get_iterations_per_second();
+ MainFrameTime advance = main_timer_sync.advance(frame_slice, physics_fps);
+ double step = advance.idle_step;
+ double scaled_step = step * time_scale;
Engine::get_singleton()->_frame_step = step;
@@ -1740,20 +1754,17 @@ bool Main::iteration() {
last_ticks = ticks;
- if (fixed_fps == -1 && step > frame_slice * 8)
- step = frame_slice * 8;
-
- time_accum += step;
-
- float time_scale = Engine::get_singleton()->get_time_scale();
+ static const int max_physics_steps = 8;
+ if (fixed_fps == -1 && advance.physics_steps > max_physics_steps) {
+ step -= (advance.physics_steps - max_physics_steps) * frame_slice;
+ advance.physics_steps = max_physics_steps;
+ }
bool exit = false;
- int iters = 0;
-
Engine::get_singleton()->_in_physics = true;
- while (time_accum > frame_slice) {
+ for (int iters = 0; iters < advance.physics_steps; ++iters) {
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
@@ -1775,12 +1786,10 @@ bool Main::iteration() {
Physics2DServer::get_singleton()->end_sync();
Physics2DServer::get_singleton()->step(frame_slice * time_scale);
- time_accum -= frame_slice;
message_queue->flush();
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference
physics_process_max = MAX(OS::get_singleton()->get_ticks_usec() - physics_begin, physics_process_max);
- iters++;
Engine::get_singleton()->_physics_frames++;
}
@@ -1797,19 +1806,16 @@ 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
+ VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
}
} else {
- VisualServer::get_singleton()->draw(); // flush visual commands
+ VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands
Engine::get_singleton()->frames_drawn++;
force_redraw_requested = false;
}
}
- if (AudioServer::get_singleton())
- AudioServer::get_singleton()->update();
-
idle_process_ticks = OS::get_singleton()->get_ticks_usec() - idle_begin;
idle_process_max = MAX(idle_process_ticks, idle_process_max);
uint64_t frame_time = OS::get_singleton()->get_ticks_usec() - ticks;
@@ -1818,6 +1824,8 @@ bool Main::iteration() {
ScriptServer::get_language(i)->frame();
}
+ AudioServer::get_singleton()->update();
+
if (script_debugger) {
if (script_debugger->is_profiling()) {
script_debugger->profiling_set_frame_times(USEC_TO_SEC(frame_time), USEC_TO_SEC(idle_process_ticks), USEC_TO_SEC(physics_process_ticks), frame_slice);
@@ -1950,6 +1958,15 @@ void Main::cleanup() {
if (engine)
memdelete(engine);
+ if (OS::get_singleton()->is_restart_on_exit_set()) {
+ //attempt to restart with arguments
+ String exec = OS::get_singleton()->get_executable_path();
+ List<String> args = OS::get_singleton()->get_restart_on_exit_arguments();
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+ OS::get_singleton()->set_restart_on_exit(false, List<String>()); //clear list (uses memory)
+ }
+
unregister_core_driver_types();
unregister_core_types();