From e6b5b7c03fa78c6f0604863722f6de52107798b0 Mon Sep 17 00:00:00 2001 From: Arctis Fireblight <6182060+Arctis-Fireblight@users.noreply.github.com> Date: Sun, 28 Jun 2026 10:37:09 -0500 Subject: [PATCH 1/9] Navbar fixes - Increased the size of the nav-bar to accomadate deeper nesting and longer names - Fixed handling of index.md files --- Redot-Documentation/Components/Layout/MainLayout.razor.css | 2 +- Redot-Documentation/Components/Layout/NavMenu.razor.css | 6 +++--- Redot-Documentation/Versioning/Section.cs | 5 +++-- Redot-Documentation/Versioning/VersionProvider.cs | 5 +++++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Redot-Documentation/Components/Layout/MainLayout.razor.css b/Redot-Documentation/Components/Layout/MainLayout.razor.css index 67599a5..f3e9ea7 100644 --- a/Redot-Documentation/Components/Layout/MainLayout.razor.css +++ b/Redot-Documentation/Components/Layout/MainLayout.razor.css @@ -52,7 +52,7 @@ main { } .sidebar { - width: 250px; + width: 350px; height: 100vh; position: sticky; top: 0; diff --git a/Redot-Documentation/Components/Layout/NavMenu.razor.css b/Redot-Documentation/Components/Layout/NavMenu.razor.css index d319781..80a84de 100644 --- a/Redot-Documentation/Components/Layout/NavMenu.razor.css +++ b/Redot-Documentation/Components/Layout/NavMenu.razor.css @@ -1,7 +1,7 @@ .navbar-toggler { appearance: none; cursor: pointer; - width: 3.5rem; + width: 5.5rem; height: 2.5rem; color: white; position: absolute; @@ -99,12 +99,12 @@ } .nav-item ::deep .nav-article-link { - padding-left: calc(0.75rem + var(--section-level, 0) * 1rem); + padding-left: calc(0.5rem + var(--section-level, 0) * 0.25rem); } .nav-item ::deep .nav-section { margin: 0; - padding-left: calc(var(--section-level, 0) * 0.75rem); + padding-left: calc(var(--section-level, 0) * 0.25rem); } .nav-item ::deep .nav-section-summary { diff --git a/Redot-Documentation/Versioning/Section.cs b/Redot-Documentation/Versioning/Section.cs index 640d878..8b56ce1 100644 --- a/Redot-Documentation/Versioning/Section.cs +++ b/Redot-Documentation/Versioning/Section.cs @@ -61,14 +61,15 @@ public void LoadAndParse() excludedItems.Add("img"); excludedItems.Add("video"); } - + if (string.IsNullOrEmpty(Slug)) + Slug = Name.ToLowerInvariant(); FileInfo[] files = directory.GetFiles("*.md"); foreach (FileInfo file in files) { if (excludedItems.Contains(file.Name)) continue; int priority = rankingPriorities.GetValueOrDefault(file.Name, 1024); Article article = new Article(file.Name, FilePath.Combine(Path, file.Name), SlugPrefix + file.Name, priority); - if (article.Name == "index") + if (article.Name == "index" || article.Name == "index.md") { IndexArticle = article; IndexArticle.Name = Name; diff --git a/Redot-Documentation/Versioning/VersionProvider.cs b/Redot-Documentation/Versioning/VersionProvider.cs index ad75f69..a39cf8b 100644 --- a/Redot-Documentation/Versioning/VersionProvider.cs +++ b/Redot-Documentation/Versioning/VersionProvider.cs @@ -8,6 +8,8 @@ public class VersionProvider public Section AboutSection { get; set; } = new("About", "./docs/About/", 0); public Section CommunitySection { get; set; } = new("Community", "./docs/Community/", 1); + + public Section ContributingSection { get; set; } = new("Contributing", "./docs/Contributing/", 2); public Section? VersionedDocsSection { get; set; } = null; @@ -23,6 +25,8 @@ public VersionProvider() AboutSection.SortRankings(); CommunitySection.LoadAndParse(); CommunitySection.SortRankings(); + ContributingSection.LoadAndParse(); + ContributingSection.SortRankings(); } public VersionProvider(string versionName) : this() { @@ -40,6 +44,7 @@ public void SortRankings() _sortedRankings.Clear(); _sortedRankings.Add(AboutSection); _sortedRankings.Add(CommunitySection); + _sortedRankings.Add(ContributingSection); _sortedRankings.Sort(); if (VersionedDocsSection != null) { From 4b3b0f42c697182a33679dbe6bfe9ddca2aad52f Mon Sep 17 00:00:00 2001 From: Arctis Fireblight <6182060+Arctis-Fireblight@users.noreply.github.com> Date: Sun, 28 Jun 2026 11:15:37 -0500 Subject: [PATCH 2/9] Add the Contributing section --- .../best_practices_for_engine_contributors.md | 225 +++++ .../Development/code_style_guidelines.md | 387 +++++++++ .../compiling/compiling_for_android.md | 303 +++++++ .../compiling/compiling_for_ios.md | 99 +++ .../compiling/compiling_for_linuxbsd.md | 664 ++++++++++++++ .../compiling/compiling_for_macos.md | 267 ++++++ .../compiling/compiling_for_web.md | 155 ++++ .../compiling/compiling_for_windows.md | 545 ++++++++++++ .../compiling/compiling_with_dotnet.md | 231 +++++ .../compiling_with_script_encryption_key.md | 113 +++ .../cross-compiling_for_ios_on_linux.md | 125 +++ .../Development/compiling/getting_source.md | 66 ++ .../introduction_to_the_buildsystem.md | 507 +++++++++++ .../compiling/optimizing_for_size.md | 323 +++++++ .../configuring_an_ide/android_studio.md | 103 +++ .../Development/configuring_an_ide/clion.md | 94 ++ .../configuring_an_ide/code_blocks.md | 122 +++ .../configuring_an_ide/kdevelop.md | 82 ++ .../configuring_an_ide/qt_creator.md | 110 +++ .../Development/configuring_an_ide/rider.md | 99 +++ .../configuring_an_ide/visual_studio.md | 73 ++ .../configuring_an_ide/visual_studio_code.md | 270 ++++++ .../Development/configuring_an_ide/xcode.md | 107 +++ .../core_and_modules/2d_coordinate_systems.md | 138 +++ .../binding_to_external_libraries.md | 238 +++++ .../common_engine_methods_and_macros.md | 267 ++++++ .../core_and_modules/core_types.md | 195 +++++ .../core_and_modules/custom_audiostreams.md | 338 ++++++++ .../core_and_modules/custom_godot_servers.md | 496 +++++++++++ .../core_and_modules/custom_modules_in_cpp.md | 752 ++++++++++++++++ .../core_and_modules/custom_platform_ports.md | 189 ++++ .../custom_resource_format_loaders.md | 364 ++++++++ .../core_and_modules/files/class_tree.zip | Bin 0 -> 55874 bytes .../godot_architecture_diagram.md | 8 + .../inheritance_class_tree.md | 23 + .../internal_rendering_architecture.md | 815 ++++++++++++++++++ .../core_and_modules/object_class.md | 328 +++++++ .../core_and_modules/scripting_development.md | 31 + .../core_and_modules/unit_testing.md | 456 ++++++++++ .../core_and_modules/variant_class.md | 109 +++ .../Development/cpp_usage_guidelines.md | 77 ++ .../Development/debugging/macos_debug.md | 45 + .../debugging/using_cpp_profilers.md | 160 ++++ .../Development/debugging/using_sanitizers.md | 205 +++++ .../vulkan/vulkan_validation_layers.md | 185 ++++ .../Development/editor/creating_icons.md | 84 ++ .../Development/editor/editor_style_guide.md | 92 ++ .../introduction_to_editor_development.md | 84 ++ .../file_formats/gdscript_grammar.md | 158 ++++ .../Development/file_formats/tscn.md | 516 +++++++++++ .../handling_compatibility_breakages.md | 141 +++ .../Documentation/building_the_manual.md | 202 +++++ .../Documentation/class_reference_primer.md | 329 +++++++ .../Documentation/content_guidelines.md | 95 ++ .../contributing_to_the_documentation.md | 215 +++++ .../Documentation/docs_image_guidelines.md | 250 ++++++ .../Documentation/docs_writing_guidelines.md | 748 ++++++++++++++++ .../editor_and_docs_localization.md | 12 + .../updating_the_class_reference.md | 118 +++ .../Workflow/bisecting_regressions.md | 206 +++++ .../Workflow/bug_triage_guidelines.md | 219 +++++ .../docs/Contributing/Workflow/first_steps.md | 127 +++ .../Workflow/pr_review_guidelines.md | 423 +++++++++ .../docs/Contributing/Workflow/pr_workflow.md | 603 +++++++++++++ .../Workflow/testing_pull_requests.md | 132 +++ .../docs/Contributing/how_to_contribute.md | 48 ++ .../Development/Compiling/andtemplates.png | Bin 0 -> 27584 bytes .../Development/Compiling/encryption_key.png | Bin 0 -> 55933 bytes .../Development/Compiling/lintemplates.png | Bin 0 -> 22519 bytes .../Development/Compiling/wintemplates.webp | Bin 0 -> 56184 bytes .../cpp_profiler_hotspot_flame_graph.png | Bin 0 -> 187939 bytes .../Debugging/cpp_profiler_hotspot_record.png | Bin 0 -> 41557 bytes .../cpp_profiler_hotspot_view_results.png | Bin 0 -> 50039 bytes .../cpp_profiler_hotspot_welcome.png | Bin 0 -> 52898 bytes .../Debugging/cpp_profiler_time_profiler.png | Bin 0 -> 35249 bytes .../cpp_profiler_time_profiler_record.png | Bin 0 -> 12357 bytes .../cpp_profiler_time_profiler_result.png | Bin 0 -> 88386 bytes ...p_profiler_verysleepy_results_filtered.png | Bin 0 -> 40992 bytes ...cpp_profiler_verysleepy_select_process.png | Bin 0 -> 19945 bytes .../Debugging/cpp_profiler_xcode_menu.png | Bin 0 -> 70685 bytes .../Development/best_practices1.png | Bin 0 -> 18342 bytes .../Development/best_practices2.png | Bin 0 -> 21580 bytes .../Development/best_practices3.png | Bin 0 -> 34845 bytes .../Development/best_practices4.png | Bin 0 -> 22748 bytes .../Development/best_practices5.png | Bin 0 -> 37992 bytes .../Development/best_practices6.png | Bin 0 -> 56157 bytes .../Development/best_practices7.png | Bin 0 -> 81191 bytes .../Development/best_practices8.png | Bin 0 -> 41884 bytes .../android_studio_app_build_variant.webp | Bin 0 -> 13322 bytes ...d_studio_app_configurations_drop_down.webp | Bin 0 -> 62808 bytes .../android_studio_app_debug_type_setup.webp | Bin 0 -> 34860 bytes .../android_studio_editor_build_variant.webp | Bin 0 -> 30180 bytes ...tudio_editor_configurations_drop_down.webp | Bin 0 -> 64080 bytes ...ndroid_studio_editor_debug_type_setup.webp | Bin 0 -> 33422 bytes .../android_studio_setup_project_1.png | Bin 0 -> 6181 bytes .../clion-add-configuration.png | Bin 0 -> 11447 bytes .../clion-add-custom-build-application.png | Bin 0 -> 348701 bytes .../configuring_an_ide/clion-build-run.png | Bin 0 -> 13609 bytes .../clion-create-build-tool.webp | Bin 0 -> 62894 bytes .../clion-create-clean-tool.png | Bin 0 -> 280376 bytes .../clion-external-tools.png | Bin 0 -> 308037 bytes .../configuring_an_ide/clion-preferences.png | Bin 0 -> 596518 bytes .../clion-run-configuration.png | Bin 0 -> 601643 bytes .../configuring_an_ide/clion-select-tools.png | Bin 0 -> 625427 bytes .../configuring_an_ide/clion-target.png | Bin 0 -> 619529 bytes .../code_block_use_tab_character.png | Bin 0 -> 110427 bytes .../code_blocks_add_files_recursively.png | Bin 0 -> 61469 bytes .../code_blocks_build_targets.png | Bin 0 -> 60764 bytes ...code_blocks_compiler_and_configuration.png | Bin 0 -> 50652 bytes .../code_blocks_file_new_project.png | Bin 0 -> 163807 bytes .../code_blocks_new_empty_project.png | Bin 0 -> 52938 bytes .../code_blocks_open_build_options.png | Bin 0 -> 61632 bytes .../code_blocks_open_properties.png | Bin 0 -> 61542 bytes .../code_blocks_project_properties.png | Bin 0 -> 70956 bytes ...code_blocks_project_title_and_location.png | Bin 0 -> 38886 bytes .../code_blocks_scons_clean.png | Bin 0 -> 31777 bytes .../code_blocks_scons_minimum.png | Bin 0 -> 31371 bytes .../code_blocks_scons_windows.png | Bin 0 -> 7878 bytes .../code_blocks_select_files.png | Bin 0 -> 28381 bytes .../code_blocks_update_editor_settings.png | Bin 0 -> 51692 bytes .../code_blocks_wizard_welcome.png | Bin 0 -> 33081 bytes .../kdevelop_addincludes.png | Bin 0 -> 53633 bytes .../kdevelop_buildconfig.png | Bin 0 -> 40292 bytes .../kdevelop_configlaunches.png | Bin 0 -> 96205 bytes .../kdevelop_configlaunches2.png | Bin 0 -> 54375 bytes .../kdevelop_custombuild.png | Bin 0 -> 18158 bytes .../kdevelop_newproject.png | Bin 0 -> 34628 bytes .../kdevelop_openconfig.png | Bin 0 -> 95364 bytes .../qtcreator-apply-import-filter.png | Bin 0 -> 49479 bytes .../qtcreator-edit-codestyle.png | Bin 0 -> 37176 bytes .../qtcreator-edit-files-menu.png | Bin 0 -> 29029 bytes .../qtcreator-new-project.png | Bin 0 -> 42295 bytes .../qtcreator-options-cpp.png | Bin 0 -> 46883 bytes .../qtcreator-project-name-includes.png | Bin 0 -> 8190 bytes .../qtcreator-projects-build.png | Bin 0 -> 35509 bytes .../qtcreator-run-command.png | Bin 0 -> 18228 bytes .../qtcreator-set-project-path.png | Bin 0 -> 14855 bytes .../qtcreator-set-scons-command.png | Bin 0 -> 16573 bytes .../rider_attach_to_process.webp | Bin 0 -> 168598 bytes .../rider_attach_to_process_dialog.webp | Bin 0 -> 139178 bytes .../rider_configurations.webp | Bin 0 -> 40710 bytes .../rider_configurations_changed.webp | Bin 0 -> 195064 bytes .../configuring_an_ide/rider_run_debug.webp | Bin 0 -> 17498 bytes .../vs_1_install_cpp_package.png | Bin 0 -> 3445 bytes .../vs_2_project_properties.png | Bin 0 -> 9973 bytes .../vs_3_debug_command_line.webp | Bin 0 -> 5292 bytes .../vs_4_debugging_main.png | Bin 0 -> 8999 bytes .../vscode_1_create_launch.json.png | Bin 0 -> 2776 bytes .../vscode_2_launch.json.png | Bin 0 -> 78804 bytes .../vscode_3_tasks.json.png | Bin 0 -> 34486 bytes .../vscode_configure_task.png | Bin 0 -> 5127 bytes .../vscode_create_tasksjson.png | Bin 0 -> 2847 bytes .../vscode_create_tasksjson_others.png | Bin 0 -> 5399 bytes .../vscode_edit_configurations.webp | Bin 0 -> 3544 bytes ...xcode_1_create_external_build_project.webp | Bin 0 -> 32772 bytes ...set_external_build_project_parameters.webp | Bin 0 -> 24496 bytes .../xcode_3_configure_scons.webp | Bin 0 -> 28332 bytes .../xcode_4_add_new_target.webp | Bin 0 -> 50884 bytes .../xcode_5_select_command_line_target.webp | Bin 0 -> 59406 bytes ...e_6_after_add_godot_source_to_project.webp | Bin 0 -> 29026 bytes .../xcode_7_setup_build_post_action.webp | Bin 0 -> 39448 bytes .../xcode_8_setup_run_scheme.webp | Bin 0 -> 27054 bytes .../Development/core_and_modules/Control.webp | Bin 0 -> 20530 bytes .../Development/core_and_modules/Node2D.png | Bin 0 -> 29463 bytes .../Development/core_and_modules/Node2D.webp | Bin 0 -> 22136 bytes .../Development/core_and_modules/Node3D.webp | Bin 0 -> 35230 bytes .../Development/core_and_modules/Object.webp | Bin 0 -> 51630 bytes .../core_and_modules/RefCounted.webp | Bin 0 -> 92110 bytes .../core_and_modules/architecture_diagram.jpg | Bin 0 -> 212500 bytes .../rendering_architecture_diagram.webp | Bin 0 -> 227942 bytes .../core_and_modules/transforms_overview.webp | Bin 0 -> 69462 bytes .../Contributing/Documentation/crop_edit.webp | Bin 0 -> 55286 bytes .../Documentation/crop_pixels.webp | Bin 0 -> 2004 bytes .../Contributing/Documentation/crop_tool.webp | Bin 0 -> 1924 bytes .../Documentation/cropped_image.webp | Bin 0 -> 11322 bytes .../editor-vocabulary-overview.png | Bin 0 -> 61570 bytes .../Documentation/l10n_01_language_list.png | Bin 0 -> 61314 bytes .../Documentation/l10n_02_new_translation.png | Bin 0 -> 9009 bytes .../l10n_03_translation_overview.png | Bin 0 -> 61188 bytes .../l10n_04_translation_interface.png | Bin 0 -> 99077 bytes .../Documentation/l10n_05_search_location.png | Bin 0 -> 47299 bytes .../l10n_06_browse_by_location.png | Bin 0 -> 96503 bytes .../l10n_07_download_po_file.png | Bin 0 -> 17181 bytes .../Documentation/l10n_08_edit_on_github.png | Bin 0 -> 23513 bytes .../Documentation/l10n_09_path_to_image.png | Bin 0 -> 25032 bytes .../Workflow/github_fork_button.png | Bin 0 -> 2824 bytes .../Workflow/github_fork_make_pr.png | Bin 0 -> 5671 bytes .../Contributing/Workflow/github_fork_url.png | Bin 0 -> 2554 bytes .../testing_pull_requests_access_checks.webp | Bin 0 -> 34948 bytes .../testing_pull_requests_access_fork.png | Bin 0 -> 79611 bytes ...esting_pull_requests_checks_artifacts.webp | Bin 0 -> 41778 bytes ...g_pull_requests_checks_artifacts_list.webp | Bin 0 -> 14290 bytes ...g_pull_requests_command_line_checkout.webp | Bin 0 -> 21004 bytes .../testing_pull_requests_fork_zip.png | Bin 0 -> 213992 bytes .../testing_pull_requests_nightly_link.png | Bin 0 -> 67037 bytes 195 files changed, 15291 insertions(+) create mode 100644 Redot-Documentation/docs/Contributing/Development/best_practices_for_engine_contributors.md create mode 100644 Redot-Documentation/docs/Contributing/Development/code_style_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_android.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_ios.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_linuxbsd.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_macos.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_web.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_windows.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_dotnet.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_script_encryption_key.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/cross-compiling_for_ios_on_linux.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/getting_source.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/introduction_to_the_buildsystem.md create mode 100644 Redot-Documentation/docs/Contributing/Development/compiling/optimizing_for_size.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/android_studio.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/clion.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/code_blocks.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/kdevelop.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/qt_creator.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/rider.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio_code.md create mode 100644 Redot-Documentation/docs/Contributing/Development/configuring_an_ide/xcode.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/2d_coordinate_systems.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/binding_to_external_libraries.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/common_engine_methods_and_macros.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/core_types.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_audiostreams.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_godot_servers.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_modules_in_cpp.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_platform_ports.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_resource_format_loaders.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/files/class_tree.zip create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/godot_architecture_diagram.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/inheritance_class_tree.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/internal_rendering_architecture.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/object_class.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/scripting_development.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/unit_testing.md create mode 100644 Redot-Documentation/docs/Contributing/Development/core_and_modules/variant_class.md create mode 100644 Redot-Documentation/docs/Contributing/Development/cpp_usage_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Development/debugging/macos_debug.md create mode 100644 Redot-Documentation/docs/Contributing/Development/debugging/using_cpp_profilers.md create mode 100644 Redot-Documentation/docs/Contributing/Development/debugging/using_sanitizers.md create mode 100644 Redot-Documentation/docs/Contributing/Development/debugging/vulkan/vulkan_validation_layers.md create mode 100644 Redot-Documentation/docs/Contributing/Development/editor/creating_icons.md create mode 100644 Redot-Documentation/docs/Contributing/Development/editor/editor_style_guide.md create mode 100644 Redot-Documentation/docs/Contributing/Development/editor/introduction_to_editor_development.md create mode 100644 Redot-Documentation/docs/Contributing/Development/file_formats/gdscript_grammar.md create mode 100644 Redot-Documentation/docs/Contributing/Development/file_formats/tscn.md create mode 100644 Redot-Documentation/docs/Contributing/Development/handling_compatibility_breakages.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/building_the_manual.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/class_reference_primer.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/content_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/contributing_to_the_documentation.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/docs_image_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/docs_writing_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/editor_and_docs_localization.md create mode 100644 Redot-Documentation/docs/Contributing/Documentation/updating_the_class_reference.md create mode 100644 Redot-Documentation/docs/Contributing/Workflow/bisecting_regressions.md create mode 100644 Redot-Documentation/docs/Contributing/Workflow/bug_triage_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Workflow/first_steps.md create mode 100644 Redot-Documentation/docs/Contributing/Workflow/pr_review_guidelines.md create mode 100644 Redot-Documentation/docs/Contributing/Workflow/pr_workflow.md create mode 100644 Redot-Documentation/docs/Contributing/Workflow/testing_pull_requests.md create mode 100644 Redot-Documentation/docs/Contributing/how_to_contribute.md create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Compiling/andtemplates.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Compiling/encryption_key.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Compiling/lintemplates.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Compiling/wintemplates.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_hotspot_flame_graph.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_hotspot_record.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_hotspot_view_results.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_hotspot_welcome.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_time_profiler.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_time_profiler_record.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_time_profiler_result.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_verysleepy_results_filtered.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_verysleepy_select_process.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/Debugging/cpp_profiler_xcode_menu.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices1.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices2.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices3.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices4.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices5.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices6.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices7.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/best_practices8.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_app_build_variant.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_app_configurations_drop_down.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_app_debug_type_setup.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_editor_build_variant.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_editor_configurations_drop_down.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_editor_debug_type_setup.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/android_studio_setup_project_1.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-add-configuration.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-add-custom-build-application.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-build-run.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-create-build-tool.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-create-clean-tool.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-external-tools.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-preferences.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-run-configuration.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-select-tools.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/clion-target.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_block_use_tab_character.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_add_files_recursively.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_build_targets.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_compiler_and_configuration.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_file_new_project.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_new_empty_project.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_open_build_options.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_open_properties.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_project_properties.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_project_title_and_location.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_scons_clean.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_scons_minimum.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_scons_windows.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_select_files.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_update_editor_settings.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/code_blocks_wizard_welcome.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_addincludes.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_buildconfig.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_configlaunches.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_configlaunches2.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_custombuild.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_newproject.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/kdevelop_openconfig.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-apply-import-filter.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-edit-codestyle.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-edit-files-menu.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-new-project.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-options-cpp.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-project-name-includes.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-projects-build.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-run-command.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-set-project-path.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/qtcreator-set-scons-command.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/rider_attach_to_process.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/rider_attach_to_process_dialog.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/rider_configurations.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/rider_configurations_changed.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/rider_run_debug.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vs_1_install_cpp_package.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vs_2_project_properties.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vs_3_debug_command_line.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vs_4_debugging_main.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_1_create_launch.json.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_2_launch.json.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_3_tasks.json.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_configure_task.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_create_tasksjson.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_create_tasksjson_others.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/vscode_edit_configurations.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_1_create_external_build_project.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_2_set_external_build_project_parameters.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_3_configure_scons.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_4_add_new_target.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_5_select_command_line_target.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_6_after_add_godot_source_to_project.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_7_setup_build_post_action.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/configuring_an_ide/xcode_8_setup_run_scheme.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/Control.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/Node2D.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/Node2D.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/Node3D.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/Object.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/RefCounted.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/architecture_diagram.jpg create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/rendering_architecture_diagram.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Development/core_and_modules/transforms_overview.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/crop_edit.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/crop_pixels.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/crop_tool.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/cropped_image.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/editor-vocabulary-overview.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_01_language_list.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_02_new_translation.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_03_translation_overview.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_04_translation_interface.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_05_search_location.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_06_browse_by_location.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_07_download_po_file.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_08_edit_on_github.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Documentation/l10n_09_path_to_image.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/github_fork_button.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/github_fork_make_pr.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/github_fork_url.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_access_checks.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_access_fork.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_checks_artifacts.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_checks_artifacts_list.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_command_line_checkout.webp create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_fork_zip.png create mode 100644 Redot-Documentation/wwwroot/img/Contributing/Workflow/testing_pull_requests_nightly_link.png diff --git a/Redot-Documentation/docs/Contributing/Development/best_practices_for_engine_contributors.md b/Redot-Documentation/docs/Contributing/Development/best_practices_for_engine_contributors.md new file mode 100644 index 0000000..81864e8 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/best_practices_for_engine_contributors.md @@ -0,0 +1,225 @@ + +# Best practices for engine contributors + +## Introduction + +Redot has a large amount of users who have the ability to contribute because the +project itself is aimed mainly at users who can code. That being said, not all +of them have the same level of experience working in large projects or in +software engineering, which can lead to common misunderstandings and bad +practices during the process of contributing code to the project. + +## Language + +The scope of this document is to be a list of best practices for contributors to +follow, as well as to create a language they can use to refer to common +situations that arise in the process of submitting their contributions. + +While a generalized list of software development best practices might be useful, +we'll focus on the situations that are most common in our project. + +Contributions are most of the time categorized as bug fixes, enhancements or new +features. To abstract this idea, we will call them *Solutions*, because they +always seek to solve something that can be described as a *Problem*. + +## Best Practices + +### #1: The problem always comes first + +Many contributors are extremely creative and just enjoy the process of designing +abstract data structures, creating nice user interfaces, or simply love +programming. Whatever the case may be, they come up with cool ideas, which may +or may not solve real problems. + +![Image](/img/Contributing/Development/best_practices1.png) + +These are usually called *solutions in search of a problem*. In an ideal world, +they would not be harmful but, in reality, code takes time to write, takes up +space and requires maintenance once it exists. Avoiding the addition of anything +unnecessary is always considered a good practice in software development. + +### #2: To solve the problem, it has to exist in the first place + +This is a variation of the previous practice. Adding anything unnecessary is not +a good idea, but what constitutes what is necessary and what isn't? + +![Image](/img/Contributing/Development/best_practices2.png) + +The answer to this question is that the problem needs to *exist* before it can +be actually solved. It must not be speculation or a belief. The user must be +using the software as intended to create something they *need*. In this process, +the user may stumble upon a problem that requires a solution to proceed, or in +order to achieve greater productivity. In this case, *a solution is needed*. + +Believing that problems may arise in the future and that the software needs to +be ready to solve them by the time they appear is called *"Future proofing"* and +its characterized by lines of thought such as: + +- I think it would be useful for users to... +- I think users will eventually need to... + +This is generally considered a bad habit because trying to solve problems that +*don't actually exist* in the present will often lead to code that will be +written but never used, or that is considerably more complex to use and maintain +than it needs to be. + +### #3: The problem has to be complex or frequent + +Software is designed to solve problems, but we can't expect it to solve *every +problem that exists under the sun*. As a game engine, Redot will help you make +games better and faster, but it won't make an *entire game* for you. A line must +be drawn somewhere. + +![Image](/img/Contributing/Development/best_practices3.png) + +Whether a problem is worth solving is determined by the effort that is required +to work around it. The required effort depends on: + +- The complexity of the problem +- The frequency the problem + +If the problem is *too complex* for most users to solve, then the software +should offer a ready-made solution for it. Likewise, if the problem is easy for +the user to work around, offering such a solution is unnecessary. + +The exception, however, is when the user encounters a problem *frequently +enough* that having to do the simple solution every time becomes an annoyance. +In this case, the software should offer a solution to simplify the use case. + +It's usually easy to tell if a problem is complex or frequent, but it can be +difficult. This is why discussing with other developers (next point) is always +advised. + +### #4: The solution must be discussed with others + +Often, users will be immersed in their own projects when they stumble upon +problems. These users will naturally try to solve the problem from their +perspective, thinking only about their own use case. As a result, user proposed +solutions don't always contemplate all use cases and are often biased towards +the user's own requirements. + +![Image](/img/Contributing/Development/best_practices4.png) + +For developers, the perspective is different. They may find the user's problem +too unique to justify a solution (instead of a workaround), or they might +suggest a partial (usually simpler or lower level) solution that applies to a +wider range of known problems and leave the rest of the solution up to the +user. + +In any case, before attempting to contribute, it is important to discuss the +actual problems with the other developers or contributors, so a better agreement +on implementation can be reached. + +The only exception is when an area of code has a clear agreed upon owner, who +talks to users directly and has the most knowledge to implement a solution +directly. + +Also, Redot's philosophy is to favor ease of use and maintenance over absolute +performance. Performance optimizations will be considered, but they may not +be accepted if they make something too difficult to use or if they add too much +complexity to the codebase. + +### #5: To each problem, its own solution + +For programmers, it is always a most enjoyable challenge to find the most +optimal solutions to problems. It is possible to go overboard, though. +Sometimes, contributors will try to come up with solutions that solve as many +problems as possible. + +The situation will often take a turn for the worse when, in order to make this +solution appear even more fantastic and flexible, the pure speculation-based +problems (as described in #2) also make their appearance on stage. + +![Image](/img/Contributing/Development/best_practices5.png) + +The main problem is that, in reality, it rarely works this way. Most of the +time, writing an individual solution to each problem results in code that +is simpler and more maintainable. + +Additionally, solutions that target individual problems are better for the +users. Targeted solutions allow users find something that does exactly what they +need, without having to learn a more complex system they will only need for simple +tasks. + +Big and flexible solutions also have an additional drawback which is that, over +time, they are rarely flexible enough for all users. Users end up requesting +more and more functionality which ends up making the API and codebase +more and more complex. + +### #6: Cater to common use cases, leave the door open for the rare ones + +This is a continuation of the previous point, which further explains why this +way of thinking and designing software is preferred. + +As mentioned before (in point #2), it is very difficult for us (as human beings +who design software) to actually understand all future user needs. Trying to +write very flexible structures that cater to many use cases at once is often a +mistake. + +We may come up with something we believe is brilliant, but later find out that +users will never even use half of it or that they require features that don't +quite fit into our original design, forcing us to either throw it away +or make it even more complex. + +The question is then, how do we design software that both allows users to do +*what we know they need to do* now and allows them to do *what we don't yet know +they'll need to do* in the future? + +![Image](/img/Contributing/Development/best_practices6.png) + +The answer to this question is that, to ensure users still can do what they want +to do, we need to give them access to a *low-level API* that they can use to +achieve what they want, even if it's more work for them because it means +reimplementing some logic that already exists. + +In real-life scenarios, these use cases will be at most rare and uncommon +anyway, so it makes sense a custom solution needs to be written. This is why +it's important to still provide users the basic building blocks to do it. + +### #7: Prefer local solutions + +When looking for a solution to a problem, be it implementing a new feature or +fixing a bug, sometimes the easiest path is to add data or a new function in the +core layers of code. + +The main problem here is, adding something to the core layers that will only be +used from a single location far away will not only make the code more difficult +to follow (split in two), but also make the core API larger, more complex, more +difficult to understand in general. + +This is bad, because readability and cleanness of core APIs is always of extreme +importance given how much code relies on it, and because it's key for new +contributors as a starting point to learning the codebase. + +![Image](/img/Contributing/Development/best_practices7.png) + +A common reason for wanting to do this is that it's usually less code to simply +add a hack in the core layers. + +Doing so is not advised. Generally, the code for a solution should be closer to +where the problem originates, even if it involves additional, duplicated, more +complex, or less efficient code. More creativity might be needed, but this path +is always the advised one. + +### #8: Don't use complex canned solutions for simple problems + +Not every problem has a simple solution and, many times, the right choice is to +use a third-party library to solve the problem. + +As Redot requires to be shipped in a large amount of platforms, we can't +link libraries dynamically. Instead, we bundle them in our source tree. + +![Image](/img/Contributing/Development/best_practices8.png) + +As a result, we are very picky with what goes in, and we tend to prefer smaller +libraries (single header ones are our favorite). We will only bundle something +larger if there is no other choice. + +Libraries must use a permissive enough license to be included into Redot. +Some examples of acceptable licenses are Apache 2.0, BSD, MIT, ISC, and MPL 2.0. +In particular, we cannot accept libraries licensed under the GPL or LGPL since +these licenses effectively disallow static linking in proprietary software +(which Redot is distributed as in most exported projects). This requirement also +applies to the editor, since we may want to run it on iOS in the long term. +Since iOS doesn't support dynamic linking, static linking is the only option on +that platform. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/code_style_guidelines.md b/Redot-Documentation/docs/Contributing/Development/code_style_guidelines.md new file mode 100644 index 0000000..566f1dd --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/code_style_guidelines.md @@ -0,0 +1,387 @@ + +# Code style guidelines + + +When contributing to Redot's source code, you will be expected to follow the +style guidelines outlined below. Some of them are checked via the Continuous +Integration process and reviewers will ask you to fix potential issues, so +best setup your system as outlined below to ensure all your commits follow the +guidelines. + +## C++ and Objective-C + +There are no written guidelines, but the code style agreed upon by the +developers is enforced via the [clang-format](https://clang.llvm.org/docs/ClangFormat.html) +code beautifier, which takes care for you of all our conventions. +To name a few: + +- Indentation and alignment are both tab based (respectively one and two tabs) +- One space around math and assignments operators as well as after commas +- Pointer and reference operators are affixed to the variable identifier, not + to the type name +- See further down regarding header includes + +The rules used by clang-format are outlined in the +[.clang-format](https://github.com/redot-engine/redot-engine/blob/master/.clang-format) +file of the Redot repository. + +As long as you ensure that your style matches the surrounding code and that you're +not introducing trailing whitespace or space-based indentation, you should be +fine. If you plan to contribute regularly, however, we strongly advise that you +set up clang-format locally to check and automatically fix all your commits. + +:::warning +Redot's code style should *not* be applied to third-party code, +i.e. code that is included in Redot's source tree, but was not written +specifically for our project. Such code usually comes from +different upstream projects with their own style guides (or lack +thereof), and don't want to introduce differences that would make +syncing with upstream repositories harder. + +Third-party code is usually included in the ``thirdparty/`` folder +and can thus easily be excluded from formatting scripts. For the +rare cases where a third-party code snippet needs to be included +directly within a Redot file, you can use +``/* clang-format off */`` and ``/* clang-format on */`` to tell +clang-format to ignore a chunk of code. + +::: + +:::info + +These guidelines only cover code formatting. See [C++ Usage Guidelines](cpp_usage_guidelines) +for a list of language features that are permitted in pull requests. + +::: + +### Using clang-format locally + +You need to use **clang-format 17** to be compatible with Redot's format. Later versions might +be suitable, but previous versions may not support all used options, or format +some things differently, leading to style issues in pull requests. + +#### Pre-commit hook + +For ease of use, we provide hooks for Git with the [pre-commit](https://pre-commit.com/) +Python framework that will run clang-format automatically on all your commits with the +correct version of clang-format. +To set up: + +``` +pip install pre-commit +pre-commit install + +``` + +You can also run the hook manually with ``pre-commit run -a``. + +:::note + +Previously, we supplied a hook in the folder ``misc/hooks``. If you copied the +script manually, these hooks should still work, but symlinks will be broken. +If you are using the new system, run ``rm .git/hooks/*`` to remove the old hooks +that are no longer needed. + +::: + +#### Installation + +Here's how to install clang-format: + +- Linux: It will usually be available out-of-the-box with the clang toolchain + packaged by your distribution. If your distro version is not the required one, + you can download a pre-compiled version from the + [LLVM website](https://releases.llvm.org/download.html), or if you are on + a Debian derivative, use the [upstream repos](https://apt.llvm.org/). +- macOS and Windows: You can download precompiled binaries from the + [LLVM website](https://releases.llvm.org/download.html). You may need to add + the path to the binary's folder to your system's ``PATH`` environment + variable to be able to call clang-format out of the box. + +You then have different possibilities to apply clang-format to your changes: + +#### Manual usage + +You can apply clang-format manually for one or more files with the following +command: + +``` +clang-format -i + +``` + +- ``-i`` means that the changes should be written directly to the file (by + default clang-format would only output the fixed version to the terminal). +- The path can point to several files, either one after the other or using + wildcards like in a typical Unix shell. Be careful when globbing so that + you don't run clang-format on compiled objects (.o and .a files) that are + in Redot's tree. So better use ``core/*.{cpp,h}`` than ``core/*``. + +#### IDE plugin + +Most IDEs or code editors have beautifier plugins that can be configured to run +clang-format automatically, for example, each time you save a file. + +Here is a non-exhaustive list of beautifier plugins for some IDEs: + +- Qt Creator: [Beautifier plugin](https://doc.qt.io/qtcreator/creator-beautifier.html) +- Visual Studio Code: [Clang-Format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format) +- Visual Studio: [Clang Power Tools 2022](https://marketplace.visualstudio.com/items?itemName=caphyon.ClangPowerTools2022) +- vim: [vim-clang-format](https://github.com/rhysd/vim-clang-format) +- CLion: Starting from version ``2019.1``, no plugin is required. Instead, enable + [ClangFormat](https://www.jetbrains.com/help/clion/clangformat-as-alternative-formatter.html#clion-support) + +(Pull requests are welcome to extend this list with tested plugins.) + +### Header includes + +When adding new C++ or Objective-C files or including new headers in existing +ones, the following rules should be followed: + +- The first lines in the file should be Redot's copyright header and MIT + license, copy-pasted from another file. Make sure to adjust the filename. +- In a ``.h`` header, include guards should be used with the form + ``FILENAME_H``. + +- In a ``.cpp`` file (e.g. ``filename.cpp``), the first include should be the + one where the class is declared (e.g. ``#include "filename.h"``), followed by + an empty line for separation. +- Then come headers from Redot's own code base, included in alphabetical order + (enforced by ``clang-format``) with paths relative to the root folder. Those + includes should be done with quotes, e.g. ``#include "core/object.h"``. The + block of Redot header includes should then be followed by an empty line for + separation. +- Finally, third-party headers (either from ``thirdparty`` or from the system's + include paths) come next and should be included with the < and > symbols, e.g. + `[#include](png.h)`. The block of third-party headers should also be followed + by an empty line for separation. +- Redot and third-party headers should be included in the file that requires + them, i.e. in the `.h` header if used in the declarative code or in the `.cpp` + if used only in the imperative code. + +Example: + +```cpp +/**************************************************************************/ +/* my_new_file.h */ +/**************************************************************************/ +/* This file is part of: */ +/* Redot ENGINE */ +/* https://redotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present the Redot community, modified from an */ +/* original work by G-dot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 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 MY_NEW_FILE_H +#define MY_NEW_FILE_H + +#include "core/hash_map.h" +#include "core/list.h" +#include "scene/gui/control.h" + +#include + +... + +#endif // MY_NEW_FILE_H + +``` + +```cpp +/**************************************************************************/ +/* my_new_file.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* Redot ENGINE */ +/* https://redotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present the Redot community, modified from an */ +/* original work by Redot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 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 "my_new_file.h" + +#include "core/math/math_funcs.h" +#include "scene/gui/line_edit.h" + +#include +#include + +``` + +## Java + +Redot's Java code (mostly in ``platform/android``) is also enforced via +``clang-format``, so see the instructions above to set it up. Keep in mind that +this style guide only applies to code written and maintained by Redot, not +third-party code such as the ``java/src/com/google`` subfolder. + +## Python + +Redot's SCons buildsystem is written in Python, and various scripts included +in the source tree are also using Python. + +For those, we use the [Ruff linter and code formatter](https://docs.astral.sh/ruff/). + +### Using ruff locally + +First of all, you will need to install Ruff. Ruff requires Python 3.7+ to run. + +#### Installation + +Here's how to install ruff: + +``` +pip3 install ruff --user + +``` + +You then have different possibilities to apply ruff to your changes: + +#### Manual usage + +You can apply ``ruff`` manually to one or more files with the following +command: + +``` +ruff -l 120 + +``` + +- ``-l 120`` means that the allowed number of characters per line is 120. + This number was agreed upon by the developers. +- The path can point to several files, either one after the other or using + wildcards like in a typical Unix shell. + +### Pre-commit hook + +For ease of use, we provide hooks for Git with the [pre-commit](https://pre-commit.com/) +Python framework that will run ``ruff`` automatically on all your commits with the +correct version of ``ruff``. +To set up: + +``` +pip install pre-commit +pre-commit install + +``` + +You can also run the hook manually with ``pre-commit run -a``. + +:::note + +Previously, we supplied a hook in the folder ``misc/hooks``. If you copied the +script manually, these hooks should still work, but symlinks will be broken. +If you are using the new system, run ``rm .git/hooks/*`` to remove the old hooks +that are no longer needed. + +::: + +#### Editor integration + +Many IDEs or code editors have beautifier plugins that can be configured to run +ruff automatically, for example, each time you save a file. For details, you can +check [Ruff Integrations](https://docs.astral.sh/ruff/integrations/). + +## Comment style guide + +This comment style guide applies to all programming languages used within +Redot's codebase. + +- Begin comments with a space character to distinguish them from disabled code. +- Use sentence case for comments. Begin comments with an uppercase character and + always end them with a period. +- Reference variable/function names and values using backticks. +- Wrap comments to ~100 characters. +- You can use ``TODO:``, ``FIXME:``, ``NOTE:``, ``WARNING:``, or ``HACK:`` as admonitions + when needed. + +**Example:** + +```cpp +// Compute the first 10,000 decimals of Pi. +// FIXME: Don't crash when computing the 1,337th decimal due to `increment` +// being negative. + +``` + +Don't repeat what the code says in a comment. Explain the *why* rather than *how*. + +**Bad:** + +```cpp +// Draw loading screen. +draw_load_screen(); + +``` + +You can use Javadoc-style comments above function or macro definitions. It's +recommended to use Javadoc-style comments *only* for methods which are not +exposed to scripting. This is because exposed methods should be documented in +the [class reference XML](../Documentation/updating_the_class_reference.md) +instead. + +**Example:** + +```cpp +/** + * Returns the number of nodes in the universe. + * This can potentially be a very large number, hence the 64-bit return type. + */ +uint64_t Universe::get_node_count() { + // ... +} + +``` + +For member variables, don't use Javadoc-style comments, but use single-line comments instead: + +```cpp +class Universe { + // The cached number of nodes in the universe. + // This value may not always be up-to-date with the current number of nodes + // in the universe. + uint64_t node_count_cached = 0; +}; +``` diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_android.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_android.md new file mode 100644 index 0000000..5df0f9e --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_android.md @@ -0,0 +1,303 @@ + +# Compiling for Android + +.. highlight:: shell + +:::info + +This page describes how to compile Android export template binaries from source. +If you're looking to export your project to Android instead, read [doc_exporting_for_android](../../../tutorials/export/exporting_for_android.md). + +::: + +## Note + +In most cases, using the built-in deployer and export templates is good +enough. Compiling the Android APK manually is mostly useful for custom +builds or custom packages for the deployer. + +Also, you still need to follow the steps mentioned in the +[doc_exporting_for_android](../../../tutorials/export/exporting_for_android.md) tutorial before attempting to build +a custom export template. + +## Requirements + +For compiling under Windows, Linux or macOS, the following is required: + +- [Python 3.8+](https://www.python.org/downloads/). +- [SCons 4.0+](https://scons.org/pages/download.html) build system. +- [Android SDK](https://developer.android.com/studio/#command-tools) + (command-line tools are sufficient). + + - Required SDK components will be automatically installed. + - On Linux, **do not use an Android SDK provided by your distribution's repositories** as it will often be outdated. + - On macOS, **do not use an Android SDK provided by Homebrew** as it will not be installed in a unified location. + +- Gradle (will be downloaded and installed automatically if missing). +- JDK 17 (either OpenJDK or Oracle JDK). + + - You can download a build from [Adoptium](https://adoptium.net/temurin/releases/?variant=openjdk17). + +:::info +To get the Redot source code for compiling, see +[doc_getting_source](getting_source.md). + +For a general overview of SCons usage for Redot, see +[doc_introduction_to_the_buildsystem](introduction_to_the_buildsystem.md). + +::: + +## Setting up the buildsystem + +- Set the environment variable ``ANDROID_HOME`` to point to the Android + SDK. If you downloaded the Android command-line tools, this would be + the folder where you extracted the contents of the ZIP archive. + + - Windows: Press `Windows + R`, type "control system", + then click on **Advanced system settings** in the left pane, + then click on **Environment variables** on the window that appears. + + - Linux or macOS: Add the text ``export ANDROID_HOME="/path/to/android-sdk"`` + to your ``.bashrc`` or ``.zshrc`` where ``/path/to/android-sdk`` points to + the root of the SDK directories. + +- Install the necessary SDK components in this folder: + + - Accept the SDK component licenses by running the following command + where ``android_sdk_path`` is the path to the Android SDK, then answering all the prompts with ``y``: + +``` +cmdline-tools/latest/bin/sdkmanager --sdk_root= --licenses + +``` + + - Complete setup by running the following command where ``android_sdk_path`` is the path to the Android SDK. + +``` +cmdline-tools/latest/bin/sdkmanager --sdk_root= "platform-tools" "build-tools;34.0.0" "platforms;android-34" "cmdline-tools;latest" "cmake;3.10.2.4988404" "ndk;23.2.8568313" + +``` + +- After setting up the SDK and environment variables, be sure to + **restart your terminal** to apply the changes. If you are using + an IDE with an integrated terminal, you need to restart the IDE. + +- Run ``scons platform=android``. If this fails, go back and check the steps. + If you completed the setup correctly, the NDK will begin downloading. + If you are trying to compile GDExtension, you need to first compile + the engine to download the NDK, then you can compile GDExtension. + +## Building the export templates + +Redot needs three export templates for Android: the optimized "release" +template (``android_release.apk``), the debug template (``android_debug.apk``), +and the Gradle build template (``android_source.zip``). +As Google requires all APKs to include ARMv8 (64-bit) libraries since August 2019, +the commands below build templates containing both ARMv7 and ARMv8 libraries. + +Compiling the standard export templates is done by calling SCons from the Redot +root directory with the following arguments: + +- Release template (used when exporting with **Debugging Enabled** unchecked) + +``` +scons platform=android target=template_release arch=arm32 +scons platform=android target=template_release arch=arm64 generate_apk=yes + +``` + +- Debug template (used when exporting with **Debugging Enabled** checked) + +``` +scons platform=android target=template_debug arch=arm32 +scons platform=android target=template_debug arch=arm64 generate_apk=yes + +``` + +- (**Optional**) Dev template (used when troubleshooting) + +``` +scons platform=android target=template_debug arch=arm32 dev_build=yes +scons platform=android target=template_debug arch=arm64 dev_build=yes generate_apk=yes + +``` + +The resulting templates will be located under the ``bin`` directory: + +- ``bin/android_release.apk`` for the release template +- ``bin/android_debug.apk`` for the debug template +- ``bin/android_dev.apk`` for the dev template +- ``bin/android_source.zip`` for the Gradle build template + +:::note + +- If you are changing the list of architectures you're building, remember to add ``generate_apk=yes`` to the *last* architecture you're building, so that the template files are generated after the build. + +- To include debug symbols in the generated templates, add the ``debug_symbols=yes`` parameter to the SCons command. + +::: + +:::info + +If you want to enable Vulkan validation layers, see +[Vulkan validation layers on Android](doc_vulkan_validation_layers_android). + +::: + +### Adding support for x86 devices + +If you also want to include support for x86 and x86_64 devices, run the SCons +command a third and fourth time with the ``arch=x86_32``, and +``arch=x86_64`` arguments before building the APK with Gradle. For +example, for the release template: + +``` +scons platform=android target=template_release arch=arm32 +scons platform=android target=template_release arch=arm64 +scons platform=android target=template_release arch=x86_32 +scons platform=android target=template_release arch=x86_64 generate_apk=yes + +``` + +This will create template binaries that works on all platforms. +The final binary size of exported projects will depend on the platforms you choose +to support when exporting; in other words, unused platforms will be removed from +the binary. + +### Cleaning the generated export templates + +You can use the following commands to remove the generated export templates: + +``` +cd platform/android/java +# On Windows +.\gradlew clean +# On Linux and macOS +./gradlew clean + +``` + +## Using the export templates + +Redot needs release and debug binaries that were compiled against the same +version/commit as the editor. If you are using official binaries +for the editor, make sure to install the matching export templates, +or build your own from the same version. + +When exporting your game, Redot uses the templates as a base, and updates their content as needed. + +### Installing the templates + +The newly-compiled templates (``android_debug.apk`` +, ``android_release.apk``, and ``android_source.zip``) must be copied to Redot's templates folder +with their respective names. The templates folder can be located in: + +- Windows: ``%APPDATA%\Redot\export_templates\<version>\`` +- Linux: ``$HOME/.local/share/Redot/export_templates/<version>/`` +- macOS: ``$HOME/Library/Application Support/Redot/export_templates/<version>/`` + +``<version>`` is of the form ``major.minor[.patch].status`` using values from +``version.py`` in your Redot source repository (e.g. ``4.1.3.stable`` or ``4.2.dev``). +You also need to write this same version string to a ``version.txt`` file located +next to your export templates. + +However, if you are writing your custom modules or custom C++ code, you +might instead want to configure your template binaries as custom export templates +here: + +![Image](img/andtemplates.png) + +You don't even need to copy them, you can just reference the resulting +file in the ``bin\`` directory of your Redot source folder, so that the +next time you build you will automatically have the custom templates +referenced. + +## Building the Redot editor + +Compiling the editor is done by calling SCons from the Redot +root directory with the following arguments: + +``` +scons platform=android arch=arm32 production=yes target=editor +scons platform=android arch=arm64 production=yes target=editor +scons platform=android arch=x86_32 production=yes target=editor +scons platform=android arch=x86_64 production=yes target=editor generate_apk=yes + +``` + +- You can add the ``dev_build=yes`` parameter to generate a dev build of the Redot editor. + +- You can add the ``debug_symbols=yes`` parameter to include the debug symbols in the generated build. + +- You can skip certain architectures depending on your target device to speed up compilation. + +Remember to add ``generate_apk=yes`` to the *last* architecture you're building, so that binaries are generated after the build. + +The resulting binaries will be located under ``bin/android_editor_builds/``. + +## Removing the Editor binaries + +You can use the following commands to remove the generated editor binaries: + +``` +cd platform/android/java +# On Windows +``` + + .\gradlew clean + # On Linux and macOS + ./gradlew clean + +## Installing the Redot editor APK + +With an Android device with Developer Options enabled, connect the Android device to your computer via its charging cable to a USB/USB-C port. +Open up a Terminal/Command Prompt and run the following commands from the root directory with the following arguments: + +``` +adb install ./bin/android_editor_builds/android_editor-release.apk + +``` + +## Troubleshooting + +### Platform doesn't appear in SCons + +Double-check that you've set the ``ANDROID_HOME`` +environment variable. This is required for the platform to appear in SCons' +list of detected platforms. +See [Setting up the buildsystem](doc_android_setting_up_the_buildsystem) +for more information. + +### Application not installed + +Android might complain the application is not correctly installed. +If so: + +- Check that the debug keystore is properly generated. +- Check that the jarsigner executable is from JDK 8. + +If it still fails, open a command line and run [logcat](https://developer.android.com/studio/command-line/logcat): + +``` +adb logcat + +``` + +Then check the output while the application is installed; +the error message should be presented there. +Seek assistance if you can't figure it out. + +### Application exits immediately + +If the application runs but exits immediately, this might be due to +one of the following reasons: + +- Make sure to use export templates that match your editor version; if + you use a new Redot version, you *have* to update the templates too. +- ``libRedot_android.so`` is not in ``libs/<arch>/`` + where ``<arch>`` is the device's architecture. +- The device's architecture does not match the exported one(s). + Make sure your templates were built for that device's architecture, + and that the export settings included support for that architecture. + +In any case, ``adb logcat`` should also show the cause of the error. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_ios.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_ios.md new file mode 100644 index 0000000..fed36cf --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_ios.md @@ -0,0 +1,99 @@ + +# Compiling for iOS + +.. highlight:: shell + +:::info + +This page describes how to compile iOS export template binaries from source. +If you're looking to export your project to iOS instead, read [doc_exporting_for_ios](doc_exporting_for_ios). + +::: + +## Requirements + +- [Python 3.8+](https://www.python.org/downloads/macos/). +- [SCons 4.0+](https://scons.org/pages/download.html) build system. +- [Xcode](https://apps.apple.com/us/app/xcode/id497799835). + - Launch Xcode once and install iOS support. If you have already launched + Xcode and need to install iOS support, go to *Xcode -> Settings... -> Platforms*. + - Go to *Xcode -> Settings... -> Locations -> Command Line Tools* and select + an installed version. Even if one is already selected, re-select it. +- Download and follow README instructions to build a static ``.xcframework`` + from the [MoltenVK SDK](https://github.com/KhronosGroup/MoltenVK#fetching-moltenvk-source-code). + +:::note +If you have [Homebrew](https://brew.sh/) installed, you can easily +install SCons using the following command + +``` +brew install scons + +``` + +Installing Homebrew will also fetch the Command Line Tools +for Xcode automatically if you don't have them already. + +Similarly, if you have [MacPorts](https://www.macports.org/) +installed, you can easily install SCons using the +following command + +``` +sudo port install scons +``` + +::: + +:::info +To get the Redot source code for compiling, see +[doc_getting_source](doc_getting_source). + +For a general overview of SCons usage for Redot, see +[doc_introduction_to_the_buildsystem](doc_introduction_to_the_buildsystem). + +::: + +## Compiling + +Open a Terminal, go to the root folder of the engine source code and type +the following to compile a debug build: + +``` +scons platform=ios target=template_debug generate_bundle=yes + +``` + +To compile a release build: + +``` +scons platform=ios target=template_release generate_bundle=yes + +``` + +Alternatively, you can run the following command for Xcode simulator libraries (optional): + +``` +scons platform=ios target=template_debug ios_simulator=yes arch=arm64 +scons platform=ios target=template_debug ios_simulator=yes arch=x86_64 generate_bundle=yes + +``` + +These simulator libraries cannot be used to run the exported project on the +target device. Instead, they can be used to run the exported project directly on +your Mac while still testing iOS platform-specific functionality. + +To create an Xcode project like in the official builds, you need to use the +template located in ``misc/dist/ios_xcode``. The release and debug libraries +should be placed in ``libRedot.ios.debug.xcframework`` and +``libRedot.ios.release.xcframework`` respectively. This process can be automated +by using the ``generate_bundle=yes`` option on the *last* SCons command used to +build export templates (so that all binaries can be included). + +The MoltenVK static ``.xcframework`` folder must also be placed in the +``ios_xcode`` folder once it has been created. MoltenVK is always statically +linked on iOS; there is no dynamic linking option available, unlike macOS. + +## Run + +To run on a device or simulator, follow these instructions: +[doc_exporting_for_ios](doc_exporting_for_ios). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_linuxbsd.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_linuxbsd.md new file mode 100644 index 0000000..a6a27ed --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_linuxbsd.md @@ -0,0 +1,664 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Compiling for Linux, \*BSD + +.. highlight:: shell + +:::info + +This page describes how to compile Linux editor and export template binaries from source. +If you're looking to export your project to Linux instead, read [doc_exporting_for_linux](../../../tutorials/export/exporting_for_linux.md). + +::: + +## Requirements + +For compiling under Linux or other Unix variants, the following is +required: + +- GCC 9+ or Clang 6+. +- [Python 3.8+](https://www.python.org/downloads/). +- [SCons 4.0+](https://scons.org/pages/download.html) build system. +- pkg-config (used to detect the development libraries listed below). +- Development libraries: + + - X11, Xcursor, Xinerama, Xi and XRandR. + - Wayland and wayland-scanner. + - Mesa. + - ALSA. + - PulseAudio. + +- *Optional* - libudev (build with ``udev=yes``). + +:::info + +To get the Redot source code for compiling, see [doc_getting_source](getting_source.md). + +For a general overview of SCons usage for Redot, see [doc_introduction_to_the_buildsystem](introduction_to_the_buildsystem.md). + +::: + +### Distro-specific one-liners + + + + + +apk add \ + scons \ + pkgconf \ + gcc \ + g++ \ + libx11-dev \ + libxcursor-dev \ + libxinerama-dev \ + libxi-dev \ + libxrandr-dev \ + mesa-dev \ + eudev-dev \ + alsa-lib-dev \ + pulseaudio-dev + + + + + +pacman -Sy --noconfirm --needed \ + scons \ + pkgconf \ + gcc \ + libxcursor \ + libxinerama \ + libxi \ + libxrandr \ + wayland-utils \ + mesa \ + glu \ + libglvnd \ + alsa-lib \ + pulseaudio + + + + + +sudo apt-get update +sudo apt-get install -y \ + build-essential \ + scons \ + pkg-config \ + libx11-dev \ + libxcursor-dev \ + libxinerama-dev \ + libgl1-mesa-dev \ + libglu1-mesa-dev \ + libasound2-dev \ + libpulse-dev \ + libudev-dev \ + libxi-dev \ + libxrandr-dev \ + libwayland-dev + + + + + +sudo dnf install -y \ + scons \ + pkgconfig \ + libX11-devel \ + libXcursor-devel \ + libXrandr-devel \ + libXinerama-devel \ + libXi-devel \ + wayland-devel \ + mesa-libGL-devel \ + mesa-libGLU-devel \ + alsa-lib-devel \ + pulseaudio-libs-devel \ + libudev-devel \ + gcc-c++ \ + libstdc++-static \ + libatomic-static + + + + + +pkg install \ + py37-scons \ + pkgconf \ + xorg-libraries \ + libXcursor \ + libXrandr \ + libXi \ + xorgproto \ + libGLU \ + alsa-lib \ + pulseaudio + + + + + +emerge --sync +emerge -an \ + dev-build/scons \ + x11-libs/libX11 \ + x11-libs/libXcursor \ + x11-libs/libXinerama \ + x11-libs/libXi \ + dev-util/wayland-scanner \ + media-libs/mesa \ + media-libs/glu \ + media-libs/alsa-lib \ + media-sound/pulseaudio + + + + + +sudo urpmi --auto \ + scons \ + task-c++-devel \ + wayland-devel \ + "pkgconfig(alsa)" \ + "pkgconfig(glu)" \ + "pkgconfig(libpulse)" \ + "pkgconfig(udev)" \ + "pkgconfig(x11)" \ + "pkgconfig(xcursor)" \ + "pkgconfig(xinerama)" \ + "pkgconfig(xi)" \ + "pkgconfig(xrandr)" + + + + + + pkg_add \ + pkg-config \ + py37-scons + +:::tip + +For audio support, you can optionally install ``pulseaudio``. + +::: + + + + + +pkg_add \ + python \ + scons \ + llvm + + + + + +sudo apt update +sudo apt install -y \ + python3-pip \ + build-essential \ + pkg-config \ + libx11-dev \ + libxcursor-dev \ + libxinerama-dev \ + libgl1-mesa-dev \ + libglu1-mesa-dev \ + libasound2-dev \ + libpulse-dev \ + libudev-dev \ + libxi-dev \ + libxrandr-dev \ + libwayland-dev +sudo pip install scons + + + + + +sudo zypper install -y \ + scons \ + pkgconfig \ + libX11-devel \ + libXcursor-devel \ + libXrandr-devel \ + libXinerama-devel \ + libXi-devel \ + wayland-devel \ + Mesa-libGL-devel \ + alsa-devel \ + libpulse-devel \ + libudev-devel \ + gcc-c++ \ + libGLU1 + + + + + +eopkg install -y \ + -c system.devel \ + scons \ + libxcursor-devel \ + libxinerama-devel \ + libxi-devel \ + libxrandr-devel \ + wayland-devel \ + mesalib-devel \ + libglu \ + alsa-lib-devel \ + pulseaudio-devel + + + + + +## Compiling + +Start a terminal, go to the root dir of the engine source code and type: + +``` +scons platform=linuxbsd + +``` + +:::note + +Prior to Redot 4.0, the Linux/\*BSD target was called ``x11`` instead of +``linuxbsd``. If you are looking to compile Redot 3.x, make sure to use the +[3.x branch of this documentation](https://docs.redotengine.org/en/3.6/development/compiling/compiling_for_x11.html). + +::: + +:::tip + +If you are compiling Redot to make changes or contribute to the engine, +you may want to use the SCons options ``dev_build=yes`` or ``dev_mode=yes``. +See [doc_introduction_to_the_buildsystem_development_and_production_aliases](doc_introduction_to_the_buildsystem_development_and_production_aliases) +for more info. + +::: + +If all goes well, the resulting binary executable will be placed in the +"bin" subdirectory. This executable file contains the whole engine and +runs without any dependencies. Executing it will bring up the Project +Manager. + +:::note + +If you wish to compile using Clang rather than GCC, use this command: + +``` +scons platform=linuxbsd use_llvm=yes + +``` + +Using Clang appears to be a requirement for OpenBSD, otherwise fonts +would not build. +For RISC-V architecture devices, use the Clang compiler instead of the GCC compiler. + +::: + +:::tip +If you are compiling Redot for production use, you can +make the final executable smaller and faster by adding the +SCons option ``production=yes``. This enables additional compiler +optimizations and link-time optimization. + +LTO takes some time to run and requires about 7 GB of available RAM +while compiling. If you're running out of memory with the above option, +use ``production=yes lto=none`` or ``production=yes lto=thin`` for a +lightweight but less effective form of LTO. + +::: + +:::note +If you want to use separate editor settings for your own Redot builds +and official releases, you can enable +[doc_data_paths_self_contained_mode](doc_data_paths_self_contained_mode) by creating a file called +``._sc_`` or ``_sc_`` in the ``bin/`` folder. + +::: + +## Running a headless/server build + +To run in *headless* mode which provides editor functionality to export +projects in an automated manner, use the normal build + +``` +scons platform=linuxbsd target=editor + +``` + +And then use the ``--headless`` command line argument + +``` +./bin/Redot.linuxbsd.editor.x86_64 --headless + +``` + +To compile a debug *server* build which can be used with +:ref:`remote debugging tools `, use + +``` +scons platform=linuxbsd target=template_debug + +``` + +To compile a *server* build which is optimized to run dedicated game servers, +use + +``` +scons platform=linuxbsd target=template_release production=yes + +``` + +## Building export templates + +:::warning +Linux binaries usually won't run on distributions that are +older than the distribution they were built on. If you wish to +distribute binaries that work on most distributions, +you should build them on an old distribution such as Ubuntu 16.04. +You can use a virtual machine or a container to set up a suitable +build environment. + +::: + +To build Linux or \*BSD export templates, run the build system with the +following parameters: + +- (32 bits) + +``` +scons platform=linuxbsd target=template_release arch=x86_32 +scons platform=linuxbsd target=template_debug arch=x86_32 + +``` + +- (64 bits) + +``` +scons platform=linuxbsd target=template_release arch=x86_64 +scons platform=linuxbsd target=template_debug arch=x86_64 + +``` + +Note that cross-compiling for the opposite bits (64/32) as your host +platform is not always straight-forward and might need a chroot environment. + +To create standard export templates, the resulting files in the ``bin/`` folder +must be copied to: + +``` +$HOME/.local/share/Redot/export_templates// + +``` + +and named like this (even for \*BSD which is seen as "Linux/X11" by Redot): + +``` +linux_debug.arm32 +linux_debug.arm64 +linux_debug.x86_32 +linux_debug.x86_64 +linux_release.arm32 +linux_release.arm64 +linux_release.x86_32 +linux_release.x86_64 + +``` + +However, if you are writing your custom modules or custom C++ code, you +might instead want to configure your binaries as custom export templates +here: + +![Image](img/lintemplates.png) + +You don't even need to copy them, you can just reference the resulting +files in the ``bin/`` directory of your Redot source folder, so the next +time you build, you automatically have the custom templates referenced. + +## Cross-compiling for RISC-V devices + +To cross-compile Redot for RISC-V devices, we need to setup the following items: + +- [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases). + While we are not going to use this directly, it provides us with a sysroot, as well + as header and libraries files that we will need. There are many versions to choose + from, however, the older the toolchain, the more compatible our final binaries will be. + If in doubt, [use this version](https://github.com/riscv-collab/riscv-gnu-toolchain/releases/tag/2021.12.22), + and download ``riscv64-glibc-ubuntu-18.04-nightly-2021.12.22-nightly.tar.gz``. Extract + it somewhere and remember its path. +- [mold](https://github.com/rui314/mold/releases). This fast linker, + is the only one that correctly links the resulting binary. Download it, extract it, + and make sure to add its ``bin`` folder to your PATH. Run + ``mold --help | grep support`` to check if your version of Mold supports RISC-V. + If you don't see RISC-V, your Mold may need to be updated. + +To make referencing our toolchain easier, we can set an environment +variable like this: + +``` +export RISCV_TOOLCHAIN_PATH="path to toolchain here" + +``` + +This way, we won't have to manually set the directory location +each time we want to reference it. + +With all the above setup, we are now ready to build Redot. + +Go to the root of the source code, and execute the following build command: + +``` +PATH="$RISCV_TOOLCHAIN_PATH/bin:$PATH" \ +scons arch=rv64 use_llvm=yes linker=mold lto=none target=editor \ + ccflags="--sysroot=$RISCV_TOOLCHAIN_PATH/sysroot --gcc-toolchain=$RISCV_TOOLCHAIN_PATH -target riscv64-unknown-linux-gnu" \ + linkflags="--sysroot=$RISCV_TOOLCHAIN_PATH/sysroot --gcc-toolchain=$RISCV_TOOLCHAIN_PATH -target riscv64-unknown-linux-gnu" + +``` + +:::note + +RISC-V GCC has [bugs with its atomic operations](https://github.com/riscv-collab/riscv-gcc/issues/15) +which prevent it from compiling Redot correctly. That's why Clang is used instead. Make sure that +it *can* compile to RISC-V. You can verify by executing this command ``clang -print-targets``, +make sure you see ``riscv64`` on the list of targets. + +::: + +:::warning +The code above includes adding ``$RISCV_TOOLCHAIN_PATH/bin`` to the PATH, +but only for the following ``scons`` command. Since riscv-gnu-toolchain uses +its own Clang located in the ``bin`` folder, adding ``$RISCV_TOOLCHAIN_PATH/bin`` +to your user's PATH environment variable may block you from accessing another +version of Clang if one is installed. For this reason it's not recommended to make +adding the bin folder permanent. You can also omit the ``PATH="$RISCV_TOOLCHAIN_PATH/bin:$PATH"`` line +if you want to use scons with self-installed version of Clang, but it may have +compatibility issues with riscv-gnu-toolchain. + +::: + +The command is similar in nature, but with some key changes. ``ccflags`` and +``linkflags`` append additional flags to the build. ``--sysroot`` points to +a folder simulating a Linux system, it contains all the headers, libraries, +and ``.so`` files Clang will use. ``--gcc-toolchain`` tells Clang where +the complete toolchain is, and ``-target riscv64-unknown-linux-gnu`` +indicates to Clang the target architecture, and OS we want to build for. + +If all went well, you should now see a ``bin`` directory, and within it, +a binary similar to the following: + +``` +Redot.linuxbsd.editor.rv64.llvm + +``` + +You can now copy this executable to your favorite RISC-V device, +then launch it there by double-clicking, which should bring up +the project manager. + +If you later decide to compile the export templates, copy the above +build command but change the value of ``target`` to ``template_debug`` for +a debug build, or ``template_release`` for a release build. + +## Using Clang and LLD for faster development + +You can also use Clang and LLD to build Redot. This has two upsides compared to +the default GCC + GNU ld setup: + +- LLD links Redot significantly faster compared to GNU ld or gold. This leads to + faster iteration times. +- Clang tends to give more useful error messages compared to GCC. + +To do so, install Clang and the ``lld`` package from your distribution's package manager +then use the following SCons command + +``` +scons platform=linuxbsd use_llvm=yes linker=lld + +``` + +After the build is completed, a new binary with a ``.llvm`` suffix will be +created in the ``bin/`` folder. + +It's still recommended to use GCC for production builds as they can be compiled using +link-time optimization, making the resulting binaries smaller and faster. + +If this error occurs + +``` +/usr/bin/ld: cannot find -l:libatomic.a: No such file or directory + +``` + +There are two solutions: + +- In your SCons command, add the parameter ``use_static_cpp=no``. +- Follow [these instructions](https://github.com/ivmai/libatomic_ops#installation-and-usage) to configure, build, and + install ``libatomic_ops``. Then, copy ``/usr/lib/libatomic_ops.a`` to ``/usr/lib/libatomic.a``, or create a soft link + to ``libatomic_ops`` by command ``ln -s /usr/lib/libatomic_ops.a /usr/lib/libatomic.a``. The soft link can ensure the + latest ``libatomic_ops`` will be used without the need to copy it every time when it is updated. + +## Using mold for faster development + +For even faster linking compared to LLD, you can use [mold](https://github.com/rui314/mold). +mold can be used with either GCC or Clang. + +As of January 2023, mold is not readily available in Linux distribution +repositories, so you will have to install its binaries manually. + +- Download mold binaries from its [releases page](https://github.com/rui314/mold/releases/latest). +- Extract the ``.tar.gz`` file, then move the extracted folder to a location such as ``.local/share/mold``. +- Add ``$HOME/.local/share/mold/bin`` to your user's ``PATH`` environment variable. + For example, you can add the following line at the end of your ``$HOME/.bash_profile`` file: + +``` +PATH="$HOME/.local/share/mold/bin:$PATH" + +``` + +- Open a new terminal (or run ``source "$HOME/.bash_profile"``), +then use the following SCons command when compiling Redot + +``` +scons platform=linuxbsd linker=mold + +``` + +## Using system libraries for faster development + +[Redot bundles the source code of various third-party libraries.](https://github.com/redot-engine/redot-engine/tree/master/thirdparty) +You can choose to use system versions of third-party libraries instead. +This makes the Redot binary faster to link, as third-party libraries are +dynamically linked. Therefore, they don't need to be statically linked +every time you build the engine (even on small incremental changes). + +However, not all Linux distributions have packages for third-party libraries +available (or they may not be up-to-date). + +Moving to system libraries can reduce linking times by several seconds on slow +CPUs, but it requires manual testing depending on your Linux distribution. Also, +you may not be able to use system libraries for everything due to bugs in the +system library packages (or in the build system, as this feature is less +tested). + +To compile Redot with system libraries, install these dependencies **on top** of the ones +listed in the [doc_compiling_for_linuxbsd_oneliners](doc_compiling_for_linuxbsd_oneliners): + + + + + +sudo apt-get update +sudo apt-get install -y \ + libembree-dev \ + libenet-dev \ + libfreetype-dev \ + libpng-dev \ + zlib1g-dev \ + libgraphite2-dev \ + libharfbuzz-dev \ + libogg-dev \ + libtheora-dev \ + libvorbis-dev \ + libwebp-dev \ + libmbedtls-dev \ + libminiupnpc-dev \ + libpcre2-dev \ + libzstd-dev \ + libsquish-dev \ + libicu-dev + + + + + +sudo dnf install -y \ + embree-devel \ + enet-devel \ + glslang-devel \ + graphite2-devel \ + harfbuzz-devel \ + libicu-devel \ + libsquish-devel \ + libtheora-devel \ + libvorbis-devel \ + libwebp-devel \ + libzstd-devel \ + mbedtls-devel \ + miniupnpc-devel + + + + + +After installing all required packages, use the following command to build Redot: + +``` +scons platform=linuxbsd builtin_embree=no builtin_enet=no builtin_freetype=no builtin_graphite=no builtin_harfbuzz=no builtin_libogg=no builtin_libpng=no builtin_libtheora=no builtin_libvorbis=no builtin_libwebp=no builtin_mbedtls=no builtin_miniupnpc=no builtin_pcre2=no builtin_zlib=no builtin_zstd=no + +``` + +On Debian stable, you will need to remove `builtin_embree=no` as the system-provided +Embree version is too old to work with Redot's latest `master` branch +(which requires Embree 4). + +You can view a list of all built-in libraries that have system alternatives by +running ``scons -h``, then looking for options starting with ``builtin_``. + +:::warning + +When using system libraries, the resulting library is **not** portable +across Linux distributions anymore. Do not use this approach for creating +binaries you intend to distribute to others, unless you're creating a +package for a Linux distribution. + +::: diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_macos.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_macos.md new file mode 100644 index 0000000..548de08 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_macos.md @@ -0,0 +1,267 @@ + +# Compiling for macOS + +.. highlight:: shell + +:::note + +This page describes how to compile macOS editor and export template binaries from source. +If you're looking to export your project to macOS instead, read [doc_exporting_for_macos](../../../tutorials/export/exporting_for_macos.md). + +::: + +## Requirements + +For compiling under macOS, the following is required: + +- [Python 3.8+](https://www.python.org/downloads/macos/). +- [SCons 4.0+](https://scons.org/pages/download.html) build system. +- [Xcode](https://apps.apple.com/us/app/xcode/id497799835) + (or the more lightweight Command Line Tools for Xcode). +- [Vulkan SDK](https://sdk.lunarg.com/sdk/download/latest/mac/vulkan-sdk.dmg) + for MoltenVK (macOS doesn't support Vulkan out of the box). + The latest Vulkan SDK version can be installed quickly by running + ``misc/scripts/install_vulkan_sdk_macos.sh`` within the Redot source repository. + +:::note +If you have [Homebrew](https://brew.sh/) installed, you can easily +install SCons using the following command + +``` +brew install scons + +``` + +Installing Homebrew will also fetch the Command Line Tools +for Xcode automatically if you don't have them already. + +Similarly, if you have [MacPorts](https://www.macports.org/) +installed, you can easily install SCons using the +following command + +``` +sudo port install scons +``` + +::: + +:::info +To get the Redot source code for compiling, see +[doc_getting_source](getting_source.md). + +For a general overview of SCons usage for Redot, see +[doc_introduction_to_the_buildsystem](introduction_to_the_buildsystem.md). + +::: + +## Compiling + +Start a terminal, go to the root directory of the engine source code. + +To compile for Intel (x86-64) powered Macs, use + +``` +scons platform=macos arch=x86_64 + +``` + +To compile for Apple Silicon (ARM64) powered Macs, use + +``` +scons platform=macos arch=arm64 + +``` + +To support both architectures in a single "Universal 2" binary, run the above two commands and then use ``lipo`` to bundle them together + +``` +lipo -create bin/Redot.macos.editor.x86_64 bin/Redot.macos.editor.arm64 -output bin/Redot.macos.editor.universal + +``` + +:::tip + +If you are compiling Redot to make changes or contribute to the engine, +you may want to use the SCons options ``dev_build=yes`` or ``dev_mode=yes``. +See [doc_introduction_to_the_buildsystem_development_and_production_aliases](doc_introduction_to_the_buildsystem_development_and_production_aliases) +for more info. + +::: + +If all goes well, the resulting binary executable will be placed in the +``bin/`` subdirectory. This executable file contains the whole engine and +runs without any dependencies. Executing it will bring up the Project +Manager. + +:::note +If you want to use separate editor settings for your own Redot builds +and official releases, you can enable +[doc_data_paths_self_contained_mode](doc_data_paths_self_contained_mode) by creating a file called +``._sc_`` or ``_sc_`` in the ``bin/`` folder. + +::: + +To create an ``.app`` bundle like in the official builds, you need to use the +template located in ``misc/dist/macos_tools.app``. Typically, for an optimized +editor binary built with ``dev_build=yes`` + +``` +cp -r misc/dist/macos_tools.app ./Redot.app +mkdir -p Redot.app/Contents/MacOS +cp bin/Redot.macos.editor.universal Redot.app/Contents/MacOS/Redot +chmod +x Redot.app/Contents/MacOS/Redot +codesign --force --timestamp --options=runtime --entitlements misc/dist/macos/editor.entitlements -s - Redot.app + +``` + +:::note + +If you are building the ``master`` branch, you also need to include support +for the MoltenVK Vulkan portability library. By default, it will be linked +statically from your installation of the Vulkan SDK for macOS. +You can also choose to link it dynamically by passing ``use_volk=yes`` and +including the dynamic library in your ``.app`` bundle + +``` +mkdir -p Redot.app/Contents/Frameworks +cp /macOS/lib/libMoltenVK.dylib Redot.app/Contents/Frameworks/libMoltenVK.dylib +``` + +::: + +## Running a headless/server build + +To run in *headless* mode which provides editor functionality to export +projects in an automated manner, use the normal build + +``` +scons platform=macos target=editor + +``` + +And then use the ``--headless`` command line argument + +``` +./bin/Redot.macos.editor.x86_64 --headless + +``` + +To compile a debug *server* build which can be used with +:ref:`remote debugging tools `, use + +``` +scons platform=macos target=template_debug + +``` + +To compile a release *server* build which is optimized to run dedicated game servers, +use + +``` +scons platform=macos target=template_release production=yes + +``` + +## Building export templates + +To build macOS export templates, you have to compile using the targets without +the editor: ``target=template_release`` (release template) and +``target=template_debug``. + +Official templates are *Universal 2* binaries which support both ARM64 and Intel +x86_64 architectures. + +- To support ARM64 (Apple Silicon) + Intel x86_64 + +``` +scons platform=macos target=template_debug arch=arm64 +scons platform=macos target=template_release arch=arm64 +scons platform=macos target=template_debug arch=x86_64 +scons platform=macos target=template_release arch=x86_64 generate_bundle=yes + +``` + +- To support ARM64 (Apple Silicon) only (smaller file size, but less compatible with older hardware) + +``` +scons platform=macos target=template_debug arch=arm64 +scons platform=macos target=template_release arch=arm64 generate_bundle=yes + +``` + +To create an ``.app`` bundle like in the official builds, you need to use the +template located in ``misc/dist/macos_template.app``. This process can be automated by using +the ``generate_bundle=yes`` option on the *last* SCons command used to build export templates +(so that all binaries can be included). This option also takes care of calling ``lipo`` to create +an *Universal 2* binary from two separate ARM64 and x86_64 binaries (if both were compiled beforehand). + +:::note + +You also need to include support for the MoltenVK Vulkan portability +library. By default, it will be linked statically from your installation of +the Vulkan SDK for macOS. You can also choose to link it dynamically by +passing ``use_volk=yes`` and including the dynamic library in your ``.app`` +bundle + +``` +mkdir -p macos_template.app/Contents/Frameworks +cp /macOS/libs/libMoltenVK.dylib macos_template.app/Contents/Frameworks/libMoltenVK.dylib + +``` + +In most cases, static linking should be preferred as it makes distribution +easier. The main upside of dynamic linking is that it allows updating +MoltenVK without having to recompile export templates. + +::: + +You can then zip the ``macos_template.app`` folder to reproduce the ``macos.zip`` +template from the official Redot distribution + +``` +zip -r9 macos.zip macos_template.app + +``` + +## Cross-compiling for macOS from Linux + +It is possible to compile for macOS in a Linux environment (and maybe also in +Windows using the Windows Subsystem for Linux). For that, you'll need to install +[OSXCross](https://github.com/tpoechtrager/osxcross) to be able to use macOS +as a target. First, follow the instructions to install it: + +Clone the [OSXCross repository](https://github.com/tpoechtrager/osxcross) +somewhere on your machine (or download a ZIP file and extract it somewhere), +e.g. + +``` +git clone --depth=1 https://github.com/tpoechtrager/osxcross.git "$HOME/osxcross" + +``` + +1. Follow the instructions to package the SDK: + https://github.com/tpoechtrager/osxcross#packaging-the-sdk +2. Follow the instructions to install OSXCross: + https://github.com/tpoechtrager/osxcross#installation + +After that, you will need to define the ``OSXCROSS_ROOT`` as the path to +the OSXCross installation (the same place where you cloned the +repository/extracted the zip), e.g. + +``` +export OSXCROSS_ROOT="$HOME/osxcross" + +``` + +Now you can compile with SCons like you normally would + +``` +scons platform=macos + +``` + +If you have an OSXCross SDK version different from the one expected by the SCons buildsystem, you can specify a custom one with the ``osxcross_sdk`` argument + +``` +scons platform=macos osxcross_sdk=darwin15 +``` diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_web.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_web.md new file mode 100644 index 0000000..dbf0706 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_web.md @@ -0,0 +1,155 @@ + +# Compiling for the Web + +:::info + +This page describes how to compile HTML5 editor and export template binaries from source. +If you're looking to export your project to HTML5 instead, read [doc_exporting_for_web](../../../tutorials/export/exporting_for_web.md). + +::: + +.. highlight:: shell + +## Requirements + +To compile export templates for the Web, the following is required: + +- [Emscripten 3.1.62+](https://emscripten.org). +- [Python 3.8+](https://www.python.org/). +- [SCons 4.0+](https://scons.org/pages/download.html) build system. + +:::info +To get the Redot source code for compiling, see +[doc_getting_source](getting_source.md). + +For a general overview of SCons usage for Redot, see +[doc_introduction_to_the_buildsystem](introduction_to_the_buildsystem.md). + +::: + +## Building export templates + +Before starting, confirm that ``emcc`` is available in your PATH. This is +usually configured by the Emscripten SDK, e.g. when invoking ``emsdk activate`` +and ``source ./emsdk_env.sh``/``emsdk_env.bat``. + +Open a terminal and navigate to the root directory of the engine source code. +Then instruct SCons to build the Web platform. Specify ``target`` as +either ``template_release`` for a release build or ``template_debug`` for a debug build + +``` +scons platform=web target=template_release +scons platform=web target=template_debug + +``` + +By default, the [JavaScriptBridge singleton](../../../tutorials/platform/web/javascript_bridge.md) will be built +into the engine. Official export templates also have the JavaScript singleton +enabled. Since ``eval()`` calls can be a security concern, the +``javascript_eval`` option can be used to build without the singleton + +``` +scons platform=web target=template_release javascript_eval=no +scons platform=web target=template_debug javascript_eval=no + +``` + +By default, WebWorker threads support is enabled. To disable it and only use a single thread, +the ``threads`` option can be used to build the web template without threads support + +``` +scons platform=web target=template_release threads=no +scons platform=web target=template_debug threads=no + +``` + +The engine will now be compiled to WebAssembly by Emscripten. Once finished, +the resulting file will be placed in the ``bin`` subdirectory. Its name is +``Redot.web.template_release.wasm32.zip`` for release or ``Redot.web.template_debug.wasm32.zip`` +for debug. + +Finally, rename the zip archive to ``web_release.zip`` for the +release template + +``` +mv bin/Redot.web.template_release.wasm32.zip bin/web_release.zip + +``` + +And ``web_debug.zip`` for the debug template + +``` +mv bin/Redot.web.template_debug.wasm32.zip bin/web_debug.zip + +``` + +## GDExtension + +The default export templates do not include GDExtension support for +performance and compatibility reasons. See the +[export page](doc_javascript_export_options) for more info. + +You can build the export templates using the option ``dlink_enabled=yes`` +to enable GDExtension support + +``` +scons platform=web dlink_enabled=yes target=template_release +scons platform=web dlink_enabled=yes target=template_debug + +``` + +Once finished, the resulting file will be placed in the ``bin`` subdirectory. +Its name will have ``_dlink`` added. + +Finally, rename the zip archives to ``web_dlink_release.zip`` and +``web_dlink_release.zip`` for the release template + +``` +mv bin/Redot.web.template_release.wasm32.dlink.zip bin/web_dlink_release.zip +mv bin/Redot.web.template_debug.wasm32.dlink.zip bin/web_dlink_debug.zip + +``` + +## Building the editor + +It is also possible to build a version of the Redot editor that can run in the +browser. The editor version is not recommended +over the native build. You can build the editor with + +``` +scons platform=web target=editor + +``` + +Once finished, the resulting file will be placed in the ``bin`` subdirectory. +Its name will be ``Redot.web.editor.wasm32.zip``. You can upload the +zip content to your web server and visit it with your browser to use the editor. + +Refer to the [export page](doc_javascript_export_options) for the web +server requirements. + +:::tip + +The Redot repository includes a +[Python script to host a local web server](https://raw.githubusercontent.com/Redot-engine/Redot-engine/master/platform/web/serve.py). +This can be used to test the web editor locally. + +After compiling the editor, extract the ZIP archive that was created in the +``bin/`` folder, then run the following command in the Redot repository +root: + +``` +# You may need to replace `python` with `python3` on some platforms. +python platform/web/serve.py + +``` + +This will serve the contents of the ``bin/`` folder and open the default web +browser automatically. In the page that opens, access ``Redot.editor.html`` +and you should be able to test the web editor this way. + +Note that for production use cases, this Python-based web server should not +be used. Instead, you should use an established web server such as Apache or +nginx. + +::: diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_windows.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_windows.md new file mode 100644 index 0000000..d5d1739 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_for_windows.md @@ -0,0 +1,545 @@ + +# Compiling for Windows + +.. highlight:: shell + +:::info + +This page describes how to compile Windows editor and export template binaries from source. +If you're looking to export your project to Windows instead, read [doc_exporting_for_windows](../../../tutorials/export/exporting_for_windows.md). + +::: + +## Requirements + +For compiling under Windows, the following is required: + +- A C++ compiler. Use one of the following: + + - [Visual Studio Community](https://www.visualstudio.com/vs/community/), + version 2019 or later. Visual Studio 2022 is recommended. + **Make sure to enable C++ in the list of workflows to install.** + If you've already installed Visual Studio without C++ support, run the installer + again; it should present you a **Modify** button. + Supports ``x86_64``, ``x86_32``, and ``arm64``. + - [MinGW-w64](https://mingw-w64.org/) with GCC can be used as an alternative to + Visual Studio. Be sure to install/configure it to use the ``posix`` thread model. + **Important:** When using MinGW to compile the ``master`` branch, you need GCC 9 or later. + Supports ``x86_64`` and ``x86_32`` only. + - [MinGW-LLVM](https://github.com/mstorsjo/llvm-mingw/releases) with clang can be used as + an alternative to Visual Studio and MinGW-w64. + Supports ``x86_64``, ``x86_32``, and ``arm64``. +- [Python 3.8+](https://www.python.org/downloads/windows/). + **Make sure to enable the option to add Python to the** ``PATH`` **in the installer.** +- [SCons 4.0+](https://scons.org/pages/download.html) build system. Using the + latest release is recommended, especially for proper support of recent Visual + Studio releases. + +:::note +If you have [Scoop](https://scoop.sh/) installed, you can easily +install MinGW and other dependencies using the following command + +``` +scoop install gcc python scons make mingw +``` + +::: + +:::note +If you have [MSYS2](https://www.msys2.org/) installed, you can easily +install MinGW and other dependencies using the following command + +``` +pacman -S mingw-w64-x86_64-python3-pip mingw-w64-x86_64-gcc \ + mingw-w64-i686-python3-pip mingw-w64-i686-gcc make + +``` + +For each MSYS2 MinGW subsystem, you should then run +`pip3 install scons` in its shell. + +::: + +:::info +To get the Redot source code for compiling, see +[doc_getting_source](getting_source.md). + +For a general overview of SCons usage for Redot, see +[doc_introduction_to_the_buildsystem](introduction_to_the_buildsystem.md). + +::: + +## Setting up SCons + +To install SCons, open the command prompt and run the following command + +``` +python -m pip install scons + +``` + +If you are prompted with the message +``Defaulting to user installation because normal site-packages is not +writeable``, you may have to run that command again using elevated +permissions. Open a new command prompt as an Administrator then run the command +again to ensure that SCons is available from the ``PATH``. + +To check whether you have installed Python and SCons correctly, you can +type ``python --version`` and ``scons --version`` into a command prompt +(``cmd.exe``). + +If the commands above don't work, make sure to add Python to your ``PATH`` +environment variable after installing it, then check again. +You can do so by running the Python installer again and enabling the option +to add Python to the ``PATH``. + +If SCons cannot detect your Visual Studio installation, it might be that your +SCons version is too old. Update it to the latest version with +``python -m pip install --upgrade scons``. + +## Downloading Redot's source + +Refer to [doc_getting_source](getting_source.md) for detailed instructions. + +The tutorial will assume from now on that you placed the source code in +``C:\Redot``. + +:::warning + +To prevent slowdowns caused by continuous virus scanning during compilation, +add the Redot source folder to the list of exceptions in your antivirus +software. + +For Windows Defender, hit the `Windows` key, type "Windows Security" +then hit `Enter`. Click on **Virus & threat protection** on the left +panel. Under **Virus & threat protection settings** click on **Manage Settings** +and scroll down to **Exclusions**. Click **Add or remove exclusions** then +add the Redot source folder. + +::: + +## Compiling + +### Selecting a compiler + +SCons will automatically find and use an existing Visual Studio installation. +If you do not have Visual Studio installed, it will attempt to use +MinGW instead. If you already have Visual Studio installed and want to +use MinGW-w64, pass ``use_mingw=yes`` to the SCons command line. Note that MSVC +builds cannot be performed from the MSYS2 or MinGW shells. Use either +``cmd.exe`` or PowerShell instead. If you are using MinGW-LLVM, pass both +``use_mingw=yes`` and ``use_llvm=yes`` to the SCons command line. + +:::tip + +During development, using the Visual Studio compiler is usually a better +idea, as it links the Redot binary much faster than MinGW. However, MinGW +can produce more optimized binaries using link-time optimization (see +below), making it a better choice for production use. This is particularly +the case for the GDScript VM which performs much better with MinGW compared +to MSVC. Therefore, it's recommended to use MinGW to produce builds that you +distribute to players. + +All official Redot binaries are built in +[custom containers](https://github.com/redot-engine/build-containers) +using MinGW. + +::: + +### Running SCons + +After opening a command prompt, change to the root directory of +the engine source code (using ``cd``) and type: + +```doscon +C:\Redot> scons platform=windows + +``` + +:::note +When compiling with multiple CPU threads, SCons may warn about +pywin32 being missing. You can safely ignore this warning. + +::: + +:::tip + +If you are compiling Redot to make changes or contribute to the engine, +you may want to use the SCons options ``dev_build=yes`` or ``dev_mode=yes``. +See [doc_introduction_to_the_buildsystem_development_and_production_aliases](doc_introduction_to_the_buildsystem_development_and_production_aliases) +for more info. + +::: + +If all goes well, the resulting binary executable will be placed in +``C:\Redot\bin\`` with the name ``Redot.windows.editor.x86_32.exe`` or +``Redot.windows.editor.x86_64.exe``. By default, SCons will build a binary matching +your CPU architecture, but this can be overridden using ``arch=x86_64``, +``arch=x86_32``, or ``arch=arm64``. + +This executable file contains the whole engine and runs without any +dependencies. Running it will bring up the Project Manager. + +:::tip +If you are compiling Redot for production use, you can +make the final executable smaller and faster by adding the +SCons option ``production=yes``. This enables additional compiler +optimizations and link-time optimization. + +LTO takes some time to run and requires up to 30 GB of available RAM +while compiling (depending on toolchain). If you're running out of memory +with the above option, use ``production=yes lto=none`` or ``production=yes lto=thin`` +(LLVM only) for a lightweight but less effective form of LTO. + +::: + +:::note +If you want to use separate editor settings for your own Redot builds +and official releases, you can enable +[doc_data_paths_self_contained_mode](doc_data_paths_self_contained_mode) by creating a file called +``._sc_`` or ``_sc_`` in the ``bin/`` folder. + +::: + +## Compiling with support for Direct3D 12 + +By default, builds of Redot do not contain support for the Direct3D 12 graphics +API. + +You can install the required dependencies by running +``python misc/scripts/install_d3d12_sdk_windows.py`` +in the Redot source repository. After running this script, add the ``d3d12=yes`` +SCons option to enable Direct3D 12 support. This will use the default paths for +the various dependencies, which match the ones used in the script. + +You can find the detailed steps below if you wish to set up dependencies +manually, but the above script handles everything for you (including the +optional PIX and Agility SDK components). + +- [Redot-nir-static library](https://github.com/redot-engine/redot-engine-nir-static/releases/). + We compile the Mesa libraries you will need into a static library. Download it + anywhere, unzip it and remember the path to the unzipped folder, you will + need it below. + +:::note +You can optionally build the Redot-nir-static libraries yourself with +the following steps: + +1. Install the Python package [mako](https://www.makotemplates.org) + which is needed to generate some files. +2. Clone the [Redot-nir-static](https://github.com/redot-engine/redot-engine-nir-static) + directory and navigate to it. +3. Run the following + +``` +git submodule update --init +./update_mesa.sh +scons + +``` + + If you are building with MinGW-w64, add ``use_mingw=yes`` to the ``scons`` + command, you can also specify build architecture using ``arch={architecture}``. + If you are building with MinGW-LLVM, add both ``use_mingw=yes`` and + ``use_llvm=yes`` to the ``scons`` command. + + If you are building with MinGW and the binaries are not located in + the ``PATH``, add ``mingw_prefix="/path/to/mingw"`` to the ``scons`` + command. + + Mesa static library should be built using the same compiler and the + same CRT (if you are building with MinGW) you are using for building + Redot. + +::: + +Optionally, you can compile with the following for additional features: + +- [PIX](https://devblogs.microsoft.com/pix/download) is a performance tuning + and debugging application for Direct3D12 applications. If you compile-in + support for it, you can get much more detailed information through PIX that + will help you optimize your game and troubleshoot graphics bugs. To use it, + download the WinPixEventRuntime package. You will be taken to a NuGet package + page where you can click "Download package" to get it. Once downloaded, change + the file extension to .zip and unzip the file to some path. +- [Agility SDK](https://devblogs.microsoft.com/directx/directx12agility) can + be used to provide access to the latest Direct3D 12 features without relying + on driver updates. To use it, download the latest Agility SDK package. You + will be taken to a NuGet package page where you can click "Download package" + to get it. Once downloaded, change the file extension to .zip and unzip the + file to some path. + +:::note +If you use a preview version of the Agility SDK, remember to enable +developer mode in Windows; otherwise it won't be used. + +::: + +:::note +If you want to use a PIX with MinGW build, navigate to PIX runtime +directory and use the following commands to generate import library + +``` +# For x86-64: +gendef ./bin/x64/WinPixEventRuntime.dll +dlltool --machine i386:x86-64 --no-leading-underscore -d WinPixEventRuntime.def -D WinPixEventRuntime.dll -l ./bin/x64/libWinPixEventRuntime.a + +# For ARM64: +gendef ./bin/ARM64/WinPixEventRuntime.dll +dlltool --machine arm64 --no-leading-underscore -d WinPixEventRuntime.def -D WinPixEventRuntime.dll -l ./bin/ARM64/libWinPixEventRuntime.a +``` + +::: + +When building Redot, you will need to tell SCons to use Direct3D 12 and where to +look for the additional libraries: + +```doscon +C:\Redot> scons platform=windows d3d12=yes mesa_libs=<...> + +``` + +Or, with all options enabled: + +```doscon +C:\Redot> scons platform=windows d3d12=yes mesa_libs=<...> agility_sdk_path=<...> pix_path=<...> + +``` + +:::note +For the Agility SDK's DLLs you have to explicitly choose the kind of +workflow. Single-arch is the default (DLLs copied to ``bin/``). If you +pass ``agility_sdk_multi_arch=yes`` to SCons, you'll opt-in for +multi-arch. DLLs will be copied to the appropriate ``bin/<arch>/`` +subdirectories and at runtime the right one will be loaded. + +::: + +## Compiling with ANGLE support + +ANGLE provides a translation layer from OpenGL ES 3.x to Direct3D 11 and can be used +to improve support for the Compatibility renderer on some older GPUs with outdated +OpenGL drivers and on Windows for ARM. + +By default, Redot is built with dynamically linked ANGLE, you can use it by placing +``libEGL.dll`` and ``libGLESv2.dll`` alongside the executable. + +:::note +You can use dynamically linked ANGLE with export templates as well, rename +aforementioned DLLs to ``libEGL.{architecture}.dll`` and ``libGLESv2.{architecture}.dll`` +and place them alongside export template executables, and libraries will +be automatically copied during the export process. + +::: + +To compile Redot with statically linked ANGLE: + +- Download pre-built static libraries from [Redot-angle-static library](https://github.com/redot-engine/redot-engine-angle-static/releases), and unzip them. +- When building Redot, add ``angle_libs={path}`` to tell SCons where to look for the ANGLE libraries + +``` +scons platform=windows angle_libs=<...> + +``` + +:::note +You can optionally build the Redot-angle-static libraries yourself with +the following steps: + +1. Clone the [Redot-angle-static](https://github.com/redot-engine/redot-engine-angle-static) + directory and navigate to it. +2. Run the following command + +``` +git submodule update --init +./update_angle.sh +scons + +``` + + If you are buildng with MinGW, add ``use_mingw=yes`` to the command, + you can also specify build architecture using ``arch={architecture}``. + If you are building with MinGW-LLVM, add both ``use_mingw=yes`` and + ``use_llvm=yes`` to the ``scons`` command. + + If you are building with MinGW and the binaries are not located in + the ``PATH``, add ``mingw_prefix="/path/to/mingw"`` to the ``scons`` + command. + + ANGLE static library should be built using the same compiler and the + same CRT (if you are building with MinGW) you are using for building + Redot. + +::: + +## Development in Visual Studio + +Using an IDE is not required to compile Redot, as SCons takes care of everything. +But if you intend to do engine development or debugging of the engine's C++ code, +you may be interested in configuring a code editor or an IDE. + +Folder-based editors don't require any particular setup to start working with Redot's +codebase. To edit projects with Visual Studio they need to be set up as a solution. + +You can create a Visual Studio solution via SCons by running SCons with +the ``vsproj=yes`` parameter, like this + +``` +scons platform=windows vsproj=yes + +``` + +You will be able to open Redot's source in a Visual Studio solution now, +and able to build Redot using Visual Studio's **Build** button. + +:::info +See [doc_configuring_an_ide_vs](../configuring_an_ide/visual_studio.md) for further details. + +::: + +## Cross-compiling for Windows from other operating systems + +If you are a Linux or macOS user, you need to install +[MinGW-w64](https://www.mingw-w64.org/), which typically comes in 32-bit +and 64-bit variants, or [MinGW-LLVM](https://github.com/mstorsjo/llvm-mingw/releases), +which comes as a single archive for all target architectures. +The package names may differ based on your distribution, here are some known ones: + +| **Arch Linux** | `pacman -Sy mingw-w64` | +| --- | --- | +| **Debian** / **Ubuntu** | `apt install mingw-w64` | +| **Fedora** | `dnf install mingw64-gcc-c++ mingw64-winpthreads-static \ mingw32-gcc-c++ mingw32-winpthreads-static` | +| **macOS** | `brew install mingw-w64` | +| **Mageia** | `urpmi mingw64-gcc-c++ mingw64-winpthreads-static \ mingw32-gcc-c++ mingw32-winpthreads-static` | + +Before attempting the compilation, SCons will check for +the following binaries in your ``PATH`` environment variable + +``` +# for MinGW-w64 +i686-w64-mingw32-gcc +x86_64-w64-mingw32-gcc + +# for MinGW-LLVM +aarch64-w64-mingw32-clang +i686-w64-mingw32-clang +x86_64-w64-mingw32-clang + +``` + +If the binaries are not located in the ``PATH`` (e.g. ``/usr/bin``), +you can define the following environment variable to give a hint to +the build system + +``` +export MINGW_PREFIX="/path/to/mingw" + +``` + +Where ``/path/to/mingw`` is the path containing the ``bin`` directory where +``i686-w64-mingw32-gcc`` and ``x86_64-w64-mingw32-gcc`` are located (e.g. +``/opt/mingw-w64`` if the binaries are located in ``/opt/mingw-w64/bin``). + +To make sure you are doing things correctly, executing the following in +the shell should result in a working compiler (the version output may +differ based on your system) + +``` +${MINGW_PREFIX}/bin/x86_64-w64-mingw32-gcc --version +# x86_64-w64-mingw32-gcc (GCC) 13.2.0 + +``` + +:::note +If you are building with MinGW-LLVM, add ``use_llvm=yes`` to the ``scons`` command. + +::: + +:::note +When cross-compiling for Windows using MinGW-w64, keep in mind only +``x86_64`` and ``x86_32`` architectures are supported. MinGW-LLVM supports +``arm64`` as well. Be sure to specify the right ``arch=`` option when +invoking SCons if building from a different architecture. + +::: + +### Troubleshooting + +Cross-compiling from some Ubuntu versions may lead to +[this bug](https://github.com/redot-engine/redot-engine/issues/9258), +due to a default configuration lacking support for POSIX threading. + +You can change that configuration following those instructions, +for 64-bit + +``` +sudo update-alternatives --config x86_64-w64-mingw32-gcc + +sudo update-alternatives --config x86_64-w64-mingw32-g++ + + +``` + +And for 32-bit + +``` +sudo update-alternatives --config i686-w64-mingw32-gcc + +sudo update-alternatives --config i686-w64-mingw32-g++ + + +``` + +## Creating Windows export templates + +Windows export templates are created by compiling Redot without the editor, +with the following flags: + +```doscon +C:\Redot> scons platform=windows target=template_debug arch=x86_32 +C:\Redot> scons platform=windows target=template_release arch=x86_32 +C:\Redot> scons platform=windows target=template_debug arch=x86_64 +C:\Redot> scons platform=windows target=template_release arch=x86_64 +C:\Redot> scons platform=windows target=template_debug arch=arm64 +C:\Redot> scons platform=windows target=template_release arch=arm64 + +``` + +If you plan on replacing the standard export templates, copy these to the +following location, replacing ``<version>`` with the version identifier +(such as ``4.2.1.stable`` or ``4.3.dev``): + +```none +%APPDATA%\Redot\export_templates\\ + +``` + +With the following names + +``` +windows_debug_x86_32_console.exe +windows_debug_x86_32.exe +windows_debug_x86_64_console.exe +windows_debug_x86_64.exe +windows_debug_arm64_console.exe +windows_debug_arm64.exe +windows_release_x86_32_console.exe +windows_release_x86_32.exe +windows_release_x86_64_console.exe +windows_release_x86_64.exe +windows_release_arm64_console.exe +windows_release_arm64.exe + +``` + +However, if you are using custom modules or custom engine code, you +may instead want to configure your binaries as custom export templates +here: + +![Image](img/wintemplates.webp) + +Select matching architecture in the export config. + +You don't need to copy them in this case, just reference the resulting +files in the ``bin\`` directory of your Redot source folder, so the next +time you build, you will automatically have the custom templates referenced. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_dotnet.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_dotnet.md new file mode 100644 index 0000000..04ebb9d --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_dotnet.md @@ -0,0 +1,231 @@ + +# Compiling with .NET + +.. highlight:: shell + +## Requirements + +- [.NET SDK 8.0+](https://dotnet.microsoft.com/download) + + You can use ``dotnet --info`` to check which .NET SDK versions are installed. + +## Enable the .NET module + +:::note +C# support for Redot has historically used the +[Mono](https://www.mono-project.com/) runtime instead of the +[.NET Runtime](https://github.com/dotnet/runtime) and internally +many things are still named ``mono`` instead of ``dotnet`` or +otherwise referred to as ``mono``. + +::: + +By default, the .NET module is disabled when building. To enable it, add the +option ``module_mono_enabled=yes`` to the SCons command line, while otherwise +following the instructions for building the desired Redot binaries. + +## Generate the glue + +Parts of the sources of the managed libraries are generated from the ClassDB. +These source files must be generated before building the managed libraries. +They can be generated by any .NET-enabled Redot editor binary by running it with +the parameters ``--headless --generate-mono-glue`` followed by the path to an +output directory. +This path must be ``modules/mono/glue`` in the Redot directory + +``` + --headless --generate-mono-glue modules/mono/glue + +``` + +This command will tell Redot to generate the C# bindings for the Redot API at +``modules/mono/glue/RedotSharp/RedotSharp/Generated``, and the C# bindings for +the editor tools at ``modules/mono/glue/RedotSharp/RedotSharpEditor/Generated``. +Once these files are generated, you can build Redot's managed libraries for all +the desired targets without having to repeat this process. + +``<Redot_binary>`` refers to the editor binary you compiled with the .NET module +enabled. Its exact name will differ based on your system and configuration, but +should be of the form ``bin/Redot.<platform>.editor.<arch>.mono``, e.g. +``bin/Redot.linuxbsd.editor.x86_64.mono`` or +``bin/Redot.windows.editor.x86_32.mono.exe``. Be especially aware of the +**.mono** suffix! If you've previously compiled Redot without .NET support, you +might have similarly named binaries without this suffix. These binaries can't be +used to generate the .NET glue. + +:::note +The glue sources must be regenerated every time the ClassDB-registered +API changes. That is, for example, when a new method is registered to +the scripting API or one of the parameters of such a method changes. +Redot will print an error at startup if there is an API mismatch +between ClassDB and the glue sources. + +::: + +## Building the managed libraries + +Once you have generated the .NET glue, you can build the managed libraries with +the ``build_assemblies.py`` script + +``` +./modules/mono/build_scripts/build_assemblies.py --Redot-output-dir=./bin + +``` + +If everything went well, the ``RedotSharp`` directory, containing the managed +libraries, should have been created in the ``bin`` directory. + +:::note +By default, all development builds share a version number, which can +cause some issues with caching of the NuGet packages. To solve this +issue either use ``Redot_VERSION_STATUS`` to give every build a unique +version or delete ``RedotNuGetFallbackFolder`` after every build to +clear the package cache. + +::: + +Unlike "classical" Redot builds, when building with the .NET module enabled +(and depending on the target platform), a data directory may be created both +for the editor and for exported projects. This directory is important for +proper functioning and must be distributed together with Redot. +More details about this directory in +[Data directory](compiling_with_dotnet_data_directory). + +### Build Platform + +Provide the `[--Redot-platform=](platform)` argument to control for which +platform specific the libraries are built. Omit this argument to build for the +current system. + +This currently only controls the inclusion of the support for Visual Studio as +an external editor, the libraries are otherwise identical. + +### NuGet packages + +The API assemblies, source generators, and custom MSBuild project SDK are +distributed as NuGet packages. This is all transparent to the user, but it can +make things complicated during development. + +In order to use Redot with a development version of those packages, a local +NuGet source must be created where MSBuild can find them. + +First, pick a location for the local NuGet source. If you don't have a +preference, create an empty directory at one of these recommended locations: + +- On Windows, ``C:\Users\<username>\MyLocalNugetSource`` +- On Linux, \*BSD, etc., ``~/MyLocalNugetSource`` + +This path is referred to later as ``<my_local_source>``. + +After picking a directory, run this .NET CLI command to configure NuGet to use +your local source: + +``` +dotnet nuget add source --name MyLocalNugetSource + +``` + +When you run the ``build_assemblies.py`` script, pass ``<my_local_source>`` to +the ``--push-nupkgs-local`` option: + +``` +./modules/mono/build_scripts/build_assemblies.py --Redot-output-dir ./bin --push-nupkgs-local + +``` + +This option ensures the packages will be added to the specified local NuGet +source and that conflicting versions of the package are removed from the NuGet +cache. It's recommended to always use this option when building the C# solutions +during development to avoid mistakes. + +### Building without depending on deprecated features (NO_DEPRECATED) + +When building Redot without deprecated classes and functions, i.e. the ``deprecated=no`` +argument for scons, the managed libraries must also be built without dependencies to deprecated code. +This is done by passing the ``--no-deprecated`` argument: + +``` +./modules/mono/build_scripts/build_assemblies.py --Redot-output-dir ./bin --push-nupkgs-local --no-deprecated + +``` + +### Double Precision Support (REAL_T_IS_DOUBLE) + +When building Redot with double precision support, i.e. the ``precision=double`` +argument for scons, the managed libraries must be adjusted to match by passing +the ``--precision=double`` argument: + +``` +./modules/mono/build_scripts/build_assemblies.py --Redot-output-dir ./bin --push-nupkgs-local --precision=double + +``` + +## Examples + +### Example (Windows) + +``` +# Build editor binary +scons platform=windows target=editor module_mono_enabled=yes +# Build export templates +scons platform=windows target=template_debug module_mono_enabled=yes +scons platform=windows target=template_release module_mono_enabled=yes + +# Generate glue sources +bin/Redot.windows.editor.x86_64.mono --headless --generate-mono-glue modules/mono/glue +# Build .NET assemblies +./modules/mono/build_scripts/build_assemblies.py --Redot-output-dir=./bin --Redot-platform=windows + +``` + +### Example (Linux, \*BSD) + +``` +# Build editor binary +scons platform=linuxbsd target=editor module_mono_enabled=yes +# Build export templates +scons platform=linuxbsd target=template_debug module_mono_enabled=yes +scons platform=linuxbsd target=template_release module_mono_enabled=yes + +# Generate glue sources +bin/Redot.linuxbsd.editor.x86_64.mono --headless --generate-mono-glue modules/mono/glue +# Generate binaries +./modules/mono/build_scripts/build_assemblies.py --Redot-output-dir=./bin --Redot-platform=linuxbsd + +``` + +## Data directory + +The data directory is a dependency for Redot binaries built with the .NET module +enabled. It contains important files for the correct functioning of Redot. It +must be distributed together with the Redot executable. + +### Editor + +The name of the data directory for the Redot editor will always be +``RedotSharp``. This directory contains an ``Api`` subdirectory with the Redot +API assemblies and a ``Tools`` subdirectory with the tools required by the +editor, like the ``RedotTools`` assemblies and its dependencies. + +On macOS, if the Redot editor is distributed as a bundle, the ``RedotSharp`` +directory may be placed in the ``<bundle_name>.app/Contents/Resources/`` +directory inside the bundle. + +### Export templates + +The data directory for exported projects is generated by the editor during the +export. It is named ``data_<APPNAME>_<ARCH>``, where ``<APPNAME>`` is the +application name as specified in the project setting ``application/config/name`` +and ``<ARCH>`` is the current architecture of the export. + +In the case of multi-architecture exports multiple such data directories will be +generated. + +## Command-line options + +The following is the list of command-line options available when building with +the .NET module: + +- **module_mono_enabled**\ =yes | **no** + + - Build Redot with the .NET module enabled. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_script_encryption_key.md b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_script_encryption_key.md new file mode 100644 index 0000000..d4616b5 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/compiling_with_script_encryption_key.md @@ -0,0 +1,113 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Compiling with PCK encryption key + +.. highlight:: shell + +The export dialog gives you the option to encrypt your PCK file with a 256-bit +AES key when releasing your project. This will make sure your scenes, scripts +and other resources are not stored in plain text and can not easily be ripped +by some script kiddie. + +Of course, the key needs to be stored in the binary, but if it's compiled, +optimized and without symbols, it would take some effort to find it. + +For this to work, you need to build the export templates from source, +with that same key. + +:::warning + +This will **not** work if you use official, precompiled export templates. +It is absolutely **required** to compile your own export templates to use +PCK encryption. + +::: + +:::warning + +By default, Android exports store assets directly in the APK file and +aren't affected by PCK encryption. To use PCK encryption on Android, enable +**APK expansion** in the export options. + +::: + +## Step by step + +1. Generate a 256-bit AES key in hexadecimal format. You can use the aes-256-cbc variant from + [this service](https://asecuritysite.com/encryption/keygen). + + Alternatively, you can generate it yourself using + [OpenSSL](https://www.openssl.org/) command-line tools: + +``` +openssl rand -hex 32 > Redot.gdkey + +``` + + The output in ``Redot.gdkey`` should be similar to: + +``` +# NOTE: Do not use the key below! Generate your own key instead. +aeb1bc56aaf580cc31784e9c41551e9ed976ecba10d315db591e749f3f64890f + +``` + + You can generate the key without redirecting the output to a file, but + that way you can minimize the risk of exposing the key. + +2. Set this key as environment variable in the console that you will use to + compile Redot, like this: + + + + + +```bash +export SCRIPT_AES256_ENCRYPTION_KEY="your_generated_key" + +``` + + + + + +```bat +set SCRIPT_AES256_ENCRYPTION_KEY=your_generated_key + +``` + + + + + +```bat +$env:SCRIPT_AES256_ENCRYPTION_KEY="your_generated_key" +``` + + + + + +3. Compile Redot export templates and set them as custom export templates + in the export preset options. + +4. Set the encryption key in the **Encryption** tab of the export preset: + +![Image](img/encryption_key.png) + +5. Add filters for the files/folders to encrypt. **By default**, include filters + are empty and **nothing will be encrypted**. + +6. Export the project. The project should run with the files encrypted now. + +## Troubleshooting + +If you get an error like below, it means the key wasn't properly included in +your Redot build. Redot is encrypting PCK file during export, but can't read +it at runtime. + +``` +ERROR: open_and_parse: Condition "String::md5(md5.digest) != String::md5(md5d)" is true. Returning: ERR_FILE_CORRUPT + At: core/io/file_access_encrypted.cpp:103 +``` diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/cross-compiling_for_ios_on_linux.md b/Redot-Documentation/docs/Contributing/Development/compiling/cross-compiling_for_ios_on_linux.md new file mode 100644 index 0000000..0a833cd --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/cross-compiling_for_ios_on_linux.md @@ -0,0 +1,125 @@ + +# Cross-compiling for iOS on Linux + +.. highlight:: shell + +The procedure for this is somewhat complex and requires a lot of steps, +but once you have the environment properly configured you can +compile Redot for iOS anytime you want. + +## Disclaimer + +While it is possible to compile for iOS on a Linux environment, Apple is +very restrictive about the tools to be used (especially hardware-wise), +allowing pretty much only their products to be used for development. So +this is **not official**. However, in 2010 Apple said they relaxed some of the +[App Store review guidelines](https://developer.apple.com/app-store/review/guidelines/) +to allow any tool to be used, as long as the resulting binary does not +download any code, which means it should be OK to use the procedure +described here and cross-compiling the binary. + +## Requirements + +- [XCode with the iOS SDK](https://developer.apple.com/download/all/?q=Xcode) + (you must be logged into an Apple ID to download Xcode). +- [Clang >= 3.5](https://clang.llvm.org) for your development + machine installed and in the ``PATH``. It has to be version >= 3.5 + to target ``arm64`` architecture. +- [xar](https://mackyle.github.io/xar/) and [pbzx](https://github.com/NiklasRosenstein/pbzx) + (required to extract the ``.xip`` archive Xcode comes in). + + - For building xar and pbzx, you may want to follow + [this guide](https://gist.github.com/phracker/1944ce190e01963c550566b749bd2b54). + +- [cctools-port](https://github.com/tpoechtrager/cctools-port) + for the needed build tools. The procedure for building is quite + peculiar and is described below. + + - This also has some extra dependencies: automake, autogen, libtool. + +## Configuring the environment + +### Preparing the SDK + +Extract the Xcode ``.xip`` file you downloaded from Apple's developer website: + +``` +mkdir xcode +xar -xf /path/to/Xcode_X.x.xip -C xcode +pbzx -n Content | cpio -i + +[...] +######### Blocks + +``` + +Note that for the commands below, you will need to replace the version (``x.x``) +with whatever iOS SDK version you're using. If you don't know your iPhone SDK +version, you can see the JSON file inside of +``Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs``. + +Extract the iOS SDK: + +``` +export IOS_SDK_VERSION="x.x" +mkdir -p iPhoneSDK/iPhoneOS${IOS_SDK_VERSION}.sdk +cp -r xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/* iPhoneSDK/iPhoneOS${IOS_SDK_VERSION}.sdk +cp -r xcode/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/* iPhoneSDK/iPhoneOS${IOS_SDK_VERSION}.sdk/usr/include/c++ +fusermount -u xcode + +``` + +Pack the SDK so that cctools can use it: + +``` +cd iPhoneSDK +tar -cf - * | xz -9 -c - > iPhoneOS${IOS_SDK_VERSION}.sdk.tar.xz + +``` + +### Toolchain + +Build cctools: + +``` +git clone https://github.com/tpoechtrager/cctools-port.git +cd cctools-port/usage_examples/ios_toolchain +./build.sh /path/iPhoneOS${IOS_SDK_VERSION}.sdk.tar.xz arm64 + +``` + +Copy the tools to a nicer place. Note that the SCons scripts for +building will look under ``usr/bin`` inside the directory you provide +for the toolchain binaries, so you must copy to such subdirectory, akin +to the following commands: + +``` +mkdir -p "$HOME/iostoolchain/usr" +cp -r target/bin "$HOME/iostoolchain/usr/" + +``` + +Now you should have the iOS toolchain binaries in +``$HOME/iostoolchain/usr/bin``. + +## Compiling Redot for iPhone + +Once you've done the above steps, you should keep two things in your +environment: the built toolchain and the iPhoneOS SDK directory. Those +can stay anywhere you want since you have to provide their paths to the +SCons build command. + +For the iPhone platform to be detected, you need the ``OSXCROSS_IOS`` +environment variable defined to anything. + +``` +export OSXCROSS_IOS="anything" + +``` + +Now you can compile for iPhone using SCons like the standard Redot +way, with some additional arguments to provide the correct paths: + +``` +scons platform=ios arch=arm64 target=template_release IOS_SDK_PATH="/path/to/iPhoneSDK" IOS_TOOLCHAIN_PATH="/path/to/iostoolchain" ios_triple="arm-apple-darwin11-" +``` diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/getting_source.md b/Redot-Documentation/docs/Contributing/Development/compiling/getting_source.md new file mode 100644 index 0000000..c273d6e --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/getting_source.md @@ -0,0 +1,66 @@ + +# Getting the source + +.. highlight:: shell + +## Downloading the Redot source code + +Before [getting into the SCons build system](introduction_to_the_buildsystem.md) +and compiling Redot, you need to actually download the Redot source code. + +The source code is available on [GitHub](https://github.com/redot-engine/redot-engine) +and while you can manually download it via the website, in general you want to +do it via the ``git`` version control system. + +If you are compiling in order to make contributions or pull requests, you should +follow the instructions from the [Pull Request workflow](../../Workflow/pr_workflow.md). + +If you don't know much about ``git`` yet, there are a great number of +[tutorials](https://git-scm.com/book) available on various websites. + +In general, you need to install ``git`` and/or one of the various GUI clients. + +Afterwards, to get the latest development version of the Redot source code +(the unstable ``master`` branch), you can use ``git clone``. + +If you are using the ``git`` command line client, this is done by entering +the following in a terminal: + +``` +git clone https://github.com/redot-engine/redot-engine.git +# You can add the --depth 1 argument to omit the commit history (shallow clone). +# A shallow clone is faster, but not all Git operations (like blame) will work. + +``` + +For any stable release, visit the [release page](https://github.com/redot-engine/redot-engine/releases) +and click on the link for the release you want. +You can then download and extract the source from the download link on the page. + +With ``git``, you can also clone a stable release by specifying its branch or tag +after the ``--branch`` (or just ``-b``) argument + +``` +# Clone the continuously maintained stable branch (`4.3` as of writing). +git clone https://github.com/redot-engine/Redot.git -b 4.3 + +# Clone the `4.3-stable` tag. This is a fixed revision that will never change. +git clone https://github.com/redot-engine/Redot.git -b 4.3-stable + +# After cloning, optionally go to a specific commit. +# This can be used to access the source code at a specific point in time, +# e.g. for development snapshots, betas and release candidates. +cd Redot +git checkout f4af8201bac157b9d47e336203d3e8a8ef729de2 + +``` + +The [maintenance branches](https://github.com/redot-engine/redot-engine/branches/all) +are used to release further patches on each minor version. + +You can get the source code for each release and pre-release in ``.tar.xz`` format from +[Redotengine/Redot-builds on GitHub](https://github.com/redot-engine/Redot-builds/releases). +This lacks version control information but has a slightly smaller download size. + +After downloading the Redot source code, +you can [continue to compiling Redot](introduction_to_the_buildsystem.md). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/introduction_to_the_buildsystem.md b/Redot-Documentation/docs/Contributing/Development/compiling/introduction_to_the_buildsystem.md new file mode 100644 index 0000000..78dfd5e --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/introduction_to_the_buildsystem.md @@ -0,0 +1,507 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Introduction to the buildsystem + +.. highlight:: shell + +Redot is a primarily C++ project and it [uses the SCons build system.](doc_faq_why_scons) +We love SCons for how maintainable and easy to set up it makes our buildsystem. And thanks to +that compiling Redot from source can be as simple as running + +``` +scons + +``` + +This produces an editor build for your current platform, operating system, and architecture. +You can change what gets built by specifying a target, a platform, and/or an architecture. +For example, to build an export template used for running exported games, you can run + +``` +scons target=template_release + +``` + +If you plan to debug or develop the engine, then you might want to enable the ``dev_build`` +option to enable dev-only debugging code + +``` +scons dev_build=yes + +``` + +Following sections in the article will explain these and other universal options in more detail. But +before you can compile Redot, you need to install a few prerequisites. Please refer to the platform +documentation to learn more: + +- [doc_compiling_for_android](compiling_for_android.md) +- [doc_compiling_for_ios](compiling_for_ios.md) +- [doc_compiling_for_linuxbsd](compiling_for_linuxbsd.md) +- [doc_compiling_for_macos](compiling_for_macos.md) +- [doc_compiling_for_web](compiling_for_web.md) +- [doc_compiling_for_windows](compiling_for_windows.md) + +These articles cover in great detail both how to setup your environment to compile Redot on a specific +platform, and how to compile for that platform. Please feel free to go back and forth between them and +this article to reference platform-specific and universal configuration options. + +## Using multi-threading + +The build process may take a while, depending on how powerful your system is. By default, Redot's +SCons setup is configured to use all CPU threads but one (to keep the system responsive during +compilation). If you want to adjust how many CPU threads SCons will use, use the `[-j](threads)` +parameter to specify how many threads will be used for the build. + +Example for using 4 threads + +``` +scons -j4 + +``` + +## Platform selection + +Redot's build system will begin by detecting the platforms it can build +for. If not detected, the platform will simply not appear on the list of +available platforms. The build requirements for each platform are +described in the rest of this tutorial section. + +SCons is invoked by just calling ``scons``. If no platform is specified, +SCons will detect the target platform automatically based on the host platform. +It will then start building for the target platform right away. + +To list the available target platforms, use ``scons platform=list`` + +``` +scons platform=list +scons: Reading SConscript files ... +The following platforms are available: + + android + javascript + linuxbsd + server + windows + +Please run SCons again and select a valid platform: platform= + +``` + +To build for a platform (for example, ``linuxbsd``), run with the ``platform=`` +(or ``p=`` to make it short) argument: + +``` +scons platform=linuxbsd + +``` + +## Resulting binary + +The resulting binaries will be placed in the ``bin/`` subdirectory, +generally with this naming convention + +``` +Redot..[.dev][.double].[.][.] + +``` + +For the previous build attempt, the result would look like this: + +```console +ls bin +bin/Redot.linuxbsd.editor.x86_64 + +``` + +This means that the binary is for Linux *or* \*BSD (*not* both), is not optimized, has the +whole editor compiled in, and is meant for 64 bits. + +A Windows binary with the same configuration will look like this: + +```doscon +C:\Redot> dir bin/ +Redot.windows.editor.64.exe + +``` + +Copy that binary to any location you like, as it contains the Project Manager, +editor and all means to execute the game. However, it lacks the data to export +it to the different platforms. For that the export templates are needed (which +can be either downloaded from [redotengine.org](https://redotengine.org/), or +you can build them yourself). + +Aside from that, there are a few standard options that can be set in all +build targets, and which will be explained below. + +## Target + +Target controls if the editor is contained and debug flags are used. +All builds are optimized. Each mode means: + +- ``target=editor``: Build with editor, optimized, with debugging code (defines: ``TOOLS_ENABLED``, ``DEBUG_ENABLED``, ``-O2``/``/O2``) +- ``target=template_debug``: Build with C++ debugging symbols (defines: ``DEBUG_ENABLED``, ``-O2``/``/O2``) +- ``target=template_release``: Build without symbols (defines: ``-O3``/``/O2``) + +The editor is enabled by default in all PC targets (Linux, Windows, macOS), +disabled for everything else. Disabling the editor produces a binary that can +run projects but does not include the editor or the Project Manager. + +``` +scons platform= target=editor/template_debug/template_release + +``` + +## Development and production aliases + +When creating builds for development (running debugging/[profiling](../debugging/using_cpp_profilers.md) +tools), you often have different goals compared to production builds +(making binaries as fast and small as possible). + +Redot provides two aliases for this purpose: + +- ``dev_mode=yes`` is an alias for ``verbose=yes warnings=extra werror=yes + tests=yes``. This enables warnings-as-errors behavior (similar to Redot's + continuous integration setup) and also builds :ref:`unit tests + <doc_unit_testing>` so you can run them locally. +- ``production=yes`` is an alias for ``use_static_cpp=yes debug_symbols=no + lto=auto``. Statically linking libstdc++ allows for better binary portability + when compiling for Linux. This alias also enables link-time optimization when + compiling for Linux, Web and Windows with MinGW, but keeps LTO disabled when + compiling for macOS, iOS or Windows with MSVC. This is because LTO on those + platforms is very slow to link or has issues with the generated code. + +You can manually override options from those aliases by specifying them on the +same command line with different values. For example, you can use ``scons +production=yes debug_symbols=yes`` to create production-optimized binaries with +debugging symbols included. + +## Dev build + +:::note + +``dev_build`` should **not** be confused with ``dev_mode``, which is an +alias for several development-related options (see above). + +::: + +When doing engine development the ``dev_build`` option can be used together +with ``target`` to enable dev-specific code. ``dev_build`` defines ``DEV_ENABLED``, +disables optimization (``-O0``/``/0d``), enables generating debug symbols, and +does not define ``NDEBUG`` (so ``assert()`` works in thirdparty libraries). + +``` +scons platform= dev_build=yes + +``` + +This flag appends the ``.dev`` suffix (for development) to the generated +binary name. + +:::info + +There are additional SCons options to enable *sanitizers*, which are tools +you can enable at compile-time to better debug certain engine issues. +See [doc_using_sanitizers](../debugging/using_sanitizers.md) for more information. + +::: + +## Debugging symbols + +By default, ``debug_symbols=no`` is used, which means **no** debugging symbols +are included in compiled binaries. Use ``debug_symbols=yes`` to include debug +symbols within compiled binaries, which allows debuggers and profilers to work +correctly. Debugging symbols are also required for Redot's crash stacktraces to +display with references to source code files and lines. + +The downside is that debugging symbols are large files (significantly larger +than the binaries themselves). As a result, official binaries currently do not +include debugging symbols. This means you need to compile Redot yourself to have +access to debugging symbols. + +When using ``debug_symbols=yes``, you can also use +``separate_debug_symbols=yes`` to put debug information in a separate file with +a ``.debug`` suffix. This allows distributing both files independently. Note +that on Windows, when compiling with MSVC, debugging information is *always* +written to a separate ``.pdb`` file regardless of ``separate_debug_symbols``. + +:::tip + +Use the `[strip](path/to/binary)` command to remove debugging symbols from +a binary you've already compiled. + +::: + +## Optimization level + +Several compiler optimization levels can be chosen from: + +- ``optimize=speed_trace`` *(default when targeting non-Web platforms)*: Favors + execution speed at the cost of larger binary size. Optimizations may sometimes + negatively impact debugger usage (stack traces may be less accurate. If this + occurs to you, use ``optimize=debug`` instead. +- ``optimize=speed``: Favors even more execution speed, at the cost of even + larger binary size compared to ``optimize=speed_trace``. Even less friendly to + debugging compared to ``optimize=debug``, as this uses the most aggressive + optimizations available. +- ``optimize=size`` *(default when targeting the Web platform)*: Favors small + binaries at the cost of slower execution speed. +- ``optimize=debug``: Only enables optimizations that do not impact debugging in + any way. This results in faster binaries than ``optimize=none``, but slower + binaries than ``optimize=speed_trace``. +- ``optimize=none``: Do not perform any optimization. This provides the fastest + build times, but the slowest execution times. +- ``optimize=custom`` *(advanced users only)*: Do not pass optimization + arguments to the C/C++ compilers. You will have to pass arguments manually + using the ``cflags``, ``ccflags`` and ``cxxflags`` SCons options. + +## Architecture + +The ``arch`` option is meant to control the CPU or OS version intended to run the +binaries. It is focused mostly on desktop platforms and ignored everywhere +else. + +Supported values for the ``arch`` option are **auto**, **x86_32**, **x86_64**, +**arm32**, **arm64**, **rv64**, **ppc32**, **ppc64** and **wasm32**. + +``` +scons platform= arch={auto|x86_32|x86_64|arm32|arm64|rv64|ppc32|ppc64|wasm32} + +``` + +This flag appends the value of ``arch`` to resulting binaries when +relevant. The default value ``arch=auto`` detects the architecture +that matches the host platform. + +## Custom modules + +It's possible to compile modules residing outside of Redot's directory +tree, along with the built-in modules. + +A ``custom_modules`` build option can be passed to the command line before +compiling. The option represents a comma-separated list of directory paths +containing a collection of independent C++ modules that can be seen as C++ +packages, just like the built-in ``modules/`` directory. + +For instance, it's possible to provide both relative, absolute, and user +directory paths containing such modules: + +``` +scons custom_modules="../modules,/abs/path/to/modules,~/src/Redot_modules" + +``` + +:::note + +If there's any custom module with the exact directory name as a built-in +module, the engine will only compile the custom one. This logic can be used +to override built-in module implementations. + +::: + +:::info + +[doc_custom_modules_in_cpp](../core_and_modules/custom_modules_in_cpp.md) + +::: + +## Cleaning generated files + +Sometimes, you may encounter an error due to generated files being present. You +can remove them by using `[scons --clean](options)`, where ``<options>`` is the +list of build options you've used to build Redot previously. + +Alternatively, you can use ``git clean -fixd`` which will clean build artifacts +for all platforms and configurations. Beware, as this will remove all untracked +and ignored files in the repository. Don't run this command if you have +uncommitted work! + +## Other build options + +There are several other build options that you can use to configure the +way Redot should be built (compiler, debug options, etc.) as well as the +features to include/disable. + +Check the output of ``scons --help`` for details about each option for +the version you are willing to compile. + +### Overriding the build options + +#### Using a file + +The default ``custom.py`` file can be created at the root of the Redot Engine +source to initialize any SCons build options passed via the command line: + +```python +optimize = "size" +module_mono_enabled = "yes" +use_llvm = "yes" +extra_suffix = "game_title" + +``` + +You can also disable some of the built-in modules before compiling, saving some +time it takes to build the engine. See [doc_optimizing_for_size](optimizing_for_size.md) page for more details. + +:::info + +You can use the online +[Redot build options generator](https://Redot-build-options-generator.github.io/) +to generate a ``custom.py`` file containing SCons options. +You can then save this file and place it at the root of your Redot source directory. + +::: + +Another custom file can be specified explicitly with the ``profile`` command +line option, both overriding the default build configuration: + +```shell +scons profile=path/to/custom.py + +``` + +:::note +Build options set from the file can be overridden by the command line +options. + +::: + +It's also possible to override the options conditionally: + +```python +import version + +# Override options specific for Redot 3.x and 4.x versions. +if version.major == 3: + pass +elif version.major == 4: + pass + +``` + +#### Using the SCONSFLAGS + +``SCONSFLAGS`` is an environment variable which is used by the SCons to set the +options automatically without having to supply them via the command line. + +For instance, you may want to force a number of CPU threads with the +aforementioned ``-j`` option for all future builds: + + + + + +```bash +export SCONSFLAGS="-j4" + +``` + + + + + +```bat +set SCONSFLAGS=-j4 + +``` + + + + + +```powershell +$env:SCONSFLAGS="-j4" +``` + + + + + +#### SCU (single compilation unit) build + +Regular builds tend to be bottlenecked by including large numbers of headers +in each compilation translation unit. Primarily to speed up development (rather +than for production builds), Redot offers a "single compilation unit" build +(aka "Unity / Jumbo" build). + +For the folders accelerated by this option, multiple ``.cpp`` files are +compiled in each translation unit, so headers can be shared between multiple +files, which can dramatically decrease build times. + +To perform an SCU build, use the ``scu_build=yes`` SCons option. + +:::note +When developing a Pull Request using SCU builds, be sure to make a +regular build prior to submitting the PR. This is because SCU builds +by nature include headers from earlier ``.cpp`` files in the +translation unit, therefore won't catch all the includes you will +need in a regular build. The CI will catch these errors, but it will +usually be faster to catch them on a local build on your machine. + +::: + +## Export templates + +Official export templates are downloaded from the Redot Engine site: +[redotengine.org](https://redotengine.org/). However, you might want +to build them yourself (in case you want newer ones, you are using custom +modules, or simply don't trust your own shadow). + +If you download the official export templates package and unzip it, you +will notice that most files are optimized binaries or packages for each +platform: + +```none +android_debug.apk +android_release.apk +android_source.zip +ios.zip +linux_debug.arm32 +linux_debug.arm64 +linux_debug.x86_32 +linux_debug.x86_64 +linux_release.arm32 +linux_release.arm64 +linux_release.x86_32 +linux_release.x86_64 +macos.zip +version.txt +web_debug.zip +web_dlink_debug.zip +web_dlink_nothreads_debug.zip +web_dlink_nothreads_release.zip +web_dlink_release.zip +web_nothreads_debug.zip +web_nothreads_release.zip +web_release.zip +windows_debug_x86_32_console.exe +windows_debug_x86_32.exe +windows_debug_x86_64_console.exe +windows_debug_x86_64.exe +windows_debug_arm64_console.exe +windows_debug_arm64.exe +windows_release_x86_32_console.exe +windows_release_x86_32.exe +windows_release_x86_64_console.exe +windows_release_x86_64.exe +windows_release_arm64_console.exe +windows_release_arm64.exe + +``` + +To create those yourself, follow the instructions detailed for each +platform in this same tutorial section. Each platform explains how to +create its own template. + +The ``version.txt`` file should contain the corresponding Redot version +identifier. This file is used to install export templates in a version-specific +directory to avoid conflicts. For instance, if you are building export templates +for Redot 3.1.1, ``version.txt`` should contain ``3.1.1.stable`` on the first +line (and nothing else). This version identifier is based on the ``major``, +``minor``, ``patch`` (if present) and ``status`` lines of the +[version.py file in the Redot Git repository](https://github.com/redot-engine/redot-engine/blob/master/version.py). + +If you are developing for multiple platforms, macOS is definitely the most +convenient host platform for cross-compilation, since you can cross-compile for +every target. Linux and Windows come in second place, +but Linux has the advantage of being the easier platform to set this up. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/compiling/optimizing_for_size.md b/Redot-Documentation/docs/Contributing/Development/compiling/optimizing_for_size.md new file mode 100644 index 0000000..3f40f96 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/compiling/optimizing_for_size.md @@ -0,0 +1,323 @@ + +# Optimizing a build for size + +.. highlight:: shell + +## Rationale + +Sometimes, it is desired to optimize a build for size rather than speed. +This means not compiling unused functions from the engine, as well as using +specific compiler flags to aid on decreasing build size. +Common situations include creating builds for mobile and Web platforms. + +This tutorial aims to give an overview on different methods to create +a smaller binary. Before continuing, it is recommended to read the previous tutorials +on compiling Redot for each platform. + +The options below are listed from the most important (greatest size savings) +to the least important (lowest size savings). + +## Stripping binaries + +- **Space savings:** Very high +- **Difficulty:** Easy +- **Performed in official builds:** Yes + +If you build Windows (MinGW), Linux or macOS binaries from source, remember to +strip debug symbols from binaries by installing the ``strip`` package from your +distribution then running: + +``` +strip path/to/Redot.binary + +``` + +On Windows, ``strip.exe`` is included in most MinGW toolchain setups. + +This will reduce the size of compiled binaries by a factor between 5× and 10×. +The downside is that crash backtraces will no longer provide accurate information +(which is useful for troubleshooting the cause of a crash). +[C++ profilers](../debugging/using_cpp_profilers.md) will also no longer be able to display +function names (this does not affect the built-in GDScript profiler). + +:::note + +The above command will not work on Windows binaries compiled with MSVC +and platforms such as Android and Web. Instead, pass ``debug_symbols=no`` +on the SCons command line when compiling. + +::: + +## Compiling with link-time optimization + +- **Space savings:** High +- **Difficulty:** Easy +- **Performed in official builds:** Yes + +Enabling link-time optimization produces more efficient binaries, both in +terms of performance and file size. It works by eliminating duplicate +template functions and unused code. It can currently be used with the GCC +and MSVC compilers: + +``` +scons target=template_release lto=full + +``` + +Linking becomes much slower and more RAM-consuming with this option, +so it should be used only for release builds: + +- When compiling the ``master`` branch, you need to have at least 8 GB of RAM + available for successful linking with LTO enabled. +- When compiling the ``3.x`` branch, you need to have at least 6 GB of RAM + available for successful linking with LTO enabled. + +## Optimizing for size instead of speed + +- **Space savings:** High +- **Difficulty:** Easy +- **Performed in official builds:** Yes, but only for web builds + +Redot 3.1 onwards allows compiling using size optimizations (instead of speed). +To enable this, set the ``optimize`` flag to ``size``: + +``` +scons target=template_release optimize=size + +``` + +Some platforms such as WebAssembly already use this mode by default. + +## Disabling advanced text server + +- **Space savings:** High +- **Difficulty:** Easy +- **Performed in official builds:** No + +By default, Redot uses an advanced text server with the support for the +following features: + +- Right-to-left typesetting and complex scripts, required to write languages + such as Arabic and Hebrew. +- Font ligatures and OpenType features (such as small capitals, fractions and + slashed zero). + +Redot provides a fallback text server that isn't compiled by default. This text +server can be used as a lightweight alternative to the default advanced text +server: + +``` +scons target=template_release module_text_server_adv_enabled=no module_text_server_fb_enabled=yes + +``` + +If you only intend on supporting Latin, Greek and Cyrillic-based languages in +your project, the fallback text server should suffice. + +This fallback text server can also process large amounts of text more quickly +than the advanced text server. This makes the fallback text server a good fit +for mobile/web projects. + +:::note + +Remember to always pass ``module_text_server_fb_enabled=yes`` when using +``module_text_server_adv_enabled=no``. Otherwise, the compiled binary won't +contain any text server, which means no text will be displayed at all when +running the project. + +::: + +## Disabling 3D + +- **Space savings:** Moderate +- **Difficulty:** Easy +- **Performed in official builds:** No + +For 2D games, having the whole 3D engine available usually makes no sense. +Because of this, there is a build flag to disable it: + +``` +scons target=template_release disable_3d=yes + +``` + +Tools must be disabled in order to use this flag, as the editor is not designed +to operate without 3D support. Without it, the binary size can be reduced +by about 15%. + +:::note + +Disabling 3D support also disables all navigation. This includes 2D navigation, +as it uses the 3D navigation system internally. + +::: + +## Disabling advanced GUI objects + +- **Space savings:** Moderate +- **Difficulty:** Easy +- **Performed in official builds:** No + +Most small games don't require complex GUI controls such as Tree, ItemList, +TextEdit or GraphEdit. They can be disabled using a build flag: + +``` +scons target=template_release disable_advanced_gui=yes + +``` + +This is everything that will be disabled: + +- [class_AcceptDialog](/docs/Classes/AcceptDialog) +- [class_CharFXTransform](/docs/Classes/CharFXTransform) +- [class_CodeEdit](/docs/Classes/CodeEdit) +- [class_CodeHighlighter](/docs/Classes/CodeHighlighter) +- [class_ColorPickerButton](/docs/Classes/ColorPickerButton) +- [class_ColorPicker](/docs/Classes/ColorPicker) +- [class_ConfirmationDialog](/docs/Classes/ConfirmationDialog) +- [class_FileDialog](/docs/Classes/FileDialog) +- [class_GraphEdit](/docs/Classes/GraphEdit) +- [class_GraphElement](/docs/Classes/GraphElement) +- [class_GraphFrame](/docs/Classes/GraphFrame) +- [class_GraphNode](/docs/Classes/GraphNode) +- [class_HSplitContainer](/docs/Classes/HSplitContainer) +- [class_MenuBar](/docs/Classes/MenuBar) +- [class_MenuButton](/docs/Classes/MenuButton) +- [class_OptionButton](/docs/Classes/OptionButton) +- [class_PopupMenu](/docs/Classes/PopupMenu) (will make all popup menus unavailable in code for classes that use them, + like [class_LineEdit](/docs/Classes/LineEdit), even though those classes are still available) +- [class_RichTextEffect](/docs/Classes/RichTextEffect) +- [class_RichTextLabel](/docs/Classes/RichTextLabel) +- [class_SpinBox](/docs/Classes/SpinBox) +- [class_SplitContainer](/docs/Classes/SplitContainer) +- [class_SubViewportContainer](/docs/Classes/SubViewportContainer) +- [class_SyntaxHighlighter](/docs/Classes/SyntaxHighlighter) +- [class_TextEdit](/docs/Classes/TextEdit) +- [class_TreeItem](/docs/Classes/TreeItem) +- [class_Tree](/docs/Classes/Tree) +- [class_VSplitContainer](/docs/Classes/VSplitContainer) + +## Disabling unwanted modules + +- **Space savings:** Very low to moderate depending on modules +- **Difficulty:** Medium to hard depending on modules +- **Performed in official builds:** No + +A lot of Redot's functions are offered as modules. +You can see a list of modules with the following command: + +``` +scons --help + +``` + +The list of modules that can be disabled will appear, together with all +build options. If you are working on a simple 2D game, you could disable +a lot of them: + +``` +scons target=template_release module_basis_universal_enabled=no module_bmp_enabled=no module_camera_enabled=no module_csg_enabled=no module_dds_enabled=no module_enet_enabled=no module_gridmap_enabled=no module_hdr_enabled=no module_jsonrpc_enabled=no module_ktx_enabled=no module_mbedtls_enabled=no module_meshoptimizer_enabled=no module_minimp3_enabled=no module_mobile_vr_enabled=no module_msdfgen_enabled=no module_multiplayer_enabled=no module_noise_enabled=no module_navigation_enabled=no module_ogg_enabled=no module_openxr_enabled=no module_raycast_enabled=no module_regex_enabled=no module_squish_enabled=no module_svg_enabled=no module_tga_enabled=no module_theora_enabled=no module_tinyexr_enabled=no module_upnp_enabled=no module_vhacd_enabled=no module_vorbis_enabled=no module_webrtc_enabled=no module_websocket_enabled=no module_webxr_enabled=no module_zip_enabled=no + +``` + +If this proves not to work for your use case, you should review the list of +modules and see which ones you actually still need for your game (e.g. you might +want to keep networking-related modules, regex support, +``minimp3``/``ogg``/``vorbis`` to play music, or ``theora`` to play videos). + +Alternatively, you can supply a list of disabled modules by creating +``custom.py`` at the root of the source, with the contents similar to the +following: + +```python +module_basis_universal_enabled = "no" +module_bmp_enabled = "no" +module_camera_enabled = "no" +module_csg_enabled = "no" +module_dds_enabled = "no" +module_enet_enabled = "no" +module_gridmap_enabled = "no" +module_hdr_enabled = "no" +module_jsonrpc_enabled = "no" +module_ktx_enabled = "no" +module_mbedtls_enabled = "no" +module_meshoptimizer_enabled = "no" +module_minimp3_enabled = "no" +module_mobile_vr_enabled = "no" +module_msdfgen_enabled= "no" +module_multiplayer_enabled = "no" +module_noise_enabled = "no" +module_navigation_enabled = "no" +module_ogg_enabled = "no" +module_openxr_enabled = "no" +module_raycast_enabled = "no" +module_regex_enabled = "no" +module_squish_enabled = "no" +module_svg_enabled = "no" +module_tga_enabled = "no" +module_theora_enabled = "no" +module_tinyexr_enabled = "no" +module_upnp_enabled = "no" +module_vhacd_enabled = "no" +module_vorbis_enabled = "no" +module_webrtc_enabled = "no" +module_websocket_enabled = "no" +module_webxr_enabled = "no" +module_zip_enabled = "no" + +``` + +:::info + +[doc_overriding_build_options](doc_overriding_build_options). + +::: + +## Optimizing the distribution of your project + +### Desktop + +:::note + +This section is only relevant when distributing the files on a desktop +platform that doesn't perform its own compression or packing. As such, this +advice is relevant when you distribute ZIP archives on itch.io or GitHub +Releases. + +Platforms like Steam already apply their own compression scheme, so you +don't need to create a ZIP archive to distribute files in the first place. + +::: + +As an aside, you can look into optimizing the distribution of your project itself. +This can be done even without recompiling the export template. + +[7-Zip](https://7-zip.org/) can be used to create ZIP archives that are more +efficient than usual, while remaining compatible with every ZIP extractor +(including Windows' own built-in extractor). ZIP size reduction in a large +project can reach dozens of megabytes compared to a typical ZIP compressor, +although average savings are in the 1-5 MB range. Creating this ZIP archive will +take longer than usual, but it will extract just as fast as any other ZIP +archive. + +When using the 7-Zip GUI, this is done by creating a ZIP archive with the Ultra +compression mode. When using the command line, this is done using the following +command: + +``` +7z a -mx9 my_project.zip folder_containing_executable_and_pck + +``` + +### Web + +Enabling gzip or Brotli compression for all file types from the web export +(especially the ``.wasm`` and ``.pck``) can reduce the download size +significantly, leading to faster loading times, especially on slow connections. + +Creating precompressed gzip or Brotli files with a high compression level can be +even more efficient, as long as the web server is configured to serve those +files when they exist. When supported, Brotli should be preferred over gzip as +it has a greater potential for file size reduction. + +See [doc_exporting_for_web_serving_the_files](doc_exporting_for_web_serving_the_files) for instructions. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/android_studio.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/android_studio.md new file mode 100644 index 0000000..a955b2b --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/android_studio.md @@ -0,0 +1,103 @@ + +# Android Studio + +[Android Studio](https://developer.android.com/studio) is a free +IDE for Android development made by [Google](https://about.google/) and [JetBrains](https://www.jetbrains.com/). +It's based on [IntelliJ IDEA](https://www.jetbrains.com/idea/) and has a +feature-rich editor which supports Java and C/C++. It can be used to +work on Redot's core engine as well as the Android platform codebase. + +## Importing the project + +- From the Android Studio's welcome window select **Open**. + +
+ Android Studio's welcome window. +
+ Android Studio's welcome window. +
+
+ +- Navigate to ``<Redot root directory>/platform/android/java`` and select the ``settings.gradle`` file. +- Android Studio will import and index the project. + +## Android Studio project layout + +The project is organized using [Android Studio's modules](https://developer.android.com/studio/projects#ApplicationModules): + +- ``lib`` module: + - Located under ``<Redot root directory>/platform/android/java/lib``, this is a **library module** that organizes + the Redot java and native code and make it available as a reusable dependency / artifact. + - The artifact generated by this module is made available for other Android modules / projects to use as a dependency, via [MavenCentral](https://repo1.maven.org/maven2/org/Redotengine/Redot/). + +- ``editor`` module: + - Located under ``<Redot root directory>/platform/android/java/editor``, this is an **application module** that holds + the source code for the Android port of the Redot Editor. + - This module has a dependency on the ``lib`` module. + +- ``app`` module: + - Located under ``<Redot root directory>/platform/android/java/app``, this is an **application module** that holds + the source code for the Android build templates. + - This module has a dependency on the ``lib`` module. + +## Building & debugging the editor module + +- To build the ``editor`` module: + - Select the [Run/Debug Configurations drop down](https://developer.android.com/studio/run/rundebugconfig#running) and select ``editor``. + +
+ +
+ + - Select **Run > Run 'editor'** from the top menu or [click the Run icon](https://developer.android.com/studio/run/rundebugconfig#running). +- To debug the ``editor`` module: + - Open the **Build Variants** window using **View > Tools Windows > Build Variants** from the top menu. + - In the **Build Variants** window, make sure that in the **Active Build Variant** column, the ``:editor`` entry is set to **dev**. + +
+ +
+ + - Open the **Run/Debug Configurations** window by clicking on **Run > Edit Configurations...** on the top menu. + - In the **Run/Debug Configurations** window, select the ``editor`` entry, and under **Debugger** make sure the **Debug Type** is set to ``Dual (Java + Native)`` + +
+ +
+ + - Select **Run > Debug 'editor'** from the top menu or [click the Debug icon](https://developer.android.com/studio/run/rundebugconfig#running). + +## Building & debugging the app module + +The ``app`` module requires the presence of a Redot project in its ``assets`` directory (``<Redot root directory>/platform/android/java/app/assets``) to run. +This is usually handled by the Redot Editor during the export process. +While developing in Android Studio, it's necessary to manually add a Redot project under that directory to replicate the export process. +Once that's done, you can follow the instructions below to run/debug the ``app`` module: + +- To build the ``app`` module: + - Select the [Run/Debug Configurations drop down](https://developer.android.com/studio/run/rundebugconfig#running) and select ``app``. + +
+ +
+ + - Select **Run > Run 'app'** from the top menu or [click the Run icon](https://developer.android.com/studio/run/rundebugconfig#running). +- To debug the ``app`` module: + - Open the **Build Variants** window using **View > Tools Windows > Build Variants** from the top menu. + - In the **Build Variants** window, make sure that in the **Active Build Variant** column, the ``:app`` entry is set to **dev**. + +
+ +
+ + - Open the **Run/Debug Configurations** window by clicking on **Run > Edit Configurations...** on the top menu. + - In the **Run/Debug Configurations** window, select the ``app`` entry, and under **Debugger** make sure the **Debug Type** is set to ``Dual (Java + Native)`` + +
+ +
+ + - Select **Run > Debug 'app'** from the top menu or [click the Debug icon](https://developer.android.com/studio/run/rundebugconfig#running). + +If you run into any issues, ask for help in +[Redot's Android dev channel](https://chat.redotengine.org/channel/android). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/clion.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/clion.md new file mode 100644 index 0000000..f9223f4 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/clion.md @@ -0,0 +1,94 @@ + +# CLion + +[CLion](https://www.jetbrains.com/clion/) is a commercial +[JetBrains](https://www.jetbrains.com/) IDE for C++. + +## Importing the project + +CLion can import a project's [compilation database file](https://clang.llvm.org/docs/JSONCompilationDatabase.html), commonly named ``compile_commands.json``. To generate the compilation database file, open the terminal, change to the Redot root directory, and run: + +``` +scons compiledb=yes + +``` + +Then, open the Redot root directory with CLion. CLion will import the compilation database, index the codebase, and provide autocompletion and other advanced code navigation and refactoring functionality. + +## Compiling and debugging the project + +CLion does not support compiling and debugging Redot via SCons out of the box. This can be achieved by creating a custom build target and run configuration in CLion. Before creating a custom build target, you must [compile Redot](toc-devel-compiling) once on the command line, to generate the Redot executable. Open the terminal, change into the Redot root directory, and execute: + +``` +scons dev_build=yes + +``` + +To add a custom build target that invokes SCons for compilation: + +- Open CLion and navigate to **Preferences > Build, Execution, Deployment > Custom Build Targets** + +
+ +
+ +- Click **Add target** and give the target a name, e.g. ``Redot debug``. + +
+ +
+ +- Click **...** next to the **Build:** selectbox, then click the **+** button in the **External Tools** dialog to add a new external tool. + +
+ +
+ +- Give the tool a name, e.g. ``Build Redot debug``, set **Program** to ``scons``, set **Arguments** to the compilation settings you want (see [compiling Redot](toc-devel-compiling)), and set the **Working directory** to ``$ProjectFileDir$``, which equals the Redot root directory. Click **OK** to create the tool. + +:::note +CLion does not expand shell commands like ``scons -j$(nproc)``. Use concrete values instead, e.g. ``scons -j8``. + +::: + +
+ +
+ +- Back in the **External Tools** dialog, click the **+** again to add a second external tool for cleaning the Redot build via SCons. Give the tool a name, e.g. ``Clean Redot debug``, set **Program** to ``scons``, set **Arguments** to ``-c`` (which will clean the build), and set the **Working directory** to ``$ProjectFileDir$``. Click **OK** to create the tool. + +
+ +
+ +- Close the **External Tools** dialog. In the **Custom Build Target** dialog for the custom ``Redot debug`` build target, select the **Build Redot debug** tool from the **Build** select box, and select the **Clean Redot debug** tool from the **Clean** select box. Click **OK** to create the custom build target. + +
+ +
+ +- In the main IDE window, click **Add Configuration**. + +
+ +
+ +- In the **Run/Debug Configuration** dialog, click **Add new...**, then select **Custom Build Application** to create a new custom run/debug configuration. + +
+ +
+ +- Give the run/debug configuration a name, e.g. ``Redot debug``, select the ``Redot debug`` custom build target as the **Target**. Select the Redot executable in the ``bin/`` folder as the **Executable**, and set the **Program arguments** to ``--editor --path path-to-your-project/``, where ``path-to-your-project/`` should be a path pointing to an existing Redot project. If you omit the ``--path`` argument, you will only be able to debug the Redot Project Manager window. Click **OK** to create the run/debug configuration. + +
+ +
+ +You can now build, run, debug, profile, and Valgrind check the Redot editor via the run configuration. + +
+ +
+ +When playing a scene, the Redot editor will spawn a separate process. You can debug this process in CLion by going to **Run > Attach to process...**, typing ``Redot``, and selecting the Redot process with the highest **pid** (process ID), which will usually be the running project. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/code_blocks.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/code_blocks.md new file mode 100644 index 0000000..8d02717 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/code_blocks.md @@ -0,0 +1,122 @@ + +# Code::Blocks + +[Code::Blocks](https://codeblocks.org/) is a free, open-source, cross-platform IDE. + +## Creating a new project + +From Code::Blocks' main screen, click **Create a new project** or select **File > New > Project...**. + +
+ +
+ +In the **New from template** window, from **Projects**, select **Empty project**, and click **Go**. + +
+ +
+ +Click Next, to pass the welcome to the new empty project wizard. + +
+ +
+ +The project file should be created in the root of the cloned project folder. To achieve this, first, ensure that the **Project title** is the same as the folder name that Redot was cloned into. Unless you cloned the project into a folder with a different name, this will be ``Redot``. + +Second, ensure that the **Folder to create project in** is the folder you ran the Git clone command from, not the ``Redot`` project folder. Confirm that the **Resulting filename** field will create the project file in the root of the cloned project folder. + +
+ +
+ +The compiler and configuration settings are managed through **SCons** and will be configured later. However, it's worth deselecting the **Create "Release" configuration** option; so only a single build target is created before clicking **Finish**. + +
+ +
+ +## Configuring the build + +The first step is to change the project properties. Right-click on the new project and select **Properties...**. + +
+ +
+ +Check the **This is a custom Makefile** property. Click OK to save the changes. + +
+ +
+ +The next step is to change the build options. Right-click on the new project and select **Build Options...**. + +
+ +
+ +Select the **"Make" commands** tab and remove all the existing commands for all the build targets. For each build target enter the **SCons** command for creating the desired build in the **Build project/target** field. The minimum is ``scons``. For details on the **SCons** build options, see [doc_introduction_to_the_buildsystem](../compiling/introduction_to_the_buildsystem.md). It's also useful to add the ``scons --clean`` command in the **Clean project/target** field to the project's default commands. + +If you're using Windows, all the commands need to be preceded with ``cmd /c`` to initialize the command interpreter. + +
+ +
+ +
+ +
+ +Windows example: + +
+ +
+ +Code::Blocks should now be configured to build Redot; so either select **Build > Build**, click the gear button, or press `Ctrl + F9`. + +## Configuring the run + +Once **SCons** has successfully built the desired target, reopen the project **Properties...** and select the **Build targets** tab. In the **Output filename** field, browse to the ``bin`` folder and select the compiled file. + +Deselect the **Auto-generate filename prefix** and **Auto-generate filename extension** options. + +
+ +
+ +Code::Blocks should now be configured to run your compiled Redot executable; so either select **Build > Run**, click the green arrow button, or press `Ctrl + F10`. + +There are two additional points worth noting. First, if required, the **Execution working dir** field can be used to test specific projects, by setting it to the folder containing the ``project.Redot`` file. Second, the **Build targets** tab can be used to add and remove build targets for working with and creating different builds. + +## Adding files to the project + +To add all the Redot code files to the project, right-click on the new project and select **Add files recursively...**. + +
+ +
+ +It should automatically select the project folder; so simply click **Open**. By default, all code files are included, so simply click **OK**. + +
+ +
+ +## Code style configuration + +Before editing any files, remember that all code needs to comply with the [doc_code_style_guidelines](../code_style_guidelines.md). One important difference with Redot is the use of tabs for indents. Therefore, the key default editor setting that needs to be changed in Code::Blocks is to enable tabs for indents. This setting can be found by selecting **Settings > Editor**. + +
+ +
+ +Under **General Settings**, on the **Editor Settings** tab, under **Tab Options** check **Use TAB character**. + +
+ +
+ +That's it. You're ready to start contributing to Redot using the Code::Blocks IDE. Remember to save the project file and the **Workspace**. If you run into any issues, ask for help in one of [Redot's community channels](https://redotengine.org/community). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/kdevelop.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/kdevelop.md new file mode 100644 index 0000000..e1e3699 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/kdevelop.md @@ -0,0 +1,82 @@ + +# KDevelop + +[KDevelop](https://www.kdevelop.org) is a free, open source IDE for all desktop platforms. + +## Importing the project + +- From the KDevelop's main screen select **Open Project**. + +
+ KDevelop's main screen. +
+ KDevelop's main screen. +
+
+ +- Navigate to the Redot root folder and select it. +- On the next screen, choose **Custom Build System** for the **Project Manager**. + +
+ +
+ +- After the project has been imported, open the project configuration by right-clicking + on it in the **Projects** panel and selecting **Open Configuration..** option. + +
+ +
+ +- Under **Language Support** open the **Includes/Imports** tab and add the following paths: + +```none +. // A dot, to indicate the root of the Redot project +core/ +core/os/ +core/math/ +drivers/ +platform// // Replace with a folder + corresponding to your current platform + +``` + +
+ +
+ +- Apply the changes. +- Under **Custom Build System** add a new build configuration with the following settings: + +| Build Directory | *blank* | +| --- | --- | +| Enable | **True** | +| Executable | **scons** | +| Arguments | See [doc_introduction_to_the_buildsystem](../compiling/introduction_to_the_buildsystem.md) for a full list of arguments. | + +
+ +
+ +- Apply the changes and close the configuration window. + +## Debugging the project + +- Select **Run > Configure Launches...** from the top menu. + +
+ +
+ +- Click **Add** to create a new launch configuration. +- Select **Executable** option and specify the path to your executable located in + the ``<Redot root directory>/bin`` folder. The name depends on your build configuration, + e.g. ``Redot.linuxbsd.editor.dev.x86_64`` for 64-bit LinuxBSD platform with + ``platform=editor`` and ``dev_build=yes``. + +
+ +
+ +If you run into any issues, ask for help in one of +[Redot's community channels](https://redotengine.org/community). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/qt_creator.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/qt_creator.md new file mode 100644 index 0000000..811d929 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/qt_creator.md @@ -0,0 +1,110 @@ + +# Qt Creator + +[Qt Creator](https://doc.qt.io/qtcreator/index.html) is a free, open source IDE for all desktop platforms. + +## Importing the project + +- From the Qt Creator's main screen select **New Project > Import Project > Import Existing Project**. + +
+ +
+ +- Under **Location** select the Redot root folder. + +
+ +
+ +- Next, you can choose which folders and files will be visible to the project. + While C/C++ files are added automatically, other extensions can be potentially useful: + ``*.glsl`` for shader files, ``*.py`` for buildsystem files, + ``*.java`` for Android platform development, ``*.mm`` for macOS platform development. + +
+ +
+ +:::note +You can change this configuration later by right-clicking on your project +and selecting the **Edit Files...** option. + +
+ +
+ +::: + +- Finish the import. +- Open the ``project_name.includes`` file and add a line containing ``.`` to it + to correctly enable the code completion. + +
+ +
+ +- From the left-side menu select **Projects** and open the **Build** tab. +- Delete the predefined ``make`` build step. + +
+ +
+ +- Click **Add Build Step > Custom Process Step** to add a new build step + with the following settings: + +| Command | **scons** | +| --- | --- | +| Arguments | See [doc_introduction_to_the_buildsystem](../compiling/introduction_to_the_buildsystem.md) for a full list of arguments. | + +
+ +
+ +:::note +If the build fails with ``Could not start process "scons"``, it can mean that ``scons`` +is not in your ``PATH`` environment variable. In this case, you'll have to specify the +full path to the SCons binary. + +::: + +## Debugging the project + +- From the left-side menu select **Projects** and open the **Run** tab. +- Under **Executable** specify the path to your executable located in + the ``<Redot root directory>/bin`` folder. The name depends on your build configuration, + e.g. ``Redot.linuxbsd.editor.dev.x86_64`` for 64-bit LinuxBSD platform with + ``platform=editor`` and ``dev_build=yes``. + You can use ``%{buildDir}`` to reference the project root, e.g: ``%{buildDir}/bin/Redot.linuxbsd.editor.dev.x86_64``. +- If you want to run a specific project, specify its root folder under **Working directory**. +- If you want to run the editor, add ``-e`` to the **Command line arguments** field. + +
+ +
+ +To learn more about command line arguments, refer to the +[command line tutorial](../../../tutorials/editor/command_line_tutorial.md). + +## Code style configuration + +Developers must follow the project's [code style](../code_style_guidelines.md) +and the IDE should help them follow it. By default, Qt Creator uses spaces +for indentation which doesn't match the Redot code style guidelines. You can +change this behavior by changing the **Code Style** in **Tools > Options > C++**. + +
+ +
+ +Click on **Edit** to change the current settings, then click on +**Copy Built-in Code Style** button to set a new code style. Set a name for it +(e.g. Redot) and change the Tab policy to be **Tabs Only**. + +
+ +
+ +If you run into any issues, ask for help in one of +[Redot's community channels](https://redotengine.org/community). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/rider.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/rider.md new file mode 100644 index 0000000..c6806bd --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/rider.md @@ -0,0 +1,99 @@ + +# JetBrains Rider + +[JetBrains Rider](https://www.jetbrains.com/rider/) is a commercial +[JetBrains](https://www.jetbrains.com/) IDE for C# and C++ that uses the same solution system as Visual Studio. + +:::note + +This documentation is for contributions to the game engine, and not using +JetBrains Rider as a C# or GDScript editor. To code C# or GDScript in an external editor, see +[the C# guide to configure an external editor](doc_c_sharp_setup_external_editor). + +::: + +## Importing the project + +You will need to install [Python](https://www.python.org/) in your development environment +along with [MinGW](https://www.mingw-w64.org/downloads/). You will also need the Visual Studio C++ Build Tools, which +you can install using the Visual Studio Installer. Ensure all dependencies are installed +before you continue to the next steps. + +:::tip +If you already use Visual Studio as your main IDE, you can use the same solution file in Rider. +Rider and Visual Studio use the same solution format, so you can switch between the two IDEs without rebuilding the solution file. +Debug configurations need to be changed when going from one IDE to another. + +::: + +Rider requires a solution file to work on a C++ project. While Redot does not come +with a solution file, it can be generated using SCons. + +- Navigate to the Redot root folder and open a Command Prompt or PowerShell window. +- Copy, paste and run the next command to generate the solution. + +``` +scons platform=windows vsproj=yes dev_build=yes + +``` + +The ``vsproj`` parameter signals that you want Visual Studio solution generated. +The ``dev_build`` parameter makes sure the debug symbols are included, allowing to e.g. step through code using breakpoints. + +- If you have Rider setup as your main IDE for .sln, you can now open the project by double-clicking on the ``Redot.sln`` in the project root + or by using the **Open** option inside of Rider. + +:::note +Rider could fail to build the solution. +If that is the case, try running `git clean -xdf` to remove all traces of the previous build artifacts +and regenerate the build files using the `scons` command again. Restarting the terminal and your +development environment may help. + +::: + +## Compiling and debugging the project +Rider comes with a built-in debugger that can be used to debug the Redot project. You can launch the debugger +by pressing the **Debug** icon at the top of the screen, this only works for the Project manager, +if you want to debug the editor, you need to configure the debugger first. + +
+ +
+ +- Click on the **Redot > Edit Configurations** option at the top of the screen. + +
+ +
+ +- Ensure the following values for the C++ Project Run Configuration: + + - Exe Path : ``$(LocalDebuggerCommand)`` + - Program Arguments: `[-e --path](path to the Redot project)` + - Working Directory: ``$(LocalDebuggerWorkingDirectory)`` + - Before Launch has a value of "Build Project" + +This will tell the executable to debug the specified project without using the project manager. +Use the root path to the project folder, not ``project.Redot`` file path. + +
+ +
+ +- Finally click on "Apply" and "OK" to save the changes. + +- When you press the **Debug** icon at the top of the screen, JetBrains Rider will launch the Redot editor with the debugger attached. + +Alternatively you can use **Run > Attach to Process** to attach the debugger to a running Redot instance. + +
+ +
+ +- You can find the Redot instance by searching for ``Redot.editor`` and then clicking ``Attach with LLDB`` + +
+ +
+ +Please consult the [JetBrains Rider documentation](https://www.jetbrains.com/rider/documentation/) for any specific information about the JetBrains IDE. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio.md new file mode 100644 index 0000000..b468a50 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio.md @@ -0,0 +1,73 @@ + +# Visual Studio + +[Visual Studio Community](https://visualstudio.microsoft.com) is a Windows-only IDE +by [Microsoft](https://microsoft.com) that's free for individual use or non-commercial use within organizations. +It has many useful features, such as memory view, performance view, source +control and more. + +## Importing the project + +Visual Studio requires a solution file to work on a project. While Redot does not come +with the solution file, it can be generated using SCons. + +- Navigate to the Redot root folder and open a Command Prompt or PowerShell window. +- | Run ``scons platform=windows vsproj=yes dev_build=yes`` to generate the solution with debug symbols. + | The ``vsproj`` parameter signals that you want Visual Studio solution generated. + | The ``dev_build`` parameter makes sure the debug symbols are included, allowing to e.g. step through code using breakpoints. +- You can now open the project by double-clicking on the ``Redot.sln`` in the project root + or by using the **Open a project or solution** option inside of the Visual Studio. +- Use the **Build** top menu to build the project. + +:::warning +Visual Studio must be configured with the C++ package. It can be selected +in the installer: + +
+ +
+ +::: + +## Debugging the project + +Visual Studio features a powerful debugger. This allows the user to examine Redot's +source code, stop at specific points in the code, inspect the current execution context, +and make live changes to the codebase. + +You can launch the project with the debugger attached using the **Debug > Start Debugging** +option from the top menu. However, unless you want to debug the Project Manager specifically, +you'd need to configure debugging options first. This is due to the fact that when the Redot +Project Manager opens a project, the initial process is terminated and the debugger gets detached. + +- To configure the launch options to use with the debugger use **Project > Properties** + from the top menu: + +
+ +
+ +- Open the **Debugging** section and under **Command Arguments** add two new arguments: + the ``-e`` flag opens the editor instead of the Project Manager, and the ``--path`` argument + tells the executable to open the specified project (must be provided as an *absolute* path + to the project root, not the ``project.Redot`` file; if the path contains spaces be sure to pass it inside double quotation marks). + +
+ +
+ +To learn more about command line arguments, refer to the +[command line tutorial](../../../tutorials/editor/command_line_tutorial.md). + +Even if you start the project without a debugger attached it can still be connected to the running +process using **Debug > Attach to Process...** menu. + +To check that everything is working, put a breakpoint in ``main.cpp`` and press `F5` to +start debugging. + +
+ +
+ +If you run into any issues, ask for help in one of +[Redot's community channels](https://redotengine.org/community). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio_code.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio_code.md new file mode 100644 index 0000000..00f13e3 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/visual_studio_code.md @@ -0,0 +1,270 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Visual Studio Code + +[Visual Studio Code](https://code.visualstudio.com) is a free cross-platform code editor +by [Microsoft](https://microsoft.com) (not to be confused with [doc_configuring_an_ide_vs](visual_studio.md)). + +## Importing the project + +- Make sure the C/C++ extension is installed. You can find instructions in + the [official documentation](https://code.visualstudio.com/docs/languages/cpp). + Alternatively, [clangd](https://open-vsx.org/extension/llvm-vs-code-extensions/vscode-clangd) + can be used instead. +- When using the clangd extension, run ``scons compiledb=yes``. +- From the Visual Studio Code's main screen open the Redot root folder with + **File > Open Folder...**. +- Press `Ctrl + Shift + P` to open the command prompt window and enter *Configure Task*. + +
+ +
+ +- Select the **Create tasks.json file from template** option. + +
+ +
+ +- Then select **Others**. + +
+ +
+ +- If there is no such option as **Create tasks.json file from template** available, either delete the file if it already exists in your folder or create a ``.vscode/tasks.json`` file manually. See [Tasks in Visual Studio Code](https://code.visualstudio.com/docs/editor/tasks#_custom-tasks) for more details on tasks. + +- Within the ``tasks.json`` file find the ``"tasks"`` array and add a new section to it: + +```js +{ + "label": "build", + "group": "build", + "type": "shell", + "command": "scons", + "args": [ + // enable for debugging with breakpoints + "dev_build=yes", + ], + "problemMatcher": "$msCompile" +} + +``` + +
+ An example of a filled out ``tasks.json``. +
+ An example of a filled out ``tasks.json``. +
+
+ +Arguments can be different based on your own setup and needs. See +[doc_introduction_to_the_buildsystem](../compiling/introduction_to_the_buildsystem.md) for a full list of arguments. + +## Debugging the project + +To run and debug the project you need to create a new configuration in the ``launch.json`` file. + +- Press `Ctrl + Shift + D` to open the Run panel. +- If ``launch.json`` file is missing you will be prompted to create a new one. + +
+ +
+ +- Select **C++ (GDB/LLDB)**. There may be another platform-specific option here. If selected, + adjust the configuration example provided accordingly. +- Within the ``launch.json`` file find the ``"configurations"`` array and add a new section to it: + + + + + +```js +{ + "name": "Launch Project", + "type": "lldb", + "request": "launch", + // Change to Redot.linuxbsd.editor.dev.x86_64.llvm for llvm-based builds. + "program": "${workspaceFolder}/bin/Redot.linuxbsd.editor.dev.x86_64", + // Change the arguments below for the project you want to test with. + // To run the project instead of editing it, remove the "--editor" argument. + "args": [ "--editor", "--path", "path-to-your-Redot-project-folder" ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "preLaunchTask": "build" +} +``` + + + + + +```js +{ + "name": "Launch Project", + "type": "cppdbg", + "request": "launch", + // Change to Redot.linuxbsd.editor.dev.x86_64.llvm for llvm-based builds. + "program": "${workspaceFolder}/bin/Redot.linuxbsd.editor.dev.x86_64", + // Change the arguments below for the project you want to test with. + // To run the project instead of editing it, remove the "--editor" argument. + "args": [ "--editor", "--path", "path-to-your-Redot-project-folder" ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "setupCommands": + [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Load custom pretty-printers for Redot types.", + "text": "source ${workspaceRoot}/misc/utility/Redot_gdb_pretty_print.py" + } + ], + "preLaunchTask": "build" +} + +``` + + + + + +```js +{ + "name": "Launch Project", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/Redot.windows.editor.dev.x86_64.exe", + // Change the arguments below for the project you want to test with. + // To run the project instead of editing it, remove the "--editor" argument. + "args": [ "--editor", "--path", "path-to-your-Redot-project-folder" ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "console": "internalConsole", + "visualizerFile": "${workspaceFolder}/platform/windows/Redot.natvis", + "preLaunchTask": "build" +} + +``` + + + + + +```js +{ + "name": "Launch Project", + "type": "lldb", + "request": "custom", + "targetCreateCommands": [ + "target create ${workspaceFolder}/bin/Redot.macos.editor.dev.x86_64" + ], + // Change the arguments below for the project you want to test with. + // To run the project instead of editing it, remove the "--editor" argument. + "processCreateCommands": [ + "process launch -- --editor --path path-to-your-Redot-project-folder" + ] +} +``` + + + + + +
+ An example of a filled out ``launch.json``. +
+ An example of a filled out ``launch.json``. +
+
+ +:::note + +Due to sporadic performance issues, it is recommended to use LLDB over GDB on Unix-based systems. +Make sure that the [CodeLLDB extension](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb) +is installed. + +If you encounter issues with lldb, you may consider using gdb (see the LinuxBSD_gdb configuration). + +Do note that lldb may work better with LLVM-based builds. See [doc_compiling_for_linuxbsd](../compiling/compiling_for_linuxbsd.md) for further information. + +::: + +The name under ``program`` depends on your build configuration, +e.g. ``Redot.linuxbsd.editor.dev.x86_64`` for 64-bit LinuxBSD platform with +``target=editor`` and ``dev_build=yes``. + +## Configuring Intellisense + +For the C/C++ extension: + +To fix include errors you may be having, you need to configure some settings in the ``c_cpp_properties.json`` file. + +- First, make sure to build the project since some files need to be generated. + +- Edit the C/C++ Configuration file either with the UI or with text: + +
+ +
+ +- Add an include path for your platform, for example, ``${workspaceFolder}/platform/windows``. + +- Add defines for the editor ``TOOLS_ENABLED``, debug builds ``DEBUG_ENABLED``, and tests ``TESTS_ENABLED``. + +- Make sure the compiler path is configured correctly to the compiler you are using. See [doc_introduction_to_the_buildsystem](../compiling/introduction_to_the_buildsystem.md) for further information on your platform. + +- The ``c_cpp_properties.json`` file should look similar to this for Windows: + +```js +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/platform/windows" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE", + "TOOLS_ENABLED", + "DEBUG_ENABLED", + "TESTS_ENABLED" + ], + "windowsSdkVersion": "10.0.22621.0", + "compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/bin/Hostx64/x64/cl.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-msvc-x64" + } + ], + "version": 4 +} + +``` + +- Alternatively, you can use the scons argument ``compiledb=yes`` and set the compile commands setting ``compileCommands`` to ``compile_commands.json``, found in the advanced section of the C/C++ Configuration UI. + + - This argument can be added to your build task in ``tasks.json`` since it will need to be run whenever files are added or moved. + +If you run into any issues, ask for help in one of +[Redot's community channels](https://redotengine.org/community). + +:::tip + +To get linting on class reference XML files, install the +[vscode-xml extension](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml). + +::: diff --git a/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/xcode.md b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/xcode.md new file mode 100644 index 0000000..c8b3b2b --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/configuring_an_ide/xcode.md @@ -0,0 +1,107 @@ + +# Xcode + +[Xcode](https://developer.apple.com/xcode) is a free macOS-only IDE. You can +download it from the Mac App Store. + +## Importing the project + +- From Xcode's main screen create a new project using the **Other > External Build System** template. + +
+ +
+ +- Now choose a name for your project and set the path to scons executable in build tool (to find the path you can type ``where scons`` in a terminal). + +
+ +
+ +- Open the main target from the **Targets** section and select the **Info** tab. + +
+ +
+ +- Fill out the form with the following settings: + +| Arguments | See [doc_introduction_to_the_buildsystem](../compiling/introduction_to_the_buildsystem.md) for a full list of arguments. | +| --- | --- | +| Directory | A full path to the Redot root folder | + +- Add a Command Line Tool target which will be used for indexing the project by + choosing **File > New > Target...**. + +
+ +
+ +- Select **macOS > Application > Command Line Tool**. + +
+ +
+ +:::note +Name it something so you know not to compile with this target (e.g. ``RedotXcodeIndex``). + +::: + +- For this target open the **Build Settings** tab and look for **Header Search Paths**. +- Set **Header Search Paths** to the absolute path to the Redot root folder. You need to + include subdirectories as well. To achieve that, add two two asterisks (``**``) to the + end of the path, e.g. ``/Users/me/repos/Redot-source/**``. + +- Add the Redot source to the project by dragging and dropping it into the project file browser. +- Select **Create groups** for the **Added folders** option and check *only* + your command line indexing target in the **Add to targets** section. + +
+ +
+ +- Xcode will now index the files. This may take a few minutes. +- Once Xcode is done indexing, you should have jump-to-definition, + autocompletion, and full syntax highlighting. + +## Debugging the project + +To enable debugging support you need to edit the external build target's build and run schemes. + +- Open the scheme editor of the external build target. +- Locate the **Build > Post Actions** section. +- Add a new script run action +- Under **Provide build settings from** select your project. This allows to reference + the project directory within the script. +- Create a script that will give the binary a name that Xcode can recognize, e.g.: + +```shell +ln -f ${PROJECT_DIR}/Redot/bin/Redot.macos.tools.64 ${PROJECT_DIR}/Redot/bin/Redot + +``` + +
+ +
+ +- Build the external build target. + +- Open the scheme editor again and select **Run**. + +
+ +
+ +- Set the **Executable** to the file you linked in your post-build action script. +- Check **Debug executable**. +- You can add two arguments on the **Arguments** tab: + the ``-e`` flag opens the editor instead of the Project Manager, and the ``--path`` argument + tells the executable to open the specified project (must be provided as an *absolute* path + to the project root, not the ``project.Redot`` file). + +To check that everything is working, put a breakpoint in ``platform/macos/Redot_main_macos.mm`` and +run the project. + +If you run into any issues, ask for help in one of +[Redot's community channels](https://redotengine.org/community). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/2d_coordinate_systems.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/2d_coordinate_systems.md new file mode 100644 index 0000000..7482da6 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/2d_coordinate_systems.md @@ -0,0 +1,138 @@ + +# 2D coordinate systems and 2D transforms + +## Introduction + +This is a detailed overview of the available 2D coordinate systems and 2D transforms that are +built in. The basic concepts are covered in [doc_viewport_and_canvas_transforms](../../../tutorials/2d/2d_transforms.md). + +[Transform2D](/docs/Classes/Transform2D) are matrices that convert coordinates from one coordinate +system to an other. In order to use them, it is beneficial to know which coordinate systems are +available in Redot. For a deeper understanding, the [doc_matrices_and_transforms](../../../tutorials/math/matrices_and_transforms.md) tutorial +offers insights to the underlying functionality. + +## Redot 2D coordinate systems + +The following graphic gives an overview of Redot 2D coordinate systems and the available +node-transforms, transform-functions and coordinate-system related functions. At the left +is the OS Window Manager screen, at the right are the [CanvasItems](/docs/Classes/CanvasItem). For +simplicity reasons this graphic doesn't include [SubViewport](/docs/Classes/SubViewport), +[SubViewportContainer](/docs/Classes/SubViewportContainer), [ParallaxLayer](/docs/Classes/ParallaxLayer) +and [ParallaxBackground](/docs/Classes/ParallaxBackground) all of which also influence transforms. + +The graphic is based on a node tree of the following form: ``Root Window (embed Windows)`` ⇒ +``Window (don't embed Windows)`` ⇒ ``CanvasLayer`` ⇒ ``CanvasItem`` ⇒ ``CanvasItem`` ⇒ +``CanvasItem``. There are more complex combinations possible, like deeply nested Window and +SubViewports, however this example intends to provide an overview of the methodology in general. + + + +Click graphic to enlarge. + +- **Item Coordinates** + This is the local coordinate system of a [CanvasItem](/docs/Classes/CanvasItem). + +- **Parent Item Coordinates** + This is the local coordinate system of the parent's *CanvasItem*. When positioning + *CanvasItems* in the *Canvas*, they usually inherit the transformations of their parent + *CanvasItems*. An exceptions is + [CanvasItems.top_level](/docs/Classes/CanvasItem_property_top_level). + +- **Canvas Coordinates** + As mentioned in the previous tutorial [doc_canvas_layers](../../../tutorials/2d/canvas_layers.md), there are two types of canvases + (*Viewport* canvas and *CanvasLayer* canvas) and both have a canvas coordinate system. These + are also called world coordinates. A *Viewport* can contain multiple *Canvases* with different + coordinate systems. + +- **Viewport Coordinates** + This is the coordinate system of the [Viewport](/docs/Classes/Viewport). + +- **Camera Coordinates** + This is only used internally for functionality like 3D-camera ray projections. + +- **Embedder Coordinates / Screen Coordinates** + Every *Viewport* (*Window* or *SubViewport*) in the scene tree is embedded either in a + different node or in the OS Window Manager. This coordinate system's origin is identical to the + top-left corner of the *Window* or *SubViewport* and its scale is the one of the embedder or + the OS Window Manager. + + If the embedder is the OS Window Manager, then they are also called Screen Coordinates. + +- **Absolute Embedder Coordinates / Absolute Screen Coordinates** + The origin of this coordinate system is the top-left corner of the embedding node or the OS + Window Manager screen. Its scale is the one of the embedder or the OS Window Manager. + + If the embedder is the OS Window Manager, then they are also called Absolute Screen + Coordinates. + +## Node transforms + +Each of the mentioned nodes have one or more transforms associated with them and the combination of +these nodes infer the transforms between the different coordinate systems. With a few exceptions, +the transforms are [Transform2D](/docs/Classes/Transform2D) and the following list shows details and +effects of each of them. + +- **CanvasItem transform** + *CanvasItems* are either *Control*-nodes or *Node2D*-nodes. + + For *Control* nodes this transform consists of a [position](/docs/Classes/Control_property_position) + relative to the parent's origin and a [scale](/docs/Classes/Control_property_scale) and + [rotation](/docs/Classes/Control_property_rotation) around a + [pivot point](/docs/Classes/Control_property_pivot_offset). + + For *Node2D* nodes [transform](/docs/Classes/Node2D_property_transform) consists of + [position](/docs/Classes/Node2D_property_position), [rotation](/docs/Classes/Node2D_property_rotation), + [scale](/docs/Classes/Node2D_property_scale) and [skew](/docs/Classes/Node2D_property_skew). + + The transform affects the item itself and usually also child-*CanvasItems* and in the case of a + *SubViewportContainer* it affects the contained *SubViewport*. + +- **CanvasLayer transform** + The *CanvasLayer's* [transform](/docs/Classes/CanvasLayer_property_transform) affects all + *CanvasItems* within the *CanvasLayer*. It doesn't affect other *CanvasLayers* or *Windows* in + its *Viewport*. + +- **CanvasLayer follow viewport transform** + The *follow viewport transform* is an automatically calculated transform, that is based on the + *Viewport's* [canvas transform](/docs/Classes/Viewport_property_canvas_transform) and the + *CanvasLayer's* [follow viewport scale](/docs/Classes/CanvasLayer_property_follow_viewport_scale) + and can be used, if [enabled](/docs/Classes/CanvasLayer_property_follow_viewport_enabled), to + achieve a pseudo-3D effect. It affects the same child nodes as the *CanvasLayer transform*. + +- **Viewport canvas transform** + The [canvas transform](/docs/Classes/Viewport_property_canvas_transform) affects all + *CanvasItems* in the *Viewport's* default canvas. It also affects *CanvasLayers*, that have + follow viewport transform enabled. The *Viewport's* active [Camera2D](/docs/Classes/Camera2D) + works by changing this transform. It doesn't affect this *Viewport's* embedded *Windows*. + +- **Viewport global canvas transform** + *Viewports* also have a [global canvas transform](/docs/Classes/Viewport_property_global_canvas_transform). + This is the master transform and affects all individual *Canvas Layer* and embedded *Window* + transforms. This is primarily used in Redot's CanvasItem Editor. + +- **Viewport stretch transform** + Finally, *Viewports* have a *stretch transform*, which is used when resizing or stretching the + viewport. This transform is used for [Windows](/docs/Classes/Window) as described in + [doc_multiple_resolutions](../../../tutorials/rendering/multiple_resolutions.md), but can also be manually set on *SubViewports* by means of + [size](/docs/Classes/SubViewport_property_size) and + [size_2d_override](/docs/Classes/SubViewport_property_size_2d_override). It's + [translation](/docs/Classes/Transform2D_method_get_origin), + [rotation](/docs/Classes/Transform2D_method_get_rotation) and + [skew](/docs/Classes/Transform2D_method_get_skew) are the default values and it can only have + non-default [scale](/docs/Classes/Transform2D_method_get_scale). + +- **Window transform** + In order to scale and position the *Window's* content as described in + [doc_multiple_resolutions](../../../tutorials/rendering/multiple_resolutions.md), each [Window](/docs/Classes/Window) contains a + *window transform*. It is for example responsible for the black bars at the *Window's* sides so + that the *Viewport* is displayed with a fixed aspect ratio. + +- **Window position** + Every *Window* also has a [position](/docs/Classes/Window_property_position) to describe its + position within its embedder. The embedder can be another *Viewport* or the OS Window Manager. + +- **SubViewportContainer shrink transform** + [stretch](/docs/Classes/SubViewportContainer_property_stretch) together with + [stretch_shrink](/docs/Classes/SubViewportContainer_property_stretch_shrink) declare for a + *SubViewportContainer* if and by what integer factor the contained *SubViewport* should be + scaled in comparison to the container's size. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/binding_to_external_libraries.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/binding_to_external_libraries.md new file mode 100644 index 0000000..dffff28 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/binding_to_external_libraries.md @@ -0,0 +1,238 @@ + +# Binding to external libraries + +## Modules + +The Summator example in [doc_custom_modules_in_cpp](custom_modules_in_cpp.md) is great for small, +custom modules, but what if you want to use a larger, external library? +Let's look at an example using [Festival](https://www.cstr.ed.ac.uk/projects/festival/), +a speech synthesis (text-to-speech) library written in C++. + +To bind to an external library, set up a module directory similar to the Summator example: + +```none +Redot/modules/tts/ + +``` + +Next, you will create a header file with a TTS class: + +```cpp +#ifndef Redot_TTS_H +#define Redot_TTS_H + +#include "core/object/ref_counted.h" + +class TTS : public RefCounted { + GDCLASS(TTS, RefCounted); + +protected: + static void _bind_methods(); + +public: + bool say_text(String p_txt); + + TTS(); +}; + +#endif // Redot_TTS_H + +``` + +And then you'll add the cpp file. + +```cpp +#include "tts.h" + +#include + +bool TTS::say_text(String p_txt) { + + //convert Redot String to Redot CharString to C string + return festival_say_text(p_txt.ascii().get_data()); +} + +void TTS::_bind_methods() { + + ClassDB::bind_method(D_METHOD("say_text", "txt"), &TTS::say_text); +} + +TTS::TTS() { + festival_initialize(true, 210000); //not the best way to do it as this should only ever be called once. +} + +``` + +Just as before, the new class needs to be registered somehow, so two more files +need to be created: + +```none +register_types.h +register_types.cpp + +``` + +:::info + +These files must be in the top-level folder of your module (next to your +``SCsub`` and ``config.py`` files) for the module to be registered properly. + +::: + +These files should contain the following: + +```cpp +void initialize_tts_module(ModuleInitializationLevel p_level); +void uninitialize_tts_module(ModuleInitializationLevel p_level); +/* yes, the word in the middle must be the same as the module folder name */ + +``` + +```cpp +#include "register_types.h" + +#include "core/object/class_db.h" +#include "tts.h" + +void initialize_tts_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + ClassDB::register_class(); +} + +void uninitialize_tts_module(ModuleInitializationLevel p_level) { + // Nothing to do here in this example. +} + +``` + +Next, you need to create an ``SCsub`` file so the build system compiles +this module: + +```python +Import('env') + +env_tts = env.Clone() +env_tts.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build + +``` + +You'll need to install the external library on your machine to get the .a library files. See the library's official +documentation for specific instructions on how to do this for your operation system. We've included the +installation commands for Linux below, for reference. + +```shell +sudo apt-get install festival festival-dev # Installs festival and speech_tools libraries +apt-cache search festvox-* # Displays list of voice packages +sudo apt-get install festvox-don festvox-rablpc16k festvox-kallpc16k festvox-kdlpc16k # Installs voices + +``` + +:::info + +The voices that Festival uses (and any other potential external/3rd-party +resource) all have varying licenses and terms of use; some (if not most) of them may be +be problematic with Redot, even if the Festival Library itself is MIT License compatible. +Please be sure to check the licenses and terms of use. + +::: + +The external library will also need to be installed inside your module to make the source +files accessible to the compiler, while also keeping the module code self-contained. The +festival and speech_tools libraries can be installed from the modules/tts/ directory via +git using the following commands: + +```shell +git clone https://github.com/festvox/festival +git clone https://github.com/festvox/speech_tools + +``` + +If you don't want the external repository source files committed to your repository, you +can link to them instead by adding them as submodules (from within the modules/tts/ directory), as seen below: + +```shell +git submodule add https://github.com/festvox/festival +git submodule add https://github.com/festvox/speech_tools + +``` + +:::info + +Please note that Git submodules are not used in the Redot repository. If +you are developing a module to be merged into the main Redot repository, you should not +use submodules. If your module doesn't get merged in, you can always try to implement +the external library as a GDExtension. + +::: + +To add include directories for the compiler to look at you can append it to the +environment's paths: + +```python +# These paths are relative to /modules/tts/ +env_tts.Append(CPPPATH=["speech_tools/include", "festival/src/include"]) + +# LIBPATH and LIBS need to be set on the real "env" (not the clone) +# to link the specified libraries to the Redot executable. + +# This is a path relative to /modules/tts/ where your .a libraries reside. +# If you are compiling the module externally (not in the Redot source tree), +# these will need to be full paths. +env.Append(LIBPATH=['libpath']) + +# Check with the documentation of the external library to see which library +# files should be included/linked. +env.Append(LIBS=['Festival', 'estools', 'estbase', 'eststring']) + +``` + +If you want to add custom compiler flags when building your module, you need to clone +`env` first, so it won't add those flags to whole Redot build (which can cause errors). +Example `SCsub` with custom flags: + +```python +Import('env') + +env_tts = env.Clone() +env_tts.add_source_files(env.modules_sources, "*.cpp") +# Append CCFLAGS flags for both C and C++ code. +env_tts.Append(CCFLAGS=['-O2']) +# If you need to, you can: +# - Append CFLAGS for C code only. +# - Append CXXFLAGS for C++ code only. + +``` + +The final module should look like this: + +```none +Redot/modules/tts/festival/ +Redot/modules/tts/libpath/libestbase.a +Redot/modules/tts/libpath/libestools.a +Redot/modules/tts/libpath/libeststring.a +Redot/modules/tts/libpath/libFestival.a +Redot/modules/tts/speech_tools/ +Redot/modules/tts/config.py +Redot/modules/tts/tts.h +Redot/modules/tts/tts.cpp +Redot/modules/tts/register_types.h +Redot/modules/tts/register_types.cpp +Redot/modules/tts/SCsub + +``` + +## Using the module + +You can now use your newly created module from any script: + +``` +var t = TTS.new() +var script = "Hello world. This is a test!" +var is_spoken = t.say_text(script) +print('is_spoken: ', is_spoken) + +``` + +And the output will be ``is_spoken: True`` if the text is spoken. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/common_engine_methods_and_macros.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/common_engine_methods_and_macros.md new file mode 100644 index 0000000..e2dc32f --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/common_engine_methods_and_macros.md @@ -0,0 +1,267 @@ + +# Common engine methods and macros + +Redot's C++ codebase makes use of dozens of custom methods and macros which are +used in almost every file. This page is geared towards beginner contributors, +but it can also be useful for those writing custom C++ modules. + +## Print text + +```cpp +// Prints a message to standard output. +print_line("Message"); + +// Non-String arguments are automatically converted to String for printing. +// If passing several arguments, they will be concatenated together with a +// space between each argument. +print_line("There are", 123, "nodes"); + +// Prints a message to standard output, but only when the engine +// is started with the `--verbose` command line argument. +print_verbose("Message"); + +// Prints a rich-formatted message using BBCode to standard output. +// This supports a subset of BBCode tags supported by RichTextLabel +// and will also appear formatted in the editor Output panel. +// On Windows, this requires Windows 10 or later to work in the terminal. +print_line_rich("[b]Bold[/b], [color=red]Red text[/color]") + +// Prints a formatted error or warning message with a trace. +ERR_PRINT("Message"); +WARN_PRINT("Message"); + +// Prints an error or warning message only once per session. +// This can be used to avoid spamming the console output. +ERR_PRINT_ONCE("Message"); +WARN_PRINT_ONCE("Message"); + +``` + +If you need to add placeholders in your messages, use format strings as +described below. + +## Format a string + +The ``vformat()`` function returns a formatted [class_String](/docs/Classes/String). It behaves +in a way similar to C's ``sprintf()``: + +```cpp +vformat("My name is %s.", "Godette"); +vformat("%d bugs on the wall!", 1234); +vformat("Pi is approximately %f.", 3.1416); + +// Converts the resulting String into a `const char *`. +// You may need to do this if passing the result as an argument +// to a method that expects a `const char *` instead of a String. +vformat("My name is %s.", "Godette").c_str(); + +``` + +In most cases, try to use ``vformat()`` instead of string concatenation as it +makes for more readable code. + +## Convert an integer or float to a string + +This is not needed when printing numbers using ``print_line()``, but you may +still need to perform manual conversion for some other use cases. + +```cpp +// Stores the string "42" using integer-to-string conversion. +String int_to_string = itos(42); + +// Stores the string "123.45" using real-to-string conversion. +String real_to_string = rtos(123.45); + +``` + +## Internationalize a string + +There are two types of internationalization in Redot's codebase: + +- ``TTR()``: **Editor ("tools") translations** will only be processed in the + editor. If a user uses the same text in one of their projects, it won't be + translated if they provide a translation for it. When contributing to the + engine, this is generally the macro you should use for localizable strings. +- ``RTR()``: **Runtime translations** will be automatically localized in + projects if they provide a translation for the given string. This kind of + translation shouldn't be used in editor-only code. + +```cpp +// Returns the translated string that matches the user's locale settings. +// Translations are located in `editor/translations`. +// The localization template is generated automatically; don't modify it. +TTR("Exit the editor?"); + +``` + +To insert placeholders in localizable strings, wrap the localization macro in a +``vformat()`` call as follows: + +```cpp +String file_path = "example.txt"; +vformat(TTR("Couldn't open \"%s\" for reading."), file_path); + +``` + +:::note + +When using ``vformat()`` and a translation macro together, always wrap the +translation macro in ``vformat()``, not the other way around. Otherwise, the +string will never match the translation as it will have the placeholder +already replaced when it's passed to TranslationServer. + +::: + +## Clamp a value + +Redot provides macros for clamping a value with a lower bound (``MAX``), an +upper bound (``MIN``) or both (``CLAMP``): + +```cpp +int a = 3; +int b = 5; + +MAX(b, 6); // 6 +MIN(2, a); // 2 +CLAMP(a, 10, 30); // 10 + +``` + +This works with any type that can be compared to other values (like ``int`` and +``float``). + +## Microbenchmarking + +If you want to benchmark a piece of code but don't know how to use a profiler, +use this snippet: + +```cpp +uint64_t begin = Time::get_singleton()->get_ticks_usec(); + +// Your code here... + +uint64_t end = Time::get_singleton()->get_ticks_usec(); +print_line(vformat("Snippet took %d microseconds", end - begin)); + +``` + +This will print the time spent between the ``begin`` declaration and the ``end`` +declaration. + +:::note + +You may have to ``#include "core/os/os.h"`` if it's not present already. + +When opening a pull request, make sure to remove this snippet as well as the +include if it wasn't there previously. + +::: + +## Get project/editor settings + +There are four macros available for this: + +```cpp +// Returns the specified project setting's value, +// defaulting to `false` if it doesn't exist. +GLOBAL_DEF("section/subsection/value", false); + +// Returns the specified editor setting's value, +// defaulting to "Untitled" if it doesn't exist. +EDITOR_DEF("section/subsection/value", "Untitled"); + +``` + +If a default value has been specified elsewhere, don't specify it again to avoid +repetition: + +```cpp +// Returns the value of the project setting. +GLOBAL_GET("section/subsection/value"); +// Returns the value of the editor setting. +EDITOR_GET("section/subsection/value"); + +``` + +It's recommended to use ``GLOBAL_DEF``/``EDITOR_DEF`` only once per setting and +use ``GLOBAL_GET``/``EDITOR_GET`` in all other places where it's referenced. + +## Error macros + +Redot features many error macros to make error reporting more convenient. + +:::warning + +Conditions in error macros work in the **opposite** way of GDScript's +built-in ``assert()`` function. An error is reached if the condition inside +evaluates to ``true``, not ``false``. + +::: + +:::note + +Only variants with custom messages are documented here, as these should +always be used in new contributions. Make sure the custom message provided +includes enough information for people to diagnose the issue, even if they +don't know C++. In case a method was passed invalid arguments, you can print +the invalid value in question to ease debugging. + +For internal error checking where displaying a human-readable message isn't +necessary, remove ``_MSG`` at the end of the macro name and don't supply a +message argument. + +Also, always try to return processable data so the engine can keep running +well. + +::: + +```cpp +// Conditionally prints an error message and returns from the function. +// Use this in methods which don't return a value. +ERR_FAIL_COND_MSG(!mesh.is_valid(), vformat("Couldn't load mesh at: %s", path)); + +// Conditionally prints an error message and returns `0` from the function. +// Use this in methods which must return a value. +ERR_FAIL_COND_V_MSG(rect.x < 0 || rect.y < 0, 0, + "Couldn't calculate the rectangle's area."); + +// Prints an error message if `index` is < 0 or >= `SomeEnum::QUALITY_MAX`, +// then returns from the function. +ERR_FAIL_INDEX_MSG(index, SomeEnum::QUALITY_MAX, + vformat("Invalid quality: %d. See SomeEnum for allowed values.", index)); + +// Prints an error message if `index` is < 0 >= `some_array.size()`, +// then returns `-1` from the function. +ERR_FAIL_INDEX_V_MSG(index, some_array.size(), -1, + vformat("Item %d is out of bounds.", index)); + +// Unconditionally prints an error message and returns from the function. +// Only use this if you need to perform complex error checking. +if (!complex_error_checking_routine()) { + ERR_FAIL_MSG("Couldn't reload the filesystem cache."); +} + +// Unconditionally prints an error message and returns `false` from the function. +// Only use this if you need to perform complex error checking. +if (!complex_error_checking_routine()) { + ERR_FAIL_V_MSG(false, "Couldn't parse the input arguments."); +} + +// Crashes the engine. This should generally never be used +// except for testing crash handling code. Redot's philosophy +// is to never crash, both in the editor and in exported projects. +CRASH_NOW_MSG("Can't predict the future! Aborting."); + +``` + +:::info + +See [core/error/error_macros.h](https://github.com/redot-engine/redot-engine/blob/master/core/error/error_macros.h) +in Redot's codebase for more information about each error macro. + +Some functions return an error code (materialized by a return type of +``Error``). This value can be returned directly from an error macro. +See the list of available error codes in +[core/error/error_list.h](https://github.com/redot-engine/redot-engine/blob/master/core/error/error_list.h). + +::: diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/core_types.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/core_types.md new file mode 100644 index 0000000..4cbd0af --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/core_types.md @@ -0,0 +1,195 @@ + +# Core types + +Redot has a rich set of classes and templates that compose its core, +and everything is built upon them. + +This reference will try to list them in order for their better +understanding. + +## Definitions + +Redot uses the standard C99 datatypes, such as ``uint8_t``, +``uint32_t``, ``int64_t``, etc. which are nowadays supported by every +compiler. Reinventing the wheel for those is not fun, as it makes code +more difficult to read. + +In general, care is not taken to use the most efficient datatype for a +given task unless using large structures or arrays. ``int`` is used +through most of the code unless necessary. This is done because nowadays +every device has at least a 32 bits bus and can do such operations in +one cycle. It makes code more readable too. + +For files or memory sizes, ``size_t`` is used, which is warranted to be +64 bits. + +For Unicode characters, CharType instead of wchar_t is used, because +many architectures have 4 bytes long wchar_t, where 2 bytes might be +desired. However, by default, this has not been forced and CharType maps +directly to wchar_t. + +### References: + +- [core/typedefs.h](https://github.com/redot-engine/redot-engine/blob/master/core/typedefs.h) + +## Memory model + +PC is a wonderful architecture. Computers often have gigabytes of RAM, +terabytes of storage and gigahertz of CPU, and when an application needs +more resources the OS will swap out the inactive ones. Other +architectures (like mobile or consoles) are in general more limited. + +The most common memory model is the heap, where an application will +request a region of memory, and the underlying OS will try to fit it +somewhere and return it. This often works best and is flexible, +but over time and with abuse, this can lead to segmentation. + +Segmentation slowly creates holes that are too small for most common +allocations, so that memory is wasted. There is a lot of literature +about heap and segmentation, so this topic will not be developed +further here. Modern operating systems use paged memory, which helps +mitigate the problem of segmentation but doesn't solve it. + +However, in many studies and tests, it is shown that given enough +memory, if the maximum allocation size is below a given threshold in +proportion to the maximum heap size and proportion of memory intended to +be unused, segmentation will not be a problem over time as it will +remain constant. In other words, leave 10-20% of your memory free +and perform all small allocations and you are fine. + +Redot ensures that all objects that can be allocated dynamically are +small (less than a few kb at most). But what happens if an allocation is +too large (like an image or mesh geometry or large array)? In this case +Redot has the option to use a dynamic memory pool. This memory needs to +be locked to be accessed, and if an allocation runs out of memory, the +pool will be rearranged and compacted on demand. Depending on the need +of the game, the programmer can configure the dynamic memory pool size. + +## Allocating memory + +Redot has many tools for tracking memory usage in a game, especially +during debug. Because of this, the regular C and C++ library calls +should not be used. Instead, a few other ones are provided. + +For C-style allocation, Redot provides a few macros: + +```none +memalloc() +memrealloc() +memfree() + +``` + +These are equivalent to the usual malloc, realloc, free of the standard C +library. + +For C++-style allocation, special macros are provided: + +```none +memnew( Class / Class(args) ) +memdelete( instance ) + +memnew_arr( Class , amount ) +memdelete_arr( pointer to array ) + +``` + +which are equivalent to new, delete, new[] and delete[]. + +memnew/memdelete also use a little C++ magic and notify Objects right +after they are created, and right before they are deleted. + +For dynamic memory, use Vector<>. + +### References: + +- [core/os/memory.h](https://github.com/redot-engine/redot-engine/blob/master/core/os/memory.h) + +## Containers + +Redot provides also a set of common containers: + +- Vector +- List +- Set +- Map + +They aim to be as minimal as possible, as templates +in C++ are often inlined and make the binary size much fatter, both in +debug symbols and code. List, Set and Map can be iterated using +pointers, like this: + +```cpp +for(List::Element *E=somelist.front();E;E=E->next()) { + print_line(E->get()); // print the element +} + +``` + +The Vector<> class also has a few nice features: + +- It does copy on write, so making copies of it is cheap as long as + they are not modified. +- It supports multi-threading, by using atomic operations on the + reference counter. + +### References: + +- [core/templates/vector.h](https://github.com/redot-engine/redot-engine/blob/master/core/templates/vector.h) +- [core/templates/list.h](https://github.com/redot-engine/redot-engine/blob/master/core/templates/list.h) +- [core/templates/set.h](https://github.com/redot-engine/redot-engine/blob/master/core/templates/hash_set.h) +- [core/templates/map.h](https://github.com/redot-engine/redot-engine/blob/master/core/templates/hash_map.h) + +## String + +Redot also provides a String class. This class has a huge amount of +features, full Unicode support in all the functions (like case +operations) and utf8 parsing/extracting, as well as helpers for +conversion and visualization. + +### References: + +- [core/string/ustring.h](https://github.com/redot-engine/redot-engine/blob/master/core/string/ustring.h) + +## StringName + +StringNames are like a String, but they are unique. Creating a +StringName from a string results in a unique internal pointer for all +equal strings. StringNames are useful for using strings as +identifier, as comparing them is basically comparing a pointer. + +Creation of a StringName (especially a new one) is slow, but comparison +is fast. + +### References: + +- [core/string/string_name.h](https://github.com/redot-engine/redot-engine/blob/master/core/string/string_name.h) + +## Math types + +There are several linear math types available in the core/math +directory. + +### References: + +- [core/math](https://github.com/redot-engine/redot-engine/tree/master/core/math) + +## NodePath + +This is a special datatype used for storing paths in a scene tree and +referencing them fast. + +### References: + +- [core/string/node_path.h](https://github.com/redot-engine/redot-engine/blob/master/core/string/node_path.h) + +## RID + +RIDs are resource IDs. Servers use these to reference data stored in +them. RIDs are opaque, meaning that the data they reference can't be +accessed directly. RIDs are unique, even for different types of +referenced data. + +### References: + +- [core/templates/rid.h](https://github.com/redot-engine/redot-engine/blob/master/core/templates/rid.h) \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_audiostreams.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_audiostreams.md new file mode 100644 index 0000000..139a4e8 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_audiostreams.md @@ -0,0 +1,338 @@ + +# Custom AudioStreams + +## Introduction + +AudioStream is the base class of all audio emitting objects. +AudioStreamPlayer binds onto an AudioStream to emit PCM data +into an AudioServer which manages audio drivers. + +All audio resources require two audio based classes: AudioStream +and AudioStreamPlayback. As a data container, AudioStream contains +the resource and exposes itself to GDScript. AudioStream references +its own internal custom AudioStreamPlayback which translates +AudioStream into PCM data. + +This guide assumes the reader knows how to create C++ modules. If not, refer to this guide +[doc_custom_modules_in_cpp](custom_modules_in_cpp.md). + +### References: + +- [servers/audio/audio_stream.h](https://github.com/redot-engine/redot-engine/blob/master/servers/audio/audio_stream.h) +- [scene/audio/audio_stream_player.cpp](https://github.com/redot-engine/redot-engine/blob/master/scene/audio/audio_stream_player.cpp) + +## What for? + +- Binding external libraries (like Wwise, FMOD, etc). +- Adding custom audio queues +- Adding support for more audio formats + +## Create an AudioStream + +An AudioStream consists of three components: data container, stream name, +and an AudioStreamPlayback friend class generator. Audio data can be +loaded in a number of ways such as with an internal counter for a tone generator, +internal/external buffer, or a file reference. + +Some AudioStreams need to be stateless such as objects loaded from +ResourceLoader. ResourceLoader loads once and references the same +object regardless how many times ``load`` is called on a specific resource. +Therefore, playback state must be self-contained in AudioStreamPlayback. + +```cpp +#include "core/reference.h" +#include "core/resource.h" +#include "servers/audio/audio_stream.h" + +class AudioStreamMyTone : public AudioStream { + GDCLASS(AudioStreamMyTone, AudioStream) + +private: + friend class AudioStreamPlaybackMyTone; + uint64_t pos; + int mix_rate; + bool stereo; + int hz; + +public: + void reset(); + void set_position(uint64_t pos); + virtual Ref instance_playback(); + virtual String get_stream_name() const; + void gen_tone(int16_t *pcm_buf, int size); + virtual float get_length() const { return 0; } // if supported, otherwise return 0 + AudioStreamMyTone(); + +protected: + static void _bind_methods(); +}; + +``` + +```cpp +#include "audiostream_mytone.h" + +AudioStreamMyTone::AudioStreamMyTone() + : mix_rate(44100), stereo(false), hz(639) { +} + +Ref AudioStreamMyTone::instance_playback() { + Ref talking_tree; + talking_tree.instantiate(); + talking_tree->base = Ref(this); + return talking_tree; +} + +String AudioStreamMyTone::get_stream_name() const { + return "MyTone"; +} +void AudioStreamMyTone::reset() { + set_position(0); +} +void AudioStreamMyTone::set_position(uint64_t p) { + pos = p; +} +void AudioStreamMyTone::gen_tone(int16_t *pcm_buf, int size) { + for (int i = 0; i < size; i++) { + pcm_buf[i] = 32767.0 * sin(2.0 * Math_PI * double(pos + i) / (double(mix_rate) / double(hz))); + } + pos += size; +} +void AudioStreamMyTone::_bind_methods() { + ClassDB::bind_method(D_METHOD("reset"), &AudioStreamMyTone::reset); + ClassDB::bind_method(D_METHOD("get_stream_name"), &AudioStreamMyTone::get_stream_name); +} + +``` + +### References: + +- [servers/audio/audio_stream.h](https://github.com/redot-engine/redot-engine/blob/master/servers/audio/audio_stream.h) + +## Create an AudioStreamPlayback + +AudioStreamPlayer uses ``mix`` callback to obtain PCM data. The callback must match sample rate and fill the buffer. + +Since AudioStreamPlayback is controlled by the audio thread, i/o and dynamic memory allocation are forbidden. + +```cpp +#include "core/reference.h" +#include "core/resource.h" +#include "servers/audio/audio_stream.h" + +class AudioStreamPlaybackMyTone : public AudioStreamPlayback { + GDCLASS(AudioStreamPlaybackMyTone, AudioStreamPlayback) + friend class AudioStreamMyTone; + +private: + enum { + PCM_BUFFER_SIZE = 4096 + }; + enum { + MIX_FRAC_BITS = 13, + MIX_FRAC_LEN = (1 << MIX_FRAC_BITS), + MIX_FRAC_MASK = MIX_FRAC_LEN - 1, + }; + void *pcm_buffer; + Ref base; + bool active; + +public: + virtual void start(float p_from_pos = 0.0); + virtual void stop(); + virtual bool is_playing() const; + virtual int get_loop_count() const; // times it looped + virtual float get_playback_position() const; + virtual void seek(float p_time); + virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); + virtual float get_length() const; // if supported, otherwise return 0 + AudioStreamPlaybackMyTone(); + ~AudioStreamPlaybackMyTone(); +}; + +``` + +```cpp +#include "audiostreamplayer_mytone.h" + +#include "core/math/math_funcs.h" +#include "core/print_string.h" + +AudioStreamPlaybackMyTone::AudioStreamPlaybackMyTone() + : active(false) { + AudioServer::get_singleton()->lock(); + pcm_buffer = AudioServer::get_singleton()->audio_data_alloc(PCM_BUFFER_SIZE); + zeromem(pcm_buffer, PCM_BUFFER_SIZE); + AudioServer::get_singleton()->unlock(); +} +AudioStreamPlaybackMyTone::~AudioStreamPlaybackMyTone() { + if(pcm_buffer) { + AudioServer::get_singleton()->audio_data_free(pcm_buffer); + pcm_buffer = NULL; + } +} +void AudioStreamPlaybackMyTone::stop() { + active = false; + base->reset(); +} +void AudioStreamPlaybackMyTone::start(float p_from_pos) { + seek(p_from_pos); + active = true; +} +void AudioStreamPlaybackMyTone::seek(float p_time) { + float max = get_length(); + if (p_time < 0) { + p_time = 0; + } + base->set_position(uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS); +} +void AudioStreamPlaybackMyTone::mix(AudioFrame *p_buffer, float p_rate, int p_frames) { + ERR_FAIL_COND(!active); + if (!active) { + return; + } + zeromem(pcm_buffer, PCM_BUFFER_SIZE); + int16_t *buf = (int16_t *)pcm_buffer; + base->gen_tone(buf, p_frames); + + for(int i = 0; i < p_frames; i++) { + float sample = float(buf[i]) / 32767.0; + p_buffer[i] = AudioFrame(sample, sample); + } +} +int AudioStreamPlaybackMyTone::get_loop_count() const { + return 0; +} +float AudioStreamPlaybackMyTone::get_playback_position() const { + return 0.0; +} +float AudioStreamPlaybackMyTone::get_length() const { + return 0.0; +} +bool AudioStreamPlaybackMyTone::is_playing() const { + return active; +} + +``` + +### Resampling + +Redot's AudioServer currently uses 44100 Hz sample rate. When other sample rates are +needed such as 48000, either provide one or use AudioStreamPlaybackResampled. +Redot provides cubic interpolation for audio resampling. + +Instead of overloading ``mix``, AudioStreamPlaybackResampled uses ``_mix_internal`` to +query AudioFrames and ``get_stream_sampling_rate`` to query current mix rate. + +```cpp +#include "core/reference.h" +#include "core/resource.h" +#include "servers/audio/audio_stream.h" + +class AudioStreamMyToneResampled; + +class AudioStreamPlaybackResampledMyTone : public AudioStreamPlaybackResampled { + GDCLASS(AudioStreamPlaybackResampledMyTone, AudioStreamPlaybackResampled) + friend class AudioStreamMyToneResampled; + +private: + enum { + PCM_BUFFER_SIZE = 4096 + }; + enum { + MIX_FRAC_BITS = 13, + MIX_FRAC_LEN = (1 << MIX_FRAC_BITS), + MIX_FRAC_MASK = MIX_FRAC_LEN - 1, + }; + void *pcm_buffer; + Ref base; + bool active; + +protected: + virtual void _mix_internal(AudioFrame *p_buffer, int p_frames); + +public: + virtual void start(float p_from_pos = 0.0); + virtual void stop(); + virtual bool is_playing() const; + virtual int get_loop_count() const; // times it looped + virtual float get_playback_position() const; + virtual void seek(float p_time); + virtual float get_length() const; // if supported, otherwise return 0 + virtual float get_stream_sampling_rate(); + AudioStreamPlaybackResampledMyTone(); + ~AudioStreamPlaybackResampledMyTone(); +}; + +``` + +```cpp +#include "mytone_audiostream_resampled.h" + +#include "core/math/math_funcs.h" +#include "core/print_string.h" + +AudioStreamPlaybackResampledMyTone::AudioStreamPlaybackResampledMyTone() + : active(false) { + AudioServer::get_singleton()->lock(); + pcm_buffer = AudioServer::get_singleton()->audio_data_alloc(PCM_BUFFER_SIZE); + zeromem(pcm_buffer, PCM_BUFFER_SIZE); + AudioServer::get_singleton()->unlock(); +} +AudioStreamPlaybackResampledMyTone::~AudioStreamPlaybackResampledMyTone() { + if (pcm_buffer) { + AudioServer::get_singleton()->audio_data_free(pcm_buffer); + pcm_buffer = NULL; + } +} +void AudioStreamPlaybackResampledMyTone::stop() { + active = false; + base->reset(); +} +void AudioStreamPlaybackResampledMyTone::start(float p_from_pos) { + seek(p_from_pos); + active = true; +} +void AudioStreamPlaybackResampledMyTone::seek(float p_time) { + float max = get_length(); + if (p_time < 0) { + p_time = 0; + } + base->set_position(uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS); +} +void AudioStreamPlaybackResampledMyTone::_mix_internal(AudioFrame *p_buffer, int p_frames) { + ERR_FAIL_COND(!active); + if (!active) { + return; + } + zeromem(pcm_buffer, PCM_BUFFER_SIZE); + int16_t *buf = (int16_t *)pcm_buffer; + base->gen_tone(buf, p_frames); + + for(int i = 0; i < p_frames; i++) { + float sample = float(buf[i]) / 32767.0; + p_buffer[i] = AudioFrame(sample, sample); + } +} +float AudioStreamPlaybackResampledMyTone::get_stream_sampling_rate() { + return float(base->mix_rate); +} +int AudioStreamPlaybackResampledMyTone::get_loop_count() const { + return 0; +} +float AudioStreamPlaybackResampledMyTone::get_playback_position() const { + return 0.0; +} +float AudioStreamPlaybackResampledMyTone::get_length() const { + return 0.0; +} +bool AudioStreamPlaybackResampledMyTone::is_playing() const { + return active; +} + +``` + +### References: +- [core/math/audio_frame.h](https://github.com/redot-engine/redot-engine/blob/master/core/math/audio_frame.h) +- [servers/audio/audio_stream.h](https://github.com/redot-engine/redot-engine/blob/master/servers/audio/audio_stream.h) +- [scene/audio/audio_stream_player.cpp](https://github.com/redot-engine/redot-engine/blob/master/scene/audio/audio_stream_player.cpp) \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_godot_servers.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_godot_servers.md new file mode 100644 index 0000000..9a98444 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_godot_servers.md @@ -0,0 +1,496 @@ + +# Custom Redot servers + +## Introduction + +Redot implements multi-threading as servers. Servers are daemons which +manage data, process it, and push the result. Servers implement the +mediator pattern which interprets resource ID and process data for the +engine and other modules. In addition, the server claims ownership for +its RID allocations. + +This guide assumes the reader knows how to create C++ modules and Redot +data types. If not, refer to [doc_custom_modules_in_cpp](custom_modules_in_cpp.md). + +### References + +- [Why does Redot use servers and RIDs?](https://godotengine.org/article/why-does-godot-use-servers-and-rids) +- [Singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern) +- [Mediator pattern](https://en.wikipedia.org/wiki/Mediator_pattern) + +## What for? + +- Adding artificial intelligence. +- Adding custom asynchronous threads. +- Adding support for a new input device. +- Adding writing threads. +- Adding a custom VoIP protocol. +- And more... + +## Creating a Redot server + +At minimum, a server must have a static instance, a sleep timer, a thread loop, +an initialization state and a cleanup procedure. + +```cpp +#ifndef HILBERT_HOTEL_H +#define HILBERT_HOTEL_H + +#include "core/object/object.h" +#include "core/os/thread.h" +#include "core/os/mutex.h" +#include "core/templates/list.h" +#include "core/templates/rid.h" +#include "core/templates/set.h" +#include "core/variant/variant.h" + +class HilbertHotel : public Object { + GDCLASS(HilbertHotel, Object); + + static HilbertHotel *singleton; + static void thread_func(void *p_udata); + +private: + bool thread_exited; + mutable bool exit_thread; + Thread *thread; + Mutex *mutex; + +public: + static HilbertHotel *get_singleton(); + Error init(); + void lock(); + void unlock(); + void finish(); + +protected: + static void _bind_methods(); + +private: + uint64_t counter; + RID_Owner bus_owner; + // https://github.com/redot-engine/redot-engine/blob/master/core/templates/rid.h + Set buses; + void _emit_occupy_room(uint64_t room, RID rid); + +public: + RID create_bus(); + Variant get_bus_info(RID id); + bool empty(); + bool delete_bus(RID id); + void clear(); + void register_rooms(); + HilbertHotel(); +}; + +#endif + +``` + +```cpp +#include "hilbert_hotel.h" + +#include "core/variant/dictionary.h" +#include "core/os/os.h" + +#include "prime_225.h" + +void HilbertHotel::thread_func(void *p_udata) { + + HilbertHotel *ac = (HilbertHotel *) p_udata; + uint64_t msdelay = 1000; + + while (!ac->exit_thread) { + if (!ac->empty()) { + ac->lock(); + ac->register_rooms(); + ac->unlock(); + } + OS::get_singleton()->delay_usec(msdelay * 1000); + } +} + +Error HilbertHotel::init() { + thread_exited = false; + counter = 0; + mutex = Mutex::create(); + thread = Thread::create(HilbertHotel::thread_func, this); + return OK; +} + +HilbertHotel *HilbertHotel::singleton = NULL; + +HilbertHotel *HilbertHotel::get_singleton() { + return singleton; +} + +void HilbertHotel::register_rooms() { + for (Set::Element *e = buses.front(); e; e = e->next()) { + auto bus = bus_owner.getornull(e->get()); + + if (bus) { + uint64_t room = bus->next_room(); + _emit_occupy_room(room, bus->get_self()); + } + } +} + +void HilbertHotel::unlock() { + if (!thread || !mutex) { + return; + } + + mutex->unlock(); +} + +void HilbertHotel::lock() { + if (!thread || !mutex) { + return; + } + + mutex->lock(); +} + +void HilbertHotel::_emit_occupy_room(uint64_t room, RID rid) { + _HilbertHotel::get_singleton()->_occupy_room(room, rid); +} + +Variant HilbertHotel::get_bus_info(RID id) { + InfiniteBus *bus = bus_owner.getornull(id); + + if (bus) { + Dictionary d; + d["prime"] = bus->get_bus_num(); + d["current_room"] = bus->get_current_room(); + return d; + } + + return Variant(); +} + +void HilbertHotel::finish() { + if (!thread) { + return; + } + + exit_thread = true; + Thread::wait_to_finish(thread); + + memdelete(thread); + + if (mutex) { + memdelete(mutex); + } + + thread = NULL; +} + +RID HilbertHotel::create_bus() { + lock(); + InfiniteBus *ptr = memnew(InfiniteBus(PRIME[counter++])); + RID ret = bus_owner.make_rid(ptr); + ptr->set_self(ret); + buses.insert(ret); + unlock(); + + return ret; +} + +// https://github.com/redot-engine/redot-engine/blob/master/core/templates/rid.h +bool HilbertHotel::delete_bus(RID id) { + if (bus_owner.owns(id)) { + lock(); + InfiniteBus *b = bus_owner.get(id); + bus_owner.free(id); + buses.erase(id); + memdelete(b); + unlock(); + return true; + } + + return false; +} + +void HilbertHotel::clear() { + for (Set::Element *e = buses.front(); e; e = e->next()) { + delete_bus(e->get()); + } +} + +bool HilbertHotel::empty() { + return buses.size() <= 0; +} + +void HilbertHotel::_bind_methods() { +} + +HilbertHotel::HilbertHotel() { + singleton = this; +} + +``` + +```cpp +const uint64_t PRIME[225] = { + 2,3,5,7,11,13,17,19,23, + 29,31,37,41,43,47,53,59,61, + 67,71,73,79,83,89,97,101,103, + 107,109,113,127,131,137,139,149,151, + 157,163,167,173,179,181,191,193,197, + 199,211,223,227,229,233,239,241,251, + 257,263,269,271,277,281,283,293,307, + 311,313,317,331,337,347,349,353,359, + 367,373,379,383,389,397,401,409,419, + 421,431,433,439,443,449,457,461,463, + 467,479,487,491,499,503,509,521,523, + 541,547,557,563,569,571,577,587,593, + 599,601,607,613,617,619,631,641,643, + 647,653,659,661,673,677,683,691,701, + 709,719,727,733,739,743,751,757,761, + 769,773,787,797,809,811,821,823,827, + 829,839,853,857,859,863,877,881,883, + 887,907,911,919,929,937,941,947,953, + 967,971,977,983,991,997,1009,1013,1019, + 1021,1031,1033,1039,1049,1051,1061,1063,1069, + 1087,1091,1093,1097,1103,1109,1117,1123,1129, + 1151,1153,1163,1171,1181,1187,1193,1201,1213, + 1217,1223,1229,1231,1237,1249,1259,1277,1279, + 1283,1289,1291,1297,1301,1303,1307,1319,1321, + 1327,1361,1367,1373,1381,1399,1409,1423,1427 +}; + +``` + +## Custom managed resource data + +Redot servers implement a mediator pattern. All data types inherit ``RID_Data``. +`RID_Owner` owns the object when ``make_rid`` is called. During debug mode only, +RID_Owner maintains a list of RIDs. In practice, RIDs are similar to writing +object-oriented C code. + +```cpp +class InfiniteBus : public RID_Data { + RID self; + +private: + uint64_t prime_num; + uint64_t num; + +public: + uint64_t next_room() { + return prime_num * num++; + } + + uint64_t get_bus_num() const { + return prime_num; + } + + uint64_t get_current_room() const { + return prime_num * num; + } + + _FORCE_INLINE_ void set_self(const RID &p_self) { + self = p_self; + } + + _FORCE_INLINE_ RID get_self() const { + return self; + } + + InfiniteBus(uint64_t prime) : prime_num(prime), num(1) {}; + ~InfiniteBus() {}; +} + +``` + +### References + +- [RID](/docs/Classes/rid) +- [core/templates/rid.h](https://github.com/redot-engine/redot-engine/blob/master/core/templates/rid.h) + +## Registering the class in GDScript + +Servers are allocated in ``register_types.cpp``. The constructor sets the static +instance and ``init()`` creates the managed thread; ``unregister_types.cpp`` +cleans up the server. + +Since a Redot server class creates an instance and binds it to a static singleton, +binding the class might not reference the correct instance. Therefore, a dummy +class must be created to reference the proper Redot server. + +In ``register_server_types()``, ``Engine::get_singleton()->add_singleton`` +is used to register the dummy class in GDScript. + +```cpp +/* Yes, the word in the middle must be the same as the module folder name */ +void register_hilbert_hotel_types(); +void unregister_hilbert_hotel_types(); + +``` + +```cpp +#include "register_types.h" + +#include "core/object/class_db.h" +#include "core/config/engine.h" + +#include "hilbert_hotel.h" + +static HilbertHotel *hilbert_hotel = NULL; +static _HilbertHotel *_hilbert_hotel = NULL; + +void register_hilbert_hotel_types() { + hilbert_hotel = memnew(HilbertHotel); + hilbert_hotel->init(); + _hilbert_hotel = memnew(_HilbertHotel); + ClassDB::register_class<_HilbertHotel>(); + Engine::get_singleton()->add_singleton(Engine::Singleton("HilbertHotel", _HilbertHotel::get_singleton())); +} + +void unregister_hilbert_hotel_types() { + if (hilbert_hotel) { + hilbert_hotel->finish(); + memdelete(hilbert_hotel); + } + + if (_hilbert_hotel) { + memdelete(_hilbert_hotel); + } +} + +``` + +- [servers/register_server_types.cpp](https://github.com/redot-engine/redot-engine/blob/master/servers/register_server_types.cpp) + +### Bind methods + +The dummy class binds singleton methods to GDScript. In most cases, the dummy class methods wraps around. + +```cpp +Variant _HilbertHotel::get_bus_info(RID id) { + return HilbertHotel::get_singleton()->get_bus_info(id); +} + +``` + +Binding Signals + +It is possible to emit signals to GDScript by calling the GDScript dummy object. + +```cpp +void HilbertHotel::_emit_occupy_room(uint64_t room, RID rid) { + _HilbertHotel::get_singleton()->_occupy_room(room, rid); +} + +``` + +```cpp +class _HilbertHotel : public Object { + GDCLASS(_HilbertHotel, Object); + + friend class HilbertHotel; + static _HilbertHotel *singleton; + +protected: + static void _bind_methods(); + +private: + void _occupy_room(int room_number, RID bus); + +public: + RID create_bus(); + void connect_signals(); + bool delete_bus(RID id); + static _HilbertHotel *get_singleton(); + Variant get_bus_info(RID id); + + _HilbertHotel(); + ~_HilbertHotel(); +}; + +#endif + +``` + +```cpp +_HilbertHotel *_HilbertHotel::singleton = NULL; +_HilbertHotel *_HilbertHotel::get_singleton() { return singleton; } + +RID _HilbertHotel::create_bus() { + return HilbertHotel::get_singleton()->create_bus(); +} + +bool _HilbertHotel::delete_bus(RID rid) { + return HilbertHotel::get_singleton()->delete_bus(rid); +} + +void _HilbertHotel::_occupy_room(int room_number, RID bus) { + emit_signal("occupy_room", room_number, bus); +} + +Variant _HilbertHotel::get_bus_info(RID id) { + return HilbertHotel::get_singleton()->get_bus_info(id); +} + +void _HilbertHotel::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_bus_info", "r_id"), &_HilbertHotel::get_bus_info); + ClassDB::bind_method(D_METHOD("create_bus"), &_HilbertHotel::create_bus); + ClassDB::bind_method(D_METHOD("delete_bus"), &_HilbertHotel::delete_bus); + ADD_SIGNAL(MethodInfo("occupy_room", PropertyInfo(Variant::INT, "room_number"), PropertyInfo(Variant::_RID, "r_id"))); +} + +void _HilbertHotel::connect_signals() { + HilbertHotel::get_singleton()->connect("occupy_room", _HilbertHotel::get_singleton(), "_occupy_room"); +} + +_HilbertHotel::_HilbertHotel() { + singleton = this; +} + +_HilbertHotel::~_HilbertHotel() { +} + +``` + +## MessageQueue + +In order to send commands into SceneTree, MessageQueue is a thread-safe buffer +to queue set and call methods for other threads. To queue a command, obtain +the target object RID and use either ``push_call``, ``push_set``, or ``push_notification`` +to execute the desired behavior. The queue will be flushed whenever either +``SceneTree::idle`` or ``SceneTree::iteration`` is executed. + +### References: + +- [core/object/message_queue.cpp](https://github.com/redot-engine/redot-engine/blob/master/core/object/message_queue.cpp) + +## Summing it up + +Here is the GDScript sample code: + +``` +extends Node + +func _ready(): + print("Start debugging") + HilbertHotel.occupy_room.connect(_print_occupy_room) + var rid = HilbertHotel.create_bus() + OS.delay_msec(2000) + HilbertHotel.create_bus() + OS.delay_msec(2000) + HilbertHotel.create_bus() + OS.delay_msec(2000) + print(HilbertHotel.get_bus_info(rid)) + HilbertHotel.delete_bus(rid) + print("Ready done") + +func _print_occupy_room(room_number, r_id): + print("Room number: " + str(room_number) + ", RID: " + str(r_id)) + print(HilbertHotel.get_bus_info(r_id)) + +``` + +### Notes + +- The actual [Hilbert Hotel](https://en.wikipedia.org/wiki/Hilbert%27s_paradox_of_the_Grand_Hotel) is impossible. +- Connecting signal example code is pretty hacky. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_modules_in_cpp.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_modules_in_cpp.md new file mode 100644 index 0000000..8ad5988 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_modules_in_cpp.md @@ -0,0 +1,752 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Custom modules in C++ + +## Modules + +Redot allows extending the engine in a modular way. New modules can be +created and then enabled/disabled. This allows for adding new engine +functionality at every level without modifying the core, which can be +split for use and reuse in different modules. + +Modules are located in the ``modules/`` subdirectory of the build system. +By default, dozens of modules are enabled, such as GDScript (which, yes, +is not part of the base engine), the Mono runtime, a regular expressions +module, and others. As many new modules as desired can be +created and combined. The SCons build system will take care of it +transparently. + +## What for? + +While it's recommended that most of a game be written in scripting (as +it is an enormous time saver), it's perfectly possible to use C++ +instead. Adding C++ modules can be useful in the following scenarios: + +- Binding an external library to Redot (like PhysX, FMOD, etc). +- Optimize critical parts of a game. +- Adding new functionality to the engine and/or editor. +- Porting an existing game to Redot. +- Write a whole, new game in C++ because you can't live without C++. + +## Creating a new module + +Before creating a module, make sure to :ref:`download the source code of Redot +and compile it <toc-devel-compiling>`. + +To create a new module, the first step is creating a directory inside +``modules/``. If you want to maintain the module separately, you can checkout +a different VCS into modules and use it. + +The example module will be called "summator" (``Redot/modules/summator``). +Inside we will create a summator class: + +```cpp +#ifndef SUMMATOR_H +#define SUMMATOR_H + +#include "core/object/ref_counted.h" + +class Summator : public RefCounted { + GDCLASS(Summator, RefCounted); + + int count; + +protected: + static void _bind_methods(); + +public: + void add(int p_value); + void reset(); + int get_total() const; + + Summator(); +}; + +#endif // SUMMATOR_H + +``` + +And then the cpp file. + +```cpp +#include "summator.h" + +void Summator::add(int p_value) { + count += p_value; +} + +void Summator::reset() { + count = 0; +} + +int Summator::get_total() const { + return count; +} + +void Summator::_bind_methods() { + ClassDB::bind_method(D_METHOD("add", "value"), &Summator::add); + ClassDB::bind_method(D_METHOD("reset"), &Summator::reset); + ClassDB::bind_method(D_METHOD("get_total"), &Summator::get_total); +} + +Summator::Summator() { + count = 0; +} + +``` + +Then, the new class needs to be registered somehow, so two more files +need to be created: + +```none +register_types.h +register_types.cpp + +``` + +:::info + +These files must be in the top-level folder of your module (next to your +``SCsub`` and ``config.py`` files) for the module to be registered properly. + +::: + +These files should contain the following: + +```cpp +#include "modules/register_module_types.h" + +void initialize_summator_module(ModuleInitializationLevel p_level); +void uninitialize_summator_module(ModuleInitializationLevel p_level); +/* yes, the word in the middle must be the same as the module folder name */ + +``` + +```cpp +#include "register_types.h" + +#include "core/object/class_db.h" +#include "summator.h" + +void initialize_summator_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + ClassDB::register_class(); +} + +void uninitialize_summator_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + // Nothing to do here in this example. +} + +``` + +Next, we need to create an ``SCsub`` file so the build system compiles +this module: + +```python +# SCsub + +Import('env') + +env.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build + +``` + +With multiple sources, you can also add each file individually to a Python +string list: + +```python +src_list = ["summator.cpp", "other.cpp", "etc.cpp"] +env.add_source_files(env.modules_sources, src_list) + +``` + +This allows for powerful possibilities using Python to construct the file list +using loops and logic statements. Look at some modules that ship with Redot by +default for examples. + +To add include directories for the compiler to look at you can append it to the +environment's paths: + +```python +env.Append(CPPPATH=["mylib/include"]) # this is a relative path +env.Append(CPPPATH=["#myotherlib/include"]) # this is an 'absolute' path + +``` + +If you want to add custom compiler flags when building your module, you need to clone +``env`` first, so it won't add those flags to whole Redot build (which can cause errors). +Example ``SCsub`` with custom flags: + +```python +Import('env') + +module_env = env.Clone() +module_env.add_source_files(env.modules_sources, "*.cpp") +# Append CCFLAGS flags for both C and C++ code. +module_env.Append(CCFLAGS=['-O2']) +# If you need to, you can: +# - Append CFLAGS for C code only. +# - Append CXXFLAGS for C++ code only. + +``` + +And finally, the configuration file for the module, this is a +Python script that must be named ``config.py``: + +```python +# config.py + +def can_build(env, platform): + return True + +def configure(env): + pass + +``` + +The module is asked if it's OK to build for the specific platform (in +this case, ``True`` means it will build for every platform). + +And that's it. Hope it was not too complex! Your module should look like +this: + +```none +Redot/modules/summator/config.py +Redot/modules/summator/summator.h +Redot/modules/summator/summator.cpp +Redot/modules/summator/register_types.h +Redot/modules/summator/register_types.cpp +Redot/modules/summator/SCsub + +``` + +You can then zip it and share the module with everyone else. When +building for every platform (instructions in the previous sections), +your module will be included. + +:::note +There is a parameter limit of 5 in C++ modules for things such +as subclasses. This can be raised to 13 by including the header +file ``core/method_bind_ext.gen.inc``. + +::: + +## Using the module + +You can now use your newly created module from any script: + + + + + +```gdscript +var s = Summator.new() +s.add(10) +s.add(20) +s.add(30) +print(s.get_total()) +s.reset() +``` + + + + + +The output will be ``60``. + +:::info +The previous Summator example is great for small, custom modules, +but what if you want to use a larger, external library? Refer to +[doc_binding_to_external_libraries](binding_to_external_libraries.md) for details about binding to +external libraries. + +::: + +:::warning +If your module is meant to be accessed from the running project +(not just from the editor), you must also recompile every export +template you plan to use, then specify the path to the custom +template in each export preset. Otherwise, you'll get errors when +running the project as the module isn't compiled in the export +template. See the [Compiling](toc-devel-compiling) pages +for more information. + +::: + +## Compiling a module externally + +Compiling a module involves moving the module's sources directly under the +engine's ``modules/`` directory. While this is the most straightforward way to +compile a module, there are a couple of reasons as to why this might not be a +practical thing to do: + +1. Having to manually copy modules sources every time you want to compile the + engine with or without the module, or taking additional steps needed to + manually disable a module during compilation with a build option similar to + ``module_summator_enabled=no``. Creating symbolic links may also be a solution, + but you may additionally need to overcome OS restrictions like needing the + symbolic link privilege if doing this via script. + +2. Depending on whether you have to work with the engine's source code, the + module files added directly to ``modules/`` changes the working tree to the + point where using a VCS (like ``git``) proves to be cumbersome as you need to + make sure that only the engine-related code is committed by filtering + changes. + +So if you feel like the independent structure of custom modules is needed, lets +take our "summator" module and move it to the engine's parent directory: + +```shell +mkdir ../modules +mv modules/summator ../modules + +``` + +Compile the engine with our module by providing ``custom_modules`` build option +which accepts a comma-separated list of directory paths containing custom C++ +modules, similar to the following: + +```shell +scons custom_modules=../modules + +``` + +The build system shall detect all modules under the ``../modules`` directory +and compile them accordingly, including our "summator" module. + +:::warning + +Any path passed to ``custom_modules`` will be converted to an absolute path +internally as a way to distinguish between custom and built-in modules. It +means that things like generating module documentation may rely on a +specific path structure on your machine. + +::: + +:::info + +[Introduction to the buildsystem - Custom modules build option](doc_buildsystem_custom_modules). + +::: + +## Customizing module types initialization + +Modules can interact with other built-in engine classes during runtime and even +affect the way core types are initialized. So far, we've been using +``register_summator_types`` as a way to bring in module classes to be available +within the engine. + +A crude order of the engine setup can be summarized as a list of the following +type registration methods: + +```cpp +preregister_module_types(); +preregister_server_types(); +register_core_singletons(); +register_server_types(); +register_scene_types(); +EditorNode::register_editor_types(); +register_platform_apis(); +register_module_types(); +initialize_physics(); +initialize_navigation_server(); +register_server_singletons(); +register_driver_types(); +ScriptServer::init_languages(); + +``` + +Our ``Summator`` class is initialized during the ``register_module_types()`` +call. Imagine that we need to satisfy some common module runtime dependency +(like singletons), or allow us to override existing engine method callbacks +before they can be assigned by the engine itself. In that case, we want to +ensure that our module classes are registered *before* any other built-in type. + +This is where we can define an optional ``preregister_summator_types()`` +method which will be called before anything else during the +``preregister_module_types()`` engine setup stage. + +We now need to add this method to ``register_types`` header and source files: + +```cpp +#define MODULE_SUMMATOR_HAS_PREREGISTER +void preregister_summator_types(); + +void register_summator_types(); +void unregister_summator_types(); + +``` + +:::note +Unlike other register methods, we have to explicitly define +``MODULE_SUMMATOR_HAS_PREREGISTER`` to let the build system know what +relevant method calls to include at compile time. The module's name +has to be converted to uppercase as well. + +::: + +```cpp +#include "register_types.h" + +#include "core/object/class_db.h" +#include "summator.h" + +void preregister_summator_types() { + // Called before any other core types are registered. + // Nothing to do here in this example. +} + +void register_summator_types() { + ClassDB::register_class(); +} + +void unregister_summator_types() { + // Nothing to do here in this example. +} + +``` + +## Improving the build system for development + +:::warning + +This shared library support is not designed to support distributing a module +to other users without recompiling the engine. For that purpose, use +a GDExtension instead. + +::: + +So far, we defined a clean SCsub that allows us to add the sources +of our new module as part of the Redot binary. + +This static approach is fine when we want to build a release version of our +game, given we want all the modules in a single binary. + +However, the trade-off is that every single change requires a full recompilation of the +game. Even though SCons is able to detect and recompile only the file that was +changed, finding such files and eventually linking the final binary takes a long time. + +The solution to avoid such a cost is to build our own module as a shared +library that will be dynamically loaded when starting our game's binary. + +```python +Import('env') + +sources = [ + "register_types.cpp", + "summator.cpp" +] + +# First, create a custom env for the shared library. +module_env = env.Clone() + +# Position-independent code is required for a shared library. +module_env.Append(CCFLAGS=['-fPIC']) + +# Don't inject Redot's dependencies into our shared library. +module_env['LIBS'] = [] + +# Define the shared library. By default, it would be built in the module's +# folder, however it's better to output it into `bin` next to the +# Redot binary. +shared_lib = module_env.SharedLibrary(target='#bin/summator', source=sources) + +# Finally, notify the main build environment it now has our shared library +# as a new dependency. + +# LIBPATH and LIBS need to be set on the real "env" (not the clone) +# to link the specified libraries to the Redot executable. + +env.Append(LIBPATH=['#bin']) + +# SCons wants the name of the library with it custom suffixes +# (e.g. ".linuxbsd.tools.64") but without the final ".so". +shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0] +env.Append(LIBS=[shared_lib_shim]) + +``` + +Once compiled, we should end up with a ``bin`` directory containing both the +``Redot*`` binary and our ``libsummator*.so``. However given the .so is not in +a standard directory (like ``/usr/lib``), we have to help our binary find it +during runtime with the ``LD_LIBRARY_PATH`` environment variable: + +```shell +export LD_LIBRARY_PATH="$PWD/bin/" +./bin/Redot* + +``` + +:::note + +You have to ``export`` the environment variable. Otherwise, +you won't be able to run your project from the editor. + +::: + +On top of that, it would be nice to be able to select whether to compile our +module as shared library (for development) or as a part of the Redot binary +(for release). To do that we can define a custom flag to be passed to SCons +using the ``ARGUMENT`` command: + +```python +Import('env') + +sources = [ + "register_types.cpp", + "summator.cpp" +] + +module_env = env.Clone() +module_env.Append(CCFLAGS=['-O2']) + +if ARGUMENTS.get('summator_shared', 'no') == 'yes': + # Shared lib compilation + module_env.Append(CCFLAGS=['-fPIC']) + module_env['LIBS'] = [] + shared_lib = module_env.SharedLibrary(target='#bin/summator', source=sources) + shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0] + env.Append(LIBS=[shared_lib_shim]) + env.Append(LIBPATH=['#bin']) +else: + # Static compilation + module_env.add_source_files(env.modules_sources, sources) + +``` + +Now by default ``scons`` command will build our module as part of Redot's binary +and as a shared library when passing ``summator_shared=yes``. + +Finally, you can even speed up the build further by explicitly specifying your +shared module as target in the SCons command: + +```shell +scons summator_shared=yes platform=linuxbsd bin/libsummator.linuxbsd.tools.64.so + +``` + +## Writing custom documentation + +Writing documentation may seem like a boring task, but it is highly recommended +to document your newly created module to make it easier for users to benefit +from it. Not to mention that the code you've written one year ago may become +indistinguishable from the code that was written by someone else, so be kind to +your future self! + +There are several steps in order to setup custom docs for the module: + +1. Make a new directory in the root of the module. The directory name can be + anything, but we'll be using the ``doc_classes`` name throughout this section. + +2. Now, we need to edit ``config.py``, add the following snippet: + +```python +def get_doc_path(): + return "doc_classes" + +def get_doc_classes(): + return [ + "Summator", + ] + +``` + +The ``get_doc_path()`` function is used by the build system to determine +the location of the docs. In this case, they will be located in the +``modules/summator/doc_classes`` directory. If you don't define this, +the doc path for your module will fall back to the main ``doc/classes`` +directory. + +The ``get_doc_classes()`` method is necessary for the build system to +know which registered classes belong to the module. You need to list all of your +classes here. The classes that you don't list will end up in the +main ``doc/classes`` directory. + +:::tip + +You can use Git to check if you have missed some of your classes by checking the +untracked files with ``git status``. For example + +``` +git status + +``` + +Example output + +``` +Untracked files: + (use "git add ..." to include in what will be committed) + + doc/classes/MyClass2D.xml + doc/classes/MyClass4D.xml + doc/classes/MyClass5D.xml + doc/classes/MyClass6D.xml + ... + +``` + +::: + +3. Now we can generate the documentation: + +We can do this via running Redot's doctool i.e. `[Redot --doctool](path)`, +which will dump the engine API reference to the given ``<path>`` in XML format. + +In our case we'll point it to the root of the cloned repository. You can point it +to an another folder, and just copy over the files that you need. + +Run command: + +``` +bin/ --doctool . + +``` + +Now if you go to the ``Redot/modules/summator/doc_classes`` folder, you will see +that it contains a ``Summator.xml`` file, or any other classes, that you referenced +in your ``get_doc_classes`` function. + +Edit the file(s) following [doc_class_reference_primer](../../Documentation/class_reference_primer.md) and recompile the engine. + +Once the compilation process is finished, the docs will become accessible within +the engine's built-in documentation system. + +In order to keep documentation up-to-date, all you'll have to do is simply modify +one of the XML files and recompile the engine from now on. + +If you change your module's API, you can also re-extract the docs, they will contain +the things that you previously added. Of course if you point it to your Redot +folder, make sure you don't lose work by extracting older docs from an older engine build +on top of the newer ones. + +Note that if you don't have write access rights to your supplied ``<path>``, +you might encounter an error similar to the following: + +```console +ERROR: Can't write doc file: docs/doc/classes/@GDScript.xml + At: editor/doc/doc_data.cpp:956 + +``` + +## Writing custom unit tests + +It's possible to write self-contained unit tests as part of a C++ module. If you +are not familiar with the unit testing process in Redot yet, please refer to +[doc_unit_testing](unit_testing.md). + +The procedure is the following: + +1. Create a new directory named ``tests/`` under your module's root: + +```console +cd modules/summator +mkdir tests +cd tests + +``` + +2. Create a new test suite: ``test_summator.h``. The header must be prefixed + with ``test_`` so that the build system can collect it and include it as part + of the ``tests/test_main.cpp`` where the tests are run. + +3. Write some test cases. Here's an example: + +```cpp +#ifndef TEST_SUMMATOR_H +#define TEST_SUMMATOR_H + +#include "tests/test_macros.h" + +#include "modules/summator/summator.h" + +namespace TestSummator { + +TEST_CASE("[Modules][Summator] Adding numbers") { + Ref s = memnew(Summator); + CHECK(s->get_total() == 0); + + s->add(10); + CHECK(s->get_total() == 10); + + s->add(20); + CHECK(s->get_total() == 30); + + s->add(30); + CHECK(s->get_total() == 60); + + s->reset(); + CHECK(s->get_total() == 0); +} + +} // namespace TestSummator + +#endif // TEST_SUMMATOR_H + +``` + +4. Compile the engine with ``scons tests=yes``, and run the tests with the + following command: + +```console +./bin/ --test --source-file="*test_summator*" --success + +``` + +You should see the passing assertions now. + +## Adding custom editor icons + +Similarly to how you can write self-contained documentation within a module, +you can also create your own custom icons for classes to appear in the editor. + +For the actual process of creating editor icons to be integrated within the engine, +please refer to [doc_editor_icons](../editor/creating_icons.md) first. + +Once you've created your icon(s), proceed with the following steps: + +1. Make a new directory in the root of the module named ``icons``. This is the + default path for the engine to look for module's editor icons. + +2. Move your newly created ``svg`` icons (optimized or not) into that folder. + +3. Recompile the engine and run the editor. Now the icon(s) will appear in + editor's interface where appropriate. + +If you'd like to store your icons somewhere else within your module, +add the following code snippet to ``config.py`` to override the default path: + +```python +def get_icons_path(): + return "path/to/icons" + +``` + +## Summing up + +Remember to: + +- Use ``GDCLASS`` macro for inheritance, so Redot can wrap it. +- Use ``_bind_methods`` to bind your functions to scripting, and to + allow them to work as callbacks for signals. +- **Avoid multiple inheritance for classes exposed to Redot**, as ``GDCLASS`` + doesn't support this. You can still use multiple inheritance in your own + classes as long as they're not exposed to Redot's scripting API. + +But this is not all, depending what you do, you will be greeted with +some (hopefully positive) surprises. + +- If you inherit from [class_Node](/docs/Classes/Node) (or any derived node type, such as + Sprite2D), your new class will appear in the editor, in the inheritance + tree in the "Add Node" dialog. +- If you inherit from [class_Resource](/docs/Classes/Resource), it will appear in the resource + list, and all the exposed properties can be serialized when + saved/loaded. +- By this same logic, you can extend the Editor and almost any area of + the engine. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_platform_ports.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_platform_ports.md new file mode 100644 index 0000000..36aafb4 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_platform_ports.md @@ -0,0 +1,189 @@ + +# Custom platform ports + +Similar to [doc_custom_modules_in_cpp](custom_modules_in_cpp.md), Redot's multi-platform architecture +is designed in a way that allows creating platform ports without modifying any +existing source code. + +An example of a custom platform port distributed independently from the engine +is [FRT](https://github.com/efornara/frt), which targets single-board +computers. Note that this platform port currently targets Redot 3.x; therefore, +it does not use the [class_DisplayServer](/docs/Classes/DisplayServer) abstraction that is new in Redot 4. + +Some reasons to create custom platform ports might be: + +- You want to [port your game to consoles](../../../tutorials/platform/consoles.md), but wish to + write the platform layer yourself. This is a long and arduous process, as it + requires signing NDAs with console manufacturers, but it allows you to have + full control over the console porting process. +- You want to port Redot to an exotic platform that isn't currently supported. + +If you have questions about creating a custom platform port, feel free to ask in +the ``#platforms`` channel of the +[Redot Contributors Chat](https://chat.redotengine.org/channel/platforms). + +:::note + +Redot is a modern engine with modern requirements. Even if you only +intend to run simple 2D projects on the target platform, it still requires +an amount of memory that makes it unviable to run on most retro consoles. +For reference, in Redot 4, an empty project with nothing visible requires +about 100 MB of RAM to run on Linux (50 MB in headless mode). + +If you want to run Redot on heavily memory-constrained platforms, older +Redot versions have lower memory requirements. The porting process is +similar, with the exception of [class_DisplayServer](/docs/Classes/DisplayServer) not being split +from the [class_OS](/docs/Classes/OS) singleton. + +::: + +## Official platform ports + +The official platform ports can be used as a reference when creating a custom platform port: + +- [Windows](https://github.com/redot-engine/redot-engine/tree/master/platform/windows) +- [macOS](https://github.com/redot-engine/redot-engine/tree/master/platform/macos) +- [Linux/\*BSD](https://github.com/redot-engine/redot-engine/tree/master/platform/linuxbsd) +- [Android](https://github.com/redot-engine/redot-engine/tree/master/platform/android) +- [iOS](https://github.com/redot-engine/redot-engine/tree/master/platform/ios) +- [Web](https://github.com/redot-engine/redot-engine/tree/master/platform/web) + +While platform code is usually self-contained, there are exceptions to this +rule. For instance, audio drivers that are shared across several platforms and +rendering drivers are located in the +[drivers/ folder](https://github.com/redot-engine/redot-engine/tree/master/drivers) +of the Redot source code. + +## Creating a custom platform port + +Creating a custom platform port is a large undertaking which requires prior +knowledge of the platform's SDKs. Depending on what features you need, the +amount of work needed varies: + +### Required features of a platform port + +At the very least, a platform port must have methods from the [class_OS](/docs/Classes/OS) +singleton implemented to be buildable and usable for headless operation. +A ``logo.svg`` (32×32) vector image must also be present within the platform +folder. This logo is displayed in the Export dialog for each export preset +targeting the platform in question. + +See [this implementation](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/os_linuxbsd.cpp) +for the Linux/\*BSD platform as an example. See also the +[OS singleton header](https://github.com/redot-engine/redot-engine/blob/master/core/os/os.h) +for reference. + +:::note + +If your target platform is UNIX-like, consider inheriting from the ``OS_Unix`` +class to get much of the work done automatically. + +If the platform is not UNIX-like, you might use the +[Windows port](https://github.com/redot-engine/redot-engine/blob/master/platform/windows/os_windows.cpp) +as a reference. + +::: + +**detect.py file** + +A ``detect.py`` file must be created within the platform's folder with all +methods implemented. This file is required for SCons to detect the platform as a +valid option for compiling. See the +[detect.py file](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/detect.py) +for the Linux/\*BSD platform as an example. + +All methods should be implemented within ``detect.py`` as follows: + +- ``is_active()``: Can be used to temporarily disable building for a platform. + This should generally always return ``True``. +- ``get_name()``: Returns the platform's user-visible name as a string. +- ``can_build()``: Return ``True`` if the host system is able to build for the + target platform, ``False`` otherwise. Do not put slow checks here, as this is + queried when the list of platforms is requested by the user. Use + ``configure()`` for extensive dependency checks instead. +- ``get_opts()``: Returns the list of SCons build options that can be defined by + the user for this platform. +- ``get_flags()``: Returns the list of overridden SCons flags for this platform. +- ``configure()``: Perform build configuration, such as selecting compiler + options depending on SCons options chosen. + +### Optional features of a platform port + +In practice, headless operation doesn't suffice if you want to see anything on +screen and handle input devices. You may also want audio output for most +games. + +*Some links on this list point to the Linux/\*BSD platform implementation as a reference.* + +- One or more [DisplayServers](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/x11/display_server_x11.cpp), + with the windowing methods implemented. DisplayServer also covers features such + as mouse support, touchscreen support and tablet driver (for pen input). + See the + [DisplayServer singleton header](https://github.com/redot-engine/redot-engine/blob/master/servers/display_server.h) + for reference. + + - For platforms not featuring full windowing support (or if it's not relevant + for the port you are making), most windowing functions can be left mostly + unimplemented. These functions can be made to only check if the window ID is + ``MAIN_WINDOW_ID`` and specific operations like resizing may be tied to the + platform's screen resolution feature (if relevant). Any attempt to create + or manipulate other window IDs can be rejected. +- *If the target platform supports the graphics APIs in question:* Rendering + context for [Vulkan](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp), + [Direct3D 12](https://github.com/redot-engine/redot-engine/blob/master/drivers/d3d12/rendering_context_driver_d3d12.cpp) + [OpenGL 3.3 or OpenGL ES 3.0](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/x11/gl_manager_x11.cpp). +- Input handlers for [keyboard](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/x11/key_mapping_x11.cpp) + and [controller](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/joypad_linux.cpp). +- One or more [audio drivers](https://github.com/redot-engine/redot-engine/blob/master/drivers/pulseaudio/audio_driver_pulseaudio.cpp). + The audio driver can be located in the ``platform/`` folder (this is done for + the Android and Web platforms), or in the ``drivers/`` folder if multiple + platforms may be using this audio driver. See the + [AudioServer singleton header](https://github.com/redot-engine/redot-engine/blob/master/servers/audio_server.h) + for reference. +- [Crash handler](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/crash_handler_linuxbsd.cpp), + for printing crash backtraces when the game crashes. This allows for easier + troubleshooting on platforms where logs aren't readily accessible. +- [Text-to-speech driver](https://github.com/redot-engine/redot-engine/blob/master/platform/linuxbsd/tts_linux.cpp) + (for accessibility). +- [Export handler](https://github.com/redot-engine/redot-engine/tree/master/platform/linuxbsd/export) + (for exporting from the editor, including [doc_one-click_deploy](../../../tutorials/export/one-click_deploy.md)). + Not required if you intend to export only a PCK from the editor, then run the + export template binary directly by renaming it to match the PCK file. See the + [EditorExportPlatform header](https://github.com/redot-engine/redot-engine/blob/master/editor/export/editor_export_platform.h) + for reference. + ``run_icon.svg`` (16×16) should be present within the platform folder if + [doc_one-click_deploy](../../../tutorials/export/one-click_deploy.md) is implemented for the target platform. This icon + is displayed at the top of the editor when one-click deploy is set up for the + target platform. + +If the target platform doesn't support running Vulkan, Direct3D 12, OpenGL 3.3, +or OpenGL ES 3.0, you have two options: + +- Use a library at runtime to translate Vulkan or OpenGL calls to another graphics API. + For example, [MoltenVK](https://moltengl.com/moltenvk/) is used on macOS + to translate Vulkan to Metal at runtime. +- Create a new renderer from scratch. This is a large undertaking, especially if + you want to support both 2D and 3D rendering with advanced features. + +## Distributing a custom platform port + +:::danger + +Before distributing a custom platform port, make sure you're allowed to +distribute all the code that is being linked against. Console SDKs are +typically under NDAs which prevent redistribution to the public. + +::: + +Platform ports are designed to be as self-contained as possible. Most of the +code can be kept within a single folder located in ``platform/``. Like +[doc_custom_modules_in_cpp](custom_modules_in_cpp.md), this allows for streamlining the build process +by making it possible to ``git clone`` a platform folder within a Redot repository +clone's ``platform/`` folder, then run `[scons platform=](name)`. No other steps are +necessary for building, unless third-party platform-specific dependencies need +to be installed first. + +However, when a custom rendering driver is needed, another folder must be added +in ``drivers/``. In this case, the platform port can be distributed as a fork of +the Redot repository, or as a collection of several folders that can be added +over a Redot Git repository clone. \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_resource_format_loaders.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_resource_format_loaders.md new file mode 100644 index 0000000..79a14ef --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/custom_resource_format_loaders.md @@ -0,0 +1,364 @@ + +# Custom resource format loaders + +## Introduction + +ResourceFormatLoader is a factory interface for loading file assets. +Resources are primary containers. When load is called on the same file +path again, the previous loaded Resource will be referenced. Naturally, +loaded resources must be stateless. + +This guide assumes the reader knows how to create C++ modules and Redot +data types. If not, refer to this guide: [doc_custom_modules_in_cpp](custom_modules_in_cpp.md) + +### References + +- [ResourceLoader](/docs/Classes/resourceloader) +- [core/io/resource_loader.cpp](https://github.com/redot-engine/redot-engine/blob/master/core/io/resource_loader.cpp) + +## What for? + +- Adding new support for many file formats +- Audio formats +- Video formats +- Machine learning models + +## What not? + +- Raster images + +ImageFormatLoader should be used to load images. + +### References + +- [core/io/image_loader.h](https://github.com/redot-engine/redot-engine/blob/master/core/io/image_loader.h) + +## Creating a ResourceFormatLoader + +Each file format consist of a data container and a ``ResourceFormatLoader``. + +ResourceFormatLoaders are classes which return all the +necessary metadata for supporting new extensions in Redot. The +class must return the format name and the extension string. + +In addition, ResourceFormatLoaders must convert file paths into +resources with the ``load`` function. To load a resource, ``load`` must +read and handle data serialization. + +```cpp +#ifndef RESOURCE_LOADER_JSON_H +#define RESOURCE_LOADER_JSON_H + +#include "core/io/resource_loader.h" + +class ResourceFormatLoaderJson : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderJson, ResourceFormatLoader); +public: + virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL); + virtual void get_recognized_extensions(List *r_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; +#endif // RESOURCE_LOADER_JSON_H + +``` + +```cpp +#include "resource_loader_json.h" + +#include "resource_json.h" + +RES ResourceFormatLoaderJson::load(const String &p_path, const String &p_original_path, Error *r_error) { +Ref json = memnew(JsonResource); + if (r_error) { + *r_error = OK; + } + Error err = json->load_file(p_path); + return json; +} + +void ResourceFormatLoaderJson::get_recognized_extensions(List *r_extensions) const { + if (!r_extensions->find("json")) { + r_extensions->push_back("json"); + } +} + +String ResourceFormatLoaderJson::get_resource_type(const String &p_path) const { + return "Resource"; +} + +bool ResourceFormatLoaderJson::handles_type(const String &p_type) const { + return ClassDB::is_parent_class(p_type, "Resource"); +} + +``` + +## Creating a ResourceFormatSaver + +If you'd like to be able to edit and save a resource, you can implement a +``ResourceFormatSaver``: + +```cpp +#ifndef RESOURCE_SAVER_JSON_H +#define RESOURCE_SAVER_JSON_H + +#include "core/io/resource_saver.h" + +class ResourceFormatSaverJson : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverJson, ResourceFormatSaver); +public: + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const RES &p_resource) const; + virtual void get_recognized_extensions(const RES &p_resource, List *r_extensions) const; +}; +#endif // RESOURCE_SAVER_JSON_H + +``` + +```cpp +#include "resource_saver_json.h" + +#include "resource_json.h" +#include "scene/resources/resource_format_text.h" + +Error ResourceFormatSaverJson::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + Ref json = memnew(JsonResource); + Error error = json->save_file(p_path, p_resource); + return error; +} + +bool ResourceFormatSaverJson::recognize(const RES &p_resource) const { + return Object::cast_to(*p_resource) != NULL; +} + +void ResourceFormatSaverJson::get_recognized_extensions(const RES &p_resource, List *r_extensions) const { + if (Object::cast_to(*p_resource)) { + r_extensions->push_back("json"); + } +} + +``` + +## Creating custom data types + +Redot may not have a proper substitute within its [doc_core_types](core_types.md) +or managed resources. Redot needs a new registered data type to +understand additional binary formats such as machine learning models. + +Here is an example of creating a custom datatype: + +```cpp +#ifndef RESOURCE_JSON_H +#define RESOURCE_JSON_H + +#include "core/io/json.h" +#include "core/variant_parser.h" + +class JsonResource : public Resource { + GDCLASS(JsonResource, Resource); + +protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("set_dict", "dict"), &JsonResource::set_dict); + ClassDB::bind_method(D_METHOD("get_dict"), &JsonResource::get_dict); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "content"), "set_dict", "get_dict"); + } + +private: + Dictionary content; + +public: + Error load_file(const String &p_path); + Error save_file(const String &p_path, const RES &p_resource); + + void set_dict(const Dictionary &p_dict); + Dictionary get_dict(); +}; +#endif // RESOURCE_JSON_H + +``` + +```cpp +#include "resource_json.h" + +Error JsonResource::load_file(const String &p_path) { + Error error; + FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error); + if (error != OK) { + if (file) { + file->close(); + } + return error; + } + + String json_string = String(""); + while (!file->eof_reached()) { + json_string += file->get_line(); + } + file->close(); + + String error_string; + int error_line; + JSON json; + Variant result; + error = json.parse(json_string, result, error_string, error_line); + if (error != OK) { + file->close(); + return error; + } + + content = Dictionary(result); + return OK; +} + +Error JsonResource::save_file(const String &p_path, const RES &p_resource) { + Error error; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &error); + if (error != OK) { + if (file) { + file->close(); + } + return error; + } + + Ref json_ref = p_resource.get_ref_ptr(); + JSON json; + + file->store_string(json.print(json_ref->get_dict(), " ")); + file->close(); + return OK; +} + +void JsonResource::set_dict(const Dictionary &p_dict) { + content = p_dict; +} + +Dictionary JsonResource::get_dict() { + return content; +} + +``` + +### Considerations + +Some libraries may not define certain common routines such as IO handling. +Therefore, Redot call translations are required. + +For example, here is the code for translating ``FileAccess`` +calls into ``std::istream``. + +```cpp +#include "core/io/file_access.h" + +#include +#include + +class RedotFileInStreamBuf : public std::streambuf { + +public: + RedotFileInStreamBuf(FileAccess *fa) { + _file = fa; + } + int underflow() { + if (_file->eof_reached()) { + return EOF; + } else { + size_t pos = _file->get_position(); + uint8_t ret = _file->get_8(); + _file->seek(pos); // Required since get_8() advances the read head. + return ret; + } + } + int uflow() { + return _file->eof_reached() ? EOF : _file->get_8(); + } + +private: + FileAccess *_file; +}; + +``` + +### References + +- [istream](https://cplusplus.com/reference/istream/istream/) +- [streambuf](https://cplusplus.com/reference/streambuf/streambuf/?kw=streambuf) +- [core/io/file_access.h](https://github.com/redot-engine/redot-engine/blob/master/core/io/file_access.h) + +## Registering the new file format + +Redot registers ``ResourcesFormatLoader`` with a ``ResourceLoader`` +handler. The handler selects the proper loader automatically +when ``load`` is called. + +```cpp +void register_json_types(); +void unregister_json_types(); + +``` + +```cpp +#include "register_types.h" + +#include "core/class_db.h" +#include "resource_loader_json.h" +#include "resource_saver_json.h" +#include "resource_json.h" + +static Ref json_loader; +static Ref json_saver; + +void register_json_types() { + ClassDB::register_class(); + + json_loader.instantiate(); + ResourceLoader::add_resource_format_loader(json_loader); + + json_saver.instantiate(); + ResourceSaver::add_resource_format_saver(json_saver); +} + +void unregister_json_types() { + ResourceLoader::remove_resource_format_loader(json_loader); + json_loader.unref(); + + ResourceSaver::remove_resource_format_saver(json_saver); + json_saver.unref(); +} + +``` + +### References + +- [core/io/resource_loader.cpp](https://github.com/redot-engine/redot-engine/blob/master/core/io/resource_loader.cpp) + +## Loading it on GDScript + +Save a file called ``demo.json`` with the following contents and place it in the +project's root folder: + +```json +{ + "savefilename": "demo.json", + "demo": [ + "welcome", + "to", + "Redot", + "resource", + "loaders" + ] +} + +``` + +Then attach the following script to any node + +``` +extends Node + +@onready var json_resource = load("res://demo.json") + +func _ready(): + print(json_resource.get_dict()) +``` diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/files/class_tree.zip b/Redot-Documentation/docs/Contributing/Development/core_and_modules/files/class_tree.zip new file mode 100644 index 0000000000000000000000000000000000000000..99ccef0983685cb1db616b222f367e0f2b49c15a GIT binary patch literal 55874 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 JKk;Yn{{ZvyRSN(B literal 0 HcmV?d00001 diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/godot_architecture_diagram.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/godot_architecture_diagram.md new file mode 100644 index 0000000..9dfe374 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/godot_architecture_diagram.md @@ -0,0 +1,8 @@ + +# Redot's architecture diagram + +The following diagram describes the architecture used by Redot, from the +core components down to the abstracted drivers, via the scene +structure and the servers. + +![Image](img/architecture_diagram.jpg) \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/inheritance_class_tree.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/inheritance_class_tree.md new file mode 100644 index 0000000..1e44119 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/inheritance_class_tree.md @@ -0,0 +1,23 @@ +# Inheritance class tree + +## Object + +![Image](img/Object.webp) + +## Reference + +![Image](img/RefCounted.webp) + +## Control + +![Image](img/Control.webp) + +## Node2D + +![Image](img/Node2D.webp) + +## Node3D + +![Image](img/Node3D.webp) + +Source files: :download:[class_tree.zip](files/class_tree.zip). \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/internal_rendering_architecture.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/internal_rendering_architecture.md new file mode 100644 index 0000000..e1e1f4d --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/internal_rendering_architecture.md @@ -0,0 +1,815 @@ + +# Internal rendering architecture + +This page is a high-level overview of Redot 4's internal renderer design. +It does not apply to previous Redot versions. + +The goal of this page is to document design decisions taken to best suit +[Redot's design philosophy](doc_best_practices_for_engine_contributors), +while providing a starting point for new rendering contributors. + +If you have questions about rendering internals not answered here, feel free to +ask in the ``#rendering`` channel of the +[Redot Contributors Chat](https://chat.redotengine.org/channel/rendering). + +:::note + +If you have difficulty understanding concepts on this page, it is +recommended to go through an OpenGL tutorial such as +[LearnOpenGL](https://learnopengl.com/). + +Modern low-level APIs (Vulkan/Direct3D 12/Metal) require intermediate +knowledge of higher-level APIs (OpenGL/Direct3D 11) to be used +effectively. Thankfully, contributors rarely need to work directly with +low-level APIs. Redot's renderers are built entirely on OpenGL and +RenderingDevice, which is our abstraction over Vulkan/Direct3D 12/Metal. + +::: + +## Rendering methods + +### Forward+ + +This is a forward renderer that uses a *clustered* approach to lighting. + +Clustered lighting uses a compute shader to group lights into a 3D frustum +aligned grid. Then, at render time, pixels can lookup what lights affect the +grid cell they are in and only run light calculations for lights that might +affect that pixel. + +This approach can greatly speed up rendering performance on desktop hardware, +but is substantially less efficient on mobile. + +### Mobile + +This is a forward renderer that uses a traditional single-pass approach to lighting. +Internally, it is called **Forward Mobile**. + +Intended for mobile platforms, but can also run on desktop platforms. This +rendering method is optimized to perform well on mobile GPUs. Mobile GPUs have a +very different architecture compared to desktop GPUs due to their unique +constraints around battery usage, heat, and overall bandwidth limitations of +reading and writing data. Compute shaders also have very limited support or +aren't supported at all. As a result, the mobile renderer purely uses +raster-based shaders (fragment/vertex). + +Unlike desktop GPUs, mobile GPUs perform *tile-based rendering*. Instead of +rendering the whole image as a single unit, the image is divided in smaller +tiles that fit within the faster internal memory of the mobile GPU. Each tile is +rendered and then written out to the destination texture. This all happens +automatically on the graphics driver. + +The problem is that this introduces bottlenecks in our traditional approach. For +desktop rendering, we render all opaque geometry, then handle the background, +then transparent geometry, then post-processing. Each pass will need to read the +current result into tile memory, perform its operations and then write it out +again. We then wait for all tiles to be completed before moving on to the next +pass. + +The first important change in the mobile renderer is that the mobile renderer +does not use the RGBA16F texture formats that the desktop renderer does. +Instead, it is using an R10G10B10A2 UNORM texture format. This halves the bandwidth +required and has further improvements as mobile hardware often further optimizes +for 32-bit formats. The tradeoff is that the mobile renderer has limited HDR +capabilities due to the reduced precision and maximum values in the color data. + +The second important change is the use of sub-passes whenever possible. +Sub-passes allows us to perform the rendering steps end-to-end per tile saving +on the overhead introduced by reading from and writing to the tiles between each +rendering pass. The ability to use sub-passes is limited by the inability to +read neighboring pixels, as we're constrained to working within a single tile. + +This limitation of subpasses results in not being able to implement features +such as glow and depth of field efficiently. Similarly, if there is a +requirement to read from the screen texture or depth texture, we must fully +write out the rendering result limiting our ability to use sub-passes. When such +features are enabled, a mix of sub-passes and normal passes are used, and these +features result in a notable performance penalty. + +On desktop platforms, the use of sub-passes won't have any impact on +performance. However, this rendering method can still perform better than +Forward+ in simple scenes thanks to its lower complexity and lower +bandwidth usage. This is especially noticeable on low-end GPUs, integrated +graphics or in VR applications. + +Given its low-end focus, this rendering method does not provide high-end +rendering features such as SDFGI and [doc_volumetric_fog](doc_volumetric_fog). Several +post-processing effects are also not available. + +### Compatibility + +:::note + +This is the only rendering method available when using the OpenGL driver. +This rendering method is not available when using Vulkan, Direct3D 12, or Metal. + +::: + +This is a traditional (non-clustered) forward renderer. Internally, it is called +**GL Compatibility**. It's intended for old GPUs that don't have Vulkan support, +but still works very efficiently on newer hardware. Specifically, it is optimized +for older and lower-end mobile devices. However, many optimizations carry over +making it a good choice for older and lower-end desktop as well. + +Like the Mobile renderer, the Compatibility renderer uses an R10G10B10A2 UNORM +texture for 3D rendering. Unlike the mobile renderer, colors are tonemapped and +stored in sRGB format so there is no HDR support. This avoids the need for a +tonemapping pass and allows us to use the lower bit texture without substantial +banding. + +The Compatibility renderer uses a traditional forward single-pass approach to +drawing objects with lights, but it uses a multi-pass approach to draw lights +with shadows. Specifically, in the first pass, it can draw multiple lights +without shadows and up to one DirectionalLight3D with shadows. In each +subsequent pass, it can draw up to one OmniLight3D, one SpotLight3D and one +DirectionalLight3D with shadows. Lights with shadows will affect the scene +differently than lights without shadows, as the lighting is blended in sRGB space +instead of linear space. This difference in lighting will impact how the scene +looks and needs to be kept in mind when designing scenes for the Compatibility +renderer. + +Given its low-end focus, this rendering method does not provide high-end +rendering features (even less so compared to Mobile). Most +post-processing effects are not available. + +### Why not deferred rendering? + +Forward rendering generally provides a better tradeoff for performance versus +flexibility, especially when a clustered approach to lighting is used. While +deferred rendering can be faster in some cases, it's also less flexible and +requires using hacks to be able to use MSAA. Since games with a less realistic +art style can benefit a lot from MSAA, we chose to go with forward rendering for +Redot 4 (like Redot 3). + +That said, parts of the forward renderer *are* performed with a deferred approach +to allow for some optimizations when possible. This applies to VoxelGI and SDFGI +in particular. + +A clustered deferred renderer may be developed in the future. This renderer +could be used in situations where performance is favored over flexibility. + +## Rendering drivers + +Redot 4 supports the following graphics APIs: + +### Vulkan + +This is the main driver in Redot 4, with most of the development focus going +towards this driver. + +Vulkan 1.0 is required as a baseline, with optional Vulkan 1.1 and 1.2 features +used when available. [volk](https://github.com/zeux/volk) is used as a Vulkan +loader, and +[Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) +is used for memory management. + +Both the Forward+ and Mobile +[doc_internal_rendering_architecture_methods](doc_internal_rendering_architecture_methods) are supported when using the +Vulkan driver. + +**Vulkan context creation:** + +- [drivers/vulkan/vulkan_context.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/drivers/vulkan/vulkan_context.cpp) + +**Direct3D 12 context creation:** + +- [drivers/d3d12/d3d12_context.cpp](https://github.com/redot-engine/redot-engine/blob/master/drivers/d3d12/d3d12_context.cpp) + +### Direct3D 12 + +Like Vulkan, the Direct3D 12 driver targets modern platforms only. It is +designed to target both Windows and Xbox (whereas Vulkan can't be used directly on Xbox). + +Both the Forward+ and Mobile [doc_internal_rendering_architecture_methods](doc_internal_rendering_architecture_methods) can be +used with Direct3D 12. + +[doc_internal_rendering_architecture_core_shaders](doc_internal_rendering_architecture_core_shaders) are shared with the +Vulkan renderer. Shaders are transpiled from +:abbr:`SPIR-V (Standard Portable Intermediate Representation)` to +:abbr:`DXIL (DirectX Intermediate Language)` using +Mesa NIR ([more information](https://godotengine.org/article/d3d12-adventures-in-shaderland/)). + +**This driver is still experimental and only available in Redot 4.3 and later.** +While Direct3D 12 allows supporting Direct3D-exclusive features on Windows 11 such +as windowed optimizations and Auto HDR, Vulkan is still recommended for most projects. +See the [pull request that introduced Direct3D 12 support](https://github.com/redot-engine/redot-engine/pull/70315) +for more information. + +### Metal + +Redot provides a native Metal driver that works on all Apple Silicon hardware +(macOS ARM). Compared to using the MoltenVK translation layer, this is +significantly faster, particularly in CPU-bound scenarios. + +Both the Forward+ and Mobile [doc_internal_rendering_architecture_methods](doc_internal_rendering_architecture_methods) can be +used with Metal. + +[doc_internal_rendering_architecture_core_shaders](doc_internal_rendering_architecture_core_shaders) are shared with the +Vulkan renderer. Shaders are transpiled from GLSL to :abbr:`MSL (Metal Shading Language)` +using SPIRV-Cross. + +Redot also supports Metal rendering via [MoltenVK](https://github.com/KhronosGroup/MoltenVK), +which is used as a fallback when native Metal support is not available (e.g. on x86 macOS). + +**This driver is still experimental and only available in Redot 4.4 and later.** +See the [pull request that introduced Metal support](https://github.com/redot-engine/redot-engine/pull/88199) +for more information. + +### OpenGL + +This driver uses OpenGL ES 3.0 and targets legacy and low-end devices that don't +support Vulkan. OpenGL 3.3 Core Profile is used on desktop platforms to run this +driver, as most graphics drivers on desktop don't support OpenGL ES. +WebGL 2.0 is used for web exports. + +It is possible to use OpenGL ES 3.0 directly on desktop platforms +by passing the ``--rendering-driver opengl3_es`` command line argument, although this +will only work on graphics drivers that feature native OpenGL ES support (such +as Mesa). + +Only the [doc_internal_rendering_architecture_compatibility](doc_internal_rendering_architecture_compatibility) rendering +method can be used with the OpenGL driver. + +[doc_internal_rendering_architecture_core_shaders](doc_internal_rendering_architecture_core_shaders) are entirely different +from the Vulkan renderer. + +Many advanced features are not supported with this driver, as it targets low-end +devices first and foremost. + +### Summary of rendering drivers/methods + +The following rendering API + rendering method combinations are currently possible: + +- Vulkan + Forward+ (optionally through MoltenVK on macOS and iOS) +- Vulkan + Mobile (optionally through MoltenVK on macOS and iOS) +- Direct3D 12 + Forward+ +- Direct3D 12 + Mobile +- Metal + Forward+ +- Metal + Mobile +- OpenGL + Compatibility (optionally through ANGLE on Windows and macOS) + +Each combination has its own limitations and performance characteristics. Make +sure to test your changes on all rendering methods if possible before opening a +pull request. + +## RenderingDevice abstraction + +:::note + +The OpenGL driver does not use the RenderingDevice abstraction. + +::: + +To make the complexity of modern low-level graphics APIs more manageable, +Redot uses its own abstraction called RenderingDevice. + +This means that when writing code for modern rendering methods, you don't +actually use the Vulkan, Direct3D 12, or Metal APIs directly. While this is still +lower-level than an API like OpenGL, this makes working on the renderer easier, +as RenderingDevice will abstract many API-specific quirks for you. The +RenderingDevice presents a similar level of abstraction as WebGPU. + +**Vulkan RenderingDevice implementation:** + +- [drivers/vulkan/rendering_device_driver_vulkan.cpp](https://github.com/redot-engine/redot-engine/blob/master/drivers/vulkan/rendering_device_driver_vulkan.cpp) + +**Direct3D 12 RenderingDevice implementation:** + +- [drivers/d3d12/rendering_device_driver_d3d12.cpp](https://github.com/redot-engine/redot-engine/blob/master/drivers/d3d12/rendering_device_driver_d3d12.cpp) + +**Metal RenderingDevice implementation:** + +- [drivers/metal/rendering_device_driver_metal.mm](https://github.com/redot-engine/redot-engine/blob/master/drivers/metal/rendering_device_driver_metal.mm) + +## Core rendering classes architecture + +This diagram represents the structure of rendering classes in Redot, including the RenderingDevice abstraction: + +![Image](img/rendering_architecture_diagram.webp) + +[View at full size](https://raw.githubusercontent.com/Redot-engine/Redot-docs/master/contributing/development/core_and_modules/img/rendering_architecture_diagram.webp) + +## Core shaders + +While shaders in Redot projects are written using a +[custom language inspired by GLSL](doc_shading_language), core shaders are +written directly in GLSL. + +These core shaders are embedded in the editor and export template binaries at +compile-time. To see any changes you've made to those GLSL shaders, you need to +recompile the editor or export template binary. + +Some material features such as height mapping, refraction and proximity fade are +not part of core shaders, and are performed in the default BaseMaterial3D using +the Redot shader language instead (not GLSL). This is done by procedurally +generating the required shader code depending on the features enabled in the +material. + +By convention, shader files with ``_inc`` in their name are included in other +GLSL files for better code reuse. Standard GLSL preprocessing is used to achieve +this. + +:::warning + +Core material shaders will be used by every material in the scene – both +with the default BaseMaterial3D and custom shaders. As a result, these +shaders must be kept as simple as possible to avoid performance issues and +ensure shader compilation doesn't become too slow. + +If you use ``if`` branching in a shader, performance may decrease as +:abbr:`VGPR (Vector General-Purpose Register)` usage will increase in the +shader. This happens even if all pixels evaluate to ``true`` or ``false`` in +a given frame. + +If you use ``#if`` preprocessor branching, the number of required shader +versions will increase in the scene. In a worst-case scenario, adding a +single boolean ``#define`` can *double* the number of shader versions that +may need to be compiled in a given scene. In some cases, Vulkan +specialization constants can be used as a faster (but more limited) +alternative. + +This means there is a high barrier to adding new built-in material features +in Redot, both in the core shaders and BaseMaterial3D. While BaseMaterial3D +can make use of dynamic code generation to only include the shader code if +the feature is enabled, it'll still require generating more shader versions +when these features are used in a project. This can make shader compilation +stutter more noticeable in complex 3D scenes. + +See +[The Shader Permutation Problem](https://therealmjp.github.io/posts/shader-permutations-part1/) +and +[Branching on a GPU](https://medium.com/@jasonbooth_86226/branching-on-a-gpu-18bfc83694f2) +blog posts for more information. + +::: + +**Core GLSL material shaders:** + +- Forward+: [servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl) +- Mobile: [servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl) +- Compatibility: [drivers/gles3/shaders/scene.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/drivers/gles3/shaders/scene.glsl) + +**Material shader generation:** + +- [scene/resources/material.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/resources/material.cpp) + +**Other GLSL shaders for Forward+ and Mobile rendering methods:** + +- [servers/rendering/renderer_rd/shaders/](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/) +- [modules/lightmapper_rd/](https://github.com/redot-engine/redot-engine/blob/4.2/modules/lightmapper_rd) + +**Other GLSL shaders for the Compatibility rendering method:** + +- [drivers/gles3/shaders/](https://github.com/redot-engine/redot-engine/blob/4.2/drivers/gles3/shaders/) + +## 2D and 3D rendering separation + +:::note + +The following is only applicable in the Forward+ and Mobile +rendering methods, not in Compatibility. Multiple Viewports can be used to +emulate this when using the Compatibility renderer, or to perform 2D +resolution scaling. + +::: + +2D and 3D are rendered to separate buffers, as 2D rendering in Redot is performed +in :abbr:`LDR (Low Dynamic Range)` sRGB-space while 3D rendering uses +:abbr:`HDR (High Dynamic Range)` linear space. + +The color format used for 2D rendering is RGB8 (RGBA8 if the **Transparent** +property on the Viewport is enabled). 3D rendering uses a 24-bit unsigned +normalized integer depth buffer, or 32-bit signed floating-point if a 24-bit +depth buffer is not supported by the hardware. 2D rendering does not use a depth +buffer. + +3D resolution scaling is performed differently depending on whether bilinear or +FSR 1.0 scaling is used. When bilinear scaling is used, no special upscaling +shader is run. Instead, the viewport's texture is stretched and displayed with a +linear sampler (which makes the filtering happen directly on the hardware). This +allows maximizing the performance of bilinear 3D scaling. + +The ``configure()`` function in RenderSceneBuffersRD reallocates the 2D/3D +buffers when the resolution or scaling changes. + +Dynamic resolution scaling isn't supported yet, but is planned in a future Redot +release. + +**2D and 3D rendering buffer configuration C++ code:** + +- [servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp) + +**FSR 1.0:** + +- [servers/rendering/renderer_rd/effects/fsr.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/effects/fsr.cpp) +- [thirdparty/amd-fsr/](https://github.com/redot-engine/redot-engine/tree/master/thirdparty/amd-fsr) + +## 2D rendering techniques + +2D light rendering is performed in a single pass to allow for better performance +with large amounts of lights. + +The Forward+ and Mobile rendering methods don't feature 2D batching yet, but +it's planned for a future release. + +The Compatibility renderer features 2D batching to improve performance, which is +especially noticeable with lots of text on screen. + +MSAA can be enabled in 2D to provide "automatic" line and polygon antialiasing, +but FXAA does not affect 2D rendering as it's calculated before 2D rendering +begins. Redot's 2D drawing methods such as the Line2D node or some CanvasItem +``draw_*()`` methods provide their own way of antialiasing based on triangle +strips and vertex colors, which don't require MSAA to work. + +A 2D signed distance field representing LightOccluder2D nodes in the viewport is +automatically generated if a user shader requests it. This can be used for +various effects in custom shaders, such as 2D global illumination. It is also +used to calculate particle collisions in 2D. + +**2D SDF generation GLSL shader:** + +- [servers/rendering/renderer_rd/shaders/canvas_sdf.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl) + +## 3D rendering techniques + +### Batching and instancing + +In the Forward+ renderer, Vulkan instancing is used to group rendering +of identical objects for performance. This is not as fast as static mesh +merging, but it still allows instances to be culled individually. + +### Light, decal and reflection probe rendering + +:::note + +Decal rendering is currently not available in the Compatibility renderer. + +::: + +The Forward+ renderer uses clustered lighting. This +allows using as many lights as you want; performance largely depends on screen +coverage. Shadow-less lights can be almost free if they don't occupy much space +on screen. + +All rendering methods also support rendering up to 8 directional lights at the +same time (albeit with lower shadow quality when more than one light has shadows +enabled). + +The Mobile renderer uses a single-pass lighting approach, with a +limitation of 8 OmniLights + 8 SpotLights affecting each Mesh *resource* (plus a +limitation of 256 OmniLights + 256 SpotLights in the camera view). These limits +are hardcoded and can't be adjusted in the project settings. + +The Compatibility renderer uses a hybrid single-pass + multi-pass lighting +approach. Lights without shadows are rendered in a single pass. Lights with +shadows are rendered in multiple passes. This is required for performance +reasons on mobile devices. As a result, performance does not scale well with +many shadow-casting lights. It is recommended to only have a handful of lights +with shadows in the camera frustum at a time and for those lights to be spread +apart so that each object is only touched by 1 or 2 shadowed lights at a time. +The maximum number of lights visible at once can be adjusted in the project +settings. + +In all 3 methods, lights without shadows are much cheaper than lights with +shadows. To improve performance, lights are only updated when the light is +modified or when objects in its radius are modified. Redot currently doesn't +separate static shadow rendering from dynamic shadow rendering, but this is +planned in a future release. + +Clustering is also used for reflection probes and decal rendering in the +Forward+ renderer. + +### Shadow mapping + +Both Forward+ and Mobile methods use +:abbr:`PCF (Percentage Closer Filtering)` to filter shadow maps and create a +soft penumbra. Instead of using a fixed PCF pattern, these methods use a vogel +disk pattern which allows for changing the number of samples and smoothly +changing the quality. + +Redot also supports percentage-closer soft shadows (PCSS) for more realistic +shadow penumbra rendering. PCSS shadows are limited to the Forward+ renderer +as they're too demanding to be usable in the Mobile renderer. +PCSS also uses a vogel-disk shaped kernel. + +Additionally, both shadow-mapping techniques rotate the kernel on a per-pixel +basis to help soften under-sampling artifacts. + +The Compatibility renderer supports shadow mapping for DirectionalLight3D, +OmniLight3D, and SpotLight3D lights. + +### Temporal antialiasing + +:::note + +Only available in the Forward+ renderer, not the Mobile or Compatibility renderers. + +::: + +Redot uses a custom TAA implementation based on the old TAA implementation from +[Spartan Engine](https://github.com/PanosK92/SpartanEngine). + +Temporal antialiasing requires motion vectors to work. If motion vectors +are not correctly generated, ghosting will occur when the camera or objects move. + +Motion vectors are generated on the GPU in the main material shader. This is +done by running the vertex shader corresponding to the previous rendered frame +(with the previous camera transform) in addition to the vertex shader for the +current rendered frame, then storing the difference between them in a color buffer. + +Alternatively, FSR 2.2 can be used as an upscaling solution that also provides +its own temporal antialiasing algorithm. FSR 2.2 is implemented on top of the +RenderingDevice abstraction as opposed to using AMD's reference code directly. + +**TAA resolve:** + +- [servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl) + +**FSR 2.2:** + +- [servers/rendering/renderer_rd/effects/fsr2.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/effects/fsr2.cpp) +- [servers/rendering/renderer_rd/shaders/effects/fsr2/](https://github.com/redot-engine/redot-engine/tree/master/servers/rendering/renderer_rd/shaders/effects/fsr2) +- [thirdparty/amd-fsr2/](https://github.com/redot-engine/redot-engine/tree/master/thirdparty/amd-fsr2) + +### Global illumination + +:::note + +VoxelGI and SDFGI are only available in the Forward+ renderer, not the +Mobile or Compatibility renderers. + +LightmapGI *baking* is only available in the Forward+ and Mobile renderers, +and can only be performed within the editor (not in an exported +project). LightmapGI *rendering* is supported by the Compatibility renderer. + +::: + +Redot supports voxel-based GI (VoxelGI), signed distance field GI (SDFGI) and +lightmap baking and rendering (LightmapGI). These techniques can be used +simultaneously if desired. + +Lightmap baking happens on the GPU using Vulkan compute shaders. The GPU-based +lightmapper is implemented in the LightmapperRD class, which inherits from the +Lightmapper class. This allows for implementing additional lightmappers, paving +the way for a future port of the CPU-based lightmapper present in Redot 3.x. +This would allow baking lightmaps while using the Compatibility renderer. + +**Core GI C++ code:** + +- [servers/rendering/renderer_rd/environment/gi.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/environment/gi.cpp) +- [scene/3d/voxel_gi.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/3d/voxel_gi.cpp) - VoxelGI node +- [editor/plugins/voxel_gi_editor_plugin.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/editor/plugins/voxel_gi_editor_plugin.cpp) - Editor UI for the VoxelGI node + +**Core GI GLSL shaders:** + +- [servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl) +- [servers/rendering/renderer_rd/shaders/environment/voxel_gi_debug.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/voxel_gi_debug.glsl) - VoxelGI debug draw mode +- [servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl) - SDFGI Cascades debug draw mode +- [servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl) - SDFGI Probes debug draw mode +- [servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/sdfgi_integrate.glsl) +- [servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/sdfgi_preprocess.glsl) +- [servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/sdfgi_direct_light.glsl) + +**Lightmapper C++ code:** + +- [scene/3d/lightmap_gi.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/3d/lightmap_gi.cpp) - LightmapGI node +- [editor/plugins/lightmap_gi_editor_plugin.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/editor/plugins/lightmap_gi_editor_plugin.cpp) - Editor UI for the LightmapGI node +- [scene/3d/lightmapper.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/3d/lightmapper.cpp) - Abstract class +- [modules/lightmapper_rd/lightmapper_rd.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/modules/lightmapper_rd/lightmapper_rd.cpp) - GPU-based lightmapper implementation + +**Lightmapper GLSL shaders:** + +- [modules/lightmapper_rd/lm_raster.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/modules/lightmapper_rd/lm_raster.glsl) +- [modules/lightmapper_rd/lm_compute.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/modules/lightmapper_rd/lm_compute.glsl) +- [modules/lightmapper_rd/lm_blendseams.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/modules/lightmapper_rd/lm_blendseams.glsl) + +### Depth of field + +:::note + +Only available in the Forward+ and Mobile renderers, not the +Compatibility renderer. + +::: + +The Forward+ and Mobile renderers use different approaches to DOF rendering, with +different visual results. This is done to best match the performance characteristics +of the target hardware. In Forward+, DOF is performed using a compute shader. In +Mobile, DOF is performed using a fragment shader (raster). + +Box, hexagon and circle bokeh shapes are available (from fastest to slowest). +Depth of field can optionally be jittered every frame to improve its appearance +when temporal antialiasing is enabled. + +**Depth of field C++ code:** + +- [servers/rendering/renderer_rd/effects/bokeh_dof.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/effects/bokeh_dof.cpp) + +**Depth of field GLSL shader (compute - used for Forward+):** + +- [servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl) + +**Depth of field GLSL shader (raster - used for Mobile):** + +- [servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl) + +### Screen-space effects (SSAO, SSIL, SSR, SSS) + +:::note + +Only available in the Forward+ renderer, not the Mobile or Compatibility renderers. + +::: + +The Forward+ renderer supports screen-space ambient occlusion, +screen-space indirect lighting, screen-space reflections and subsurface scattering. + +SSAO uses an implementation derived from Intel's +[ASSAO](https://www.intel.com/content/www/us/en/developer/articles/technical/adaptive-screen-space-ambient-occlusion.html) +(converted to Vulkan). SSIL is derived from SSAO to provide high-performance +indirect lighting. + +When both SSAO and SSIL are enabled, parts of SSAO and SSIL are shared to reduce +the performance impact. + +SSAO and SSIL are performed at half resolution by default to improve performance. +SSR is always performed at half resolution to improve performance. + +**Screen-space effects C++ code:** + +- [servers/rendering/renderer_rd/effects/ss_effects.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/effects/ss_effects.cpp) + +**Screen-space ambient occlusion GLSL shader:** + +- [servers/rendering/renderer_rd/shaders/effects/ssao.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssao.glsl) +- [servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl) +- [servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl) +- [servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl) + +**Screen-space indirect lighting GLSL shader:** + +- [servers/rendering/renderer_rd/shaders/effects/ssil.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssil.glsl) +- [servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl) +- [servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl) +- [servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl) + +**Screen-space reflections GLSL shader:** + +- [servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl) +- [servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl) +- [servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl) + +**Subsurface scattering GLSL:** + +- [servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl) + +### Sky rendering + +:::info + +[doc_sky_shader](doc_sky_shader) + +::: + +Redot supports using shaders to render the sky background. The radiance map +(which is used to provide ambient light and reflections for PBR materials) is +automatically updated based on the sky shader. + +The SkyMaterial resources such as ProceduralSkyMaterial, PhysicalSkyMaterial and +PanoramaSkyMaterial generate a built-in shader for sky rendering. This is +similar to what BaseMaterial3D provides for 3D scene materials. + +A detailed technical implementation can be found in the +[Custom sky shaders in Redot 4.0](https://godotengine.org/article/custom-sky-shaders-godot-4-0) +article. + +**Sky rendering C++ code:** + +- [servers/rendering/renderer_rd/environment/sky.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/environment/sky.cpp) - Sky rendering +- [scene/resources/sky.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/resources/sky.cpp) - Sky resource (not to be confused with sky rendering) +- [scene/resources/sky_material.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/resources/sky_material.cpp) SkyMaterial resources (used in the Sky resource) + +**Sky rendering GLSL shader:** + +### Volumetric fog + +:::note + +Only available in the Forward+ renderer, not the Mobile or Compatibility renderers. + +::: + +:::info + +[doc_fog_shader](doc_fog_shader) + +::: + +Redot supports a frustum-aligned voxel (froxel) approach to volumetric fog +rendering. As opposed to a post-processing filter, this approach is more +general-purpose as it can work with any light type. Fog can also use shaders for +custom behavior, which allows animating the fog or using a 3D texture to +represent density. + +The FogMaterial resource generates a built-in shader for FogVolume nodes. This is +similar to what BaseMaterial3D provides for 3D scene materials. + +A detailed technical explanation can be found in the +[Fog Volumes arrive in Redot 4.0](https://godotengine.org/article/fog-volumes-arrive-in-godot-4) +article. + +**Volumetric fog C++ code:** + +- [servers/rendering/renderer_rd/environment/fog.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/environment/fog.cpp) - General volumetric fog +- [scene/3d/fog_volume.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/3d/fog_volume.cpp) - FogVolume node +- [scene/resources/fog_material.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/resources/fog_material.cpp) - FogMaterial resource (used by FogVolume) + +**Volumetric fog GLSL shaders:** + +- [servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl) +- [servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl) + +### Occlusion culling + +While modern GPUs can handle drawing a lot of triangles, the number of draw +calls in complex scenes can still be a bottleneck (even with Vulkan, Direct3D 12, +and Metal). + +Redot 4 supports occlusion culling to reduce overdraw (when the depth prepass +is disabled) and reduce vertex throughput. +This is done by rasterizing a low-resolution buffer on the CPU using +[Embree](https://github.com/embree/embree). The buffer's resolution depends +on the number of CPU threads on the system, as this is done in parallel. +This buffer includes occluder shapes that were baked in the editor or created at +runtime. + +As complex occluders can introduce a lot of strain on the CPU, baked occluders +can be simplified automatically when generated in the editor. + +Redot's occlusion culling doesn't support dynamic occluders yet, but +OccluderInstance3D nodes can still have their visibility toggled or be moved. +However, this will be slow when updating complex occluders this way. Therefore, +updating occluders at runtime is best done only on simple occluder shapes such +as quads or cuboids. + +This CPU-based approach has a few advantages over other solutions, such as +portals and rooms or a GPU-based culling solution: + +- No manual setup required (but can be tweaked manually for best performance). +- No frame delay, which is problematic in cutscenes during camera cuts or when + the camera moves fast behind a wall. +- Works the same on all rendering drivers and methods, with no unpredictable + behavior depending on the driver or GPU hardware. + +Occlusion culling is performed by registering occluder meshes, which is done +using OccluderInstance3D *nodes* (which themselves use Occluder3D *resources*). +RenderingServer then performs occlusion culling by calling Embree in +RendererSceneOcclusionCull. + +**Occlusion culling C++ code:** + +- [scene/3d/occluder_instance_3d.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/3d/occluder_instance_3d.cpp) +- [servers/rendering/renderer_scene_occlusion_cull.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_scene_occlusion_cull.cpp) + +### Visibility range (LOD) + +Redot supports manually authored hierarchical level of detail (HLOD), with +distances specified by the user in the inspector. + +In RenderingSceneCull, the ``_scene_cull()`` and ``_render_scene()`` functions +are where most of the LOD determination happens. Each viewport can render the +same mesh with different LODs (to allow for split screen rendering to look correct). + +**Visibility range C++ code:** + +- [servers/rendering/renderer_scene_cull.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_scene_cull.cpp) + +### Automatic mesh LOD + +The ImporterMesh class is used for the 3D mesh import workflow in the editor. +Its ``generate_lods()`` function handles generating using the +[meshoptimizer](https://meshoptimizer.org/) library. + +LOD mesh generation also generates shadow meshes at the same time. These are +meshes that have their vertices welded regardless of smoothing and materials. +This is used to improve shadow rendering performance by lowering the vertex +throughput required to render shadows. + +The RenderingSceneCull class's ``_render_scene()`` function determines which +mesh LOD should be used when rendering. Each viewport can render the +same mesh with different LODs (to allow for split screen rendering to look correct). + +The mesh LOD is automatically chosen based on a screen coverage metric. This +takes resolution and camera FOV changes into account without requiring user +intervention. The threshold multiplier can be adjusted in the project settings. + +To improve performance, shadow rendering and reflection probe rendering also choose +their own mesh LOD thresholds (which can be different from the main scene rendering). + +**Mesh LOD generation on import C++ code:** + +- [scene/resources/importer_mesh.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/scene/resources/importer_mesh.cpp) + +**Mesh LOD determination C++ code:** + +- [servers/rendering/renderer_scene_cull.cpp](https://github.com/redot-engine/redot-engine/blob/4.2/servers/rendering/renderer_scene_cull.cpp) \ No newline at end of file diff --git a/Redot-Documentation/docs/Contributing/Development/core_and_modules/object_class.md b/Redot-Documentation/docs/Contributing/Development/core_and_modules/object_class.md new file mode 100644 index 0000000..635a879 --- /dev/null +++ b/Redot-Documentation/docs/Contributing/Development/core_and_modules/object_class.md @@ -0,0 +1,328 @@ + +# Object class + +:::info + +This page describes the C++ implementation of objects in Redot. +Looking for the Object class reference? [Have a look here.](/docs/Classes/Object) + +::: + +## General definition + +[Object](/docs/Classes/object) is the base class for almost everything. Most classes in Redot +inherit directly or indirectly from it. Objects provide reflection and +editable properties, and declaring them is a matter of using a single +macro like this: + +```cpp +class CustomObject : public Object { + + GDCLASS(CustomObject, Object); // this is required to inherit +}; + +``` + +This adds a lot of functionality to Objects. For example: + +```cpp +obj = memnew(CustomObject); +print_line("Object class: ", obj->get_class()); // print object class + +obj2 = Object::cast_to(obj); // converting between classes, this also works without RTTI enabled. + +``` + +### References: + +- [core/object/object.h](https://github.com/redot-engine/redot-engine/blob/master/core/object/object.h) + +## Registering an Object + +ClassDB is a static class that holds the entire list of registered +classes that inherit from Object, as well as dynamic bindings to all +their methods properties and integer constants. + +Classes are registered by calling: + +```cpp +ClassDB::register_class() + +``` + +Registering it will allow the class to be instanced by scripts, code, or +creating them again when deserializing. + +Registering as virtual is the same but it can't be instanced. + +```cpp +ClassDB::register_virtual_class() + +``` + +Object-derived classes can override the static function +``static void _bind_methods()``. When one class is registered, this +static function is called to register all the object methods, +properties, constants, etc. It's only called once. If an Object derived +class is instanced but has not been registered, it will be registered as +virtual automatically. + +Inside ``_bind_methods``, there are a couple of things that can be done. +Registering functions is one: + +```cpp +ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name", "arg3name"), &MyCustomType::method); + +``` + +Default values for arguments can be passed as parameters at the end: + +```cpp +ClassDB::bind_method(D_METHOD("methodname", "arg1name", "arg2name", "arg3name"), &MyCustomType::method, DEFVAL(-1), DEFVAL(-2)); // Default values for arg2name (-1) and arg3name (-2). + +``` + +Default values must be provided in the same order as they are declared, +skipping required arguments and then providing default values for the optional ones. +This matches the syntax for declaring methods in C++. + +``D_METHOD`` is a macro that converts "methodname" to a StringName for more +efficiency. Argument names are used for introspection, but when +compiling on release, the macro ignores them, so the strings are unused +and optimized away. + +Check ``_bind_methods`` of Control or Object for more examples. + +If just adding modules and functionality that is not expected to be +documented as thoroughly, the ``D_METHOD()`` macro can safely be ignored and a +string passing the name can be passed for brevity. + +### References: + +- [core/object/class_db.h](https://github.com/redot-engine/redot-engine/blob/master/core/object/class_db.h) + +## Constants + +Classes often have enums such as: + +```cpp +enum SomeMode { + MODE_FIRST, + MODE_SECOND +}; + +``` + +For these to work when binding to methods, the enum must be declared +convertible to int. A macro is provided to help with this: + +```cpp +VARIANT_ENUM_CAST(MyClass::SomeMode); // now functions that take SomeMode can be bound. + +``` + +The constants can also be bound inside ``_bind_methods``, by using: + +```cpp +BIND_CONSTANT(MODE_FIRST); +BIND_CONSTANT(MODE_SECOND); + +``` + +## Properties (set/get) + +Objects export properties, properties are useful for the following: + +- Serializing and deserializing the object. +- Creating a list of editable values for the Object derived class. + +Properties are usually defined by the PropertyInfo() class and +constructed as: + +```cpp +PropertyInfo(type, name, hint, hint_string, usage_flags) + +``` + +For example: + +```cpp +PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "0,49,1", PROPERTY_USAGE_EDITOR) + +``` + +This is an integer property named "amount". The hint is a range, and the range +goes from 0 to 49 in steps of 1 (integers). It is only usable for the editor +(editing the value visually) but won't be serialized. + +Another example: + +```cpp +PropertyInfo(Variant::STRING, "modes", PROPERTY_HINT_ENUM, "Enabled,Disabled,Turbo") + +``` + +This is a string property, can take any string but the editor will only +allow the defined hint ones. Since no usage flags were specified, the +default ones are PROPERTY_USAGE_STORAGE and PROPERTY_USAGE_EDITOR. + +There are plenty of hints and usage flags available in object.h, give them a +check. + +Properties can also work like C# properties and be accessed from script +using indexing, but this usage is generally discouraged, as using +functions is preferred for legibility. Many properties are also bound +with categories, such as "animation/frame" which also make indexing +impossible unless using operator []. + +From ``_bind_methods()``, properties can be created and bound as long as +set/get functions exist. Example: + +```cpp +ADD_PROPERTY(PropertyInfo(Variant::INT, "amount"), "set_amount", "get_amount") + +``` + +This creates the property using the setter and the getter. + +## Binding properties using ``_set``/``_get``/``_get_property_list`` + +An additional method of creating properties exists when more flexibility +is desired (i.e. adding or removing properties on context). + +The following functions can be overridden in an Object derived class, +they are NOT virtual, DO NOT make them virtual, they are called for +every override and the previous ones are not invalidated (multilevel +call). + +```cpp +protected: + void _get_property_list(List *r_props) const; // return list of properties + bool _get(const StringName &p_property, Variant &r_value) const; // return true if property was found + bool _set(const StringName &p_property, const Variant &p_value); // return true if property was found + +``` + +This is also a little less efficient since ``p_property`` must be +compared against the desired names in serial order. + +## Dynamic casting + +Redot provides dynamic casting between Object-derived classes, for +example: + +```cpp +void somefunc(Object *some_obj) { + + Button *button = Object::cast_to