├── source ├── WinApp.rc ├── Version.h.in ├── opengl.h ├── GalaxyEditor.h ├── FleetEditor.h ├── HazardEditor.h ├── EffectEditor.h ├── GovernmentEditor.h ├── ShipyardEditor.h ├── OutfitterEditor.h ├── PlanetEditor.h ├── ArenaControl.h ├── ShipEditor.h ├── OutfitEditor.h ├── FakeMad.h ├── opengl.cpp ├── mfunction.h ├── SystemEditor.h ├── imgui_ex.cpp ├── MainEditorPanel.h ├── ArenaPanel.h ├── MapEditorPanel.h ├── ArenaControl.cpp ├── Editor.h ├── EditorPlugin.h ├── OutfitterEditorPanel.h ├── GalaxyEditor.cpp ├── ShipyardEditor.cpp ├── OutfitterEditor.cpp ├── EditorPlugin.cpp ├── EffectEditor.cpp ├── imgui_ex.h ├── TemplateEditor.cpp ├── ArenaPanel.cpp ├── main.cpp ├── MainEditorPanel.cpp └── TemplateEditor.h ├── resources ├── WinApp.ico ├── icons │ ├── icon_16x16.png │ ├── icon_22x22.png │ ├── icon_24x24.png │ ├── icon_32x32.png │ ├── icon_48x48.png │ ├── icon_128x128.png │ ├── icon_256x256.png │ └── icon_512x512.png ├── editor.iconset │ ├── icon_128x128.png │ ├── icon_16x16.png │ ├── icon_256x256.png │ ├── icon_32x32.png │ ├── icon_512x512.png │ ├── icon_16x16@2x.png │ ├── icon_32x32@2x.png │ ├── icon_128x128@2x.png │ ├── icon_256x256@2x.png │ └── icon_512x512@2x.png ├── editor.desktop ├── Editor-Info.plist.in └── io.github.quyykk.editor.appdata.xml ├── .gitmodules ├── overlays ├── x64-osx10.13-dynamic.cmake ├── sdl2 │ ├── usage │ ├── alsa-dep-fix.patch │ ├── deps.patch │ ├── a94d724f17d7236e9307a02ec946997aa192778e.patch │ ├── vcpkg.json │ ├── 8184.patch │ └── portfile.cmake ├── nativefiledialog-extended │ ├── vcpkg.json │ ├── portfile.cmake │ └── 0001-enable-shared-library.patch ├── libdecor │ ├── vcpkg.json │ └── portfile.cmake └── imgui │ ├── imgui-config.cmake.in │ ├── 0001-combo-additional-flags.patch │ ├── vcpkg.json │ ├── portfile.cmake │ └── CMakeLists.txt ├── utils ├── check_cmake.sh └── build_appimage.sh ├── vcpkg.json ├── README.md ├── CMakePresets.json └── CMakeLists.txt /source/WinApp.rc: -------------------------------------------------------------------------------- 1 | AppIcon ICON "../icons/WinApp.ico" 2 | -------------------------------------------------------------------------------- /resources/WinApp.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/WinApp.ico -------------------------------------------------------------------------------- /resources/icons/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_16x16.png -------------------------------------------------------------------------------- /resources/icons/icon_22x22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_22x22.png -------------------------------------------------------------------------------- /resources/icons/icon_24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_24x24.png -------------------------------------------------------------------------------- /resources/icons/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_32x32.png -------------------------------------------------------------------------------- /resources/icons/icon_48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_48x48.png -------------------------------------------------------------------------------- /resources/icons/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_128x128.png -------------------------------------------------------------------------------- /resources/icons/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_256x256.png -------------------------------------------------------------------------------- /resources/icons/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/icons/icon_512x512.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_128x128.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_16x16.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_256x256.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_32x32.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_512x512.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /resources/editor.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quyykk/plugin-editor/HEAD/resources/editor.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vcpkg"] 2 | path = vcpkg 3 | url = https://github.com/microsoft/vcpkg 4 | [submodule "endless-sky"] 5 | path = endless-sky 6 | url = https://github.com/quyykk/endless-sky 7 | branch = editor-patched 8 | -------------------------------------------------------------------------------- /overlays/x64-osx10.13-dynamic.cmake: -------------------------------------------------------------------------------- 1 | set(VCPKG_TARGET_ARCHITECTURE x64) 2 | set(VCPKG_CRT_LINKAGE dynamic) 3 | set(VCPKG_LIBRARY_LINKAGE dynamic) 4 | 5 | set(VCPKG_CMAKE_SYSTEM_NAME Darwin) 6 | set(VCPKG_OSX_ARCHITECTURES x86_64) 7 | set(VCPKG_OSX_DEPLOYMENT_TARGET 10.13) 8 | -------------------------------------------------------------------------------- /overlays/sdl2/usage: -------------------------------------------------------------------------------- 1 | sdl2 provides CMake targets: 2 | 3 | find_package(SDL2 CONFIG REQUIRED) 4 | target_link_libraries(main 5 | PRIVATE 6 | $ 7 | $,SDL2::SDL2,SDL2::SDL2-static> 8 | ) 9 | -------------------------------------------------------------------------------- /resources/editor.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.5 3 | Name=Editor 4 | Comment=Unofficial plugin editor for the game Endless Sky 5 | Exec=editor 6 | Icon=editor 7 | Type=Application 8 | Keywords=editor;endless-sky; 9 | Categories=Development; 10 | PrefersNonDefaultGPU=true 11 | SingleMainWindow=true 12 | -------------------------------------------------------------------------------- /source/Version.h.in: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef VERSION_H_IN_ 4 | #define VERSION_H_IN_ 5 | 6 | // The current version of Endless Sky. 7 | #define ES_VERSION "@PROJECT_VERSION@" 8 | 9 | // The date this was built on. 10 | #define EDITOR_DATE "@EDITOR_CURRENT_DATE@" 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /source/opengl.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef ES_OPENGL_H_ 4 | #define ES_OPENGL_H_ 5 | 6 | #include "glad/glad.h" 7 | 8 | #include 9 | 10 | 11 | 12 | // A helper class for various OpenGL platform specific calls. 13 | class OpenGL 14 | { 15 | public: 16 | static bool InitializeLoader(SDL_Window *window); 17 | 18 | static bool HasAdaptiveVSyncSupport(); 19 | static bool HasSwizzleSupport(); 20 | }; 21 | 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /overlays/sdl2/alsa-dep-fix.patch: -------------------------------------------------------------------------------- 1 | diff --git a/SDL2Config.cmake.in b/SDL2Config.cmake.in 2 | index cc8bcf26d..ead829767 100644 3 | --- a/SDL2Config.cmake.in 4 | +++ b/SDL2Config.cmake.in 5 | @@ -35,7 +35,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/sdlfind.cmake") 6 | 7 | set(SDL_ALSA @SDL_ALSA@) 8 | set(SDL_ALSA_SHARED @SDL_ALSA_SHARED@) 9 | -if(SDL_ALSA AND NOT SDL_ALSA_SHARED AND TARGET SDL2::SDL2-static) 10 | +if(SDL_ALSA) 11 | sdlFindALSA() 12 | endif() 13 | unset(SDL_ALSA) 14 | -------------------------------------------------------------------------------- /overlays/sdl2/deps.patch: -------------------------------------------------------------------------------- 1 | diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake 2 | index 65a98efbe..2f99f28f1 100644 3 | --- a/cmake/sdlchecks.cmake 4 | +++ b/cmake/sdlchecks.cmake 5 | @@ -352,7 +352,7 @@ endmacro() 6 | # - HAVE_SDL_LOADSO opt 7 | macro(CheckLibSampleRate) 8 | if(SDL_LIBSAMPLERATE) 9 | - find_package(SampleRate QUIET) 10 | + find_package(SampleRate CONFIG REQUIRED) 11 | if(SampleRate_FOUND AND TARGET SampleRate::samplerate) 12 | set(HAVE_LIBSAMPLERATE TRUE) 13 | set(HAVE_LIBSAMPLERATE_H TRUE) 14 | -------------------------------------------------------------------------------- /overlays/nativefiledialog-extended/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nativefiledialog-extended", 3 | "version-semver": "1.0.0", 4 | "description": "Native file dialog library with C and C++ bindings, based on mlabbe/nativefiledialog.", 5 | "homepage": "https://github.com/btzy/nativefiledialog-extended", 6 | "license": "Zlib", 7 | "supports": "!uwp", 8 | "dependencies": [ 9 | { 10 | "name": "vcpkg-cmake", 11 | "host": true 12 | }, 13 | { 14 | "name": "vcpkg-cmake-config", 15 | "host": true 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /source/GalaxyEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef GALAXY_EDITOR_H_ 4 | #define GALAXY_EDITOR_H_ 5 | 6 | #include "Galaxy.h" 7 | #include "TemplateEditor.h" 8 | 9 | class DataWriter; 10 | class Editor; 11 | 12 | 13 | 14 | // Class representing the galaxy editor window. 15 | class GalaxyEditor : public TemplateEditor { 16 | public: 17 | GalaxyEditor(Editor &editor, bool &show) noexcept; 18 | 19 | void Render(); 20 | void WriteToFile(DataWriter &writer, const Galaxy *galaxy) const; 21 | 22 | private: 23 | void RenderGalaxy(); 24 | }; 25 | 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /source/FleetEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef FLEET_EDITOR_H_ 4 | #define FLEET_EDITOR_H_ 5 | 6 | #include "Fleet.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DataWriter; 14 | class Editor; 15 | 16 | 17 | 18 | // Class representing the fleet editor window. 19 | class FleetEditor : public TemplateEditor { 20 | public: 21 | FleetEditor(Editor &editor, bool &show) noexcept; 22 | 23 | void Render(); 24 | void WriteToFile(DataWriter &writer, const Fleet *fleet) const; 25 | 26 | private: 27 | void RenderFleet(); 28 | }; 29 | 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /overlays/libdecor/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libdecor", 3 | "version": "0.1.0", 4 | "description": "Library to help Wayland clients draw window decorations.", 5 | "homepage": "https://gitlab.freedesktop.org/libdecor/libdecor", 6 | "license": "MIT", 7 | "supports": "linux", 8 | "dependencies": [ 9 | "dbus", 10 | "harfbuzz", 11 | "pango", 12 | { 13 | "name": "vcpkg-tool-meson", 14 | "host": true 15 | }, 16 | "wayland-protocols" 17 | ], 18 | "features": { 19 | "gtk": { 20 | "description": "Enables the use of the GTK backend", 21 | "dependencies": [ 22 | "gtk3" 23 | ] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /source/HazardEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef HAZARD_EDITOR_H_ 4 | #define HAZARD_EDITOR_H_ 5 | 6 | #include "Hazard.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DataWriter; 14 | class Editor; 15 | 16 | 17 | 18 | // Class representing the hazard editor window. 19 | class HazardEditor : public TemplateEditor { 20 | public: 21 | HazardEditor(Editor &editor, bool &show) noexcept; 22 | 23 | void Render(); 24 | void WriteToFile(DataWriter &writer, const Hazard *hazard) const; 25 | 26 | private: 27 | void RenderHazard(); 28 | }; 29 | 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /source/EffectEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef EFFECT_EDITOR_H_ 4 | #define EFFECT_EDITOR_H_ 5 | 6 | #include "Effect.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DataWriter; 14 | class Editor; 15 | 16 | 17 | 18 | // Class representing the effect editor window. 19 | class EffectEditor : public TemplateEditor { 20 | public: 21 | EffectEditor(Editor &editor, bool &show) noexcept; 22 | 23 | void Render(); 24 | void WriteToFile(DataWriter &writer, const Effect *effect) const; 25 | 26 | private: 27 | void RenderPlanetMenu(); 28 | void RenderEffect(); 29 | }; 30 | 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /overlays/imgui/imgui-config.cmake.in: -------------------------------------------------------------------------------- 1 | cmake_policy(SET CMP0012 NEW) 2 | 3 | @PACKAGE_INIT@ 4 | 5 | include(CMakeFindDependencyMacro) 6 | 7 | if (@IMGUI_BUILD_GLFW_BINDING@) 8 | find_dependency(glfw3 CONFIG) 9 | endif() 10 | 11 | if (@IMGUI_BUILD_GLUT_BINDING@) 12 | find_dependency(GLUT) 13 | endif() 14 | 15 | if (@IMGUI_BUILD_SDL2_BINDING@ OR @IMGUI_BUILD_SDL2_RENDERER_BINDING@) 16 | find_dependency(SDL2 CONFIG) 17 | endif() 18 | 19 | if (@IMGUI_BUILD_VULKAN_BINDING@) 20 | find_dependency(Vulkan) 21 | endif() 22 | 23 | if (@IMGUI_FREETYPE@) 24 | find_dependency(freetype CONFIG) 25 | endif() 26 | 27 | include("${CMAKE_CURRENT_LIST_DIR}/imgui-targets.cmake") 28 | -------------------------------------------------------------------------------- /source/GovernmentEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef GOVERNMENT_EDITOR_H_ 4 | #define GOVERNMENT_EDITOR_H_ 5 | 6 | #include "Government.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DataWriter; 14 | class Editor; 15 | 16 | 17 | 18 | // Class representing the government editor window. 19 | class GovernmentEditor : public TemplateEditor { 20 | public: 21 | GovernmentEditor(Editor &editor, bool &show) noexcept; 22 | 23 | void Render(); 24 | void WriteToFile(DataWriter &writer, const Government *government) const; 25 | 26 | private: 27 | void RenderGovernment(); 28 | }; 29 | 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /source/ShipyardEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef SHIPYARD_EDITOR_H_ 4 | #define SHIPYARD_EDITOR_H_ 5 | 6 | #include "Sale.h" 7 | #include "Ship.h" 8 | #include "TemplateEditor.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class DataWriter; 15 | class Editor; 16 | 17 | 18 | 19 | // Class representing the shipyard editor window. 20 | class ShipyardEditor : public TemplateEditor> { 21 | public: 22 | ShipyardEditor(Editor &editor, bool &show) noexcept; 23 | 24 | void Render(); 25 | void WriteToFile(DataWriter &writer, const Sale *shipyard) const; 26 | 27 | private: 28 | void RenderShipyard(); 29 | }; 30 | 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /source/OutfitterEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef OUTFITTER_EDITOR_H_ 4 | #define OUTFITTER_EDITOR_H_ 5 | 6 | #include "Sale.h" 7 | #include "Outfit.h" 8 | #include "TemplateEditor.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class DataWriter; 15 | class Editor; 16 | 17 | 18 | 19 | // Class representing the outfitter editor window. 20 | class OutfitterEditor : public TemplateEditor> { 21 | public: 22 | OutfitterEditor(Editor &editor, bool &show) noexcept; 23 | 24 | void Render(); 25 | void WriteToFile(DataWriter &writer, const Sale *outfitter) const; 26 | 27 | private: 28 | void RenderOutfitter(); 29 | }; 30 | 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /source/PlanetEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef PLANET_EDITOR_H_ 4 | #define PLANET_EDITOR_H_ 5 | 6 | #include "Planet.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DataWriter; 14 | class Editor; 15 | 16 | 17 | 18 | // Class representing the planet editor window. 19 | class PlanetEditor : public TemplateEditor { 20 | public: 21 | PlanetEditor(Editor &editor, bool &show) noexcept; 22 | 23 | void Select(const Planet *planet); 24 | 25 | void Render(); 26 | void WriteToFile(DataWriter &writer, const Planet *planet) const; 27 | 28 | private: 29 | void RenderPlanetMenu(); 30 | void RenderPlanet(); 31 | }; 32 | 33 | 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /source/ArenaControl.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef ARENA_CONTROL_H_ 4 | #define ARENA_CONTROL_H_ 5 | 6 | #include 7 | 8 | class ArenaPanel; 9 | class Editor; 10 | class Government; 11 | class Ship; 12 | class SystemEditor; 13 | 14 | 15 | 16 | // Class representing the arena control window. 17 | class ArenaControl { 18 | public: 19 | ArenaControl(Editor &editor, SystemEditor &systemEditor); 20 | 21 | void SetArena(std::weak_ptr ptr); 22 | void Render(bool &show); 23 | 24 | 25 | private: 26 | void PlaceShip(const Ship &ship, const Government &gov) const; 27 | 28 | 29 | private: 30 | Editor &editor; 31 | SystemEditor &systemEditor; 32 | 33 | std::weak_ptr arena; 34 | }; 35 | 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /source/ShipEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef SHIP_EDITOR_H_ 4 | #define SHIP_EDITOR_H_ 5 | 6 | #include "Ship.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class DataWriter; 15 | class Editor; 16 | 17 | 18 | 19 | // Class representing the ship editor window. 20 | class ShipEditor : public TemplateEditor { 21 | public: 22 | ShipEditor(Editor &editor, bool &show) noexcept; 23 | 24 | void Render(); 25 | void WriteToFile(DataWriter &writer, const Ship *ship) const; 26 | 27 | Ship *GetShip() { return object; } 28 | void SetModified() { SetDirty(); } 29 | 30 | 31 | private: 32 | void RenderShip(); 33 | void RenderHardpoint(); 34 | }; 35 | 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /source/OutfitEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef OUTFIT_EDITOR_H_ 4 | #define OUTFIT_EDITOR_H_ 5 | 6 | #include "Outfit.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class DataWriter; 16 | class Editor; 17 | 18 | 19 | 20 | // Class representing the outfit editor window. 21 | class OutfitEditor : public TemplateEditor { 22 | public: 23 | static const std::array &AttributesOrder(); 24 | 25 | 26 | 27 | public: 28 | OutfitEditor(Editor &editor, bool &show) noexcept; 29 | 30 | void Render(); 31 | void WriteToFile(DataWriter &writer, const Outfit *outfit) const; 32 | 33 | private: 34 | void RenderOutfitMenu(); 35 | void RenderOutfit(); 36 | }; 37 | 38 | 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /overlays/libdecor/portfile.cmake: -------------------------------------------------------------------------------- 1 | vcpkg_from_gitlab( 2 | GITLAB_URL https://gitlab.freedesktop.org/ 3 | OUT_SOURCE_PATH SOURCE_PATH 4 | REPO libdecor/libdecor 5 | REF ca6e6b68a3ecc4cff2da975580dbe1ae07caf18e 6 | SHA512 a4749861fff46db0b8ed1f74e0bbc1c3cba9eca0bf1c9861d4e3f49d17447c48530e06573fd796255b606aee2f7029ab7f466a2b2f822e43d8f832314d38ddc7 7 | HEAD_REF master # branch name 8 | ) 9 | 10 | if("gtk" IN_LIST FEATURES) 11 | list(APPEND OPTIONS -Dgtk=enabled) 12 | else() 13 | list(APPEND OPTIONS -Dgtk=disabled) 14 | endif() 15 | 16 | vcpkg_configure_meson( 17 | SOURCE_PATH "${SOURCE_PATH}" 18 | OPTIONS ${OPTIONS} 19 | -Ddemo=false 20 | ) 21 | vcpkg_install_meson() 22 | vcpkg_copy_pdbs() 23 | vcpkg_check_linkage(ONLY_DYNAMIC_LIBRARY) 24 | vcpkg_fixup_pkgconfig() 25 | 26 | vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") 27 | -------------------------------------------------------------------------------- /utils/check_cmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script that checks if the CMake project is complete. 4 | # TODO: If the project is incomplete generate a patch file to make it complete. 5 | 6 | set -u pipefail -e 7 | # Determine path of the current script, and go to the ES project root. 8 | HERE=$(cd "$(dirname "$0")" && pwd) 9 | cd "${HERE}"/.. || exit 10 | 11 | ESTOP=$(pwd) 12 | LIBLIST="${ESTOP}/source/CMakeLists.txt" 13 | TESTLIST="${ESTOP}/tests/unit/CMakeLists.txt" 14 | 15 | RESULT=0 16 | 17 | for FILE in $(find source -type f -name "*.h" -o -name "*.cpp" -not -name main.cpp | sed s,^source/,, | sort) 18 | do 19 | # Check if the file is present in the source list. 20 | if ! grep -Fq "${FILE}" "${LIBLIST}"; then 21 | if [ $RESULT -ne 1 ]; then 22 | echo -e "\033[1mMissing files in source/CMakeLists.txt:\033[0m" 23 | fi 24 | echo -e "${FILE}" 25 | RESULT=1 26 | fi 27 | done 28 | 29 | exit ${RESULT} 30 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | { 4 | "name": "glad", 5 | "features": [ 6 | "gl-api-30", 7 | "extensions" 8 | ] 9 | }, 10 | { 11 | "name": "glad", 12 | "features": [ 13 | "wgl" 14 | ], 15 | "platform": "windows" 16 | }, 17 | { 18 | "name": "glad", 19 | "features": [ 20 | "glx", 21 | "gles2-api-30" 22 | ], 23 | "platform": "linux" 24 | }, 25 | { 26 | "name": "imgui", 27 | "features": [ 28 | "opengl3-binding", 29 | "sdl2-binding", 30 | "docking-experimental" 31 | ] 32 | }, 33 | "libpng", 34 | "libjpeg-turbo", 35 | "libmad", 36 | { 37 | "name": "libuuid", 38 | "platform": "!windows & !osx" 39 | }, 40 | "nativefiledialog-extended", 41 | "openal-soft", 42 | { 43 | "name": "openal-soft", 44 | "features": [ 45 | "pipewire" 46 | ], 47 | "platform": "linux" 48 | }, 49 | "rapidfuzz", 50 | "sdl2" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /overlays/sdl2/a94d724f17d7236e9307a02ec946997aa192778e.patch: -------------------------------------------------------------------------------- 1 | From a94d724f17d7236e9307a02ec946997aa192778e Mon Sep 17 00:00:00 2001 2 | From: Anonymous Maarten 3 | Date: Wed, 30 Aug 2023 23:03:03 +0200 4 | Subject: [PATCH] wayland: add SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL 5 | 6 | --- 7 | src/video/wayland/SDL_waylanddyn.c | 3 ++- 8 | 1 file changed, 2 insertions(+), 1 deletion(-) 9 | 10 | diff --git a/src/video/wayland/SDL_waylanddyn.c b/src/video/wayland/SDL_waylanddyn.c 11 | index 4b41f3bf7b77..dde99bf4d3e0 100644 12 | --- a/src/video/wayland/SDL_waylanddyn.c 13 | +++ b/src/video/wayland/SDL_waylanddyn.c 14 | @@ -35,8 +35,9 @@ typedef struct 15 | } waylanddynlib; 16 | 17 | static waylanddynlib waylandlibs[] = { 18 | -#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL 19 | { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC }, 20 | +#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL 21 | + { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL }, 22 | #endif 23 | #ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR 24 | { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR }, 25 | -------------------------------------------------------------------------------- /overlays/nativefiledialog-extended/portfile.cmake: -------------------------------------------------------------------------------- 1 | vcpkg_from_github( 2 | OUT_SOURCE_PATH SOURCE_PATH 3 | REPO btzy/nativefiledialog-extended 4 | REF d4df2b6ad5420f5300c00f418bf28d86291fa675 # nativefiledialog-extended-1.0.0 5 | SHA512 164bea794e38401fbcfb1a20077e3420e7e2195f4bf18c39adc94e394004531dc3d506b266f5318e9e3ab02a92d99b3c373c40ef5b5f60765fdd03570d91dded 6 | HEAD_REF master 7 | PATCHES 8 | 0001-enable-shared-library.patch 9 | ) 10 | 11 | set(NFDE_SHARED OFF) 12 | if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") 13 | set(NFDE_SHARED ON) 14 | endif() 15 | 16 | set(ALSOFT_REQUIRE_LINUX OFF) 17 | 18 | 19 | vcpkg_cmake_configure( 20 | SOURCE_PATH "${SOURCE_PATH}" 21 | OPTIONS 22 | -DBUILD_SHARED_LIBS=${NFDE_SHARED} 23 | -DNFD_PORTAL=${VCPKG_TARGET_IS_LINUX} 24 | ) 25 | 26 | vcpkg_cmake_install() 27 | 28 | file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") 29 | file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") 30 | file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) 31 | 32 | vcpkg_copy_pdbs() 33 | -------------------------------------------------------------------------------- /resources/Editor-Info.plist.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | Editor 7 | CFBundleExecutable 8 | Editor 9 | CFBundleIconFile 10 | editor 11 | CFBundleIdentifier 12 | Editor 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | Editor 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | @PROJECT_VERSION@ 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | @CMAKE_OSX_DEPLOYMENT_TARGET@ 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /resources/io.github.quyykk.editor.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.github.quyykk.editor 4 | editor.desktop 5 | Editor 6 | Unofficial plugin editor for the game Endless Sky 7 | quyykk 8 | GPL-3.0 9 | CC0-1.0 10 | 11 |

A unofficial plugin editor for the game Endless Sky. Includes helpful tools to help you make plugins!

12 |
13 | 14 | Development 15 | 16 | https://github.com/quyykk/plugin-editor/issues 17 | https://github.com/quyykk/plugin-editor/wiki 18 | https://github.com/quyykk/plugin-editor 19 | 20 | 21 | https://user-images.githubusercontent.com/85879619/131727841-bd3bdfc0-32ce-41c0-bfd2-b5223c37c806.png 22 | Various editor windows opened while adding a new ship 23 | 24 | 25 | 26 | 27 | 28 |

This is the initial release, compatible with the latest stable release of Endless Sky.

29 |
30 | https://github.com/quyykk/plugin-editor/releases/tag/continuous 31 |
32 |
33 | 34 | 35 |
36 | -------------------------------------------------------------------------------- /utils/build_appimage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | if [ -z "$1" ]; then 5 | echo "Please provide the path to the build directory!" 6 | exit 1 7 | fi 8 | 9 | # Builds Endless Sky and packages it as AppImage 10 | # Control the output filename with the OUTPUT environment variable 11 | # You may have to set the ARCH environment variable to e.g. x86_64. 12 | 13 | # Install 14 | DESTDIR=AppDir cmake --install "$1" --prefix /usr 15 | 16 | # Inside an AppImage, the executable is a link called "AppRun" at the root of AppDir/. 17 | # Keeping the data files next to the executable is perfectly valid, so we just move them to AppDir/ to avoid errors. 18 | mv AppDir/usr/share/games/editor/* AppDir/ 19 | 20 | # Now build the actual AppImage 21 | curl -sSL https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage -o linuxdeploy && chmod +x linuxdeploy 22 | OUTPUT=Editor-continuous-x86_64.AppImage ./linuxdeploy --appdir AppDir -e "$1/editor" -d resources/editor.desktop --output appimage 23 | 24 | # Use the static runtime for the AppImage. This lets the AppImage being run on systems without fuse2. 25 | gh release download -R probonopd/go-appimage continuous -p appimagetool*x86_64.AppImage 26 | mv ./appimagetool* appimagetool && chmod +x appimagetool 27 | 28 | ./Editor-continuous-x86_64.AppImage --appimage-extract 29 | chmod -R 755 ./squashfs-root 30 | 31 | if [ ! -z "$OUTPUT" ] ; then 32 | VERSION=000 ./appimagetool ./squashfs-root 33 | mv ./Editor-000-x86_64.AppImage $OUTPUT 34 | else 35 | ./appimagetool ./squashfs-root 36 | fi 37 | 38 | # Clean up 39 | rm -rf AppDir linuxdeploy appimagetool endless-sky.png Editor-continuous-x86_64.AppImage squashfs-root 40 | -------------------------------------------------------------------------------- /source/FakeMad.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | // A header-only no-op implementation of enough of libmad to use in Music.cpp 4 | // without actually doing anything. 5 | // Ordinarily provided by 6 | 7 | #ifdef __EMSCRIPTEN__ 8 | 9 | typedef signed long mad_sample_t; 10 | typedef signed long mad_fixed_t; 11 | enum mad_error { 12 | MAD_ERROR_NONE = 0x0000, /* no error */ 13 | }; 14 | struct mad_stream { 15 | unsigned char const *buffer; /* input bitstream buffer */ 16 | unsigned char const *bufend; /* end of buffer */ 17 | unsigned char const *next_frame; /* start of next frame */ 18 | enum mad_error error; /* error code (see above) */ 19 | }; 20 | 21 | struct mad_frame { 22 | int options; 23 | }; 24 | 25 | struct mad_pcm { 26 | unsigned int samplerate; /* sampling frequency (Hz) */ 27 | unsigned short channels; /* number of channels */ 28 | unsigned short length; /* number of samples per channel */ 29 | mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ 30 | }; 31 | struct mad_synth { 32 | struct mad_pcm pcm; /* PCM output */ 33 | }; 34 | 35 | # define mad_stream_init(synth) /* nothing */ 36 | # define mad_stream_finish(synth) /* nothing */ 37 | # define mad_frame_init(synth) /* nothing */ 38 | # define mad_frame_finish(synth) /* nothing */ 39 | # define mad_synth_init(synth) /* nothing */ 40 | # define mad_synth_finish(synth) /* nothing */ 41 | 42 | # define mad_stream_buffer(a, b, c) /* nothing */ 43 | # define mad_synth_frame(a, b) /* nothing */ 44 | 45 | int mad_frame_decode(struct mad_frame *, struct mad_stream *){return 0;} 46 | 47 | # define MAD_RECOVERABLE(error) ((error) & 0xff00) 48 | # define MAD_F_FRACBITS 28 49 | # define MAD_F(x) ((mad_fixed_t) (x##L)) 50 | # define MAD_F_ONE MAD_F(0x10000000) 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /overlays/sdl2/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdl2", 3 | "version": "2.28.2", 4 | "port-version": 1, 5 | "description": "Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.", 6 | "homepage": "https://www.libsdl.org/download-2.0.php", 7 | "license": "Zlib", 8 | "dependencies": [ 9 | { 10 | "name": "vcpkg-cmake", 11 | "host": true 12 | }, 13 | { 14 | "name": "vcpkg-cmake-config", 15 | "host": true 16 | } 17 | ], 18 | "default-features": [ 19 | "base" 20 | ], 21 | "features": { 22 | "base": { 23 | "description": "Base functionality for SDL", 24 | "dependencies": [ 25 | { 26 | "name": "sdl2", 27 | "default-features": false, 28 | "features": [ 29 | "ibus", 30 | "wayland", 31 | "x11" 32 | ], 33 | "platform": "linux" 34 | } 35 | ] 36 | }, 37 | "ibus": { 38 | "description": "Build with ibus IME support", 39 | "supports": "linux" 40 | }, 41 | "samplerate": { 42 | "description": "Use libsamplerate for audio rate conversion", 43 | "dependencies": [ 44 | "libsamplerate" 45 | ] 46 | }, 47 | "vulkan": { 48 | "description": "Vulkan functionality for SDL" 49 | }, 50 | "wayland": { 51 | "description": "Build with Wayland support", 52 | "dependencies":[ 53 | { 54 | "name": "libdecor", 55 | "features": [ 56 | "gtk" 57 | ] 58 | } 59 | ], 60 | "supports": "linux" 61 | }, 62 | "x11": { 63 | "description": "Build with X11 support", 64 | "supports": "!windows" 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /source/opengl.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "opengl.h" 4 | 5 | #if defined(__linux__) && !defined(ES_GLES) 6 | #include "glad/glad_glx.h" 7 | #elif defined(_WIN32) 8 | #define STRICT 9 | #define WIN32_LEAN_AND_MEAN 10 | #include 11 | #include "glad/glad_wgl.h" 12 | #endif 13 | 14 | #include 15 | 16 | #include 17 | 18 | 19 | 20 | bool OpenGL::InitializeLoader(SDL_Window *window) 21 | { 22 | // Initialize glad. 23 | #ifdef ES_GLES 24 | if(!gladLoadGLES2Loader(&SDL_GL_GetProcAddress)) 25 | return false; 26 | #else 27 | if(!gladLoadGLLoader(&SDL_GL_GetProcAddress)) 28 | return false; 29 | #endif 30 | 31 | // Initialize WGL or GLX if necessary. 32 | SDL_SysWMinfo handle; 33 | SDL_VERSION(&handle.version); 34 | if(!SDL_GetWindowWMInfo(window, &handle)) 35 | return false; 36 | 37 | #if defined(__linux__) && !defined(ES_GLES) 38 | if(handle.subsystem == SDL_SYSWM_X11 39 | && !gladLoadGLXLoader( 40 | &SDL_GL_GetProcAddress, 41 | handle.info.x11.display, 42 | DefaultScreen(handle.info.x11.display))) 43 | return false; 44 | #elif defined(_WIN32) 45 | if(handle.subsystem == SDL_SYSWM_WINDOWS 46 | && !gladLoadWGLLoader( 47 | &SDL_GL_GetProcAddress, 48 | handle.info.win.hdc)) 49 | return false; 50 | #endif 51 | 52 | return true; 53 | } 54 | 55 | 56 | 57 | bool OpenGL::HasAdaptiveVSyncSupport() 58 | { 59 | #if defined(__APPLE__) || defined(ES_GLES) 60 | // macOS doesn't support Adaptive VSync for OpenGL. 61 | // EGL doesn't support Adaptive VSync as well. 62 | return false; 63 | #elif defined(_WIN32) 64 | return GLAD_WGL_EXT_swap_control_tear; 65 | #else 66 | return GLAD_GLX_EXT_swap_control_tear; 67 | #endif 68 | } 69 | 70 | 71 | 72 | bool OpenGL::HasSwizzleSupport() 73 | { 74 | return GLAD_GL_ARB_texture_swizzle || GLAD_GL_EXT_texture_swizzle; 75 | } 76 | -------------------------------------------------------------------------------- /source/mfunction.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef MFUNCTION_H_ 4 | #define MFUNCTION_H_ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | class mfunction; 12 | 13 | // A simple move-only std::function. 14 | template 15 | class mfunction { 16 | public: 17 | constexpr mfunction() noexcept = default; 18 | template 19 | mfunction(T &&func) noexcept 20 | : func(reinterpret_cast( 21 | new std::decay_t(std::forward(func)))), 22 | caller([](std::byte *Ptr, Ps &&...Args) -> decltype(auto) { 23 | return (*reinterpret_cast *>(Ptr))( 24 | std::forward(Args)...); 25 | }), 26 | deleter([](std::byte *Ptr) noexcept { 27 | delete reinterpret_cast *>(Ptr); 28 | }) {} 29 | constexpr mfunction(mfunction &&Other) noexcept 30 | : func(std::exchange(Other.func, nullptr)), 31 | caller(std::exchange(Other.caller, nullptr)), 32 | deleter(std::exchange(Other.deleter, nullptr)) {} 33 | constexpr mfunction &operator=(mfunction &&Other) noexcept 34 | { 35 | func = std::exchange(Other.func, nullptr); 36 | caller = std::exchange(Other.caller, nullptr); 37 | deleter = std::exchange(Other.deleter, nullptr); 38 | return *this; 39 | } 40 | ~mfunction() 41 | { 42 | if(deleter) 43 | deleter(func); 44 | } 45 | 46 | template 47 | constexpr decltype(auto) operator()(Ts &&...Args) noexcept 48 | { 49 | assert(caller && "can't call null function"); 50 | return caller(func, std::forward(Args)...); 51 | } 52 | 53 | constexpr operator bool() noexcept { return func; } 54 | 55 | private: 56 | std::byte *func = nullptr; 57 | R (*caller)(std::byte *, Ps &&...) = nullptr; 58 | void (*deleter)(std::byte *) = nullptr; 59 | }; 60 | 61 | template 62 | mfunction(R(*Func)(Ts&&...)) -> mfunction; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /overlays/imgui/0001-combo-additional-flags.patch: -------------------------------------------------------------------------------- 1 | diff --git a/imgui_internal.h b/imgui_internal.h 2 | index 19b88086..7d078048 100644 3 | --- a/imgui_internal.h 4 | +++ b/imgui_internal.h 5 | @@ -2907,7 +2907,7 @@ namespace ImGui 6 | IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true); 7 | 8 | // Combos 9 | - IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); 10 | + IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags, ImGuiWindowFlags window_flags); 11 | IMGUI_API bool BeginComboPreview(); 12 | IMGUI_API void EndComboPreview(); 13 | 14 | diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp 15 | index bd2d7635..2b6470ea 100644 16 | --- a/imgui_widgets.cpp 17 | +++ b/imgui_widgets.cpp 18 | @@ -1684,10 +1684,10 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF 19 | return false; 20 | 21 | g.NextWindowData.Flags = backup_next_window_data_flags; 22 | - return BeginComboPopup(popup_id, bb, flags); 23 | + return BeginComboPopup(popup_id, bb, flags, 0); 24 | } 25 | 26 | -bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags) 27 | +bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags, ImGuiWindowFlags window_flags) 28 | { 29 | ImGuiContext& g = *GImGui; 30 | if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None)) 31 | @@ -1733,7 +1733,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags 32 | } 33 | 34 | // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() 35 | - ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; 36 | + window_flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; 37 | PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text 38 | bool ret = Begin(name, NULL, window_flags); 39 | PopStyleVar(); 40 | -------------------------------------------------------------------------------- /source/SystemEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef SYSTEM_EDITOR_H_ 4 | #define SYSTEM_EDITOR_H_ 5 | 6 | #include "System.h" 7 | #include "TemplateEditor.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class DataWriter; 15 | class Editor; 16 | class MainEditorPanel; 17 | class MapEditorPanel; 18 | class StellarObject; 19 | 20 | 21 | 22 | // Class representing the system editor window. 23 | class SystemEditor : public TemplateEditor { 24 | public: 25 | SystemEditor(Editor &editor, bool &show) noexcept; 26 | 27 | void Render(); 28 | void AlwaysRender(bool showNewSystem = false, bool showCloneSystem = false); 29 | void WriteToFile(DataWriter &writer, const System *system) const; 30 | 31 | void Delete(const std::vector &systems); 32 | 33 | // Updates the given system's position by the given delta. 34 | void UpdateSystemPosition(const System *system, Point dp); 35 | // Updates the given stellar's position by the given delta. 36 | void UpdateStellarPosition(const StellarObject &object, Point pos, const System *system); 37 | // Toggles a link between the current object and the given one. 38 | void ToggleLink(const System *system); 39 | // Create a new system at the specified position. 40 | void CreateNewSystem(Point position); 41 | // Clones a new system at the specified position. 42 | void CloneSystem(Point position); 43 | void Delete(const StellarObject &stellar, bool selectedObject); 44 | 45 | const System *Selected() const { return object; } 46 | void Select(const System *system) { object = const_cast(system); selectedObject = nullptr; } 47 | void Select(const StellarObject *object) { selectedObject = object; } 48 | 49 | void RandomizeAll(); 50 | void GenerateTrades(); 51 | 52 | void UpdateMap() const; 53 | void UpdateMain() const; 54 | 55 | 56 | private: 57 | void RenderSystem(); 58 | void RenderObject(StellarObject &object, int index, int &nested, bool &hovered, bool &add); 59 | void RenderHazards(std::vector> &hazards); 60 | 61 | void WriteObject(DataWriter &writer, const System *system, const StellarObject *object, bool add = false) const; 62 | 63 | void Randomize(); 64 | void RandomizeAsteroids(); 65 | void RandomizeMinables(); 66 | 67 | // Standardizes habitable and period values of the current system. 68 | void StandardizeSystem(); 69 | 70 | const Sprite *RandomStarSprite(); 71 | const Sprite *RandomPlanetSprite(bool recalculate = false); 72 | const Sprite *RandomMoonSprite(); 73 | const Sprite *RandomGiantSprite(); 74 | 75 | void Delete(const System *system, bool safe); 76 | 77 | private: 78 | Point position; 79 | bool createNewSystem = false; 80 | bool cloneSystem = false; 81 | const StellarObject *selectedObject = nullptr; 82 | 83 | std::random_device rd; 84 | std::mt19937 gen; 85 | }; 86 | 87 | 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Editor 2 | 3 | This is an unofficial plugin editor for Endless Sky. It is continuously updated, and supports the latest release of Endless Sky! You can download it [here](https://github.com/quyykk/plugin-editor/releases/latest). 4 | 5 | Features: 6 | 7 | - Supports galaxies, systems, planets, hazards, effects, fleets, governments, ships, outfits, shipyards, and outfitters. 8 | - A powerful map editor! 9 | - An outfitter to easily create ship loadouts! 10 | - A ship arena to easily test ships against one another. 11 | 12 | It is the successor of the old [plugin editor](https://github.com/quyykk/editor). 13 | 14 | ## Screenshots 15 | 16 | ![map editor showcase](https://user-images.githubusercontent.com/85879619/192547576-d65f99b5-32dc-4bb6-bfad-7814e7028f9a.png) 17 | 18 | ![system view showcase](https://user-images.githubusercontent.com/85879619/192548174-94d40f19-ba7b-4be7-b196-5f564efd8b3e.png) 19 | 20 | 21 | ## Build instructions 22 | 23 | Clone this repo with submodules: 24 | 25 | ```bash 26 | $ git clone https://github.com/quyykk/plugin-editor --recursive 27 | ``` 28 | 29 | This guide assumes you have at least CMake 3.21. 30 | 31 | Install the following, depending on your OS: 32 | 33 |
34 | Windows 35 | If you're planning on using Visual Studio, make sure to install the [clang/LLVM components](https://docs.microsoft.com/en-us/cpp/build/clang-support-msbuild) and the CMake component as well. 36 | 37 | If you want to use MinGW (select the **MSVCRT runtime**; get it from [here](https://winlibs.com/#download-release)), I'd recommend using Visual Studio Code as IDE, because it provides pretty good CMake integration and MinGW support (including debugging). 38 |
39 |
40 | MacOS 41 | Install [Homebrew](https://brew.sh). Once it is installed, use it to install the tools you will need: 42 | 43 | ``` 44 | $ brew install cmake ninja pkg-config nasm 45 | ``` 46 |
47 |
48 | Debian distros 49 | ``` 50 | g++ cmake ninja-build pkg-config libgl1-mesa-dev libxmu-dev libxi-dev libglu1-mesa-dev tar zip unzip curl 51 | ``` 52 |
53 |
54 | Fedora distros 55 | ``` 56 | gcc-c++ cmake ninja-build mesa-libGL-devel autoconf libtool libXext-devel mesa-libGLU-devel 57 | ``` 58 |
59 | 60 | A lot of IDEs have built-in CMake integration (VS, VSCode, CLion, ...). For those, you can simply open the folder in the IDE and build. 61 | 62 | There are a couple of presets to choose from before you build. Select the appropriate one. For example, if you want to build with MinGW select the `mingw` preset. (You can execute `cmake --preset help` to get a list of presets that are available). 63 | 64 | If you want to build from the command line: 65 | 66 | ```bash 67 | $ cmake --preset 68 | $ cmake --build --preset -debug 69 | ``` 70 | 71 | where `` is your chosen preset. You can also specify `release` instead of `debug` to get a release build. The built files are located in the `build/` folder. 72 | -------------------------------------------------------------------------------- /source/imgui_ex.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "imgui_ex.h" 4 | 5 | #include "imgui_internal.h" 6 | #include "imgui_stdlib.h" 7 | 8 | #define __STDC_FORMAT_MACROS 9 | #include 10 | 11 | 12 | 13 | namespace ImGui 14 | { 15 | IMGUI_API bool InputDoubleEx(const char *label, double *v, ImGuiInputTextFlags flags) 16 | { 17 | return InputDouble(label, v, 0., 0., "%g", flags); 18 | } 19 | 20 | 21 | 22 | IMGUI_API bool InputFloatEx(const char *label, float *v, ImGuiInputTextFlags flags) 23 | { 24 | return InputFloat(label, v, 0., 0., "%g", flags); 25 | } 26 | 27 | 28 | 29 | IMGUI_API bool InputDouble2Ex(const char *label, double *v, ImGuiInputTextFlags flags) 30 | { 31 | return InputScalarN(label, ImGuiDataType_Double, v, 2, nullptr, nullptr, "%g", flags); 32 | } 33 | 34 | 35 | 36 | IMGUI_API bool InputInt64Ex(const char *label, int64_t *v, ImGuiInputTextFlags flags) 37 | { 38 | return InputScalar(label, ImGuiDataType_S64, v, nullptr, nullptr, "%" PRId64, flags); 39 | } 40 | 41 | 42 | 43 | IMGUI_API bool InputSizeTEx(const char *label, size_t *v, ImGuiInputTextFlags flags) 44 | { 45 | return InputScalar(label, ImGuiDataType_U64, v, nullptr, nullptr, "%zu", flags); 46 | } 47 | 48 | 49 | 50 | IMGUI_API bool IsInputFocused(const char *id) 51 | { 52 | return GetCurrentWindow()->GetID(id) == GetFocusID() && GetIO().WantTextInput; 53 | } 54 | 55 | 56 | 57 | IMGUI_API bool InputSwizzle(const char *label, int *swizzle, bool allowNoSwizzle) 58 | { 59 | constexpr int count = 29; 60 | constexpr const char *swizzles[count] = 61 | { 62 | "0 - red + yellow markings", 63 | "1 - red + magenta markings", 64 | "2 - green + yellow", 65 | "3 - green + cyan", 66 | "4 - blue + magenta", 67 | "5 - blue + cyan", 68 | "6 - red + black", 69 | "7 - pure red", 70 | "8 - faded red", 71 | "9 - pure black", 72 | "10 - faded black", 73 | "11 - pure white", 74 | "12 - darkened blue", 75 | "13 - pure blue", 76 | "14 - faded blue", 77 | "15 - darkened cyan", 78 | "16 - pure cyan", 79 | "17 - faded cyan", 80 | "18 - darkened green", 81 | "19 - pure green", 82 | "20 - faded green", 83 | "21 - darkened yellow", 84 | "22 - pure yellow", 85 | "23 - faded yellow", 86 | "24 - darkened magenta", 87 | "25 - pure magenta", 88 | "26 - faded magenta", 89 | "27 - red only (cloaked)", 90 | "28 - black only (outline)", 91 | }; 92 | bool changed = false; 93 | if(BeginCombo(label, *swizzle == -1 ? "-1 - none" : swizzles[*swizzle])) 94 | { 95 | for(int i = allowNoSwizzle ? -1 : 0; i < count; ++i) 96 | { 97 | const bool selected = i == *swizzle; 98 | if(Selectable(i == -1 ? "-1 - none" : swizzles[i], selected)) 99 | { 100 | *swizzle = i; 101 | changed = true; 102 | } 103 | if(selected) 104 | SetItemDefaultFocus(); 105 | } 106 | EndCombo(); 107 | } 108 | return changed; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /source/MainEditorPanel.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef MAIN_EDITOR_PANEL_H_ 4 | #define MAIN_EDITOR_PANEL_H_ 5 | 6 | #include "Panel.h" 7 | 8 | #include "AsteroidField.h" 9 | #include "BatchDrawList.h" 10 | #include "Date.h" 11 | #include "DrawList.h" 12 | #include "Color.h" 13 | #include "PlanetLabel.h" 14 | #include "Point.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | class Angle; 23 | class Editor; 24 | class Government; 25 | class PlanetEditor; 26 | class StellarObject; 27 | class System; 28 | class SystemEditor; 29 | 30 | 31 | 32 | // This class provides a limited version of the MainPanel which you can edit. 33 | class MainEditorPanel : public Panel { 34 | public: 35 | static void RenderProperties(SystemEditor &systemEditor, bool &show); 36 | 37 | static inline bool showHabitableRings = true; 38 | static inline bool showOrbits = true; 39 | static inline bool showBelts = false; 40 | static inline bool showArrivalDistance = false; 41 | static inline int timeIncrement = 1; 42 | 43 | 44 | public: 45 | MainEditorPanel(const Editor &editor, PlanetEditor *planetEditor, SystemEditor *systemEditor); 46 | 47 | virtual void Step() override; 48 | virtual void Draw() override; 49 | 50 | // Map panels allow fast-forward to stay active. 51 | virtual bool AllowsFastForward() const noexcept override; 52 | 53 | void Select(const System *system); 54 | const System *Selected() const; 55 | void DeselectObject(); 56 | void SelectObject(const StellarObject &stellar); 57 | const StellarObject *SelectedObject() { return currentObject; } 58 | 59 | 60 | protected: 61 | // Only override the ones you need; the default action is to return false. 62 | virtual bool KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) override; 63 | virtual bool Click(int x, int y, int clicks) override; 64 | virtual bool Drag(double dx, double dy) override; 65 | virtual bool Scroll(double dx, double dy) override; 66 | virtual bool Release(int x, int y) override; 67 | 68 | 69 | protected: 70 | PlanetEditor *planetEditor; 71 | SystemEditor *systemEditor; 72 | 73 | // The (non-null) system which is currently selected. 74 | const System *currentSystem; 75 | const StellarObject *currentObject = nullptr; 76 | AsteroidField asteroids; 77 | std::list> newFlotsam; 78 | std::vector newVisuals; 79 | 80 | Point center; 81 | int step = 0; 82 | double zoom; 83 | Point mouse; 84 | 85 | void UpdateSystem(); 86 | void UpdateCache(); 87 | 88 | double ViewZoom() const; 89 | void ZoomViewIn(); 90 | void ZoomViewOut(); 91 | 92 | 93 | private: 94 | size_t zoomIndex = 4; 95 | int64_t date = 100000; 96 | bool paused = false; 97 | 98 | Point click; 99 | 100 | bool isDragging = false; 101 | bool moveStellars = false; 102 | DrawList draw; 103 | BatchDrawList batchDraw; 104 | std::vector labels; 105 | 106 | friend class SystemEditor; 107 | }; 108 | 109 | 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /overlays/imgui/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "imgui", 3 | "version": "1.89", 4 | "description": "Bloat-free Immediate Mode Graphical User interface for C++ with minimal dependencies.", 5 | "homepage": "https://github.com/ocornut/imgui", 6 | "license": "MIT", 7 | "dependencies": [ 8 | { 9 | "name": "vcpkg-cmake", 10 | "host": true 11 | }, 12 | { 13 | "name": "vcpkg-cmake-config", 14 | "host": true 15 | } 16 | ], 17 | "features": { 18 | "allegro5-binding": { 19 | "description": "Make available Allegro5 binding", 20 | "dependencies": [ 21 | "allegro5" 22 | ] 23 | }, 24 | "docking-experimental": { 25 | "description": "Build with docking support" 26 | }, 27 | "dx10-binding": { 28 | "description": "Make available DirectX10 binding", 29 | "supports": "windows & !uwp" 30 | }, 31 | "dx11-binding": { 32 | "description": "Make available DirectX11 binding", 33 | "supports": "windows & !uwp" 34 | }, 35 | "dx12-binding": { 36 | "description": "Make available DirectX12 binding", 37 | "supports": "!x86 & windows & !uwp" 38 | }, 39 | "dx9-binding": { 40 | "description": "Make available DirectX9 binding", 41 | "supports": "windows & !uwp" 42 | }, 43 | "freetype": { 44 | "description": "Build font atlases using FreeType instead of stb_truetype", 45 | "dependencies": [ 46 | "freetype" 47 | ] 48 | }, 49 | "glfw-binding": { 50 | "description": "Make available GLFW binding", 51 | "dependencies": [ 52 | "glfw3" 53 | ] 54 | }, 55 | "glut-binding": { 56 | "description": "Make available Glut binding", 57 | "dependencies": [ 58 | "freeglut" 59 | ] 60 | }, 61 | "libigl-imgui": { 62 | "description": "Install the libigl-imgui headers" 63 | }, 64 | "metal-binding": { 65 | "description": "Make available Metal binding", 66 | "supports": "osx" 67 | }, 68 | "opengl2-binding": { 69 | "description": "Make available OpenGL (legacy) binding" 70 | }, 71 | "opengl3-binding": { 72 | "description": "Make available OpenGL3/ES/ES2 (modern) binding" 73 | }, 74 | "osx-binding": { 75 | "description": "Make available OSX binding", 76 | "supports": "osx" 77 | }, 78 | "sdl2-binding": { 79 | "description": "Make available SDL2 binding", 80 | "dependencies": [ 81 | "sdl2" 82 | ] 83 | }, 84 | "sdl2-renderer-binding": { 85 | "description": "Make available SDL2 Renderer binding", 86 | "dependencies": [ 87 | "sdl2" 88 | ] 89 | }, 90 | "vulkan-binding": { 91 | "description": "Make available Vulkan binding", 92 | "dependencies": [ 93 | "vulkan" 94 | ] 95 | }, 96 | "wchar32": { 97 | "description": "Use WCHAR32 instead of WCHAR16" 98 | }, 99 | "win32-binding": { 100 | "description": "Make available Win32 binding" 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /overlays/sdl2/8184.patch: -------------------------------------------------------------------------------- 1 | From cbc14b03d0373c63bc58fc8afd005e3b6268cbb6 Mon Sep 17 00:00:00 2001 2 | From: Anonymous Maarten 3 | Date: Wed, 30 Aug 2023 19:28:11 +0200 4 | Subject: [PATCH] wayland: don't define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_* 5 | macro's 6 | 7 | They mess with #ifdef conditional in headers. 8 | --- 9 | src/video/wayland/SDL_waylanddyn.c | 40 ++++++++++++++---------------- 10 | 1 file changed, 18 insertions(+), 22 deletions(-) 11 | 12 | diff --git a/src/video/wayland/SDL_waylanddyn.c b/src/video/wayland/SDL_waylanddyn.c 13 | index 572813e9eb62..4b41f3bf7b77 100644 14 | --- a/src/video/wayland/SDL_waylanddyn.c 15 | +++ b/src/video/wayland/SDL_waylanddyn.c 16 | @@ -34,34 +34,29 @@ typedef struct 17 | const char *libname; 18 | } waylanddynlib; 19 | 20 | -#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL 21 | -#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL NULL 22 | -#endif 23 | -#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR 24 | -#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR NULL 25 | -#endif 26 | -#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON 27 | -#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON NULL 28 | -#endif 29 | -#ifndef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR 30 | -#define SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR NULL 31 | -#endif 32 | - 33 | static waylanddynlib waylandlibs[] = { 34 | +#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL 35 | { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC }, 36 | - { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL }, 37 | +#endif 38 | +#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR 39 | { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR }, 40 | +#endif 41 | +#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON 42 | { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON }, 43 | - { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR } 44 | +#endif 45 | +#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR 46 | + { NULL, SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR }, 47 | +#endif 48 | + { NULL, NULL } 49 | }; 50 | 51 | static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool required) 52 | { 53 | - int i; 54 | void *fn = NULL; 55 | - for (i = 0; i < SDL_TABLESIZE(waylandlibs); i++) { 56 | - if (waylandlibs[i].lib != NULL) { 57 | - fn = SDL_LoadFunction(waylandlibs[i].lib, fnname); 58 | + waylanddynlib *dynlib; 59 | + for (dynlib = waylandlibs; dynlib->libname; dynlib++) { 60 | + if (dynlib->lib != NULL) { 61 | + fn = SDL_LoadFunction(dynlib->lib, fnname); 62 | if (fn != NULL) { 63 | break; 64 | } 65 | @@ -69,10 +64,11 @@ static void *WAYLAND_GetSym(const char *fnname, int *pHasModule, SDL_bool requir 66 | } 67 | 68 | #if DEBUG_DYNAMIC_WAYLAND 69 | - if (fn != NULL) 70 | - SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, waylandlibs[i].libname, fn); 71 | - else 72 | + if (fn != NULL) { 73 | + SDL_Log("WAYLAND: Found '%s' in %s (%p)\n", fnname, dynlib->libname, fn); 74 | + } else { 75 | SDL_Log("WAYLAND: Symbol '%s' NOT FOUND!\n", fnname); 76 | + } 77 | #endif 78 | 79 | if (fn == NULL && required) { 80 | -------------------------------------------------------------------------------- /source/ArenaPanel.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef ARENA_PANEL_H_ 4 | #define ARENA_PANEL_H_ 5 | 6 | #include "Panel.h" 7 | 8 | #include "Command.h" 9 | #include "Engine.h" 10 | #include "PlayerInfo.h" 11 | #include "ShipEvent.h" 12 | 13 | #include 14 | #include 15 | 16 | class Editor; 17 | class SystemEditor; 18 | 19 | 20 | 21 | // Class representing the main panel (i.e. the view of your ship moving around). 22 | // The goal is that the Engine class will not need to know about displaying 23 | // panels or handling key presses; it instead focuses just on the calculations 24 | // needed to move the ships around and to figure out where they should be drawn. 25 | class ArenaPanel : public Panel { 26 | public: 27 | static void RenderProperties(SystemEditor &systemEditor, bool &show); 28 | 29 | static inline Date currentDate = Date(16, 11, 3013); 30 | static inline bool enableFleets = false; 31 | static inline bool enablePersons = false; 32 | static inline bool highlightFlagship = false; 33 | static inline bool showStatusOverlays = false; 34 | static inline bool showChat = false; 35 | 36 | 37 | public: 38 | ArenaPanel(Editor &editor, SystemEditor &systemEditor); 39 | 40 | virtual void Step() override; 41 | virtual void Draw() override; 42 | 43 | void SetSystem(const System *system); 44 | void Execute(std::function f); 45 | 46 | // The main panel allows fast-forward. 47 | bool AllowsFastForward() const noexcept final; 48 | 49 | Engine &GetEngine() { return engine; } 50 | 51 | protected: 52 | // Only override the ones you need; the default action is to return false. 53 | virtual bool KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) override; 54 | virtual bool Click(int x, int y, int clicks) override; 55 | virtual bool RClick(int x, int y) override; 56 | virtual bool Drag(double dx, double dy) override; 57 | virtual bool Release(int x, int y) override; 58 | virtual bool Scroll(double dx, double dy) override; 59 | 60 | 61 | private: 62 | void StepEvents(bool &isActive); 63 | 64 | 65 | private: 66 | friend class ArenaControl; 67 | 68 | // Things to execute while the engine is paused. 69 | std::vector> commands; 70 | 71 | Editor &editor; 72 | SystemEditor &systemEditor; 73 | 74 | static inline PlayerInfo player; 75 | Engine engine; 76 | 77 | Point center; 78 | bool paused = false; 79 | 80 | // These are the pending ShipEvents that have yet to be processed. 81 | std::list eventQueue; 82 | bool handledFront = false; 83 | 84 | Command show; 85 | 86 | // For displaying the GPU load. 87 | double load = 0.; 88 | double loadSum = 0.; 89 | int loadCount = 0; 90 | 91 | // Keep track of how long a starting player has spent drifting in deep space. 92 | int lostness = 0; 93 | int lostCount = 0; 94 | 95 | Point dragSource; 96 | Point dragPoint; 97 | bool isDragging = false; 98 | bool hasShift = false; 99 | bool canClick = false; 100 | bool canDrag = false; 101 | 102 | friend class Editor; 103 | }; 104 | 105 | 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /source/MapEditorPanel.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef MAP_EDITOR_PANEL_H_ 4 | #define MAP_EDITOR_PANEL_H_ 5 | 6 | #include "Panel.h" 7 | 8 | #include "Color.h" 9 | #include "Point.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class Angle; 17 | class Editor; 18 | class Galaxy; 19 | class Government; 20 | class PlanetEditor; 21 | class System; 22 | class SystemEditor; 23 | 24 | 25 | 26 | // This class provides a limited version of the MapPanel which you can edit. 27 | class MapEditorPanel : public Panel { 28 | public: 29 | MapEditorPanel(const Editor &editor, PlanetEditor *planetEditor, SystemEditor *systemEditor); 30 | 31 | virtual void Step() override; 32 | virtual void Draw() override; 33 | 34 | // Map panels allow fast-forward to stay active. 35 | virtual bool AllowsFastForward() const noexcept override; 36 | 37 | const System *Selected() const; 38 | void Select(const Galaxy *galaxy); 39 | 40 | 41 | protected: 42 | // Only override the ones you need; the default action is to return false. 43 | virtual bool KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) override; 44 | virtual bool Click(int x, int y, int clicks) override; 45 | virtual bool RClick(int x, int y) override; 46 | virtual bool MClick(int x, int y) override; 47 | virtual bool Drag(double dx, double dy) override; 48 | virtual bool Scroll(double dx, double dy) override; 49 | virtual bool Release(int x, int y) override; 50 | 51 | // Get the color mapping for various system attributes. 52 | Color MapColor(double value); 53 | Color GovernmentColor(const Government *government); 54 | Color UninhabitedColor(); 55 | 56 | void Select(const System *system, bool appendSelection = false); 57 | void Find(const std::string &name); 58 | 59 | double Zoom() const; 60 | 61 | // Function for the "find" dialogs: 62 | static int Search(const std::string &str, const std::string &sub); 63 | 64 | 65 | protected: 66 | const Editor &editor; 67 | PlanetEditor *planetEditor; 68 | SystemEditor *systemEditor; 69 | 70 | // The (non-null) system which is currently selected. 71 | std::vector selectedSystems; 72 | 73 | double playerJumpDistance; 74 | 75 | Point center; 76 | Point recenterVector; 77 | int recentering = 0; 78 | 79 | // Center the view on the given system (may actually be slightly offset 80 | // to account for panels on the screen). 81 | void CenterOnSystem(bool immediate = false); 82 | 83 | // Cache the map layout, so it doesn't have to be re-calculated every frame. 84 | // The cache must be updated when the coloring mode changes. 85 | void UpdateCache(); 86 | 87 | void UpdateJumpDistance(); 88 | 89 | 90 | private: 91 | void DrawWormholes(); 92 | void DrawLinks(); 93 | // Draw systems in accordance to the set commodity color scheme. 94 | void DrawSystems(); 95 | void DrawNames(); 96 | 97 | 98 | private: 99 | struct Link { 100 | Point first; 101 | Point second; 102 | Color color; 103 | }; 104 | std::vector links; 105 | Point click; 106 | bool isDragging = false; 107 | bool rclick = false; 108 | bool moveSystems = false; 109 | 110 | bool selectSystems = false; 111 | Point dragSource; 112 | Point dragPoint; 113 | 114 | int commodity = -1; 115 | int tradeY = 0; 116 | 117 | int zoom = 0; 118 | 119 | friend class SystemEditor; 120 | }; 121 | 122 | 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /overlays/imgui/portfile.cmake: -------------------------------------------------------------------------------- 1 | vcpkg_check_linkage(ONLY_STATIC_LIBRARY) 2 | 3 | if ("docking-experimental" IN_LIST FEATURES) 4 | vcpkg_from_github( 5 | OUT_SOURCE_PATH SOURCE_PATH 6 | REPO ocornut/imgui 7 | REF 94e850fd6ff9eceb98fda3147e3ffd4781ad2dc7 8 | SHA512 3461ce0c843d214b5f954952896905094ba993a39864d11c2ddeb087e68bbb1f3e76027aff537ca8404c0dc797d27ede5d881ef6e274bec528a40971313934ba 9 | HEAD_REF docking 10 | PATCHES 11 | 0001-combo-additional-flags.patch 12 | ) 13 | else() 14 | vcpkg_from_github( 15 | OUT_SOURCE_PATH SOURCE_PATH 16 | REPO ocornut/imgui 17 | REF v1.89 18 | SHA512 6c027444842f8109bd6e0743c7eb40deb804b86419a190d304e0727d0c165f9c232c4386c244fa161ab9f1283880e998b970596f6505759808082e01c4cb7466 19 | HEAD_REF master 20 | PATCHES 21 | 0001-combo-additional-flags.patch 22 | ) 23 | endif() 24 | 25 | file(COPY "${CMAKE_CURRENT_LIST_DIR}/imgui-config.cmake.in" DESTINATION "${SOURCE_PATH}") 26 | file(COPY "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" DESTINATION "${SOURCE_PATH}") 27 | 28 | vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS 29 | FEATURES 30 | allegro5-binding IMGUI_BUILD_ALLEGRO5_BINDING 31 | dx9-binding IMGUI_BUILD_DX9_BINDING 32 | dx10-binding IMGUI_BUILD_DX10_BINDING 33 | dx11-binding IMGUI_BUILD_DX11_BINDING 34 | dx12-binding IMGUI_BUILD_DX12_BINDING 35 | glfw-binding IMGUI_BUILD_GLFW_BINDING 36 | glut-binding IMGUI_BUILD_GLUT_BINDING 37 | metal-binding IMGUI_BUILD_METAL_BINDING 38 | opengl2-binding IMGUI_BUILD_OPENGL2_BINDING 39 | opengl3-binding IMGUI_BUILD_OPENGL3_BINDING 40 | osx-binding IMGUI_BUILD_OSX_BINDING 41 | sdl2-binding IMGUI_BUILD_SDL2_BINDING 42 | sdl2-renderer-binding IMGUI_BUILD_SDL2_RENDERER_BINDING 43 | vulkan-binding IMGUI_BUILD_VULKAN_BINDING 44 | win32-binding IMGUI_BUILD_WIN32_BINDING 45 | freetype IMGUI_FREETYPE 46 | wchar32 IMGUI_USE_WCHAR32 47 | ) 48 | 49 | if ("libigl-imgui" IN_LIST FEATURES) 50 | vcpkg_download_distfile( 51 | IMGUI_FONTS_DROID_SANS_H 52 | URLS 53 | https://raw.githubusercontent.com/libigl/libigl-imgui/c3efb9b62780f55f9bba34561f79a3087e057fc0/imgui_fonts_droid_sans.h 54 | FILENAME "imgui_fonts_droid_sans.h" 55 | SHA512 56 | abe9250c9a5989e0a3f2285bbcc83696ff8e38c1f5657c358e6fe616ff792d3c6e5ff2fa23c2eeae7d7b307392e0dc798a95d14f6d10f8e9bfbd7768d36d8b31 57 | ) 58 | 59 | file(INSTALL "${IMGUI_FONTS_DROID_SANS_H}" DESTINATION "${CURRENT_PACKAGES_DIR}/include") 60 | endif() 61 | 62 | vcpkg_cmake_configure( 63 | SOURCE_PATH "${SOURCE_PATH}" 64 | OPTIONS 65 | ${FEATURE_OPTIONS} 66 | OPTIONS_DEBUG 67 | -DIMGUI_SKIP_HEADERS=ON 68 | ) 69 | 70 | vcpkg_cmake_install() 71 | 72 | if ("freetype" IN_LIST FEATURES) 73 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/imconfig.h" "//#define IMGUI_ENABLE_FREETYPE" "#define IMGUI_ENABLE_FREETYPE") 74 | endif() 75 | if ("wchar32" IN_LIST FEATURES) 76 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/imconfig.h" "//#define IMGUI_USE_WCHAR32" "#define IMGUI_USE_WCHAR32") 77 | endif() 78 | 79 | vcpkg_copy_pdbs() 80 | vcpkg_cmake_config_fixup() 81 | 82 | file(INSTALL "${SOURCE_PATH}/LICENSE.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) 83 | -------------------------------------------------------------------------------- /source/ArenaControl.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "ArenaControl.h" 4 | 5 | #include "Editor.h" 6 | #include "Fleet.h" 7 | #include "imgui_ex.h" 8 | #include "Ship.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | using namespace std; 18 | 19 | 20 | 21 | ArenaControl::ArenaControl(Editor &editor, SystemEditor &systemEditor) 22 | : editor(editor), systemEditor(systemEditor) 23 | {} 24 | 25 | 26 | 27 | void ArenaControl::SetArena(weak_ptr ptr) 28 | { 29 | arena = std::move(ptr); 30 | } 31 | 32 | 33 | 34 | void ArenaControl::Render(bool &show) 35 | { 36 | ImGui::SetNextWindowSize(ImVec2(550, 500), ImGuiCond_FirstUseEver); 37 | if(!ImGui::Begin("Arena Control", &show)) 38 | { 39 | ImGui::End(); 40 | return; 41 | } 42 | 43 | auto arenaPtr = arena.lock(); 44 | if(!arenaPtr) 45 | return ImGui::End(); 46 | 47 | if(ImGui::Button(arenaPtr->paused ? "Unpause" : "Pause")) 48 | arenaPtr->paused = !arenaPtr->paused; 49 | ImGui::SameLine(); 50 | if(ImGui::Button("Clear Ships")) 51 | arenaPtr->Execute([arenaPtr] 52 | { 53 | arenaPtr->engine.ships.clear(); 54 | }); 55 | 56 | ImGui::Spacing(); 57 | 58 | // Ship spawning. 59 | static Ship *ship; 60 | string shipName; 61 | if(ship) 62 | shipName = ship->VariantName(); 63 | ImGui::InputCombo("ship", &shipName, &ship, editor.Universe().ships); 64 | 65 | static Government *gov; 66 | string govName; 67 | if(gov) 68 | govName = gov->TrueName(); 69 | ImGui::InputCombo("government", &govName, &gov, editor.Universe().governments); 70 | 71 | int amount = 1; 72 | if(ImGui::GetIO().KeyShift) 73 | amount *= 5; 74 | if(ImGui::GetIO().KeyCtrl) 75 | amount *= 20; 76 | if(ImGui::GetIO().KeyAlt) 77 | amount *= 500; 78 | 79 | if(!ship || !gov) 80 | ImGui::BeginDisabled(); 81 | if(ImGui::Button("Spawn")) 82 | arenaPtr->Execute([this, amount] { 83 | for(int i = 0; i < amount; ++i) 84 | PlaceShip(*ship, *gov); 85 | }); 86 | if(!ship || !gov) 87 | ImGui::EndDisabled(); 88 | 89 | ImGui::SameLine(); 90 | ImGui::Text("x%d", amount); 91 | 92 | ImGui::Spacing(); 93 | 94 | // Fleet spawning. 95 | static Fleet *fleet; 96 | string fleetName; 97 | if(fleet) 98 | fleetName = fleet->Name(); 99 | ImGui::InputCombo("fleet", &fleetName, &fleet, editor.Universe().fleets); 100 | 101 | static Government *fleetgov; 102 | string fleetgovName; 103 | if(fleetgov) 104 | fleetgovName = fleetgov->TrueName(); 105 | ImGui::InputCombo("government##fleet", &fleetgovName, &fleetgov, editor.Universe().governments); 106 | 107 | amount = 1; 108 | if(ImGui::GetIO().KeyShift) 109 | amount *= 5; 110 | if(ImGui::GetIO().KeyCtrl) 111 | amount *= 20; 112 | if(ImGui::GetIO().KeyAlt) 113 | amount *= 500; 114 | 115 | if(!fleet || !fleetgov) 116 | ImGui::BeginDisabled(); 117 | if(ImGui::Button("Spawn##fleet")) 118 | arenaPtr->Execute([this, amount] { 119 | for(int i = 0; i < amount; ++i) 120 | for(const auto &ship : fleet->variants.Get().Ships()) 121 | PlaceShip(*ship, *fleetgov); 122 | }); 123 | if(!fleet || !fleetgov) 124 | ImGui::EndDisabled(); 125 | 126 | ImGui::SameLine(); 127 | ImGui::Text("x%d", amount); 128 | ImGui::End(); 129 | } 130 | 131 | 132 | 133 | void ArenaControl::PlaceShip(const Ship &ship, const Government &gov) const 134 | { 135 | auto newShip = make_shared(ship); 136 | newShip->SetName(ship.TrueName()); 137 | newShip->SetSystem(systemEditor.Selected()); 138 | newShip->SetGovernment(&gov); 139 | newShip->SetPersonality(Personality::STAYING | Personality::UNINTERESTED); 140 | 141 | Fleet::Place(*systemEditor.Selected(), *newShip); 142 | arena.lock()->engine.Place(newShip); 143 | } 144 | -------------------------------------------------------------------------------- /source/Editor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef EDITOR_H_ 4 | #define EDITOR_H_ 5 | 6 | #include "GameAssets.h" 7 | 8 | #include "ArenaControl.h" 9 | #include "ArenaPanel.h" 10 | #include "EffectEditor.h" 11 | #include "FleetEditor.h" 12 | #include "GalaxyEditor.h" 13 | #include "HazardEditor.h" 14 | #include "GovernmentEditor.h" 15 | #include "OutfitEditor.h" 16 | #include "OutfitterEditor.h" 17 | #include "PlanetEditor.h" 18 | #include "ShipEditor.h" 19 | #include "ShipyardEditor.h" 20 | #include "SystemEditor.h" 21 | 22 | #include "EditorPlugin.h" 23 | #include "UniverseObjects.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | class Body; 33 | class Engine; 34 | class OutfitterEditorPanel; 35 | class Sprite; 36 | class StellarObject; 37 | class UI; 38 | 39 | 40 | 41 | class HashPairOfStrings 42 | { 43 | public: 44 | std::size_t operator()(const std::pair &pair) const noexcept 45 | { 46 | return std::hash()(pair.first) * 3 + std::hash()(pair.second); 47 | } 48 | }; 49 | 50 | 51 | 52 | // Class representing the editor UI. 53 | class Editor { 54 | public: 55 | Editor(UI &panels) noexcept; 56 | Editor(const Editor &) = delete; 57 | Editor &operator=(const Editor &) = delete; 58 | 59 | void Initialize(); 60 | 61 | void RenderMain(); 62 | 63 | void ShowConfirmationDialog(); 64 | 65 | bool HasPlugin() const; 66 | const std::string &GetPluginPath() const; 67 | UI &GetUI(); 68 | 69 | const GameAssets::Snapshot &BaseUniverse() const; 70 | UniverseObjects &Universe(); 71 | const UniverseObjects &Universe() const; 72 | const Set &Sprites() const; 73 | const Set &Sounds() const; 74 | const SpriteSet &Spriteset() const; 75 | EditorPlugin &GetPlugin(); 76 | 77 | const std::shared_ptr &MapPanel() const; 78 | const std::shared_ptr &SystemViewPanel() const; 79 | const std::shared_ptr &OutfitterPanel() const; 80 | const std::shared_ptr &GetArenaPanel() const; 81 | 82 | 83 | private: 84 | void ResetEditor(); 85 | void ResetPanels(); 86 | 87 | void NewPlugin(const std::string &plugin, bool reset = true); 88 | bool OpenPlugin(const std::string &plugin); 89 | bool OpenGameData(const std::string &game); 90 | void SavePlugin(); 91 | 92 | void StyleColorsGray(); 93 | void StyleColorsDarkGray(); 94 | 95 | 96 | public: 97 | EffectEditor effectEditor; 98 | FleetEditor fleetEditor; 99 | GalaxyEditor galaxyEditor; 100 | HazardEditor hazardEditor; 101 | GovernmentEditor governmentEditor; 102 | OutfitEditor outfitEditor; 103 | OutfitterEditor outfitterEditor; 104 | PlanetEditor planetEditor; 105 | ShipEditor shipEditor; 106 | ShipyardEditor shipyardEditor; 107 | SystemEditor systemEditor; 108 | 109 | 110 | private: 111 | UI &ui; 112 | bool showEditor = true; 113 | 114 | // The base universe of the game without any plugins. 115 | GameAssets::Snapshot baseAssets; 116 | 117 | std::shared_ptr mapEditorPanel; 118 | std::shared_ptr mainEditorPanel; 119 | std::shared_ptr outfitterEditorPanel; 120 | 121 | std::shared_ptr arenaPanel; 122 | ArenaControl arenaControl; 123 | 124 | EditorPlugin plugin; 125 | std::string currentPluginPath; 126 | bool isGameData = false; 127 | 128 | bool showConfirmationDialog = false; 129 | bool showMainEditorPanelProperties = false; 130 | bool showOutfitterEditorPanelProperties = false; 131 | bool showArenaPanelProperties = false; 132 | bool showArenaControl = false; 133 | 134 | bool showEffectMenu = false; 135 | bool showFleetMenu = false; 136 | bool showGalaxyMenu = false; 137 | bool showHazardMenu = false; 138 | bool showGovernmentMenu = false; 139 | bool showOutfitMenu = false; 140 | bool showOutfitterMenu = false; 141 | bool showShipMenu = false; 142 | bool showShipyardMenu = false; 143 | bool showSystemMenu = false; 144 | bool showPlanetMenu = false; 145 | }; 146 | 147 | 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /source/EditorPlugin.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef EDITOR_PLUGIN_H_ 4 | #define EDITOR_PLUGIN_H_ 5 | 6 | #include "Sale.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class DataNode; 19 | class Editor; 20 | class Effect; 21 | class Fleet; 22 | class Galaxy; 23 | class Hazard; 24 | class Government; 25 | class Outfit; 26 | class Planet; 27 | class Ship; 28 | class System; 29 | 30 | 31 | // This class stores a list of objects that the plugin contains. 32 | class EditorPlugin { 33 | public: 34 | using Node = std::variant *, const Planet *, const Ship *, 36 | const Sale *, const System *, const DataNode *>; 37 | 38 | 39 | public: 40 | // Loads the plugin at the specified path. 41 | void Load(const Editor &editor, std::string_view path); 42 | // Saves this plugin to the specified path. 43 | void Save(const Editor &editor, std::string_view path); 44 | 45 | // Whether any changes were made to this plugin since loading it. 46 | bool HasChanges() const; 47 | 48 | // Adds the specified object as part of this plugin. 49 | void Add(Node node); 50 | 51 | // Checks if the specified object is part of this plugin. 52 | bool Has(const Node &node) const; 53 | 54 | // Removes the specified object as part of this plugin. 55 | void Remove(const Node &node); 56 | 57 | 58 | private: 59 | // Helper function that returns the map corresponding to the type of ptr. 60 | template 61 | std::map &GetMapForNodeElement(); 62 | template 63 | const std::map &GetMapForNodeElement() const; 64 | 65 | 66 | private: 67 | // Whether this plugin had modifications made to it since calling Load. 68 | // Saving the plugin clears this flag. 69 | bool hasModifications = false; 70 | 71 | // List of data files that have modifications. This is to avoid rewriting files 72 | // that haven't been touched. 73 | std::set filesChanged; 74 | 75 | std::unordered_map> data; 76 | std::list unknownNodes; 77 | 78 | std::map effects; 79 | std::map fleets; 80 | std::map galaxies; 81 | std::map hazards; 82 | std::map governments; 83 | std::map outfits; 84 | std::map *, std::string> outfitters; 85 | std::map planets; 86 | std::map ships; 87 | std::map *, std::string> shipyards; 88 | std::map systems; 89 | }; 90 | 91 | 92 | 93 | template 94 | std::map &EditorPlugin::GetMapForNodeElement() 95 | { 96 | const auto &This = *this; 97 | return const_cast &>(This.GetMapForNodeElement()); 98 | } 99 | 100 | 101 | 102 | template 103 | const std::map &EditorPlugin::GetMapForNodeElement() const 104 | { 105 | if constexpr(std::is_same_v) 106 | return effects; 107 | else if constexpr(std::is_same_v) 108 | return fleets; 109 | else if constexpr(std::is_same_v) 110 | return galaxies; 111 | else if constexpr(std::is_same_v) 112 | return hazards; 113 | else if constexpr(std::is_same_v) 114 | return governments; 115 | else if constexpr(std::is_same_v) 116 | return outfits; 117 | else if constexpr(std::is_same_v *>) 118 | return outfitters; 119 | else if constexpr(std::is_same_v) 120 | return planets; 121 | else if constexpr(std::is_same_v) 122 | return ships; 123 | else if constexpr(std::is_same_v *>) 124 | return shipyards; 125 | else if constexpr(std::is_same_v) 126 | return systems; 127 | else 128 | { 129 | assert(!"no map for T"); 130 | static std::map empty; 131 | return empty; 132 | } 133 | } 134 | 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /source/OutfitterEditorPanel.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef OUTFITTER_EDITOR_PANEL_H_ 4 | #define OUTFITTER_EDITOR_PANEL_H_ 5 | 6 | #include "Panel.h" 7 | 8 | #include "CategoryList.h" 9 | #include "ClickZone.h" 10 | #include "OutfitInfoDisplay.h" 11 | #include "ShipInfoDisplay.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class Editor; 19 | class Outfit; 20 | class PlayerInfo; 21 | class Point; 22 | class Ship; 23 | class ShipEditor; 24 | 25 | 26 | 27 | class OutfitterEditorPanel : public Panel { 28 | public: 29 | static void RenderProperties(bool &show); 30 | 31 | static inline bool showDeprecatedOutfits = false; 32 | 33 | 34 | public: 35 | OutfitterEditorPanel(Editor &editor, ShipEditor &shipEditor); 36 | 37 | virtual void Step() override; 38 | virtual void Draw() override; 39 | 40 | void SetShip(Ship *ship) { this->ship = ship; } 41 | void UpdateCache(); 42 | 43 | 44 | protected: 45 | void DrawShipsSidebar(); 46 | void DrawDetailsSidebar(); 47 | void DrawButtons(); 48 | void DrawMain(); 49 | 50 | void DrawShip(const Ship &ship, const Point ¢er, bool isSelected); 51 | int TileSize() const; 52 | int VisiblityCheckboxesSize() const; 53 | int DrawPlayerShipInfo(const Point &point); 54 | bool HasItem(const std::string &name) const; 55 | void DrawItem(const std::string &name, const Point &point, int scrollY); 56 | int DividerOffset() const; 57 | int DetailWidth() const; 58 | int DrawDetails(const Point ¢er); 59 | bool CanBuy(bool checkAlreadyOwned = true) const; 60 | void Buy(bool alreadyOwned = false); 61 | void FailBuy() const; 62 | bool CanSell(bool toStorage = false) const; 63 | void Sell(bool toStorage = false); 64 | void FailSell(bool toStorage = false) const; 65 | bool ShouldHighlight(const Ship *ship); 66 | 67 | // Only override the ones you need; the default action is to return false. 68 | virtual bool KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) override; 69 | virtual bool Click(int x, int y, int clicks) override; 70 | virtual bool Hover(int x, int y) override; 71 | virtual bool Scroll(double dx, double dy) override; 72 | 73 | 74 | private: 75 | class Zone : public ClickZone { 76 | public: 77 | explicit Zone(Point center, Point size, const Outfit *outfit, double scrollY = 0.); 78 | 79 | double ScrollY() const; 80 | 81 | private: 82 | double scrollY = 0.; 83 | }; 84 | 85 | enum class ShopPane : int { 86 | Main, 87 | Sidebar, 88 | Info 89 | }; 90 | 91 | 92 | private: 93 | bool DoScroll(double dy); 94 | bool SetScrollToTop(); 95 | bool SetScrollToBottom(); 96 | void SideSelect(int count); 97 | void SideSelect(Ship *ship); 98 | void MainLeft(); 99 | void MainRight(); 100 | void MainUp(); 101 | void MainDown(); 102 | std::vector::const_iterator Selected() const; 103 | std::vector::const_iterator MainStart() const; 104 | std::map> FlightCheck() const; 105 | bool ShipCanBuy(const Ship *ship, const Outfit *outfit) const; 106 | bool ShipCanSell(const Ship *ship, const Outfit *outfit) const; 107 | void DrawOutfit(const Outfit &outfit, const Point ¢er, bool isSelected, bool isOwned) const; 108 | bool IsLicense(const std::string &name) const; 109 | bool HasLicense(const std::string &name) const; 110 | std::string LicenseName(const std::string &name) const; 111 | // Check if the given point is within the button zone, and if so return the 112 | // letter of the button (or ' ' if it's not on a button). 113 | char CheckButton(int x, int y); 114 | 115 | private: 116 | Editor &editor; 117 | ShipEditor &shipEditor; 118 | 119 | Ship *ship = nullptr; 120 | 121 | // The currently selected Outfit, for the OutfitterPanel. 122 | const Outfit *selectedOutfit = nullptr; 123 | 124 | double mainScroll = 0.; 125 | double sidebarScroll = 0.; 126 | double infobarScroll = 0.; 127 | double maxMainScroll = 0.; 128 | double maxSidebarScroll = 0.; 129 | double maxInfobarScroll = 0.; 130 | ShopPane activePane = ShopPane::Main; 131 | int mainDetailHeight = 0; 132 | int sideDetailHeight = 0; 133 | bool scrollDetailsIntoView = false; 134 | double selectedTopY = 0.; 135 | bool sameSelectedTopY = false; 136 | char hoverButton = '\0'; 137 | 138 | std::vector zones; 139 | std::vector> categoryZones; 140 | 141 | std::map> catalog; 142 | const CategoryList &categories; 143 | static inline std::set collapsed; 144 | 145 | ShipInfoDisplay shipInfo; 146 | OutfitInfoDisplay outfitInfo; 147 | 148 | mutable Point warningPoint; 149 | mutable std::string warningType; 150 | }; 151 | 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /source/GalaxyEditor.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "GalaxyEditor.h" 4 | 5 | #include "DataFile.h" 6 | #include "DataNode.h" 7 | #include "DataWriter.h" 8 | #include "Dialog.h" 9 | #include "imgui.h" 10 | #include "imgui_ex.h" 11 | #include "imgui_internal.h" 12 | #include "imgui_stdlib.h" 13 | #include "Editor.h" 14 | #include "Effect.h" 15 | #include "Engine.h" 16 | #include "Files.h" 17 | #include "Galaxy.h" 18 | #include "Government.h" 19 | #include "MainPanel.h" 20 | #include "MapEditorPanel.h" 21 | #include "MapPanel.h" 22 | #include "Minable.h" 23 | #include "Planet.h" 24 | #include "PlayerInfo.h" 25 | #include "Ship.h" 26 | #include "Sound.h" 27 | #include "SpriteSet.h" 28 | #include "Sprite.h" 29 | #include "System.h" 30 | #include "UI.h" 31 | 32 | #include 33 | #include 34 | 35 | using namespace std; 36 | 37 | 38 | 39 | GalaxyEditor::GalaxyEditor(Editor &editor, bool &show) noexcept 40 | : TemplateEditor(editor, show) 41 | { 42 | } 43 | 44 | 45 | 46 | void GalaxyEditor::Render() 47 | { 48 | ImGui::SetNextWindowSize(ImVec2(550, 500), ImGuiCond_FirstUseEver); 49 | if(!ImGui::Begin("Galaxy Editor", &show, ImGuiWindowFlags_MenuBar)) 50 | { 51 | ImGui::End(); 52 | return; 53 | } 54 | 55 | bool showNewGalaxy = false; 56 | bool showRenameGalaxy = false; 57 | bool showCloneGalaxy = false; 58 | if(ImGui::BeginMenuBar()) 59 | { 60 | if(ImGui::BeginMenu("Galaxy")) 61 | { 62 | const bool alreadyDefined = object && !editor.BaseUniverse().galaxies.Has(object->name); 63 | ImGui::MenuItem("New", nullptr, &showNewGalaxy); 64 | ImGui::MenuItem("Rename", nullptr, &showRenameGalaxy, alreadyDefined); 65 | ImGui::MenuItem("Clone", nullptr, &showCloneGalaxy, object); 66 | if(ImGui::MenuItem("Reset", nullptr, false, alreadyDefined && editor.GetPlugin().Has(object))) 67 | { 68 | editor.GetPlugin().Remove(object); 69 | *object = *editor.BaseUniverse().galaxies.Get(object->name); 70 | } 71 | if(ImGui::MenuItem("Delete", nullptr, false, alreadyDefined)) 72 | { 73 | editor.GetPlugin().Remove(object); 74 | editor.Universe().galaxies.Erase(object->name); 75 | object = nullptr; 76 | } 77 | ImGui::EndMenu(); 78 | } 79 | if(ImGui::BeginMenu("Tools")) 80 | { 81 | if(ImGui::MenuItem("Go to Galaxy", nullptr, false, object)) 82 | if(auto *panel = dynamic_cast(editor.GetUI().Top().get())) 83 | panel->Select(object); 84 | ImGui::EndMenu(); 85 | } 86 | ImGui::EndMenuBar(); 87 | } 88 | 89 | if(showNewGalaxy) 90 | ImGui::OpenPopup("New Galaxy"); 91 | if(showRenameGalaxy) 92 | ImGui::OpenPopup("Rename Galaxy"); 93 | if(showCloneGalaxy) 94 | ImGui::OpenPopup("Clone Galaxy"); 95 | ImGui::BeginSimpleNewModal("New Galaxy", [this](const string &name) 96 | { 97 | if(editor.Universe().galaxies.Find(name)) 98 | return; 99 | 100 | auto *newGalaxy = editor.Universe().galaxies.Get(name); 101 | newGalaxy->name = name; 102 | object = newGalaxy; 103 | SetDirty(); 104 | }); 105 | ImGui::BeginSimpleRenameModal("Rename Galaxy", [this](const string &name) 106 | { 107 | if(editor.Universe().galaxies.Find(name)) 108 | return; 109 | 110 | editor.Universe().galaxies.Rename(object->name, name); 111 | object->name = name; 112 | SetDirty(); 113 | }); 114 | ImGui::BeginSimpleCloneModal("Clone Galaxy", [this](const string &name) 115 | { 116 | if(editor.Universe().galaxies.Find(name)) 117 | return; 118 | 119 | auto *clone = editor.Universe().galaxies.Get(name); 120 | *clone = *object; 121 | object = clone; 122 | 123 | object->name = name; 124 | SetDirty(); 125 | }); 126 | 127 | if(ImGui::InputCombo("galaxy", &searchBox, &object, editor.Universe().galaxies)) 128 | searchBox.clear(); 129 | 130 | ImGui::Separator(); 131 | ImGui::Spacing(); 132 | ImGui::PushID(object); 133 | if(object) 134 | RenderGalaxy(); 135 | ImGui::PopID(); 136 | ImGui::End(); 137 | } 138 | 139 | 140 | 141 | void GalaxyEditor::RenderGalaxy() 142 | { 143 | ImGui::Text("name: %s", object->name.c_str()); 144 | 145 | double pos[2] = {object->position.X(), object->Position().Y()}; 146 | if(ImGui::InputDouble2Ex("pos", pos)) 147 | { 148 | object->position.Set(pos[0], pos[1]); 149 | SetDirty(); 150 | } 151 | 152 | string spriteName = object->sprite ? object->sprite->Name() : ""; 153 | if(ImGui::InputCombo("sprite", &spriteName, &object->sprite, editor.Sprites())) 154 | SetDirty(); 155 | 156 | // TODO: Maybe show the galaxy image here. ImGui doesn't support texture arrays (which 157 | // we use to draw sprites), so we'd have to hack something in. *pain* 158 | } 159 | 160 | 161 | 162 | void GalaxyEditor::WriteToFile(DataWriter &writer, const Galaxy *galaxy) const 163 | { 164 | const auto *diff = editor.BaseUniverse().galaxies.Has(galaxy->name) 165 | ? editor.BaseUniverse().galaxies.Get(galaxy->name) 166 | : nullptr; 167 | 168 | writer.Write("galaxy", galaxy->Name()); 169 | writer.BeginChild(); 170 | 171 | if(!diff || (diff && (galaxy->position.X() != diff->position.X() || galaxy->position.Y() != diff->position.Y()))) 172 | if(galaxy->position || diff) 173 | writer.Write("pos", galaxy->position.X(), galaxy->position.Y()); 174 | if(!diff || galaxy->sprite != diff->sprite) 175 | if(galaxy->sprite) 176 | writer.Write("sprite", galaxy->sprite->Name()); 177 | 178 | writer.EndChild(); 179 | } 180 | -------------------------------------------------------------------------------- /source/ShipyardEditor.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "ShipyardEditor.h" 4 | 5 | #include "DataFile.h" 6 | #include "DataNode.h" 7 | #include "DataWriter.h" 8 | #include "Dialog.h" 9 | #include "imgui.h" 10 | #include "imgui_ex.h" 11 | #include "imgui_internal.h" 12 | #include "imgui_stdlib.h" 13 | #include "Editor.h" 14 | #include "Effect.h" 15 | #include "Engine.h" 16 | #include "Files.h" 17 | #include "Government.h" 18 | #include "Hazard.h" 19 | #include "MainPanel.h" 20 | #include "MapPanel.h" 21 | #include "Minable.h" 22 | #include "Planet.h" 23 | #include "PlayerInfo.h" 24 | #include "Ship.h" 25 | #include "ShipEvent.h" 26 | #include "Sound.h" 27 | #include "SpriteSet.h" 28 | #include "Sprite.h" 29 | #include "System.h" 30 | #include "UI.h" 31 | 32 | #include 33 | #include 34 | 35 | using namespace std; 36 | 37 | 38 | 39 | ShipyardEditor::ShipyardEditor(Editor &editor, bool &show) noexcept 40 | : TemplateEditor>(editor, show) 41 | { 42 | } 43 | 44 | 45 | 46 | void ShipyardEditor::Render() 47 | { 48 | ImGui::SetNextWindowSize(ImVec2(550, 500), ImGuiCond_FirstUseEver); 49 | if(!ImGui::Begin("Shipyard Editor", &show, ImGuiWindowFlags_MenuBar)) 50 | { 51 | ImGui::End(); 52 | return; 53 | } 54 | 55 | bool showNewShipyard = false; 56 | bool showRenameShipyard = false; 57 | bool showCloneShipyard = false; 58 | if(ImGui::BeginMenuBar()) 59 | { 60 | if(ImGui::BeginMenu("Shipyard")) 61 | { 62 | const bool alreadyDefined = object && !editor.BaseUniverse().shipSales.Has(object->name); 63 | ImGui::MenuItem("New", nullptr, &showNewShipyard); 64 | ImGui::MenuItem("Rename", nullptr, &showRenameShipyard, alreadyDefined); 65 | ImGui::MenuItem("Clone", nullptr, &showCloneShipyard, object); 66 | if(ImGui::MenuItem("Reset", nullptr, false, alreadyDefined && editor.GetPlugin().Has(object))) 67 | { 68 | editor.GetPlugin().Remove(object); 69 | *object = *editor.BaseUniverse().shipSales.Get(object->name); 70 | } 71 | if(ImGui::MenuItem("Delete", nullptr, false, alreadyDefined)) 72 | { 73 | editor.GetPlugin().Remove(object); 74 | editor.Universe().shipSales.Erase(object->name); 75 | object = nullptr; 76 | } 77 | ImGui::EndMenu(); 78 | } 79 | ImGui::EndMenuBar(); 80 | } 81 | 82 | if(showNewShipyard) 83 | ImGui::OpenPopup("New Shipyard"); 84 | if(showRenameShipyard) 85 | ImGui::OpenPopup("Rename Shipyard"); 86 | if(showCloneShipyard) 87 | ImGui::OpenPopup("Clone Shipyard"); 88 | ImGui::BeginSimpleNewModal("New Shipyard", [this](const string &name) 89 | { 90 | if(editor.Universe().shipSales.Find(name)) 91 | return; 92 | 93 | auto *newShipyard = editor.Universe().shipSales.Get(name); 94 | newShipyard->name = name; 95 | object = newShipyard; 96 | SetDirty(); 97 | }); 98 | ImGui::BeginSimpleRenameModal("Rename Shipyard", [this](const string &name) 99 | { 100 | if(editor.Universe().shipSales.Find(name)) 101 | return; 102 | 103 | editor.Universe().shipSales.Rename(object->name, name); 104 | object->name = name; 105 | SetDirty(); 106 | }); 107 | ImGui::BeginSimpleCloneModal("Clone Shipyard", [this](const string &name) 108 | { 109 | if(editor.Universe().shipSales.Find(name)) 110 | return; 111 | 112 | auto *clone = editor.Universe().shipSales.Get(name); 113 | *clone = *object; 114 | object = clone; 115 | 116 | object->name = name; 117 | SetDirty(); 118 | }); 119 | 120 | if(ImGui::InputCombo("shipyard", &searchBox, &object, editor.Universe().shipSales)) 121 | searchBox.clear(); 122 | 123 | ImGui::Separator(); 124 | ImGui::Spacing(); 125 | ImGui::PushID(object); 126 | if(object) 127 | RenderShipyard(); 128 | ImGui::PopID(); 129 | ImGui::End(); 130 | } 131 | 132 | 133 | 134 | void ShipyardEditor::RenderShipyard() 135 | { 136 | ImGui::Text("name: %s", object->name.c_str()); 137 | int index = 0; 138 | const Ship *toAdd = nullptr; 139 | const Ship *toRemove = nullptr; 140 | for(auto it = object->begin(); it != object->end(); ++it) 141 | { 142 | ImGui::PushID(index++); 143 | string name = (*it)->TrueName(); 144 | Ship *change = nullptr; 145 | if(ImGui::InputCombo("##ship", &name, &change, editor.Universe().ships)) 146 | { 147 | if(name.empty()) 148 | { 149 | toRemove = *it; 150 | SetDirty(); 151 | } 152 | else 153 | { 154 | toAdd = change; 155 | toRemove = *it; 156 | SetDirty(); 157 | } 158 | } 159 | ImGui::PopID(); 160 | } 161 | if(toAdd) 162 | object->insert(toAdd); 163 | if(toRemove) 164 | object->erase(toRemove); 165 | 166 | static string shipName; 167 | static Ship *ship = nullptr; 168 | ImGui::Spacing(); 169 | if(ImGui::InputCombo("add ship", &shipName, &ship, editor.Universe().ships)) 170 | if(!shipName.empty()) 171 | { 172 | object->insert(ship); 173 | SetDirty(); 174 | shipName.clear(); 175 | } 176 | } 177 | 178 | 179 | 180 | void ShipyardEditor::WriteToFile(DataWriter &writer, const Sale *shipyard) const 181 | { 182 | const auto *diff = editor.BaseUniverse().shipSales.Has(shipyard->name) 183 | ? editor.BaseUniverse().shipSales.Get(shipyard->name) 184 | : nullptr; 185 | 186 | writer.Write("shipyard", shipyard->name); 187 | writer.BeginChild(); 188 | if(diff) 189 | WriteSorted(diff->AsBase(), [](const Ship *lhs, const Ship *rhs) { return lhs->TrueName() < rhs->TrueName(); }, 190 | [&writer, &shipyard](const Ship &ship) 191 | { 192 | if(!shipyard->Has(&ship)) 193 | writer.Write("remove", ship.TrueName()); 194 | }); 195 | WriteSorted(shipyard->AsBase(), [](const Ship *lhs, const Ship *rhs) { return lhs->TrueName() < rhs->TrueName(); }, 196 | [&writer, &diff](const Ship &ship) 197 | { 198 | if(!diff || !diff->Has(&ship)) 199 | writer.Write(ship.TrueName()); 200 | }); 201 | writer.EndChild(); 202 | } 203 | -------------------------------------------------------------------------------- /source/OutfitterEditor.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "OutfitterEditor.h" 4 | 5 | #include "DataFile.h" 6 | #include "DataNode.h" 7 | #include "DataWriter.h" 8 | #include "Dialog.h" 9 | #include "imgui.h" 10 | #include "imgui_ex.h" 11 | #include "imgui_internal.h" 12 | #include "imgui_stdlib.h" 13 | #include "Editor.h" 14 | #include "Effect.h" 15 | #include "Engine.h" 16 | #include "Files.h" 17 | #include "Government.h" 18 | #include "Hazard.h" 19 | #include "MainPanel.h" 20 | #include "MapPanel.h" 21 | #include "Minable.h" 22 | #include "Planet.h" 23 | #include "PlayerInfo.h" 24 | #include "Ship.h" 25 | #include "ShipEvent.h" 26 | #include "Sound.h" 27 | #include "SpriteSet.h" 28 | #include "Sprite.h" 29 | #include "System.h" 30 | #include "UI.h" 31 | 32 | #include 33 | #include 34 | 35 | using namespace std; 36 | 37 | 38 | 39 | OutfitterEditor::OutfitterEditor(Editor &editor, bool &show) noexcept 40 | : TemplateEditor>(editor, show) 41 | { 42 | } 43 | 44 | 45 | 46 | void OutfitterEditor::Render() 47 | { 48 | ImGui::SetNextWindowSize(ImVec2(550, 500), ImGuiCond_FirstUseEver); 49 | if(!ImGui::Begin("Outfitter Editor", &show, ImGuiWindowFlags_MenuBar)) 50 | { 51 | ImGui::End(); 52 | return; 53 | } 54 | 55 | bool showNewOutfitter = false; 56 | bool showRenameOutfitter = false; 57 | bool showCloneOutfitter = false; 58 | if(ImGui::BeginMenuBar()) 59 | { 60 | if(ImGui::BeginMenu("Outfitter")) 61 | { 62 | const bool alreadyDefined = object && !editor.BaseUniverse().outfitSales.Has(object->name); 63 | ImGui::MenuItem("New", nullptr, &showNewOutfitter); 64 | ImGui::MenuItem("Rename", nullptr, &showRenameOutfitter, alreadyDefined); 65 | ImGui::MenuItem("Clone", nullptr, &showCloneOutfitter, object); 66 | if(ImGui::MenuItem("Reset", nullptr, false, alreadyDefined && editor.GetPlugin().Has(object))) 67 | { 68 | editor.GetPlugin().Remove(object); 69 | *object = *editor.BaseUniverse().outfitSales.Get(object->name); 70 | } 71 | if(ImGui::MenuItem("Delete", nullptr, false, alreadyDefined)) 72 | { 73 | editor.GetPlugin().Remove(object); 74 | editor.Universe().outfitSales.Erase(object->name); 75 | object = nullptr; 76 | } 77 | ImGui::EndMenu(); 78 | } 79 | ImGui::EndMenuBar(); 80 | } 81 | 82 | if(showNewOutfitter) 83 | ImGui::OpenPopup("New Outfitter"); 84 | if(showRenameOutfitter) 85 | ImGui::OpenPopup("Rename Outfitter"); 86 | if(showCloneOutfitter) 87 | ImGui::OpenPopup("Clone Outfitter"); 88 | ImGui::BeginSimpleNewModal("New Outfitter", [this](const string &name) 89 | { 90 | if(editor.Universe().outfitSales.Find(name)) 91 | return; 92 | 93 | auto *newOutfitter = editor.Universe().outfitSales.Get(name); 94 | newOutfitter->name = name; 95 | object = newOutfitter; 96 | SetDirty(); 97 | }); 98 | ImGui::BeginSimpleRenameModal("Rename Outfitter", [this](const string &name) 99 | { 100 | if(editor.Universe().outfitSales.Find(name)) 101 | return; 102 | 103 | editor.Universe().outfitSales.Rename(object->name, name); 104 | object->name = name; 105 | SetDirty(); 106 | }); 107 | ImGui::BeginSimpleCloneModal("Clone Outfitter", [this](const string &name) 108 | { 109 | if(editor.Universe().outfitSales.Find(name)) 110 | return; 111 | 112 | auto *clone = editor.Universe().outfitSales.Get(name); 113 | *clone = *object; 114 | object = clone; 115 | 116 | object->name = name; 117 | SetDirty(); 118 | }); 119 | 120 | if(ImGui::InputCombo("outfitter", &searchBox, &object, editor.Universe().outfitSales)) 121 | searchBox.clear(); 122 | 123 | ImGui::Separator(); 124 | ImGui::Spacing(); 125 | ImGui::PushID(object); 126 | if(object) 127 | RenderOutfitter(); 128 | ImGui::PopID(); 129 | ImGui::End(); 130 | } 131 | 132 | 133 | 134 | void OutfitterEditor::RenderOutfitter() 135 | { 136 | ImGui::Text("name: %s", object->name.c_str()); 137 | int index = 0; 138 | const Outfit *toAdd = nullptr; 139 | const Outfit *toRemove = nullptr; 140 | for(auto it = object->begin(); it != object->end(); ++it) 141 | { 142 | ImGui::PushID(index++); 143 | string name = (*it)->TrueName(); 144 | Outfit *change = nullptr; 145 | if(ImGui::InputCombo("##outfit", &name, &change, editor.Universe().outfits)) 146 | { 147 | if(name.empty()) 148 | { 149 | toRemove = *it; 150 | SetDirty(); 151 | } 152 | else 153 | { 154 | toAdd = change; 155 | toRemove = *it; 156 | SetDirty(); 157 | } 158 | } 159 | ImGui::PopID(); 160 | } 161 | if(toAdd) 162 | object->insert(toAdd); 163 | if(toRemove) 164 | object->erase(toRemove); 165 | 166 | static string outfitName; 167 | static Outfit *outfit = nullptr; 168 | ImGui::Spacing(); 169 | if(ImGui::InputCombo("add outfit", &outfitName, &outfit, editor.Universe().outfits)) 170 | if(!outfitName.empty()) 171 | { 172 | object->insert(outfit); 173 | SetDirty(); 174 | outfitName.clear(); 175 | } 176 | } 177 | 178 | 179 | 180 | void OutfitterEditor::WriteToFile(DataWriter &writer, const Sale *outfitter) const 181 | { 182 | const auto *diff = editor.BaseUniverse().outfitSales.Has(outfitter->name) 183 | ? editor.BaseUniverse().outfitSales.Get(outfitter->name) 184 | : nullptr; 185 | 186 | writer.Write("outfitter", outfitter->name); 187 | writer.BeginChild(); 188 | if(diff) 189 | WriteSorted(diff->AsBase(), [](const Outfit *lhs, const Outfit *rhs) { return lhs->TrueName() < rhs->TrueName(); }, 190 | [&writer, &outfitter](const Outfit &outfit) 191 | { 192 | if(!outfitter->Has(&outfit)) 193 | writer.Write("remove", outfit.TrueName()); 194 | }); 195 | WriteSorted(outfitter->AsBase(), [](const Outfit *lhs, const Outfit *rhs) { return lhs->TrueName() < rhs->TrueName(); }, 196 | [&writer, &diff](const Outfit &outfit) 197 | { 198 | if(!diff || !diff->Has(&outfit)) 199 | writer.Write(outfit.TrueName()); 200 | }); 201 | writer.EndChild(); 202 | } 203 | -------------------------------------------------------------------------------- /overlays/sdl2/portfile.cmake: -------------------------------------------------------------------------------- 1 | vcpkg_from_github( 2 | OUT_SOURCE_PATH SOURCE_PATH 3 | REPO libsdl-org/SDL 4 | REF "release-${VERSION}" 5 | SHA512 d4ddc1abf84f09b9d2357b5bf2adc224a693767c170a6b778283c2783436d940aee4db4c9628776de28de6c499bbfb04b65f9d9210f4670525248ce5b0d31bee 6 | HEAD_REF main 7 | PATCHES 8 | deps.patch 9 | alsa-dep-fix.patch 10 | 8184.patch 11 | a94d724f17d7236e9307a02ec946997aa192778e.patch 12 | ) 13 | 14 | string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" SDL_STATIC) 15 | string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" SDL_SHARED) 16 | string(COMPARE EQUAL "${VCPKG_CRT_LINKAGE}" "static" FORCE_STATIC_VCRT) 17 | 18 | vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS 19 | FEATURES 20 | vulkan SDL_VULKAN 21 | x11 SDL_X11 22 | wayland SDL_WAYLAND 23 | samplerate SDL_LIBSAMPLERATE 24 | ibus SDL_IBUS 25 | ) 26 | 27 | if ("x11" IN_LIST FEATURES) 28 | message(WARNING "You will need to install Xorg dependencies to use feature x11:\nsudo apt install libx11-dev libxft-dev libxext-dev\n") 29 | endif() 30 | if ("wayland" IN_LIST FEATURES) 31 | message(WARNING "You will need to install Wayland dependencies to use feature wayland:\nsudo apt install libwayland-dev libxkbcommon-dev libegl1-mesa-dev\n") 32 | endif() 33 | if ("ibus" IN_LIST FEATURES) 34 | message(WARNING "You will need to install ibus dependencies to use feature ibus:\nsudo apt install libibus-1.0-dev\n") 35 | endif() 36 | 37 | if(VCPKG_TARGET_IS_UWP) 38 | set(configure_opts WINDOWS_USE_MSBUILD) 39 | endif() 40 | 41 | vcpkg_cmake_configure( 42 | SOURCE_PATH "${SOURCE_PATH}" 43 | ${configure_opts} 44 | OPTIONS ${FEATURE_OPTIONS} 45 | -DSDL_STATIC=${SDL_STATIC} 46 | -DSDL_SHARED=${SDL_SHARED} 47 | -DSDL_FORCE_STATIC_VCRT=${FORCE_STATIC_VCRT} 48 | -DSDL_LIBC=ON 49 | -DSDL_TEST=OFF 50 | -DSDL_INSTALL_CMAKEDIR="cmake" 51 | -DCMAKE_DISABLE_FIND_PACKAGE_Git=ON 52 | -DSDL_LIBSAMPLERATE_SHARED=OFF 53 | -DSDL_WAYLAND_LIBDECOR_SHARED=OFF 54 | MAYBE_UNUSED_VARIABLES 55 | SDL_FORCE_STATIC_VCRT 56 | ) 57 | 58 | vcpkg_cmake_install() 59 | vcpkg_cmake_config_fixup(CONFIG_PATH cmake) 60 | 61 | file(REMOVE_RECURSE 62 | "${CURRENT_PACKAGES_DIR}/debug/include" 63 | "${CURRENT_PACKAGES_DIR}/debug/share" 64 | "${CURRENT_PACKAGES_DIR}/bin/sdl2-config" 65 | "${CURRENT_PACKAGES_DIR}/debug/bin/sdl2-config" 66 | "${CURRENT_PACKAGES_DIR}/SDL2.framework" 67 | "${CURRENT_PACKAGES_DIR}/debug/SDL2.framework" 68 | "${CURRENT_PACKAGES_DIR}/share/licenses" 69 | "${CURRENT_PACKAGES_DIR}/share/aclocal" 70 | ) 71 | 72 | file(GLOB BINS "${CURRENT_PACKAGES_DIR}/debug/bin/*" "${CURRENT_PACKAGES_DIR}/bin/*") 73 | if(NOT BINS) 74 | file(REMOVE_RECURSE 75 | "${CURRENT_PACKAGES_DIR}/bin" 76 | "${CURRENT_PACKAGES_DIR}/debug/bin" 77 | ) 78 | endif() 79 | 80 | if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_UWP AND NOT VCPKG_TARGET_IS_MINGW) 81 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") 82 | file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib/manual-link") 83 | file(RENAME "${CURRENT_PACKAGES_DIR}/lib/SDL2main.lib" "${CURRENT_PACKAGES_DIR}/lib/manual-link/SDL2main.lib") 84 | endif() 85 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") 86 | file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link") 87 | file(RENAME "${CURRENT_PACKAGES_DIR}/debug/lib/SDL2maind.lib" "${CURRENT_PACKAGES_DIR}/debug/lib/manual-link/SDL2maind.lib") 88 | endif() 89 | 90 | file(GLOB SHARE_FILES "${CURRENT_PACKAGES_DIR}/share/sdl2/*.cmake") 91 | foreach(SHARE_FILE ${SHARE_FILES}) 92 | vcpkg_replace_string("${SHARE_FILE}" "lib/SDL2main" "lib/manual-link/SDL2main") 93 | endforeach() 94 | endif() 95 | 96 | vcpkg_copy_pdbs() 97 | 98 | set(DYLIB_COMPATIBILITY_VERSION_REGEX "set\\(DYLIB_COMPATIBILITY_VERSION (.+)\\)") 99 | set(DYLIB_CURRENT_VERSION_REGEX "set\\(DYLIB_CURRENT_VERSION (.+)\\)") 100 | file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_COMPATIBILITY_VERSION REGEX ${DYLIB_COMPATIBILITY_VERSION_REGEX}) 101 | file(STRINGS "${SOURCE_PATH}/CMakeLists.txt" DYLIB_CURRENT_VERSION REGEX ${DYLIB_CURRENT_VERSION_REGEX}) 102 | string(REGEX REPLACE ${DYLIB_COMPATIBILITY_VERSION_REGEX} "\\1" DYLIB_COMPATIBILITY_VERSION "${DYLIB_COMPATIBILITY_VERSION}") 103 | string(REGEX REPLACE ${DYLIB_CURRENT_VERSION_REGEX} "\\1" DYLIB_CURRENT_VERSION "${DYLIB_CURRENT_VERSION}") 104 | 105 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") 106 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2main" "-lSDL2maind") 107 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2 " "-lSDL2d ") 108 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-static " "-lSDL2-staticd ") 109 | endif() 110 | 111 | if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic" AND VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW) 112 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") 113 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-lSDL2-static " " ") 114 | endif() 115 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") 116 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-lSDL2-staticd " " ") 117 | endif() 118 | endif() 119 | 120 | if(VCPKG_TARGET_IS_UWP) 121 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") 122 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "$<$:d>.lib" "") 123 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:") 124 | endif() 125 | if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") 126 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "$<$:d>.lib" "d") 127 | vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/sdl2.pc" "-l-nodefaultlib:" "-nodefaultlib:") 128 | endif() 129 | endif() 130 | 131 | vcpkg_fixup_pkgconfig() 132 | 133 | file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") 134 | vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.txt") 135 | -------------------------------------------------------------------------------- /source/EditorPlugin.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "EditorPlugin.h" 4 | 5 | #include "DataFile.h" 6 | #include "DataWriter.h" 7 | #include "Editor.h" 8 | #include "Files.h" 9 | #include "TemplateEditor.h" 10 | 11 | using namespace std; 12 | 13 | namespace { 14 | 15 | template 16 | auto &GetEditorForNodeElement(const Editor &editor) 17 | { 18 | if constexpr(std::is_same_v) 19 | return editor.effectEditor; 20 | else if constexpr(std::is_same_v) 21 | return editor.fleetEditor; 22 | else if constexpr(std::is_same_v) 23 | return editor.galaxyEditor; 24 | else if constexpr(std::is_same_v) 25 | return editor.hazardEditor; 26 | else if constexpr(std::is_same_v) 27 | return editor.governmentEditor; 28 | else if constexpr(std::is_same_v) 29 | return editor.outfitEditor; 30 | else if constexpr(std::is_same_v *>) 31 | return editor.outfitterEditor; 32 | else if constexpr(std::is_same_v) 33 | return editor.planetEditor; 34 | else if constexpr(std::is_same_v) 35 | return editor.shipEditor; 36 | else if constexpr(std::is_same_v *>) 37 | return editor.shipyardEditor; 38 | else if constexpr(std::is_same_v) 39 | return editor.systemEditor; 40 | else 41 | assert(!"no editor for T"); 42 | } 43 | 44 | } 45 | 46 | 47 | void EditorPlugin::Load(const Editor &editor, string_view path) 48 | { 49 | data.clear(); 50 | unknownNodes.clear(); 51 | filesChanged.clear(); 52 | hasModifications = false; 53 | 54 | // We assume that path refers to a valid path to the root of the plugin. 55 | auto files = Files::RecursiveList(string(path)); 56 | for(const auto &file : files) 57 | { 58 | const auto filename = file.substr(path.size()); 59 | for(auto &node : DataFile(file)) 60 | { 61 | const string &key = node.Token(0); 62 | if(node.Size() < 2) 63 | continue; 64 | const auto &value = node.Token(1); 65 | 66 | if(key == "effect") 67 | data[filename].emplace_back(effects.emplace(editor.Universe().effects.Get(value), filename).first->first); 68 | else if(key == "fleet") 69 | data[filename].emplace_back(fleets.emplace(editor.Universe().fleets.Get(value), filename).first->first); 70 | else if(key == "galaxy") 71 | data[filename].emplace_back(galaxies.emplace(editor.Universe().galaxies.Get(value), filename).first->first); 72 | else if(key == "hazard") 73 | data[filename].emplace_back(hazards.emplace(editor.Universe().hazards.Get(value), filename).first->first); 74 | else if(key == "government") 75 | data[filename].emplace_back(governments.emplace(editor.Universe().governments.Get(value), filename).first->first); 76 | else if(key == "outfit") 77 | data[filename].emplace_back(outfits.emplace(editor.Universe().outfits.Get(value), filename).first->first); 78 | else if(key == "outfitter") 79 | data[filename].emplace_back(outfitters.emplace(editor.Universe().outfitSales.Get(value), filename).first->first); 80 | else if(key == "planet") 81 | data[filename].emplace_back(planets.emplace(editor.Universe().planets.Get(value), filename).first->first); 82 | else if(key == "ship") 83 | data[filename].emplace_back(ships.emplace(editor.Universe().ships.Get(value), filename).first->first); 84 | else if(key == "shipyard") 85 | data[filename].emplace_back(shipyards.emplace(editor.Universe().shipSales.Get(value), filename).first->first); 86 | else if(key == "system") 87 | data[filename].emplace_back(systems.emplace(editor.Universe().systems.Get(value), filename).first->first); 88 | else 89 | { 90 | unknownNodes.emplace_back(std::move(node)); 91 | data[filename].emplace_back(&unknownNodes.back()); 92 | } 93 | } 94 | } 95 | } 96 | 97 | 98 | 99 | void EditorPlugin::Save(const Editor &editor, string_view path) 100 | { 101 | for(const auto &[file, objects] : data) 102 | { 103 | // Skip files that haven't been modified by this plugin editor. 104 | if(!filesChanged.count(file)) 105 | continue; 106 | 107 | DataWriter writer(string(path) + file); 108 | for(const auto &object : objects) 109 | { 110 | std::visit([this, &writer, &editor](const auto *ptr) 111 | { 112 | if constexpr(std::is_same_v) 113 | writer.Write(*ptr); 114 | else 115 | { 116 | const auto &map = GetMapForNodeElement(); 117 | if(map.count(ptr)) 118 | GetEditorForNodeElement(editor).WriteToFile(writer, ptr); 119 | } 120 | }, object); 121 | 122 | writer.Write(); 123 | } 124 | } 125 | hasModifications = false; 126 | } 127 | 128 | 129 | 130 | bool EditorPlugin::HasChanges() const 131 | { 132 | return hasModifications; 133 | } 134 | 135 | 136 | 137 | void EditorPlugin::Add(Node node) 138 | { 139 | hasModifications = true; 140 | 141 | // If the modified node is already present, we don't need to add it. 142 | if(std::visit([this](const auto *ptr) 143 | { 144 | if constexpr(!std::is_same_v) 145 | { 146 | const auto &map = GetMapForNodeElement(); 147 | auto it = map.find(ptr); 148 | if(it != map.end()) 149 | { 150 | // But we do need to save that we have touch a node in this file. 151 | filesChanged.insert(it->second); 152 | return true; 153 | } 154 | } 155 | else 156 | assert(!"can't add a DataNode"); 157 | 158 | return false; 159 | }, node)) 160 | return; 161 | 162 | string file; 163 | std::visit([this, &file](const auto *ptr) 164 | { 165 | if constexpr(!std::is_same_v) 166 | { 167 | file = defaultFileFor>>(); 168 | GetMapForNodeElement().emplace(ptr, file); 169 | } 170 | else 171 | assert(!"can't add a DataNode"); 172 | }, node); 173 | 174 | data[file].emplace_back(std::move(node)); 175 | filesChanged.insert(file); 176 | } 177 | 178 | 179 | 180 | bool EditorPlugin::Has(const Node &node) const 181 | { 182 | return std::visit([this](const auto *ptr) 183 | { 184 | return GetMapForNodeElement().count(ptr); 185 | }, node); 186 | } 187 | 188 | 189 | 190 | void EditorPlugin::Remove(const Node &node) 191 | { 192 | hasModifications = true; 193 | std::visit([this](const auto *ptr) 194 | { 195 | GetMapForNodeElement().erase(ptr); 196 | }, node); 197 | } 198 | -------------------------------------------------------------------------------- /source/EffectEditor.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "EffectEditor.h" 4 | 5 | #include "DataFile.h" 6 | #include "DataNode.h" 7 | #include "DataWriter.h" 8 | #include "Dialog.h" 9 | #include "imgui.h" 10 | #include "imgui_ex.h" 11 | #include "imgui_internal.h" 12 | #include "imgui_stdlib.h" 13 | #include "Editor.h" 14 | #include "Effect.h" 15 | #include "Engine.h" 16 | #include "Files.h" 17 | #include "Government.h" 18 | #include "Hazard.h" 19 | #include "MainPanel.h" 20 | #include "MapPanel.h" 21 | #include "Minable.h" 22 | #include "Planet.h" 23 | #include "PlayerInfo.h" 24 | #include "Ship.h" 25 | #include "Sound.h" 26 | #include "SpriteSet.h" 27 | #include "Sprite.h" 28 | #include "System.h" 29 | #include "UI.h" 30 | 31 | #include 32 | #include 33 | 34 | using namespace std; 35 | 36 | 37 | 38 | EffectEditor::EffectEditor(Editor &editor, bool &show) noexcept 39 | : TemplateEditor(editor, show) 40 | { 41 | } 42 | 43 | 44 | 45 | void EffectEditor::Render() 46 | { 47 | ImGui::SetNextWindowSize(ImVec2(550, 500), ImGuiCond_FirstUseEver); 48 | if(!ImGui::Begin("Effect Editor", &show, ImGuiWindowFlags_MenuBar)) 49 | { 50 | ImGui::End(); 51 | return; 52 | } 53 | 54 | bool showNewEffect = false; 55 | bool showRenameEffect = false; 56 | bool showCloneEffect = false; 57 | if(ImGui::BeginMenuBar()) 58 | { 59 | if(ImGui::BeginMenu("Effect")) 60 | { 61 | const bool alreadyDefined = object && !editor.BaseUniverse().effects.Has(object->name); 62 | ImGui::MenuItem("New", nullptr, &showNewEffect); 63 | ImGui::MenuItem("Rename", nullptr, &showRenameEffect, alreadyDefined); 64 | ImGui::MenuItem("Clone", nullptr, &showCloneEffect, object); 65 | if(ImGui::MenuItem("Reset", nullptr, false, alreadyDefined && editor.GetPlugin().Has(object))) 66 | { 67 | editor.GetPlugin().Remove(object); 68 | *object = *editor.BaseUniverse().effects.Get(object->name); 69 | } 70 | if(ImGui::MenuItem("Delete", nullptr, false, alreadyDefined)) 71 | { 72 | editor.GetPlugin().Remove(object); 73 | editor.Universe().effects.Erase(object->name); 74 | object = nullptr; 75 | } 76 | ImGui::EndMenu(); 77 | } 78 | ImGui::EndMenuBar(); 79 | } 80 | 81 | if(showNewEffect) 82 | ImGui::OpenPopup("New Effect"); 83 | if(showRenameEffect) 84 | ImGui::OpenPopup("Rename Effect"); 85 | if(showCloneEffect) 86 | ImGui::OpenPopup("Clone Effect"); 87 | ImGui::BeginSimpleNewModal("New Effect", [this](const string &name) 88 | { 89 | if(editor.Universe().effects.Find(name)) 90 | return; 91 | 92 | auto *newEffect = editor.Universe().effects.Get(name); 93 | newEffect->name = name; 94 | object = newEffect; 95 | SetDirty(); 96 | }); 97 | ImGui::BeginSimpleRenameModal("Rename Effect", [this](const string &name) 98 | { 99 | if(editor.Universe().effects.Find(name)) 100 | return; 101 | 102 | editor.Universe().effects.Rename(object->name, name); 103 | object->name = name; 104 | SetDirty(); 105 | }); 106 | ImGui::BeginSimpleCloneModal("Clone Effect", [this](const string &name) 107 | { 108 | if(editor.Universe().effects.Find(name)) 109 | return; 110 | 111 | auto *clone = editor.Universe().effects.Get(name); 112 | *clone = *object; 113 | object = clone; 114 | 115 | object->name = name; 116 | SetDirty(); 117 | }); 118 | 119 | if(ImGui::InputCombo("effect", &searchBox, &object, editor.Universe().effects)) 120 | searchBox.clear(); 121 | 122 | ImGui::Separator(); 123 | ImGui::Spacing(); 124 | ImGui::PushID(object); 125 | if(object) 126 | RenderEffect(); 127 | ImGui::PopID(); 128 | ImGui::End(); 129 | } 130 | 131 | 132 | 133 | void EffectEditor::RenderEffect() 134 | { 135 | ImGui::Text("effect: %s", object->name.c_str()); 136 | RenderElement(object, "sprite"); 137 | 138 | string soundName = object->sound ? object->sound->Name() : ""; 139 | if(ImGui::InputCombo("sound", &soundName, &object->sound, editor.Sounds())) 140 | SetDirty(); 141 | 142 | if(ImGui::InputInt("lifetime", &object->lifetime)) 143 | SetDirty(); 144 | if(ImGui::InputInt("random lifetime", &object->randomLifetime)) 145 | SetDirty(); 146 | if(ImGui::InputDoubleEx("velocity scale", &object->velocityScale)) 147 | SetDirty(); 148 | if(ImGui::InputDoubleEx("random velocity", &object->randomVelocity)) 149 | SetDirty(); 150 | if(ImGui::InputDoubleEx("random angle", &object->randomAngle)) 151 | SetDirty(); 152 | if(ImGui::InputDoubleEx("random spin", &object->randomSpin)) 153 | SetDirty(); 154 | if(ImGui::InputDoubleEx("random frame rate", &object->randomFrameRate)) 155 | SetDirty(); 156 | } 157 | 158 | 159 | 160 | void EffectEditor::WriteToFile(DataWriter &writer, const Effect *effect) const 161 | { 162 | const auto *diff = editor.BaseUniverse().effects.Has(effect->name) 163 | ? editor.BaseUniverse().effects.Get(effect->name) 164 | : nullptr; 165 | 166 | writer.Write("effect", effect->name); 167 | writer.BeginChild(); 168 | 169 | if(!diff || effect->sprite != diff->sprite) 170 | if(effect->HasSprite()) 171 | { 172 | writer.Write("sprite", effect->GetSprite()->Name()); 173 | writer.BeginChild(); 174 | if(effect->scale != 1.f) 175 | writer.Write("scale", effect->scale); 176 | if(effect->frameRate != 2.f / 60.f) 177 | writer.Write("frame rate", effect->frameRate * 60.f); 178 | if(effect->delay) 179 | writer.Write("delay", effect->delay); 180 | if(effect->randomize) 181 | writer.Write("random start frame"); 182 | if(!effect->repeat) 183 | writer.Write("no repeat"); 184 | if(effect->rewind) 185 | writer.Write("rewind"); 186 | writer.EndChild(); 187 | } 188 | 189 | if(!diff || effect->sound != diff->sound) 190 | if(effect->sound) 191 | writer.Write("sound", effect->sound->Name()); 192 | if(!diff || effect->lifetime != diff->lifetime) 193 | if(effect->lifetime || diff) 194 | writer.Write("lifetime", effect->lifetime); 195 | if(!diff || effect->randomLifetime != diff->randomLifetime) 196 | if(effect->randomLifetime || diff) 197 | writer.Write("random lifetime", effect->randomLifetime); 198 | if(!diff || effect->velocityScale != diff->velocityScale) 199 | if(effect->velocityScale != 1. || diff) 200 | writer.Write("velocity scale", effect->velocityScale); 201 | if(!diff || effect->randomAngle != diff->randomAngle) 202 | if(effect->randomAngle || diff) 203 | writer.Write("random angle", effect->randomAngle); 204 | if(!diff || effect->randomVelocity != diff->randomVelocity) 205 | if(effect->randomVelocity || diff) 206 | writer.Write("random velocity", effect->randomVelocity); 207 | if(!diff || effect->randomSpin != diff->randomSpin) 208 | if(effect->randomSpin || diff) 209 | writer.Write("random spin", effect->randomSpin); 210 | if(!diff || effect->randomFrameRate != diff->randomFrameRate) 211 | if(effect->randomFrameRate || diff) 212 | writer.Write("random frame rate", effect->randomFrameRate); 213 | writer.EndChild(); 214 | } 215 | -------------------------------------------------------------------------------- /source/imgui_ex.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef IMGUI_EX_H_ 4 | #define IMGUI_EX_H_ 5 | 6 | #define IMGUI_DEFINE_MATH_OPERATORS 7 | 8 | #include "Set.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | 24 | namespace ImGui 25 | { 26 | IMGUI_API bool InputDoubleEx(const char *label, double *v, ImGuiInputTextFlags flags = 0); 27 | IMGUI_API bool InputFloatEx(const char *label, float *v, ImGuiInputTextFlags flags = 0); 28 | IMGUI_API bool InputDouble2Ex(const char *label, double *v, ImGuiInputTextFlags flags = 0); 29 | IMGUI_API bool InputInt64Ex(const char *label, int64_t *v, ImGuiInputTextFlags flags = 0); 30 | IMGUI_API bool InputSizeTEx(const char *label, size_t *v, ImGuiInputTextFlags flags = 0); 31 | IMGUI_API bool IsInputFocused(const char *id); 32 | 33 | template 34 | IMGUI_API bool InputCombo(const char *label, std::string *input, T **element, const Set &elements, std::function sort = {}); 35 | template 36 | IMGUI_API bool InputCombo(const char *label, std::string *input, const T **element, const Set &elements, std::function sort = {}); 37 | 38 | IMGUI_API bool InputSwizzle(const char *label, int *swizzle, bool allowNoSwizzle = false); 39 | 40 | template 41 | IMGUI_API void BeginSimpleModal(const char *id, const char *label, const char *button, F &&f); 42 | template 43 | IMGUI_API void BeginSimpleNewModal(const char *id, F &&f); 44 | template 45 | IMGUI_API void BeginSimpleRenameModal(const char *id, F &&f); 46 | template 47 | IMGUI_API void BeginSimpleCloneModal(const char *id, F &&f); 48 | } 49 | 50 | 51 | 52 | 53 | template 54 | bool IsValid(const T &obj, ...) 55 | { 56 | return !obj.Name().empty(); 57 | } 58 | template 59 | bool IsValid(const T &obj, decltype(obj.TrueName(), void()) *) 60 | { 61 | return !obj.TrueName().empty(); 62 | } 63 | 64 | 65 | 66 | template 67 | IMGUI_API bool ImGui::InputCombo(const char *label, std::string *input, T **element, const Set &elements, std::function sort) 68 | { 69 | ImGuiWindow *window = GetCurrentWindow(); 70 | const auto callback = [](ImGuiInputTextCallbackData *data) 71 | { 72 | bool &autocomplete = *reinterpret_cast(data->UserData); 73 | switch(data->EventFlag) 74 | { 75 | case ImGuiInputTextFlags_CallbackCompletion: 76 | autocomplete = true; 77 | break; 78 | } 79 | 80 | return 0; 81 | }; 82 | 83 | const auto id = ImHashStr("##combo/popup", 0, window->GetID(label)); 84 | bool autocomplete = false; 85 | bool enter = false; 86 | if(InputText(label, input, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion, callback, &autocomplete)) 87 | { 88 | SetActiveID(0, FindWindowByID(id)); 89 | enter = true; 90 | } 91 | 92 | bool isOpen = IsPopupOpen(id, ImGuiPopupFlags_None); 93 | if(IsItemActive() && !isOpen) 94 | { 95 | OpenPopupEx(id, ImGuiPopupFlags_None); 96 | isOpen = true; 97 | } 98 | 99 | if(!isOpen) 100 | return false; 101 | if(autocomplete && input->empty()) 102 | autocomplete = false; 103 | 104 | const ImRect bb(window->DC.CursorPos, 105 | window->DC.CursorPos + ImVec2(CalcItemWidth(), 0.f)); 106 | 107 | bool changed = false; 108 | if(BeginComboPopup(id, bb, ImGuiComboFlags_None, ImGuiWindowFlags_NoFocusOnAppearing)) 109 | { 110 | if(IsWindowAppearing()) 111 | BringWindowToDisplayFront(GetCurrentWindow()); 112 | if(enter) 113 | { 114 | *element = elements.Find(*input) ? const_cast(elements.Get(*input)) : nullptr; 115 | CloseCurrentPopup(); 116 | EndCombo(); 117 | return true; 118 | } 119 | 120 | std::vector> weights; 121 | 122 | // Filter the possible values using the provider filter function (if available) 123 | // and perform a fuzzy search on the input to further limit the list. 124 | if(!input->empty()) 125 | { 126 | rapidfuzz::fuzz::CachedPartialRatio scorer(*input); 127 | const double scoreCutoff = .75; 128 | for(const auto &it : elements) 129 | { 130 | if(!IsValid(it.second, 0) || (sort && !sort(it.first))) 131 | continue; 132 | 133 | const double score = scorer.similarity(it.first, scoreCutoff); 134 | if(score > scoreCutoff) 135 | weights.emplace_back(score, it.first.c_str()); 136 | } 137 | 138 | std::sort(weights.begin(), weights.end(), 139 | [](const auto &lhs, const auto &rhs) 140 | { 141 | if(lhs.first == rhs.first) 142 | return std::strcmp(lhs.second, rhs.second) < 0; 143 | return lhs.first > rhs.first; 144 | }); 145 | } 146 | else 147 | { 148 | // If no input is provided sort the list by alphabetical order instead. 149 | for(const auto &it : elements) 150 | if(IsValid(it.second, 0) && (!sort || sort(it.first))) 151 | weights.emplace_back(0., it.first.c_str()); 152 | std::sort(weights.begin(), weights.end(), 153 | [](const auto &lhs, const auto &rhs) 154 | { return std::strcmp(lhs.second, rhs.second) < 0; }); 155 | } 156 | 157 | if(!weights.empty()) 158 | { 159 | auto topWeight = weights[0].first; 160 | for(const auto &item : weights) 161 | { 162 | // Allow the user to select an entry in the combo box. 163 | // This is a hack to workaround the fact that we change the focus when clicking an 164 | // entry and that this means that the filtered list will change (breaking entries). 165 | if(GetActiveID() == GetCurrentWindow()->GetID(item.second) || GetFocusID() == GetCurrentWindow()->GetID(item.second)) 166 | { 167 | *element = const_cast(elements.Get(item.second)); 168 | changed = true; 169 | *input = item.second; 170 | CloseCurrentPopup(); 171 | SetActiveID(0, GetCurrentWindow()); 172 | } 173 | 174 | if(topWeight && item.first < topWeight * .45) 175 | continue; 176 | 177 | if(Selectable(item.second) || autocomplete) 178 | { 179 | *element = const_cast(elements.Get(item.second)); 180 | changed = true; 181 | *input = item.second; 182 | if(autocomplete) 183 | { 184 | autocomplete = false; 185 | CloseCurrentPopup(); 186 | SetActiveID(0, GetCurrentWindow()); 187 | } 188 | } 189 | } 190 | } 191 | EndCombo(); 192 | } 193 | 194 | return changed; 195 | } 196 | 197 | 198 | template 199 | IMGUI_API bool ImGui::InputCombo(const char *label, std::string *input, const T **element, const Set &elements, std::function sort) 200 | { 201 | return InputCombo(label, input, const_cast(element), elements, sort); 202 | } 203 | 204 | 205 | 206 | template 207 | IMGUI_API void ImGui::BeginSimpleModal(const char *id, const char *label, const char *button, F &&f) 208 | { 209 | if(BeginPopupModal(id, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) 210 | { 211 | if(IsWindowAppearing()) 212 | SetKeyboardFocusHere(); 213 | static std::string name; 214 | bool create = InputText(label, &name, ImGuiInputTextFlags_EnterReturnsTrue); 215 | if(Button("Cancel")) 216 | { 217 | CloseCurrentPopup(); 218 | name.clear(); 219 | } 220 | SameLine(); 221 | if(name.empty()) 222 | BeginDisabled(); 223 | if((Button(button) || create) && !name.empty()) 224 | { 225 | std::forward(f)(name); 226 | CloseCurrentPopup(); 227 | name.clear(); 228 | } 229 | else if(name.empty()) 230 | EndDisabled(); 231 | EndPopup(); 232 | } 233 | } 234 | 235 | 236 | 237 | template 238 | IMGUI_API void ImGui::BeginSimpleNewModal(const char *id, F &&f) 239 | { 240 | return BeginSimpleModal(id, "new name", "Create", std::forward(f)); 241 | } 242 | 243 | 244 | 245 | template 246 | IMGUI_API void ImGui::BeginSimpleRenameModal(const char *id, F &&f) 247 | { 248 | return BeginSimpleModal(id, "new name", "Rename", std::forward(f)); 249 | } 250 | 251 | 252 | 253 | template 254 | IMGUI_API void ImGui::BeginSimpleCloneModal(const char *id, F &&f) 255 | { 256 | return BeginSimpleModal(id, "clone name", "Clone", std::forward(f)); 257 | } 258 | 259 | 260 | 261 | #endif 262 | -------------------------------------------------------------------------------- /overlays/imgui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(imgui CXX) 3 | 4 | set(CMAKE_DEBUG_POSTFIX d) 5 | 6 | if(APPLE) 7 | set(CMAKE_CXX_STANDARD 11) 8 | enable_language(OBJCXX) 9 | endif() 10 | 11 | add_library(${PROJECT_NAME} "") 12 | add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 13 | target_include_directories( 14 | ${PROJECT_NAME} 15 | PUBLIC 16 | $ 17 | $ 18 | ) 19 | 20 | target_sources( 21 | ${PROJECT_NAME} 22 | PRIVATE 23 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui.cpp 24 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui_demo.cpp 25 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui_draw.cpp 26 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui_tables.cpp 27 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui_widgets.cpp 28 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp 29 | ) 30 | 31 | target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) 32 | 33 | if(IMGUI_BUILD_ALLEGRO5_BINDING) 34 | find_path(ALLEGRO5_INCLUDE_DIRS allegro5/allegro.h) 35 | target_include_directories(${PROJECT_NAME} PRIVATE ${ALLEGRO5_INCLUDE_DIRS}) 36 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_allegro5.cpp) 37 | endif() 38 | 39 | if(IMGUI_BUILD_DX9_BINDING) 40 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx9.cpp) 41 | endif() 42 | 43 | if(IMGUI_BUILD_DX10_BINDING) 44 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx10.cpp) 45 | endif() 46 | 47 | if(IMGUI_BUILD_DX11_BINDING) 48 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx11.cpp) 49 | endif() 50 | 51 | if(IMGUI_BUILD_DX12_BINDING) 52 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx12.cpp) 53 | endif() 54 | 55 | if(IMGUI_BUILD_GLFW_BINDING) 56 | find_package(glfw3 CONFIG REQUIRED) 57 | target_link_libraries(${PROJECT_NAME} PUBLIC glfw) 58 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glfw.cpp) 59 | endif() 60 | 61 | if(IMGUI_BUILD_GLUT_BINDING) 62 | find_package(GLUT REQUIRED) 63 | target_link_libraries(${PROJECT_NAME} PUBLIC GLUT::GLUT) 64 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glut.cpp) 65 | endif() 66 | 67 | if(IMGUI_BUILD_METAL_BINDING) 68 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_metal.mm) 69 | set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_metal.mm PROPERTIES COMPILE_FLAGS -fobjc-weak) 70 | endif() 71 | 72 | if(IMGUI_BUILD_OPENGL2_BINDING) 73 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl2.cpp) 74 | endif() 75 | 76 | if(IMGUI_BUILD_OPENGL3_BINDING) 77 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp) 78 | endif() 79 | 80 | if(IMGUI_BUILD_OSX_BINDING) 81 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_osx.mm) 82 | endif() 83 | 84 | if(IMGUI_BUILD_SDL2_BINDING) 85 | find_package(SDL2 CONFIG REQUIRED) 86 | target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2) 87 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdl.cpp) 88 | endif() 89 | 90 | if(IMGUI_BUILD_SDL2_RENDERER_BINDING) 91 | find_package(SDL2 CONFIG REQUIRED) 92 | target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2) 93 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdlrenderer.cpp) 94 | endif() 95 | 96 | if(IMGUI_BUILD_VULKAN_BINDING) 97 | find_package(Vulkan REQUIRED) 98 | target_link_libraries(${PROJECT_NAME} PUBLIC Vulkan::Vulkan) 99 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_vulkan.cpp) 100 | endif() 101 | 102 | if(IMGUI_BUILD_WIN32_BINDING) 103 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_win32.cpp) 104 | endif() 105 | 106 | if(IMGUI_FREETYPE) 107 | find_package(freetype CONFIG REQUIRED) 108 | target_link_libraries(${PROJECT_NAME} PUBLIC freetype) 109 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp) 110 | target_compile_definitions(${PROJECT_NAME} PUBLIC IMGUI_ENABLE_FREETYPE) 111 | endif() 112 | 113 | if(IMGUI_USE_WCHAR32) 114 | target_compile_definitions(${PROJECT_NAME} PUBLIC IMGUI_USE_WCHAR32) 115 | endif() 116 | 117 | list(REMOVE_DUPLICATES BINDINGS_SOURCES) 118 | 119 | install( 120 | TARGETS ${PROJECT_NAME} 121 | EXPORT ${PROJECT_NAME}_target 122 | ARCHIVE DESTINATION lib 123 | LIBRARY DESTINATION lib 124 | RUNTIME DESTINATION bin 125 | ) 126 | 127 | foreach(BINDING_TARGET ${BINDING_TARGETS}) 128 | install( 129 | TARGETS ${BINDING_TARGET} 130 | EXPORT ${PROJECT_NAME}_target 131 | ARCHIVE DESTINATION lib 132 | LIBRARY DESTINATION lib 133 | RUNTIME DESTINATION bin 134 | ) 135 | endforeach() 136 | 137 | if(NOT IMGUI_SKIP_HEADERS) 138 | install(FILES 139 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui.h 140 | ${CMAKE_CURRENT_SOURCE_DIR}/imconfig.h 141 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui_internal.h 142 | ${CMAKE_CURRENT_SOURCE_DIR}/imstb_textedit.h 143 | ${CMAKE_CURRENT_SOURCE_DIR}/imstb_rectpack.h 144 | ${CMAKE_CURRENT_SOURCE_DIR}/imstb_truetype.h 145 | ${CMAKE_CURRENT_SOURCE_DIR}/misc/cpp/imgui_stdlib.h 146 | DESTINATION include 147 | ) 148 | 149 | if(IMGUI_BUILD_ALLEGRO5_BINDING) 150 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_allegro5.h DESTINATION include) 151 | endif() 152 | 153 | if(IMGUI_BUILD_DX9_BINDING) 154 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx9.h DESTINATION include) 155 | endif() 156 | 157 | if(IMGUI_BUILD_DX10_BINDING) 158 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx10.h DESTINATION include) 159 | endif() 160 | 161 | if(IMGUI_BUILD_DX11_BINDING) 162 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx11.h DESTINATION include) 163 | endif() 164 | 165 | if(IMGUI_BUILD_DX12_BINDING) 166 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx12.h DESTINATION include) 167 | endif() 168 | 169 | if(IMGUI_BUILD_GLFW_BINDING) 170 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glfw.h DESTINATION include) 171 | endif() 172 | 173 | if(IMGUI_BUILD_GLUT_BINDING) 174 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glut.h DESTINATION include) 175 | endif() 176 | 177 | if(IMGUI_BUILD_METAL_BINDING) 178 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_metal.h DESTINATION include) 179 | endif() 180 | 181 | if(IMGUI_BUILD_OPENGL2_BINDING) 182 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl2.h DESTINATION include) 183 | endif() 184 | 185 | if(IMGUI_BUILD_OPENGL3_BINDING) 186 | install( 187 | FILES 188 | ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl3.h 189 | ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl3_loader.h 190 | DESTINATION 191 | include 192 | ) 193 | endif() 194 | 195 | if(IMGUI_BUILD_OSX_BINDING) 196 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_osx.h DESTINATION include) 197 | endif() 198 | 199 | if(IMGUI_BUILD_SDL2_BINDING) 200 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdl.h DESTINATION include) 201 | endif() 202 | 203 | if(IMGUI_BUILD_SDL2_RENDERER_BINDING) 204 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdlrenderer.h DESTINATION include) 205 | endif() 206 | 207 | if(IMGUI_BUILD_VULKAN_BINDING) 208 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_vulkan.h DESTINATION include) 209 | endif() 210 | 211 | if(IMGUI_BUILD_WIN32_BINDING) 212 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_win32.h DESTINATION include) 213 | endif() 214 | 215 | if(IMGUI_FREETYPE) 216 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/misc/freetype/imgui_freetype.h DESTINATION include) 217 | endif() 218 | endif() 219 | 220 | include(CMakePackageConfigHelpers) 221 | configure_package_config_file(imgui-config.cmake.in imgui-config.cmake INSTALL_DESTINATION share/imgui) 222 | 223 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/imgui-config.cmake DESTINATION share/imgui) 224 | 225 | install( 226 | EXPORT ${PROJECT_NAME}_target 227 | NAMESPACE ${PROJECT_NAME}:: 228 | FILE ${PROJECT_NAME}-targets.cmake 229 | DESTINATION share/${PROJECT_NAME} 230 | ) 231 | -------------------------------------------------------------------------------- /source/TemplateEditor.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "TemplateEditor.h" 4 | 5 | #include "Body.h" 6 | #include "DataWriter.h" 7 | #include "Editor.h" 8 | #include "Effect.h" 9 | #include "Fleet.h" 10 | #include "GameData.h" 11 | #include "Minable.h" 12 | #include "RandomEvent.h" 13 | #include "Sound.h" 14 | #include "Sprite.h" 15 | #include "System.h" 16 | #include "WeightedList.h" 17 | #include "imgui.h" 18 | #include "imgui_ex.h" 19 | #include "imgui_stdlib.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using namespace std; 30 | 31 | 32 | template 33 | void TemplateEditor::Clear() 34 | { 35 | searchBox.clear(); 36 | object = nullptr; 37 | } 38 | 39 | 40 | 41 | template 42 | void TemplateEditor::SetDirty() 43 | { 44 | editor.GetPlugin().Add(object); 45 | } 46 | 47 | 48 | 49 | template 50 | void TemplateEditor::SetDirty(const T *obj) 51 | { 52 | editor.GetPlugin().Add(obj); 53 | } 54 | 55 | 56 | 57 | template 58 | void TemplateEditor::RenderSprites(const std::string &name, std::vector> &map) 59 | { 60 | auto found = map.end(); 61 | int index = 0; 62 | ImGui::PushID(name.c_str()); 63 | for(auto it = map.begin(); it != map.end(); ++it) 64 | { 65 | ImGui::PushID(index++); 66 | if(RenderElement(&it->first, name)) 67 | found = it; 68 | ImGui::PopID(); 69 | } 70 | ImGui::PopID(); 71 | 72 | if(found != map.end()) 73 | { 74 | map.erase(found); 75 | SetDirty(); 76 | } 77 | } 78 | 79 | 80 | 81 | template 82 | bool TemplateEditor::RenderElement(Body *sprite, const std::string &name, const function &spriteFilter) 83 | { 84 | static std::string spriteName; 85 | spriteName.clear(); 86 | bool open = ImGui::TreeNode(name.c_str(), "%s: %s", name.c_str(), sprite->GetSprite() ? sprite->GetSprite()->Name().c_str() : ""); 87 | bool value = false; 88 | if(ImGui::BeginPopupContextItem()) 89 | { 90 | if(ImGui::Selectable("Remove")) 91 | value = true; 92 | ImGui::EndPopup(); 93 | } 94 | 95 | if(open) 96 | { 97 | if(sprite->GetSprite()) 98 | spriteName = sprite->GetSprite()->Name(); 99 | if(ImGui::InputCombo("sprite", &spriteName, &sprite->sprite, editor.Sprites(), spriteFilter)) 100 | SetDirty(); 101 | 102 | if(ImGui::InputFloatEx("scale", &sprite->scale)) 103 | SetDirty(); 104 | 105 | double value = sprite->frameRate * 60.; 106 | if(ImGui::InputDoubleEx("frame rate", &value)) 107 | { 108 | if(value) 109 | sprite->frameRate = value / 60.; 110 | SetDirty(); 111 | } 112 | 113 | if(ImGui::InputInt("delay", &sprite->delay)) 114 | SetDirty(); 115 | if(ImGui::Checkbox("random start frame", &sprite->randomize)) 116 | SetDirty(); 117 | bool bvalue = !sprite->repeat; 118 | if(ImGui::Checkbox("no repeat", &bvalue)) 119 | SetDirty(); 120 | sprite->repeat = !bvalue; 121 | if(ImGui::Checkbox("rewind", &sprite->rewind)) 122 | SetDirty(); 123 | ImGui::TreePop(); 124 | } 125 | 126 | return value; 127 | } 128 | 129 | 130 | 131 | template 132 | void TemplateEditor::RenderSound(const std::string &name, std::map &map) 133 | { 134 | static std::string soundName; 135 | soundName.clear(); 136 | 137 | if(ImGui::TreeNode(name.c_str())) 138 | { 139 | const Sound *toAdd = nullptr; 140 | auto toRemove = map.end(); 141 | int index = 0; 142 | for(auto it = map.begin(); it != map.end(); ++it) 143 | { 144 | ImGui::PushID(index++); 145 | 146 | soundName = it->first ? it->first->Name() : ""; 147 | bool open = ImGui::TreeNode("sound", "%s", soundName.c_str()); 148 | if(ImGui::BeginPopupContextItem()) 149 | { 150 | if(ImGui::Selectable("Remove")) 151 | { 152 | toRemove = it; 153 | SetDirty(); 154 | } 155 | ImGui::EndPopup(); 156 | } 157 | 158 | if(open) 159 | { 160 | if(ImGui::InputCombo("sound", &soundName, &toAdd, editor.Sounds())) 161 | { 162 | toRemove = it; 163 | SetDirty(); 164 | } 165 | if(ImGui::InputInt("count", &it->second)) 166 | { 167 | if(!it->second) 168 | toRemove = it; 169 | SetDirty(); 170 | } 171 | ImGui::TreePop(); 172 | } 173 | ImGui::PopID(); 174 | } 175 | 176 | static std::string newSoundName; 177 | static const Sound *newSound; 178 | if(ImGui::InputCombo("new sound", &newSoundName, &newSound, editor.Sounds())) 179 | if(!newSoundName.empty()) 180 | { 181 | ++map[newSound]; 182 | newSoundName.clear(); 183 | newSound = nullptr; 184 | SetDirty(); 185 | } 186 | 187 | if(toAdd) 188 | { 189 | map[toAdd] += map[toRemove->first]; 190 | map.erase(toRemove); 191 | } 192 | else if(toRemove != map.end()) 193 | map.erase(toRemove); 194 | ImGui::TreePop(); 195 | } 196 | } 197 | 198 | 199 | 200 | template 201 | void TemplateEditor::RenderEffect(const std::string &name, std::map &map) 202 | { 203 | static std::string effectName; 204 | effectName.clear(); 205 | 206 | if(ImGui::TreeNode(name.c_str())) 207 | { 208 | Effect *toAdd = nullptr; 209 | auto toRemove = map.end(); 210 | int index = 0; 211 | for(auto it = map.begin(); it != map.end(); ++it) 212 | { 213 | ImGui::PushID(index++); 214 | 215 | effectName = it->first->Name(); 216 | bool open = ImGui::TreeNode("effect", "%s", effectName.c_str()); 217 | if(ImGui::BeginPopupContextItem()) 218 | { 219 | if(ImGui::Selectable("Remove")) 220 | { 221 | toRemove = it; 222 | SetDirty(); 223 | } 224 | ImGui::EndPopup(); 225 | } 226 | 227 | if(open) 228 | { 229 | if(ImGui::InputCombo("effect", &effectName, &toAdd, GameData::Effects())) 230 | { 231 | toRemove = it; 232 | SetDirty(); 233 | } 234 | if(ImGui::InputFloat("count", &it->second, 1, 1, "%g", ImGuiInputTextFlags_EnterReturnsTrue)) 235 | { 236 | if(!it->second) 237 | toRemove = it; 238 | SetDirty(); 239 | } 240 | ImGui::TreePop(); 241 | } 242 | ImGui::PopID(); 243 | } 244 | 245 | static std::string newEffectName; 246 | static const Effect *newEffect; 247 | if(ImGui::InputCombo("new effect", &newEffectName, &newEffect, GameData::Effects())) 248 | if(!newEffectName.empty()) 249 | { 250 | ++map[newEffect]; 251 | newEffectName.clear(); 252 | newEffect = nullptr; 253 | SetDirty(); 254 | } 255 | if(toAdd) 256 | { 257 | map[toAdd] += map[toRemove->first]; 258 | map.erase(toRemove); 259 | } 260 | else if(toRemove != map.end()) 261 | map.erase(toRemove); 262 | ImGui::TreePop(); 263 | } 264 | } 265 | 266 | 267 | 268 | template 269 | void TemplateEditor::RenderEffect(const std::string &name, std::map &map) 270 | { 271 | static std::string effectName; 272 | effectName.clear(); 273 | 274 | if(ImGui::TreeNode(name.c_str())) 275 | { 276 | Effect *toAdd = nullptr; 277 | auto toRemove = map.end(); 278 | int index = 0; 279 | for(auto it = map.begin(); it != map.end(); ++it) 280 | { 281 | ImGui::PushID(index++); 282 | 283 | effectName = it->first->Name(); 284 | bool open = ImGui::TreeNode("effect", "%s", effectName.c_str()); 285 | if(ImGui::BeginPopupContextItem()) 286 | { 287 | if(ImGui::Selectable("Remove")) 288 | { 289 | toRemove = it; 290 | SetDirty(); 291 | } 292 | ImGui::EndPopup(); 293 | } 294 | 295 | if(open) 296 | { 297 | if(ImGui::InputCombo("effect", &effectName, &toAdd, GameData::Effects())) 298 | { 299 | toRemove = it; 300 | SetDirty(); 301 | } 302 | if(ImGui::InputInt("count", &it->second, 1, 1, ImGuiInputTextFlags_EnterReturnsTrue)) 303 | { 304 | if(!it->second) 305 | toRemove = it; 306 | SetDirty(); 307 | } 308 | ImGui::TreePop(); 309 | } 310 | ImGui::PopID(); 311 | } 312 | 313 | static std::string newEffectName; 314 | static const Effect *newEffect; 315 | if(ImGui::InputCombo("new effect", &newEffectName, &newEffect, GameData::Effects())) 316 | if(!newEffectName.empty()) 317 | { 318 | ++map[newEffect]; 319 | newEffectName.clear(); 320 | newEffect = nullptr; 321 | SetDirty(); 322 | } 323 | if(toAdd) 324 | { 325 | map[toAdd] += map[toRemove->first]; 326 | map.erase(toRemove); 327 | } 328 | else if(toRemove != map.end()) 329 | map.erase(toRemove); 330 | ImGui::TreePop(); 331 | } 332 | } 333 | 334 | 335 | 336 | template class TemplateEditor; 337 | template class TemplateEditor; 338 | template class TemplateEditor; 339 | template class TemplateEditor; 340 | template class TemplateEditor; 341 | template class TemplateEditor; 342 | template class TemplateEditor>; 343 | template class TemplateEditor; 344 | template class TemplateEditor; 345 | template class TemplateEditor>; 346 | template class TemplateEditor; 347 | -------------------------------------------------------------------------------- /source/ArenaPanel.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "ArenaPanel.h" 4 | 5 | #include "comparators/ByGivenOrder.h" 6 | #include "BoardingPanel.h" 7 | #include "Dialog.h" 8 | #include "Editor.h" 9 | #include "text/Font.h" 10 | #include "text/FontSet.h" 11 | #include "text/Format.h" 12 | #include "FrameTimer.h" 13 | #include "GameData.h" 14 | #include "Government.h" 15 | #include "HailPanel.h" 16 | #include "MapDetailPanel.h" 17 | #include "Messages.h" 18 | #include "Mission.h" 19 | #include "Phrase.h" 20 | #include "Planet.h" 21 | #include "PlanetPanel.h" 22 | #include "PlayerInfo.h" 23 | #include "PlayerInfoPanel.h" 24 | #include "Preferences.h" 25 | #include "Projectile.h" 26 | #include "Random.h" 27 | #include "Screen.h" 28 | #include "Ship.h" 29 | #include "ShipEvent.h" 30 | #include "StellarObject.h" 31 | #include "System.h" 32 | #include "UI.h" 33 | #include "Visual.h" 34 | #include "Weather.h" 35 | 36 | #include "opengl.h" 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | using namespace std; 44 | 45 | 46 | 47 | void ArenaPanel::RenderProperties(SystemEditor &systemEditor, bool &show) 48 | { 49 | if(!ImGui::Begin("Arena Properties", &show, ImGuiWindowFlags_AlwaysAutoResize)) 50 | { 51 | ImGui::End(); 52 | return; 53 | } 54 | 55 | int date[3] = {currentDate.Day(), currentDate.Month(), currentDate.Year()}; 56 | if(ImGui::InputInt3("Current Date", date)) 57 | { 58 | date[0] = clamp(date[0], 1, 31); 59 | date[1] = clamp(date[1], 1, 12); 60 | date[2] = clamp(date[2], 1, 8388607 /*2^23 - 1*/); 61 | currentDate = Date(date[0], date[1], date[2]); 62 | 63 | player.date = currentDate; 64 | if(systemEditor.Selected()) 65 | const_cast(systemEditor.Selected())->SetDate(currentDate); 66 | } 67 | 68 | if(ImGui::Checkbox("Enable Fleet Spawns", &enableFleets)) 69 | Preferences::Set("editor - fleet spawn", enableFleets); 70 | if(ImGui::Checkbox("Enable Person Ship Spawns", &enablePersons)) 71 | Preferences::Set("editor - person spawn", enablePersons); 72 | if(ImGui::Checkbox("Highlight Flagship", &highlightFlagship)) 73 | Preferences::Set("flagship highlight", highlightFlagship); 74 | if(ImGui::Checkbox("Show Status Overlays", &showStatusOverlays)) 75 | Preferences::Set("Show status overlays", showStatusOverlays); 76 | if(ImGui::Checkbox("Show Chat", &showChat)) 77 | Preferences::Set("editor - show chat", showChat); 78 | 79 | ImGui::End(); 80 | } 81 | 82 | 83 | 84 | ArenaPanel::ArenaPanel(Editor &editor, SystemEditor &systemEditor) 85 | : editor(editor), systemEditor(systemEditor), engine(player) 86 | { 87 | SetIsFullScreen(true); 88 | 89 | player.date = currentDate; 90 | if(systemEditor.Selected()) 91 | systemEditor.Select(editor.Universe().systems.Get("Sol")); 92 | SetSystem(systemEditor.Selected()); 93 | 94 | highlightFlagship = Preferences::Has("flagship highlight"); 95 | showStatusOverlays = Preferences::Has("Show status overlays"); 96 | enableFleets = Preferences::Has("editor - fleet spawn"); 97 | enablePersons = Preferences::Has("editor - person spawn"); 98 | showChat = Preferences::Has("editor - show chat"); 99 | } 100 | 101 | 102 | 103 | void ArenaPanel::Step() 104 | { 105 | if(GetUI()->Top().get() != this) 106 | return; 107 | // Update the planets' dates. 108 | if(player.GetSystem()) 109 | const_cast(player.GetSystem())->SetDate(currentDate); 110 | 111 | engine.Wait(); 112 | 113 | // Depending on what UI element is on top, the game is "paused." This 114 | // checks only already-drawn panels. 115 | bool isActive = !paused && GetUI()->IsTop(this); 116 | 117 | engine.Step(isActive); 118 | 119 | // Execute any commands. 120 | for(const auto &f : commands) 121 | f(); 122 | commands.clear(); 123 | 124 | // Splice new events onto the eventQueue for (eventual) handling. No 125 | // other classes use Engine::Events() after Engine::Step() completes. 126 | eventQueue.splice(eventQueue.end(), engine.Events()); 127 | // Handle as many ShipEvents as possible (stopping if no longer active 128 | // and updating the isActive flag). 129 | StepEvents(isActive); 130 | 131 | if(isActive) 132 | engine.Go(); 133 | else 134 | canDrag = false; 135 | canClick = isActive; 136 | } 137 | 138 | 139 | 140 | void ArenaPanel::Draw() 141 | { 142 | FrameTimer loadTimer; 143 | glClear(GL_COLOR_BUFFER_BIT); 144 | 145 | engine.Draw(); 146 | 147 | if(Preferences::Has("Show CPU / GPU load")) 148 | { 149 | string loadString = to_string(lround(load * 100.)) + "% GPU"; 150 | const Color &color = *GameData::Colors().Get("medium"); 151 | FontSet::Get(14).Draw(loadString, Point(10., Screen::Height() * -.5 + 5.), color); 152 | 153 | loadSum += loadTimer.Time(); 154 | if(++loadCount == 60) 155 | { 156 | load = loadSum; 157 | loadSum = 0.; 158 | loadCount = 0; 159 | } 160 | } 161 | } 162 | 163 | 164 | 165 | void ArenaPanel::SetSystem(const System *system) 166 | { 167 | Execute([this, system] { 168 | if(system) 169 | player.SetSystem(*system); 170 | const_cast(system)->SetDate(currentDate); 171 | engine.EnterSystem(system); 172 | }); 173 | } 174 | 175 | 176 | 177 | void ArenaPanel::Execute(function f) 178 | { 179 | commands.push_back(std::move(f)); 180 | } 181 | 182 | 183 | 184 | bool ArenaPanel::AllowsFastForward() const noexcept 185 | { 186 | return true; 187 | } 188 | 189 | 190 | 191 | // Only override the ones you need; the default action is to return false. 192 | bool ArenaPanel::KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) 193 | { 194 | if(command.Has(Command::MAP) || key == 'd' || key == SDLK_ESCAPE 195 | || (key == 'w' && (mod & (KMOD_CTRL | KMOD_GUI)))) 196 | GetUI()->Pop(this); 197 | else if(command.Has(Command::MAP | Command::INFO | Command::HAIL)) 198 | show = command; 199 | else if(command.Has(Command::AMMO)) 200 | { 201 | Preferences::ToggleAmmoUsage(); 202 | Messages::Add("Your escorts will now expend ammo: " + Preferences::AmmoUsage() + "." 203 | , Messages::Importance::High); 204 | } 205 | else if((key == SDLK_MINUS || key == SDLK_KP_MINUS) && !command) 206 | Preferences::ZoomViewOut(); 207 | else if((key == SDLK_PLUS || key == SDLK_KP_PLUS || key == SDLK_EQUALS) && !command) 208 | Preferences::ZoomViewIn(); 209 | else if(key >= '0' && key <= '9' && !command) 210 | engine.SelectGroup(key - '0', mod & KMOD_SHIFT, mod & (KMOD_CTRL | KMOD_GUI)); 211 | else if(key == ' ') 212 | paused = !paused; 213 | else 214 | return false; 215 | 216 | return true; 217 | } 218 | 219 | 220 | 221 | bool ArenaPanel::Click(int x, int y, int clicks) 222 | { 223 | // Don't respond to clicks if another panel is active. 224 | if(!canClick) 225 | return true; 226 | // Only allow drags that start when clicking was possible. 227 | canDrag = true; 228 | 229 | dragSource = Point(x, y); 230 | dragPoint = dragSource; 231 | 232 | SDL_Keymod mod = SDL_GetModState(); 233 | hasShift = (mod & KMOD_SHIFT); 234 | 235 | engine.Click(dragSource, dragSource, hasShift, false); 236 | 237 | return true; 238 | } 239 | 240 | 241 | 242 | bool ArenaPanel::RClick(int x, int y) 243 | { 244 | engine.RClick(Point(x, y)); 245 | 246 | return true; 247 | } 248 | 249 | 250 | 251 | bool ArenaPanel::Drag(double dx, double dy) 252 | { 253 | if(!canDrag) 254 | return true; 255 | 256 | center -= Point(dx, dy) / engine.zoom; 257 | engine.SetCustomCenter(center); 258 | isDragging = true; 259 | return true; 260 | } 261 | 262 | 263 | 264 | bool ArenaPanel::Release(int x, int y) 265 | { 266 | if(isDragging) 267 | { 268 | dragPoint = Point(x, y); 269 | if(dragPoint.Distance(dragSource) > 5.) 270 | engine.Click(dragSource, dragPoint, hasShift, false); 271 | 272 | isDragging = false; 273 | } 274 | 275 | return true; 276 | } 277 | 278 | 279 | 280 | bool ArenaPanel::Scroll(double dx, double dy) 281 | { 282 | if(dy < 0) 283 | Preferences::ZoomViewOut(); 284 | else if(dy > 0) 285 | Preferences::ZoomViewIn(); 286 | else 287 | return false; 288 | 289 | return true; 290 | } 291 | 292 | 293 | 294 | // Handle ShipEvents from this and previous Engine::Step calls. Start with the 295 | // oldest and then process events until any create a new UI element. 296 | void ArenaPanel::StepEvents(bool &isActive) 297 | { 298 | while(isActive && !eventQueue.empty()) 299 | { 300 | const ShipEvent &event = eventQueue.front(); 301 | 302 | // Pass this event to the player, to update conditions and make 303 | // any new UI elements (e.g. an "on enter" dialog) from their 304 | // active missions. 305 | if(!handledFront) 306 | player.HandleEvent(event, GetUI()); 307 | handledFront = true; 308 | isActive = (GetUI()->Top().get() == this); 309 | 310 | // If we can't safely display a new UI element (i.e. an active 311 | // mission created a UI element), then stop processing events 312 | // until the current Conversation or Dialog is resolved. This 313 | // will keep the current event in the queue, so we can still 314 | // check it for various special cases involving the player. 315 | if(!isActive) 316 | break; 317 | 318 | // Remove the fully-handled event. 319 | eventQueue.pop_front(); 320 | handledFront = false; 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "configurePresets": [ 4 | { 5 | "name": "base", 6 | "hidden": true, 7 | "generator": "Ninja Multi-Config", 8 | "binaryDir": "${sourceDir}/build/${presetName}", 9 | "installDir": "${sourceDir}/install/${presetName}", 10 | "architecture": { 11 | "value": "x64", 12 | "strategy": "external" 13 | }, 14 | "cacheVariables": { 15 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", 16 | "CMAKE_COLOR_DIAGNOSTICS": "ON" 17 | } 18 | }, 19 | { 20 | "name": "ci", 21 | "hidden": true, 22 | "generator": "Ninja", 23 | "binaryDir": "${sourceDir}/build/ci", 24 | "installDir": "${sourceDir}/install/ci", 25 | "architecture": { 26 | "value": "x64", 27 | "strategy": "external" 28 | }, 29 | "cacheVariables": { 30 | "CMAKE_CXX_COMPILER_LAUNCHER": "ccache", 31 | "CMAKE_BUILD_TYPE": "Release" 32 | }, 33 | "condition": { 34 | "type": "equals", 35 | "lhs": "$env{CI}", 36 | "rhs": "true" 37 | } 38 | }, 39 | { 40 | "name": "linux", 41 | "displayName": "Linux", 42 | "description": "Builds with the default host compiler on Linux", 43 | "inherits": "base", 44 | "cacheVariables": { 45 | "VCPKG_HOST_TRIPLET": "x64-linux-dynamic", 46 | "VCPKG_TARGET_TRIPLET": "x64-linux-dynamic" 47 | }, 48 | "condition": { 49 | "type": "equals", 50 | "lhs": "${hostSystemName}", 51 | "rhs": "Linux" 52 | } 53 | }, 54 | { 55 | "name": "linux-gles", 56 | "displayName": "Linux", 57 | "description": "Builds with the default host compiler with OpenGL ES on Linux", 58 | "inherits": "base", 59 | "cacheVariables": { 60 | "VCPKG_TARGET_TRIPLET": "x64-linux-dynamic", 61 | "ES_GLES": "ON" 62 | }, 63 | "condition": { 64 | "type": "equals", 65 | "lhs": "${hostSystemName}", 66 | "rhs": "Linux" 67 | } 68 | }, 69 | { 70 | "name": "macos", 71 | "displayName": "MacOS", 72 | "description": "Builds with the default host compiler on MacOS", 73 | "inherits": "base", 74 | "cacheVariables": { 75 | "VCPKG_TARGET_TRIPLET": "x64-osx-dynamic" 76 | }, 77 | "condition": { 78 | "type": "equals", 79 | "lhs": "${hostSystemName}", 80 | "rhs": "Darwin" 81 | } 82 | }, 83 | { 84 | "name": "mingw", 85 | "displayName": "MinGW", 86 | "description": "Builds with the MinGW compiler toolchain", 87 | "inherits": "base", 88 | "cacheVariables": { 89 | "CMAKE_CXX_COMPILER": "x86_64-w64-mingw32-g++", 90 | "CMAKE_RC_COMPILER": "windres", 91 | "CMAKE_AR": "x86_64-w64-mingw32-gcc-ar", 92 | "CMAKE_RANLIB": "x86_64-w64-mingw32-gcc-ranlib", 93 | "VCPKG_TARGET_TRIPLET": "x64-mingw-dynamic" 94 | } 95 | }, 96 | { 97 | "name": "mingw32", 98 | "displayName": "MinGW x86", 99 | "description": "Builds with the x86 MinGW compiler toolchain", 100 | "inherits": "base", 101 | "architecture": { 102 | "value": "x86", 103 | "strategy": "external" 104 | }, 105 | "cacheVariables": { 106 | "CMAKE_CXX_COMPILER": "i686-w64-mingw32-g++", 107 | "CMAKE_RC_COMPILER": "windres", 108 | "CMAKE_AR": "i686-w64-mingw32-gcc-ar", 109 | "CMAKE_RANLIB": "i686-mingw32-gcc-ranlib", 110 | "VCPKG_TARGET_TRIPLET": "x86-mingw-dynamic" 111 | } 112 | }, 113 | { 114 | "name": "xcode", 115 | "displayName": "Xcode", 116 | "description": "Builds with Xcode on MacOS", 117 | "inherits": "base", 118 | "generator": "Xcode", 119 | "cacheVariables": { 120 | "VCPKG_TARGET_TRIPLET": "x64-osx-dynamic" 121 | }, 122 | "condition": { 123 | "type": "equals", 124 | "lhs": "${hostSystemName}", 125 | "rhs": "Darwin" 126 | } 127 | }, 128 | { 129 | "name": "vs", 130 | "displayName": "Visual Studio", 131 | "description": "Builds with clang-cl as a VS 2022 project", 132 | "inherits": "base", 133 | "generator": "Visual Studio 17", 134 | "toolset": "ClangCL", 135 | "cacheVariables": { 136 | "VCPKG_TARGET_TRIPLET": "x64-windows" 137 | }, 138 | "condition": { 139 | "type": "equals", 140 | "lhs": "${hostSystemName}", 141 | "rhs": "Windows" 142 | } 143 | }, 144 | { 145 | "name": "linux-ci", 146 | "displayName": "Linux CI", 147 | "description": "Builds for Linux for CI purposes", 148 | "inherits": "ci", 149 | "cacheVariables": { 150 | "VCPKG_TARGET_TRIPLET": "x64-linux-dynamic" 151 | } 152 | }, 153 | { 154 | "name": "linux-gles-ci", 155 | "displayName": "Linux GLES CI", 156 | "description": "Builds for Linux GLES for CI purposes", 157 | "inherits": "ci", 158 | "cacheVariables": { 159 | "VCPKG_TARGET_TRIPLET": "x64-linux-dynamic", 160 | "ES_GLES": "ON" 161 | } 162 | }, 163 | { 164 | "name": "macos-ci", 165 | "displayName": "MacOS CI", 166 | "description": "Builds for MacOS for CI purposes", 167 | "inherits": "ci", 168 | "cacheVariables": { 169 | "VCPKG_TARGET_TRIPLET": "x64-osx10.13-dynamic", 170 | "CMAKE_OSX_DEPLOYMENT_TARGET": "10.13" 171 | } 172 | }, 173 | { 174 | "name": "mingw-ci", 175 | "displayName": "MinGW CI", 176 | "description": "Builds with MinGW for CI purposes", 177 | "inherits": "ci", 178 | "cacheVariables": { 179 | "CMAKE_CXX_COMPILER": "x86_64-w64-mingw32-g++", 180 | "CMAKE_RC_COMPILER": "windres", 181 | "CMAKE_AR": "x86_64-w64-mingw32-gcc-ar", 182 | "CMAKE_RANLIB": "x86_64-w64-mingw32-gcc-ranlib", 183 | "VCPKG_TARGET_TRIPLET": "x64-mingw-dynamic" 184 | } 185 | }, 186 | { 187 | "name": "mingw32-ci", 188 | "displayName": "MinGW x86 CI", 189 | "description": "Builds with x86 MinGW for CI purposes", 190 | "inherits": "ci", 191 | "architecture": { 192 | "value": "x86", 193 | "strategy": "external" 194 | }, 195 | "cacheVariables": { 196 | "CMAKE_CXX_COMPILER": "i686-w64-mingw32-g++", 197 | "CMAKE_RC_COMPILER": "windres", 198 | "CMAKE_AR": "i686-w64-mingw32-gcc-ar", 199 | "CMAKE_RANLIB": "i686-mingw32-gcc-ranlib", 200 | "VCPKG_TARGET_TRIPLET": "x86-mingw-dynamic" 201 | } 202 | } 203 | ], 204 | "buildPresets": [ 205 | { 206 | "name": "debug", 207 | "hidden": true, 208 | "configuration": "Debug" 209 | }, 210 | { 211 | "name": "release", 212 | "hidden": true, 213 | "configuration": "Release" 214 | }, 215 | { 216 | "name": "ci", 217 | "hidden": true, 218 | "condition": { 219 | "type": "equals", 220 | "lhs": "$env{CI}", 221 | "rhs": "true" 222 | } 223 | }, 224 | { 225 | "name": "linux-debug", 226 | "displayName": "Debug", 227 | "configurePreset": "linux", 228 | "inherits": "debug" 229 | }, 230 | { 231 | "name": "linux-release", 232 | "displayName": "Release", 233 | "configurePreset": "linux", 234 | "inherits": "release" 235 | }, 236 | { 237 | "name": "linux-gles-debug", 238 | "displayName": "Debug", 239 | "configurePreset": "linux-gles", 240 | "inherits": "debug" 241 | }, 242 | { 243 | "name": "linux-gles-release", 244 | "displayName": "Release", 245 | "configurePreset": "linux-gles", 246 | "inherits": "release" 247 | }, 248 | { 249 | "name": "macos-debug", 250 | "displayName": "Debug", 251 | "configurePreset": "macos", 252 | "inherits": "debug" 253 | }, 254 | { 255 | "name": "macos-release", 256 | "displayName": "Release", 257 | "configurePreset": "macos", 258 | "inherits": "release" 259 | }, 260 | { 261 | "name": "xcode-debug", 262 | "displayName": "Debug", 263 | "configurePreset": "xcode", 264 | "inherits": "debug" 265 | }, 266 | { 267 | "name": "xcode-release", 268 | "displayName": "Release", 269 | "configurePreset": "xcode", 270 | "inherits": "release" 271 | }, 272 | { 273 | "name": "mingw-debug", 274 | "displayName": "Debug", 275 | "configurePreset": "mingw", 276 | "inherits": "debug" 277 | }, 278 | { 279 | "name": "mingw-release", 280 | "displayName": "Release", 281 | "configurePreset": "mingw", 282 | "inherits": "release" 283 | }, 284 | { 285 | "name": "mingw32-debug", 286 | "displayName": "Debug", 287 | "configurePreset": "mingw32", 288 | "inherits": "debug" 289 | }, 290 | { 291 | "name": "mingw32-release", 292 | "displayName": "Release", 293 | "configurePreset": "mingw32", 294 | "inherits": "release" 295 | }, 296 | { 297 | "name": "vs-debug", 298 | "displayName": "Debug", 299 | "configurePreset": "vs", 300 | "inherits": "debug" 301 | }, 302 | { 303 | "name": "vs-release", 304 | "displayName": "Release", 305 | "configurePreset": "vs", 306 | "inherits": "release" 307 | }, 308 | { 309 | "name": "linux-ci", 310 | "displayName": "Linux CI build", 311 | "configurePreset": "linux-ci", 312 | "inherits": "ci" 313 | }, 314 | { 315 | "name": "linux-gles-ci", 316 | "displayName": "Linux GLES CI build", 317 | "configurePreset": "linux-gles-ci", 318 | "inherits": "ci" 319 | }, 320 | { 321 | "name": "macos-ci", 322 | "displayName": "MacOS CI build", 323 | "configurePreset": "macos-ci", 324 | "inherits": "ci" 325 | }, 326 | { 327 | "name": "mingw-ci", 328 | "displayName": "MinGW CI build", 329 | "configurePreset": "mingw-ci", 330 | "inherits": "ci" 331 | }, 332 | { 333 | "name": "mingw32-ci", 334 | "displayName": "MinGW x86 CI build", 335 | "configurePreset": "mingw32-ci", 336 | "inherits": "ci" 337 | } 338 | ] 339 | } 340 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | /* main.cpp 2 | Copyright (c) 2014 by Michael Zahniser 3 | 4 | Main function for Endless Sky, a space exploration and combat RPG. 5 | 6 | Endless Sky is free software: you can redistribute it and/or modify it under the 7 | terms of the GNU General Public License as published by the Free Software 8 | Foundation, either version 3 of the License, or (at your option) any later version. 9 | 10 | Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY 11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 12 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 | */ 14 | 15 | #include "Audio.h" 16 | #include "Command.h" 17 | #include "Conversation.h" 18 | #include "ConversationPanel.h" 19 | #include "DataFile.h" 20 | #include "DataNode.h" 21 | #include "Dialog.h" 22 | #include "Editor.h" 23 | #include "Files.h" 24 | #include "text/Font.h" 25 | #include "FrameTimer.h" 26 | #include "GameAssets.h" 27 | #include "GameData.h" 28 | #include "GameWindow.h" 29 | #include "GameLoadingPanel.h" 30 | #include "Hardpoint.h" 31 | #include "Logger.h" 32 | #include "MenuAnimationPanel.h" 33 | #include "MenuPanel.h" 34 | #include "Outfit.h" 35 | #include "Panel.h" 36 | #include "PlayerInfo.h" 37 | #include "Preferences.h" 38 | #include "Screen.h" 39 | #include "Ship.h" 40 | #include "SpriteSet.h" 41 | #include "SpriteShader.h" 42 | #include "TaskQueue.h" 43 | #include "Test.h" 44 | #include "TestContext.h" 45 | #include "UI.h" 46 | #include "Version.h" 47 | #include "imgui.h" 48 | #include "imgui_impl_sdl.h" 49 | #include "imgui_impl_opengl3.h" 50 | #include "nfd.h" 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | #ifdef _WIN32 63 | #define STRICT 64 | #define WIN32_LEAN_AND_MEAN 65 | #include 66 | #include 67 | #endif 68 | 69 | using namespace std; 70 | 71 | void PrintHelp(); 72 | void PrintVersion(); 73 | void GameLoop(); 74 | #ifdef _WIN32 75 | void InitConsole(); 76 | #endif 77 | 78 | 79 | 80 | // Entry point for the EndlessSky executable 81 | int main(int argc, char *argv[]) 82 | { 83 | // Handle command-line arguments 84 | #ifdef _WIN32 85 | if(argc > 1) 86 | InitConsole(); 87 | #endif 88 | // Ensure that we log errors to the errors.txt file. 89 | Logger::SetLogErrorCallback([](const string &errorMessage) { Files::LogErrorToFile(errorMessage); }); 90 | 91 | for(const char *const *it = argv + 1; *it; ++it) 92 | { 93 | string arg = *it; 94 | if(arg == "-h" || arg == "--help") 95 | { 96 | PrintHelp(); 97 | return 0; 98 | } 99 | else if(arg == "-v" || arg == "--version") 100 | { 101 | PrintVersion(); 102 | return 0; 103 | } 104 | } 105 | Files::Init(argv); 106 | 107 | try { 108 | TaskQueue _; 109 | 110 | // OpenAL needs to be initialized before we begin loading any sounds/music. 111 | Audio::Init(); 112 | 113 | // Begin loading the game data. 114 | future dataLoading = GameData::BeginLoad(0); 115 | 116 | // On Windows, make sure that the sleep timer has at least 1 ms resolution 117 | // to avoid irregular frame rates. 118 | #ifdef _WIN32 119 | timeBeginPeriod(1); 120 | #endif 121 | 122 | Preferences::Load(); 123 | 124 | #ifdef __linux__ 125 | // TODO: Prefer wayland if it is available. 126 | //SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland,x11"); 127 | #endif 128 | 129 | if(!GameWindow::Init([](SDL_Window *window, const SDL_GLContext &context) 130 | { 131 | ImGui::CreateContext(); 132 | ImGuiIO& io = ImGui::GetIO(); 133 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; 134 | io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; 135 | //io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; 136 | 137 | ImGui_ImplSDL2_InitForOpenGL(window, context); 138 | 139 | SDL_SetWindowTitle(window, "Editor"); 140 | })) 141 | return 1; 142 | 143 | ImGui_ImplOpenGL3_Init(nullptr); 144 | NFD_Init(); 145 | 146 | 147 | GameData::LoadShaders(!GameWindow::HasSwizzle()); 148 | 149 | // Show something other than a blank window. 150 | GameWindow::Step(); 151 | 152 | // This is the main loop where all the action begins. 153 | GameLoop(); 154 | } 155 | catch(const exception &error) 156 | { 157 | Audio::Quit(); 158 | GameWindow::ExitWithError(error.what(), true); 159 | return 1; 160 | } 161 | 162 | // Remember the window state and preferences if quitting normally. 163 | Preferences::Set("maximized", GameWindow::IsMaximized()); 164 | Preferences::Set("fullscreen", GameWindow::IsFullscreen()); 165 | Screen::SetRaw(GameWindow::Width(), GameWindow::Height()); 166 | Preferences::Save(); 167 | 168 | NFD_Quit(); 169 | ImGui_ImplOpenGL3_Shutdown(); 170 | ImGui_ImplSDL2_Shutdown(); 171 | ImGui::DestroyContext(); 172 | 173 | Audio::Quit(); 174 | GameWindow::Quit(); 175 | 176 | return 0; 177 | } 178 | 179 | 180 | 181 | void GameLoop() 182 | { 183 | // Panels shown to the user. Unlike the proper game, there is only one group 184 | // of panels. 185 | UI panels; 186 | 187 | Editor editor(panels); 188 | 189 | // Whether the game data is done loading. This is used to trigger any 190 | // tests to run. 191 | bool dataFinishedLoading = false; 192 | panels.Push(new GameLoadingPanel([&panels, &editor] (GameLoadingPanel *This) 193 | { 194 | panels.Pop(This); 195 | editor.Initialize(); 196 | }, dataFinishedLoading)); 197 | 198 | int frameRate = 60; 199 | FrameTimer timer(frameRate); 200 | bool isPaused = false; 201 | 202 | // Limit how quickly full-screen mode can be toggled. 203 | int toggleTimeout = 0; 204 | 205 | const auto &io = ImGui::GetIO(); 206 | // IsDone becomes true when the game is quit. 207 | while(!panels.IsDone()) 208 | { 209 | if(toggleTimeout) 210 | --toggleTimeout; 211 | 212 | // Handle any events that occurred in this frame. 213 | SDL_Event event; 214 | while(SDL_PollEvent(&event)) 215 | { 216 | if(!io.WantCaptureKeyboard && event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_BACKQUOTE) 217 | isPaused = !isPaused; 218 | else if(event.type == SDL_QUIT) 219 | panels.Quit(); 220 | else if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) 221 | { 222 | // The window has been resized. Adjust the raw screen size 223 | // and the OpenGL viewport to match. 224 | GameWindow::AdjustViewport(); 225 | } 226 | else if(((!io.WantCaptureKeyboard && event.type == SDL_KEYDOWN) || 227 | (!io.WantCaptureMouse && (event.type == SDL_MOUSEMOTION 228 | || event.type == SDL_MOUSEBUTTONDOWN 229 | || event.type == SDL_MOUSEBUTTONUP 230 | || event.type == SDL_MOUSEWHEEL))) && panels.Handle(event)) 231 | { 232 | // The UI handled the event. 233 | } 234 | else if(!io.WantCaptureKeyboard && event.type == SDL_KEYDOWN && !toggleTimeout 235 | && (Command(event.key.keysym.sym).Has(Command::FULLSCREEN) 236 | || (event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT)))) 237 | { 238 | toggleTimeout = 30; 239 | GameWindow::ToggleFullscreen(); 240 | } 241 | 242 | ImGui_ImplSDL2_ProcessEvent(&event); 243 | } 244 | SDL_Keymod mod = SDL_GetModState(); 245 | Font::ShowUnderlines((mod & KMOD_ALT) && !io.WantCaptureKeyboard); 246 | 247 | // Tell all the panels to step forward, then draw them. 248 | panels.StepAll(); 249 | 250 | // Process any tasks to execute. 251 | TaskQueue::ProcessTasks(); 252 | 253 | Audio::Step(); 254 | 255 | ImGui_ImplOpenGL3_NewFrame(); 256 | ImGui_ImplSDL2_NewFrame(); 257 | ImGui::NewFrame(); 258 | if(dataFinishedLoading) 259 | editor.RenderMain(); 260 | ImGui::Render(); 261 | 262 | // Events in this frame may have cleared out the menu, in which case 263 | // we should draw the game panels instead: 264 | panels.DrawAll(); 265 | 266 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 267 | 268 | SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); 269 | SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); 270 | ImGui::UpdatePlatformWindows(); 271 | ImGui::RenderPlatformWindowsDefault(); 272 | SDL_GL_MakeCurrent(backup_current_window, backup_current_context); 273 | 274 | GameWindow::Step(); 275 | 276 | // Lock the framerate to 60fps. 277 | timer.Wait(); 278 | } 279 | } 280 | 281 | 282 | 283 | void PrintHelp() 284 | { 285 | cerr << endl; 286 | cerr << "Command line options:" << endl; 287 | cerr << " -h, --help: print this help message." << endl; 288 | cerr << " -v, --version: print version information." << endl; 289 | cerr << endl; 290 | cerr << "Report bugs to: " << endl; 291 | cerr << endl; 292 | } 293 | 294 | 295 | 296 | void PrintVersion() 297 | { 298 | cerr << endl; 299 | cerr << "Editor, compatible with Endless Sky " << ES_VERSION << endl; 300 | cerr << "License GPLv3+: GNU GPL version 3 or later: " << endl; 301 | cerr << "This is free software: you are free to change and redistribute it." << endl; 302 | cerr << "There is NO WARRANTY, to the extent permitted by law." << endl; 303 | cerr << endl; 304 | cerr << GameWindow::SDLVersions() << endl; 305 | cerr << endl; 306 | } 307 | 308 | 309 | 310 | #ifdef _WIN32 311 | void InitConsole() 312 | { 313 | const int UNINITIALIZED = -2; 314 | bool redirectStdout = _fileno(stdout) == UNINITIALIZED; 315 | bool redirectStderr = _fileno(stderr) == UNINITIALIZED; 316 | bool redirectStdin = _fileno(stdin) == UNINITIALIZED; 317 | 318 | // Bail if stdin, stdout, and stderr are already initialized (e.g. writing to a file) 319 | if(!redirectStdout && !redirectStderr && !redirectStdin) 320 | return; 321 | 322 | // Bail if we fail to attach to the console 323 | if(!AttachConsole(ATTACH_PARENT_PROCESS) && !AllocConsole()) 324 | return; 325 | 326 | // Perform console redirection. 327 | if(redirectStdout) 328 | { 329 | FILE *fstdout = nullptr; 330 | freopen_s(&fstdout, "CONOUT$", "w", stdout); 331 | if(fstdout) 332 | setvbuf(stdout, nullptr, _IOFBF, 4096); 333 | } 334 | if(redirectStderr) 335 | { 336 | FILE *fstderr = nullptr; 337 | freopen_s(&fstderr, "CONOUT$", "w", stderr); 338 | if(fstderr) 339 | setvbuf(stderr, nullptr, _IOLBF, 1024); 340 | } 341 | if(redirectStdin) 342 | { 343 | FILE *fstdin = nullptr; 344 | freopen_s(&fstdin, "CONIN$", "r", stdin); 345 | if(fstdin) 346 | setvbuf(stdin, nullptr, _IONBF, 0); 347 | } 348 | } 349 | #endif 350 | -------------------------------------------------------------------------------- /overlays/nativefiledialog-extended/0001-enable-shared-library.patch: -------------------------------------------------------------------------------- 1 | From e018ec82bc86240c80161ac616fd7da8bdcd85db Mon Sep 17 00:00:00 2001 2 | From: Jonathan Wright 3 | Date: Wed, 17 Aug 2022 09:19:04 -0500 4 | Subject: [PATCH] Option to generate shared library & use GNUInstallDirs (#76) 5 | 6 | * add option to build shared library 7 | 8 | * use GNUInstallDirs on linux 9 | 10 | * add default dirs for win/apple 11 | 12 | * Add CI builds for shared library 13 | 14 | * Set GNUInstallDirs on all OSes 15 | 16 | Co-authored-by: Bernard Teo 17 | --- 18 | .github/workflows/cmake.yml | 63 +++++++++++++++++++++++-------------- 19 | CMakeLists.txt | 4 ++- 20 | src/CMakeLists.txt | 12 ++++--- 21 | 3 files changed, 51 insertions(+), 28 deletions(-) 22 | 23 | diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml 24 | index fa7d976..5f6ec48 100644 25 | --- a/.github/workflows/cmake.yml 26 | +++ b/.github/workflows/cmake.yml 27 | @@ -22,7 +22,7 @@ jobs: 28 | 29 | build-ubuntu: 30 | 31 | - name: Ubuntu ${{ matrix.os.name }} - ${{ matrix.compiler.name }}, ${{ matrix.portal.name }}, ${{ matrix.autoappend.name }}, C++${{ matrix.cppstd }} 32 | + name: Ubuntu ${{ matrix.os.name }} - ${{ matrix.compiler.name }}, ${{ matrix.portal.name }}, ${{ matrix.autoappend.name }}, ${{ matrix.shared_lib.name }}, C++${{ matrix.cppstd }} 33 | runs-on: ${{ matrix.os.label }} 34 | 35 | strategy: 36 | @@ -32,17 +32,26 @@ jobs: 37 | autoappend: [ {flag: OFF, name: NoAppendExtn} ] # By default the NFD_PORTAL mode does not append extensions, because it breaks some features of the portal 38 | compiler: [ {c: gcc, cpp: g++, name: GCC}, {c: clang, cpp: clang++, name: Clang} ] # The default compiler is gcc/g++ 39 | cppstd: [23, 11] 40 | + shared_lib: [ {flag: OFF, name: Static} ] 41 | include: 42 | - os: {label: ubuntu-latest, name: latest} 43 | portal: {flag: ON, dep: libdbus-1-dev, name: Portal} 44 | autoappend: {flag: ON, name: AutoAppendExtn} 45 | compiler: {c: gcc, cpp: g++, name: GCC} 46 | cppstd: 11 47 | + shared_lib: {flag: OFF, name: Static} 48 | - os: {label: ubuntu-latest, name: latest} 49 | portal: {flag: ON, dep: libdbus-1-dev, name: Portal} 50 | autoappend: {flag: ON, name: AutoAppendExtn} 51 | compiler: {c: clang, cpp: clang++, name: Clang} 52 | cppstd: 11 53 | + shared_lib: {flag: OFF, name: Static} 54 | + - os: {label: ubuntu-latest, name: latest} 55 | + portal: {flag: ON, dep: libdbus-1-dev, name: Portal} 56 | + autoappend: {flag: ON, name: NoAppendExtn} 57 | + compiler: {c: gcc, cpp: g++, name: GCC} 58 | + cppstd: 11 59 | + shared_lib: {flag: ON, name: Shared} 60 | 61 | steps: 62 | - name: Checkout 63 | @@ -50,64 +59,72 @@ jobs: 64 | - name: Installing Dependencies 65 | run: sudo apt-get update && sudo apt-get install ${{ matrix.portal.dep }} 66 | - name: Configure 67 | - run: mkdir build && mkdir install && cd build && cmake -DCMAKE_INSTALL_PREFIX="../install" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${{ matrix.compiler.c }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cpp }} -DCMAKE_CXX_STANDARD=${{ matrix.cppstd }} -DCMAKE_C_FLAGS="-Wall -Wextra -Werror -pedantic" -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -pedantic" -DNFD_PORTAL=${{ matrix.portal.flag }} -DNFD_APPEND_EXTENSION=${{ matrix.autoappend.flag }} -DNFD_BUILD_TESTS=ON .. 68 | + run: mkdir build && mkdir install && cd build && cmake -DCMAKE_INSTALL_PREFIX="../install" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${{ matrix.compiler.c }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cpp }} -DCMAKE_CXX_STANDARD=${{ matrix.cppstd }} -DCMAKE_C_FLAGS="-Wall -Wextra -Werror -pedantic" -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -pedantic" -DNFD_PORTAL=${{ matrix.portal.flag }} -DNFD_APPEND_EXTENSION=${{ matrix.autoappend.flag }} -DBUILD_SHARED_LIBS=${{ matrix.shared_lib.flag }} -DNFD_BUILD_TESTS=ON .. 69 | - name: Build 70 | run: cmake --build build --target install 71 | - name: Upload test binaries 72 | uses: actions/upload-artifact@v2 73 | with: 74 | - name: Ubuntu ${{ matrix.os.name }} - ${{ matrix.compiler.name }}, ${{ matrix.portal.name }}, ${{ matrix.autoappend.name }}, C++${{ matrix.cppstd }} 75 | + name: Ubuntu ${{ matrix.os.name }} - ${{ matrix.compiler.name }}, ${{ matrix.portal.name }}, ${{ matrix.autoappend.name }}, ${{ matrix.shared_lib.name }}, C++${{ matrix.cppstd }} 76 | path: | 77 | - build/src/libnfd.a 78 | - build/test/test_* 79 | + build/src/* 80 | + build/test/* 81 | 82 | build-macos-clang: 83 | 84 | - name: MacOS ${{ matrix.os.name }} - Clang 85 | + name: MacOS ${{ matrix.os.name }} - Clang, ${{ matrix.shared_lib.name }} 86 | runs-on: ${{ matrix.os.label }} 87 | 88 | strategy: 89 | matrix: 90 | os: [ {label: macos-latest, name: latest}, {label: macos-10.15, name: 10.15} ] 91 | + shared_lib: [ {flag: OFF, name: Static} ] 92 | + include: 93 | + - os: {label: macos-latest, name: latest} 94 | + shared_lib: {flag: ON, name: Shared} 95 | 96 | steps: 97 | - name: Checkout 98 | uses: actions/checkout@v2 99 | - name: Configure 100 | - run: mkdir build && mkdir install && cd build && cmake -DCMAKE_INSTALL_PREFIX="../install" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra -Werror -pedantic" -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -pedantic" -DNFD_BUILD_TESTS=ON .. 101 | + run: mkdir build && mkdir install && cd build && cmake -DCMAKE_INSTALL_PREFIX="../install" -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra -Werror -pedantic" -DCMAKE_CXX_FLAGS="-Wall -Wextra -Werror -pedantic" -DBUILD_SHARED_LIBS=${{ matrix.shared_lib.flag }} -DNFD_BUILD_TESTS=ON .. 102 | - name: Build 103 | run: cmake --build build --target install 104 | - name: Upload test binaries 105 | uses: actions/upload-artifact@v2 106 | with: 107 | - name: MacOS ${{ matrix.os.name }} - Clang 108 | + name: MacOS ${{ matrix.os.name }} - Clang, ${{ matrix.shared_lib.name }} 109 | path: | 110 | - build/src/libnfd.a 111 | - build/test/test_* 112 | + build/src/* 113 | + build/test/* 114 | 115 | build-windows-msvc: 116 | 117 | - name: Windows latest - MSVC 118 | + name: Windows latest - MSVC, ${{ matrix.shared_lib.name }} 119 | runs-on: windows-latest 120 | 121 | + strategy: 122 | + matrix: 123 | + shared_lib: [ {flag: OFF, name: Static}, {flag: ON, name: Shared} ] 124 | + 125 | steps: 126 | - name: Checkout 127 | uses: actions/checkout@v2 128 | - name: Configure 129 | - run: mkdir build && mkdir install && cd build && cmake -DCMAKE_INSTALL_PREFIX="../install" -DNFD_BUILD_TESTS=ON .. 130 | + run: mkdir build && mkdir install && cd build && cmake -DCMAKE_INSTALL_PREFIX="../install" -DBUILD_SHARED_LIBS=${{ matrix.shared_lib.flag }} -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=${{ matrix.shared_lib.flag }} -DNFD_BUILD_TESTS=ON .. 131 | - name: Build 132 | run: cmake --build build --target install --config Release 133 | - name: Upload test binaries 134 | uses: actions/upload-artifact@v2 135 | with: 136 | - name: Windows latest - MSVC 137 | + name: Windows latest - MSVC, ${{ matrix.shared_lib.name }} 138 | path: | 139 | - build/src/Release/nfd.lib 140 | - build/test/Release/test_* 141 | + build/src/Release/* 142 | + build/test/Release/* 143 | 144 | build-windows-clang: 145 | 146 | - name: Windows latest - Clang 147 | + name: Windows latest - Clang, Static 148 | runs-on: windows-latest 149 | 150 | steps: 151 | @@ -120,14 +137,14 @@ jobs: 152 | - name: Upload test binaries 153 | uses: actions/upload-artifact@v2 154 | with: 155 | - name: Windows latest - Clang 156 | + name: Windows latest - Clang, Static 157 | path: | 158 | - build/src/Release/nfd.lib 159 | - build/test/Release/test_* 160 | + build/src/Release/* 161 | + build/test/Release/* 162 | 163 | build-windows-mingw: 164 | 165 | - name: Windows latest - MinGW 166 | + name: Windows latest - MinGW, Static 167 | runs-on: windows-latest 168 | 169 | defaults: 170 | @@ -152,7 +169,7 @@ jobs: 171 | - name: Upload test binaries 172 | uses: actions/upload-artifact@v2 173 | with: 174 | - name: Windows latest - MinGW 175 | + name: Windows latest - MinGW, Static 176 | path: | 177 | - build/src/libnfd.a 178 | - build/test/test_* 179 | + build/src/* 180 | + build/test/* 181 | diff --git a/CMakeLists.txt b/CMakeLists.txt 182 | index f3deec3..feeb8f3 100644 183 | --- a/CMakeLists.txt 184 | +++ b/CMakeLists.txt 185 | @@ -1,5 +1,7 @@ 186 | cmake_minimum_required(VERSION 3.2) 187 | -project(nativefiledialog-extended) 188 | +project(nativefiledialog-extended VERSION 1.0.0) 189 | + 190 | +option(BUILD_SHARED_LIBS "Build a shared library instead of static" OFF) 191 | 192 | set(nfd_PLATFORM Undefined) 193 | if(WIN32) 194 | diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt 195 | index 78f9d0f..d95d666 100644 196 | --- a/src/CMakeLists.txt 197 | +++ b/src/CMakeLists.txt 198 | @@ -57,8 +57,7 @@ if(nfd_PLATFORM STREQUAL PLATFORM_MACOS) 199 | endif() 200 | 201 | # Define the library 202 | -add_library(${TARGET_NAME} STATIC 203 | - ${SOURCE_FILES}) 204 | +add_library(${TARGET_NAME} ${SOURCE_FILES}) 205 | 206 | # Allow includes from include/ 207 | target_include_directories(${TARGET_NAME} 208 | @@ -110,6 +109,11 @@ if(nfd_COMPILER STREQUAL COMPILER_GNU) 209 | target_compile_options(${TARGET_NAME} PRIVATE -nostdlib -fno-exceptions -fno-rtti) 210 | endif() 211 | 212 | -set_target_properties(${TARGET_NAME} PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADER_FILES}") 213 | +set_target_properties(${TARGET_NAME} PROPERTIES 214 | + PUBLIC_HEADER "${PUBLIC_HEADER_FILES}" 215 | + VERSION ${PROJECT_VERSION} 216 | + SOVERSION ${PROJECT_VERSION_MAJOR}) 217 | 218 | -install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include) 219 | +include(GNUInstallDirs) 220 | + 221 | +install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 222 | -------------------------------------------------------------------------------- /source/MainEditorPanel.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #include "MainEditorPanel.h" 4 | 5 | #include "text/alignment.hpp" 6 | #include "Angle.h" 7 | #include "CargoHold.h" 8 | #include "Dialog.h" 9 | #include "Editor.h" 10 | #include "FillShader.h" 11 | #include "Flotsam.h" 12 | #include "FogShader.h" 13 | #include "text/Font.h" 14 | #include "text/FontSet.h" 15 | #include "text/Format.h" 16 | #include "Galaxy.h" 17 | #include "Government.h" 18 | #include "Information.h" 19 | #include "Interface.h" 20 | #include "LineShader.h" 21 | #include "MapDetailPanel.h" 22 | #include "MapOutfitterPanel.h" 23 | #include "MapShipyardPanel.h" 24 | #include "Mission.h" 25 | #include "MissionPanel.h" 26 | #include "Planet.h" 27 | #include "PlanetEditor.h" 28 | #include "PointerShader.h" 29 | #include "Politics.h" 30 | #include "Radar.h" 31 | #include "RingShader.h" 32 | #include "Screen.h" 33 | #include "Ship.h" 34 | #include "SpriteShader.h" 35 | #include "StarField.h" 36 | #include "StellarObject.h" 37 | #include "SystemEditor.h" 38 | #include "System.h" 39 | #include "Trade.h" 40 | #include "UI.h" 41 | #include "Visual.h" 42 | 43 | #include "opengl.h" 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | using namespace std; 53 | 54 | 55 | namespace { 56 | constexpr double ZOOMS[] = {.1, .15, .2, .25, .35, .50, .70, 1., 1.4, 2.}; 57 | constexpr size_t SIZE = sizeof(ZOOMS) / sizeof(double); 58 | } 59 | 60 | 61 | 62 | void MainEditorPanel::RenderProperties(SystemEditor &systemEditor, bool &show) 63 | { 64 | if(!ImGui::Begin("In-System Properties", &show, ImGuiWindowFlags_AlwaysAutoResize)) 65 | { 66 | ImGui::End(); 67 | return; 68 | } 69 | 70 | ImGui::Checkbox("Show Habitable Rings", &showHabitableRings); 71 | ImGui::Checkbox("Show Orbits", &showOrbits); 72 | ImGui::Checkbox("Show Belts", &showBelts); 73 | ImGui::Checkbox("Show Arrival Distance", &showArrivalDistance); 74 | ImGui::InputInt("Time Increment", &timeIncrement); 75 | ImGui::End(); 76 | } 77 | 78 | 79 | 80 | MainEditorPanel::MainEditorPanel(const Editor &editor, PlanetEditor *planetEditor, SystemEditor *systemEditor) 81 | : planetEditor(planetEditor), systemEditor(systemEditor) 82 | { 83 | zoom = ViewZoom(); 84 | if(!systemEditor->Selected()) 85 | systemEditor->Select(editor.Universe().systems.Get("Sol")); 86 | Select(systemEditor->Selected()); 87 | SetIsFullScreen(true); 88 | SetInterruptible(false); 89 | 90 | UpdateSystem(); 91 | UpdateCache(); 92 | } 93 | 94 | 95 | 96 | void MainEditorPanel::Step() 97 | { 98 | if(GetUI()->Top().get() != this) 99 | return; 100 | 101 | UpdateSystem(); 102 | 103 | double zoomTarget = ViewZoom(); 104 | if(zoom != zoomTarget) 105 | { 106 | static const double ZOOM_SPEED = .05; 107 | 108 | // Define zoom speed bounds to prevent asymptotic behavior. 109 | static const double MAX_SPEED = .05; 110 | static const double MIN_SPEED = .002; 111 | const Point anchor = -mouse / zoom - center; 112 | 113 | double zoomRatio = max(MIN_SPEED, min(MAX_SPEED, abs(log2(zoom) - log2(zoomTarget)) * ZOOM_SPEED)); 114 | if(zoom < zoomTarget) 115 | zoom = min(zoomTarget, zoom * (1. + zoomRatio)); 116 | else if(zoom > zoomTarget) 117 | zoom = max(zoomTarget, zoom * (1. / (1. + zoomRatio))); 118 | center = -mouse / zoom - anchor; 119 | } 120 | 121 | labels.clear(); 122 | for(const StellarObject &object : currentSystem->Objects()) 123 | if(object.planet) 124 | labels.emplace_back(object.Position() - center, object, currentSystem, zoom, true); 125 | } 126 | 127 | 128 | 129 | void MainEditorPanel::Draw() 130 | { 131 | glClear(GL_COLOR_BUFFER_BIT); 132 | GameData::Background().Draw(center, Point(), zoom); 133 | for(const PlanetLabel &label : labels) 134 | label.Draw(); 135 | 136 | draw.Clear(step, zoom); 137 | batchDraw.Clear(step, zoom); 138 | draw.SetCenter(center); 139 | batchDraw.SetCenter(center); 140 | 141 | for(const auto &object : currentSystem->Objects()) 142 | { 143 | if(object.HasSprite()) 144 | { 145 | // Don't apply motion blur to very large planets and stars. 146 | if(object.Width() >= 280.) 147 | draw.AddUnblurred(object); 148 | else 149 | draw.Add(object); 150 | } 151 | 152 | if(object.IsStar() || !showOrbits) 153 | continue; 154 | 155 | if(object.Parent() == -1) 156 | RingShader::Draw(-center * zoom, object.Distance() * zoom, object.Radius() * zoom, 1.f, Color(169.f / 255.f, 169.f / 255.f, 169.f / 255.f).Transparent(.1f)); 157 | else 158 | { 159 | const auto &parent = currentSystem->Objects()[object.Parent()]; 160 | RingShader::Draw((parent.Position() - center) * zoom, 161 | object.Distance() * zoom, object.Radius() * zoom, 1.f, 162 | Color(169.f / 255.f, 169.f / 255.f, 169.f / 255.f).Transparent(.1f)); 163 | } 164 | } 165 | 166 | asteroids.Step(newVisuals, newFlotsam, step); 167 | asteroids.Draw(draw, center, zoom); 168 | for(const auto &visual : newVisuals) 169 | batchDraw.AddVisual(visual); 170 | for(const auto &floatsam : newFlotsam) 171 | draw.Add(*floatsam); 172 | ++step; 173 | 174 | if(currentObject) 175 | { 176 | Angle a = currentObject->Facing(); 177 | Angle da(360. / 5); 178 | 179 | PointerShader::Bind(); 180 | for(int i = 0; i < 5; ++i) 181 | { 182 | PointerShader::Add((currentObject->Position() - center) * zoom, a.Unit(), 12.f, 14.f, -currentObject->RealRadius() * zoom, Radar::GetColor(Radar::FRIENDLY)); 183 | a += da; 184 | } 185 | PointerShader::Unbind(); 186 | } 187 | 188 | if(showHabitableRings) 189 | { 190 | RingShader::Draw(-center * zoom, currentSystem->HabitableZone() * zoom, 2.5f, 1.f, Color(50.f / 255.f, 205.f / 255.f, 50.f / 255.f).Transparent(.3f)); 191 | RingShader::Draw(-center * zoom, currentSystem->HabitableZone() * .5 * zoom, 2.5f, 1.f, Color(1.f, 140.f / 255.f, 0.f).Transparent(.3f)); 192 | RingShader::Draw(-center * zoom, currentSystem->HabitableZone() * 2 * zoom, 2.5f, 1.f, Color(0.f, 191.f / 255.f, 1.f).Transparent(.3f)); 193 | } 194 | 195 | if(showBelts) 196 | for(const auto &belt : currentSystem->AsteroidBelts()) 197 | RingShader::Draw(-center * zoom, belt.item * zoom, 2.5f, 1.f, Color(230.f / 255.f, 176.f / 255.f, 170.f / 255.f).Transparent(.3f)); 198 | 199 | if(showArrivalDistance) 200 | { 201 | RingShader::Draw(-center * zoom, currentSystem->ExtraHyperArrivalDistance() * zoom, 2.5f, 1.f, Color(243.f / 255.f, 156.f / 255.f, 18.f / 255.f).Transparent(.3f)); 202 | RingShader::Draw(-center * zoom, currentSystem->ExtraJumpArrivalDistance() * zoom, 2.5f, 1.f, Color(222.f / 255.f, 49.f / 255.f, 99.f / 255.f).Transparent(.3f)); 203 | } 204 | draw.Draw(); 205 | batchDraw.Draw(); 206 | } 207 | 208 | 209 | 210 | bool MainEditorPanel::AllowsFastForward() const noexcept 211 | { 212 | return true; 213 | } 214 | 215 | 216 | 217 | const System *MainEditorPanel::Selected() const 218 | { 219 | return currentSystem; 220 | } 221 | 222 | 223 | 224 | void MainEditorPanel::DeselectObject() 225 | { 226 | currentObject = nullptr; 227 | } 228 | 229 | 230 | 231 | void MainEditorPanel::SelectObject(const StellarObject &stellar) 232 | { 233 | currentObject = &stellar; 234 | } 235 | 236 | 237 | 238 | bool MainEditorPanel::KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) 239 | { 240 | if(command.Has(Command::MAP) || key == 'd' || key == SDLK_ESCAPE 241 | || (key == 'w' && (mod & (KMOD_CTRL | KMOD_GUI)))) 242 | GetUI()->Pop(this); 243 | else if(key == SDLK_PLUS || key == SDLK_KP_PLUS || key == SDLK_EQUALS) 244 | ZoomViewIn(); 245 | else if(key == SDLK_MINUS || key == SDLK_KP_MINUS) 246 | ZoomViewOut(); 247 | else if(key == SDLK_DELETE && currentObject) 248 | systemEditor->Delete(*currentObject, true); 249 | else if(key == 'r' && (mod & KMOD_CTRL)) 250 | systemEditor->RandomizeAll(); 251 | else if(key == SDLK_SPACE) 252 | paused = !paused; 253 | else 254 | return false; 255 | 256 | return true; 257 | } 258 | 259 | 260 | 261 | bool MainEditorPanel::Click(int x, int y, int clicks) 262 | { 263 | // Figure out if a system was clicked on. 264 | click = Point(x, y) / zoom + center; 265 | if(!currentSystem || !currentSystem->IsValid()) 266 | return false; 267 | double dist = numeric_limits::max(); 268 | const StellarObject *selected = nullptr; 269 | for(const auto &it : currentSystem->Objects()) 270 | { 271 | const double clickDist = click.Distance(it.Position()); 272 | if(clickDist < it.RealRadius() && clickDist < dist) 273 | { 274 | dist = clickDist; 275 | selected = ⁢ 276 | } 277 | } 278 | if(selected) 279 | { 280 | currentObject = selected; 281 | systemEditor->Select(currentObject); 282 | if(currentObject->planet) 283 | planetEditor->Select(currentObject->planet); 284 | moveStellars = true; 285 | return true; 286 | } 287 | 288 | systemEditor->Select(currentObject = nullptr); 289 | moveStellars = false; 290 | return true; 291 | } 292 | 293 | 294 | 295 | bool MainEditorPanel::Drag(double dx, double dy) 296 | { 297 | isDragging = true; 298 | if(moveStellars && currentObject) 299 | { 300 | click += Point(dx, dy) / zoom; 301 | auto dragCenter = currentObject->parent == -1 ? Point() 302 | : currentSystem->objects[currentObject->parent].position; 303 | systemEditor->UpdateStellarPosition(*currentObject, click - dragCenter, currentSystem); 304 | } 305 | else 306 | center -= Point(dx, dy) / zoom; 307 | 308 | return true; 309 | } 310 | 311 | 312 | 313 | bool MainEditorPanel::Scroll(double dx, double dy) 314 | { 315 | if(dy < 0.) 316 | ZoomViewOut(); 317 | else if(dy > 0.) 318 | ZoomViewIn(); 319 | mouse = UI::GetMouse(); 320 | return true; 321 | } 322 | 323 | 324 | 325 | bool MainEditorPanel::Release(int x, int y) 326 | { 327 | // Figure out if a system was clicked on, but 328 | // only if we didn't move the systems. 329 | if(isDragging) 330 | { 331 | isDragging = false; 332 | moveStellars = false; 333 | return true; 334 | } 335 | 336 | return true; 337 | } 338 | 339 | 340 | 341 | void MainEditorPanel::Select(const System *system) 342 | { 343 | if(!system) 344 | return; 345 | currentSystem = system; 346 | currentObject = nullptr; 347 | UpdateCache(); 348 | } 349 | 350 | 351 | 352 | void MainEditorPanel::UpdateSystem() 353 | { 354 | if(!paused) 355 | date += timeIncrement; 356 | double now = date / 60.; 357 | auto &objects = const_cast(currentSystem)->objects; 358 | for(StellarObject &object : objects) 359 | { 360 | // "offset" is used to allow binary orbits; the second object is offset 361 | // by 180 degrees. 362 | object.angle = Angle(now * object.speed + object.offset); 363 | object.position = object.angle.Unit() * object.distance; 364 | 365 | // Because of the order of the vector, the parent's position has always 366 | // been updated before this loop reaches any of its children, so: 367 | if(object.parent >= 0) 368 | object.position += objects[object.parent].position; 369 | 370 | if(object.position) 371 | object.angle = Angle(object.position); 372 | } 373 | } 374 | 375 | 376 | 377 | void MainEditorPanel::UpdateCache() 378 | { 379 | asteroids.Clear(); 380 | for(const System::Asteroid &a : currentSystem->Asteroids()) 381 | { 382 | // Check whether this is a minable or an ordinary asteroid. 383 | if(a.Type()) 384 | asteroids.Add(a.Type(), a.Count(), a.Energy(), currentSystem->AsteroidBelts()); 385 | else 386 | asteroids.Add(a.Name(), a.Count(), a.Energy()); 387 | } 388 | 389 | GameData::SetHaze(currentSystem->Haze(), false); 390 | } 391 | 392 | 393 | 394 | double MainEditorPanel::ViewZoom() const 395 | { 396 | return ZOOMS[zoomIndex]; 397 | } 398 | 399 | 400 | 401 | void MainEditorPanel::ZoomViewIn() 402 | { 403 | if(zoomIndex < SIZE - 1) 404 | ++zoomIndex; 405 | } 406 | 407 | 408 | 409 | void MainEditorPanel::ZoomViewOut() 410 | { 411 | if(zoomIndex > 0) 412 | --zoomIndex; 413 | } 414 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | include(CMakeDependentOption) 4 | cmake_dependent_option(ES_GLES "Build the game with OpenGL ES" OFF UNIX OFF) 5 | 6 | # Support Debug and Release configurations. 7 | set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" CACHE STRING "" FORCE) 8 | 9 | # Use C++17 without any compiler specific extensions. 10 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "") 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | set(CMAKE_CXX_EXTENSIONS OFF) 13 | # Use LTO for Release builds only. 14 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_DEBUG FALSE) 15 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) 16 | # On Linux use relative RPATH. 17 | set(CMAKE_BUILD_RPATH_USE_ORIGIN ON) 18 | 19 | # Add our overlays for vcpkg and setup vcpkg. 20 | set(VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/overlays") 21 | set(VCPKG_OVERLAY_PORTS "${CMAKE_CURRENT_SOURCE_DIR}/overlays") 22 | set(VCPKG_BOOTSTRAP_OPTIONS "-disableMetrics") 23 | set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) 24 | set(X_VCPKG_APPLOCAL_DEPS_INSTALL ON) 25 | set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake" 26 | CACHE STRING "Vcpkg toolchain file" FORCE) 27 | 28 | project("Editor" VERSION 0.9.15 29 | DESCRIPTION "Unofficial plugin editor for Endless Sky" 30 | HOMEPAGE_URL https://github.com/quyykk/plugin-editor 31 | LANGUAGES CXX) 32 | 33 | string(TIMESTAMP EDITOR_CURRENT_DATE "%d %b %Y") 34 | configure_file("./source/Version.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/source/Version.h" @ONLY) 35 | 36 | # Find the needed library dependencies. 37 | find_package(SDL2 CONFIG REQUIRED) 38 | find_package(PNG REQUIRED) 39 | find_package(JPEG REQUIRED) 40 | find_package(rapidfuzz CONFIG REQUIRED) 41 | find_package(glad CONFIG REQUIRED) 42 | 43 | # Only very new versions of OpenAL provide a config package, so try to find it manually. 44 | find_package(OpenAL CONFIG QUIET) 45 | if(NOT OpenAL_FOUND) 46 | find_library(OPENAL openal REQUIRED) 47 | add_library(OpenAL UNKNOWN IMPORTED) 48 | add_library(OpenAL::OpenAL ALIAS OpenAL) 49 | set_target_properties(OpenAL PROPERTIES IMPORTED_LOCATION ${OPENAL}) 50 | endif() 51 | 52 | # libmad doesn't provide native cmake support. 53 | find_path(LIBMAD_INCLUDE_DIR mad.h) 54 | find_library(LIBMAD_LIB_DEBUG NAMES mad libmad NAMES_PER_DIR PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib") 55 | find_library(LIBMAD_LIB_RELEASE NAMES mad libmad NAMES_PER_DIR PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib") 56 | 57 | # Libraries that aren't distributed in distros. 58 | find_package(imgui CONFIG REQUIRED) 59 | # nativefiledialog-extended doesn't provide native cmake support. 60 | find_path(NFDE_INCLUDE_DIR nfd.h) 61 | find_library(NFDE_LIB_DEBUG NAMES nfd NAMES_PER_DIR PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" NO_DEFAULT_PATH) 62 | find_library(NFDE_LIB_RELEASE NAMES nfd NAMES_PER_DIR PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" NO_DEFAULT_PATH) 63 | 64 | # Create game target. 65 | if(APPLE) 66 | add_executable(Editor MACOSX_BUNDLE source/main.cpp) 67 | 68 | # MacOS bundles are a bit special and need every resource specified when 69 | # creating the executable. 70 | foreach(folder "data" "images" "sounds") 71 | file(GLOB_RECURSE RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/endless-sky/${folder}/*") 72 | target_sources(Editor PRIVATE ${RESOURCES}) 73 | 74 | foreach(FILE ${RESOURCES}) 75 | # Get the relative path from the root folder to the current file. 76 | file(RELATIVE_PATH NEW_FILE "${CMAKE_CURRENT_SOURCE_DIR}/endless-sky" ${FILE}) 77 | # Get the parent directory for the new location. 78 | get_filename_component(FILE_PATH ${NEW_FILE} DIRECTORY) 79 | 80 | # Resources belong under Resources/. 81 | set_source_files_properties(${FILE} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/${FILE_PATH}") 82 | endforeach() 83 | endforeach() 84 | 85 | # Create the icns file, required for the bundle icon. 86 | add_custom_command( 87 | OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/resources/editor.icns 88 | COMMAND iconutil -c icns -o resources/editor.icns resources/editor.iconset 89 | DEPENDS resources/editor.iconset/icon_16x16.png resources/editor.iconset/icon_16x16@2x.png 90 | resources/editor.iconset/icon_32x32.png resources/editor.iconset/icon_32x32@2x.png 91 | resources/editor.iconset/icon_128x128.png resources/editor.iconset/icon_128x128@2x.png 92 | resources/editor.iconset/icon_256x256.png resources/editor.iconset/icon_256x256@2x.png 93 | resources/editor.iconset/icon_512x512.png resources/editor.iconset/icon_512x512@2x.png 94 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 95 | 96 | # Now do the same to standone files. 97 | foreach(file "endless-sky/license.txt" "endless-sky/keys.txt" "endless-sky/credits.txt" "endless-sky/copyright" "endless-sky/changelog" "resources/editor.icns") 98 | target_sources(Editor PRIVATE ${file}) 99 | set_source_files_properties(${file} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/") 100 | endforeach() 101 | 102 | # Add plist to bundle. 103 | set_target_properties(Editor PROPERTIES 104 | MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_LIST_DIR}/resources/Editor-Info.plist.in 105 | XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME editor) 106 | elseif(WIN32) 107 | add_executable(Editor WIN32 source/main.cpp) 108 | target_sources(Editor PRIVATE source/WinApp.rc) 109 | else() 110 | add_executable(Editor source/main.cpp) 111 | endif() 112 | 113 | # Add the source files to the target. 114 | add_subdirectory(source) 115 | target_include_directories(Editor PRIVATE endless-sky/source source/) 116 | 117 | # The 'mingw32' lib needs to appear first. 118 | if(MINGW) 119 | target_link_libraries(Editor PRIVATE mingw32) 120 | 121 | # On Windows copy the MinGW runtime DLLs to the output folder as well. 122 | # This is to avoid the situation where a user has other MinGW runtime DLLs 123 | # in their PATH that are incompatible with the MinGW used to compile ES. 124 | if(WIN32) 125 | get_filename_component(PARENT_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) 126 | get_filename_component(MINGW_RUNTIME_DIR ${PARENT_DIR} DIRECTORY) 127 | 128 | # MinGW doesn't have seh exceptions support for 32-bit Windows unfortunately, 129 | # and requires libgcc_s_dw2-1.dll instead of libgcc_s_seh-1.dll. There's no 130 | # perfect way to figure out which one to copy, so we simply copy both. 131 | # The executable will choose the correct DLL anyways. 132 | foreach(lib "stdc++-6" "winpthread-1" "gcc_s_seh-1" "gcc_s_dw2-1") 133 | file(GLOB_RECURSE FILE_PATH "${MINGW_RUNTIME_DIR}/lib${lib}.dll") 134 | if(FILE_PATH) 135 | add_custom_command(TARGET Editor POST_BUILD 136 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FILE_PATH} $ 137 | COMMAND_EXPAND_LISTS) 138 | 139 | # Add an install rule for this DLLs, so that it is also included when installing. 140 | install(FILES ${FILE_PATH} DESTINATION .) 141 | endif() 142 | endforeach() 143 | endif() 144 | endif() 145 | 146 | # Link with the library dependencies. 147 | target_link_libraries(Editor PRIVATE SDL2::SDL2main) 148 | 149 | target_include_directories(Editor PUBLIC ${LIBMAD_INCLUDE_DIR} ${NFDE_INCLUDE_DIR}) 150 | target_link_libraries(Editor PRIVATE SDL2::SDL2 PNG::PNG JPEG::JPEG OpenAL::OpenAL imgui::imgui 151 | rapidfuzz::rapidfuzz 152 | $,${LIBMAD_LIB_DEBUG},${LIBMAD_LIB_RELEASE}> 153 | $,${NFDE_LIB_DEBUG},${NFDE_LIB_RELEASE}>) 154 | 155 | target_include_directories(Editor PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/endless-sky/source") 156 | 157 | # Link the needed OS-specific dependencies, if any. 158 | if(WIN32) 159 | target_link_libraries(Editor PUBLIC rpcrt4 Winmm) 160 | elseif(UNIX AND NOT APPLE) 161 | target_link_libraries(Editor PUBLIC pthread dbus-1 ${CMAKE_DL_LIBS}) 162 | endif() 163 | 164 | # Link with the UUID library, which is different for each OS. 165 | if(UNIX) 166 | if(APPLE) 167 | find_library(UUID_LIB NAMES System PATHS /lib /usr/lib /usr/local/lib) 168 | find_path(UUID_INCLUDE uuid/uuid.h /usr/local/include /usr/include) 169 | target_link_libraries(Editor PUBLIC ${UUID_LIB}) 170 | target_include_directories(Editor PUBLIC ${UUID_INCLUDE}) 171 | else() 172 | find_package(unofficial-libuuid CONFIG REQUIRED) 173 | target_link_libraries(Editor PUBLIC unofficial::UUID::uuid) 174 | endif() 175 | endif() 176 | 177 | # Use OpenGL or OpenGL ES. 178 | if(ES_GLES) 179 | find_package(OpenGL REQUIRED OpenGL EGL) 180 | target_link_libraries(Editor PRIVATE OpenGL::OpenGL OpenGL::EGL) 181 | target_compile_definitions(Editor PUBLIC ES_GLES) 182 | else() 183 | find_package(OpenGL REQUIRED) 184 | target_link_libraries(Editor PRIVATE OpenGL::GL glad::glad) 185 | 186 | if(APPLE) 187 | # Apple deprecated OpenGL in MacOS 10.14, but we don't care. 188 | target_compile_definitions(Editor PUBLIC GL_SILENCE_DEPRECATION) 189 | elseif(UNIX) 190 | # For GLX support on Linux. 191 | target_link_libraries(Editor PRIVATE X11) 192 | endif() 193 | endif() 194 | 195 | # Set the appropriate compiler flags. 196 | if(MSVC) 197 | target_compile_options(Editor PUBLIC "/W3" "/permissive-" "/Gm-" "/sdl" "/MP" "/analyze-" 198 | "-Wno-nonportable-include-path" "$<$:/Gy;/WX;/Oi>") 199 | target_compile_definitions(Editor PUBLIC "_UNICODE" "UNICODE" "$,_DEBUG,NDEBUG>") 200 | else() 201 | target_compile_options(Editor PUBLIC "-Wall" "$<$:-Werror>") 202 | endif() 203 | 204 | # Various helpful options for IDEs. 205 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 206 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Editor) 207 | set_property(TARGET Editor PROPERTY VS_JUST_MY_CODE_DEBUGGING ON) 208 | 209 | # Installation configurations. 210 | if(APPLE) 211 | install(TARGETS Editor CONFIGURATIONS Release BUNDLE DESTINATION .) 212 | elseif(WIN32) 213 | # Install the binary. 214 | install(TARGETS Editor CONFIGURATIONS Release RUNTIME DESTINATION .) 215 | 216 | # The MinGW DLLs needed were already installed above, and vcpkg installs the library DLLs. 217 | 218 | # Install the resouce files. 219 | install(DIRECTORY endless-sky/data DESTINATION .) 220 | install(DIRECTORY endless-sky/images DESTINATION .) 221 | install(DIRECTORY endless-sky/sounds DESTINATION .) 222 | install(FILES endless-sky/credits.txt DESTINATION .) 223 | install(FILES endless-sky/keys.txt DESTINATION .) 224 | install(FILES endless-sky/copyright DESTINATION .) 225 | install(FILES endless-sky/changelog DESTINATION .) 226 | elseif(UNIX) 227 | # Use lowercase target name on Linux. 228 | set_target_properties(Editor PROPERTIES OUTPUT_NAME "editor") 229 | 230 | # Install the binary. 231 | install(TARGETS Editor CONFIGURATIONS Release RUNTIME DESTINATION games) 232 | 233 | # Install the desktop file. 234 | install(FILES resources/editor.desktop DESTINATION share/applications) 235 | 236 | # Install app center metadata. 237 | install(FILES resources/io.github.quyykk.editor.appdata.xml DESTINATION share/metainfo) 238 | 239 | # Install icons, keeping track of all the paths. 240 | # Most Ubuntu apps supply 16, 22, 24, 32, 48, and 256, and sometimes others. 241 | foreach(size "16x16" "22x22" "24x24" "32x32" "48x48" "128x128" "256x256" "512x512") 242 | install(FILES "resources/icons/icon_${size}.png" DESTINATION "share/icons/hicolor/${size}/apps" 243 | RENAME editor.png) 244 | endforeach() 245 | 246 | # Install the resouce files. 247 | install(DIRECTORY endless-sky/data DESTINATION share/games/editor) 248 | install(DIRECTORY endless-sky/images DESTINATION share/games/editor) 249 | install(DIRECTORY endless-sky/sounds DESTINATION share/games/editor) 250 | install(FILES endless-sky/credits.txt DESTINATION share/games/editor) 251 | install(FILES endless-sky/keys.txt DESTINATION share/games/editor) 252 | install(FILES endless-sky/copyright DESTINATION share/doc/editor) 253 | install(FILES endless-sky/changelog DESTINATION share/doc/editor) 254 | endif() 255 | -------------------------------------------------------------------------------- /source/TemplateEditor.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | #ifndef TEMPLATE_EDITOR_H_ 4 | #define TEMPLATE_EDITOR_H_ 5 | 6 | #include "Body.h" 7 | #include "DataWriter.h" 8 | #include "Effect.h" 9 | #include "Fleet.h" 10 | #include "GameData.h" 11 | #include "Government.h" 12 | #include "Minable.h" 13 | #include "RandomEvent.h" 14 | #include "Sound.h" 15 | #include "Sprite.h" 16 | #include "System.h" 17 | #include "WeightedList.h" 18 | #include "imgui.h" 19 | #include "imgui_ex.h" 20 | #include "imgui_stdlib.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | class Editor; 34 | 35 | 36 | 37 | template constexpr const char *defaultFileFor() = delete; 38 | template <> constexpr const char *defaultFileFor() { return "effects.txt"; } 39 | template <> constexpr const char *defaultFileFor() { return "fleets.txt"; } 40 | template <> constexpr const char *defaultFileFor() { return "map.txt"; } 41 | template <> constexpr const char *defaultFileFor() { return "hazards.txt"; } 42 | template <> constexpr const char *defaultFileFor() { return "governments.txt"; } 43 | template <> constexpr const char *defaultFileFor() { return "outfits.txt"; } 44 | template <> constexpr const char *defaultFileFor>() { return "outfitters.txt"; } 45 | template <> constexpr const char *defaultFileFor() { return "map.txt"; } 46 | template <> constexpr const char *defaultFileFor() { return "ships.txt"; } 47 | template <> constexpr const char *defaultFileFor>() { return "shipyards.txt"; } 48 | template <> constexpr const char *defaultFileFor() { return "map.txt"; } 49 | 50 | namespace impl { 51 | template 52 | std::string GetName(const T &obj, ...) { return obj.Name(); } 53 | template 54 | std::string GetName(const T &obj, decltype(std::declval().TrueName(), int()) *) { return obj.TrueName(); } 55 | } 56 | template 57 | std::string GetName(const T &obj) { return impl::GetName(obj, 0); } 58 | 59 | // Base class common for any editor window. 60 | template 61 | class TemplateEditor { 62 | public: 63 | TemplateEditor(Editor &editor, bool &show) noexcept 64 | : editor(editor), show(show) {} 65 | TemplateEditor(const TemplateEditor &) = delete; 66 | TemplateEditor& operator=(const TemplateEditor &) = delete; 67 | 68 | void Clear(); 69 | 70 | 71 | protected: 72 | // Marks the current object as dirty. 73 | void SetDirty(); 74 | void SetDirty(const T *obj); 75 | 76 | void RenderSprites(const std::string &name, std::vector> &map); 77 | bool RenderElement(Body *sprite, const std::string &name, const std::function &spriteFilter = {}); 78 | void RenderSound(const std::string &name, std::map &map); 79 | void RenderEffect(const std::string &name, std::map &map); 80 | void RenderEffect(const std::string &name, std::map &map); 81 | 82 | 83 | protected: 84 | Editor &editor; 85 | bool &show; 86 | 87 | std::string searchBox; 88 | T *object = nullptr; 89 | }; 90 | 91 | 92 | extern template class TemplateEditor; 93 | extern template class TemplateEditor; 94 | extern template class TemplateEditor; 95 | extern template class TemplateEditor; 96 | extern template class TemplateEditor; 97 | extern template class TemplateEditor; 98 | extern template class TemplateEditor>; 99 | extern template class TemplateEditor; 100 | extern template class TemplateEditor; 101 | extern template class TemplateEditor>; 102 | extern template class TemplateEditor; 103 | 104 | 105 | inline const std::string &NameFor(const std::string &obj) { return obj; } 106 | inline const std::string &NameFor(const std::string *obj) { return *obj; } 107 | template 108 | const std::string &NameFor(const T &obj) { return obj.Name(); } 109 | template 110 | const std::string &NameFor(const T *obj) { return obj->Name(); } 111 | template 112 | std::string NameFor(const std::pair &obj) { return obj.first; } 113 | inline const std::string &NameFor(const System::Asteroid &obj) { return obj.Type() ? obj.Type()->TrueName() : obj.Name(); } 114 | inline std::string NameFor(const Government::RaidFleet &obj) { return obj.GetFleet() ? obj.GetFleet()->Name() : ""; } 115 | inline std::string NameFor(const Government::RaidFleet *obj) { return obj->GetFleet() ? obj->GetFleet()->Name() : ""; } 116 | inline std::string NameFor(double d) { 117 | std::ostringstream stream; 118 | stream << std::fixed << std::setprecision(3) << d; 119 | std::string str = std::move(stream).str(); 120 | 121 | // Remove any trailing digits. 122 | while(str.back() == '0') 123 | str.pop_back(); 124 | 125 | // Remove trailing dot. 126 | if(str.back() == '.') 127 | str.pop_back(); 128 | return str; 129 | } 130 | template 131 | std::string NameFor(const WeightedItem &item) { return NameFor(item.item); } 132 | template 133 | std::string NameFor(const WeightedItem *item) { return NameFor(item->item); } 134 | 135 | template 136 | bool Count(const std::set &container, const T &obj) { return container.count(obj); } 137 | template 138 | bool Count(const std::vector &container, const T &obj) { return std::find(container.begin(), container.end(), obj) != container.end(); } 139 | template 140 | bool Count(const WeightedList &list, const U &obj) { return std::find(list.begin(), list.end(), obj) != list.end(); } 141 | 142 | template 143 | void Insert(std::set &container, const T &obj) { container.insert(obj); } 144 | template 145 | void Insert(std::vector &container, const T &obj) { container.push_back(obj); } 146 | template 147 | void Insert(WeightedList &container, const U &obj) { container.emplace_back(obj.weight, obj.item); } 148 | 149 | template 150 | void AdditionalCalls(DataWriter &writer, const T &obj) {} 151 | inline void AdditionalCalls(DataWriter &writer, const System::Asteroid &obj) 152 | { 153 | writer.WriteToken(obj.Count()); 154 | writer.WriteToken(obj.Energy()); 155 | } 156 | inline void AdditionalCalls(DataWriter &writer, const RandomEvent &obj) 157 | { 158 | writer.WriteToken(obj.Period()); 159 | } 160 | inline void AdditionalCalls(DataWriter &writer, const RandomEvent &obj) 161 | { 162 | writer.WriteToken(obj.Period()); 163 | } 164 | template 165 | inline void AdditionalCalls(DataWriter &writer, const WeightedItem &item) 166 | { 167 | if(item.weight != 1) 168 | writer.WriteToken(item.weight); 169 | } 170 | 171 | template 172 | void WriteDiff(DataWriter &writer, const char *name, const C &orig, const C *diff, bool onOneLine = false, bool allowRemoving = true, bool implicitAdd = false, bool sorted = false) 173 | { 174 | auto writeRaw = onOneLine 175 | ? [](DataWriter &writer, const char *name, const C &list, bool sorted) 176 | { 177 | writer.WriteToken(name); 178 | if(sorted) 179 | WriteSorted(list, [](const auto *lhs, const auto *rhs) { return NameFor(lhs) < NameFor(rhs); }, 180 | [&writer](const auto &element) 181 | { 182 | writer.WriteToken(NameFor(element)); 183 | AdditionalCalls(writer, element); 184 | }); 185 | else 186 | for(auto &&it : list) 187 | { 188 | writer.WriteToken(NameFor(it)); 189 | AdditionalCalls(writer, it); 190 | } 191 | writer.Write(); 192 | } 193 | : [](DataWriter &writer, const char *name, const C &list, bool sorted) 194 | { 195 | if(sorted) 196 | WriteSorted(list, [](const auto *lhs, const auto *rhs) { return NameFor(lhs) < NameFor(rhs); }, 197 | [&writer, &name](const auto &element) 198 | { 199 | writer.WriteToken(name); 200 | writer.WriteToken(NameFor(element)); 201 | AdditionalCalls(writer, element); 202 | writer.Write(); 203 | }); 204 | else 205 | for(auto &&it : list) 206 | { 207 | writer.WriteToken(name); 208 | writer.WriteToken(NameFor(it)); 209 | AdditionalCalls(writer, it); 210 | writer.Write(); 211 | } 212 | }; 213 | auto writeAdd = onOneLine 214 | ? [](DataWriter &writer, const char *name, const C &list, bool sorted) 215 | { 216 | writer.WriteToken("add"); 217 | writer.WriteToken(name); 218 | if(sorted) 219 | WriteSorted(list, [](const auto *lhs, const auto *rhs) { return NameFor(lhs) < NameFor(rhs); }, 220 | [&writer](const auto &element) 221 | { 222 | writer.WriteToken(NameFor(element)); 223 | AdditionalCalls(writer, element); 224 | }); 225 | else 226 | for(auto &&it : list) 227 | { 228 | writer.WriteToken(NameFor(it)); 229 | AdditionalCalls(writer, it); 230 | } 231 | writer.Write(); 232 | } 233 | : [](DataWriter &writer, const char *name, const C &list, bool sorted) 234 | { 235 | if(sorted) 236 | WriteSorted(list, [](const auto *lhs, const auto *rhs) { return NameFor(lhs) < NameFor(rhs); }, 237 | [&writer, &name](const auto &element) 238 | { 239 | writer.WriteToken("add"); 240 | writer.WriteToken(name); 241 | writer.WriteToken(NameFor(element)); 242 | AdditionalCalls(writer, element); 243 | writer.Write(); 244 | }); 245 | else 246 | for(auto &&it : list) 247 | { 248 | writer.WriteToken("add"); 249 | writer.WriteToken(name); 250 | writer.WriteToken(NameFor(it)); 251 | AdditionalCalls(writer, it); 252 | writer.Write(); 253 | } 254 | }; 255 | auto writeRemove = onOneLine 256 | ? [](DataWriter &writer, const char *name, const C &list, bool sorted) 257 | { 258 | writer.WriteToken("remove"); 259 | writer.WriteToken(name); 260 | if(sorted) 261 | WriteSorted(list, [](const auto *lhs, const auto *rhs) { return NameFor(lhs) < NameFor(rhs); }, 262 | [&writer](const auto &element) 263 | { 264 | writer.Write(NameFor(element)); 265 | }); 266 | else 267 | for(auto &&it : list) 268 | writer.WriteToken(NameFor(it)); 269 | writer.Write(); 270 | } 271 | : [](DataWriter &writer, const char *name, const C &list, bool sorted) 272 | { 273 | if(sorted) 274 | WriteSorted(list, [](const auto *lhs, const auto *rhs) { return NameFor(lhs) < NameFor(rhs); }, 275 | [&writer, &name](const auto &element) 276 | { 277 | writer.Write("remove", name, NameFor(element)); 278 | }); 279 | else 280 | for(auto &&it : list) 281 | writer.Write("remove", name, NameFor(it)); 282 | }; 283 | if(!diff) 284 | { 285 | if(!orig.empty()) 286 | writeRaw(writer, name, orig, sorted); 287 | return; 288 | } 289 | 290 | typename std::decay::type toAdd; 291 | auto toRemove = toAdd; 292 | 293 | for(auto &&it : orig) 294 | if(!Count(*diff, it)) 295 | Insert(toAdd, it); 296 | for(auto &&it : *diff) 297 | if(!Count(orig, it)) 298 | Insert(toRemove, it); 299 | 300 | if(toAdd.empty() && toRemove.empty()) 301 | return; 302 | 303 | if(toRemove.size() == diff->size() && !diff->empty()) 304 | { 305 | if(orig.empty()) 306 | writer.Write("remove", name); 307 | else 308 | writeRaw(writer, name, toAdd, sorted); 309 | } 310 | else if(allowRemoving) 311 | { 312 | if(!toAdd.empty()) 313 | { 314 | if(implicitAdd) 315 | writeRaw(writer, name, toAdd, sorted); 316 | else 317 | writeAdd(writer, name, toAdd, sorted); 318 | } 319 | if(!toRemove.empty()) 320 | writeRemove(writer, name, toRemove, sorted); 321 | } 322 | else if(!orig.empty()) 323 | writeRaw(writer, name, orig, sorted); 324 | } 325 | 326 | 327 | 328 | #endif 329 | --------------------------------------------------------------------------------