diff --git a/.github/workflows/macosx-ci.yml b/.github/workflows/macosx-ci.yml index d7b86776db..e38c9e3e6e 100644 --- a/.github/workflows/macosx-ci.yml +++ b/.github/workflows/macosx-ci.yml @@ -59,7 +59,7 @@ jobs: - name: Install environment helpers with homebrew run: brew install ccache - name: Install dependencies with homebrew - run: brew install libepoxy freetype fontconfig harfbuzz sdl2 sdl2_image opus opusfile qt6 libogg libpng toml11 eigen + run: brew install libepoxy freetype fontconfig harfbuzz opus opusfile qt6 libogg libpng toml11 eigen - name: Install nyan dependencies with homebrew run: brew install flex make - name: Install python3 packages diff --git a/.github/workflows/ubuntu-22.04.yml b/.github/workflows/ubuntu-22.04.yml index 3343df5506..b6eaa70230 100644 --- a/.github/workflows/ubuntu-22.04.yml +++ b/.github/workflows/ubuntu-22.04.yml @@ -32,7 +32,7 @@ jobs: run: mkdir -p /tmp/image shell: bash - name: Download devenv image - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: devenv-image-compressed.tar.gz path: '/tmp/image' diff --git a/.github/workflows/windows-server-2019.yml b/.github/workflows/windows-server-2019.yml index 93a9ecf867..7a2262c00f 100644 --- a/.github/workflows/windows-server-2019.yml +++ b/.github/workflows/windows-server-2019.yml @@ -24,7 +24,7 @@ jobs: mkdir download cd download $zipfile = "openage-dep-x64-windows.zip" - Invoke-WebRequest https://github.com/SFTtech/openage-dependencies/releases/download/v0.5.0/openage-dep-x64-windows.zip -OutFile $zipfile + Invoke-WebRequest https://github.com/SFTtech/openage-dependencies/releases/download/v0.5.1/openage-dep-x64-windows.zip -OutFile $zipfile Expand-Archive -Path $zipfile -DestinationPath . -Force Remove-Item $zipfile (Get-ChildItem . -Recurse -File).FullName diff --git a/.github/workflows/windows-server-2022.yml b/.github/workflows/windows-server-2022.yml index c4deba0d46..f0172b103e 100644 --- a/.github/workflows/windows-server-2022.yml +++ b/.github/workflows/windows-server-2022.yml @@ -24,7 +24,7 @@ jobs: mkdir download cd download $zipfile = "openage-dep-x64-windows.zip" - Invoke-WebRequest https://github.com/SFTtech/openage-dependencies/releases/download/v0.5.0/openage-dep-x64-windows.zip -OutFile $zipfile + Invoke-WebRequest https://github.com/SFTtech/openage-dependencies/releases/download/v0.5.1/openage-dep-x64-windows.zip -OutFile $zipfile Expand-Archive -Path $zipfile -DestinationPath . -Force Remove-Item $zipfile (Get-ChildItem . -Recurse -File).FullName diff --git a/README.md b/README.md index 00d3715d85..db9b9a4a82 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Quickstart ``` * **I compiled everything. Now how do I run it?** - * Execute `./bin/run`. + * Execute `cd bin && ./run main`. * [The convert script](/doc/media_convert.md) will transform original assets into openage formats, which are a lot saner and more moddable. * Use your brain and react to the things you'll see. diff --git a/assets/test/textures/test_animation.sprite b/assets/test/textures/test_animation.sprite index 26481ff896..9f96f91b65 100644 --- a/assets/test/textures/test_animation.sprite +++ b/assets/test/textures/test_animation.sprite @@ -5,7 +5,7 @@ version 2 texture 0 "test_texture.texture" -scalefactor 1 +scalefactor 1.0 layer 0 mode=loop position=20 time_per_frame=0.125 diff --git a/assets/test/textures/test_missing.sprite b/assets/test/textures/test_missing.sprite index 00a166e27f..84b7b66676 100644 --- a/assets/test/textures/test_missing.sprite +++ b/assets/test/textures/test_missing.sprite @@ -5,7 +5,7 @@ version 2 texture 0 "test_missing.texture" -scalefactor 1 +scalefactor 1.0 layer 0 mode=once diff --git a/assets/test/textures/test_terrain.terrain b/assets/test/textures/test_terrain.terrain index bbcc8dcd7c..7588a69194 100644 --- a/assets/test/textures/test_terrain.terrain +++ b/assets/test/textures/test_terrain.terrain @@ -5,7 +5,7 @@ version 2 texture 0 "test_terrain.texture" -scalefactor 1 +scalefactor 1.0 layer 0 diff --git a/buildsystem/modules/FindSDL2Image.cmake b/buildsystem/modules/FindSDL2Image.cmake deleted file mode 100644 index 74b36be8ba..0000000000 --- a/buildsystem/modules/FindSDL2Image.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2014-2017 the openage authors. See copying.md for legal info. - -find_package(PackageHandleStandardArgs) - -if(APPLE) - find_library(SDL2IMAGE_LIBRARIES SDL2_image DOC "SDL2 library framework for MacOS X") - find_path(SDL2IMAGE_INCLUDE_DIRS SDL_image.h - HINTS - $ENV{SDL2DIR} - PATH_SUFFIXES include/SDL2 include - PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local/include/SDL2 - /usr/include/SDL2 - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt - DOC "Include directory for SDL2_image under MacOS X" - ) -else() - find_library(SDL2IMAGE_LIBRARIES SDL2_image DOC "SDL2 library") - find_path(SDL2IMAGE_INCLUDE_DIRS SDL2/SDL_image.h DOC "Include directory for SDL2_image") -endif() - -# handle the QUIETLY and REQUIRED arguments and set SDL2Image_FOUND to TRUE if -# all listed variables are TRUE -find_package_handle_standard_args(SDL2Image DEFAULT_MSG SDL2IMAGE_LIBRARIES) diff --git a/doc/build_instructions/arch_linux.md b/doc/build_instructions/arch_linux.md index 7665cb9888..9c42ff64fd 100644 --- a/doc/build_instructions/arch_linux.md +++ b/doc/build_instructions/arch_linux.md @@ -4,7 +4,7 @@ This command should provide required packages from the Arch Linux repositories: -`sudo pacman -S --needed eigen python python-mako python-pillow python-numpy python-lz4 python-pygments cython libepoxy libogg libpng ttf-dejavu freetype2 fontconfig harfbuzz cmake sdl2 sdl2_image opusfile opus python-pylint python-toml qt6-declarative` +`sudo pacman -S --needed eigen python python-mako python-pillow python-numpy python-lz4 python-pygments cython libepoxy libogg libpng ttf-dejavu freetype2 fontconfig harfbuzz cmake opusfile opus python-pylint python-toml qt6-declarative qt6-multimedia` Additionally, you have to install [`toml11`](https://aur.archlinux.org/packages/toml11) from the AUR. If you have `yay`, you can run this command: diff --git a/doc/build_instructions/debian.md b/doc/build_instructions/debian.md index 5381ef165e..de74a192fc 100644 --- a/doc/build_instructions/debian.md +++ b/doc/build_instructions/debian.md @@ -1,6 +1,6 @@ # Prerequisite steps for Debian users - `sudo apt-get update` - - `sudo apt-get install cmake cython3 libeigen3-dev libepoxy-dev libfontconfig1-dev libfreetype-dev libharfbuzz-dev libogg-dev libopus-dev libopusfile-dev libpng-dev libsdl2-dev libsdl2-image-dev libtoml11-dev python3-dev python3-mako python3-numpy python3-lz4 python3-pil python3-pip python3-pygments python3-toml qml6-module-qtquick-controls qt6-declarative-dev` + - `sudo apt-get install cmake cython3 libeigen3-dev libepoxy-dev libfontconfig1-dev libfreetype-dev libharfbuzz-dev libogg-dev libopus-dev libopusfile-dev libpng-dev libtoml11-dev python3-dev python3-mako python3-numpy python3-lz4 python3-pil python3-pip python3-pygments python3-toml qml6-module-qtquick-controls qt6-declarative-dev qt6-multimedia-dev qml6-module-qtquick3d-spatialaudio` You will also need [nyan](https://github.com/SFTtech/nyan/blob/master/doc/building.md) and its dependencies. diff --git a/doc/build_instructions/fedora.md b/doc/build_instructions/fedora.md index c710a57282..e18e5f74c2 100644 --- a/doc/build_instructions/fedora.md +++ b/doc/build_instructions/fedora.md @@ -2,6 +2,6 @@ Run the following command: -`sudo dnf install clang cmake eigen3-devel fontconfig-devel gcc-c harfbuzz-devel libepoxy-devel libogg-devel libopusenc-devel libpng-devel opusfile-devel python3-Cython python3-devel python3-mako python3-numpy python3-lz4 python3-pillow python3-pygments python3-toml SDL2-devel SDL2_image-devel++ toml11-devel qt6-qtdeclarative-devel` +`sudo dnf install clang cmake eigen3-devel fontconfig-devel gcc-c harfbuzz-devel libepoxy-devel libogg-devel libopusenc-devel libpng-devel opusfile-devel python3-Cython python3-devel python3-mako python3-numpy python3-lz4 python3-pillow python3-pygments python3-toml toml11-devel qt6-qtdeclarative-devel qt6-qtmultimedia-devel` You will also need [nyan](https://github.com/SFTtech/nyan/blob/master/doc/building.md) and its dependencies. diff --git a/doc/build_instructions/freebsd.md b/doc/build_instructions/freebsd.md index b52d7e6177..fb53e1e9e2 100644 --- a/doc/build_instructions/freebsd.md +++ b/doc/build_instructions/freebsd.md @@ -2,7 +2,7 @@ This command should provide required packages for FreeBSD installation: -`sudo pkg install cmake cython eigen3 harfbuzz opus-tools opusfile png py-mako py-numpy py-lz4 py-pillow py-pygments py-toml pylint python qt6 sdl2 sdl2_image toml11` +`sudo pkg install cmake cython eigen3 harfbuzz opus-tools opusfile png py-mako py-numpy py-lz4 py-pillow py-pygments py-toml pylint python qt6 toml11` You will also need [nyan](https://github.com/SFTtech/nyan/blob/master/doc/building.md) and its dependencies. diff --git a/doc/build_instructions/macos.md b/doc/build_instructions/macos.md index ffe6e64f67..ba139c3b12 100644 --- a/doc/build_instructions/macos.md +++ b/doc/build_instructions/macos.md @@ -8,7 +8,7 @@ brew update-reset && brew update brew tap homebrew/cask-fonts brew install font-dejavu -brew install cmake python3 libepoxy freetype fontconfig harfbuzz sdl2 sdl2_image opus opusfile qt6 libogg libpng toml11 eigen +brew install cmake python3 libepoxy freetype fontconfig harfbuzz opus opusfile qt6 libogg libpng toml11 eigen brew install llvm pip3 install cython numpy mako lz4 pillow pygments toml diff --git a/doc/build_instructions/opensuse.md b/doc/build_instructions/opensuse.md index e2b51c41ef..8b967b1779 100644 --- a/doc/build_instructions/opensuse.md +++ b/doc/build_instructions/opensuse.md @@ -1,5 +1,5 @@ # Prerequisite steps for openSUSE users -- `zypper install --no-recommends cmake doxygen eigen3-devel fontconfig-devel gcc-c graphviz++ harfbuzz-devel libSDL2-devel libSDL2_image-devel libepoxy-devel libfreetype-dev libogg-devel libopus-devel libpng-devel libtoml11-dev libqt6-qtdeclarative-devel libqt6-qtquickcontrols opusfile-devel python3-Cython python3-Mako python3-lz4 python3-Pillow python3-Pygments python3-toml python3-devel` +- `zypper install --no-recommends cmake doxygen eigen3-devel fontconfig-devel gcc-c graphviz++ harfbuzz-devel libepoxy-devel libfreetype-dev libogg-devel libopus-devel libpng-devel libtoml11-dev qt6-declarative-dev qt6-quickcontrols2 qt6-multimedia-dev opusfile-devel python3-Cython python3-Mako python3-lz4 python3-Pillow python3-Pygments python3-toml python3-devel` You will also need [nyan](https://github.com/SFTtech/nyan/blob/master/doc/building.md) and its dependencies. diff --git a/doc/build_instructions/ubuntu.md b/doc/build_instructions/ubuntu.md index bc151975e2..08fc635abb 100644 --- a/doc/build_instructions/ubuntu.md +++ b/doc/build_instructions/ubuntu.md @@ -3,7 +3,7 @@ Run the following commands: - `sudo apt-get update` - - `sudo apt-get install g++ cmake cython3 libeigen3-dev libepoxy-dev libfontconfig1-dev libfreetype-dev libharfbuzz-dev libogg-dev libopus-dev libopusfile-dev libpng-dev libsdl2-dev libsdl2-image-dev libtoml11-dev python3-dev python3-mako python3-numpy python3-lz4 python3-pil python3-pip python3-pygments python3-toml qml6-module-qtquick-controls qt6-declarative-dev` + - `sudo apt-get install g++ cmake cython3 libeigen3-dev libepoxy-dev libfontconfig1-dev libfreetype-dev libharfbuzz-dev libogg-dev libopus-dev libopusfile-dev libpng-dev libtoml11-dev python3-dev python3-mako python3-numpy python3-lz4 python3-pil python3-pip python3-pygments python3-toml qml6-module-qtquick-controls qt6-declarative-dev qt6-multimedia-dev qml6-module-qtquick3d-spatialaudio` You will also need [nyan](https://github.com/SFTtech/nyan/blob/master/doc/building.md) and its dependencies. diff --git a/doc/build_instructions/windows_msvc.md b/doc/build_instructions/windows_msvc.md index 4c742e0e2c..5be6d9167c 100644 --- a/doc/build_instructions/windows_msvc.md +++ b/doc/build_instructions/windows_msvc.md @@ -45,7 +45,7 @@ _Note:_ Also ensure that `python` and `python3` both point to the correct and th ### vcpkg packages Set up [vcpkg](https://github.com/Microsoft/vcpkg#quick-start). Open a command prompt at `` - vcpkg install dirent eigen3 fontconfig freetype harfbuzz libepoxy libogg libpng opus opusfile qtbase qtdeclarative sdl2 sdl2-image toml11 + vcpkg install dirent eigen3 fontconfig freetype harfbuzz libepoxy libogg libpng opus opusfile qtbase qtdeclarative qtmultimedia toml11 _Note:_ The `qt6` port in vcpkg has been split into multiple packages, build times are acceptable now. If you want, you can still use [the prebuilt version](https://www.qt.io/download-open-source/) instead. diff --git a/doc/building.md b/doc/building.md index c5b8af6180..e7e0339d64 100644 --- a/doc/building.md +++ b/doc/building.md @@ -48,15 +48,13 @@ Dependency list: CR nyan (https://github.com/SFTtech/nyan) CR O ncurses C mako - CR sdl2 - CR sdl2_image CR opusfile CRA opus CRA ogg S pycodestyle C pygments S pylint - CR qt6 >=6.2 (Core, Quick, QuickControls modules) + CR qt6 >=6.2 (Core, Quick, QuickControls, Multimedia modules) CR toml11 CR O vulkan @@ -167,10 +165,10 @@ The reference package is [created for Gentoo](https://github.com/SFTtech/gentoo- - I wanna see compiler invocations - `make VERBOSE=1` -- My `SDL2_Image`/`Python`/whatever is installed somewhere, but `cmake` can't find it! +- My `Qt`/`Python`/whatever is installed somewhere, but `cmake` can't find it! - Run `ccmake` or `cmake-gui` in the build directory to see and change config variables. - You can manually tell `cmake` where to look. Try something along the lines of - - `./configure -- -DSDL2IMAGE_INCLUDE_DIRS=/whereever/sdl2_image/include/` + - `./configure -- -DPYTHON_INCLUDE_DIRS=/whereever/python/include/` - `-DPython3_EXECUTABLE=/your/py3/directory/` - I get compiler errors about missing header files diff --git a/doc/code/gui.md b/doc/code/gui.md index 6c548c2b65..3f1a4afb17 100644 --- a/doc/code/gui.md +++ b/doc/code/gui.md @@ -51,7 +51,7 @@ qmlRegisterType("yay.sfttech.openage", 1, 0, "ResourceAmount 2. Specializations `struct Wrap` and `struct Unwrap` must be defined: ```cpp -namespace qtsdl { +namespace qtgui { template<> struct Wrap { using Type = ResourceAmountLink; @@ -61,13 +61,13 @@ template<> struct Unwrap { using Type = ResourceAmount; }; -} // namespace qtsdl +} // namespace qtgui ``` 3. Also ResourceAmount needs a public member to be added: ```cpp public: - qtsdl::GuiItemLink *gui_link + qtgui::GuiItemLink *gui_link ``` 4. Declare and implement needed properties and signals in the `ResourceAmountLink` using Qt property syntax. @@ -78,7 +78,7 @@ There is a class `GeneratorParameters` in `libopenage/` directory. It has a big list of parameters of different types like `generation_seed`, `player_radius`, `player_names`, etc. So, we're not going to write a Qt property for each one: -1. `GeneratorParameters` must derive from the `qtsdl::GuiPropertyMap`. +1. `GeneratorParameters` must derive from the `qtgui::GuiPropertyMap`. 2. `GeneratorParameters` should set its initial values like so: ```cpp @@ -96,7 +96,7 @@ qmlRegisterType("yay.sfttech.openage", 1, 0, "Generator 4. Specializations `struct Wrap` and `struct Unwrap` must be defined: ```cpp -namespace qtsdl { +namespace qtgui { template<> struct Wrap { using Type = GeneratorParametersLink; @@ -106,7 +106,7 @@ template<> struct Unwrap { using Type = GeneratorParameters; }; -} // namespace qtsdl +} // namespace qtgui ``` That results into a `ListModel`-like QML type with `display` and `edit` roles. diff --git a/doc/code_style/mom.cpp b/doc/code_style/mom.cpp index 6655d0956d..ad2bb5d07d 100644 --- a/doc/code_style/mom.cpp +++ b/doc/code_style/mom.cpp @@ -17,13 +17,16 @@ // The associated header file comes first! #include "mom.h" -// System includes follow, sorted alphabetically +// C++ std library includes follow, sorted alphabetically #include #include #include -#include -// Local includes next, sorted alphabetically +// External libraries are next, sorted alphabetically +#include +#include + +// Local includes come last, sorted alphabetically #include "../valve.h" #include "half_life.h" #include "log/log.h" diff --git a/doc/troubleshooting.md b/doc/troubleshooting.md index 5ed9cc440a..a955eca018 100644 --- a/doc/troubleshooting.md +++ b/doc/troubleshooting.md @@ -26,18 +26,3 @@ A workaround would be to make a backup of your AGE2 directory and let the conver backup at subfolder `AGE2/resources` delete all files ***except*** folders. Another workaround would be to backup your AGE2 folder and redownload it to have a clean install. After conversion you can replace it with the backup. - -## Installation - -### Cannot specify compile definitions for target "SDL2::SDL2" which is not built by this project - -This error is specific to a few operating systems. The main cause is that your SDL2 version is too old and does not -include the necessary CMake files defining the target. There is an indepth discussion about this -[here](https://discourse.libsdl.org/t/how-is-sdl2-supposed-to-be-used-with-cmake/31275/16). -As a solution, you should update your SDL packages to SDL >=2.0.12 or **compile the latest SDL2 and SDL2-image from -source**. The latest version includes the necessary CMake files to expose the `SDL2::SDL2` target. - -## Building on Debian 12 -On Debian you might get an error saying that it couldn't find SDL2 library. This happens because the CMAKE prefix and SDL2 path are not set correctly. -The solution is to append at the end of the `./configure` command the cmake variables for both the prefix and SDL2 path, like so: -`./configure -- -DCMAKE_PREFIX_PATH=/usr -DSDL2_DIR=/usr/include/SDL2` (you can use `find` to look for the correct paths) diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index f1772bfc36..030231baf7 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -53,9 +53,6 @@ find_library(FONTCONFIG_LIB fontconfig) find_package(toml11 REQUIRED) find_package(Freetype REQUIRED) find_package(PNG REQUIRED) -find_package(SDL2 CONFIG REQUIRED) -target_compile_definitions(SDL2::SDL2 INTERFACE SDL_MAIN_HANDLED) -find_package(SDL2Image REQUIRED) find_package(Opusfile REQUIRED) find_package(Epoxy REQUIRED) find_package(HarfBuzz 1.0.0 REQUIRED) @@ -65,8 +62,7 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads REQUIRED) set(QT_VERSION_REQ "6.2") -find_package(Qt6Core ${QT_VERSION_REQ} REQUIRED) -find_package(Qt6Quick ${QT_VERSION_REQ} REQUIRED) +find_package(Qt6 ${QT_VERSION_REQ} REQUIRED COMPONENTS Core Quick Multimedia) if(WANT_BACKTRACE) find_package(GCCBacktrace) @@ -268,7 +264,6 @@ target_include_directories(libopenage ${EPOXY_INCLUDE_DIRS} ${OPUS_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS} - ${SDL2IMAGE_INCLUDE_DIRS} ${HarfBuzz_INCLUDE_DIRS} ${QTPLATFORM_INCLUDE_DIRS} ) @@ -292,14 +287,13 @@ target_link_libraries(libopenage ${FREETYPE_LIBRARIES} ${EPOXY_LIBRARIES} ${MATH_LIB} - ${SDL2IMAGE_LIBRARIES} - SDL2::SDL2 ${UTIL_LIB} ${HarfBuzz_LIBRARIES} ${RT_LIB} ${EXECINFO_LIB} Qt6::Core Qt6::Quick + Qt6::Multimedia ) ################################################## @@ -322,19 +316,14 @@ get_codegen_scu_file() # are specified above the source file list. add_sources(libopenage - handlers.cpp - legacy_engine.cpp main.cpp options.cpp - screenshot.cpp - texture.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.cpp ${CMAKE_CURRENT_BINARY_DIR}/version.cpp ${CODEGEN_SCU_FILE} ) pxdgen( - legacy_engine.h main.h ) @@ -349,9 +338,7 @@ add_subdirectory("datastructure") add_subdirectory("engine") add_subdirectory("error") add_subdirectory("event") -add_subdirectory("gamedata") add_subdirectory("gamestate") -add_subdirectory("gui") add_subdirectory("input") add_subdirectory("job") add_subdirectory("log") @@ -361,10 +348,7 @@ add_subdirectory("presenter") add_subdirectory("pyinterface") add_subdirectory("renderer") add_subdirectory("rng") -add_subdirectory("shader") -add_subdirectory("terrain") add_subdirectory("testing") add_subdirectory("time") -add_subdirectory("unit") add_subdirectory("util") add_subdirectory("versions") diff --git a/libopenage/assets/CMakeLists.txt b/libopenage/assets/CMakeLists.txt index 681d9882b9..234ac3b1b0 100644 --- a/libopenage/assets/CMakeLists.txt +++ b/libopenage/assets/CMakeLists.txt @@ -1,6 +1,4 @@ add_sources(libopenage - assetmanager.cpp - legacy_assetmanager.cpp mod_manager.cpp modpack.cpp ) diff --git a/libopenage/assets/assetmanager.cpp b/libopenage/assets/assetmanager.cpp deleted file mode 100644 index a62f0c2d34..0000000000 --- a/libopenage/assets/assetmanager.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -/** - * TODO: Deprecated in favor of presenter/assets/asset_manager.h - * - */ - -#include "assetmanager.h" - -#if WITH_INOTIFY -#include /* for NAME_MAX */ -#include -#include -#endif - -#include "error/error.h" -#include "log/log.h" -#include "util/compiler.h" -#include "util/file.h" - -#include "texture.h" - -namespace openage { - -AssetManager::AssetManager(qtsdl::GuiItemLink *gui_link) : - missing_tex{nullptr}, - gui_link{gui_link} { -#if WITH_INOTIFY - // initialize the inotify instance - this->inotify_fd = inotify_init1(IN_NONBLOCK); - if (this->inotify_fd < 0) { - throw Error{MSG(err) << "Failed to initialize inotify!"}; - } -#endif -} - - -const util::Path &AssetManager::get_asset_dir() { - return this->asset_path; -} - - -void AssetManager::set_asset_dir(const util::Path &new_path) { - if (this->asset_path != new_path) { - this->asset_path = new_path; - this->clear(); - } -} - - -void AssetManager::set_display(presenter::LegacyDisplay *display) { - this->display = display; -} - - -presenter::LegacyDisplay *AssetManager::get_display() const { - return this->display; -} - -void AssetManager::set_engine(gamestate::GameSimulation *engine) { - this->engine = engine; -} - -gamestate::GameSimulation *AssetManager::get_engine() const { - return this->engine; -} - - -std::shared_ptr AssetManager::load_texture(const std::string &name, - bool use_metafile, - bool null_if_missing) { - // the texture to be associated with the given filename - std::shared_ptr tex; - - util::Path tex_path = this->asset_path[name]; - - // try to open the texture filename. - if (not tex_path.is_file()) { - // TODO: add/fetch inotify watch on the containing folder - // to display the tex as soon at it exists. - - if (null_if_missing) { - return nullptr; - } - else { - // return the big X texture instead - tex = this->get_missing_tex(); - } - } - else { - // create the texture! - tex = std::make_shared(tex_path, use_metafile); - -#if WITH_INOTIFY - std::string native_path = tex_path.resolve_native_path(); - - if (native_path.size() > 0) { - // create inotify update trigger for the requested file - - // TODO: let util::Path do the file watching - int wd = inotify_add_watch( - this->inotify_fd, - native_path.c_str(), - IN_CLOSE_WRITE); - - if (wd < 0) { - log::log(WARN << "Failed to add inotify watch for " << native_path); - } - else { - this->watch_fds[wd] = tex; - } - } -#endif - } - - // pass back the shared_ptr - return tex; -} - - -Texture *AssetManager::get_texture(const std::string &name, bool use_metafile, bool null_if_missing) { - // check whether the requested texture was loaded already - auto tex_it = this->textures.find(name); - - // the texture was not loaded yet: - if (tex_it == this->textures.end()) { - auto tex = this->load_texture(name, use_metafile, null_if_missing); - - if (tex.get() != nullptr) { - // insert the texture into the map - this->textures.insert(std::make_pair(name, tex)); - } - - // and return the texture pointer. - return tex.get(); - } - - return tex_it->second.get(); -} - - -void AssetManager::check_updates() { -#if WITH_INOTIFY - // buffer for at least 4 inotify events - char buf[4 * (sizeof(struct inotify_event) + NAME_MAX + 1)]; - ssize_t len; - - while (true) { - // fetch all events, the kernel won't write "half" structs. - len = read(this->inotify_fd, buf, sizeof(buf)); - - if (len == -1) { - if (errno == EAGAIN) { - // no events, nothing to do. - break; - } - else { - // something went wrong - log::log(WARN << "Failed to read inotify events!"); - break; - } - } - - // process fetched events, - // the kernel guarantees complete events in the buffer. - char *ptr = buf; - while (ptr < buf + len) { - auto *event = reinterpret_cast(ptr); - - if (event->mask & IN_CLOSE_WRITE) { - // TODO: this should invoke callback functions - this->watch_fds[event->wd]->reload(); - } - - // move the buffer ptr to the next event. - ptr += sizeof(struct inotify_event) + event->len; - } - } -#endif -} - -std::shared_ptr AssetManager::get_missing_tex() { - // if not loaded, fetch the "missing" texture (big red X). - if (this->missing_tex.get() == nullptr) [[unlikely]] { - this->missing_tex = std::make_shared( - this->asset_path["test"]["textures"]["missing.png"], - false); - } - - return this->missing_tex; -} - -void AssetManager::clear() { -#if WITH_INOTIFY - for (auto &watch_fd : this->watch_fds) { - int result = inotify_rm_watch(this->inotify_fd, watch_fd.first); - if (result < 0) { - log::log(WARN << "Failed to remove inotify watches"); - } - } - this->watch_fds.clear(); -#endif - - this->textures.clear(); -} - -} // namespace openage diff --git a/libopenage/assets/assetmanager.h b/libopenage/assets/assetmanager.h deleted file mode 100644 index 482f2ac672..0000000000 --- a/libopenage/assets/assetmanager.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "config.h" - -#include -#include -#include - -#include "presenter/legacy/legacy.h" -#include "util/path.h" - -namespace qtsdl { -class GuiItemLink; -} // namespace qtsdl - -namespace openage { -class Texture; - -namespace gamestate { -class GameSimulation; -} - -/** - * Container class for all available assets. - * Responsible for loading, providing and updating requested files. - */ -class AssetManager final { -public: - explicit AssetManager(qtsdl::GuiItemLink *gui_link); - - /** - * Return the path where assets are found in. - */ - const util::Path &get_asset_dir(); - - /** - * Set the asset search path. - */ - void set_asset_dir(const util::Path &asset_dir); - - /** - * Set the game display of this asset manager. - * Called from QML. - */ - void set_display(presenter::LegacyDisplay *display); - - /** - * Return the display responsible for this asset manager. - */ - presenter::LegacyDisplay *get_display() const; - - /** - * Set the game engine of this asset manager. - * Called from QML. - */ - void set_engine(gamestate::GameSimulation *engine); - - /** - * Return the engine responsible for this asset manager. - */ - gamestate::GameSimulation *get_engine() const; - - /** - * Query the Texture for a given filename. - * - * @param name: the asset file name relative to the asset root. - * @param use_metafile: load subtexture information from meta file - * @param null_if_missing: instead of providing the "missing texture", - * return nullptr. - * @returns the queried texture handle. - */ - Texture *get_texture(const std::string &name, bool use_metafile = true, bool null_if_missing = false); - - /** - * Ask the kernel whether there were updates to watched files. - */ - void check_updates(); - -protected: - /** - * Create an internal texture handle. - */ - std::shared_ptr load_texture(const std::string &name, - bool use_metafile = true, - bool null_if_missing = false); - - /** - * Retrieves the texture for missing textures. - */ - std::shared_ptr get_missing_tex(); - -private: - void clear(); - - /** - * The display this asset manager is attached to. - */ - presenter::LegacyDisplay *display; - - /** - * The engine this asset manager is attached to. - */ - gamestate::GameSimulation *engine; - - /** - * The root directory for the available assets. - */ - util::Path asset_path; - - /** - * The replacement texture for missing textures. - */ - std::shared_ptr missing_tex; - - /** - * Map from texture filename to texture instance ptr. - */ - std::unordered_map> textures; - -#if WITH_INOTIFY - /** - * The file descriptor pointing to the inotify instance. - */ - int inotify_fd; - - /** - * Map from inotify watch handle fd to texture instance ptr. - * The kernel returns the handle fd when events are triggered. - */ - std::unordered_map> watch_fds; -#endif - -public: - qtsdl::GuiItemLink *gui_link; -}; - -} // namespace openage diff --git a/libopenage/assets/legacy_assetmanager.cpp b/libopenage/assets/legacy_assetmanager.cpp deleted file mode 100644 index 1058aee26e..0000000000 --- a/libopenage/assets/legacy_assetmanager.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -/** - * TODO: Deprecated in favor of presenter/assets/asset_manager.h - * - */ - -#include "legacy_assetmanager.h" - -#if WITH_INOTIFY -#include /* for NAME_MAX */ -#include -#include -#endif - -#include "error/error.h" -#include "log/log.h" -#include "util/compiler.h" -#include "util/file.h" - -#include "texture.h" - -namespace openage { - -LegacyAssetManager::LegacyAssetManager(qtsdl::GuiItemLink *gui_link) : - missing_tex{nullptr}, - gui_link{gui_link} { -#if WITH_INOTIFY - // initialize the inotify instance - this->inotify_fd = inotify_init1(IN_NONBLOCK); - if (this->inotify_fd < 0) { - throw Error{MSG(err) << "Failed to initialize inotify!"}; - } -#endif -} - - -const util::Path &LegacyAssetManager::get_asset_dir() { - return this->asset_path; -} - - -void LegacyAssetManager::set_asset_dir(const util::Path &new_path) { - if (this->asset_path != new_path) { - this->asset_path = new_path; - this->clear(); - } -} - - -void LegacyAssetManager::set_display(presenter::LegacyDisplay *display) { - this->display = display; -} - - -presenter::LegacyDisplay *LegacyAssetManager::get_display() const { - return this->display; -} - -void LegacyAssetManager::set_engine(LegacyEngine *engine) { - this->engine = engine; -} - -LegacyEngine *LegacyAssetManager::get_engine() const { - return this->engine; -} - - -std::shared_ptr LegacyAssetManager::load_texture(const std::string &name, - bool use_metafile, - bool null_if_missing) { - // the texture to be associated with the given filename - std::shared_ptr tex; - - util::Path tex_path = this->asset_path[name]; - - // try to open the texture filename. - if (not tex_path.is_file()) { - // TODO: add/fetch inotify watch on the containing folder - // to display the tex as soon at it exists. - - if (null_if_missing) { - return nullptr; - } - else { - // return the big X texture instead - tex = this->get_missing_tex(); - } - } - else { - // create the texture! - tex = std::make_shared(tex_path, use_metafile); - -#if WITH_INOTIFY - std::string native_path = tex_path.resolve_native_path(); - - if (native_path.size() > 0) { - // create inotify update trigger for the requested file - - // TODO: let util::Path do the file watching - int wd = inotify_add_watch( - this->inotify_fd, - native_path.c_str(), - IN_CLOSE_WRITE); - - if (wd < 0) { - log::log(WARN << "Failed to add inotify watch for " << native_path); - } - else { - this->watch_fds[wd] = tex; - } - } -#endif - } - - // pass back the shared_ptr - return tex; -} - - -Texture *LegacyAssetManager::get_texture(const std::string &name, bool use_metafile, bool null_if_missing) { - // check whether the requested texture was loaded already - auto tex_it = this->textures.find(name); - - // the texture was not loaded yet: - if (tex_it == this->textures.end()) { - auto tex = this->load_texture(name, use_metafile, null_if_missing); - - if (tex.get() != nullptr) { - // insert the texture into the map - this->textures.insert(std::make_pair(name, tex)); - } - - // and return the texture pointer. - return tex.get(); - } - - return tex_it->second.get(); -} - - -void LegacyAssetManager::check_updates() { -#if WITH_INOTIFY - // buffer for at least 4 inotify events - char buf[4 * (sizeof(struct inotify_event) + NAME_MAX + 1)]; - ssize_t len; - - while (true) { - // fetch all events, the kernel won't write "half" structs. - len = read(this->inotify_fd, buf, sizeof(buf)); - - if (len == -1) { - if (errno == EAGAIN) { - // no events, nothing to do. - break; - } - else { - // something went wrong - log::log(WARN << "Failed to read inotify events!"); - break; - } - } - - // process fetched events, - // the kernel guarantees complete events in the buffer. - char *ptr = buf; - while (ptr < buf + len) { - auto *event = reinterpret_cast(ptr); - - if (event->mask & IN_CLOSE_WRITE) { - // TODO: this should invoke callback functions - this->watch_fds[event->wd]->reload(); - } - - // move the buffer ptr to the next event. - ptr += sizeof(struct inotify_event) + event->len; - } - } -#endif -} - -std::shared_ptr LegacyAssetManager::get_missing_tex() { - // if not loaded, fetch the "missing" texture (big red X). - if (this->missing_tex.get() == nullptr) [[unlikely]] { - this->missing_tex = std::make_shared( - this->asset_path["test"]["textures"]["missing.png"], - false); - } - - return this->missing_tex; -} - -void LegacyAssetManager::clear() { -#if WITH_INOTIFY - for (auto &watch_fd : this->watch_fds) { - int result = inotify_rm_watch(this->inotify_fd, watch_fd.first); - if (result < 0) { - log::log(WARN << "Failed to remove inotify watches"); - } - } - this->watch_fds.clear(); -#endif - - this->textures.clear(); -} - -} // namespace openage diff --git a/libopenage/assets/legacy_assetmanager.h b/libopenage/assets/legacy_assetmanager.h deleted file mode 100644 index 284719b1e1..0000000000 --- a/libopenage/assets/legacy_assetmanager.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "config.h" - -#include -#include -#include - -#include "presenter/legacy/legacy.h" -#include "util/path.h" - -namespace qtsdl { -class GuiItemLink; -} // namespace qtsdl - -namespace openage { - -class LegacyEngine; -class Texture; - -/** - * Container class for all available assets. - * Responsible for loading, providing and updating requested files. - */ -class LegacyAssetManager final { -public: - explicit LegacyAssetManager(qtsdl::GuiItemLink *gui_link); - - /** - * Return the path where assets are found in. - */ - const util::Path &get_asset_dir(); - - /** - * Set the asset search path. - */ - void set_asset_dir(const util::Path &asset_dir); - - /** - * Set the game display of this asset manager. - * Called from QML. - */ - void set_display(presenter::LegacyDisplay *display); - - /** - * Return the display responsible for this asset manager. - */ - presenter::LegacyDisplay *get_display() const; - - /** - * Set the game engine of this asset manager. - * Called from QML. - */ - void set_engine(LegacyEngine *engine); - - /** - * Return the engine responsible for this asset manager. - */ - LegacyEngine *get_engine() const; - - /** - * Query the Texture for a given filename. - * - * @param name: the asset file name relative to the asset root. - * @param use_metafile: load subtexture information from meta file - * @param null_if_missing: instead of providing the "missing texture", - * return nullptr. - * @returns the queried texture handle. - */ - Texture *get_texture(const std::string &name, bool use_metafile = true, bool null_if_missing = false); - - /** - * Ask the kernel whether there were updates to watched files. - */ - void check_updates(); - -protected: - /** - * Create an internal texture handle. - */ - std::shared_ptr load_texture(const std::string &name, - bool use_metafile = true, - bool null_if_missing = false); - - /** - * Retrieves the texture for missing textures. - */ - std::shared_ptr get_missing_tex(); - -private: - void clear(); - - /** - * The display this asset manager is attached to. - */ - presenter::LegacyDisplay *display; - - /** - * The engine this asset manager is attached to. - */ - LegacyEngine *engine; - - /** - * The root directory for the available assets. - */ - util::Path asset_path; - - /** - * The replacement texture for missing textures. - */ - std::shared_ptr missing_tex; - - /** - * Map from texture filename to texture instance ptr. - */ - std::unordered_map> textures; - -#if WITH_INOTIFY - /** - * The file descriptor pointing to the inotify instance. - */ - int inotify_fd; - - /** - * Map from inotify watch handle fd to texture instance ptr. - * The kernel returns the handle fd when events are triggered. - */ - std::unordered_map> watch_fds; -#endif - -public: - qtsdl::GuiItemLink *gui_link; -}; - -} // namespace openage diff --git a/libopenage/audio/audio_manager.cpp b/libopenage/audio/audio_manager.cpp index 5bda65e6e9..b46fbcf7e2 100644 --- a/libopenage/audio/audio_manager.cpp +++ b/libopenage/audio/audio_manager.cpp @@ -1,96 +1,61 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. #include "audio_manager.h" #include -#include #include +#include +#include +#include +#include + +#include "../log/log.h" +#include "../util/misc.h" #include "error.h" #include "hash_functions.h" #include "resource.h" -#include "../log/log.h" -#include "../util/misc.h" namespace openage { namespace audio { - - - -/** - * Wrapper class for the sdl audio device locking so - * the device doesn't deadlock because of funny exceptions. - */ -class SDLDeviceLock { -public: - explicit SDLDeviceLock(const SDL_AudioDeviceID &id) - : - dev_id{id} { - SDL_LockAudioDevice(this->dev_id); - } - - ~SDLDeviceLock() { - SDL_UnlockAudioDevice(this->dev_id); - } - - SDLDeviceLock(SDLDeviceLock &&) = delete; - SDLDeviceLock(const SDLDeviceLock &) = delete; - SDLDeviceLock& operator =(SDLDeviceLock &&) = delete; - SDLDeviceLock& operator =(const SDLDeviceLock &) = delete; - -private: - SDL_AudioDeviceID dev_id; -}; - - -AudioManager::AudioManager(job::JobManager *job_manager, - const std::string &device_name) - : +AudioManager::AudioManager(const std::shared_ptr &job_manager, + const std::string &device_name) : available{false}, job_manager{job_manager}, - device_name{device_name} { + device_name{device_name}, + device_format{std::make_shared()}, + device{nullptr}, + audio_sink{nullptr} { + // set desired audio output format + this->device_format->setSampleRate(48000); + this->device_format->setSampleFormat(QAudioFormat::SampleFormat::Int16); + this->device_format->setChannelCount(2); + + // find the device with the given name + for (auto &device : QMediaDevices::audioOutputs()) { + if (device.description().toStdString() == device_name) { + this->device = std::make_shared(device); + break; + } + } - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - log::log(MSG(err) - << "SDL audio initialization failed: " - << SDL_GetError()); + // select the default device if the name was not found + if (not this->device) { + this->device = std::make_shared(QMediaDevices::defaultAudioOutput()); return; - } else { - log::log(MSG(info) << "SDL audio subsystems initialized"); } - // set desired audio output format - SDL_AudioSpec desired_spec; - SDL_zero(desired_spec); - desired_spec.freq = 48000; - desired_spec.format = AUDIO_S16LSB; - desired_spec.channels = 2; - desired_spec.samples = 4096; - desired_spec.userdata = this; - - // call back that is invoked once SDL needs the next chunk of data - desired_spec.callback = [] (void *userdata, uint8_t *stream, int len) { - auto *audio_manager = static_cast(userdata); - audio_manager->audio_callback(reinterpret_cast(stream), len / 2); - }; - - // convert device name to valid parameter for sdl call - // if the device name is empty, use a nullptr in order to indicate that the - // default device should be used - const char *c_device_name = device_name.empty() ? - nullptr : device_name.c_str(); - // open audio playback device - device_id = SDL_OpenAudioDevice(c_device_name, 0, &desired_spec, - &device_spec, 0); - - // no device could be opened - if (device_id == 0) { - log::log(MSG(err) << "Error opening audio device: " << SDL_GetError()); + if (not this->device->isFormatSupported(*this->device_format)) { + log::log(MSG(err) << "Audio device does not support the desired format!"); return; } + // create audio sink + this->audio_sink = std::make_unique(*this->device.get(), *this->device_format.get()); + // TODO: connect callback to get audio data to device + // initialize playing sounds vectors using sound_vector = std::vector>; playing_sounds.insert({category_t::GAME, sound_vector{}}); @@ -100,25 +65,23 @@ AudioManager::AudioManager(job::JobManager *job_manager, // create buffer for mixing this->mix_buffer = std::make_unique( - 4 * device_spec.samples * device_spec.channels - ); + 4 * device_format->bytesPerSample() * device_format->channelCount()); - log::log(MSG(info) << - "Using audio device: " - << (device_name.empty() ? "default" : device_name) - << " [freq=" << device_spec.freq - << ", format=" << device_spec.format - << ", channels=" << static_cast(device_spec.channels) - << ", samples=" << device_spec.samples - << "]"); + log::log(MSG(info) << "Using audio device: " + << (device_name.empty() ? "default" : device_name) + << " [sample rate=" << device_format->sampleRate() + << ", format=" << device_format->sampleFormat() + << ", channels=" << device_format->channelCount() + << ", samples=" << device_format->bytesPerSample() + << "]"); - SDL_PauseAudioDevice(device_id, 0); + this->audio_sink->stop(); this->available = true; } AudioManager::~AudioManager() { - SDL_CloseAudioDevice(device_id); + this->audio_sink->stop(); } void AudioManager::load_resources(const std::vector &sound_files) { @@ -148,11 +111,10 @@ Sound AudioManager::get_sound(category_t category, int id) { auto resource = resources.find(std::make_tuple(category, id)); if (resource == std::end(resources)) { throw audio::Error{ - MSG(err) << - "Sound resource does not exist: " - "category=" << category << ", " << - "id=" << id - }; + MSG(err) << "Sound resource does not exist: " + "category=" + << category << ", " + << "id=" << id}; } auto sound_impl = std::make_shared(resource->second); @@ -161,7 +123,7 @@ Sound AudioManager::get_sound(category_t category, int id) { void AudioManager::audio_callback(int16_t *stream, int length) { - std::memset(mix_buffer.get(), 0, length*4); + std::memset(mix_buffer.get(), 0, length * 4); // iterate over all categories for (auto &entry : this->playing_sounds) { @@ -181,28 +143,25 @@ void AudioManager::audio_callback(int16_t *stream, int length) { // write the mix buffer to the output stream and adjust volume for (int i = 0; i < length; i++) { - auto value = mix_buffer[i]/256; + auto value = mix_buffer[i] / 256; if (value > 32767) { value = 32767; - } else if (value < -32768) { + } + else if (value < -32768) { value = -32768; } stream[i] = static_cast(value); } } -void AudioManager::add_sound(const std::shared_ptr& sound) { - SDLDeviceLock lock{this->device_id}; - +void AudioManager::add_sound(const std::shared_ptr &sound) { auto category = sound->get_category(); auto &playing_list = this->playing_sounds.find(category)->second; // TODO probably check if sound already exists in playing list playing_list.push_back(sound); } -void AudioManager::remove_sound(const std::shared_ptr& sound) { - SDLDeviceLock lock{this->device_id}; - +void AudioManager::remove_sound(const std::shared_ptr &sound) { auto category = sound->get_category(); auto &playing_list = this->playing_sounds.find(category)->second; @@ -214,11 +173,11 @@ void AudioManager::remove_sound(const std::shared_ptr& sound) { } } -SDL_AudioSpec AudioManager::get_device_spec() const { - return this->device_spec; +const std::shared_ptr &AudioManager::get_device_spec() const { + return this->device_format; } -job::JobManager *AudioManager::get_job_manager() const { +const std::shared_ptr &AudioManager::get_job_manager() const { return this->job_manager; } @@ -228,32 +187,21 @@ bool AudioManager::is_available() const { std::vector AudioManager::get_devices() { + auto devices = QMediaDevices::audioOutputs(); + std::vector device_list; - auto num_devices = SDL_GetNumAudioDevices(0); - device_list.reserve(num_devices); - for (int i = 0; i < num_devices; i++) { - device_list.emplace_back(SDL_GetAudioDeviceName(i, 0)); - } - return device_list; -} + device_list.reserve(devices.size()); -std::vector AudioManager::get_drivers() { - std::vector driver_list; - auto num_drivers = SDL_GetNumAudioDrivers(); - driver_list.reserve(num_drivers); - for (int i = 0; i < num_drivers; i++) { - driver_list.emplace_back(SDL_GetAudioDriver(i)); + for (auto &device : devices) { + device_list.emplace_back(device.description().toStdString()); } - return driver_list; + + return device_list; } -std::string AudioManager::get_current_driver() { - const char *c_driver = SDL_GetCurrentAudioDriver(); - if (c_driver == nullptr) { - return ""; - } else { - return c_driver; - } +std::string AudioManager::get_default_device() { + return QMediaDevices::defaultAudioOutput().description().toStdString(); } -}} // openage::audio +} // namespace audio +} // namespace openage diff --git a/libopenage/audio/audio_manager.h b/libopenage/audio/audio_manager.h index d97197b5b5..8d3269a5a2 100644 --- a/libopenage/audio/audio_manager.h +++ b/libopenage/audio/audio_manager.h @@ -7,18 +7,19 @@ #include #include -#include +#include #include "category.h" #include "hash_functions.h" #include "resource_def.h" #include "sound.h" +Q_FORWARD_DECLARE_OBJC_CLASS(QAudioDevice); +Q_FORWARD_DECLARE_OBJC_CLASS(QAudioFormat); +Q_FORWARD_DECLARE_OBJC_CLASS(QAudioSink); namespace openage { -class LegacyEngine; - namespace job { class JobManager; } @@ -28,6 +29,8 @@ namespace audio { /** * This class provides audio functionality for openage. + * + * TODO: Finish porting to Qt. */ class AudioManager { public: @@ -35,7 +38,7 @@ class AudioManager { * Initializes the audio manager with the given device name. * If the name is empty, the default device is used. */ - AudioManager(job::JobManager *job_manager, + AudioManager(const std::shared_ptr &job_manager, const std::string &device_name = ""); ~AudioManager(); @@ -68,12 +71,12 @@ class AudioManager { /** * Returns the currently used audio output format. */ - SDL_AudioSpec get_device_spec() const; + const std::shared_ptr &get_device_spec() const; /** * Return the game engine the audio manager is attached to. */ - job::JobManager *get_job_manager() const; + const std::shared_ptr &get_job_manager() const; /** * If this audio manager is available. @@ -81,6 +84,16 @@ class AudioManager { */ bool is_available() const; + /** + * Returns a vector of all available device names. + */ + static std::vector get_devices(); + + /** + * Returns the default device name. + */ + static std::string get_default_device(); + private: void add_sound(const std::shared_ptr &sound); void remove_sound(const std::shared_ptr &sound); @@ -98,7 +111,7 @@ class AudioManager { /** * The job manager used in this audio manager for job queuing. */ - job::JobManager *job_manager; + std::shared_ptr job_manager; /** * the used audio device's name @@ -108,12 +121,17 @@ class AudioManager { /** * the audio output format */ - SDL_AudioSpec device_spec; + std::shared_ptr device_format; /** * the used audio device's id */ - SDL_AudioDeviceID device_id; + std::shared_ptr device; + + /** + * the audio sink + */ + std::shared_ptr audio_sink; /** * Buffer used for mixing audio to one stream. @@ -123,23 +141,6 @@ class AudioManager { std::unordered_map, std::shared_ptr> resources; std::unordered_map>> playing_sounds; - - // static functions -public: - /** - * Returns a vector of all available device names. - */ - static std::vector get_devices(); - - /** - * Returns a vector of all available driver names. - */ - static std::vector get_drivers(); - - /** - * Returns the name of the currently used driver. - */ - static std::string get_current_driver(); }; } // namespace audio diff --git a/libopenage/audio/dynamic_resource.cpp b/libopenage/audio/dynamic_resource.cpp index bb2347c07b..97aac8df37 100644 --- a/libopenage/audio/dynamic_resource.cpp +++ b/libopenage/audio/dynamic_resource.cpp @@ -4,7 +4,6 @@ #include "../job/job_manager.h" -#include "../legacy_engine.h" #include "../log/log.h" #include "audio_manager.h" diff --git a/libopenage/audio/resource.cpp b/libopenage/audio/resource.cpp index b5b3a3af55..66efcf52c2 100644 --- a/libopenage/audio/resource.cpp +++ b/libopenage/audio/resource.cpp @@ -3,7 +3,6 @@ #include "resource.h" #include "../error/error.h" -#include "../legacy_engine.h" #include "dynamic_resource.h" #include "in_memory_resource.h" @@ -30,7 +29,6 @@ int Resource::get_id() const { std::shared_ptr Resource::create_resource(AudioManager *manager, const resource_def &def) { - if (not def.location.is_file()) [[unlikely]] { throw Error{ERR << "sound file does not exist: " << def.location}; } diff --git a/libopenage/console/console.cpp b/libopenage/console/console.cpp index ae9c2cae77..a07d42b898 100644 --- a/libopenage/console/console.cpp +++ b/libopenage/console/console.cpp @@ -3,7 +3,6 @@ #include "console.h" #include "../error/error.h" -#include "../legacy_engine.h" #include "../log/log.h" #include "../util/strings.h" #include "../util/unicode.h" @@ -22,8 +21,8 @@ namespace console { * log console, command console */ -Console::Console(presenter::LegacyDisplay *engine) : - engine{engine}, +Console::Console(/* presenter::LegacyDisplay *display */) : + // display{display}, bottomleft{0, 0}, topright{1, 1}, charsize{1, 1}, @@ -45,6 +44,7 @@ Console::Console(presenter::LegacyDisplay *engine) : Console::~Console() {} +/* void Console::load_colors(std::vector &colortable) { for (auto &c : colortable) { this->termcolors.emplace_back(c); @@ -54,25 +54,28 @@ void Console::load_colors(std::vector &colortable) { throw Error(MSG(err) << "Exactly 256 terminal colors are required."); } } +*/ void Console::register_to_engine() { - this->engine->register_input_action(this); - this->engine->register_tick_action(this); - this->engine->register_drawhud_action(this); - this->engine->register_resize_action(this); + // TODO: Use new renderer + /* + this->display->register_input_action(this); + this->display->register_tick_action(this); + this->display->register_drawhud_action(this); + this->display->register_resize_action(this); - // Bind the console toggle key globally - auto &action = this->engine->get_action_manager(); - auto &global = this->engine->get_input_manager().get_global_context(); + Bind the console toggle key globally + auto &action = this->display->get_action_manager(); + auto &global = this->display->get_input_manager().get_global_context(); global.bind(action.get("TOGGLE_CONSOLE"), [this](const input::legacy::action_arg_t &) { this->set_visible(!this->visible); }); - // TODO: bind any needed input to InputContext + TODO: bind any needed input to InputContext - // toggle console will take highest priority + toggle console will take highest priority this->input_context.bind(action.get("TOGGLE_CONSOLE"), [this](const input::legacy::action_arg_t &) { this->set_visible(false); }); @@ -103,17 +106,21 @@ void Console::register_to_engine() { } }); this->input_context.utf8_mode = true; + */ } -void Console::set_visible(bool make_visible) { +void Console::set_visible(bool /* make_visible */) { + // TODO: Use new renderer + /* if (make_visible) { - this->engine->get_input_manager().push_context(&this->input_context); + this->display->get_input_manager().push_context(&this->input_context); this->visible = true; } else { - this->engine->get_input_manager().remove_context(&this->input_context); + this->display->get_input_manager().remove_context(&this->input_context); this->visible = false; } + */ } void Console::write(const char *text) { @@ -126,9 +133,11 @@ void Console::interpret(const std::string &command) { this->set_visible(false); } else if (command == "list") { - for (auto &line : this->engine->list_options()) { - this->write(line.c_str()); - } + // TODO: Use new renderer + + // for (auto &line : this->display->list_options()) { + // this->write(line.c_str()); + // } } else if (command.substr(0, 3) == "set") { std::size_t first_space = command.find(" "); @@ -154,7 +163,7 @@ void Console::interpret(const std::string &command) { } } } - +/* bool Console::on_tick() { if (!this->visible) { return true; @@ -170,7 +179,9 @@ bool Console::on_drawhud() { return true; } - draw::to_opengl(this->engine, this); + // TODO: Use new renderer + + // draw::to_opengl(this->display, this); return true; } @@ -201,6 +212,6 @@ bool Console::on_resize(coord::viewport_delta new_size) { return true; } - +*/ } // namespace console } // namespace openage diff --git a/libopenage/console/console.h b/libopenage/console/console.h index 8585373eb6..380a563e17 100644 --- a/libopenage/console/console.h +++ b/libopenage/console/console.h @@ -2,39 +2,31 @@ #pragma once -#include #include #include "../coord/pixel.h" -#include "../gamedata/color_dummy.h" -#include "../handlers.h" -#include "../input/legacy/input_manager.h" -#include "../presenter/legacy/legacy.h" #include "../renderer/font/font.h" #include "../util/color.h" #include "buf.h" namespace openage { -class LegacyEngine; - /** * In-game console subsystem. Featuring a full terminal emulator. + * + * TODO: Adapt to new engine subsystems. */ namespace console { -class Console : InputHandler - , TickHandler - , HudHandler - , ResizeHandler { +class Console { public: - Console(presenter::LegacyDisplay *renderer); + Console(/* presenter::LegacyDisplay *display */); ~Console(); /** * load the consoles color table */ - void load_colors(std::vector &colortable); + // void load_colors(std::vector &colortable); /** * register this console to the renderer. @@ -54,13 +46,14 @@ class Console : InputHandler */ void interpret(const std::string &command); - bool on_drawhud() override; - bool on_tick() override; - bool on_input(SDL_Event *event) override; - bool on_resize(coord::viewport_delta new_size) override; + // bool on_drawhud() override; + // bool on_tick() override; + // bool on_input(SDL_Event *event) override; + // bool on_resize(coord::viewport_delta new_size) override; protected: - presenter::LegacyDisplay *engine; + // TODO: Replace with new renderer + // presenter::LegacyDisplay *display; public: coord::camhud bottomleft; @@ -74,7 +67,7 @@ class Console : InputHandler Buf buf; renderer::Font font; - input::legacy::InputContext input_context; + // input::legacy::InputContext input_context; // the command state std::string command; diff --git a/libopenage/console/draw.cpp b/libopenage/console/draw.cpp index 237c16d91c..ba5b4588c9 100644 --- a/libopenage/console/draw.cpp +++ b/libopenage/console/draw.cpp @@ -10,7 +10,6 @@ #include "../util/timing.h" #include -#include "../renderer/text.h" #include "buf.h" #include "console.h" @@ -18,6 +17,7 @@ namespace openage { namespace console { namespace draw { +/* void to_opengl(presenter::LegacyDisplay *engine, Console *console) { coord::camhud topleft{ console->bottomleft.x, @@ -85,6 +85,7 @@ void to_opengl(presenter::LegacyDisplay *engine, Console *console) { } } } +*/ void to_terminal(Buf *buf, util::FD *fd, bool clear) { //move cursor, draw top left corner diff --git a/libopenage/console/draw.h b/libopenage/console/draw.h index 2e35555f05..13634ea5b4 100644 --- a/libopenage/console/draw.h +++ b/libopenage/console/draw.h @@ -2,12 +2,9 @@ #pragma once -#include "../presenter/legacy/legacy.h" namespace openage { -class LegacyEngine; - namespace util { class FD; } // namespace util @@ -22,7 +19,7 @@ namespace draw { /** * experimental and totally inefficient opengl draw of a terminal buffer. */ -void to_opengl(presenter::LegacyDisplay *engine, Console *console); +// void to_opengl(presenter::LegacyDisplay *engine, Console *console); /** * very early and inefficient printing of the console to a pty. diff --git a/libopenage/coord/CMakeLists.txt b/libopenage/coord/CMakeLists.txt index 5123577052..7f01010d8a 100644 --- a/libopenage/coord/CMakeLists.txt +++ b/libopenage/coord/CMakeLists.txt @@ -3,7 +3,6 @@ add_sources(libopenage chunk.cpp coord_test.cpp - coordmanager.cpp declarations.cpp phys.cpp pixel.cpp diff --git a/libopenage/coord/coordmanager.cpp b/libopenage/coord/coordmanager.cpp deleted file mode 100644 index 7d175b0702..0000000000 --- a/libopenage/coord/coordmanager.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017-2018 the openage authors. See copying.md for legal info. - -#include "coordmanager.h" - -namespace openage { -namespace coord { - -// no implementation needed - -}} diff --git a/libopenage/coord/coordmanager.h b/libopenage/coord/coordmanager.h deleted file mode 100644 index 19195de83e..0000000000 --- a/libopenage/coord/coordmanager.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "phys.h" -#include "pixel.h" -#include "tile.h" - -namespace openage { -namespace coord { - - -/** - * Holds all coordinate-related state and metadata. - * - * Among other things, this stores the camera positions. - * - * TODO: rename to CoordState! - */ -class CoordManager final { -public: - explicit CoordManager() {}; - - /** - * What's the current size of the viewport? - * (what's the coordinate of the top right pixel + (1, 1)?) - */ - viewport_delta viewport_size{800, 600}; - - /** - * What place (in Phys3) is the origin of the CamGame coordinate system looking at? - */ - phys3 camgame_phys{10, 10, 0}; - - /** - * Where in the viewport is the origin of the CamGame coordinate system? - * (this is usually the center of the viewport). - */ - viewport camgame_viewport{400, 300}; - - /** - * Where in the viewport is the origin of the CamHUD coordinate system? - * (this is usually the bottom left corner of the viewport) - */ - viewport camhud_viewport{0, 0}; - - /** - * The size of a terrain tile, in pixels. - * Rile diamonds are 96 pixels wide and 48 pixels high. - * The area of each tile is 96 * 48 * 0.5 square pixels. - */ - // TODO: dynamically get from nyan data - camgame_delta tile_size{96, 48}; -}; - -}} // namespace openage::coord diff --git a/libopenage/coord/declarations.h b/libopenage/coord/declarations.h index 05b89cb4fa..698b594aac 100644 --- a/libopenage/coord/declarations.h +++ b/libopenage/coord/declarations.h @@ -74,8 +74,5 @@ using term_t = int; struct term_delta; struct term; -// forward declaration of the coord manager -class CoordManager; - } // namespace coord } // namespace openage diff --git a/libopenage/coord/phys.cpp b/libopenage/coord/phys.cpp index bb5e89498d..250709e2b2 100644 --- a/libopenage/coord/phys.cpp +++ b/libopenage/coord/phys.cpp @@ -2,11 +2,9 @@ #include "phys.h" -#include "coord/coordmanager.h" #include "coord/pixel.h" #include "coord/scene.h" #include "coord/tile.h" -#include "terrain/terrain.h" #include "util/math.h" #include "util/math_constants.h" @@ -65,16 +63,6 @@ scene2 phys2::to_scene2() const { return scene2(this->ne, this->se); } - -[[deprecated]] phys3 phys2::to_phys3(const Terrain & /* terrain */, phys_t altitude) const { - // TODO: once terrain elevations have been implemented, - // query the terrain elevation at {ne, se}. - phys_t elevation = 0; - - return phys3{this->ne, this->se, elevation + altitude}; -} - - double phys3_delta::length() const { return math::hypot3(this->ne.to_double(), this->se.to_double(), this->up.to_double()); } @@ -108,22 +96,6 @@ phys_angle_t phys3_delta::to_angle(const coord::phys2_delta &other) const { return phys_angle_t::from_float(angle); } - -[[deprecated]] camgame_delta phys3_delta::to_camgame(const CoordManager &mgr) const { - // apply transformation matrix to phys3_delta, to get 'scaled': - // (ne) - // (x) = (+1 +1 +0) (se) - // (y) = (+1 -1 +1) (up) - phys_t x = phys_t{this->ne} * (+1) + this->se * (+1) + this->up * (+0); - phys_t y = phys_t{this->ne} * (+1) + this->se * (-1) + this->up * (+1); - - // add scaling (w/2 for x, h/2 for y) - return camgame_delta{ - static_cast((x * (mgr.tile_size.x / 2)).to_int()), - static_cast((y * (mgr.tile_size.y / 2)).to_int())}; -} - - tile3 phys3::to_tile3() const { return tile3{this->ne.to_int(), this->se.to_int(), this->up.to_int()}; } @@ -143,20 +115,4 @@ scene3 phys3::to_scene3() const { return scene3{this->ne, this->se, this->up}; } - -[[deprecated]] camgame phys3::to_camgame(const CoordManager &mgr) const { - return (*this - mgr.camgame_phys).to_camgame(mgr) + camgame{0, 0}; -} - - -[[deprecated]] viewport phys3::to_viewport(const CoordManager &mgr) const { - return this->to_camgame(mgr).to_viewport(mgr); -} - - -[[deprecated]] camhud phys3::to_camhud(const CoordManager &mgr) const { - return this->to_viewport(mgr).to_camhud(mgr); -} - - } // namespace openage::coord diff --git a/libopenage/coord/phys.h b/libopenage/coord/phys.h index 3a88072fff..7d933410f3 100644 --- a/libopenage/coord/phys.h +++ b/libopenage/coord/phys.h @@ -44,9 +44,6 @@ struct phys2 : CoordNeSeAbsolute { tile to_tile() const; phys3 to_phys3(phys_t up = 0) const; scene2 to_scene2() const; - - // TODO: Remove - [[deprecated]] phys3 to_phys3(const Terrain &terrain, phys_t altitude = 0) const; }; struct phys3_delta : CoordNeSeUpRelative { @@ -66,9 +63,6 @@ struct phys3_delta : CoordNeSeUpRelative { // TODO: This DOES NOT use fixed point math currently phys_angle_t to_angle(const coord::phys2_delta &other = {-1, 1}) const; - - // TODO: Remove - [[deprecated]] camgame_delta to_camgame(const CoordManager &mgr) const; }; struct phys3 : CoordNeSeUpAbsolute { @@ -79,11 +73,6 @@ struct phys3 : CoordNeSeUpAbsolute { tile to_tile() const; phys2 to_phys2() const; scene3 to_scene3() const; - - // TODO: Remove - [[deprecated]] camgame to_camgame(const CoordManager &mgr) const; - [[deprecated]] viewport to_viewport(const CoordManager &mgr) const; - [[deprecated]] camhud to_camhud(const CoordManager &mgr) const; }; diff --git a/libopenage/coord/pixel.cpp b/libopenage/coord/pixel.cpp index 24ad6a507f..c7dac5f815 100644 --- a/libopenage/coord/pixel.cpp +++ b/libopenage/coord/pixel.cpp @@ -2,86 +2,25 @@ #include "pixel.h" -#include "coord/coordmanager.h" #include "coord/phys.h" #include "renderer/camera/camera.h" namespace openage { namespace coord { - -phys3_delta camgame_delta::to_phys3(const CoordManager &mgr, phys_t up) const { - // apply scaling factor; w/2 for x, h/2 for y - phys_t x = phys_t::from_int(this->x) / static_cast(mgr.tile_size.x / 2); - phys_t y = phys_t::from_int(this->y) / static_cast(mgr.tile_size.y / 2); - - // apply transformation matrix to 'scaled', - // to get the relative phys3 position - // - // a camgame position represents a line in the 3D phys space - // a camgame delta of 0 might actually correlate to an arbitrarily - // large phys delta. - // we select one specific point on that line by explicitly specifying the - // 'up' value of the result. - // - // the transformation matrix is: - // - // (ne) = (+0.5 +0.5 +0.5) ( x) - // (se) = (+0.5 -0.5 -0.5) ( y) - // (up) = (+0.0 +0.0 +1.0) (up) - phys3_delta result; - result.ne = (x + y + up) / 2L; - result.se = (x - y - up) / 2L; - result.up = (up); - - return result; -} - - -viewport_delta camgame_delta::to_viewport() const { - return viewport_delta{this->x, this->y}; -} - - -viewport camgame::to_viewport(const CoordManager &mgr) const { - // reverse of viewport::to_camgame - return (*this - camgame{0, 0}).to_viewport() + mgr.camgame_viewport; -} - - -camhud camgame::to_camhud(const CoordManager &mgr) const { - return this->to_viewport(mgr).to_camhud(mgr); -} - - -phys3 camgame::to_phys3(const CoordManager &mgr, phys_t up) const { - return (*this - camgame{0, 0}).to_phys3(mgr, up) + mgr.camgame_phys; -} - - -tile camgame::to_tile(const CoordManager &mgr, phys_t up) const { - return this->to_phys3(mgr, up).to_tile(); -} - - viewport_delta camhud_delta::to_viewport() const { return viewport_delta{this->x, this->y}; } -viewport camhud::to_viewport(const CoordManager &mgr) const { +viewport camhud::to_viewport() const { // reverse of viewport::to_camhud - return (*this - camhud{0, 0}).to_viewport() + mgr.camhud_viewport; + return (*this - camhud{0, 0}).to_viewport() + viewport{0, 0}; } -[[deprecated]] phys3_delta viewport_delta::to_phys3(const CoordManager &mgr, phys_t up) const { - return this->to_camgame().to_phys3(mgr, up); -} - - -camhud viewport::to_camhud(const CoordManager &mgr) const { - return camhud{0, 0} + (*this - mgr.camhud_viewport).to_camhud(); +camhud viewport::to_camhud() const { + return camhud{0, 0} + (*this - viewport{0, 0}).to_camhud(); } @@ -92,44 +31,18 @@ Eigen::Vector2f viewport::to_ndc_space(const std::shared_ptrto_camgame(mgr).to_phys3(mgr, up); -} - - -[[deprecated]] tile viewport::to_tile(const CoordManager &mgr, phys_t up) const { - return this->to_camgame(mgr).to_tile(mgr, up); -} - - -viewport_delta input_delta::to_viewport(const CoordManager &mgr) const { +viewport_delta input_delta::to_viewport(const std::shared_ptr &camera) const { viewport_delta result; result.x = this->x; - result.y = mgr.viewport_size.y - this->y; + result.y = camera->get_viewport_size()[1] - this->y; return result; } -[[deprecated]] camgame_delta input_delta::to_camgame(const CoordManager &mgr) const { - return this->to_viewport(mgr).to_camgame(); -} - - -[[deprecated]] phys3_delta input_delta::to_phys3(const CoordManager &mgr, phys_t up) const { - return this->to_viewport(mgr).to_camgame().to_phys3(mgr, up); -} - - -viewport input::to_viewport(const CoordManager &mgr) const { - return viewport{0, 0} + (*this - input{0, 0}).to_viewport(mgr); +viewport input::to_viewport(const std::shared_ptr &camera) const { + return viewport{0, 0} + (*this - input{0, 0}).to_viewport(camera); } @@ -155,16 +68,5 @@ scene3 input::to_scene3(const std::shared_ptr &camera) return scene3(-p_intersect.z(), p_intersect.x(), 0.0f); } - -[[deprecated]] phys3 input::to_phys3(const CoordManager &mgr, phys_t up) const { - return this->to_viewport(mgr).to_camgame(mgr).to_phys3(mgr, up); -} - - -[[deprecated]] camgame input::to_camgame(const CoordManager &mgr) const { - return this->to_viewport(mgr).to_camgame(mgr); -} - - } // namespace coord } // namespace openage diff --git a/libopenage/coord/pixel.h b/libopenage/coord/pixel.h index 5c42b92a4a..e97106224b 100644 --- a/libopenage/coord/pixel.h +++ b/libopenage/coord/pixel.h @@ -21,41 +21,6 @@ namespace coord { * See doc/code/coordinate-systems.md for more information. */ - -// TODO: Remove -struct [[deprecated]] camgame_delta : CoordXYRelative { - using CoordXYRelative::CoordXYRelative; - - /** - * There are infinite solutions to this conversion problem because - * a 2D coordinate is converted into a 3D coordinate. - * - * The user needs to manually give the 'up' value of the phys3 result. - */ - phys3_delta to_phys3(const CoordManager &mgr, phys_t up = phys_t::zero()) const; - viewport_delta to_viewport() const; -}; - - -// TODO: Remove -struct [[deprecated]] camgame : CoordXYAbsolute { - using CoordXYAbsolute::CoordXYAbsolute; - - /** - * See the comments for camgame_delta::to_phys3. - * - * TODO: Once we have terrain elevation, 'up' will not mean the absolute - * elevation, but instead the returned phys3 coordinate will be - * the intersection between the camgame line and the 3d terrain + - * up altitude. - */ - viewport to_viewport(const CoordManager &mgr) const; - camhud to_camhud(const CoordManager &mgr) const; - phys3 to_phys3(const CoordManager &mgr, phys_t up = phys_t::zero()) const; - tile to_tile(const CoordManager &mgr, phys_t up = phys_t::zero()) const; -}; - - struct camhud_delta : CoordXYRelative { using CoordXYRelative::CoordXYRelative; @@ -68,7 +33,7 @@ struct camhud : CoordXYAbsolute { using CoordXYAbsolute::CoordXYAbsolute; // coordinate conversions - viewport to_viewport(const CoordManager &mgr) const; + viewport to_viewport() const; }; @@ -79,12 +44,6 @@ struct viewport_delta : CoordXYRelative { camhud_delta to_camhud() const { return camhud_delta{this->x, this->y}; } - - // TODO: Remove - [[deprecated]] constexpr camgame_delta to_camgame() const { - return camgame_delta{this->x, this->y}; - } - [[deprecated]] phys3_delta to_phys3(const CoordManager &mgr, phys_t up) const; }; @@ -92,15 +51,10 @@ struct viewport : CoordXYAbsolute { using CoordXYAbsolute::CoordXYAbsolute; // coordinate conversions - camhud to_camhud(const CoordManager &mgr) const; + camhud to_camhud() const; // renderer conversions Eigen::Vector2f to_ndc_space(const std::shared_ptr &camera) const; - - // TODO: Remove - [[deprecated]] camgame to_camgame(const CoordManager &mgr) const; - [[deprecated]] phys3 to_phys3(const CoordManager &mgr, phys_t up = phys_t::zero()) const; - [[deprecated]] tile to_tile(const CoordManager &mgr, phys_t up = phys_t::zero()) const; }; @@ -108,11 +62,7 @@ struct input_delta : CoordXYRelative { using CoordXYRelative::CoordXYRelative; // coordinate conversions - viewport_delta to_viewport(const CoordManager &mgr) const; - - // TODO: Remove - [[deprecated]] camgame_delta to_camgame(const CoordManager &mgr) const; - [[deprecated]] phys3_delta to_phys3(const CoordManager &mgr, phys_t up = phys_t::zero()) const; + viewport_delta to_viewport(const std::shared_ptr &camera) const; }; @@ -120,13 +70,9 @@ struct input : CoordXYAbsolute { using CoordXYAbsolute::CoordXYAbsolute; // coordinate conversions - viewport to_viewport(const CoordManager &mgr) const; + viewport to_viewport(const std::shared_ptr &camera) const; phys3 to_phys3(const std::shared_ptr &camera) const; scene3 to_scene3(const std::shared_ptr &camera) const; - - // TODO: Remove - [[deprecated]] phys3 to_phys3(const CoordManager &mgr, phys_t up = phys_t::zero()) const; - [[deprecated]] camgame to_camgame(const CoordManager &mgr) const; }; diff --git a/libopenage/coord/scene.cpp b/libopenage/coord/scene.cpp index d34519bfe4..45e262d519 100644 --- a/libopenage/coord/scene.cpp +++ b/libopenage/coord/scene.cpp @@ -4,7 +4,6 @@ #include -#include "coord/coordmanager.h" #include "coord/pixel.h" #include "coord/tile.h" #include "util/math.h" @@ -108,7 +107,7 @@ Eigen::Vector3f scene3_delta::to_world_space() const { } float scene3_delta::to_angle(const coord::scene2_delta &other) const { - return this->to_scene2().to_angle(); + return this->to_scene2().to_angle(other); } scene2 scene3::to_scene2() const { diff --git a/libopenage/coord/tile.cpp b/libopenage/coord/tile.cpp index dbd68a0d5a..e20868ff98 100644 --- a/libopenage/coord/tile.cpp +++ b/libopenage/coord/tile.cpp @@ -2,8 +2,9 @@ #include "tile.h" -#include "../terrain/terrain.h" -#include "coordmanager.h" +#include "chunk.h" +#include "phys.h" + namespace openage::coord { @@ -37,34 +38,6 @@ tile_delta tile::get_pos_on_chunk() const { } -[[deprecated]] tile3 tile::to_tile3(const Terrain & /*terrain*/, tile_t altitude) const { - // TODO: once terrain elevations have been implemented, - // query the terrain elevation at {ne, se}. - tile_t elevation = 0; - - return tile3{this->ne, this->se, elevation + altitude}; -} - - -[[deprecated]] phys3 tile::to_phys3(const Terrain &terrain, tile_t altitude) const { - return this->to_tile3(terrain, altitude).to_phys3(); -} - - -[[deprecated]] camgame tile::to_camgame(const CoordManager &mgr, - const Terrain &terrain, - tile_t altitude) const { - return this->to_phys3(terrain, altitude).to_camgame(mgr); -} - - -[[deprecated]] viewport tile::to_viewport(const CoordManager &mgr, - const Terrain &terrain, - tile_t altitude) const { - return this->to_camgame(mgr, terrain, altitude).to_viewport(mgr); -} - - phys2 tile3::to_phys2() const { return this->to_tile().to_phys2(); } @@ -78,4 +51,12 @@ phys3 tile3::to_phys3() const { } +phys2_delta tile_delta::to_phys2() const { + return phys2_delta(this->ne, this->se); +} + +phys3_delta tile_delta::to_phys3(tile_t up) const { + return phys3_delta(this->ne, this->se, up); +} + } // namespace openage::coord diff --git a/libopenage/coord/tile.h b/libopenage/coord/tile.h index 4570564d32..5cb3f2475d 100644 --- a/libopenage/coord/tile.h +++ b/libopenage/coord/tile.h @@ -14,9 +14,6 @@ class Terrain; namespace coord { -class CoordManager; - - /* * Gameworld tile-related coordinate systems. * See doc/code/coordinate-systems.md for more information. @@ -25,6 +22,9 @@ class CoordManager; struct tile_delta : CoordNeSeRelative { using CoordNeSeRelative::CoordNeSeRelative; + + phys2_delta to_phys2() const; + phys3_delta to_phys3(tile_t up = 0) const; }; struct tile : CoordNeSeAbsolute { @@ -41,12 +41,6 @@ struct tile : CoordNeSeAbsolute { phys3 to_phys3(tile_t up = 0) const; chunk to_chunk() const; tile_delta get_pos_on_chunk() const; - - // TODO: Remove - [[deprecated]] tile3 to_tile3(const Terrain &terrain, tile_t altitude = 0) const; - [[deprecated]] phys3 to_phys3(const Terrain &terrain, tile_t altitude = 0) const; - [[deprecated]] camgame to_camgame(const CoordManager &mgr, const Terrain &terrain, tile_t altitude = 0) const; - [[deprecated]] viewport to_viewport(const CoordManager &mgr, const Terrain &terrain, tile_t altitude = 0) const; }; struct tile3_delta : CoordNeSeUpRelative { @@ -57,6 +51,7 @@ struct tile3_delta : CoordNeSeUpRelative { constexpr tile_delta to_tile() const { return tile_delta{this->ne, this->se}; } + phys3_delta to_phys3() const; }; struct tile3 : CoordNeSeUpAbsolute { diff --git a/libopenage/curve/map_filter_iterator.h b/libopenage/curve/map_filter_iterator.h index e514330f67..5e71c0789f 100644 --- a/libopenage/curve/map_filter_iterator.h +++ b/libopenage/curve/map_filter_iterator.h @@ -32,8 +32,6 @@ class MapFilterIterator : public CurveIterator { const time::time_t &to) : CurveIterator(base, container, from, to) {} - MapFilterIterator(const MapFilterIterator &) = default; - using CurveIterator::operator=; virtual bool valid() const override { diff --git a/libopenage/engine/engine.cpp b/libopenage/engine/engine.cpp index 9af6d4fe89..fa2c251b4d 100644 --- a/libopenage/engine/engine.cpp +++ b/libopenage/engine/engine.cpp @@ -55,7 +55,7 @@ Engine::Engine(mode mode, // if presenter is used, run it in a separate thread if (this->run_mode == mode::FULL) { - this->threads.emplace_back([&]() { + this->threads.emplace_back([&, debug_graphics]() { this->presenter->run(debug_graphics); // Make sure that the presenter gets destructed in the same thread diff --git a/libopenage/error/CMakeLists.txt b/libopenage/error/CMakeLists.txt index 9fefd61a5d..b54fa5e524 100644 --- a/libopenage/error/CMakeLists.txt +++ b/libopenage/error/CMakeLists.txt @@ -2,7 +2,6 @@ add_sources(libopenage backtrace.cpp demo.cpp error.cpp - gl_debug.cpp handlers.cpp stackanalyzer.cpp ) diff --git a/libopenage/error/gl_debug.cpp b/libopenage/error/gl_debug.cpp deleted file mode 100644 index fc89d33d74..0000000000 --- a/libopenage/error/gl_debug.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016-2023 the openage authors. See copying.md for legal info. - -#include "gl_debug.h" - -#include - -#include "log/message.h" - -#include "error/error.h" - -namespace openage::error { - -namespace { -void APIENTRY callback(GLenum source, GLenum, GLuint, GLenum, GLsizei, const GLchar *message, const void *) { - const char *source_name; - - switch (source) { - case GL_DEBUG_SOURCE_API: - source_name = "API"; - break; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: - source_name = "window system"; - break; - case GL_DEBUG_SOURCE_SHADER_COMPILER: - source_name = "shader compiler"; - break; - case GL_DEBUG_SOURCE_THIRD_PARTY: - source_name = "third party"; - break; - case GL_DEBUG_SOURCE_APPLICATION: - source_name = "application"; - break; - case GL_DEBUG_SOURCE_OTHER: - source_name = "other"; - break; - default: - source_name = "unknown"; - break; - } - - throw Error(MSG(err) << "OpenGL error from " << source_name << ": '" << message << "'."); -} - -} // namespace - -SDL_GLContext create_debug_context(SDL_Window *window) { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); - - auto ctx = SDL_GL_CreateContext(window); - - if (ctx != nullptr) { - GLint flags; - glGetIntegerv(GL_CONTEXT_FLAGS, &flags); - - if (!(flags & GL_CONTEXT_FLAG_DEBUG_BIT)) - throw Error(MSG(err) << "Failed creating a debug OpenGL context."); - - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE); - - glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, nullptr, GL_TRUE); - glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DONT_CARE, 0, nullptr, GL_TRUE); - - glDebugMessageCallback(callback, nullptr); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - } - - return ctx; -} - -} // namespace openage::error diff --git a/libopenage/error/gl_debug.h b/libopenage/error/gl_debug.h deleted file mode 100644 index a874c1086e..0000000000 --- a/libopenage/error/gl_debug.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace openage { -namespace error { - -SDL_GLContext create_debug_context(SDL_Window *window); - -}} // openage::error diff --git a/libopenage/event/demo/main.cpp b/libopenage/event/demo/main.cpp index 442e9910c7..3ccbed5ac6 100644 --- a/libopenage/event/demo/main.cpp +++ b/libopenage/event/demo/main.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include "config.h" #include "event/demo/aicontroller.h" @@ -13,6 +13,7 @@ #include "event/demo/physics.h" #include "event/event.h" #include "event/event_loop.h" +#include "renderer/gui/integration/public/gui_application_with_logger.h" #if WITH_NCURSES #ifdef __MINGW32__ @@ -41,6 +42,7 @@ enum class timescale { void curvepong(bool disable_gui, bool no_human) { + renderer::gui::GuiApplicationWithLogger gui_app{}; bool enable_gui = not disable_gui; bool human_player = not no_human; @@ -99,6 +101,8 @@ void curvepong(bool disable_gui, bool no_human) { while (state->p1->lives->get(now) > 0 and state->p2->lives->get(now) > 0) { auto loop_start = Clock::now(); + gui_app.process_events(); + #if WITH_NCURSES if (enable_gui) { gui->clear(); @@ -157,7 +161,7 @@ void curvepong(bool disable_gui, bool no_human) { if (speed == timescale::NOSLEEP) { // increase the simulation loop time a bit - SDL_Delay(5); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); } dt_ms_t dt_us = Clock::now() - loop_start; @@ -166,7 +170,7 @@ void curvepong(bool disable_gui, bool no_human) { dt_ms_t wait_time = per_frame - dt_us; if (wait_time > dt_ms_t::zero()) { - SDL_Delay(wait_time.count()); + std::this_thread::sleep_for(wait_time); } } diff --git a/libopenage/game_renderer.cpp b/libopenage/game_renderer.cpp deleted file mode 100644 index 530d87ad92..0000000000 --- a/libopenage/game_renderer.cpp +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include -#include -#include -#include -#include - -#include "console/console.h" -#include "game_renderer.h" -#include "gamedata/color_dummy.h" -#include "gamestate/old/game_main.h" -#include "gamestate/old/game_spec.h" -#include "input/input_manager.h" -#include "legacy_engine.h" -#include "log/log.h" -#include "renderer/text.h" -#include "terrain/terrain.h" -#include "unit/action.h" -#include "unit/command.h" -#include "unit/producer.h" -#include "unit/unit.h" -#include "unit/unit_texture.h" -#include "util/externalprofiler.h" -#include "util/timer.h" - -namespace openage { - -RenderOptions::RenderOptions() : - OptionNode{"RendererOptions"}, - draw_debug{this, "draw_debug", false}, - terrain_blending{this, "terrain_blending", true} {} - -GameRenderer::GameRenderer(LegacyEngine *e) : - engine{e} { - // set options structure - this->settings.set_parent(this->engine); - - // engine callbacks - this->engine->register_draw_action(this); - - // fetch asset loading dir - util::Path asset_dir = engine->get_root_dir()["assets"]; - - // load textures and stuff - gaben = new Texture{asset_dir["test"]["textures"]["gaben.png"]}; - - std::vector player_color_lines = util::read_csv_file( - asset_dir["converted/player_palette.docx"]); - - std::unique_ptr playercolors = std::make_unique(player_color_lines.size() * 4); - for (size_t i = 0; i < player_color_lines.size(); i++) { - auto line = &player_color_lines[i]; - playercolors[i * 4] = line->r / 255.0; - playercolors[i * 4 + 1] = line->g / 255.0; - playercolors[i * 4 + 2] = line->b / 255.0; - playercolors[i * 4 + 3] = line->a / 255.0; - } - - // shader initialisation - // read shader source codes and create shader objects for wrapping them. - const char *shader_header_code = "#version 120\n"; - std::string equals_epsilon_code = asset_dir["shaders/equalsEpsilon.glsl"].open().read(); - std::string texture_vert_code = asset_dir["shaders/maptexture.vert.glsl"].open().read(); - auto plaintexture_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, texture_vert_code.c_str()}); - - std::string texture_frag_code = asset_dir["shaders/maptexture.frag.glsl"].open().read(); - auto plaintexture_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, texture_frag_code.c_str()}); - - std::string teamcolor_frag_code = asset_dir["shaders/teamcolors.frag.glsl"].open().read(); - std::stringstream ss; - ss << player_color_lines.size(); - auto teamcolor_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{ - shader_header_code, - ("#define NUM_OF_PLAYER_COLORS " + ss.str() + "\n").c_str(), - equals_epsilon_code.c_str(), - teamcolor_frag_code.c_str()}); - - std::string alphamask_vert_code = asset_dir["shaders/alphamask.vert.glsl"].open().read(); - auto alphamask_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, alphamask_vert_code.c_str()}); - - std::string alphamask_frag_code = asset_dir["shaders/alphamask.frag.glsl"].open().read(); - auto alphamask_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, alphamask_frag_code.c_str()}); - - std::string texturefont_vert_code = asset_dir["shaders/texturefont.vert.glsl"].open().read(); - auto texturefont_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, texturefont_vert_code.c_str()}); - - std::string texturefont_frag_code = asset_dir["shaders/texturefont.frag.glsl"].open().read(); - auto texturefont_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, texturefont_frag_code.c_str()}); - - // create program for rendering simple textures - texture_shader::program = new shader::Program(plaintexture_vert.get(), plaintexture_frag.get()); - texture_shader::program->link(); - texture_shader::texture = texture_shader::program->get_uniform_id("texture"); - texture_shader::tex_coord = texture_shader::program->get_attribute_id("tex_coordinates"); - texture_shader::program->use(); - glUniform1i(texture_shader::texture, 0); - texture_shader::program->stopusing(); - - - // create program for tinting textures at alpha-marked pixels - // with team colors - teamcolor_shader::program = new shader::Program(plaintexture_vert.get(), teamcolor_frag.get()); - teamcolor_shader::program->link(); - teamcolor_shader::texture = teamcolor_shader::program->get_uniform_id("texture"); - teamcolor_shader::tex_coord = teamcolor_shader::program->get_attribute_id("tex_coordinates"); - teamcolor_shader::player_id_var = teamcolor_shader::program->get_uniform_id("player_number"); - teamcolor_shader::alpha_marker_var = teamcolor_shader::program->get_uniform_id("alpha_marker"); - teamcolor_shader::player_color_var = teamcolor_shader::program->get_uniform_id("player_color"); - teamcolor_shader::program->use(); - glUniform1i(teamcolor_shader::texture, 0); - glUniform1f(teamcolor_shader::alpha_marker_var, 254.0 / 255.0); - // fill the teamcolor shader's player color table: - glUniform4fv(teamcolor_shader::player_color_var, 64, playercolors.get()); - teamcolor_shader::program->stopusing(); - - - // create program for drawing textures that are alpha-masked before - alphamask_shader::program = new shader::Program(alphamask_vert.get(), alphamask_frag.get()); - alphamask_shader::program->link(); - alphamask_shader::base_coord = alphamask_shader::program->get_attribute_id("base_tex_coordinates"); - alphamask_shader::mask_coord = alphamask_shader::program->get_attribute_id("mask_tex_coordinates"); - alphamask_shader::show_mask = alphamask_shader::program->get_uniform_id("show_mask"); - alphamask_shader::base_texture = alphamask_shader::program->get_uniform_id("base_texture"); - alphamask_shader::mask_texture = alphamask_shader::program->get_uniform_id("mask_texture"); - alphamask_shader::program->use(); - glUniform1i(alphamask_shader::base_texture, 0); - glUniform1i(alphamask_shader::mask_texture, 1); - alphamask_shader::program->stopusing(); - - // Create program for texture based font rendering - texturefont_shader::program = new shader::Program(texturefont_vert.get(), texturefont_frag.get()); - texturefont_shader::program->link(); - texturefont_shader::texture = texturefont_shader::program->get_uniform_id("texture"); - texturefont_shader::color = texturefont_shader::program->get_uniform_id("color"); - texturefont_shader::tex_coord = texturefont_shader::program->get_attribute_id("tex_coordinates"); - texturefont_shader::program->use(); - glUniform1i(texturefont_shader::texture, 0); - texturefont_shader::program->stopusing(); - - // Renderer keybinds - // TODO: a renderer settings struct - // would allow these to be put somewhere better - input::ActionManager &action = this->engine->get_action_manager(); - auto &global_input_context = engine->get_input_manager().get_global_context(); - global_input_context.bind(action.get("TOGGLE_BLENDING"), [this](const input::action_arg_t &) { - this->settings.terrain_blending.value = !this->settings.terrain_blending.value; - }); - global_input_context.bind(action.get("TOGGLE_UNIT_DEBUG"), [this](const input::action_arg_t &) { - this->settings.draw_debug.value = !this->settings.draw_debug.value; - - log::log(MSG(dbg) << "Toggle debug grid"); - - // TODO remove this hack, use render settings instead - UnitAction::show_debug = !UnitAction::show_debug; - }); - - log::log(MSG(dbg) << "Loaded Renderer"); -} - -GameRenderer::~GameRenderer() { - // oh noes, release hl3 before that! - delete this->gaben; - - delete texture_shader::program; - delete teamcolor_shader::program; - delete alphamask_shader::program; - delete texturefont_shader::program; -} - - -bool GameRenderer::on_draw() { - // draw terrain - GameMain *game = this->engine->get_game(); - - if (game) { - // draw gaben, our great and holy protector, bringer of the half-life 3. - gaben->draw(this->engine->coord, coord::camgame{0, 0}); - - // TODO move render code out of terrain - if (game->terrain) { - game->terrain->draw(this->engine, &this->settings); - } - } - return true; -} - -GameMain *GameRenderer::game() const { - return this->engine->get_game(); -} - -GameSpec *GameRenderer::game_spec() const { - return this->game()->get_spec(); -} - -} // namespace openage diff --git a/libopenage/gamedata/CMakeLists.txt b/libopenage/gamedata/CMakeLists.txt deleted file mode 100644 index 9eb8632148..0000000000 --- a/libopenage/gamedata/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -add_sources(libopenage - blending_mode_dummy.cpp - civilisation_dummy.cpp - color_dummy.cpp - gamedata_dummy.cpp - graphic_dummy.cpp - player_color_dummy.cpp - research_dummy.cpp - sound_dummy.cpp - string_resource_dummy.cpp - tech_dummy.cpp - terrain_dummy.cpp - texture_dummy.cpp - unit_dummy.cpp - util_dummy.cpp -) diff --git a/libopenage/gamedata/about b/libopenage/gamedata/about deleted file mode 100644 index f9e60f268e..0000000000 --- a/libopenage/gamedata/about +++ /dev/null @@ -1,3 +0,0 @@ -all source files in this directory are auto-generated during the build process. - -this file mainly exists to ensure that the directory isn't empty. diff --git a/libopenage/gamedata/blending_mode_dummy.cpp b/libopenage/gamedata/blending_mode_dummy.cpp deleted file mode 100644 index 468c55c84e..0000000000 --- a/libopenage/gamedata/blending_mode_dummy.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "blending_mode_dummy.h" -#include "error/error.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t blending_mode::member_count; -int blending_mode::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', blending_mode::member_count - ); - - if (buf.size() != blending_mode::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing blending_mode led to " - << buf.size() - << " columns (expected " - << blending_mode::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->blend_mode) != 1) { return 0; } - - return -1; -} - -bool blending_mode::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/blending_mode_dummy.h b/libopenage/gamedata/blending_mode_dummy.h deleted file mode 100644 index 55b29788ae..0000000000 --- a/libopenage/gamedata/blending_mode_dummy.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * describes one blending mode, a blending transition shape between two different terrain types. - */ -struct blending_mode { - int32_t blend_mode; - static constexpr size_t member_count = 1; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/civilisation_dummy.cpp b/libopenage/gamedata/civilisation_dummy.cpp deleted file mode 100644 index e4b0300edf..0000000000 --- a/libopenage/gamedata/civilisation_dummy.cpp +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include -#include "civilisation_dummy.h" -#include "error/error.h" -#include "unit_dummy.h" -#include "util_dummy.h" -#include "util/csv.h" -#include "util/path.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t civilisation::member_count; -int civilisation::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', civilisation::member_count - ); - - if (buf.size() != civilisation::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing civilisation led to " - << buf.size() - << " columns (expected " - << civilisation::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hhd", &this->player_type) != 1) { return 0; } - this->name = buf[1]; - if (sscanf(buf[2].c_str(), "%hd", &this->tech_tree_id) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hd", &this->team_bonus_id) != 1) { return 3; } - if (sscanf(buf[5].c_str(), "%hhd", &this->icon_set) != 1) { return 5; } - this->units.subdata_meta.filename = buf[6]; - - return -1; -} - -bool civilisation::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->units.recurse(storage, basedir); - - return true; -} - -int unit_types::fill(const std::string & /*line*/) { - return -1; -} -bool unit_types::recurse(const openage::util::CSVCollection &storage, - const std::string &basedir) { - - // the .filename was set by the previous entry parser already - // so now read the index-file entries - this->subdata_meta.read(storage, basedir); - - int subtype_count = this->subdata_meta.data.size(); - if (subtype_count != 9) { - throw openage::error::Error( - ERR << "multisubtype index file entry count mismatched!" - << subtype_count << " != 9" - ); - } - - // the recursed data files are relative to the subdata_meta filename - std::string metadata_dir = basedir + openage::util::fslike::PATHSEP + openage::util::dirname(this->subdata_meta.filename); - int idx; - int idxtry; - - // read subtype 'action' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "action") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for action!" - ); - } - - // the filename is relative to the metadata file! - this->action.filename = this->subdata_meta.data[idx].filename; - this->action.read(storage, metadata_dir); - - // read subtype 'animated' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "animated") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for animated!" - ); - } - - // the filename is relative to the metadata file! - this->animated.filename = this->subdata_meta.data[idx].filename; - this->animated.read(storage, metadata_dir); - - // read subtype 'building' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "building") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for building!" - ); - } - - // the filename is relative to the metadata file! - this->building.filename = this->subdata_meta.data[idx].filename; - this->building.read(storage, metadata_dir); - - // read subtype 'doppelganger' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "doppelganger") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for doppelganger!" - ); - } - - // the filename is relative to the metadata file! - this->doppelganger.filename = this->subdata_meta.data[idx].filename; - this->doppelganger.read(storage, metadata_dir); - - // read subtype 'living' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "living") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for living!" - ); - } - - // the filename is relative to the metadata file! - this->living.filename = this->subdata_meta.data[idx].filename; - this->living.read(storage, metadata_dir); - - // read subtype 'missile' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "missile") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for missile!" - ); - } - - // the filename is relative to the metadata file! - this->missile.filename = this->subdata_meta.data[idx].filename; - this->missile.read(storage, metadata_dir); - - // read subtype 'moving' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "moving") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for moving!" - ); - } - - // the filename is relative to the metadata file! - this->moving.filename = this->subdata_meta.data[idx].filename; - this->moving.read(storage, metadata_dir); - - // read subtype 'object' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "object") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for object!" - ); - } - - // the filename is relative to the metadata file! - this->object.filename = this->subdata_meta.data[idx].filename; - this->object.read(storage, metadata_dir); - - // read subtype 'tree' - idx = -1; - idxtry = 0; - // find the index of the subdata in the metadata - for (auto &file_reference : this->subdata_meta.data) { - if (file_reference.subtype == "tree") { - idx = idxtry; - break; - } - idxtry += 1; - } - if (idx == -1) { - throw openage::error::Error( - ERR << "multisubtype index file contains no entry for tree!" - ); - } - - // the filename is relative to the metadata file! - this->tree.filename = this->subdata_meta.data[idx].filename; - this->tree.read(storage, metadata_dir); - - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/civilisation_dummy.h b/libopenage/gamedata/civilisation_dummy.h deleted file mode 100644 index 1627b4112f..0000000000 --- a/libopenage/gamedata/civilisation_dummy.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include -#include "unit_dummy.h" -#include "util_dummy.h" -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -struct unit_types { - struct openage::util::csv_subdata action; - struct openage::util::csv_subdata animated; - struct openage::util::csv_subdata building; - struct openage::util::csv_subdata doppelganger; - struct openage::util::csv_subdata living; - struct openage::util::csv_subdata missile; - struct openage::util::csv_subdata moving; - struct openage::util::csv_subdata object; - struct openage::util::csv_subdata tree; - struct openage::util::csv_subdata subdata_meta; - - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * describes a civilisation. - */ -struct civilisation { - int8_t player_type; - std::string name; - int16_t tech_tree_id; - int16_t team_bonus_id; - int8_t icon_set; - unit_types units; - static constexpr size_t member_count = 7; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/color_dummy.cpp b/libopenage/gamedata/color_dummy.cpp deleted file mode 100644 index 9985fb0b9d..0000000000 --- a/libopenage/gamedata/color_dummy.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "color_dummy.h" -#include "error/error.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t palette_color::member_count; -int palette_color::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', palette_color::member_count - ); - - if (buf.size() != palette_color::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing palette_color led to " - << buf.size() - << " columns (expected " - << palette_color::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->idx) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhu", &this->r) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hhu", &this->g) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hhu", &this->b) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%hhu", &this->a) != 1) { return 4; } - - return -1; -} - -bool palette_color::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/color_dummy.h b/libopenage/gamedata/color_dummy.h deleted file mode 100644 index 4c6915e5cb..0000000000 --- a/libopenage/gamedata/color_dummy.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * indexed color storage. - */ -struct palette_color { - int32_t idx; - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; - static constexpr size_t member_count = 5; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/gamedata_dummy.cpp b/libopenage/gamedata/gamedata_dummy.cpp deleted file mode 100644 index 959df5237a..0000000000 --- a/libopenage/gamedata/gamedata_dummy.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "gamedata_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t empiresdat::member_count; -int empiresdat::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', empiresdat::member_count - ); - - if (buf.size() != empiresdat::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing empiresdat led to " - << buf.size() - << " columns (expected " - << empiresdat::member_count - << ")!" - ); - } - - this->versionstr = buf[0]; - this->terrain_restrictions.filename = buf[1]; - this->player_colors.filename = buf[2]; - this->sounds.filename = buf[3]; - this->graphics.filename = buf[4]; - if (sscanf(buf[5].c_str(), "%d", &this->virt_function_ptr) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%d", &this->map_pointer) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%d", &this->map_width) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%d", &this->map_height) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%d", &this->world_width) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%d", &this->world_height) != 1) { return 10; } - this->tile_sizes.filename = buf[11]; - if (sscanf(buf[12].c_str(), "%hd", &this->padding1) != 1) { return 12; } - this->terrains.filename = buf[13]; - this->terrain_border.filename = buf[14]; - if (sscanf(buf[15].c_str(), "%d", &this->map_row_offset) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%f", &this->map_min_x) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%f", &this->map_min_y) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%f", &this->map_max_x) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%f", &this->map_max_y) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%f", &this->map_max_xplus1) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%f", &this->map_min_yplus1) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->current_row) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hd", &this->current_column) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->block_beginn_row) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->block_end_row) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->block_begin_column) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->block_end_column) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%d", &this->search_map_ptr) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%d", &this->search_map_rows_ptr) != 1) { return 29; } - if (sscanf(buf[30].c_str(), "%hhd", &this->any_frame_change) != 1) { return 30; } - if (sscanf(buf[31].c_str(), "%hhd", &this->map_visible_flag) != 1) { return 31; } - if (sscanf(buf[32].c_str(), "%hhd", &this->fog_flag) != 1) { return 32; } - this->effect_bundles.filename = buf[33]; - this->unit_headers.filename = buf[34]; - this->civs.filename = buf[35]; - this->researches.filename = buf[36]; - if (sscanf(buf[37].c_str(), "%d", &this->time_slice) != 1) { return 37; } - if (sscanf(buf[38].c_str(), "%d", &this->unit_kill_rate) != 1) { return 38; } - if (sscanf(buf[39].c_str(), "%d", &this->unit_kill_total) != 1) { return 39; } - if (sscanf(buf[40].c_str(), "%d", &this->unit_hitpoint_rate) != 1) { return 40; } - if (sscanf(buf[41].c_str(), "%d", &this->unit_hitpoint_total) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%d", &this->razing_kill_rate) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->razing_kill_total) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->total_unit_tech_groups) != 1) { return 44; } - this->age_connections.filename = buf[45]; - this->building_connections.filename = buf[46]; - this->unit_connections.filename = buf[47]; - this->tech_connections.filename = buf[48]; - - return -1; -} - -bool empiresdat::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->terrain_restrictions.read(storage, basedir); - this->player_colors.read(storage, basedir); - this->sounds.read(storage, basedir); - this->graphics.read(storage, basedir); - this->tile_sizes.read(storage, basedir); - this->terrains.read(storage, basedir); - this->terrain_border.read(storage, basedir); - this->effect_bundles.read(storage, basedir); - this->unit_headers.read(storage, basedir); - this->civs.read(storage, basedir); - this->researches.read(storage, basedir); - this->age_connections.read(storage, basedir); - this->building_connections.read(storage, basedir); - this->unit_connections.read(storage, basedir); - this->tech_connections.read(storage, basedir); - - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/gamedata_dummy.h b/libopenage/gamedata/gamedata_dummy.h deleted file mode 100644 index d702b8cd4f..0000000000 --- a/libopenage/gamedata/gamedata_dummy.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "civilisation_dummy.h" -#include "graphic_dummy.h" -#include "player_color_dummy.h" -#include "research_dummy.h" -#include "sound_dummy.h" -#include "tech_dummy.h" -#include "terrain_dummy.h" -#include "unit_dummy.h" -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * empires2_x1_p1.dat structure - */ -struct empiresdat { - std::string versionstr; - openage::util::csv_subdata terrain_restrictions; - openage::util::csv_subdata player_colors; - openage::util::csv_subdata sounds; - openage::util::csv_subdata graphics; - int32_t virt_function_ptr; - int32_t map_pointer; - int32_t map_width; - int32_t map_height; - int32_t world_width; - int32_t world_height; - openage::util::csv_subdata tile_sizes; - int16_t padding1; - openage::util::csv_subdata terrains; - openage::util::csv_subdata terrain_border; - int32_t map_row_offset; - float map_min_x; - float map_min_y; - float map_max_x; - float map_max_y; - float map_max_xplus1; - float map_min_yplus1; - int16_t current_row; - int16_t current_column; - int16_t block_beginn_row; - int16_t block_end_row; - int16_t block_begin_column; - int16_t block_end_column; - int32_t search_map_ptr; - int32_t search_map_rows_ptr; - int8_t any_frame_change; - int8_t map_visible_flag; - int8_t fog_flag; - openage::util::csv_subdata effect_bundles; - openage::util::csv_subdata unit_headers; - openage::util::csv_subdata civs; - openage::util::csv_subdata researches; - int32_t time_slice; - int32_t unit_kill_rate; - int32_t unit_kill_total; - int32_t unit_hitpoint_rate; - int32_t unit_hitpoint_total; - int32_t razing_kill_rate; - int32_t razing_kill_total; - int32_t total_unit_tech_groups; - openage::util::csv_subdata age_connections; - openage::util::csv_subdata building_connections; - openage::util::csv_subdata unit_connections; - openage::util::csv_subdata tech_connections; - static constexpr size_t member_count = 49; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/graphic_dummy.cpp b/libopenage/gamedata/graphic_dummy.cpp deleted file mode 100644 index 6a0d6b63cb..0000000000 --- a/libopenage/gamedata/graphic_dummy.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "graphic_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t graphic::member_count; -constexpr size_t graphic_attack_sound::member_count; -constexpr size_t graphic_delta::member_count; -constexpr size_t sound_prop::member_count; -int graphic_attack_sound::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', graphic_attack_sound::member_count - ); - - if (buf.size() != graphic_attack_sound::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing graphic_attack_sound led to " - << buf.size() - << " columns (expected " - << graphic_attack_sound::member_count - << ")!" - ); - } - - this->sound_props.filename = buf[0]; - - return -1; -} - -bool graphic_attack_sound::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->sound_props.read(storage, basedir); - - return true; -} - -int graphic_delta::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', graphic_delta::member_count - ); - - if (buf.size() != graphic_delta::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing graphic_delta led to " - << buf.size() - << " columns (expected " - << graphic_delta::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->graphic_id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->padding_1) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->sprite_ptr) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hd", &this->offset_x) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%hd", &this->offset_y) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->display_angle) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->padding_2) != 1) { return 6; } - - return -1; -} - -bool graphic_delta::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int graphic::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', graphic::member_count - ); - - if (buf.size() != graphic::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing graphic led to " - << buf.size() - << " columns (expected " - << graphic::member_count - << ")!" - ); - } - - this->name = buf[0]; - this->filename = buf[1]; - if (sscanf(buf[2].c_str(), "%d", &this->slp_id) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hhd", &this->is_loaded) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%hhd", &this->old_color_flag) != 1) { return 4; } - // parse enum graphics_layer - if (buf[5] == "DUMMY") { - this->layer = graphics_layer::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[5] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[6].c_str(), "%hhd", &this->player_color_force_id) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hhd", &this->adapt_color) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhu", &this->transparent_selection) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->sound_id) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%hu", &this->frame_count) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hu", &this->angle_count) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->speed_adjust) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->frame_rate) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->replay_delay) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hhd", &this->sequence_type) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->graphic_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hhd", &this->mirroring_mode) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->editor_flag) != 1) { return 18; } - this->graphic_deltas.filename = buf[19]; - this->graphic_attack_sounds.filename = buf[20]; - - return -1; -} - -bool graphic::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->graphic_deltas.read(storage, basedir); - this->graphic_attack_sounds.read(storage, basedir); - - return true; -} - -int sound_prop::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', sound_prop::member_count - ); - - if (buf.size() != sound_prop::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing sound_prop led to " - << buf.size() - << " columns (expected " - << sound_prop::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->sound_delay) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->sound_id) != 1) { return 1; } - - return -1; -} - -bool sound_prop::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/graphic_dummy.h b/libopenage/gamedata/graphic_dummy.h deleted file mode 100644 index 34f0a2a82f..0000000000 --- a/libopenage/gamedata/graphic_dummy.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * delta definitions for ingame graphics files. - */ -struct graphic_delta { - int16_t graphic_id; - int16_t padding_1; - int32_t sprite_ptr; - int16_t offset_x; - int16_t offset_y; - int16_t display_angle; - int16_t padding_2; - static constexpr size_t member_count = 7; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -enum class graphics_layer { - DUMMY -}; - - -/** - * sound id and delay definition for graphics sounds. - */ -struct sound_prop { - int16_t sound_delay; - int16_t sound_id; - static constexpr size_t member_count = 2; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * attack sounds for a given graphics file. - */ -struct graphic_attack_sound { - openage::util::csv_subdata sound_props; - static constexpr size_t member_count = 1; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * metadata for ingame graphics files. - */ -struct graphic { - std::string name; - std::string filename; - int32_t slp_id; - int8_t is_loaded; - int8_t old_color_flag; - graphics_layer layer; - int8_t player_color_force_id; - int8_t adapt_color; - uint8_t transparent_selection; - int16_t sound_id; - uint16_t frame_count; - uint16_t angle_count; - float speed_adjust; - float frame_rate; - float replay_delay; - int8_t sequence_type; - int16_t graphic_id; - int8_t mirroring_mode; - int8_t editor_flag; - openage::util::csv_subdata graphic_deltas; - openage::util::csv_subdata graphic_attack_sounds; - static constexpr size_t member_count = 21; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/player_color_dummy.cpp b/libopenage/gamedata/player_color_dummy.cpp deleted file mode 100644 index 949b0de3c1..0000000000 --- a/libopenage/gamedata/player_color_dummy.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "player_color_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t player_color::member_count; -int player_color::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', player_color::member_count - ); - - if (buf.size() != player_color::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing player_color led to " - << buf.size() - << " columns (expected " - << player_color::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%d", &this->player_color_base) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->outline_color) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%d", &this->unit_selection_color1) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%d", &this->unit_selection_color2) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%d", &this->minimap_color1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%d", &this->minimap_color2) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%d", &this->minimap_color3) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%d", &this->statistics_text_color) != 1) { return 8; } - - return -1; -} - -bool player_color::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/player_color_dummy.h b/libopenage/gamedata/player_color_dummy.h deleted file mode 100644 index ced379fba4..0000000000 --- a/libopenage/gamedata/player_color_dummy.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * describes player color settings. - */ -struct player_color { - int32_t id; - int32_t player_color_base; - int32_t outline_color; - int32_t unit_selection_color1; - int32_t unit_selection_color2; - int32_t minimap_color1; - int32_t minimap_color2; - int32_t minimap_color3; - int32_t statistics_text_color; - static constexpr size_t member_count = 9; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/research_dummy.cpp b/libopenage/gamedata/research_dummy.cpp deleted file mode 100644 index 3b3a9af15b..0000000000 --- a/libopenage/gamedata/research_dummy.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "research_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t tech::member_count; -constexpr size_t tech_resource_cost::member_count; -int tech::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', tech::member_count - ); - - if (buf.size() != tech::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing tech led to " - << buf.size() - << " columns (expected " - << tech::member_count - << ")!" - ); - } - - this->research_resource_costs.filename = buf[1]; - if (sscanf(buf[2].c_str(), "%hd", &this->required_tech_count) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hd", &this->civilization_id) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%hd", &this->full_tech_mode) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->research_location_id) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hu", &this->language_dll_name) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hu", &this->language_dll_description) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hd", &this->research_time) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->tech_effect_id) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%hd", &this->tech_type) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hd", &this->icon_id) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%hhd", &this->button_id) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%d", &this->language_dll_help) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%d", &this->language_dll_techtree) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%d", &this->hotkey) != 1) { return 15; } - this->name = buf[16]; - - return -1; -} - -bool tech::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->research_resource_costs.read(storage, basedir); - - return true; -} - -int tech_resource_cost::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', tech_resource_cost::member_count - ); - - if (buf.size() != tech_resource_cost::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing tech_resource_cost led to " - << buf.size() - << " columns (expected " - << tech_resource_cost::member_count - << ")!" - ); - } - - // parse enum resource_types - if (buf[0] == "DUMMY") { - this->type_id = resource_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[0] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[1].c_str(), "%hd", &this->amount) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hhd", &this->enabled) != 1) { return 2; } - - return -1; -} - -bool tech_resource_cost::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/research_dummy.h b/libopenage/gamedata/research_dummy.h deleted file mode 100644 index f1a3205c16..0000000000 --- a/libopenage/gamedata/research_dummy.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "unit_dummy.h" -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * amount definition for a single type resource for researches. - */ -struct tech_resource_cost { - resource_types type_id; - int16_t amount; - int8_t enabled; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * one researchable technology. - */ -struct tech { - openage::util::csv_subdata research_resource_costs; - int16_t required_tech_count; - int16_t civilization_id; - int16_t full_tech_mode; - int16_t research_location_id; - uint16_t language_dll_name; - uint16_t language_dll_description; - int16_t research_time; - int16_t tech_effect_id; - int16_t tech_type; - int16_t icon_id; - int8_t button_id; - int32_t language_dll_help; - int32_t language_dll_techtree; - int32_t hotkey; - std::string name; - static constexpr size_t member_count = 17; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/sound_dummy.cpp b/libopenage/gamedata/sound_dummy.cpp deleted file mode 100644 index 67d781d0c0..0000000000 --- a/libopenage/gamedata/sound_dummy.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "sound_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t sound::member_count; -constexpr size_t sound_item::member_count; -int sound::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', sound::member_count - ); - - if (buf.size() != sound::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing sound led to " - << buf.size() - << " columns (expected " - << sound::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->sound_id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->play_delay) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->cache_time) != 1) { return 2; } - this->sound_items.filename = buf[3]; - - return -1; -} - -int sound_item::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', sound_item::member_count - ); - - if (buf.size() != sound_item::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing sound_item led to " - << buf.size() - << " columns (expected " - << sound_item::member_count - << ")!" - ); - } - - this->filename = buf[0]; - if (sscanf(buf[1].c_str(), "%d", &this->resource_id) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hd", &this->probablilty) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hd", &this->civilization_id) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%hd", &this->icon_set) != 1) { return 4; } - - return -1; -} - -bool sound_item::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -bool sound::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->sound_items.read(storage, basedir); - - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/sound_dummy.h b/libopenage/gamedata/sound_dummy.h deleted file mode 100644 index 7c004cba5a..0000000000 --- a/libopenage/gamedata/sound_dummy.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * one possible file for a sound. - */ -struct sound_item { - std::string filename; - int32_t resource_id; - int16_t probablilty; - int16_t civilization_id; - int16_t icon_set; - static constexpr size_t member_count = 5; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * describes a sound, consisting of several sound items. - */ -struct sound { - int16_t sound_id; - int16_t play_delay; - int32_t cache_time; - openage::util::csv_subdata sound_items; - static constexpr size_t member_count = 4; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/string_resource_dummy.cpp b/libopenage/gamedata/string_resource_dummy.cpp deleted file mode 100644 index 7030d15150..0000000000 --- a/libopenage/gamedata/string_resource_dummy.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "string_resource_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t string_resource::member_count; -int string_resource::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', string_resource::member_count - ); - - if (buf.size() != string_resource::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing string_resource led to " - << buf.size() - << " columns (expected " - << string_resource::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->id) != 1) { return 0; } - this->lang = buf[1]; - this->text = buf[2]; - - return -1; -} - -bool string_resource::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/string_resource_dummy.h b/libopenage/gamedata/string_resource_dummy.h deleted file mode 100644 index 7673489566..0000000000 --- a/libopenage/gamedata/string_resource_dummy.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * string id/language to text mapping, extracted from language.dll file. - */ -struct string_resource { - int32_t id; - std::string lang; - std::string text; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/tech_dummy.cpp b/libopenage/gamedata/tech_dummy.cpp deleted file mode 100644 index f2697695db..0000000000 --- a/libopenage/gamedata/tech_dummy.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "tech_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t age_tech_tree::member_count; -constexpr size_t building_connection::member_count; -constexpr size_t effect_bundle::member_count; -constexpr size_t other_connection::member_count; -constexpr size_t research_connection::member_count; -constexpr size_t tech_effect::member_count; -constexpr size_t unit_connection::member_count; -int age_tech_tree::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', age_tech_tree::member_count - ); - - if (buf.size() != age_tech_tree::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing age_tech_tree led to " - << buf.size() - << " columns (expected " - << age_tech_tree::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhd", &this->status) != 1) { return 1; } - if (sscanf(buf[5].c_str(), "%d", &this->connected_slots_used) != 1) { return 5; } - this->other_connections.filename = buf[7]; - if (sscanf(buf[8].c_str(), "%hhd", &this->building_level_count) != 1) { return 8; } - if (sscanf(buf[11].c_str(), "%hhd", &this->max_age_length) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%d", &this->line_mode) != 1) { return 12; } - - return -1; -} - -bool age_tech_tree::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->other_connections.read(storage, basedir); - - return true; -} - -int building_connection::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', building_connection::member_count - ); - - if (buf.size() != building_connection::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing building_connection led to " - << buf.size() - << " columns (expected " - << building_connection::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->id) != 1) { return 0; } - if (sscanf(buf[4].c_str(), "%d", &this->connected_slots_used) != 1) { return 4; } - this->other_connections.filename = buf[6]; - if (sscanf(buf[7].c_str(), "%hhd", &this->location_in_age) != 1) { return 7; } - if (sscanf(buf[10].c_str(), "%d", &this->line_mode) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%d", &this->enabling_research) != 1) { return 11; } - - return -1; -} - -bool building_connection::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->other_connections.read(storage, basedir); - - return true; -} - -int effect_bundle::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', effect_bundle::member_count - ); - - if (buf.size() != effect_bundle::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing effect_bundle led to " - << buf.size() - << " columns (expected " - << effect_bundle::member_count - << ")!" - ); - } - - this->name = buf[0]; - this->effects.filename = buf[1]; - - return -1; -} - -bool effect_bundle::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->effects.read(storage, basedir); - - return true; -} - -int other_connection::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', other_connection::member_count - ); - - if (buf.size() != other_connection::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing other_connection led to " - << buf.size() - << " columns (expected " - << other_connection::member_count - << ")!" - ); - } - - // parse enum connection_mode - if (buf[0] == "DUMMY") { - this->other_connection = connection_mode::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[0] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - - return -1; -} - -bool other_connection::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int research_connection::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', research_connection::member_count - ); - - if (buf.size() != research_connection::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing research_connection led to " - << buf.size() - << " columns (expected " - << research_connection::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhd", &this->status) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->upper_building) != 1) { return 2; } - if (sscanf(buf[6].c_str(), "%d", &this->connected_slots_used) != 1) { return 6; } - this->other_connections.filename = buf[8]; - if (sscanf(buf[9].c_str(), "%d", &this->vertical_line) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%d", &this->location_in_age) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%d", &this->line_mode) != 1) { return 11; } - - return -1; -} - -bool research_connection::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->other_connections.read(storage, basedir); - - return true; -} - -int tech_effect::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', tech_effect::member_count - ); - - if (buf.size() != tech_effect::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing tech_effect led to " - << buf.size() - << " columns (expected " - << tech_effect::member_count - << ")!" - ); - } - - // parse enum effect_apply_type - if (buf[0] == "DUMMY") { - this->type_id = effect_apply_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[0] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[1].c_str(), "%hd", &this->attr_a) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hd", &this->attr_b) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%hd", &this->attr_c) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%f", &this->attr_d) != 1) { return 4; } - - return -1; -} - -bool tech_effect::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int unit_connection::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', unit_connection::member_count - ); - - if (buf.size() != unit_connection::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing unit_connection led to " - << buf.size() - << " columns (expected " - << unit_connection::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhd", &this->status) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->upper_building) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%d", &this->connected_slots_used) != 1) { return 3; } - this->other_connections.filename = buf[5]; - if (sscanf(buf[6].c_str(), "%d", &this->vertical_line) != 1) { return 6; } - if (sscanf(buf[8].c_str(), "%d", &this->location_in_age) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%d", &this->required_research) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%d", &this->line_mode) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%d", &this->enabling_research) != 1) { return 11; } - - return -1; -} - -bool unit_connection::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->other_connections.read(storage, basedir); - - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/tech_dummy.h b/libopenage/gamedata/tech_dummy.h deleted file mode 100644 index bac2cc13ff..0000000000 --- a/libopenage/gamedata/tech_dummy.h +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -enum class connection_mode { - DUMMY -}; - - -enum class effect_apply_type { - DUMMY -}; - - -/** - * misc connection for a building/unit/research connection - */ -struct other_connection { - connection_mode other_connection; - static constexpr size_t member_count = 1; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * items available when this age was reached. - */ -struct age_tech_tree { - int32_t id; - int8_t status; - int32_t connected_slots_used; - openage::util::csv_subdata other_connections; - int8_t building_level_count; - int8_t max_age_length; - int32_t line_mode; - static constexpr size_t member_count = 13; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * new available buildings/units/researches when this building was created. - */ -struct building_connection { - int32_t id; - int32_t connected_slots_used; - openage::util::csv_subdata other_connections; - int8_t location_in_age; - int32_t line_mode; - int32_t enabling_research; - static constexpr size_t member_count = 12; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * applied effect for a research technology. - */ -struct tech_effect { - effect_apply_type type_id; - int16_t attr_a; - int16_t attr_b; - int16_t attr_c; - float attr_d; - static constexpr size_t member_count = 5; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * a bundle of effects. - */ -struct effect_bundle { - std::string name; - openage::util::csv_subdata effects; - static constexpr size_t member_count = 2; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * research updates to apply when activating the technology. - */ -struct research_connection { - int32_t id; - int8_t status; - int32_t upper_building; - int32_t connected_slots_used; - openage::util::csv_subdata other_connections; - int32_t vertical_line; - int32_t location_in_age; - int32_t line_mode; - static constexpr size_t member_count = 12; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * unit updates to apply when activating the technology. - */ -struct unit_connection { - int32_t id; - int8_t status; - int32_t upper_building; - int32_t connected_slots_used; - openage::util::csv_subdata other_connections; - int32_t vertical_line; - int32_t location_in_age; - int32_t required_research; - int32_t line_mode; - int32_t enabling_research; - static constexpr size_t member_count = 12; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/terrain_dummy.cpp b/libopenage/gamedata/terrain_dummy.cpp deleted file mode 100644 index d99f430a4f..0000000000 --- a/libopenage/gamedata/terrain_dummy.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "terrain_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t frame_data::member_count; -constexpr size_t terrain_animation::member_count; -constexpr size_t terrain_border::member_count; -constexpr size_t terrain_pass_graphic::member_count; -constexpr size_t terrain_restriction::member_count; -constexpr size_t terrain_type::member_count; -constexpr size_t tile_size::member_count; -int frame_data::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', frame_data::member_count - ); - - if (buf.size() != frame_data::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing frame_data led to " - << buf.size() - << " columns (expected " - << frame_data::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->frame_count) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->angle_count) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hd", &this->shape_id) != 1) { return 2; } - - return -1; -} - -bool frame_data::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int terrain_animation::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', terrain_animation::member_count - ); - - if (buf.size() != terrain_animation::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing terrain_animation led to " - << buf.size() - << " columns (expected " - << terrain_animation::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hhd", &this->is_animated) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->animation_frame_count) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hd", &this->pause_frame_count) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%f", &this->interval) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%f", &this->pause_between_loops) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->frame) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->draw_frame) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%f", &this->animate_last) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->frame_changed) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hhd", &this->drawn) != 1) { return 9; } - - return -1; -} - -bool terrain_animation::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int terrain_border::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', terrain_border::member_count - ); - - if (buf.size() != terrain_border::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing terrain_border led to " - << buf.size() - << " columns (expected " - << terrain_border::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hhd", &this->enabled) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhd", &this->random) != 1) { return 1; } - this->internal_name = buf[2]; - this->filename = buf[3]; - if (sscanf(buf[4].c_str(), "%d", &this->slp_id) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%d", &this->shape_ptr) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%d", &this->sound_id) != 1) { return 6; } - if (sscanf(buf[8].c_str(), "%hhd", &this->is_animated) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->animation_frame_count) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%hd", &this->pause_frame_count) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%f", &this->interval) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->pause_between_loops) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%hd", &this->frame) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%hd", &this->draw_frame) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%f", &this->animate_last) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hhd", &this->frame_changed) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hhd", &this->drawn) != 1) { return 17; } - this->frames.filename = buf[18]; - if (sscanf(buf[19].c_str(), "%hd", &this->draw_tile) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->underlay_terrain) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hd", &this->border_style) != 1) { return 21; } - - return -1; -} - -bool terrain_border::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->frames.read(storage, basedir); - - return true; -} - -int terrain_pass_graphic::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', terrain_pass_graphic::member_count - ); - - if (buf.size() != terrain_pass_graphic::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing terrain_pass_graphic led to " - << buf.size() - << " columns (expected " - << terrain_pass_graphic::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->slp_id_exit_tile) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%d", &this->slp_id_enter_tile) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->slp_id_walk_tile) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%d", &this->replication_amount) != 1) { return 3; } - - return -1; -} - -bool terrain_pass_graphic::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int terrain_restriction::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', terrain_restriction::member_count - ); - - if (buf.size() != terrain_restriction::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing terrain_restriction led to " - << buf.size() - << " columns (expected " - << terrain_restriction::member_count - << ")!" - ); - } - - this->pass_graphics.filename = buf[1]; - - return -1; -} - -bool terrain_restriction::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->pass_graphics.read(storage, basedir); - - return true; -} - -int terrain_type::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', terrain_type::member_count - ); - - if (buf.size() != terrain_type::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing terrain_type led to " - << buf.size() - << " columns (expected " - << terrain_type::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hhd", &this->enabled) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhd", &this->random) != 1) { return 1; } - this->internal_name = buf[2]; - this->filename = buf[3]; - if (sscanf(buf[4].c_str(), "%d", &this->slp_id) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%d", &this->shape_ptr) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%d", &this->sound_id) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%d", &this->blend_priority) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%d", &this->blend_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hhu", &this->map_color_hi) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%hhu", &this->map_color_med) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhu", &this->map_color_low) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%hhu", &this->map_color_cliff_lt) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%hhu", &this->map_color_cliff_rt) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%hhd", &this->passable_terrain) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hhd", &this->impassable_terrain) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hhd", &this->is_animated) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->animation_frame_count) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hd", &this->pause_frame_count) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%f", &this->interval) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%f", &this->pause_between_loops) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hd", &this->frame) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->draw_frame) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%f", &this->animate_last) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hhd", &this->frame_changed) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hhd", &this->drawn) != 1) { return 25; } - this->elevation_graphics.filename = buf[26]; - if (sscanf(buf[27].c_str(), "%hd", &this->terrain_replacement_id) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%hd", &this->terrain_to_draw0) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%hd", &this->terrain_to_draw1) != 1) { return 29; } - if (sscanf(buf[34].c_str(), "%hd", &this->terrain_units_used_count) != 1) { return 34; } - - return -1; -} - -bool terrain_type::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->elevation_graphics.read(storage, basedir); - - return true; -} - -int tile_size::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', tile_size::member_count - ); - - if (buf.size() != tile_size::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing tile_size led to " - << buf.size() - << " columns (expected " - << tile_size::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->width) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->height) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hd", &this->delta_z) != 1) { return 2; } - - return -1; -} - -bool tile_size::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/terrain_dummy.h b/libopenage/gamedata/terrain_dummy.h deleted file mode 100644 index 6985296ed0..0000000000 --- a/libopenage/gamedata/terrain_dummy.h +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * specification of terrain frames. - */ -struct frame_data { - int16_t frame_count; - int16_t angle_count; - int16_t shape_id; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * describes animation properties of a terrain type - */ -struct terrain_animation { - int8_t is_animated; - int16_t animation_frame_count; - int16_t pause_frame_count; - float interval; - float pause_between_loops; - int16_t frame; - int16_t draw_frame; - float animate_last; - int8_t frame_changed; - int8_t drawn; - static constexpr size_t member_count = 10; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -struct terrain_pass_graphic { - int32_t slp_id_exit_tile; - int32_t slp_id_enter_tile; - int32_t slp_id_walk_tile; - int32_t replication_amount; - static constexpr size_t member_count = 4; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * size definition of one terrain tile. - */ -struct tile_size { - int16_t width; - int16_t height; - int16_t delta_z; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * TODO - */ -struct terrain_restriction { - openage::util::csv_subdata pass_graphics; - static constexpr size_t member_count = 2; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * one inter-terraintile border specification. - */ -struct terrain_border : terrain_animation { - int8_t enabled; - int8_t random; - std::string internal_name; - std::string filename; - int32_t slp_id; - int32_t shape_ptr; - int32_t sound_id; - openage::util::csv_subdata frames; - int16_t draw_tile; - int16_t underlay_terrain; - int16_t border_style; - static constexpr size_t member_count = 22; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * describes a terrain type, like water, ice, etc. - */ -struct terrain_type : terrain_animation { - int8_t enabled; - int8_t random; - std::string internal_name; - std::string filename; - int32_t slp_id; - int32_t shape_ptr; - int32_t sound_id; - int32_t blend_priority; - int32_t blend_mode; - uint8_t map_color_hi; - uint8_t map_color_med; - uint8_t map_color_low; - uint8_t map_color_cliff_lt; - uint8_t map_color_cliff_rt; - int8_t passable_terrain; - int8_t impassable_terrain; - openage::util::csv_subdata elevation_graphics; - int16_t terrain_replacement_id; - int16_t terrain_to_draw0; - int16_t terrain_to_draw1; - int16_t terrain_units_used_count; - static constexpr size_t member_count = 35; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/texture_dummy.cpp b/libopenage/gamedata/texture_dummy.cpp deleted file mode 100644 index 6d599c663b..0000000000 --- a/libopenage/gamedata/texture_dummy.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "texture_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t subtexture::member_count; -int subtexture::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', subtexture::member_count - ); - - if (buf.size() != subtexture::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing subtexture led to " - << buf.size() - << " columns (expected " - << subtexture::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%d", &this->x) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%d", &this->y) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%d", &this->w) != 1) { return 2; } - if (sscanf(buf[3].c_str(), "%d", &this->h) != 1) { return 3; } - if (sscanf(buf[4].c_str(), "%d", &this->cx) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%d", &this->cy) != 1) { return 5; } - - return -1; -} - -bool subtexture::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/texture_dummy.h b/libopenage/gamedata/texture_dummy.h deleted file mode 100644 index 9ac92d4e3e..0000000000 --- a/libopenage/gamedata/texture_dummy.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * one sprite, as part of a texture atlas. - * - * this struct stores information about positions and sizes - * of sprites included in the 'big texture'. - */ -struct subtexture { - int32_t x; - int32_t y; - int32_t w; - int32_t h; - int32_t cx; - int32_t cy; - static constexpr size_t member_count = 6; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/unit_dummy.cpp b/libopenage/gamedata/unit_dummy.cpp deleted file mode 100644 index 190e6774a3..0000000000 --- a/libopenage/gamedata/unit_dummy.cpp +++ /dev/null @@ -1,2820 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include -#include "error/error.h" -#include "unit_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t action_unit::member_count; -constexpr size_t animated_unit::member_count; -constexpr size_t building_annex::member_count; -constexpr size_t building_unit::member_count; -constexpr size_t damage_graphic::member_count; -constexpr size_t doppelganger_unit::member_count; -constexpr size_t hit_type::member_count; -constexpr size_t living_unit::member_count; -constexpr size_t missile_unit::member_count; -constexpr size_t moving_unit::member_count; -constexpr size_t projectile_unit::member_count; -constexpr size_t resource_cost::member_count; -constexpr size_t resource_storage::member_count; -constexpr size_t tree_unit::member_count; -constexpr size_t unit_command::member_count; -constexpr size_t unit_header::member_count; -constexpr size_t unit_object::member_count; -int action_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', action_unit::member_count - ); - - if (buf.size() != action_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing action_unit led to " - << buf.size() - << " columns (expected " - << action_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; } - if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; } - if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; } - if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; } - if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; } - if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; } - if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; } - if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; } - if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; } - if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; } - if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; } - if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; } - if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; } - if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; } - if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; } - if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; } - if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; } - if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; } - if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; } - if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; } - - return -1; -} - -bool action_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - - return true; -} - -int animated_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', animated_unit::member_count - ); - - if (buf.size() != animated_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing animated_unit led to " - << buf.size() - << " columns (expected " - << animated_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - - return -1; -} - -bool animated_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - - return true; -} - -int building_annex::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', building_annex::member_count - ); - - if (buf.size() != building_annex::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing building_annex led to " - << buf.size() - << " columns (expected " - << building_annex::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->unit_id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%f", &this->misplaced0) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%f", &this->misplaced1) != 1) { return 2; } - - return -1; -} - -bool building_annex::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int building_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', building_unit::member_count - ); - - if (buf.size() != building_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing building_unit led to " - << buf.size() - << " columns (expected " - << building_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; } - if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; } - if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; } - if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; } - if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; } - if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; } - if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; } - if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; } - if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; } - if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; } - if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; } - if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; } - if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; } - if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; } - if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; } - if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; } - if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; } - if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; } - if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; } - if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; } - if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; } - this->attacks.filename = buf[92]; - this->armors.filename = buf[93]; - // parse enum boundary_ids - if (buf[94] == "DUMMY") { - this->boundary_id = boundary_ids::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[94] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; } - if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; } - if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; } - if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; } - if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; } - if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; } - if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; } - // parse enum range_damage_type - if (buf[103] == "DUMMY") { - this->blast_level_offence = range_damage_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[103] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; } - if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; } - if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; } - if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; } - if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; } - if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; } - if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; } - this->resource_cost.filename = buf[111]; - if (sscanf(buf[112].c_str(), "%hd", &this->creation_time) != 1) { return 112; } - if (sscanf(buf[113].c_str(), "%hd", &this->train_location_id) != 1) { return 113; } - if (sscanf(buf[114].c_str(), "%f", &this->rear_attack_modifier) != 1) { return 114; } - if (sscanf(buf[115].c_str(), "%f", &this->flank_attack_modifier) != 1) { return 115; } - // parse enum creatable_types - if (buf[116] == "DUMMY") { - this->creatable_type = creatable_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[116] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[117].c_str(), "%hhd", &this->hero_mode) != 1) { return 117; } - if (sscanf(buf[118].c_str(), "%d", &this->garrison_graphic) != 1) { return 118; } - if (sscanf(buf[119].c_str(), "%f", &this->attack_projectile_count) != 1) { return 119; } - if (sscanf(buf[120].c_str(), "%hhd", &this->attack_projectile_max_count) != 1) { return 120; } - if (sscanf(buf[121].c_str(), "%f", &this->attack_projectile_spawning_area_width) != 1) { return 121; } - if (sscanf(buf[122].c_str(), "%f", &this->attack_projectile_spawning_area_length) != 1) { return 122; } - if (sscanf(buf[123].c_str(), "%f", &this->attack_projectile_spawning_area_randomness) != 1) { return 123; } - if (sscanf(buf[124].c_str(), "%d", &this->attack_projectile_secondary_unit_id) != 1) { return 124; } - if (sscanf(buf[125].c_str(), "%d", &this->special_graphic_id) != 1) { return 125; } - if (sscanf(buf[126].c_str(), "%hhd", &this->special_activation) != 1) { return 126; } - if (sscanf(buf[127].c_str(), "%hd", &this->pierce_armor_displayed) != 1) { return 127; } - if (sscanf(buf[128].c_str(), "%hd", &this->construction_graphic_id) != 1) { return 128; } - if (sscanf(buf[129].c_str(), "%hd", &this->snow_graphic_id) != 1) { return 129; } - if (sscanf(buf[130].c_str(), "%hhd", &this->adjacent_mode) != 1) { return 130; } - if (sscanf(buf[131].c_str(), "%hd", &this->graphics_angle) != 1) { return 131; } - if (sscanf(buf[132].c_str(), "%hhd", &this->disappears_when_built) != 1) { return 132; } - if (sscanf(buf[133].c_str(), "%hd", &this->stack_unit_id) != 1) { return 133; } - if (sscanf(buf[134].c_str(), "%hd", &this->foundation_terrain_id) != 1) { return 134; } - if (sscanf(buf[135].c_str(), "%hd", &this->old_overlay_id) != 1) { return 135; } - if (sscanf(buf[136].c_str(), "%hd", &this->research_id) != 1) { return 136; } - if (sscanf(buf[137].c_str(), "%hhd", &this->can_burn) != 1) { return 137; } - this->building_annex.filename = buf[138]; - if (sscanf(buf[139].c_str(), "%hd", &this->head_unit_id) != 1) { return 139; } - if (sscanf(buf[140].c_str(), "%hd", &this->transform_unit_id) != 1) { return 140; } - if (sscanf(buf[141].c_str(), "%hd", &this->transform_sound_id) != 1) { return 141; } - if (sscanf(buf[142].c_str(), "%hd", &this->construction_sound_id) != 1) { return 142; } - // parse enum garrison_types - if (buf[143] == "DUMMY") { - this->garrison_type = garrison_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[143] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[144].c_str(), "%f", &this->garrison_heal_rate) != 1) { return 144; } - if (sscanf(buf[145].c_str(), "%f", &this->garrison_repair_rate) != 1) { return 145; } - if (sscanf(buf[146].c_str(), "%hd", &this->salvage_unit_id) != 1) { return 146; } - - return -1; -} - -bool building_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - this->attacks.read(storage, basedir); - this->armors.read(storage, basedir); - this->resource_cost.read(storage, basedir); - this->building_annex.read(storage, basedir); - - return true; -} - -int damage_graphic::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', damage_graphic::member_count - ); - - if (buf.size() != damage_graphic::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing damage_graphic led to " - << buf.size() - << " columns (expected " - << damage_graphic::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->graphic_id) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hhd", &this->damage_percent) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hhd", &this->old_apply_mode) != 1) { return 2; } - // parse enum damage_draw_type - if (buf[3] == "DUMMY") { - this->apply_mode = damage_draw_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - - return -1; -} - -bool damage_graphic::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int doppelganger_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', doppelganger_unit::member_count - ); - - if (buf.size() != doppelganger_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing doppelganger_unit led to " - << buf.size() - << " columns (expected " - << doppelganger_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - - return -1; -} - -bool doppelganger_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - - return true; -} - -int hit_type::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', hit_type::member_count - ); - - if (buf.size() != hit_type::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing hit_type led to " - << buf.size() - << " columns (expected " - << hit_type::member_count - << ")!" - ); - } - - // parse enum hit_class - if (buf[0] == "DUMMY") { - this->type_id = hit_class::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[0] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[1].c_str(), "%hd", &this->amount) != 1) { return 1; } - - return -1; -} - -bool hit_type::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int living_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', living_unit::member_count - ); - - if (buf.size() != living_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing living_unit led to " - << buf.size() - << " columns (expected " - << living_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; } - if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; } - if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; } - if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; } - if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; } - if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; } - if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; } - if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; } - if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; } - if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; } - if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; } - if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; } - if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; } - if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; } - if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; } - if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; } - if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; } - if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; } - if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; } - if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; } - if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; } - this->attacks.filename = buf[92]; - this->armors.filename = buf[93]; - // parse enum boundary_ids - if (buf[94] == "DUMMY") { - this->boundary_id = boundary_ids::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[94] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; } - if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; } - if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; } - if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; } - if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; } - if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; } - if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; } - // parse enum range_damage_type - if (buf[103] == "DUMMY") { - this->blast_level_offence = range_damage_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[103] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; } - if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; } - if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; } - if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; } - if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; } - if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; } - if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; } - this->resource_cost.filename = buf[111]; - if (sscanf(buf[112].c_str(), "%hd", &this->creation_time) != 1) { return 112; } - if (sscanf(buf[113].c_str(), "%hd", &this->train_location_id) != 1) { return 113; } - if (sscanf(buf[114].c_str(), "%f", &this->rear_attack_modifier) != 1) { return 114; } - if (sscanf(buf[115].c_str(), "%f", &this->flank_attack_modifier) != 1) { return 115; } - // parse enum creatable_types - if (buf[116] == "DUMMY") { - this->creatable_type = creatable_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[116] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[117].c_str(), "%hhd", &this->hero_mode) != 1) { return 117; } - if (sscanf(buf[118].c_str(), "%d", &this->garrison_graphic) != 1) { return 118; } - if (sscanf(buf[119].c_str(), "%f", &this->attack_projectile_count) != 1) { return 119; } - if (sscanf(buf[120].c_str(), "%hhd", &this->attack_projectile_max_count) != 1) { return 120; } - if (sscanf(buf[121].c_str(), "%f", &this->attack_projectile_spawning_area_width) != 1) { return 121; } - if (sscanf(buf[122].c_str(), "%f", &this->attack_projectile_spawning_area_length) != 1) { return 122; } - if (sscanf(buf[123].c_str(), "%f", &this->attack_projectile_spawning_area_randomness) != 1) { return 123; } - if (sscanf(buf[124].c_str(), "%d", &this->attack_projectile_secondary_unit_id) != 1) { return 124; } - if (sscanf(buf[125].c_str(), "%d", &this->special_graphic_id) != 1) { return 125; } - if (sscanf(buf[126].c_str(), "%hhd", &this->special_activation) != 1) { return 126; } - if (sscanf(buf[127].c_str(), "%hd", &this->pierce_armor_displayed) != 1) { return 127; } - - return -1; -} - -bool living_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - this->attacks.read(storage, basedir); - this->armors.read(storage, basedir); - this->resource_cost.read(storage, basedir); - - return true; -} - -int missile_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', missile_unit::member_count - ); - - if (buf.size() != missile_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing missile_unit led to " - << buf.size() - << " columns (expected " - << missile_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; } - if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; } - if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; } - if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; } - if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; } - if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; } - if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; } - if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; } - if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; } - if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; } - if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; } - if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; } - if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; } - if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; } - if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; } - if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; } - if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; } - if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; } - if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; } - if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; } - if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; } - this->attacks.filename = buf[92]; - this->armors.filename = buf[93]; - // parse enum boundary_ids - if (buf[94] == "DUMMY") { - this->boundary_id = boundary_ids::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[94] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; } - if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; } - if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; } - if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; } - if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; } - if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; } - if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; } - // parse enum range_damage_type - if (buf[103] == "DUMMY") { - this->blast_level_offence = range_damage_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[103] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; } - if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; } - if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; } - if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; } - if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; } - if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; } - if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; } - if (sscanf(buf[111].c_str(), "%hhd", &this->projectile_type) != 1) { return 111; } - if (sscanf(buf[112].c_str(), "%hhd", &this->smart_mode) != 1) { return 112; } - if (sscanf(buf[113].c_str(), "%hhd", &this->drop_animation_mode) != 1) { return 113; } - if (sscanf(buf[114].c_str(), "%hhd", &this->penetration_mode) != 1) { return 114; } - if (sscanf(buf[115].c_str(), "%hhd", &this->area_of_effect_special) != 1) { return 115; } - if (sscanf(buf[116].c_str(), "%f", &this->projectile_arc) != 1) { return 116; } - - return -1; -} - -bool missile_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - this->attacks.read(storage, basedir); - this->armors.read(storage, basedir); - - return true; -} - -int moving_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', moving_unit::member_count - ); - - if (buf.size() != moving_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing moving_unit led to " - << buf.size() - << " columns (expected " - << moving_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; } - if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; } - if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; } - if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; } - if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; } - if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; } - if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; } - if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; } - if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; } - if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; } - if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; } - if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; } - if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; } - - return -1; -} - -bool moving_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - - return true; -} - -int projectile_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', projectile_unit::member_count - ); - - if (buf.size() != projectile_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing projectile_unit led to " - << buf.size() - << " columns (expected " - << projectile_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - if (sscanf(buf[69].c_str(), "%f", &this->speed) != 1) { return 69; } - if (sscanf(buf[70].c_str(), "%hd", &this->move_graphics) != 1) { return 70; } - if (sscanf(buf[71].c_str(), "%hd", &this->run_graphics) != 1) { return 71; } - if (sscanf(buf[72].c_str(), "%f", &this->turn_speed) != 1) { return 72; } - if (sscanf(buf[73].c_str(), "%hhd", &this->old_size_class) != 1) { return 73; } - if (sscanf(buf[74].c_str(), "%hd", &this->trail_unit_id) != 1) { return 74; } - if (sscanf(buf[75].c_str(), "%hhu", &this->trail_opsions) != 1) { return 75; } - if (sscanf(buf[76].c_str(), "%f", &this->trail_spacing) != 1) { return 76; } - if (sscanf(buf[77].c_str(), "%hhd", &this->old_move_algorithm) != 1) { return 77; } - if (sscanf(buf[78].c_str(), "%f", &this->turn_radius) != 1) { return 78; } - if (sscanf(buf[79].c_str(), "%f", &this->turn_radius_speed) != 1) { return 79; } - if (sscanf(buf[80].c_str(), "%f", &this->max_yaw_per_sec_moving) != 1) { return 80; } - if (sscanf(buf[81].c_str(), "%f", &this->stationary_yaw_revolution_time) != 1) { return 81; } - if (sscanf(buf[82].c_str(), "%f", &this->max_yaw_per_sec_stationary) != 1) { return 82; } - if (sscanf(buf[83].c_str(), "%hd", &this->default_task_id) != 1) { return 83; } - if (sscanf(buf[84].c_str(), "%f", &this->search_radius) != 1) { return 84; } - if (sscanf(buf[85].c_str(), "%f", &this->work_rate) != 1) { return 85; } - if (sscanf(buf[87].c_str(), "%hhd", &this->task_group) != 1) { return 87; } - if (sscanf(buf[88].c_str(), "%hd", &this->command_sound_id) != 1) { return 88; } - if (sscanf(buf[89].c_str(), "%hd", &this->stop_sound_id) != 1) { return 89; } - if (sscanf(buf[90].c_str(), "%hhd", &this->run_pattern) != 1) { return 90; } - if (sscanf(buf[91].c_str(), "%hd", &this->default_armor) != 1) { return 91; } - this->attacks.filename = buf[92]; - this->armors.filename = buf[93]; - // parse enum boundary_ids - if (buf[94] == "DUMMY") { - this->boundary_id = boundary_ids::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[94] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[95].c_str(), "%f", &this->weapon_range_max) != 1) { return 95; } - if (sscanf(buf[96].c_str(), "%f", &this->blast_range) != 1) { return 96; } - if (sscanf(buf[97].c_str(), "%f", &this->attack_speed) != 1) { return 97; } - if (sscanf(buf[98].c_str(), "%hd", &this->attack_projectile_primary_unit_id) != 1) { return 98; } - if (sscanf(buf[99].c_str(), "%hd", &this->accuracy) != 1) { return 99; } - if (sscanf(buf[100].c_str(), "%hhd", &this->break_off_combat) != 1) { return 100; } - if (sscanf(buf[101].c_str(), "%hd", &this->frame_delay) != 1) { return 101; } - // parse enum range_damage_type - if (buf[103] == "DUMMY") { - this->blast_level_offence = range_damage_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[103] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[104].c_str(), "%f", &this->weapon_range_min) != 1) { return 104; } - if (sscanf(buf[105].c_str(), "%f", &this->accuracy_dispersion) != 1) { return 105; } - if (sscanf(buf[106].c_str(), "%hd", &this->attack_sprite_id) != 1) { return 106; } - if (sscanf(buf[107].c_str(), "%hd", &this->melee_armor_displayed) != 1) { return 107; } - if (sscanf(buf[108].c_str(), "%hd", &this->attack_displayed) != 1) { return 108; } - if (sscanf(buf[109].c_str(), "%f", &this->range_displayed) != 1) { return 109; } - if (sscanf(buf[110].c_str(), "%f", &this->reload_time_displayed) != 1) { return 110; } - - return -1; -} - -bool projectile_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - this->attacks.read(storage, basedir); - this->armors.read(storage, basedir); - - return true; -} - -int resource_cost::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', resource_cost::member_count - ); - - if (buf.size() != resource_cost::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing resource_cost led to " - << buf.size() - << " columns (expected " - << resource_cost::member_count - << ")!" - ); - } - - // parse enum resource_types - if (buf[0] == "DUMMY") { - this->type_id = resource_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[0] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[1].c_str(), "%hd", &this->amount) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hd", &this->enabled) != 1) { return 2; } - - return -1; -} - -bool resource_cost::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int resource_storage::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', resource_storage::member_count - ); - - if (buf.size() != resource_storage::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing resource_storage led to " - << buf.size() - << " columns (expected " - << resource_storage::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->type) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%f", &this->amount) != 1) { return 1; } - // parse enum resource_handling - if (buf[2] == "DUMMY") { - this->used_mode = resource_handling::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[2] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - - return -1; -} - -bool resource_storage::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int tree_unit::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', tree_unit::member_count - ); - - if (buf.size() != tree_unit::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing tree_unit led to " - << buf.size() - << " columns (expected " - << tree_unit::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[57].c_str(), "%f", &this->selection_shape_x) != 1) { return 57; } - if (sscanf(buf[58].c_str(), "%f", &this->selection_shape_y) != 1) { return 58; } - if (sscanf(buf[59].c_str(), "%f", &this->selection_shape_z) != 1) { return 59; } - this->resource_storage.filename = buf[60]; - this->damage_graphics.filename = buf[61]; - if (sscanf(buf[62].c_str(), "%hd", &this->selection_sound_id) != 1) { return 62; } - if (sscanf(buf[63].c_str(), "%hd", &this->dying_sound_id) != 1) { return 63; } - // parse enum attack_modes - if (buf[64] == "DUMMY") { - this->old_attack_mode = attack_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[64] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - - return -1; -} - -bool tree_unit::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - - return true; -} - -int unit_command::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', unit_command::member_count - ); - - if (buf.size() != unit_command::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing unit_command led to " - << buf.size() - << " columns (expected " - << unit_command::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->command_used) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hd", &this->command_id) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hhd", &this->is_default) != 1) { return 2; } - // parse enum command_ability - if (buf[3] == "DUMMY") { - this->type = command_ability::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->class_id) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->unit_id) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->terrain_id) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->resource_in) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hd", &this->resource_multiplier) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->resource_out) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%hd", &this->unused_resource) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%f", &this->work_value1) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->work_value2) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->work_range) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%hhd", &this->search_mode) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%f", &this->search_time) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hhd", &this->enable_targeting) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hhd", &this->combat_level_flag) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hd", &this->gather_type) != 1) { return 18; } - // parse enum selection_type - if (buf[19] == "DUMMY") { - this->owner_type = selection_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[19] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[20].c_str(), "%hhd", &this->carry_check) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->state_build) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->move_sprite_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hd", &this->proceed_sprite_id) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->work_sprite_id) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->carry_sprite_id) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->resource_gather_sound_id) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->resource_deposit_sound_id) != 1) { return 27; } - - return -1; -} - -bool unit_command::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -int unit_header::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', unit_header::member_count - ); - - if (buf.size() != unit_header::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing unit_header led to " - << buf.size() - << " columns (expected " - << unit_header::member_count - << ")!" - ); - } - - // remember if the following members are undefined - if (buf[0] == "data_absent") { - this->exists = 0; - } else if (buf[0] == "data_exists") { - this->exists = 1; - } else { - throw openage::error::Error(ERR << "unexpected value '"<< buf[0] << "' for ContinueReadMember"); - } - this->unit_commands.filename = buf[1]; - - return -1; -} - -bool unit_header::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->unit_commands.read(storage, basedir); - - return true; -} - -int unit_object::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', unit_object::member_count - ); - - if (buf.size() != unit_object::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing unit_object led to " - << buf.size() - << " columns (expected " - << unit_object::member_count - << ")!" - ); - } - - if (sscanf(buf[0].c_str(), "%hd", &this->id0) != 1) { return 0; } - if (sscanf(buf[1].c_str(), "%hu", &this->language_dll_name) != 1) { return 1; } - if (sscanf(buf[2].c_str(), "%hu", &this->language_dll_creation) != 1) { return 2; } - // parse enum unit_classes - if (buf[3] == "DUMMY") { - this->unit_class = unit_classes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[3] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[4].c_str(), "%hd", &this->idle_graphic0) != 1) { return 4; } - if (sscanf(buf[5].c_str(), "%hd", &this->idle_graphic1) != 1) { return 5; } - if (sscanf(buf[6].c_str(), "%hd", &this->dying_graphic) != 1) { return 6; } - if (sscanf(buf[7].c_str(), "%hd", &this->undead_graphic) != 1) { return 7; } - if (sscanf(buf[8].c_str(), "%hhd", &this->death_mode) != 1) { return 8; } - if (sscanf(buf[9].c_str(), "%hd", &this->hit_points) != 1) { return 9; } - if (sscanf(buf[10].c_str(), "%f", &this->line_of_sight) != 1) { return 10; } - if (sscanf(buf[11].c_str(), "%hhd", &this->garrison_capacity) != 1) { return 11; } - if (sscanf(buf[12].c_str(), "%f", &this->radius_x) != 1) { return 12; } - if (sscanf(buf[13].c_str(), "%f", &this->radius_y) != 1) { return 13; } - if (sscanf(buf[14].c_str(), "%f", &this->radius_z) != 1) { return 14; } - if (sscanf(buf[15].c_str(), "%hd", &this->train_sound_id) != 1) { return 15; } - if (sscanf(buf[16].c_str(), "%hd", &this->damage_sound_id) != 1) { return 16; } - if (sscanf(buf[17].c_str(), "%hd", &this->dead_unit_id) != 1) { return 17; } - if (sscanf(buf[18].c_str(), "%hhd", &this->placement_mode) != 1) { return 18; } - if (sscanf(buf[19].c_str(), "%hhd", &this->can_be_built_on) != 1) { return 19; } - if (sscanf(buf[20].c_str(), "%hd", &this->icon_id) != 1) { return 20; } - if (sscanf(buf[21].c_str(), "%hhd", &this->hidden_in_editor) != 1) { return 21; } - if (sscanf(buf[22].c_str(), "%hd", &this->old_portrait_icon_id) != 1) { return 22; } - if (sscanf(buf[23].c_str(), "%hhd", &this->enabled) != 1) { return 23; } - if (sscanf(buf[24].c_str(), "%hd", &this->placement_side_terrain0) != 1) { return 24; } - if (sscanf(buf[25].c_str(), "%hd", &this->placement_side_terrain1) != 1) { return 25; } - if (sscanf(buf[26].c_str(), "%hd", &this->placement_terrain0) != 1) { return 26; } - if (sscanf(buf[27].c_str(), "%hd", &this->placement_terrain1) != 1) { return 27; } - if (sscanf(buf[28].c_str(), "%f", &this->clearance_size_x) != 1) { return 28; } - if (sscanf(buf[29].c_str(), "%f", &this->clearance_size_y) != 1) { return 29; } - // parse enum elevation_modes - if (buf[30] == "DUMMY") { - this->elevation_mode = elevation_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[30] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum fog_visibility - if (buf[31] == "DUMMY") { - this->visible_in_fog = fog_visibility::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[31] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum ground_type - if (buf[32] == "DUMMY") { - this->terrain_restriction = ground_type::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[32] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[33].c_str(), "%hhd", &this->fly_mode) != 1) { return 33; } - if (sscanf(buf[34].c_str(), "%hd", &this->resource_capacity) != 1) { return 34; } - if (sscanf(buf[35].c_str(), "%f", &this->resource_decay) != 1) { return 35; } - // parse enum blast_types - if (buf[36] == "DUMMY") { - this->blast_defense_level = blast_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[36] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum combat_levels - if (buf[37] == "DUMMY") { - this->combat_level = combat_levels::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[37] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum interaction_modes - if (buf[38] == "DUMMY") { - this->interaction_mode = interaction_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[38] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum minimap_modes - if (buf[39] == "DUMMY") { - this->map_draw_level = minimap_modes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[39] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - // parse enum command_attributes - if (buf[40] == "DUMMY") { - this->unit_level = command_attributes::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[40] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[41].c_str(), "%f", &this->attack_reaction) != 1) { return 41; } - if (sscanf(buf[42].c_str(), "%hhd", &this->minimap_color) != 1) { return 42; } - if (sscanf(buf[43].c_str(), "%d", &this->language_dll_help) != 1) { return 43; } - if (sscanf(buf[44].c_str(), "%d", &this->language_dll_hotkey_text) != 1) { return 44; } - if (sscanf(buf[45].c_str(), "%d", &this->hot_keys) != 1) { return 45; } - if (sscanf(buf[46].c_str(), "%hhd", &this->recyclable) != 1) { return 46; } - if (sscanf(buf[47].c_str(), "%hhd", &this->enable_auto_gather) != 1) { return 47; } - if (sscanf(buf[48].c_str(), "%hhd", &this->doppelgaenger_on_death) != 1) { return 48; } - if (sscanf(buf[49].c_str(), "%hhd", &this->resource_gather_drop) != 1) { return 49; } - if (sscanf(buf[50].c_str(), "%hhu", &this->occlusion_mode) != 1) { return 50; } - // parse enum obstruction_types - if (buf[51] == "DUMMY") { - this->obstruction_type = obstruction_types::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[51] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[52].c_str(), "%hhd", &this->obstruction_class) != 1) { return 52; } - if (sscanf(buf[53].c_str(), "%hhu", &this->trait) != 1) { return 53; } - if (sscanf(buf[54].c_str(), "%hhd", &this->civilization_id) != 1) { return 54; } - if (sscanf(buf[55].c_str(), "%hd", &this->attribute_piece) != 1) { return 55; } - // parse enum selection_effects - if (buf[56] == "DUMMY") { - this->selection_effect = selection_effects::DUMMY; - } - else { - throw openage::error::Error( - MSG(err) - << "unknown enum value '" << buf[56] - << "' encountered. valid are: " - "DUMMY\n---\n" - );} - if (sscanf(buf[65].c_str(), "%hhd", &this->convert_terrain) != 1) { return 65; } - this->name = buf[66]; - if (sscanf(buf[67].c_str(), "%hd", &this->id1) != 1) { return 67; } - if (sscanf(buf[68].c_str(), "%hd", &this->id2) != 1) { return 68; } - - return -1; -} - -bool unit_object::recurse(const openage::util::CSVCollection &storage, const std::string &basedir) { - this->resource_storage.read(storage, basedir); - this->damage_graphics.read(storage, basedir); - - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/unit_dummy.h b/libopenage/gamedata/unit_dummy.h deleted file mode 100644 index 4398fa0d11..0000000000 --- a/libopenage/gamedata/unit_dummy.h +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -enum class attack_modes { - DUMMY -}; - - -enum class blast_types { - DUMMY -}; - - -enum class boundary_ids { - DUMMY -}; - - -/** - * a possible building annex. - */ -struct building_annex { - int16_t unit_id; - float misplaced0; - float misplaced1; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -enum class combat_levels { - DUMMY -}; - - -enum class command_ability { - DUMMY -}; - - -enum class command_attributes { - DUMMY -}; - - -enum class creatable_types { - DUMMY -}; - - -enum class damage_draw_type { - DUMMY -}; - - -enum class elevation_modes { - DUMMY -}; - - -enum class fog_visibility { - DUMMY -}; - - -enum class garrison_types { - DUMMY -}; - - -enum class ground_type { - DUMMY, - WATER, - WATER_0x0D, - WATER_SHIP_0x03, - WATER_SHIP_0x0F, - SOLID, - FOUNDATION, - NO_ICE_0x08, - FOREST -}; - - -enum class hit_class { - DUMMY -}; - - -enum class interaction_modes { - DUMMY -}; - - -enum class minimap_modes { - DUMMY -}; - - -enum class obstruction_types { - DUMMY -}; - - -enum class range_damage_type { - DUMMY -}; - - -enum class resource_handling { - DUMMY -}; - - -enum class resource_types { - DUMMY -}; - - -enum class selection_effects { - DUMMY -}; - - -enum class selection_type { - DUMMY -}; - - -enum class unit_classes { - DUMMY, - BUILDING, - CIVILIAN, - TREES, - HERDABLE, - GOLD_MINE, - STONE_MINE, - BERRY_BUSH, - PREY_ANIMAL, - SEA_FISH, - FISHING_BOAT -}; - - -/** - * stores one possible unit image that is displayed at a given damage percentage. - */ -struct damage_graphic { - int16_t graphic_id; - int8_t damage_percent; - int8_t old_apply_mode; - damage_draw_type apply_mode; - static constexpr size_t member_count = 4; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * determines the resource storage capacity for one unit mode. - */ -struct resource_storage { - int16_t type; - float amount; - resource_handling used_mode; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * base properties for all units. - */ -struct unit_object { - int16_t id0; - uint16_t language_dll_name; - uint16_t language_dll_creation; - unit_classes unit_class; - int16_t idle_graphic0; - int16_t idle_graphic1; - int16_t dying_graphic; - int16_t undead_graphic; - int8_t death_mode; - int16_t hit_points; - float line_of_sight; - int8_t garrison_capacity; - float radius_x; - float radius_y; - float radius_z; - int16_t train_sound_id; - int16_t damage_sound_id; - int16_t dead_unit_id; - int8_t placement_mode; - int8_t can_be_built_on; - int16_t icon_id; - int8_t hidden_in_editor; - int16_t old_portrait_icon_id; - int8_t enabled; - int16_t placement_side_terrain0; - int16_t placement_side_terrain1; - int16_t placement_terrain0; - int16_t placement_terrain1; - float clearance_size_x; - float clearance_size_y; - elevation_modes elevation_mode; - fog_visibility visible_in_fog; - ground_type terrain_restriction; - int8_t fly_mode; - int16_t resource_capacity; - float resource_decay; - blast_types blast_defense_level; - combat_levels combat_level; - interaction_modes interaction_mode; - minimap_modes map_draw_level; - command_attributes unit_level; - float attack_reaction; - int8_t minimap_color; - int32_t language_dll_help; - int32_t language_dll_hotkey_text; - int32_t hot_keys; - int8_t recyclable; - int8_t enable_auto_gather; - int8_t doppelgaenger_on_death; - int8_t resource_gather_drop; - uint8_t occlusion_mode; - obstruction_types obstruction_type; - int8_t obstruction_class; - uint8_t trait; - int8_t civilization_id; - int16_t attribute_piece; - selection_effects selection_effect; - float selection_shape_x; - float selection_shape_y; - float selection_shape_z; - openage::util::csv_subdata resource_storage; - openage::util::csv_subdata damage_graphics; - int16_t selection_sound_id; - int16_t dying_sound_id; - attack_modes old_attack_mode; - int8_t convert_terrain; - std::string name; - int16_t id1; - int16_t id2; - static constexpr size_t member_count = 69; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * adds speed property to units. - */ -struct animated_unit : unit_object { - float speed; - static constexpr size_t member_count = 70; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * weird doppelganger unit thats actually the same as an animated unit. - */ -struct doppelganger_unit : animated_unit { - static constexpr size_t member_count = 70; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * adds walking graphics, rotations and tracking properties to units. - */ -struct moving_unit : doppelganger_unit { - int16_t move_graphics; - int16_t run_graphics; - float turn_speed; - int8_t old_size_class; - int16_t trail_unit_id; - uint8_t trail_opsions; - float trail_spacing; - int8_t old_move_algorithm; - float turn_radius; - float turn_radius_speed; - float max_yaw_per_sec_moving; - float stationary_yaw_revolution_time; - float max_yaw_per_sec_stationary; - static constexpr size_t member_count = 83; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * adds search radius and work properties, as well as movement sounds. - */ -struct action_unit : moving_unit { - int16_t default_task_id; - float search_radius; - float work_rate; - int8_t task_group; - int16_t command_sound_id; - int16_t stop_sound_id; - int8_t run_pattern; - static constexpr size_t member_count = 91; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * stores attack amount for a damage type. - */ -struct hit_type { - hit_class type_id; - int16_t amount; - static constexpr size_t member_count = 2; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * adds attack and armor properties to units. - */ -struct projectile_unit : action_unit { - int16_t default_armor; - openage::util::csv_subdata attacks; - openage::util::csv_subdata armors; - boundary_ids boundary_id; - float weapon_range_max; - float blast_range; - float attack_speed; - int16_t attack_projectile_primary_unit_id; - int16_t accuracy; - int8_t break_off_combat; - int16_t frame_delay; - range_damage_type blast_level_offence; - float weapon_range_min; - float accuracy_dispersion; - int16_t attack_sprite_id; - int16_t melee_armor_displayed; - int16_t attack_displayed; - float range_displayed; - float reload_time_displayed; - static constexpr size_t member_count = 111; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * adds missile specific unit properties. - */ -struct missile_unit : projectile_unit { - int8_t projectile_type; - int8_t smart_mode; - int8_t drop_animation_mode; - int8_t penetration_mode; - int8_t area_of_effect_special; - float projectile_arc; - static constexpr size_t member_count = 117; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * stores cost for one resource for creating the unit. - */ -struct resource_cost { - resource_types type_id; - int16_t amount; - int16_t enabled; - static constexpr size_t member_count = 3; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * just a tree unit. - */ -struct tree_unit : unit_object { - static constexpr size_t member_count = 69; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * a command a single unit may receive by script or human. - */ -struct unit_command { - int16_t command_used; - int16_t command_id; - int8_t is_default; - command_ability type; - int16_t class_id; - int16_t unit_id; - int16_t terrain_id; - int16_t resource_in; - int16_t resource_multiplier; - int16_t resource_out; - int16_t unused_resource; - float work_value1; - float work_value2; - float work_range; - int8_t search_mode; - float search_time; - int8_t enable_targeting; - int8_t combat_level_flag; - int16_t gather_type; - selection_type owner_type; - int8_t carry_check; - int8_t state_build; - int16_t move_sprite_id; - int16_t proceed_sprite_id; - int16_t work_sprite_id; - int16_t carry_sprite_id; - int16_t resource_gather_sound_id; - int16_t resource_deposit_sound_id; - static constexpr size_t member_count = 28; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * stores a bunch of unit commands. - */ -struct unit_header { - uint8_t exists; - openage::util::csv_subdata unit_commands; - static constexpr size_t member_count = 2; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * adds creation location and garrison unit properties. - */ -struct living_unit : projectile_unit { - openage::util::csv_subdata resource_cost; - int16_t creation_time; - int16_t train_location_id; - float rear_attack_modifier; - float flank_attack_modifier; - creatable_types creatable_type; - int8_t hero_mode; - int32_t garrison_graphic; - float attack_projectile_count; - int8_t attack_projectile_max_count; - float attack_projectile_spawning_area_width; - float attack_projectile_spawning_area_length; - float attack_projectile_spawning_area_randomness; - int32_t attack_projectile_secondary_unit_id; - int32_t special_graphic_id; - int8_t special_activation; - int16_t pierce_armor_displayed; - static constexpr size_t member_count = 128; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -/** - * construction graphics and garrison building properties for units. - */ -struct building_unit : living_unit { - int16_t construction_graphic_id; - int16_t snow_graphic_id; - int8_t adjacent_mode; - int16_t graphics_angle; - int8_t disappears_when_built; - int16_t stack_unit_id; - int16_t foundation_terrain_id; - int16_t old_overlay_id; - int16_t research_id; - int8_t can_burn; - openage::util::csv_subdata building_annex; - int16_t head_unit_id; - int16_t transform_unit_id; - int16_t transform_sound_id; - int16_t construction_sound_id; - garrison_types garrison_type; - float garrison_heal_rate; - float garrison_repair_rate; - int16_t salvage_unit_id; - static constexpr size_t member_count = 148; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamedata/util_dummy.cpp b/libopenage/gamedata/util_dummy.cpp deleted file mode 100644 index ee4c97bb50..0000000000 --- a/libopenage/gamedata/util_dummy.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - - -#include -#include "error/error.h" -#include "util_dummy.h" -#include "util/strings.h" - - -namespace openage { -namespace gamedata { - -constexpr size_t multisubtype_ref::member_count; -int multisubtype_ref::fill(const std::string &line) { - std::vector buf = openage::util::split_escape( - line, ',', multisubtype_ref::member_count - ); - - if (buf.size() != multisubtype_ref::member_count) { - throw openage::error::Error( - ERR - << "Tokenizing multisubtype_ref led to " - << buf.size() - << " columns (expected " - << multisubtype_ref::member_count - << ")!" - ); - } - - this->subtype = buf[0]; - this->filename = buf[1]; - - return -1; -} - -bool multisubtype_ref::recurse(const openage::util::CSVCollection & /*storage*/, const std::string & /*basedir*/) { - return true; -} - -} // gamedata -} // openage diff --git a/libopenage/gamedata/util_dummy.h b/libopenage/gamedata/util_dummy.h deleted file mode 100644 index 87c6b21868..0000000000 --- a/libopenage/gamedata/util_dummy.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -// Warning: this file is a dummy file and was auto-generated by the v0.4.1 converter; -// its purpose is to keep the deprecated gamestate compilable and intact; -// these files keep only the minimum functionality and should not be changed; -// For details, see buildsystem/codegen.cmake and openage/codegen. - -#pragma once - -#include -#include -#include "util/csv.h" - - - -namespace openage { -namespace gamedata { - -/** - * format for multi-subtype references - */ -struct multisubtype_ref { - std::string subtype; - std::string filename; - static constexpr size_t member_count = 2; - int fill(const std::string &line); - bool recurse(const openage::util::CSVCollection &storage, const std::string &basedir); - -}; - -} // gamedata -} // openage diff --git a/libopenage/gamestate/CMakeLists.txt b/libopenage/gamestate/CMakeLists.txt index c89d9cd52d..a94cd93514 100644 --- a/libopenage/gamestate/CMakeLists.txt +++ b/libopenage/gamestate/CMakeLists.txt @@ -8,6 +8,8 @@ add_sources(libopenage player.cpp simulation.cpp terrain_chunk.cpp + terrain_factory.cpp + terrain_tile.cpp terrain.cpp types.cpp world.cpp @@ -20,6 +22,3 @@ add_subdirectory(component/) add_subdirectory(demo/) add_subdirectory(event/) add_subdirectory(system/) - -# TODO: remove once migration is done. -add_subdirectory(old/) diff --git a/libopenage/gamestate/api/CMakeLists.txt b/libopenage/gamestate/api/CMakeLists.txt index e235b05137..f079f11be3 100644 --- a/libopenage/gamestate/api/CMakeLists.txt +++ b/libopenage/gamestate/api/CMakeLists.txt @@ -6,6 +6,7 @@ add_sources(libopenage player_setup.cpp property.cpp sound.cpp + terrain.cpp types.cpp util.cpp ) diff --git a/libopenage/gamestate/api/terrain.cpp b/libopenage/gamestate/api/terrain.cpp new file mode 100644 index 0000000000..e69edee5fc --- /dev/null +++ b/libopenage/gamestate/api/terrain.cpp @@ -0,0 +1,24 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#include "terrain.h" + +#include + +#include "gamestate/api/util.h" + + +namespace openage::gamestate::api { + +bool APITerrain::is_terrain(const nyan::Object &obj) { + nyan::fqon_t immediate_parent = obj.get_parents()[0]; + return immediate_parent == "engine.util.terrain.Terrain"; +} + +const std::string APITerrain::get_terrain_path(const nyan::Object &terrain) { + nyan::Object terrain_texture_obj = terrain.get_object("Terrain.terrain_graphic"); + std::string terrain_path = terrain_texture_obj.get_file("Terrain.sprite"); + + return resolve_file_path(terrain, terrain_path); +} + +} // namespace openage::gamestate::api diff --git a/libopenage/gamestate/api/terrain.h b/libopenage/gamestate/api/terrain.h new file mode 100644 index 0000000000..ef4ca357a8 --- /dev/null +++ b/libopenage/gamestate/api/terrain.h @@ -0,0 +1,35 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include + + +namespace openage::gamestate::api { + +class APITerrain { +public: + /** + * Check if a nyan object is a terrain (type == \p engine.util.terrain.Terrain). + * + * @param obj nyan object handle. + * + * @return true if the object is a terrain, else false. + */ + static bool is_terrain(const nyan::Object &obj); + + /** + * Get the terrain path of a terrain. + * + * The path is relative to the directory the modpack is mounted in. + * + * @param terrain \p Terrain nyan object (type == \p engine.util.terrain.Terrain). + * + * @return Relative path to the terrain file. + */ + static const std::string get_terrain_path(const nyan::Object &terrain); +}; + +} // namespace openage::gamestate::api diff --git a/libopenage/gamestate/event/spawn_entity.cpp b/libopenage/gamestate/event/spawn_entity.cpp index 5cc1cf27df..155441445f 100644 --- a/libopenage/gamestate/event/spawn_entity.cpp +++ b/libopenage/gamestate/event/spawn_entity.cpp @@ -76,6 +76,52 @@ static const std::vector trial_test_entities = { "trial_base.data.game_entity.generic.barracks.barracks.Barracks", }; +// TODO: Remove hardcoded test entity references +// declared static so we only have to build the vector once +static std::vector test_entities; + + +void build_test_entities(const std::shared_ptr &gstate) { + auto modpack_ids = gstate->get_mod_manager()->get_load_order(); + for (auto &modpack_id : modpack_ids) { + if (modpack_id == "aoe1_base") { + test_entities.insert(test_entities.end(), + aoe1_test_entities.begin(), + aoe1_test_entities.end()); + } + else if (modpack_id == "de1_base") { + test_entities.insert(test_entities.end(), + de1_test_entities.begin(), + de1_test_entities.end()); + } + else if (modpack_id == "aoe2_base") { + test_entities.insert(test_entities.end(), + aoe2_test_entities.begin(), + aoe2_test_entities.end()); + } + else if (modpack_id == "de2_base") { + test_entities.insert(test_entities.end(), + de2_test_entities.begin(), + de2_test_entities.end()); + } + else if (modpack_id == "hd_base") { + test_entities.insert(test_entities.end(), + hd_test_entities.begin(), + hd_test_entities.end()); + } + else if (modpack_id == "swgb_base") { + test_entities.insert(test_entities.end(), + swgb_test_entities.begin(), + swgb_test_entities.end()); + } + else if (modpack_id == "trial_base") { + test_entities.insert(test_entities.end(), + trial_test_entities.begin(), + trial_test_entities.end()); + } + } +} + Spawner::Spawner(const std::shared_ptr &loop) : EventEntity(loop) { @@ -113,52 +159,14 @@ void SpawnEntityHandler::invoke(openage::event::EventLoop & /* loop */, auto game_entities = nyan_db->get_obj_children_all("engine.util.game_entity.GameEntity"); - // TODO: Remove hardcoded test entity references - static std::vector test_entities; // declared static so we only have to do this once if (test_entities.empty()) { - auto modpack_ids = gstate->get_mod_manager()->get_load_order(); - for (auto &modpack_id : modpack_ids) { - if (modpack_id == "aoe1_base") { - test_entities.insert(test_entities.end(), - aoe1_test_entities.begin(), - aoe1_test_entities.end()); - } - else if (modpack_id == "de1_base") { - test_entities.insert(test_entities.end(), - de1_test_entities.begin(), - de1_test_entities.end()); - } - else if (modpack_id == "aoe2_base") { - test_entities.insert(test_entities.end(), - aoe2_test_entities.begin(), - aoe2_test_entities.end()); - } - else if (modpack_id == "de2_base") { - test_entities.insert(test_entities.end(), - de2_test_entities.begin(), - de2_test_entities.end()); - } - else if (modpack_id == "hd_base") { - test_entities.insert(test_entities.end(), - hd_test_entities.begin(), - hd_test_entities.end()); - } - else if (modpack_id == "swgb_base") { - test_entities.insert(test_entities.end(), - swgb_test_entities.begin(), - swgb_test_entities.end()); - } - else if (modpack_id == "trial_base") { - test_entities.insert(test_entities.end(), - trial_test_entities.begin(), - trial_test_entities.end()); - } + build_test_entities(gstate); + + // Do nothing if there are no test entities + if (test_entities.empty()) { + return; } } - if (test_entities.empty()) { - // Do nothing because we don't have anything to spawn - return; - } static uint8_t index = 0; nyan::fqon_t nyan_entity = test_entities.at(index); @@ -190,7 +198,7 @@ void SpawnEntityHandler::invoke(openage::event::EventLoop & /* loop */, // TODO: Select the unit when it's created // very dumb but it gets the job done - auto select_cb = params.get("select_cb", std::function{}); + auto select_cb = params.get("select_cb", std::function{[](entity_id_t /* id */) {}}); select_cb(entity->get_id()); gstate->add_game_entity(entity); diff --git a/libopenage/gamestate/game.cpp b/libopenage/gamestate/game.cpp index d31310945d..8e3497bfbc 100644 --- a/libopenage/gamestate/game.cpp +++ b/libopenage/gamestate/game.cpp @@ -13,16 +13,20 @@ #include "assets/modpack.h" #include "gamestate/entity_factory.h" #include "gamestate/game_state.h" +#include "gamestate/terrain.h" +#include "gamestate/terrain_factory.h" #include "gamestate/universe.h" #include "util/path.h" #include "util/strings.h" +#include "coord/tile.h" namespace openage::gamestate { Game::Game(const std::shared_ptr &event_loop, const std::shared_ptr &mod_manager, - const std::shared_ptr &entity_factory) : + const std::shared_ptr &entity_factory, + const std::shared_ptr &terrain_factory) : db{nyan::Database::create()}, state{std::make_shared(this->db, event_loop)}, universe{std::make_shared(state)} { @@ -39,6 +43,8 @@ Game::Game(const std::shared_ptr &event_loop, // This can be removed when we spawn based on game logic rather than // hardcoded entity types. this->state->set_mod_manager(mod_manager); + + this->generate_terrain(terrain_factory); } const std::shared_ptr &Game::get_state() const { @@ -47,6 +53,7 @@ const std::shared_ptr &Game::get_state() const { void Game::attach_renderer(const std::shared_ptr &render_factory) { this->universe->attach_renderer(render_factory); + this->state->get_terrain()->attach_renderer(render_factory); } void Game::load_data(const std::shared_ptr &mod_manager) { @@ -89,7 +96,7 @@ void Game::load_path(const util::Path &base_dir, auto base_path = base_dir.resolve_native_path(); auto search_path = base_dir / mod_dir / search; - auto fileload_func = [&base_path, &mod_dir](const std::string &filename) { + auto fileload_func = [&base_path](const std::string &filename) { // nyan wants a string filepath, so we have to construct it from the // path and subpath parameters log::log(INFO << "Loading .nyan file: " << filename); @@ -98,7 +105,7 @@ void Game::load_path(const util::Path &base_dir, }; // file loading - if (search_path.is_file() && search_path.get_suffix() == ".nyan") { + if (search_path.is_file() and search_path.get_suffix() == ".nyan") { auto loc = mod_dir + "/" + search; this->db->load(loc, fileload_func); return; @@ -119,4 +126,27 @@ void Game::load_path(const util::Path &base_dir, } } +void Game::generate_terrain(const std::shared_ptr &terrain_factory) { + auto terrain = terrain_factory->add_terrain(); + + auto chunk0 = terrain_factory->add_chunk(this->state, + util::Vector2s{10, 10}, + coord::tile_delta{0, 0}); + auto chunk1 = terrain_factory->add_chunk(this->state, + util::Vector2s{10, 10}, + coord::tile_delta{10, 0}); + auto chunk2 = terrain_factory->add_chunk(this->state, + util::Vector2s{10, 10}, + coord::tile_delta{0, 10}); + auto chunk3 = terrain_factory->add_chunk(this->state, + util::Vector2s{10, 10}, + coord::tile_delta{10, 10}); + terrain->add_chunk(chunk0); + terrain->add_chunk(chunk1); + terrain->add_chunk(chunk2); + terrain->add_chunk(chunk3); + + this->state->set_terrain(terrain); +} + } // namespace openage::gamestate diff --git a/libopenage/gamestate/game.h b/libopenage/gamestate/game.h index aecfd3bd72..139c4e87fa 100644 --- a/libopenage/gamestate/game.h +++ b/libopenage/gamestate/game.h @@ -30,6 +30,7 @@ class Path; namespace gamestate { class GameState; class EntityFactory; +class TerrainFactory; class Universe; /** @@ -53,7 +54,8 @@ class Game { */ Game(const std::shared_ptr &event_loop, const std::shared_ptr &mod_manager, - const std::shared_ptr &entity_factory); + const std::shared_ptr &entity_factory, + const std::shared_ptr &terrain_factory); ~Game() = default; /** @@ -93,6 +95,15 @@ class Game { const std::string &search, bool recursive = false); + /** + * Generate the terrain for the current game. + * + * TODO: Use a real map generator. + * + * @param terrain_factory Factory for creating terrain objects. + */ + void generate_terrain(const std::shared_ptr &terrain_factory); + /** * Nyan game data database. */ diff --git a/libopenage/gamestate/game_entity.h b/libopenage/gamestate/game_entity.h index a79f167e7f..d4b61202e9 100644 --- a/libopenage/gamestate/game_entity.h +++ b/libopenage/gamestate/game_entity.h @@ -103,7 +103,7 @@ class GameEntity { * Update the render entity. * * @param time Simulation time of the update. - * @param animation_path Animation path used at \p time. + * @param animation_path Path to the animation definition used at \p time. */ void render_update(const time::time_t &time, const std::string &animation_path); diff --git a/libopenage/gamestate/game_state.cpp b/libopenage/gamestate/game_state.cpp index 9cda363379..9de7c69bff 100644 --- a/libopenage/gamestate/game_state.cpp +++ b/libopenage/gamestate/game_state.cpp @@ -37,6 +37,10 @@ void GameState::add_player(const std::shared_ptr &player) { this->players[player->get_id()] = player; } +void GameState::set_terrain(const std::shared_ptr &terrain) { + this->terrain = terrain; +} + const std::shared_ptr &GameState::get_game_entity(entity_id_t id) const { if (!this->game_entities.contains(id)) [[unlikely]] { throw Error(MSG(err) << "Game entity with ID " << id << " does not exist"); @@ -55,6 +59,10 @@ const std::shared_ptr &GameState::get_player(player_id_t id) const { return this->players.at(id); } +const std::shared_ptr &GameState::get_terrain() const { + return this->terrain; +} + const std::shared_ptr &GameState::get_mod_manager() const { return this->mod_manager; } diff --git a/libopenage/gamestate/game_state.h b/libopenage/gamestate/game_state.h index d252acaadc..401070780c 100644 --- a/libopenage/gamestate/game_state.h +++ b/libopenage/gamestate/game_state.h @@ -27,6 +27,7 @@ class EventLoop; namespace gamestate { class GameEntity; class Player; +class Terrain; /** * State of the game. @@ -68,6 +69,13 @@ class GameState : public openage::event::State { */ void add_player(const std::shared_ptr &player); + /** + * Set the terrain of the current game. + * + * @param terrain Terrain object. + */ + void set_terrain(const std::shared_ptr &terrain); + /** * Get a game entity by its ID. * @@ -93,6 +101,13 @@ class GameState : public openage::event::State { */ const std::shared_ptr &get_player(player_id_t id) const; + /** + * Get the terrain of the current game. + * + * @return Terrain object. + */ + const std::shared_ptr &get_terrain() const; + /** * TODO: Only for testing. */ @@ -115,6 +130,11 @@ class GameState : public openage::event::State { */ std::unordered_map> players; + /** + * Terrain of the current game. + */ + std::shared_ptr terrain; + /** * TODO: Only for testing */ diff --git a/libopenage/gamestate/old/CMakeLists.txt b/libopenage/gamestate/old/CMakeLists.txt deleted file mode 100644 index d141c14607..0000000000 --- a/libopenage/gamestate/old/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_sources(libopenage - civilisation.cpp - cost.cpp - game_main.cpp - game_save.cpp - game_spec.cpp - generator.cpp - market.cpp - player.cpp - population_tracker.cpp - resource.cpp - score.cpp - team.cpp - types.cpp -) diff --git a/libopenage/gamestate/old/civilisation.cpp b/libopenage/gamestate/old/civilisation.cpp deleted file mode 100644 index 6139ed23fe..0000000000 --- a/libopenage/gamestate/old/civilisation.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015-2018 the openage authors. See copying.md for legal info. - -#include "civilisation.h" - -#include "../../log/log.h" -#include "../../unit/unit_type.h" - - -namespace openage { - -Civilisation::Civilisation(const GameSpec &spec, int id) - : - civ_id{id}, - civ_name{spec.get_civ_name(id)} { - this->initialise_unit_types(spec); -} - - -std::vector> Civilisation::object_meta() const { - return civ_objects; -} - - -std::vector Civilisation::get_category(const std::string &c) const { - auto cat = this->categories.find(c); - if (cat == this->categories.end()) { - return std::vector(); - } - return cat->second; -} - - -std::vector Civilisation::get_type_categories() const { - return this->all_categories; -} - - -const gamedata::building_unit *Civilisation::get_building_data(index_t unit_id) const { - if (this->buildings.count(unit_id) == 0) { - log::log(MSG(info) << " -> ignoring unit_id: " << unit_id); - return nullptr; - } - return this->buildings.at(unit_id); -} - - -void Civilisation::initialise_unit_types(const GameSpec &spec) { - log::log(MSG(dbg) << "Init units of civilisation " << civ_name); - spec.create_unit_types(this->civ_objects, this->civ_id); - for (auto &type : this->civ_objects) { - this->add_to_category(type->name(), type->id()); - } -} - - -void Civilisation::add_to_category(const std::string &c, index_t type) { - if (this->categories.count(c) == 0) { - this->all_categories.push_back(c); - this->categories[c] = std::vector(); - } - this->categories[c].push_back(type); -} - - -} diff --git a/libopenage/gamestate/old/civilisation.h b/libopenage/gamestate/old/civilisation.h deleted file mode 100644 index 97045031ea..0000000000 --- a/libopenage/gamestate/old/civilisation.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "game_spec.h" - -namespace openage { - -/** - * contains the initial tech structure for - * one civilisation - */ -class Civilisation { -public: - Civilisation(const GameSpec &spec, int id); - - /** - * civ index - */ - const int civ_id; - - /** - * civ name - */ - const std::string civ_name; - - /** - * return all the objects available to this civ - */ - std::vector> object_meta() const; - - /** - * return all types in a particular named category - */ - std::vector get_category(const std::string &c) const; - - /** - * return all used categories, such as living, building or projectile - */ - std::vector get_type_categories() const; - - /** - * gamedata for a building - */ - const gamedata::building_unit *get_building_data(index_t unit_id) const; - - /** - * initialise the unit meta data - */ - void initialise_unit_types(const GameSpec &spec); - -private: - - /** - * creates and adds items to categories - */ - void add_to_category(const std::string &c, index_t type); - - /** - * unit types which can be produced by this civilisation. - */ - std::vector> civ_objects; - - /** - * all available categories of units - */ - std::vector all_categories; - - /** - * category lists - */ - std::unordered_map> categories; - - /** - * used for annex creation - */ - std::unordered_map buildings; - -}; - -} diff --git a/libopenage/gamestate/old/cost.cpp b/libopenage/gamestate/old/cost.cpp deleted file mode 100644 index 089cb6da4b..0000000000 --- a/libopenage/gamestate/old/cost.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017-2021 the openage authors. See copying.md for legal info. - -#include "cost.h" -#include "player.h" - - -namespace openage { - -ResourceCost::ResourceCost() - : - type{cost_type::constant}, - resources{} {} - -ResourceCost::ResourceCost(const ResourceBundle& resources) - : - type{cost_type::constant}, - resources{} { - this->resources.set(resources); -} - -ResourceCost::ResourceCost(cost_type type, const ResourceBundle& multiplier) - : - type{type}, - resources{} { - this->resources.set(multiplier); -} - -ResourceCost::~ResourceCost() = default; - -void ResourceCost::set(cost_type type, const ResourceBundle& resources) { - this->type = type; - this->resources.set(resources); -} - -const ResourceBundle ResourceCost::get(const Player& player) const { - if (type == cost_type::constant) { - return resources; - } - - // calculate dynamic cost - ResourceBundle resources = this->resources.clone(); - if (type == cost_type::workforce) { - resources *= player.get_workforce_count(); - } - return resources; -} - -} // openage diff --git a/libopenage/gamestate/old/cost.h b/libopenage/gamestate/old/cost.h deleted file mode 100644 index 749aa50986..0000000000 --- a/libopenage/gamestate/old/cost.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2017-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include "resource.h" - - -namespace openage { - -class Player; - -/** - * Types of dynamic cost calculation (and one constant). - * - * Used in ResourceCost - * TODO use in TimeCost - */ -enum class cost_type : int { - /** Constant resources. */ - constant, - /** Dynamic cost based on the workforce. */ - workforce -}; - -/** - * A container for a constant or dynamic ResourceBundle representing the cost. - */ -class ResourceCost { -public: - - /** - * Constant zero cost - */ - ResourceCost(); - - /** - * Constant cost - */ - ResourceCost(const ResourceBundle& resources); - - /** - * Dynamic cost - */ - ResourceCost(cost_type type, const ResourceBundle& multiplier); - - virtual ~ResourceCost(); - - void set(cost_type type, const ResourceBundle& multiplier); - - /** - * Returns the cost. - */ - const ResourceBundle get(const Player& player) const; - -private: - - cost_type type; - - ResourceBundle resources; - -}; - -// TODO implement TimeCost - -} // namespace openage diff --git a/libopenage/gamestate/old/game_main.cpp b/libopenage/gamestate/old/game_main.cpp deleted file mode 100644 index bd26fe6e48..0000000000 --- a/libopenage/gamestate/old/game_main.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#include "game_main.h" - -#include "../../legacy_engine.h" -#include "../../log/log.h" -#include "../../terrain/terrain.h" -#include "../../unit/unit_type.h" -#include "game_spec.h" -#include "generator.h" - - -namespace openage { - -GameMain::GameMain(const Generator &generator) : - OptionNode{"GameMain"}, - terrain{generator.terrain()}, - placed_units{}, - spec{generator.get_spec()} { - // players - this->players.reserve(generator.player_names().size()); - unsigned int i = 0; - for (auto &name : generator.player_names()) { - this->players.push_back(std::make_shared(this->add_civ(i), i, name)); - i++; - } - - // initialise types only after all players are added - for (auto &p : this->players) { - p->initialise_unit_types(); - } - - // initialise units - this->placed_units.set_terrain(this->terrain); - generator.add_units(*this); -} - -GameMain::~GameMain() = default; - -unsigned int GameMain::player_count() const { - return this->players.size(); -} - -Player *GameMain::get_player(unsigned int player_id) { - return this->players.at(player_id).get(); -} - -unsigned int GameMain::team_count() const { - return this->teams.size(); -} - -Team *GameMain::get_team(unsigned int team_id) { - return &this->teams.at(team_id); -} - -GameSpec *GameMain::get_spec() { - return this->spec.get(); -} - -void GameMain::update(time_nsec_t lastframe_duration) { - this->placed_units.update_all(lastframe_duration); -} - -Civilisation *GameMain::add_civ(int civ_id) { - auto new_civ = std::make_shared(*this->spec, civ_id); - this->civs.emplace_back(new_civ); - return new_civ.get(); -} - -GameMainHandle::GameMainHandle(qtsdl::GuiItemLink *gui_link) : - game{}, - engine{}, - gui_link{gui_link} { -} - -void GameMainHandle::set_engine(LegacyEngine *engine) { - ENSURE(!this->engine || this->engine == engine, "relinking GameMain to another engine is not supported and not caught properly"); - this->engine = engine; -} - -void GameMainHandle::clear() { - if (this->engine) { - this->game = nullptr; - this->display->end_game(); - announce_running(); - } -} - -void GameMainHandle::set_game(std::unique_ptr &&game) { - if (this->engine) { - ENSURE(game, "linking game to engine problem"); - - // remember the pointer - this->game = game.get(); - - // then pass on the game to the engine - this->display->start_game(std::move(game)); - - announce_running(); - } -} - -GameMain *GameMainHandle::get_game() const { - return this->game; -} - -bool GameMainHandle::is_game_running() const { - return this->game != nullptr; -} - -void GameMainHandle::announce_running() { - emit this->gui_signals.game_running(this->game); -} - -} // namespace openage diff --git a/libopenage/gamestate/old/game_main.h b/libopenage/gamestate/old/game_main.h deleted file mode 100644 index 13d1ceb9d1..0000000000 --- a/libopenage/gamestate/old/game_main.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include - -#include "../../options.h" -#include "../../presenter/legacy/legacy.h" -#include "../../terrain/terrain.h" -#include "../../unit/unit_container.h" -#include "../../util/timing.h" -#include "market.h" -#include "player.h" -#include "team.h" - -namespace openage { - -class LegacyEngine; -class Generator; -class Terrain; - - -/** - * Contains information for a single game - * This information must be synced across network clients - * - * TODO: include a list of actions to be saved - * as the game replay file - */ -class GameMain : public options::OptionNode { -public: - GameMain(const Generator &generator); - ~GameMain(); - - /** - * the number of players - */ - unsigned int player_count() const; - - /** - * player by index - */ - Player *get_player(unsigned int player_id); - - /** - * the number of teams - */ - unsigned int team_count() const; - - /** - * team by id - */ - Team *get_team(unsigned int team_id); - - /** - * the spec in this games settings - */ - GameSpec *get_spec(); - - /** - * updates the game by one frame - */ - void update(time_nsec_t lastframe_duration); - - /** - * map information - */ - std::shared_ptr terrain; - - /** - * all teams in the game - */ - std::vector teams; - - /** - * The global market (the global market prices). - */ - Market market; - - /** - * all the objects that have been placed. - */ - UnitContainer placed_units; - -private: - /** - * all players in the game - * no objects should be added of removed once populated - */ - std::vector> players; - - /** - * creates a random civ, owned and managed by this game - */ - Civilisation *add_civ(int civ_id); - - /** - * civs used in this game - */ - std::vector> civs; - - std::shared_ptr spec; -}; - -} // namespace openage - -namespace qtsdl { -class GuiItemLink; -} // namespace qtsdl - -namespace openage { - -class GameMainSignals : public QObject { - Q_OBJECT - -public: -signals: - void game_running(bool running); -}; - - -/** - * Class linked to the QML object "GameMain" via GameMainLink. - * Gets instanciated from QML. - */ -class GameMainHandle { -public: - explicit GameMainHandle(qtsdl::GuiItemLink *gui_link); - - void set_engine(LegacyEngine *engine); - - /** - * End the game and delete the game handle. - */ - void clear(); - - /** - * Pass the given game to the engine and start it. - */ - void set_game(std::unique_ptr &&game); - - /** - * Return the game. - */ - GameMain *get_game() const; - - /** - * Test if there is a game running. - */ - bool is_game_running() const; - - /** - * Emit a qt signal to notify for changes in a running game. - */ - void announce_running(); - -private: - /** - * The game state as currently owned by the engine, - * just remembered here to access it quickly. - */ - GameMain *game; - - /** - * The engine the main game handle is attached to. - */ - LegacyEngine *engine; - - /** - * The engine the main game handle is attached to. - */ - presenter::LegacyDisplay *display; - -public: - GameMainSignals gui_signals; - qtsdl::GuiItemLink *gui_link; -}; - -} // namespace openage diff --git a/libopenage/gamestate/old/game_save.cpp b/libopenage/gamestate/old/game_save.cpp deleted file mode 100644 index 47d598530b..0000000000 --- a/libopenage/gamestate/old/game_save.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "game_save.h" - -#include -#include - -#include "version.h" -#include "../../log/log.h" -#include "../../terrain/terrain_chunk.h" -#include "../../unit/producer.h" -#include "../../unit/unit.h" -#include "../../unit/unit_type.h" -#include "../../versions/compiletime.h" -#include "game_main.h" -#include "game_save.h" -#include "game_spec.h" - -namespace openage::gameio { - -void save_unit(std::ofstream &file, Unit *unit) { - file << unit->unit_type->id() << std::endl; - file << unit->get_attribute().player.player_number << std::endl; - coord::tile pos = unit->location->pos.start; - file << pos.ne << " " << pos.se << std::endl; - - bool has_building_attr = unit->has_attribute(attr_type::building); - file << has_building_attr << std::endl; - if (has_building_attr) { - file << unit->get_attribute().completed << std::endl; - } -} - -void load_unit(std::ifstream &file, GameMain *game) { - int pr_id; - int player_no; - coord::tile_t ne, se; - file >> pr_id; - file >> player_no; - file >> ne; - file >> se; - - UnitType &saved_type = *game->get_player(player_no)->get_type(pr_id); - auto ref = game->placed_units.new_unit(saved_type, *game->get_player(player_no), coord::tile{ne, se}.to_phys3(*game->terrain)); - - bool has_building_attr; - file >> has_building_attr; - if (has_building_attr) { - float completed; - file >> completed; - if (completed >= 1.0f && ref.is_valid()) { - complete_building(*ref.get()); - } - } -} - -void save_tile_content(std::ofstream &file, openage::TileContent *content) { - file << content->terrain_id << std::endl; - file << content->obj.size() << std::endl; -} - -TileContent load_tile_content(std::ifstream &file) { - openage::TileContent content; - file >> content.terrain_id; - - unsigned int o_size; - file >> o_size; - return content; -} - -void save(openage::GameMain *game, const std::string &fname) { - std::ofstream file(fname, std::ofstream::out); - log::log(MSG(dbg) << "saving " + fname); - - // metadata - file << save_label << std::endl; - file << save_version << std::endl; - file << versions::engine_version << std::endl; - - // how many chunks - std::vector used = game->terrain->used_chunks(); - file << used.size() << std::endl; - - // save each chunk - for (coord::chunk &position : used) { - file << position.ne << " " << position.se << std::endl; - openage::TerrainChunk *chunk = game->terrain->get_chunk(position); - - file << chunk->tile_count << std::endl; - for (size_t p = 0; p < chunk->tile_count; ++p) { - save_tile_content( file, chunk->get_data(p) ); - } - } - - // save units - std::vector units = game->placed_units.all_units(); - file << units.size() << std::endl; - for (Unit *u : units) { - save_unit(file, u); - } -} - -void load(openage::GameMain *game, const std::string &fname) { - std::ifstream file(fname, std::ifstream::in); - if (!file.good()) { - log::log(MSG(dbg) << "could not find " + fname); - return; - } - log::log(MSG(dbg) << "loading " + fname); - - // load metadata - std::string file_label; - file >> file_label; - if (file_label != save_label) { - log::log(MSG(warn) << fname << " is not a savefile"); - return; - } - std::string version; - file >> version; - if (version != save_version) { - log::log(MSG(warn) << "savefile has different version"); - } - std::string build; - file >> build; - - // read terrain chunks - unsigned int num_chunks; - file >> num_chunks; - for (unsigned int c = 0; c < num_chunks; ++c) { - coord::chunk_t ne, se; - size_t tile_count; - file >> ne; - file >> se; - file >> tile_count; - openage::TerrainChunk *chunk = game->terrain->get_create_chunk(coord::chunk{ne, se}); - for (size_t p = 0; p < tile_count; ++p) { - *chunk->get_data(p) = load_tile_content( file ); - } - } - - game->placed_units.reset(); - unsigned int num_units; - file >> num_units; - for (unsigned int u = 0; u < num_units; ++u) { - load_unit( file, game ); - } -} - -} // openage::gameio diff --git a/libopenage/gamestate/old/game_save.h b/libopenage/gamestate/old/game_save.h deleted file mode 100644 index 36ddb49b82..0000000000 --- a/libopenage/gamestate/old/game_save.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace openage { - -class GameMain; -class Terrain; - -namespace gameio { - -const std::string save_label = "openage-save-file"; -const std::string save_version = "v0.1"; - -/** - * a game save function that sometimes works - */ -void save(openage::GameMain *, const std::string &fname); - -/** - * a game load function that sometimes works - */ -void load(openage::GameMain *, const std::string &fname); - -}} // openage::gameio diff --git a/libopenage/gamestate/old/game_spec.cpp b/libopenage/gamestate/old/game_spec.cpp deleted file mode 100644 index c35528d62f..0000000000 --- a/libopenage/gamestate/old/game_spec.cpp +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "game_spec.h" - -#include - -#include "../../audio/error.h" -#include "../../audio/resource_def.h" -#include "../../legacy_engine.h" -#include "../../gamedata/blending_mode_dummy.h" -#include "../../gamedata/string_resource_dummy.h" -#include "../../gamedata/terrain_dummy.h" -#include "../../log/log.h" -#include "../../rng/global_rng.h" -#include "../../unit/producer.h" -#include "../../util/compiler.h" -#include "../../util/strings.h" -#include "../../util/timer.h" -#include "assets/legacy_assetmanager.h" -#include "civilisation.h" - - -namespace openage { - -GameSpec::GameSpec(LegacyAssetManager *am) : - assetmanager{am}, - gamedata_loaded{false} { -} - -GameSpec::~GameSpec() = default; - - -bool GameSpec::initialize() { - util::Timer load_timer; - load_timer.start(); - - const util::Path &asset_dir = this->assetmanager->get_asset_dir(); - - log::log(MSG(info) << "Loading game specification files..."); - - std::vector string_resources = util::read_csv_file( - asset_dir["converted/string_resources.docx"]); - - try { - // read the packed csv file - util::CSVCollection raw_gamedata{ - asset_dir["converted/gamedata/gamedata.docx"]}; - - // parse the original game description files - this->gamedata = raw_gamedata.read( - "gamedata-empiresdat.docx"); - - this->load_terrain(this->gamedata[0]); - - // process and load the game description files - this->on_gamedata_loaded(this->gamedata[0]); - this->gamedata_loaded = true; - } - catch (Error &exc) { - // rethrow allmighty openage exceptions - throw; - } - catch (std::exception &exc) { - // unfortunately we have no idea of the std::exception backtrace - throw Error{ERR << "gamedata could not be loaded: " - << util::typestring(exc) - << ": " << exc.what()}; - } - - log::log(MSG(info).fmt("Loading time [data]: %5.3f s", - load_timer.getval() / 1e9)); - return true; -} - -bool GameSpec::load_complete() const { - return this->gamedata_loaded; -} - -terrain_meta *GameSpec::get_terrain_meta() { - return &this->terrain_data; -} - -index_t GameSpec::get_slp_graphic(index_t slp) { - return this->slp_to_graphic[slp]; -} - -Texture *GameSpec::get_texture(index_t graphic_id) const { - if (graphic_id <= 0 || this->graphics.count(graphic_id) == 0) { - log::log(MSG(dbg) << " -> ignoring graphics_id: " << graphic_id); - return nullptr; - } - - auto g = this->graphics.at(graphic_id); - int slp_id = g->slp_id; - if (slp_id <= 0) { - log::log(MSG(dbg) << " -> ignoring negative slp_id: " << slp_id); - return nullptr; - } - - log::log(MSG(dbg) << " slp id/name: " << slp_id << " " << g->name); - std::string tex_fname = util::sformat("converted/graphics/%d.slp.png", slp_id); - - return this->get_texture(tex_fname, true); -} - -Texture *GameSpec::get_texture(const std::string &file_name, bool use_metafile) const { - // return nullptr if the texture wasn't found (3rd param) - return this->assetmanager->get_texture(file_name, use_metafile, true); -} - -std::shared_ptr GameSpec::get_unit_texture(index_t unit_id) const { - if (this->unit_textures.count(unit_id) == 0) { - if (unit_id > 0) { - log::log(MSG(dbg) << " -> ignoring unit_id: " << unit_id); - } - return nullptr; - } - return this->unit_textures.at(unit_id); -} - -const Sound *GameSpec::get_sound(index_t sound_id) const { - if (this->available_sounds.count(sound_id) == 0) { - if (sound_id > 0) { - log::log(MSG(dbg) << " -> ignoring sound_id: " << sound_id); - } - return nullptr; - } - return &this->available_sounds.at(sound_id); -} - - -const gamedata::graphic *GameSpec::get_graphic_data(index_t grp_id) const { - if (this->graphics.count(grp_id) == 0) { - log::log(MSG(dbg) << " -> ignoring grp_id: " << grp_id); - return nullptr; - } - return this->graphics.at(grp_id); -} - -std::vector GameSpec::get_command_data(index_t unit_id) const { - if (this->commands.count(unit_id) == 0) { - return std::vector(); // empty vector - } - return this->commands.at(unit_id); -} - -std::string GameSpec::get_civ_name(int civ_id) const { - return this->gamedata[0].civs.data[civ_id].name; -} - -void GameSpec::create_unit_types(unit_meta_list &objects, int civ_id) const { - if (!this->load_complete()) { - return; - } - - // create projectile types first - for (auto &obj : this->gamedata[0].civs.data[civ_id].units.missile.data) { - this->load_missile(obj, objects); - } - - // create object unit types - for (auto &obj : this->gamedata[0].civs.data[civ_id].units.object.data) { - this->load_object(obj, objects); - } - - // create dead unit types - for (auto &unit : this->gamedata[0].civs.data[civ_id].units.moving.data) { - this->load_object(unit, objects); - } - - // create living unit types - for (auto &unit : this->gamedata[0].civs.data[civ_id].units.living.data) { - this->load_living(unit, objects); - } - - // create building unit types - for (auto &building : this->gamedata[0].civs.data[civ_id].units.building.data) { - this->load_building(building, objects); - } -} - - -LegacyAssetManager *GameSpec::get_asset_manager() const { - return this->assetmanager; -} - - -void GameSpec::on_gamedata_loaded(const gamedata::empiresdat &gamedata) { - const util::Path &asset_dir = this->assetmanager->get_asset_dir(); - util::Path sound_dir = asset_dir["converted/sounds"]; - - // create graphic id => graphic map - for (auto &graphic : gamedata.graphics.data) { - this->graphics[graphic.graphic_id] = &graphic; - this->slp_to_graphic[graphic.slp_id] = graphic.graphic_id; - } - - log::log(INFO << "Loading textures..."); - - // create complete set of unit textures - for (auto &g : this->graphics) { - this->unit_textures.insert({g.first, std::make_shared(*this, g.second)}); - } - - log::log(INFO << "Loading sounds..."); - - // playable sound files for the audio manager - std::vector load_sound_files; - - // all sounds defined in the game specification - for (const gamedata::sound &sound : gamedata.sounds.data) { - std::vector sound_items; - - // each sound may have multiple variation, - // processed in this loop - // these are the single sound files. - for (const gamedata::sound_item &item : sound.sound_items.data) { - if (item.resource_id < 0) { - log::log(SPAM << " Invalid sound resource id < 0"); - continue; - } - - std::string snd_filename = util::sformat("%d.opus", item.resource_id); - util::Path snd_path = sound_dir[snd_filename]; - - if (not snd_path.is_file()) { - continue; - } - - // single items for a sound (so that we can ramdomize it) - sound_items.push_back(item.resource_id); - - // the single sound will be loaded in the audio system. - audio::resource_def resource{ - audio::category_t::GAME, - item.resource_id, - snd_path, - audio::format_t::OPUS, - audio::loader_policy_t::DYNAMIC}; - load_sound_files.push_back(resource); - } - - - // create test sound objects that can be played later - this->available_sounds.insert({sound.sound_id, - Sound{ - this, - std::move(sound_items)}}); - } - - // TODO: move out the loading of the sound. - // this class only provides the names and locations - - // load the requested sounds. - audio::AudioManager &am = this->assetmanager->get_display()->get_audio_manager(); - am.load_resources(load_sound_files); - - // this final step occurs after loading media - // as producers require both the graphics and sounds - this->create_abilities(gamedata); -} - -bool GameSpec::valid_graphic_id(index_t graphic_id) const { - if (graphic_id <= 0 || this->graphics.count(graphic_id) == 0) { - return false; - } - if (this->graphics.at(graphic_id)->slp_id <= 0) { - return false; - } - return true; -} - -void GameSpec::load_building(const gamedata::building_unit &building, unit_meta_list &list) const { - // check graphics - if (this->valid_graphic_id(building.idle_graphic0)) { - auto meta_type = std::make_shared("Building", building.id0, [this, &building](const Player &owner) { - return std::make_shared(owner, *this, &building); - }); - list.emplace_back(meta_type); - } -} - -void GameSpec::load_living(const gamedata::living_unit &unit, unit_meta_list &list) const { - // check graphics - if (this->valid_graphic_id(unit.dying_graphic) && this->valid_graphic_id(unit.idle_graphic0) && this->valid_graphic_id(unit.move_graphics)) { - auto meta_type = std::make_shared("Living", unit.id0, [this, &unit](const Player &owner) { - return std::make_shared(owner, *this, &unit); - }); - list.emplace_back(meta_type); - } -} - -void GameSpec::load_object(const gamedata::unit_object &object, unit_meta_list &list) const { - // check graphics - if (this->valid_graphic_id(object.idle_graphic0)) { - auto meta_type = std::make_shared("Object", object.id0, [this, &object](const Player &owner) { - return std::make_shared(owner, *this, &object); - }); - list.emplace_back(meta_type); - } -} - -void GameSpec::load_missile(const gamedata::missile_unit &proj, unit_meta_list &list) const { - // check graphics - if (this->valid_graphic_id(proj.idle_graphic0)) { - auto meta_type = std::make_shared("Projectile", proj.id0, [this, &proj](const Player &owner) { - return std::make_shared(owner, *this, &proj); - }); - list.emplace_back(meta_type); - } -} - - -void GameSpec::load_terrain(const gamedata::empiresdat &gamedata) { - // fetch blending modes - util::Path convert_dir = this->assetmanager->get_asset_dir()["converted"]; - std::vector blending_meta = util::read_csv_file( - convert_dir["blending_modes.docx"]); - - // copy the terrain metainformation - std::vector terrain_meta = gamedata.terrains.data; - - // remove any disabled textures - terrain_meta.erase( - std::remove_if( - terrain_meta.begin(), - terrain_meta.end(), - [](const gamedata::terrain_type &t) { - return not t.enabled; - }), - terrain_meta.end()); - - // result attributes - this->terrain_data.terrain_id_count = terrain_meta.size(); - this->terrain_data.blendmode_count = blending_meta.size(); - this->terrain_data.textures.resize(terrain_data.terrain_id_count); - this->terrain_data.blending_masks.reserve(terrain_data.blendmode_count); - this->terrain_data.terrain_id_priority_map = std::make_unique( - this->terrain_data.terrain_id_count); - this->terrain_data.terrain_id_blendmode_map = std::make_unique( - this->terrain_data.terrain_id_count); - this->terrain_data.influences_buf = std::make_unique( - this->terrain_data.terrain_id_count); - - - log::log(MSG(dbg) << "Terrain prefs: " - << "tiletypes=" << terrain_data.terrain_id_count << ", " - "blendmodes=" - << terrain_data.blendmode_count); - - // create tile textures (snow, ice, grass, whatever) - for (size_t terrain_id = 0; - terrain_id < terrain_data.terrain_id_count; - terrain_id++) { - auto line = &terrain_meta[terrain_id]; - - // TODO: terrain double-define check? - terrain_data.terrain_id_priority_map[terrain_id] = line->blend_priority; - terrain_data.terrain_id_blendmode_map[terrain_id] = line->blend_mode; - - // TODO: remove hardcoding and rely on nyan data - auto terraintex_filename = util::sformat("converted/terrain/%d.slp.png", - line->slp_id); - - auto new_texture = this->assetmanager->get_texture(terraintex_filename, true); - - terrain_data.textures[terrain_id] = new_texture; - } - - // create blending masks (see doc/media/blendomatic) - for (size_t i = 0; i < terrain_data.blendmode_count; i++) { - auto line = &blending_meta[i]; - - // TODO: remove hardcodingn and use nyan data - std::string mask_filename = util::sformat("converted/blendomatic/mode%02d.png", - line->blend_mode); - terrain_data.blending_masks[i] = this->assetmanager->get_texture(mask_filename); - } -} - - -void GameSpec::create_abilities(const gamedata::empiresdat &gamedata) { - // use game data unit commands - int headers = gamedata.unit_headers.data.size(); - int total = 0; - - // it seems the index of the header indicates the unit - for (int i = 0; i < headers; ++i) { - // init unit command vector - std::vector list; - - // add each element - auto &head = gamedata.unit_headers.data[i]; - for (auto &cmd : head.unit_commands.data) { - total++; - - // commands either have a class id or a unit id - // log::dbg("unit command %d %d -> class %d, unit %d, resource %d", i, cmd.id, cmd.class_id, cmd.unit_id, cmd.resource_in); - list.push_back(&cmd); - } - - // insert to command map - this->commands[i] = list; - } -} - - -void Sound::play() const { - if (this->sound_items.size() <= 0) { - return; - } - - int rand = rng::random_range(0, this->sound_items.size()); - int sndid = this->sound_items.at(rand); - - try { - // TODO: buhuuuu gnargghh this has to be moved to the asset loading subsystem hnnnng - audio::AudioManager &am = this->game_spec->get_asset_manager()->get_display()->get_audio_manager(); - - if (not am.is_available()) { - return; - } - - audio::Sound sound = am.get_sound(audio::category_t::GAME, sndid); - sound.play(); - } - catch (audio::Error &e) { - log::log(MSG(warn) << "cannot play: " << e); - } -} - -GameSpecHandle::GameSpecHandle(qtsdl::GuiItemLink *gui_link) : - active{}, - asset_manager{}, - gui_signals{std::make_shared()}, - gui_link{gui_link} { -} - -void GameSpecHandle::set_active(bool active) { - this->active = active; - - this->start_loading_if_needed(); -} - -void GameSpecHandle::set_asset_manager(LegacyAssetManager *asset_manager) { - if (this->asset_manager != asset_manager) { - this->asset_manager = asset_manager; - - this->start_loading_if_needed(); - } -} - -bool GameSpecHandle::is_ready() const { - return this->spec && this->spec->load_complete(); -} - -void GameSpecHandle::invalidate() { - this->spec = nullptr; - - if (this->asset_manager) - this->asset_manager->check_updates(); - - this->start_loading_if_needed(); -} - -void GameSpecHandle::announce_spec() { - if (this->spec && this->spec->load_complete()) - emit this->gui_signals->game_spec_loaded(this->spec); -} - -std::shared_ptr GameSpecHandle::get_spec() { - return this->spec; -} - -void GameSpecHandle::start_loading_if_needed() { - if (this->active && this->asset_manager && !this->spec) { - // create the game specification - this->spec = std::make_shared(this->asset_manager); - - // the load the data - this->start_load_job(); - } -} - -void GameSpecHandle::start_load_job() { - // store the shared pointers in another sharedptr - // so we can pass them to the other thread - auto spec_and_job = std::make_tuple(this->spec, this->gui_signals, job::Job{}); - auto spec_and_job_ptr = std::make_shared(spec_and_job); - - // lambda to be executed to actually load the data files. - auto perform_load = [spec_and_job_ptr] { - return std::get>(*spec_and_job_ptr)->initialize(); - }; - - auto load_finished = [gui_signals_ptr = this->gui_signals.get()](job::result_function_t result) { - bool load_ok; - try { - load_ok = result(); - } - catch (Error &) { - // TODO: display that error in the ui. - throw; - } - catch (std::exception &) { - // TODO: same here. - throw Error{ERR << "gamespec loading failed!"}; - } - - if (load_ok) { - // send the signal that the load job was finished - emit gui_signals_ptr->load_job_finished(); - } - }; - - job::JobManager *job_mgr = this->asset_manager->get_engine()->get_job_manager(); - - std::get>(*spec_and_job_ptr) = job_mgr->enqueue( - perform_load, - load_finished); -} - -} // namespace openage diff --git a/libopenage/gamestate/old/game_spec.h b/libopenage/gamestate/old/game_spec.h deleted file mode 100644 index c5a9a66348..0000000000 --- a/libopenage/gamestate/old/game_spec.h +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../../gamedata/gamedata_dummy.h" -#include "../../gamedata/graphic_dummy.h" -#include "../../job/job.h" -#include "../../unit/unit_texture.h" -#include "../../util/csv.h" -#include "terrain/terrain.h" -#include "types.h" - -#include -#include -#include - - -namespace openage { - -class LegacyAssetManager; -class GameSpec; -class UnitType; -class UnitTypeMeta; -class Player; - - -/** - * could use unique ptr - */ -using unit_type_list = std::vector>; -using unit_meta_list = std::vector>; - - -/** - * simple sound object - * TODO: move to assetmanager - */ -class Sound { -public: - Sound(GameSpec *spec, std::vector &&sound_items) : - sound_items{sound_items}, - game_spec{spec} {} - - void play() const; - - std::vector sound_items; - - GameSpec *game_spec; -}; - - -/** - * GameSpec gives a collection of all game elements - * this currently includes unit types and terrain types - * This provides a system which can easily allow game modding - * - * uses the LegacyAssetManager to gather - * graphic data, composite textures and sounds. - * - * all types are sorted and stored by id values, - * each data object is referenced by a type and id pair - * - * dealing directly with files done by asset manager - * TODO: should the audio loading should be moved there? - */ -class GameSpec { -public: - GameSpec(LegacyAssetManager *am); - virtual ~GameSpec(); - - /** - * perform the main loading job. - * this loads all the data into the storage. - */ - bool initialize(); - - /** - * Check if loading has been completed, - * a load percent would be nice - */ - bool load_complete() const; - - /** - * return data used for constructing terrain objects - */ - terrain_meta *get_terrain_meta(); - - /** - * reverse lookup of slp - */ - index_t get_slp_graphic(index_t slp); - - /** - * lookup using a texture id, this specifically avoids returning the missing placeholder texture - */ - Texture *get_texture(index_t graphic_id) const; - - /** - * lookup using a texture file name - */ - Texture *get_texture(const std::string &file_name, bool use_metafile = true) const; - - /** - * get unit texture by graphic id -- this is an directional texture - * which also includes graphic deltas - */ - std::shared_ptr get_unit_texture(index_t graphic_id) const; - - /** - * get sound by sound id - */ - const Sound *get_sound(index_t sound_id) const; - - /** - * gamedata for a graphic - * nyan will have to replace this somehow - */ - const gamedata::graphic *get_graphic_data(index_t grp_id) const; - - /** - * get available commands for a unit id - * nyan will have to replace this somehow - */ - std::vector get_command_data(index_t unit_id) const; - - /** - * returns the name of a civ by index - */ - std::string get_civ_name(int civ_id) const; - - /** - * makes initial unit types for a particular civ id - */ - void create_unit_types(unit_meta_list &objects, int civ_id) const; - - /** - * Return the asset manager used for loading resources - * of this game specification. - */ - LegacyAssetManager *get_asset_manager() const; - -private: - /** - * check graphic id is valid - */ - bool valid_graphic_id(index_t) const; - - /** - * create unit abilities from game data - */ - void create_abilities(const gamedata::empiresdat &gamedata); - - /** - * loads required assets to construct a buildings. - * adds to the type list if the object can be created safely. - */ - void load_building(const gamedata::building_unit &, unit_meta_list &) const; - - /** - * loads assets for living things. - */ - void load_living(const gamedata::living_unit &, unit_meta_list &) const; - - /** - * load assets for other game objects (not building and living). - */ - void load_object(const gamedata::unit_object &, unit_meta_list &) const; - - /** - * load missile assets. - */ - void load_missile(const gamedata::missile_unit &, unit_meta_list &) const; - - /** - * fill in the terrain_data attribute of this - */ - void load_terrain(const gamedata::empiresdat &gamedata); - - /** - * Invoked when the gamedata has been loaded. - */ - void on_gamedata_loaded(const gamedata::empiresdat &gamedata); - - /** - * Asset management entity that is responsible for textures, sounds, etc. - */ - LegacyAssetManager *assetmanager; - - /** - * The full original gamedata tree. - */ - std::vector gamedata; - - /** - * data used for constructing terrain objects - */ - terrain_meta terrain_data; - - /** - * slp to graphic id reverse lookup - */ - std::unordered_map slp_to_graphic; - - /** - * map graphic id to gamedata graphic. - */ - std::unordered_map graphics; - - /** - * commands available for each unit id - */ - std::unordered_map> commands; - - /** - * graphic ids -> unit texture for that id - */ - std::unordered_map> unit_textures; - - /** - * sound ids mapped to playable sounds for all available sounds. - */ - std::unordered_map available_sounds; - - /** - * has game data been load yet - */ - bool gamedata_loaded; -}; - -} // namespace openage - -namespace qtsdl { -class GuiItemLink; -} // namespace qtsdl - -namespace openage { - -class GameSpecSignals; - -/** - * Game specification instanciated in QML. - * Linked to the "GameSpec" QML type. - * - * Wraps the "GameSpec" C++ class from above. - */ -class GameSpecHandle { -public: - explicit GameSpecHandle(qtsdl::GuiItemLink *gui_link); - - /** - * Control whether this specification can be loaded (=true) - * or will not be loaded (=false). - */ - void set_active(bool active); - - /** - * invoked from qml when the asset_manager member is set. - */ - void set_asset_manager(LegacyAssetManager *asset_manager); - - /** - * Return if the specification was fully loaded. - */ - bool is_ready() const; - - /** - * forget everything about the specification and - * reload it with `start_loading_if_needed`. - */ - void invalidate(); - - /** - * signal about a loaded spec if any - */ - void announce_spec(); - - /** - * Return the contained game specification. - */ - std::shared_ptr get_spec(); - -private: - /** - * load the game specification if not already present. - */ - void start_loading_if_needed(); - - /** - * Actually dispatch the loading job to the job manager. - */ - void start_load_job(); - - /** - * called from the job manager when the loading job finished. - */ - void on_loaded(job::result_function_t result); - - /** - * The real game specification. - */ - std::shared_ptr spec; - - /** - * enables the loading of the game specification. - */ - bool active; - - LegacyAssetManager *asset_manager; - -public: - std::shared_ptr gui_signals; - qtsdl::GuiItemLink *gui_link; -}; - -class GameSpecSignals : public QObject { - Q_OBJECT - -public: -signals: - /* - * Some load job has finished. - * - * To be sure that the latest result is used, do the verification at the point of use. - */ - void load_job_finished(); - - void game_spec_loaded(std::shared_ptr loaded_game_spec); -}; - -} // namespace openage diff --git a/libopenage/gamestate/old/generator.cpp b/libopenage/gamestate/old/generator.cpp deleted file mode 100644 index b60ce1ffd7..0000000000 --- a/libopenage/gamestate/old/generator.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "generator.h" - -#include "../../log/log.h" -#include "../../rng/rng.h" -#include "../../terrain/terrain_chunk.h" -#include "../../unit/unit.h" -#include "../../util/math_constants.h" -#include "game_main.h" -#include "game_save.h" -#include "game_spec.h" - - -namespace openage { - -coord::tile random_tile(rng::RNG &rng, tileset_t tiles) { - if (tiles.empty()) { - log::log(MSG(err) << "random tile failed"); - return coord::tile{0, 0}; - } - uint64_t index = rng.random() % tiles.size(); - auto it = std::begin(tiles); - std::advance(it, index); - return *it; -} - - -Region::Region(int size) - : - owner{0}, - object_id{0}, - terrain_id{0}, - center{0, 0} { - for (int ne = -size; ne < size; ++ne) { - for (int se = -size; se < size; ++se) { - this->tiles.emplace(coord::tile{ne, se}); - } - } -} - -Region::Region(coord::tile center, tileset_t tiles) - : - owner{0}, - object_id{0}, - terrain_id{0}, - center(center), - tiles{tiles} { -} - -tileset_t Region::get_tiles() const { - return this->tiles; -} - -coord::tile Region::get_center() const { - return this->center; -} - -coord::tile Region::get_tile(rng::RNG &rng) const { - return random_tile(rng, this->tiles); -} - - -tileset_t Region::subset(rng::RNG &rng, coord::tile start_point, unsigned int number, double p) const { - if (p == 0.0) { - return tileset_t(); - } - - // the set of included tiles - std::unordered_set subtiles; - subtiles.emplace(start_point); - - // outside layer of tiles - std::unordered_set edge_set; - - while (subtiles.size() < number) { - if (edge_set.empty()) { - - // try fill the edge list - for (auto &t : subtiles) { - - // check adjacent tiles - for (int i = 0; i < 4; ++i) { - coord::tile adj = t + neigh_tiles[i]; - if (this->tiles.count(adj) && - !subtiles.count(adj)) { - edge_set.emplace(adj); - } - } - } - if (edge_set.empty()) { - - // unable to grow further - return subtiles; - } - } - - // transfer a random tile - coord::tile next_tile = random_tile(rng, edge_set); - edge_set.erase(next_tile); - if (rng.probability(p)) { - subtiles.emplace(next_tile); - } - } - return subtiles; -} - -Region Region::take_tiles(rng::RNG &rng, coord::tile start_point, unsigned int number, double p) { - - tileset_t new_set = this->subset(rng, start_point, number, p); - - // erase from current set - for (auto &t: new_set) { - this->tiles.erase(t); - } - - Region new_region(start_point, new_set); - new_region.terrain_id = this->terrain_id; - return new_region; -} - -Region Region::take_random(rng::RNG &rng, unsigned int number, double p) { - return this->take_tiles(rng, this->get_tile(rng), number, p); -} - -Generator::Generator(qtsdl::GuiItemLink *gui_link) - : - gui_link{gui_link} -{ - this->setv("generation_seed", 4321); - this->setv("terrain_size", 2); - this->setv("terrain_base_id", 0); - this->setv("player_area", 850); - this->setv("player_radius", 10); - this->setv("load_filename", "/tmp/default_save.oas"); - this->setv("from_file", false); - // TODO pick the users name - this->set_csv("player_names", std::vector{"Jonas", "Michael"}); -} - -std::shared_ptr Generator::get_spec() const { - return this->spec; -} - -std::vector Generator::player_names() const { - auto result = this->get_csv("player_names"); - - // gaia is player 0 - result.insert(result.begin(), "Gaia"); - - return result; -} - -void Generator::create_regions() { - - // get option settings - int seed = this->getv("generation_seed"); - int size = this->getv("terrain_size"); - int base_id = this->getv("terrain_base_id"); - int p_area = this->getv("player_area"); - int p_radius = this->getv("player_radius"); - - // enforce some lower limits - size = std::max(1, size); - base_id = std::max(0, base_id); - p_area = std::max(50, p_area); - p_radius = std::max(2, p_radius); - - rng::RNG rng(seed); - Region base(size * 16); - base.terrain_id = base_id; - std::vector player_regions; - - int player_count = this->player_names().size() - 1; - for (int i = 0; i < player_count; ++i) { - log::log(MSG(dbg) << "generate player " << i); - - // space players in a circular pattern - double angle = static_cast(i) / static_cast(player_count); - int ne = size * p_radius * sin(math::TAU * angle); - int se = size * p_radius * cos(math::TAU * angle); - coord::tile player_tile{ne, se}; - - Region player = base.take_tiles(rng, player_tile, p_area, 0.5); - player.terrain_id = 10; - - Region obj_space = player.take_tiles(rng, player.get_center(), p_area / 5, 0.5); - obj_space.owner = i + 1; - obj_space.terrain_id = 8; - - Region trees1 = player.take_random(rng, p_area / 10, 0.3); - trees1.terrain_id = 9; - trees1.object_id = 349; - - Region trees2 = player.take_random(rng, p_area / 10, 0.3); - trees2.terrain_id = 9; - trees2.object_id = 351; - - Region stone = player.take_random(rng, 5, 0.3); - stone.object_id = 102; - - Region gold = player.take_random(rng, 7, 0.3); - gold.object_id = 66; - - Region forage = player.take_random(rng, 6, 0.3); - forage.object_id = 59; - - Region sheep = player.take_random(rng, 4, 0.3); - sheep.owner = obj_space.owner; - sheep.object_id = 594; - - player_regions.push_back(player); - player_regions.push_back(obj_space); - player_regions.push_back(trees1); - player_regions.push_back(trees2); - player_regions.push_back(stone); - player_regions.push_back(gold); - player_regions.push_back(forage); - player_regions.push_back(sheep); - } - - for (int i = 0; i < 6; ++i) { - Region extra_trees = base.take_random(rng, 160, 0.3); - extra_trees.terrain_id = 9; - extra_trees.object_id = 349; - player_regions.push_back(extra_trees); - } - - // set regions - this->regions.clear(); - this->regions.push_back(base); - for (auto &r : player_regions) { - this->regions.push_back(r); - } -} - - -std::shared_ptr Generator::terrain() const { - auto terrain = std::make_shared(this->spec->get_terrain_meta(), true); - for (auto &r : this->regions) { - for (auto &tile : r.get_tiles()) { - TerrainChunk *chunk = terrain->get_create_chunk(tile); - chunk->get_data(tile.get_pos_on_chunk())->terrain_id = r.terrain_id; - } - } - - // mark the 0, 0 tile. - coord::tile debug_tile_pos{0, 0}; - terrain->get_data(debug_tile_pos)->terrain_id = 6; - return terrain; -} - -void Generator::add_units(GameMain &m) const { - for (auto &r : this->regions) { - - // Regions filled with resource objects - // trees / mines - if (r.object_id) { - Player* p = m.get_player(r.owner); - auto otype = p->get_type(r.object_id); - if (!otype) { - break; - } - for (auto &tile : r.get_tiles()) { - m.placed_units.new_unit(*otype, *p, tile.to_phys3(*m.terrain)); - } - } - - // A space for starting town center and villagers - else if (r.owner) { - Player* p = m.get_player(r.owner); - auto tctype = p->get_type(109); // town center - auto mvtype = p->get_type(83); // male villager - auto fvtype = p->get_type(293); // female villager - auto sctype = p->get_type(448); // scout cavarly - if (!tctype || !mvtype || !fvtype || !sctype) { - break; - } - - coord::tile tile = r.get_center(); - tile.ne -= 1; - tile.se -= 1; - - // Place a completed town center - auto ref = m.placed_units.new_unit(*tctype, *p, tile.to_phys3(*m.terrain)); - if (ref.is_valid()) { - complete_building(*ref.get()); - } - - // Place three villagers - tile.ne -= 1; - m.placed_units.new_unit(*fvtype, *p, tile.to_phys3(*m.terrain)); - tile.se += 1; - m.placed_units.new_unit(*mvtype, *p, tile.to_phys3(*m.terrain)); - tile.se += 1; - m.placed_units.new_unit(*fvtype, *p, tile.to_phys3(*m.terrain)); - // TODO uncomment when the scout looks better - //tile.se += 2; - //m.placed_units.new_unit(*sctype, *p, tile.to_tile3().to_phys3()); - } - } -} - -std::unique_ptr Generator::create(std::shared_ptr spec) { - ENSURE(spec->load_complete(), "spec hasn't been checked or was invalidated"); - this->spec = spec; - - if (this->getv("from_file")) { - // create an empty game - this->regions.clear(); - - auto game = std::make_unique(*this); - gameio::load(game.get(), this->getv("load_filename")); - - return game; - } else { - // generation - this->create_regions(); - return std::make_unique(*this); - } -} - -} // namespace openage diff --git a/libopenage/gamestate/old/generator.h b/libopenage/gamestate/old/generator.h deleted file mode 100644 index a2d4bf58b7..0000000000 --- a/libopenage/gamestate/old/generator.h +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../../coord/tile.h" -#include "../../gui/guisys/public/gui_property_map.h" - -namespace qtsdl { -class GuiItemLink; -} // qtsdl - -namespace openage { - -class GameSpec; -class Terrain; -class GameMain; - -namespace rng { -class RNG; -} // openage::rng - -/** - * the type to store a set of tiles - */ -using tileset_t = std::unordered_set; - -/** - * picks a random tile from a set - */ -coord::tile random_tile(rng::RNG &rng, tileset_t tiles); - -/** - * the four directions available for 2d tiles - */ -constexpr coord::tile_delta const neigh_tiles[] = { - { 1, 0}, - {-1, 0}, - { 0, 1}, - { 0, -1} -}; - -/** - * A region is a set of tiles around a starting point, - * including functions to create child regions - */ -class Region { -public: - /** - * a square of tiles ranging from - * {-size, -size} to {size, size} - */ - Region(int size); - - /** - * a specified set of tiles - */ - Region(coord::tile center, tileset_t tiles); - - /** - * all tiles in this region - */ - tileset_t get_tiles() const; - - /** - * the center point of the region - */ - coord::tile get_center() const; - - /** - * picks a random tile from this subset - */ - coord::tile get_tile(rng::RNG &rng) const; - - /** - * find a group of tiles inside this region, number is the number of tiles to be contained - * in the subset, p is a probability between 0.0 and 1.0 which produces various shapes. a value - * of 1.0 produces circular shapes, where as a low value produces more scattered shapes. a value - * of 0.0 should not be used, and will always return no tiles - */ - tileset_t subset(rng::RNG &rng, coord::tile start_tile, unsigned int number, double p) const; - - /** - * removes the given set of tiles from this region, which get split of as a new child region - */ - Region take_tiles(rng::RNG &rng, coord::tile start_tile, unsigned int number, double p); - - /** - * similiar to take_tiles, but takes a random group of tiles - */ - Region take_random(rng::RNG &rng, unsigned int number, double p); - - /** - * player id of the owner, 0 for none - */ - int owner; - - /** - * the object to be placed on each tile of this region - * 0 for placing no object - */ - int object_id; - - /** - * the base terrain for this region - */ - int terrain_id; - -private: - - /** - * the center tile of this region - */ - coord::tile center; - - /** - * tiles in this region - */ - tileset_t tiles; -}; - - -/** - * Manages creation and setup of new games - * - * required values used to construct a game - * this includes game spec and players - * - * this will be identical for each networked - * player in a game - */ -class Generator : public qtsdl::GuiPropertyMap { -public: - explicit Generator(qtsdl::GuiItemLink *gui_link); - - /** - * game spec used by this generator - */ - std::shared_ptr get_spec() const; - - /** - * return the list of player names - */ - std::vector player_names() const; - - /** - * returns the generated terrain - */ - std::shared_ptr terrain() const; - - /** - * places all initial objects - */ - void add_units(GameMain &m) const; - - /** - * Create a game from a specification. - */ - std::unique_ptr create(std::shared_ptr spec); - -private: - void create_regions(); - - /** - * data version used to create a game - */ - std::shared_ptr spec; - - /** - * the generated data - */ - std::vector regions; - -public: - qtsdl::GuiItemLink *gui_link; -}; - -} // namespace openage diff --git a/libopenage/gamestate/old/market.cpp b/libopenage/gamestate/old/market.cpp deleted file mode 100644 index 4b1d50bc24..0000000000 --- a/libopenage/gamestate/old/market.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2017-2019 the openage authors. See copying.md for legal info. - -#include "player.h" -#include "market.h" - -namespace openage { - -Market::Market() { - // the default prices when a game starts - this->base_prices[game_resource::wood] = 100; - this->base_prices[game_resource::food] = 100; - this->base_prices[game_resource::stone] = 130; -} - -// Price calculation is documented at doc/reverse_engineering/market.md#prices - -bool Market::sell(Player &player, const game_resource res) { - // deduct the standard MARKET_TRANSACTION_AMOUNT of the selling res - if (player.deduct(res, MARKET_TRANSACTION_AMOUNT)) { - // if deduct was successful - // calc the gold received from selling MARKET_TRANSACTION_AMOUNT of res - double amount = this->get_sell_prices(player).get(res); - player.receive(game_resource::gold, amount); - - // decrease the price - this->base_prices[res] -= MARKET_PRICE_D; - if (this->base_prices.get(res) < MARKET_PRICE_MIN) { - this->base_prices[res] = MARKET_PRICE_MIN; - } - return true; - } - return false; -} - -bool Market::buy(Player &player, const game_resource res) { - // calc the gold needed to buy MARKET_TRANSACTION_AMOUNT of res - double price = this->get_buy_prices(player).get(res); - if (player.deduct(game_resource::gold, price)) { - // if deduct was successful - player.receive(res, MARKET_TRANSACTION_AMOUNT); - - // increase the price - this->base_prices[res] += MARKET_PRICE_D; - if (this->base_prices.get(res) > MARKET_PRICE_MAX) { - this->base_prices[res] = MARKET_PRICE_MAX; - } - return true; - } - return false; -} - -ResourceBundle Market::get_buy_prices(const Player &player) const { - return this->get_prices(player, true); -} - -ResourceBundle Market::get_sell_prices(const Player &player) const { - return this->get_prices(player, false); -} - -ResourceBundle Market::get_prices(const Player &player, const bool is_buy) const { - double mult = this->get_multiplier(player, is_buy); - - auto rb = ResourceBundle(this->base_prices); - rb *= mult; - rb.round(); // round to nearest integer - return rb; -} - -double Market::get_multiplier(const Player &/*player*/, const bool is_buy) const { - double base = 0.3; - // TODO change multiplier based on civ bonuses and player researched techs - double mult = base; - - if (is_buy) { - mult = 1 + mult; - } - else { - mult = 1 - mult; - } - - return mult; -} - -} // openage diff --git a/libopenage/gamestate/old/market.h b/libopenage/gamestate/old/market.h deleted file mode 100644 index 643668fe59..0000000000 --- a/libopenage/gamestate/old/market.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2017-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include "resource.h" - -namespace openage { - -class Player; - -constexpr double MARKET_PRICE_D = 3.0; -constexpr double MARKET_PRICE_MIN = 20.0; -constexpr double MARKET_PRICE_MAX = 9999.0; -constexpr double MARKET_TRANSACTION_AMOUNT = 100.0; - -/** - * The global market prices. - * - * Price calculation is documented at doc/reverse_engineering/market.md#prices - */ -class Market { -public: - Market(); - - /** - * The given player sells the given resource for gold. - * Returns true when the transaction is successful. - */ - bool sell(Player &player, const game_resource res); - - /** - * The given player buys the given resource with gold. - * Returns true when the transaction is successful. - */ - bool buy(Player &player, const game_resource res); - - /** - * Get the selling prices for a given player. - */ - ResourceBundle get_buy_prices(const Player &player) const; - - /** - * Get the buying prices for a given player. - */ - ResourceBundle get_sell_prices(const Player &player) const; - -protected: - - /** - * The getBuyPrices and getSellPrices are redirected here. - */ - ResourceBundle get_prices(const Player &player, const bool is_buy) const; - - /** - * Get the multiplier for the base prices - */ - double get_multiplier(const Player &player, const bool is_buy) const; - -private: - - /** - * Stores the base price values of each resource. - * - * The ResourceBundle is used to represent the prices instead of the amounts - * for each resource. - */ - ResourceBundle base_prices; - -}; - -} // openage diff --git a/libopenage/gamestate/old/player.cpp b/libopenage/gamestate/old/player.cpp deleted file mode 100644 index ed6bd9e8b9..0000000000 --- a/libopenage/gamestate/old/player.cpp +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2015-2018 the openage authors. See copying.md for legal info. - -#include "player.h" - -#include - -#include "../../log/log.h" -#include "../../unit/unit.h" -#include "../../unit/unit_type.h" -#include "../../util/math_constants.h" -#include "team.h" - - -namespace openage { - -Player::Player(Civilisation *civ, unsigned int number, std::string name) - : - player_number{number}, - color{number}, - civ{civ}, - name{std::move(name)}, - team{nullptr}, - population{0, 200}, // TODO change, get population cap max from game options - score{this}, - age{1} { // TODO change, get starting age from game options - // starting resources - // TODO change, get starting resources from game options - this->resources.set_all(1000); - // TODO change, get starting resources capacity from game options or nyan - this->resources_capacity.set_all(math::DOUBLE_INF / 2); // half to avoid overflows - this->on_resources_change(); -} - -bool Player::operator ==(const Player &other) const { - return this->player_number == other.player_number; -} - -bool Player::is_enemy(const Player &other) const { - - return !this->is_ally(other); -} - -bool Player::is_ally(const Player &other) const { - - if (this->player_number == other.player_number) { - return true; // same player - } - - if (this->team && this->team->is_member(other)) { - return true; // same team - } - - // everyone else is enemy - return false; -} - -bool Player::owns(Unit &unit) const { - if (unit.has_attribute(attr_type::owner)) { - return this == &unit.get_attribute().player; - } - return false; -} - -void Player::receive(const ResourceBundle& amount) { - this->resources += amount; - this->on_resources_change(); -} - -void Player::receive(const game_resource resource, double amount) { - this->resources[resource] += amount; - this->on_resources_change(); -} - -bool Player::can_receive(const ResourceBundle& amount) const { - return this->resources_capacity.has(this->resources, amount); -} - -bool Player::can_receive(const game_resource resource, double amount) const { - return this->resources_capacity.get(resource) >= this->resources.get(resource) + amount; -} - -bool Player::deduct(const ResourceBundle& amount) { - if (this->resources.deduct(amount)) { - this->on_resources_change(); - return true; - } - return false; -} - -bool Player::deduct(const game_resource resource, double amount) { - if (this->resources[resource] >= amount) { - this->resources[resource] -= amount; - this->on_resources_change(); - return true; - } - return false; -} - -bool Player::can_deduct(const ResourceBundle& amount) const { - return this->resources.has(amount); -} - -bool Player::can_deduct(const game_resource resource, double amount) const { - return this->resources.get(resource) >= amount; -} - -double Player::amount(const game_resource resource) const { - return this->resources.get(resource); -} - -bool Player::can_make(const UnitType &type) const { - return this->can_deduct(type.cost.get(*this)) && - this->get_units_have(type.id()) + this->get_units_pending(type.id()) < type.have_limit && - this->get_units_had(type.id()) + this->get_units_pending(type.id()) < type.had_limit; -} - -size_t Player::type_count() { - return this->available_ids.size(); -} - -UnitType *Player::get_type(index_t type_id) const { - if (this->available_ids.count(type_id) == 0) { - if (type_id > 0) { - log::log(MSG(info) << " -> ignoring type_id: " << type_id); - } - return nullptr; - } - return this->available_ids.at(type_id); -} - -UnitType *Player::get_type_index(size_t type_index) const { - if (type_index < available_objects.size()) { - return available_objects.at(type_index).get(); - } - log::log(MSG(info) << " -> ignoring type_index: " << type_index); - return nullptr; -} - - -void Player::initialise_unit_types() { - log::log(MSG(info) << name << " has civilisation " << this->civ->civ_name); - for (auto &type : this->civ->object_meta()) { - auto shared_type = type->init(*this); - index_t id = shared_type->id(); - this->available_objects.emplace_back(shared_type); - this->available_ids[id] = shared_type.get(); - } -} - -void Player::active_unit_added(Unit *unit, bool from_pending) { - // check if unit is actually active - if (this->is_unit_pending(unit)) { - this->units_pending[unit->unit_type->id()] += 1; - return; - } - - if (from_pending) { - this->units_pending[unit->unit_type->id()] -= 1; - } - - this->units_have[unit->unit_type->id()] += 1; - this->units_had[unit->unit_type->id()] += 1; - // TODO handle here building dependencies - - // population - if (unit->has_attribute(attr_type::population)) { - auto popul = unit->get_attribute(); - if (popul.demand > 0) { - this->population.demand_population(popul.demand); - } - if (popul.capacity > 0) { - this->population.add_capacity(popul.capacity); - } - } - - // resources capacity - if (unit->has_attribute(attr_type::storage)) { - auto storage = unit->get_attribute(); - this->resources_capacity += storage.capacity; - this->on_resources_change(); - } - - // score - // TODO improve selectors - if (unit->unit_type->id() == 82 || unit->unit_type->id() == 276) { // Castle, Wonder - this->score.add_score(score_category::society, unit->unit_type->cost.get(*this).sum() * 0.2); - } else if (unit->has_attribute(attr_type::building) || unit->has_attribute(attr_type::population)) { // building, living - this->score.add_score(score_category::economy, unit->unit_type->cost.get(*this).sum() * 0.2); - } - - // TODO handle here on create unit triggers - // TODO check for unit based win conditions -} - -void Player::active_unit_removed(Unit *unit) { - // check if unit is actually active - if (this->is_unit_pending(unit)) { - this->units_pending[unit->unit_type->id()] -= 1; - return; - } - - this->units_have[unit->unit_type->id()] -= 1; - // TODO handle here building dependencies - - // population - if (unit->has_attribute(attr_type::population)) { - auto popul = unit->get_attribute(); - if (popul.demand > 0) { - this->population.free_population(popul.demand); - } - if (popul.capacity > 0) { - this->population.remove_capacity(popul.capacity); - } - } - - // resources capacity - if (unit->has_attribute(attr_type::storage)) { - auto storage = unit->get_attribute(); - this->resources_capacity -= storage.capacity; - this->on_resources_change(); - } - - // score - // TODO improve selectors - if (unit->unit_type->id() == 82 || unit->unit_type->id() == 276) { // Castle, Wonder - // nothing - } else if (unit->has_attribute(attr_type::building) || unit->has_attribute(attr_type::population)) { // building, living - this->score.remove_score(score_category::economy, unit->unit_type->cost.get(*this).sum() * 0.2); - } - - // TODO handle here on death unit triggers - // TODO check for unit based win conditions -} - -void Player::killed_unit(const Unit & unit) { - // score - this->score.add_score(score_category::military, unit.unit_type->cost.get(*this).sum() * 0.2); -} - -void Player::advance_age() { - this->age += 1; -} - -void Player::on_resources_change() { - - // capacity overflow - if (! (this->resources_capacity >= this->resources_capacity)) { - this->resources.limit(this->resources_capacity); - } - - // score - this->score.update_resources(this->resources); - - // TODO check for resource based win conditions -} - -int Player::get_units_have(int type_id) const { - if (this->units_have.count(type_id)) { - return this->units_have.at(type_id); - } - return 0; -} - -int Player::get_units_had(int type_id) const { - if (this->units_had.count(type_id)) { - return this->units_had.at(type_id); - } - return 0; -} - -int Player::get_units_pending(int type_id) const { - if (this->units_pending.count(type_id)) { - return this->units_pending.at(type_id); - } - return 0; -} - -bool Player::is_unit_pending(Unit *unit) const { - // TODO check aslo if unit is training - return unit->has_attribute(attr_type::building) && unit->get_attribute().completed < 1.0f; -} - -int Player::get_workforce_count() const { - // TODO get all units tagged as work force - return this->units_have.at(83) + this->units_have.at(293) + // villagers - this->units_have.at(13) + // fishing ship - this->units_have.at(128) + // trade cart - this->units_have.at(545); // transport ship -} - -} // openage diff --git a/libopenage/gamestate/old/player.h b/libopenage/gamestate/old/player.h deleted file mode 100644 index 469a6c1f98..0000000000 --- a/libopenage/gamestate/old/player.h +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "civilisation.h" -#include "population_tracker.h" -#include "resource.h" -#include "score.h" - - -namespace openage { - -class Unit; -class Team; - -class Player { -public: - Player(Civilisation *civ, unsigned int number, std::string name); - - /** - * values 0 .. player count - 1 - */ - const unsigned int player_number; - - /** - * values 1 .. player count - * would be better to have rgb color value - */ - const unsigned int color; - - /** - * civilisation and techs of this player - */ - const Civilisation *civ; - - /** - * visible name of this player - */ - const std::string name; - - /** - * the team of this player - * nullptr if member of no team - */ - Team *team; - - /** - * checks if two players are the same - */ - bool operator ==(const Player &other) const; - - /** - * the specified player is an enemy of this player - */ - bool is_enemy(const Player &) const; - - /** - * the specified player is an ally of this player - */ - bool is_ally(const Player &) const; - - /** - * this player owns the specified unit - */ - bool owns(Unit &) const; - - /** - * add to stockpile - */ - void receive(const ResourceBundle& amount); - void receive(const game_resource resource, double amount); - - /** - * Check if can add to stockpile - */ - bool can_receive(const ResourceBundle& amount) const; - bool can_receive(const game_resource resource, double amount) const; - - /** - * remove from stockpile if available - */ - bool deduct(const ResourceBundle& amount); - bool deduct(const game_resource resource, double amount); - - /** - * Check if the player has enough resources to deduct the given amount. - */ - bool can_deduct(const ResourceBundle& amount) const; - bool can_deduct(const game_resource resource, double amount) const; - - /** - * current stockpile amount - */ - double amount(const game_resource resource) const; - - /** - * Check if the player can make a new unit of the given type - */ - bool can_make(const UnitType &type) const; - - /** - * total number of unit types available - */ - size_t type_count(); - - /** - * unit types by aoe gamedata unit ids -- the unit type which corresponds to an aoe unit id - */ - UnitType *get_type(index_t type_id) const; - - /** - * unit types by list index -- a continuous array of all types - * probably not a useful function / can be removed - */ - UnitType *get_type_index(size_t type_index) const; - - /** - * initialise with the base tech level - */ - void initialise_unit_types(); - - /** - * Keeps track of the population information. - */ - PopulationTracker population; - - /** - * The score of the player. - */ - PlayerScore score; - - /** - * Called when a unit is created and active. - * - * If the unit was pending when create (constuction site, training) the method must be - * called again when the unit activates (with the from_penging param set to true) - */ - void active_unit_added(Unit *unit, bool from_pending=false); - - /** - * Called when a unit is destroyed. - */ - void active_unit_removed(Unit *unit); - - /** - * Called when a unit is killed by this player. - */ - void killed_unit(const Unit & unit); - - /** - * Advance to next age; - */ - void advance_age(); - - // Getters - - /** - * Get the number of units the player has for each unit type id. - */ - int get_units_have(int type_id) const; - - /** - * Get the number of units the player ever had for each unit type id. - */ - int get_units_had(int type_id) const; - - /** - * Get the number of units the player has being made for each unit type id. - */ - int get_units_pending(int type_id) const; - - /** - * Get the current age. - * The first age has the value 1. - */ - int get_age() const { return age; } - - /** - * The number of units considered part of the workforce. - */ - int get_workforce_count() const; - - -private: - - bool is_unit_pending(Unit *unit) const; - - /** - * The resources this player currently has - */ - ResourceBundle resources; - - /** - * The resources capacities this player currently has - */ - ResourceBundle resources_capacity; - - /** - * Called when the resources amounts change. - */ - void on_resources_change(); - - /** - * unit types which can be produced by this player. - * TODO revisit, can be simplified? - */ - unit_type_list available_objects; - - /** - * available objects mapped using type id - * unit ids -> unit type for that id - * TODO revisit, can be simplified? - */ - std::unordered_map available_ids; - - /** - * The number of units the player has for each unit type id. - * Used for and event triggers. - */ - std::unordered_map units_have; - - /** - * The number of units the player ever had for each unit type id. - * Used for unit dependencies (eg. Farm). - */ - std::unordered_map units_had; - - /* - * The number of units the player has being made for each unit type id. - * Used for unit limits (eg. Town Center). - */ - std::unordered_map units_pending; - - /** - * The current age. - */ - int age; - -}; - -} // openage diff --git a/libopenage/gamestate/old/population_tracker.cpp b/libopenage/gamestate/old/population_tracker.cpp deleted file mode 100644 index fdb79590f6..0000000000 --- a/libopenage/gamestate/old/population_tracker.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2017-2019 the openage authors. See copying.md for legal info. - -#include "population_tracker.h" - -namespace openage { - -PopulationTracker::PopulationTracker(int capacity_static, int capacity_max) { - this->demand = 0; - this->capacity_static = capacity_static; - this->capacity_real = 0; - this->capacity_max = capacity_max; - this->update_capacity(); -} - -void PopulationTracker::demand_population(int i) { - this->demand += i; - // TODO triger gui update -} - -void PopulationTracker::free_population(int i) { - this->demand -= i; - // TODO triger gui update -} - -void PopulationTracker::add_capacity_static(int i) { - this->capacity_static += i; - this->update_capacity(); -} - -void PopulationTracker::add_capacity(int i) { - this->capacity_real += i; - this->update_capacity(); -} - -void PopulationTracker::remove_capacity(int i) { - this->capacity_real -= i; - this->update_capacity(); -} - -void PopulationTracker::add_capacity_max(int i) { - this->capacity_max += i; - this->update_capacity(); -} - -void PopulationTracker::update_capacity() { - this->capacity_total = this->capacity_static + this->capacity_real; - // check the capacity limit - if (this->capacity_total > this->capacity_max) { - this->capacity = this->capacity_max; - } else { - this->capacity = this->capacity_total; - } - // TODO triger gui update -} - -int PopulationTracker::get_demand() const { - return this->demand; -} - -int PopulationTracker::get_capacity() const { - return this->capacity; -} - -int PopulationTracker::get_space() const { - return this->capacity - this->demand; -} - -int PopulationTracker::get_capacity_overflow() const { - return this->capacity_total - this->capacity; -} - -bool PopulationTracker::is_capacity_maxed() const { - return this->capacity >= this->capacity_max; -} - -} // openage diff --git a/libopenage/gamestate/old/population_tracker.h b/libopenage/gamestate/old/population_tracker.h deleted file mode 100644 index 431c0f28ea..0000000000 --- a/libopenage/gamestate/old/population_tracker.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2017-2019 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { - -/** - * Keeps track of the population size and capacity. - */ -class PopulationTracker { -public: - - PopulationTracker(int capacity_static, int capacity_max); - - /** - * Add to the population demand - */ - void demand_population(int i); - - /** - * Remove from the population demand - */ - void free_population(int i); - - /** - * Changes the capacity given by civ bonuses - */ - void add_capacity_static(int i); - - /** - * Add to the capacity given by units - */ - void add_capacity(int i); - - /** - * Remove from the capacity given by units - */ - void remove_capacity(int i); - - /** - * Changes the max capacity given by civ bonuses - */ - void add_capacity_max(int i); - - int get_demand() const; - - int get_capacity() const; - - /** - * Returns the available population capacity for new units. - */ - int get_space() const; - - /** - * Returns the population capacity over the max limit. - */ - int get_capacity_overflow() const; - - /** - * Check if the population capacity has reached the max limit. - */ - bool is_capacity_maxed() const; - -private: - - /** - * Calculates the capacity values based on the limits. - * Must be called when a capacity variable changes. - */ - void update_capacity(); - - /** - * The population demand - */ - int demand; - - /** - * The population capacity given by civ bonuses - */ - int capacity_static; - - /** - * The population capacity given by units - */ - int capacity_real; - - /** - * The max population capacity - */ - int capacity_max; - - // generated values - - /** - * All the population capacity without the limitation - */ - int capacity_total; - - /** - * All the population capacity with the limitation - */ - int capacity; - -}; - -} // openage diff --git a/libopenage/gamestate/old/resource.cpp b/libopenage/gamestate/old/resource.cpp deleted file mode 100644 index 2c3acdda19..0000000000 --- a/libopenage/gamestate/old/resource.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include -#include -#include - -#include "resource.h" - -namespace openage { - -ResourceBundle Resources::create_bundle() const { - return ResourceBundle(*this); -} - -ResourceBundle::ResourceBundle() - : - ResourceBundle{4} { -} - -ResourceBundle::ResourceBundle(const Resources& resources) - : - ResourceBundle{static_cast(resources.get_count())} { -} - -ResourceBundle::ResourceBundle(const int count) - : - count{count}, - value{new double[count] {0}} { -} - -ResourceBundle::ResourceBundle(const ResourceBundle &resources) - : - ResourceBundle{resources.count} { - this->set(resources); -} - -ResourceBundle ResourceBundle::clone() const { - return ResourceBundle(*this); -} - -ResourceBundle::~ResourceBundle() { - delete[] value; -} - -void ResourceBundle::expand(const ResourceBundle& other) { - this->expand(other.count); -} - -void ResourceBundle::expand(const int count) { - if (this->count == count) { - return; - } - // create new array with old values - auto *new_value = new double[count]; - for (int i = 0; i < this->count; i++) { - new_value[i] = this->value[i]; - } - // replace the private variables - this->count = count; - delete[] value; - this->value = new_value; -} - -bool ResourceBundle::operator> (const ResourceBundle& other) const { - for (int i = 0; i < this->count; i++) { - if (!(this->get(i) > other.get(i))) { - return false; - } - } - // check also resources that are not in both bundles - for (int i = this->count; i < other.count; i++) { - if (other.get(i) > 0) { - return false; - } - } - return true; -} - -bool ResourceBundle::operator>= (const ResourceBundle& other) const { - for (int i = 0; i < this->count; i++) { - if (!(this->get(i) >= other.get(i))) { - return false; - } - } - // check also resources that are not in both bundles - for (int i = this->count; i < other.count; i++) { - if (other.get(i) > 0) { - return false; - } - } - return true; -} - -ResourceBundle& ResourceBundle::operator+= (const ResourceBundle& other) { - this->expand(other); - for (int i = 0; i < this->count; i++) { - (*this)[i] += other.get(i); - } - return *this; -} - -ResourceBundle& ResourceBundle::operator-= (const ResourceBundle& other) { - this->expand(other); - for (int i = 0; i < this->count; i++) { - (*this)[i] -= other.get(i); - } - return *this; -} - -ResourceBundle& ResourceBundle::operator*= (const double a) { - for (int i = 0; i < this->count; i++) { - (*this)[i] *= a; - } - return *this; -} - -ResourceBundle& ResourceBundle::round() { - for (int i = 0; i < this->count; i++) { - (*this)[i] = std::round(this->get(i)); - } - return *this; -} - -bool ResourceBundle::has(const ResourceBundle& amount) const { - return *this >= amount; -} - -bool ResourceBundle::has(const ResourceBundle& amount1, const ResourceBundle& amount2) const { - for (int i = 0; i < this->count; i++) { - if (!(this->get(i) >= amount1.get(i) + amount2.get(i))) { - return false; - } - } - // check also resources that are not in both bundles - for (int i = this->count; i < amount1.count; i++) { - if (amount1.get(i) > 0) { - return false; - } - } - for (int i = this->count; i < amount2.count; i++) { - if (amount2.get(i) > 0) { - return false; - } - } - return true; -} - -bool ResourceBundle::deduct(const ResourceBundle& amount) { - if (this->has(amount)) { - *this -= amount; - return true; - } - return false; -} - -void ResourceBundle::set(const ResourceBundle &amount) { - this->expand(amount); - for (int i = 0; i < this->count; i++) { - (*this)[i] = amount.get(i); - } -} - -void ResourceBundle::set_all(const double amount) { - for (int i = 0; i < this->count; i++) { - (*this)[i] = amount; - } -} - -void ResourceBundle::limit(const ResourceBundle &limits) { - for (int i = 0; i < this->min_count(limits); i++) { - if (this->get(i) > limits.get(i)) { - (*this)[i] = limits.get(i); - } - } -} - -double ResourceBundle::sum() const { - double sum = 0; - for (int i = 0; i < this->count; i++) { - sum += this->get(i); - } - return sum; -} - -int ResourceBundle::min_count(const ResourceBundle &other) { - return this->count <= other.count ? this->count : other.count; -} - -} // openage - -namespace std { - -string to_string(const openage::game_resource &res) { - switch (res) { - case openage::game_resource::wood: - return "wood"; - case openage::game_resource::food: - return "food"; - case openage::game_resource::gold: - return "gold"; - case openage::game_resource::stone: - return "stone"; - default: - return "unknown"; - } -} - -} // namespace std diff --git a/libopenage/gamestate/old/resource.h b/libopenage/gamestate/old/resource.h deleted file mode 100644 index 4a52b5c008..0000000000 --- a/libopenage/gamestate/old/resource.h +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2015-2018 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -namespace openage { - -class ResourceBundle; - -/** - * A resource - */ -class Resource { -public: - - Resource(); - - virtual int id() const = 0; - - virtual std::string name() const = 0; - - // TODO add images and icons - -}; - -class ResourceProducer : public Resource { -public: - - ResourceProducer(int id, std::string name) - : - _id{id}, - _name{name} { } - - int id() const override { return _id; } - - std::string name() const override { return _name; } - -private: - - int _id; - std::string _name; -}; - -/** - * All the resources. - * - * The the ids of the resources must be inside [0, count). - * - * The static variables wood, food, gold, stone are the ids of the representing resource. - * Any extension of Resources must use this ids as they are an engine dependency (at the moment). - */ -class Resources { -public: - - Resources(); - - virtual unsigned int get_count() const = 0; - - virtual const Resource& get_resource(int id) const = 0; - - ResourceBundle create_bundle() const; - - // TODO remove when the engine is fully decupled from the data - static const int wood = 0; - static const int food = 1; - static const int gold = 2; - static const int stone = 3; - -}; - -class ClassicResources : public Resources { -public: - - ClassicResources() - : - resources{{Resources::wood, "wood"}, - {Resources::food, "food"}, - {Resources::gold, "gold"}, - {Resources::stone, "stone"}} { - } - - unsigned int get_count() const override { return 4; } - - const Resource& get_resource(int id) const override { return this->resources[id]; }; - -private: - - const ResourceProducer resources[4]; -}; - -// TODO remove, here for backwards compatibility -enum class game_resource : int { - wood = 0, - food = 1, - gold = 2, - stone = 3, - RESOURCE_TYPE_COUNT = 4 -}; - - -/** - * A set of amounts of game resources. - * - * Can be also used to store other information about the resources. - * - * TODO change amounts from doubles to integers - */ -class ResourceBundle { -public: - - // TODO remove, here for backwards compatibility - ResourceBundle(); - - ResourceBundle(const Resources& resources); - - virtual ~ResourceBundle(); - - ResourceBundle(const ResourceBundle& other); - - ResourceBundle clone() const; - - bool operator> (const ResourceBundle& other) const; - bool operator>= (const ResourceBundle& other) const; - - ResourceBundle& operator+= (const ResourceBundle& other); - ResourceBundle& operator-= (const ResourceBundle& other); - - ResourceBundle& operator*= (const double a); - - /** - * Round each value to the nearest integer. - * Returns itself. - */ - ResourceBundle& round(); - - bool has(const ResourceBundle& amount) const; - - bool has(const ResourceBundle& amount1, const ResourceBundle& amount2) const; - - /** - * If amount can't be deducted return false, else deduct the given amount - * and return true. - */ - bool deduct(const ResourceBundle& amount); - - void set(const ResourceBundle& amount); - - void set_all(const double amount); - - void limit(const ResourceBundle& limits); - - double& operator[] (const game_resource res) { return value[static_cast(res)]; } - double& operator[] (const int id) { return value[id]; } - - // Getters - - double get(const game_resource res) const { return value[static_cast(res)]; } - double get(const int id) const { return value[id]; } - - /** - * Returns the sum of all the resources. - */ - double sum() const; - - /** - * The number of resources - */ - int get_count() const { return count; }; - -private: - - ResourceBundle(const int count); - - void expand(const ResourceBundle& other); - - void expand(const int count); - - /** - * The number of resources - */ - int count; - - double *value; - - int min_count(const ResourceBundle& other); - -}; - -} // namespace openage - -namespace std { - -std::string to_string(const openage::game_resource &res); - -/** - * hasher for game resource - */ -template<> struct hash { - typedef underlying_type::type underlying_type; - - size_t operator()(const openage::game_resource &arg) const { - hash hasher; - return hasher(static_cast(arg)); - } -}; - -} // namespace std diff --git a/libopenage/gamestate/old/score.cpp b/libopenage/gamestate/old/score.cpp deleted file mode 100644 index 9d26d9c9f0..0000000000 --- a/libopenage/gamestate/old/score.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2017-2021 the openage authors. See copying.md for legal info. - -#include - -#include "player.h" -#include "score.h" -#include "team.h" -#include "../../log/log.h" - -namespace openage { - -Score::Score() - : - score{0}, - score_total{0}, - score_exploration{0}, - score_resources{0} { -} - -void Score::add_score(const score_category cat, double value) { - this->add_score(cat, static_cast(std::lround(value))); -} - -void Score::add_score(const score_category cat, int value) { - this->score[static_cast(cat)] += value; - this->update_score(); -} - -void Score::remove_score(const score_category cat, double value) { - this->remove_score(cat, static_cast(std::lround(value))); -} - -void Score::remove_score(const score_category cat, int value) { - this->score[static_cast(cat)] -= value; - this->update_score(); -} - -void Score::update_map_explored(double progress) { - this->remove_score(score_category::technology, this->score_exploration); - this->score_exploration = progress * 1000; - this->add_score(score_category::technology, this->score_exploration); -} - -void Score::update_resources(const ResourceBundle & resources) { - this->remove_score(score_category::economy, this->score_resources); - this->score_resources = resources.sum() * 0.1; - this->add_score(score_category::economy, this->score_resources); -} - -void Score::update_score() { - this->score_total = 0; - for (int i = 0; i < static_cast(score_category::SCORE_CATEGORY_COUNT); i++) { - this->score_total += this->get_score(i); - } -} - -PlayerScore::PlayerScore(Player *player) - : - Score(), - player{player} { -} - -void PlayerScore::update_score() { - Score::update_score(); - // update team score - if (this->player->team) { - this->player->team->score.update_score(); - } -} - -TeamScore::TeamScore(Team *team) - : - Score(), - team{team} { -} - -void TeamScore::update_score() { - // scores are the corresponding sums of players score - for (int i = 0; i < static_cast(score_category::SCORE_CATEGORY_COUNT); i++) { - this->score[i] = 0; - } - for (auto player : this->team->get_players()) { - for (int i = 0; i < static_cast(score_category::SCORE_CATEGORY_COUNT); i++) { - this->score[i] += player->score.get_score(i); - } - } - Score::update_score(); -} - -} // openage - -namespace std { - -string to_string(const openage::score_category &cat) { - switch (cat) { - case openage::score_category::military: - return "military"; - case openage::score_category::economy: - return "economy"; - case openage::score_category::technology: - return "technology"; - case openage::score_category::society: - return "society"; - default: - return "unknown"; - } -} - -} // namespace std diff --git a/libopenage/gamestate/old/score.h b/libopenage/gamestate/old/score.h deleted file mode 100644 index 2a8c762290..0000000000 --- a/libopenage/gamestate/old/score.h +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2017-2018 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "resource.h" - - -namespace openage { - -class Player; -class Team; - -/** - * The categories of sub-scores that sum to a player's score. - */ -enum class score_category : int { - /** 20% of units killed cost */ - military, - /** 20% of alive units cost and 10% of resources */ - economy, - /** 20% of researched technologies and 10 for each 1% of map explored*/ - technology, - /** 20% of Castles and Wonders cost */ - society, - SCORE_CATEGORY_COUNT -}; - -/** - * Keeps track of a score and all the sub-scores - */ -class Score { -public: - - Score(); - - void add_score(const score_category cat, double value); - void add_score(const score_category cat, int value); - - void remove_score(const score_category cat, double value); - void remove_score(const score_category cat, int value); - - /** - * Updates map exploration precentance based sub-scores - */ - void update_map_explored(double progress); - - /** - * Updates resource based sub-scores - */ - void update_resources(const ResourceBundle & resources); - - /** - * Calculates the total score from the sub-scores. - * TODO update gui here - */ - virtual void update_score(); - - // Getters - - int get_score(const score_category cat) const { return score[static_cast(cat)]; } - int get_score(const int index) const { return score[index]; } - - int get_score_total() const { return score_total; } - -protected: - - int score[static_cast(score_category::SCORE_CATEGORY_COUNT)]; - - // generated values - - int score_total; - -private: - - /** Used by update_map_explored. */ - int score_exploration; - - /** Used by update_resources. */ - int score_resources; -}; - - -/** - * The score of a player - */ -class PlayerScore : public Score { -public: - - PlayerScore(Player *player); - - virtual void update_score() override; - -protected: - -private: - - Player *player; -}; - - -/** - * The score of a team - */ -class TeamScore : public Score { -public: - - TeamScore(Team *team); - - virtual void update_score() override; - -protected: - -private: - - Team *team; -}; - -} // namespace openage - -namespace std { - -std::string to_string(const openage::score_category &cat); - -/** - * hasher for score_category - * TODO decide if needed, not used at the moment - */ -template<> -struct hash { - typedef underlying_type::type underlying_type; - - size_t operator()(const openage::score_category &arg) const { - hash hasher; - return hasher(static_cast(arg)); - } -}; - -} // namespace std diff --git a/libopenage/gamestate/old/team.cpp b/libopenage/gamestate/old/team.cpp deleted file mode 100644 index 92e556437f..0000000000 --- a/libopenage/gamestate/old/team.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016-2021 the openage authors. See copying.md for legal info. - -#include "team.h" - -#include "player.h" -#include "score.h" -#include - - -namespace openage { - -Team::Team(unsigned int id) - : - Team{id, "Anonymous Team", nullptr} {} - -Team::Team(unsigned int id, std::string name) - : - Team{id, std::move(name), nullptr} {} - -Team::Team(unsigned int id, std::string name, Player *leader) - : - id{id}, - name{std::move(name)}, - score{this} { - - if (leader) { - this->add_member(*leader, member_type::leader); - } -} - -bool Team::operator ==(const Team &other) const { - return this->id == other.id; -} - -void Team::add_member(Player &player, const member_type type) { - // if already exists, replace member type - this->members[&player] = type; - // change player team pointer - player.team = this; -} - -void Team::change_member_type(Player &player, const member_type type) { - auto p = this->members.find(&player); - if (p != this->members.end()) { - this->members[&player] = type; - } -} - -bool Team::is_member(const Player &player) const { - auto p = this->members.find(&player); - return (p != this->members.end()); -} - -void Team::remove_member(Player &player) { - this->members.erase(&player); - // change player team pointer - player.team = nullptr; -} - -member_type Team::get_member_type(Player &player) { - auto p = this->members.find(&player); - if (p != this->members.end()) { - return this->members[&player]; - } - // return pseudo member type for completion - return member_type::none; -} - -std::vector Team::get_players() const { - std::vector players; - for (auto& i : members) { - players.push_back(i.first); - } - return players; -} - -} // openage diff --git a/libopenage/gamestate/old/team.h b/libopenage/gamestate/old/team.h deleted file mode 100644 index 657909df9e..0000000000 --- a/libopenage/gamestate/old/team.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2016-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - - -#include "score.h" - - -namespace openage { - -class Player; - -/** - * Types of membership - */ -enum class member_type { - leader, - member, - recruit, - none // pseudo type -}; - -/** - * A team of players - */ -class Team { -public: - Team(unsigned int id); - Team(unsigned int id, std::string name); - Team(unsigned int id, std::string name, Player *leader); - - /** - * unique id of the team - */ - const unsigned int id; - - /** - * visible name of this team - */ - const std::string name; - - bool operator ==(const Team &other) const; - - - void add_member(Player &player, const member_type type); - - void change_member_type(Player &player, const member_type type); - - bool is_member(const Player &player) const; - - void remove_member(Player &player); - - member_type get_member_type(Player &player); - - /** - * TODO find a better way to get all the players - */ - std::vector get_players() const; - - /** - * The score of the team, based on the team's players score. - */ - TeamScore score; - -private: - - std::unordered_map members; - -}; - -} // openage diff --git a/libopenage/gamestate/old/types.cpp b/libopenage/gamestate/old/types.cpp deleted file mode 100644 index ca80997a97..0000000000 --- a/libopenage/gamestate/old/types.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2018-2023 the openage authors. See copying.md for legal info. - -#include "types.h" - - -namespace openage { - -} // openage diff --git a/libopenage/gamestate/old/types.h b/libopenage/gamestate/old/types.h deleted file mode 100644 index 805cd63627..0000000000 --- a/libopenage/gamestate/old/types.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018-2023 the openage authors. See copying.md for legal info. - -#pragma once - - -namespace openage { - -/** - * The key type mapped to data objects. - * Used for graphics indices, sounds, ... - * TODO: get rid of this. - */ -using index_t = int; - - -} // openage diff --git a/libopenage/gamestate/player.cpp b/libopenage/gamestate/player.cpp index e57c4d8a35..cb7aeed3ea 100644 --- a/libopenage/gamestate/player.cpp +++ b/libopenage/gamestate/player.cpp @@ -13,6 +13,13 @@ Player::Player(player_id_t id, db_view{db_view} { } +std::shared_ptr Player::copy(entity_id_t id) { + auto copy = std::shared_ptr(new Player(*this)); + copy->set_id(id); + + return copy; +} + player_id_t Player::get_id() const { return this->id; } @@ -21,4 +28,8 @@ const std::shared_ptr &Player::get_db_view() const { return this->db_view; } +void Player::set_id(entity_id_t id) { + this->id = id; +} + } // namespace openage::gamestate diff --git a/libopenage/gamestate/player.h b/libopenage/gamestate/player.h index db6c53b128..a7eb5bac4d 100644 --- a/libopenage/gamestate/player.h +++ b/libopenage/gamestate/player.h @@ -27,15 +27,20 @@ class Player { Player(player_id_t id, const std::shared_ptr &db_view); - // players can't be copied to prevent duplicate IDs - Player(const Player &) = delete; Player(Player &&) = default; - - Player &operator=(const Player &) = delete; Player &operator=(Player &&) = default; ~Player() = default; + /** + * Copy this player. + * + * @param id Unique identifier. + * + * @return Copy of this player. + */ + std::shared_ptr copy(entity_id_t id); + /** * Get the unique ID of the player. * @@ -50,11 +55,29 @@ class Player { */ const std::shared_ptr &get_db_view() const; +protected: + /** + * A player cannot be default copied because of their unique ID. + * + * \p copy() must be used instead. + */ + Player(const Player &) = default; + Player &operator=(const Player &) = default; + private: + /** + * Set the unique identifier of this player. + * + * Only called by \p copy(). + * + * @param id New ID. + */ + void set_id(entity_id_t id); + /** * Player ID. Must be unique. */ - const player_id_t id; + player_id_t id; /** * Player view of the nyan game data database. diff --git a/libopenage/gamestate/simulation.cpp b/libopenage/gamestate/simulation.cpp index c925888815..4af77d2815 100644 --- a/libopenage/gamestate/simulation.cpp +++ b/libopenage/gamestate/simulation.cpp @@ -9,6 +9,7 @@ #include "gamestate/event/send_command.h" #include "gamestate/event/spawn_entity.h" #include "gamestate/event/wait.h" +#include "gamestate/terrain_factory.h" #include "time/clock.h" #include "time/time_loop.h" @@ -27,6 +28,7 @@ GameSimulation::GameSimulation(const util::Path &root_dir, time_loop{time_loop}, event_loop{std::make_shared()}, entity_factory{std::make_shared()}, + terrain_factory{std::make_shared()}, mod_manager{std::make_shared(this->root_dir / "assets" / "converted")}, spawner{std::make_shared(this->event_loop)}, commander{std::make_shared(this->event_loop)} { @@ -54,9 +56,11 @@ void GameSimulation::start() { this->init_event_handlers(); + // TODO: wait for presenter to initialize before starting? this->game = std::make_shared(event_loop, this->mod_manager, - this->entity_factory); + this->entity_factory, + this->terrain_factory); this->running = true; @@ -114,6 +118,7 @@ void GameSimulation::attach_renderer(const std::shared_ptrgame->attach_renderer(render_factory); this->entity_factory->attach_renderer(render_factory); + this->terrain_factory->attach_renderer(render_factory); } void GameSimulation::set_modpacks(const std::vector &modpacks) { diff --git a/libopenage/gamestate/simulation.h b/libopenage/gamestate/simulation.h index aab81c524e..fe2de8257c 100644 --- a/libopenage/gamestate/simulation.h +++ b/libopenage/gamestate/simulation.h @@ -31,6 +31,7 @@ class TimeLoop; namespace gamestate { class EntityFactory; class Game; +class TerrainFactory; namespace event { class Commander; @@ -178,6 +179,11 @@ class GameSimulation final { */ std::shared_ptr entity_factory; + /** + * Factory for creating terrain. + */ + std::shared_ptr terrain_factory; + /** * Mod manager. */ diff --git a/libopenage/gamestate/terrain.cpp b/libopenage/gamestate/terrain.cpp index 247b457251..f31fc648b8 100644 --- a/libopenage/gamestate/terrain.cpp +++ b/libopenage/gamestate/terrain.cpp @@ -6,37 +6,34 @@ #include #include -#include "renderer/stages/terrain/terrain_render_entity.h" +#include "gamestate/terrain_chunk.h" +#include "renderer/render_factory.h" + namespace openage::gamestate { -Terrain::Terrain(const std::string &texture_path) : +Terrain::Terrain() : size{0, 0}, - height_map{}, - texture_path{texture_path}, - render_entity{nullptr} { - // TODO: Actual terrain generation code - this->size = util::Vector2s{10, 10}; - - // fill the terrain grid with height values - this->height_map.reserve(this->size[0] * this->size[1]); - for (size_t i = 0; i < this->size[0] * this->size[1]; ++i) { - this->height_map.push_back(0.0f); - } + chunks{} { + // TODO: Get actual size of terrain. } -void Terrain::push_to_render() { - if (this->render_entity != nullptr) { - this->render_entity->update(this->size, - this->height_map, - this->texture_path); - } +void Terrain::add_chunk(const std::shared_ptr &chunk) { + this->chunks.push_back(chunk); } -void Terrain::set_render_entity(const std::shared_ptr &entity) { - this->render_entity = entity; +const std::vector> &Terrain::get_chunks() const { + return this->chunks; +} + +void Terrain::attach_renderer(const std::shared_ptr &render_factory) { + for (auto &chunk : this->get_chunks()) { + auto render_entity = render_factory->add_terrain_render_entity(chunk->get_size(), + chunk->get_offset()); + chunk->set_render_entity(render_entity); - this->push_to_render(); + chunk->render_update(time::time_t::zero()); + } } } // namespace openage::gamestate diff --git a/libopenage/gamestate/terrain.h b/libopenage/gamestate/terrain.h index 1e1aef9846..c84b926d9a 100644 --- a/libopenage/gamestate/terrain.h +++ b/libopenage/gamestate/terrain.h @@ -9,42 +9,63 @@ #include "util/vector.h" namespace openage { -namespace renderer::terrain { -class TerrainRenderEntity; -} +namespace renderer { +class RenderFactory; +} // namespace renderer namespace gamestate { +class TerrainChunk; /** * Entity for managing the map terrain of a game. */ class Terrain { public: - Terrain(const std::string &texture_path); + /** + * Create a new terrain. + */ + Terrain(); ~Terrain() = default; /** - * Set the current render entity of the terrain. + * Add a chunk to the terrain. + * + * @param chunk New chunk. + */ + void add_chunk(const std::shared_ptr &chunk); + + /** + * Get the chunks of the terrain. + * + * @return Terrain chunks. + */ + const std::vector> &get_chunks() const; + + /** + * Attach a renderer which enables graphical display. * - * @param entity New render entity. + * TODO: We currently have to do attach this here too in addition to the terrain + * factory because the renderer gets attached AFTER the terrain is + * already created. In the future, the game should wait for the renderer + * before creating the terrain. + * + * @param render_factory Factory for creating connector objects for gamestate->renderer + * communication. */ - void set_render_entity(const std::shared_ptr &entity); + void attach_renderer(const std::shared_ptr &render_factory); private: - // test connection to renderer - void push_to_render(); - - // size of the map - // origin is the left corner - // x = top left edge; y = top right edge + /** + * Total size of the map + * origin is the left corner + * x = top left edge; y = top right edge + */ util::Vector2s size; - // Heights of the terrain grid - std::vector height_map; - // path to a texture - std::string texture_path; - // render entity for pushing updates to - std::shared_ptr render_entity; + /** + * Subdivision of the main terrain entity. + */ + std::vector> chunks; }; } // namespace gamestate diff --git a/libopenage/gamestate/terrain_chunk.cpp b/libopenage/gamestate/terrain_chunk.cpp index d434a7a921..9fc5422b65 100644 --- a/libopenage/gamestate/terrain_chunk.cpp +++ b/libopenage/gamestate/terrain_chunk.cpp @@ -1,8 +1,68 @@ -// Copyright 2018-2018 the openage authors. See copying.md for legal info. +// Copyright 2018-2023 the openage authors. See copying.md for legal info. #include "terrain_chunk.h" namespace openage::gamestate { -} // openage::gamestate +TerrainChunk::TerrainChunk(const util::Vector2s size, + const coord::tile_delta offset, + const std::vector &&tiles) : + size{size}, + offset{offset}, + tiles{std::move(tiles)} { + if (this->size[0] > MAX_CHUNK_WIDTH || this->size[1] > MAX_CHUNK_HEIGHT) { + throw Error(MSG(err) << "Terrain chunk size exceeds maximum size: " + << this->size[0] << "x" << this->size[1] << " > " + << MAX_CHUNK_WIDTH << "x" << MAX_CHUNK_HEIGHT); + } +} + +void TerrainChunk::set_render_entity(const std::shared_ptr &entity) { + this->render_entity = entity; +} + +void TerrainChunk::render_update(const time::time_t &time, + const std::string &terrain_path) { + if (this->render_entity != nullptr) { + // TODO: Update individual tiles instead of the whole chunk + std::vector> tiles; + tiles.reserve(this->tiles.size()); + for (const auto &tile : this->tiles) { + tiles.emplace_back(tile.elevation, terrain_path); + } + + this->render_entity->update(this->size, + tiles, + time); + } +} + +const util::Vector2s &TerrainChunk::get_size() const { + return this->size; +} + +const coord::tile_delta &TerrainChunk::get_offset() const { + return this->offset; +} + +void TerrainChunk::set_terrain_path(const std::string &terrain_path) { + this->terrain_path = terrain_path; +} + +void TerrainChunk::render_update(const time::time_t &time) { + if (this->render_entity != nullptr) { + // TODO: Update individual tiles instead of the whole chunk + std::vector> tiles; + tiles.reserve(this->tiles.size()); + for (const auto &tile : this->tiles) { + tiles.emplace_back(tile.elevation, terrain_path); + } + + this->render_entity->update(this->size, + tiles, + time); + } +} + +} // namespace openage::gamestate diff --git a/libopenage/gamestate/terrain_chunk.h b/libopenage/gamestate/terrain_chunk.h index 784aec7c9e..df9091a321 100644 --- a/libopenage/gamestate/terrain_chunk.h +++ b/libopenage/gamestate/terrain_chunk.h @@ -2,13 +2,96 @@ #pragma once +#include + +#include "coord/tile.h" +#include "gamestate/terrain_tile.h" +#include "renderer/stages/terrain/terrain_render_entity.h" +#include "time/time.h" +#include "util/vector.h" + namespace openage::gamestate { +const size_t MAX_CHUNK_WIDTH = 16; +const size_t MAX_CHUNK_HEIGHT = 16; + + /** * Subdivision of the main terrain entity. */ class TerrainChunk { +public: + TerrainChunk(const util::Vector2s size, + const coord::tile_delta offset, + const std::vector &&tiles); + ~TerrainChunk() = default; + + /** + * Set the current render entity of the terrain. + * + * @param entity New render entity. + */ + void set_render_entity(const std::shared_ptr &entity); + + /** + * Update the render entity. + * + * @param time Simulation time of the update. + * @param terrain_path Path to the terrain definition used at \p time. + */ + void render_update(const time::time_t &time, + const std::string &terrain_path); + + /** + * Get the size of this terrain chunk. + * + * @return Size of the terrain chunk (in tiles). + */ + const util::Vector2s &get_size() const; + + /** + * Get the offset of this terrain chunk to the terrain origin. + * + * @return Offset of the terrain chunk (in tiles). + */ + const coord::tile_delta &get_offset() const; + + // TODO: Remove test texture references + + // Set the terrain path of this terrain chunk. + // TODO: Remove later + void set_terrain_path(const std::string &terrain_path); + + // Send the current texture to the renderer. + // TODO: Replace later with render_update(time, terrain_path) + void render_update(const time::time_t &time); + +private: + /** + * Size of the terrain chunk. + * Origin is the left corner. + * x = top left edge; y = top right edge. + */ + util::Vector2s size; + + /** + * Offset of the terrain chunk to the origin. + */ + coord::tile_delta offset; + + /** + * Height map of the terrain chunk. + */ + std::vector tiles; + + /** + * Render entity for pushing updates to the renderer. Can be \p nullptr. + */ + std::shared_ptr render_entity; + + // TODO: Remove test texture references + std::string terrain_path; }; } // namespace openage::gamestate diff --git a/libopenage/gamestate/terrain_factory.cpp b/libopenage/gamestate/terrain_factory.cpp new file mode 100644 index 0000000000..3a46773429 --- /dev/null +++ b/libopenage/gamestate/terrain_factory.cpp @@ -0,0 +1,149 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#include "terrain_factory.h" + +#include + +#include + +#include "gamestate/api/terrain.h" +#include "gamestate/terrain.h" +#include "gamestate/terrain_chunk.h" +#include "gamestate/terrain_tile.h" +#include "renderer/render_factory.h" +#include "renderer/stages/terrain/terrain_render_entity.h" +#include "time/time.h" + +#include "assets/mod_manager.h" +#include "gamestate/game_state.h" + + +namespace openage::gamestate { + +static const std::vector aoe1_test_terrain = {}; +static const std::vector de1_test_terrain = {}; +static const std::vector aoe2_test_terrain = { + "aoe2_base.data.terrain.foundation.foundation.Foundation", + "aoe2_base.data.terrain.grass.grass.Grass", + "aoe2_base.data.terrain.dirt.dirt.Dirt", +}; +static const std::vector de2_test_terrain = {}; +static const std::vector hd_test_terrain = { + "hd_base.data.terrain.foundation.foundation.Foundation", + "hd_base.data.terrain.grass.grass.Grass", + "hd_base.data.terrain.dirt.dirt.Dirt", +}; +static const std::vector swgb_test_terrain = { + "swgb_base.data.terrain.desert0.desert0.Desert0", + "swgb_base.data.terrain.grass2.grass2.Grass2", + "swgb_base.data.terrain.foundation.foundation.Foundation", +}; +static const std::vector trial_test_terrain = {}; + +std::shared_ptr TerrainFactory::add_terrain() { + // TODO: Replace this with a proper terrain generator. + auto terrain = std::make_shared(); + + return terrain; +} + +// TODO: Remove hardcoded test texture references +static std::vector test_terrains; // declare static so we only have to do this once + +void build_test_terrains(const std::shared_ptr &gstate) { + auto modpack_ids = gstate->get_mod_manager()->get_load_order(); + for (auto &modpack_id : modpack_ids) { + if (modpack_id == "aoe1_base") { + test_terrains.insert(test_terrains.end(), + aoe1_test_terrain.begin(), + aoe1_test_terrain.end()); + } + else if (modpack_id == "de1_base") { + test_terrains.insert(test_terrains.end(), + de1_test_terrain.begin(), + de1_test_terrain.end()); + } + else if (modpack_id == "aoe2_base") { + test_terrains.insert(test_terrains.end(), + aoe2_test_terrain.begin(), + aoe2_test_terrain.end()); + } + else if (modpack_id == "de2_base") { + test_terrains.insert(test_terrains.end(), + de2_test_terrain.begin(), + de2_test_terrain.end()); + } + else if (modpack_id == "hd_base") { + test_terrains.insert(test_terrains.end(), + hd_test_terrain.begin(), + hd_test_terrain.end()); + } + else if (modpack_id == "swgb_base") { + test_terrains.insert(test_terrains.end(), + swgb_test_terrain.begin(), + swgb_test_terrain.end()); + } + else if (modpack_id == "trial_base") { + test_terrains.insert(test_terrains.end(), + trial_test_terrain.begin(), + trial_test_terrain.end()); + } + } +} + + +std::shared_ptr TerrainFactory::add_chunk(const std::shared_ptr &gstate, + const util::Vector2s size, + const coord::tile_delta offset) { + // TODO: Remove test texture references + std::string test_texture_path = "../test/textures/test_terrain.terrain"; + + // TODO: Remove test texture references + // ========== + std::optional terrain_obj; + if (test_terrains.empty()) { + build_test_terrains(gstate); + } + + static size_t test_terrain_index = 0; + if (not test_terrains.empty()) { + // use one of the modpack terrain textures + if (test_terrain_index >= test_terrains.size()) { + test_terrain_index = 0; + } + terrain_obj = gstate->get_db_view()->get_object(test_terrains[test_terrain_index]); + test_texture_path = api::APITerrain::get_terrain_path(terrain_obj.value()); + + test_terrain_index += 1; + } + // ========== + + // fill the chunk with tiles + std::vector tiles{}; + tiles.reserve(size[0] * size[1]); + for (size_t i = 0; i < size[0] * size[1]; ++i) { + tiles.push_back({terrain_obj, test_texture_path, terrain_elevation_t::zero()}); + } + + auto chunk = std::make_shared(size, offset, std::move(tiles)); + + if (this->render_factory) { + auto render_entity = this->render_factory->add_terrain_render_entity(size, offset); + chunk->set_render_entity(render_entity); + + chunk->render_update(time::time_t::zero(), + test_texture_path); + } + + chunk->set_terrain_path(test_texture_path); + + return chunk; +} + +void TerrainFactory::attach_renderer(const std::shared_ptr &render_factory) { + std::unique_lock lock{this->mutex}; + + this->render_factory = render_factory; +} + +} // namespace openage::gamestate diff --git a/libopenage/gamestate/terrain_factory.h b/libopenage/gamestate/terrain_factory.h new file mode 100644 index 0000000000..32f804257f --- /dev/null +++ b/libopenage/gamestate/terrain_factory.h @@ -0,0 +1,81 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include + +#include "coord/tile.h" +#include "util/vector.h" + + +namespace openage { + +namespace renderer { +class RenderFactory; +} + +namespace gamestate { +class GameState; +class Terrain; +class TerrainChunk; + +/** + * Creates terrain data (tiles, chunks, etc.) to generate a map. + */ +class TerrainFactory { +public: + /** + * Create a new terrain factory. + */ + TerrainFactory() = default; + ~TerrainFactory() = default; + + /** + * Create a new empty terrain object. + * + * @return New terrain object. + */ + std::shared_ptr add_terrain(); + + /** + * Create a new empty terrain chunk. + * + * @param size Size of the chunk. + * @param offset Offset of the chunk. + * + * @return New terrain chunk. + */ + std::shared_ptr add_chunk(const std::shared_ptr &gstate, + const util::Vector2s size, + const coord::tile_delta offset); + + // TODO: Add tiles + // std::shared_ptr add_tile(const std::shared_ptr &loop, + // const std::shared_ptr &state, + // const nyan::fqon_t &nyan_entity); + + /** + * Attach a render factory for graphical display. + * + * This enables rendering for all created terrain chunks. + * + * @param render_factory Factory for creating connector objects for gamestate->renderer + * communication. + */ + void attach_renderer(const std::shared_ptr &render_factory); + +private: + /** + * Factory for creating connector objects to the renderer which make game entities displayable. + */ + std::shared_ptr render_factory; + + /** + * Mutex for thread safety. + */ + std::shared_mutex mutex; +}; + +} // namespace gamestate +} // namespace openage diff --git a/libopenage/gamestate/terrain_tile.cpp b/libopenage/gamestate/terrain_tile.cpp new file mode 100644 index 0000000000..0fcb157d06 --- /dev/null +++ b/libopenage/gamestate/terrain_tile.cpp @@ -0,0 +1,10 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#include "terrain_tile.h" + + +namespace openage::gamestate { + +// This file is intentionally empty. + +} // namespace openage::gamestate diff --git a/libopenage/gamestate/terrain_tile.h b/libopenage/gamestate/terrain_tile.h new file mode 100644 index 0000000000..e2a046bb07 --- /dev/null +++ b/libopenage/gamestate/terrain_tile.h @@ -0,0 +1,41 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include + +#include + +#include "util/fixed_point.h" + + +namespace openage::gamestate { + +using terrain_elevation_t = util::FixedPoint; + +/** + * A single terrain tile. + */ +struct TerrainTile { + /** + * Terrain definition used by this tile. + * + * TODO: Make this non-optional once all modpacks support terrain graphics. + */ + std::optional terrain; + + /** + * Path to the terrain asset used by this tile. + * + * TODO: Remove this and fetch the asset path from the terrain definition. + */ + std::string terrain_asset_path; + + /** + * Height of this tile on the terrain. + */ + terrain_elevation_t elevation; +}; + +} // namespace openage::gamestate diff --git a/libopenage/gamestate/universe.cpp b/libopenage/gamestate/universe.cpp index 6299296734..cf44782e7d 100644 --- a/libopenage/gamestate/universe.cpp +++ b/libopenage/gamestate/universe.cpp @@ -10,9 +10,6 @@ namespace openage::gamestate { Universe::Universe(const std::shared_ptr &state) : world{std::make_shared(state)} { - // TODO - auto texpath = "../test/textures/test_terrain.terrain"; - this->terrain = std::make_shared(texpath); } std::shared_ptr Universe::get_world() { @@ -26,10 +23,6 @@ std::shared_ptr Universe::get_terrain() { void Universe::attach_renderer(const std::shared_ptr &render_factory) { this->render_factory = render_factory; - // TODO: Notify entities somwhere else? - auto terrain_render_entity = this->render_factory->add_terrain_render_entity(); - this->terrain->set_render_entity(terrain_render_entity); - this->world->attach_renderer(render_factory); } diff --git a/libopenage/gamestate/universe.h b/libopenage/gamestate/universe.h index ed77f84095..7e33a83765 100644 --- a/libopenage/gamestate/universe.h +++ b/libopenage/gamestate/universe.h @@ -18,6 +18,8 @@ class World; /** * Entity for managing the "physical" game world entities (units, buildings, etc.) as well as * conceptual entities (players, resources, ...). + * + * TODO: Remove Universe and other subclasses. */ class Universe { public: diff --git a/libopenage/gui/CMakeLists.txt b/libopenage/gui/CMakeLists.txt deleted file mode 100644 index e63046c401..0000000000 --- a/libopenage/gui/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -add_sources(libopenage - assetmanager_link.cpp - actions_list_model.cpp - category_contents_list_model.cpp - engine_info.cpp - engine_link.cpp - game_control_link.cpp - game_creator.cpp - game_main_link.cpp - game_saver.cpp - game_spec_link.cpp - generator_link.cpp - gui.cpp - main_args_link.cpp - registrations.cpp - resources_list_model.cpp -) - -add_subdirectory("guisys") - -add_sources(libopenage - ${QT_SDL_SOURCES} -) - -add_subdirectory("integration") diff --git a/libopenage/gui/actions_list_model.cpp b/libopenage/gui/actions_list_model.cpp deleted file mode 100644 index 67f2d2780f..0000000000 --- a/libopenage/gui/actions_list_model.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2016-2019 the openage authors. See copying.md for legal info. - -#include "actions_list_model.h" - -#include "../log/log.h" -#include "game_control_link.h" - -#include -#include - -namespace openage { -namespace gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "ActionsListModel"); -} - -ActionsListModel::ActionsListModel(QObject *parent) - : - QAbstractListModel{parent}, - action_mode{} { - Q_UNUSED(registration); -} - -ActionsListModel::~ActionsListModel() = default; - -ActionButtonsType ActionsListModel::get_active_buttons() const { - return this->active_buttons; -} - -void ActionsListModel::set_active_buttons(const ActionButtonsType &active_buttons) { - if (this->active_buttons == active_buttons) { - return; - } - this->active_buttons = active_buttons; - - switch (active_buttons) { - case ActionButtonsType::None: - this->clear_buttons(); - break; - - case ActionButtonsType::MilitaryUnits: - this->clear_buttons(); - this->set_icons_source("image://by-filename/converted/interface/hudactions.slp.png"); - this->beginResetModel(); - this->add_button(6, -1, static_cast(GroupIDs::NoGroup), "SET_ABILITY_PATROL"); - this->add_button(7, -1, static_cast(GroupIDs::NoGroup), "SET_ABILITY_GUARD"); - this->add_button(8, -1, static_cast(GroupIDs::NoGroup), "SET_ABILITY_FOLLOW"); - this->add_button(59, -1, static_cast(GroupIDs::NoGroup), "KILL_UNIT"); - this->add_button(2, -1, static_cast(GroupIDs::NoGroup), "SET_ABILITY_GARRISON"); - - this->add_button(9, 53, static_cast(GroupIDs::StanceGroup), "AGGRESSIVE_STANCE"); - this->add_button(10, 52, static_cast(GroupIDs::StanceGroup), "DEFENSIVE_STANCE"); - this->add_button(11, 51, static_cast(GroupIDs::StanceGroup), "HOLD_STANCE"); - this->add_button(50, 54, static_cast(GroupIDs::StanceGroup), "PASSIVE_STANCE"); - this->add_button(3, -1, static_cast(GroupIDs::NoGroup), "STOP"); - this->endResetModel(); - break; - - case ActionButtonsType::CivilianUnits: - this->clear_buttons(); - this->set_icons_source("image://by-filename/converted/interface/hudactions.slp.png"); - this->beginResetModel(); - this->add_button(30, -1, static_cast(GroupIDs::NoGroup), "BUILD_MENU"); - this->add_button(31, -1, static_cast(GroupIDs::NoGroup), "BUILD_MENU_MIL"); - this->add_button(28, -1, static_cast(GroupIDs::NoGroup), "SET_ABILITY_REPAIR"); - this->add_button(59, -1, static_cast(GroupIDs::NoGroup), "KILL_UNIT"); - this->add_button(2, -1, static_cast(GroupIDs::NoGroup), "SET_ABILITY_GARRISON"); - - this->add_button(-1, -1, static_cast(GroupIDs::NoGroup), ""); - this->add_button(-1, -1, static_cast(GroupIDs::NoGroup), ""); - this->add_button(-1, -1, static_cast(GroupIDs::NoGroup), ""); - this->add_button(-1, -1, static_cast(GroupIDs::NoGroup), ""); - this->add_button(3, -1, static_cast(GroupIDs::NoGroup), "STOP"); - this->endResetModel(); - break; - - case ActionButtonsType::BuildMenu: - this->clear_buttons(); - this->set_icons_source("image://by-filename/converted/interface/50705.slp.png"); - this->beginResetModel(); - this->add_button(34, -1, static_cast(GroupIDs::NoGroup), "BUILDING_HOUS"); - this->add_button(20, -1, static_cast(GroupIDs::NoGroup), "BUILDING_MILL"); - this->add_button(39, -1, static_cast(GroupIDs::NoGroup), "BUILDING_MINE"); - this->add_button(40, -1, static_cast(GroupIDs::NoGroup), "BUILDING_SMIL"); - this->add_button(13, -1, static_cast(GroupIDs::NoGroup), "BUILDING_DOCK"); - this->add_button(35, -1, static_cast(GroupIDs::NoGroup), "BUILDING_FARM"); - this->add_button(4, -1, static_cast(GroupIDs::NoGroup), "BUILDING_BLAC"); - this->add_button(16, -1, static_cast(GroupIDs::NoGroup), "BUILDING_MRKT"); - this->add_button(10, -1, static_cast(GroupIDs::NoGroup), "BUILDING_CRCH"); - this->add_button(32, -1, static_cast(GroupIDs::NoGroup), "BUILDING_UNIV"); - this->add_button(28, -1, static_cast(GroupIDs::NoGroup), "BUILDING_RTWC"); - this->add_button(37, -1, static_cast(GroupIDs::NoGroup), "BUILDING_WNDR"); - // the go back button is not in this slp (is in hudactions.slp.png) - this->endResetModel(); - break; - - case ActionButtonsType::MilBuildMenu: - this->clear_buttons(); - this->set_icons_source("image://by-filename/converted/interface/50705.slp.png"); - this->beginResetModel(); - this->add_button(2, -1, static_cast(GroupIDs::NoGroup), "BUILDING_BRKS"); - this->add_button(0, -1, static_cast(GroupIDs::NoGroup), "BUILDING_ARRG"); - this->add_button(23, -1, static_cast(GroupIDs::NoGroup), "BUILDING_STBL"); - this->add_button(22, -1, static_cast(GroupIDs::NoGroup), "BUILDING_SIWS"); - this->add_button(38, -1, static_cast(GroupIDs::NoGroup), "BUILDING_WCTWX"); - this->add_button(30, -1, static_cast(GroupIDs::NoGroup), "BUILDING_WALL"); - this->add_button(29, -1, static_cast(GroupIDs::NoGroup), "BUILDING_WALL2"); - this->add_button(25, -1, static_cast(GroupIDs::NoGroup), "BUILDING_WCTW"); - this->add_button(42, -1, static_cast(GroupIDs::NoGroup), "BUILDING_WCTW4"); - this->add_button(36, -1, static_cast(GroupIDs::NoGroup), "BUILDING_GTCA2"); - this->add_button(7, -1, static_cast(GroupIDs::NoGroup), "BUILDING_CSTL"); - // the go back button is not in this slp (is in hudactions.slp.png) - this->endResetModel(); - break; - - default: - log::log(MSG(warn) << "Unknown action mode selection"); - } -} - -ActionModeLink* ActionsListModel::get_action_mode() const { - return this->action_mode; -} - -void ActionsListModel::set_action_mode(ActionModeLink *action_mode) { - if (this->action_mode != action_mode) { - if (this->action_mode != nullptr) { - QObject::disconnect(this->action_mode, - &ActionModeLink::buttons_type_changed, - this, - &ActionsListModel::on_buttons_type_changed); - } - - this->action_mode = action_mode; - - QObject::connect(this->action_mode, - &ActionModeLink::buttons_type_changed, - this, - &ActionsListModel::on_buttons_type_changed); - } -} - -QUrl ActionsListModel::get_icons_source() const { - return QUrl(this->icons_source); -} - -void ActionsListModel::set_icons_source(QUrl icons_source) { - this->icons_source = std::move(icons_source); -} - -void ActionsListModel::set_icons_source(const std::string &icons_source) { - this->icons_source = QUrl(icons_source.c_str()); - emit this->icons_source_changed(this->icons_source); -} - -Q_INVOKABLE void ActionsListModel::set_initial_buttons() { - this->set_active_buttons(ActionButtonsType::None); -} - -void ActionsListModel::on_buttons_type_changed(const ActionButtonsType buttons_type) { - this->set_active_buttons(buttons_type); -} - -QHash ActionsListModel::roleNames() const { - QHash roles; - roles[static_cast(ActionsRoles::IconRole)] = "ico"; - roles[static_cast(ActionsRoles::IconCheckedRole)] = "icoChk"; - roles[static_cast(ActionsRoles::GroupIDRole)] = "grpID"; - roles[static_cast(ActionsRoles::NameRole)] = "name"; - return roles; -} - -int ActionsListModel::rowCount(const QModelIndex&) const { - return this->buttons.size(); -} - -QVariant ActionsListModel::data(const QModelIndex &index, int role) const { - return this->buttons.at(index.row()).value(role); -} - -QMap ActionsListModel::itemData(const QModelIndex &index) const { - return this->buttons.at(index.row()); -} - -void ActionsListModel::clear_buttons() { - this->beginResetModel(); - this->buttons.clear(); - this->endResetModel(); -} - -void ActionsListModel::add_button(int ico, int ico_chk, int grp_id, const char *name) { - QMap map; - map[static_cast(ActionsRoles::IconRole)] = QVariant(ico); - map[static_cast(ActionsRoles::IconCheckedRole)] = QVariant(ico_chk); - map[static_cast(ActionsRoles::GroupIDRole)] = QVariant(grp_id); - map[static_cast(ActionsRoles::NameRole)] = QVariant(name); - this->buttons.push_back(map); -} - -}} // namespace openage::gui diff --git a/libopenage/gui/actions_list_model.h b/libopenage/gui/actions_list_model.h deleted file mode 100644 index e0ce30f605..0000000000 --- a/libopenage/gui/actions_list_model.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2016-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "game_control_link.h" - -#include -#include -#include - -namespace openage { -namespace gui { - -/** - * Model used for the Action Buttons to render (e.g. for civilian units, - * military units, buildings etc.) - */ -class ActionsListModel : public QAbstractListModel { - Q_OBJECT - - Q_PROPERTY(ActionButtonsType active_buttons READ get_active_buttons WRITE set_active_buttons) - Q_PROPERTY(ActionModeLink* action_mode READ get_action_mode WRITE set_action_mode) - Q_PROPERTY(QUrl iconsSource READ get_icons_source WRITE set_icons_source NOTIFY icons_source_changed) - -public: - ActionsListModel(QObject *parent=nullptr); - virtual ~ActionsListModel(); - - ActionButtonsType get_active_buttons() const; - void set_active_buttons(const ActionButtonsType &active_buttons); - - ActionModeLink* get_action_mode() const; - void set_action_mode(ActionModeLink* action_mode); - - QUrl get_icons_source() const; - void set_icons_source(QUrl icons_source); - - Q_INVOKABLE void set_initial_buttons(); - - enum class ActionsRoles { - IconRole = Qt::UserRole + 1, - IconCheckedRole, - GroupIDRole, - NameRole - }; - - enum class GroupIDs { - NoGroup, - StanceGroup - }; - -signals: - void icons_source_changed(const QUrl icons_source); - -private slots: - void on_buttons_type_changed(const ActionButtonsType buttons_type); - -private: - virtual QHash roleNames() const override; - virtual int rowCount(const QModelIndex&) const override; - virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override; - virtual QMap itemData(const QModelIndex &index) const override; - - /** - * Utility function to create a QUrl from a string and set it as iconsSource - */ - void set_icons_source(const std::string &icons_source); - - /** - * Clears all buttons - */ - void clear_buttons(); - - /** - * Shortcut to creating a QMap for a button - */ - void add_button(int ico, int ico_chk, int grp_id, const char *name); - - ActionButtonsType active_buttons; - ActionModeLink *action_mode; - QUrl icons_source; - std::vector> buttons; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/assetmanager_link.cpp b/libopenage/gui/assetmanager_link.cpp deleted file mode 100644 index 7d05bd5564..0000000000 --- a/libopenage/gui/assetmanager_link.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "assetmanager_link.h" - -#include - -#include "engine_link.h" - -namespace openage { - -class LegacyEngine; - -namespace gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "LegacyAssetManager"); -} - -AssetManagerLink::AssetManagerLink(QObject *parent) : - GuiItemQObject{parent}, - GuiItem{this} { - Q_UNUSED(registration); -} - -AssetManagerLink::~AssetManagerLink() = default; - - -const util::Path &AssetManagerLink::get_asset_dir() const { - return this->asset_dir; -} - - -void AssetManagerLink::set_asset_dir(const util::Path &asset_dir) { - static auto f = [](LegacyAssetManager *_this, const util::Path &dir) { - _this->set_asset_dir(dir); - }; - this->s(f, this->asset_dir, asset_dir); -} - - -EngineLink *AssetManagerLink::get_engine() const { - return this->engine; -} - - -void AssetManagerLink::set_engine(EngineLink *engine_link) { - static auto f = [](LegacyAssetManager *_this, LegacyEngine *engine) { - _this->set_engine(engine); - }; - this->s(f, this->engine, engine_link); -} - - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/assetmanager_link.h b/libopenage/gui/assetmanager_link.h deleted file mode 100644 index effa0abc33..0000000000 --- a/libopenage/gui/assetmanager_link.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../util/path.h" -#include "assets/legacy_assetmanager.h" -#include "guisys/link/gui_item.h" - - -namespace openage { -namespace gui { -class AssetManagerLink; -class EngineLink; -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::AssetManagerLink; -}; - -template <> -struct Unwrap { - using Type = openage::LegacyAssetManager; -}; - -} // namespace qtsdl - - -namespace openage { -namespace gui { - -class AssetManagerLink : public qtsdl::GuiItemQObject - , public qtsdl::GuiItem { - Q_OBJECT - - Q_PROPERTY(openage::util::Path assetDir READ get_asset_dir WRITE set_asset_dir) - Q_MOC_INCLUDE("gui/engine_link.h") - Q_PROPERTY(openage::gui::EngineLink *engine READ get_engine WRITE set_engine) - -public: - explicit AssetManagerLink(QObject *parent = nullptr); - virtual ~AssetManagerLink(); - - const util::Path &get_asset_dir() const; - void set_asset_dir(const util::Path &data_dir); - - EngineLink *get_engine() const; - void set_engine(EngineLink *engine); - -private: - util::Path asset_dir; - EngineLink *engine; -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/category_contents_list_model.cpp b/libopenage/gui/category_contents_list_model.cpp deleted file mode 100644 index 334bf7570f..0000000000 --- a/libopenage/gui/category_contents_list_model.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "category_contents_list_model.h" - -#include - -#include "game_control_link.h" - -namespace openage { -namespace gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "Category"); -} - -CategoryContentsListModel::CategoryContentsListModel(QObject *parent) - : - QAbstractListModel{parent}, - editor_mode{} { - Q_UNUSED(registration); -} - -CategoryContentsListModel::~CategoryContentsListModel() = default; - -QString CategoryContentsListModel::get_name() const { - return this->name; -} - -void CategoryContentsListModel::set_name(const QString &name) { - if (this->name != name) { - this->name = name; - - this->on_categories_content_changed(); - } -} - -EditorModeLink* CategoryContentsListModel::get_editor_mode() const { - return this->editor_mode; -} - -void CategoryContentsListModel::set_editor_mode(EditorModeLink *editor_mode) { - if (this->editor_mode != editor_mode) { - if (this->editor_mode) { - QObject::disconnect(this->editor_mode, &EditorModeLink::categories_content_changed, this, &CategoryContentsListModel::on_categories_content_changed); - QObject::disconnect(this->editor_mode, &EditorModeLink::category_content_changed, this, &CategoryContentsListModel::on_category_content_changed); - } - - this->editor_mode = editor_mode; - - if (this->editor_mode) { - QObject::connect(this->editor_mode, &EditorModeLink::categories_content_changed, this, &CategoryContentsListModel::on_categories_content_changed); - QObject::connect(this->editor_mode, &EditorModeLink::category_content_changed, this, &CategoryContentsListModel::on_category_content_changed); - } - - this->on_categories_content_changed(); - } -} - -void CategoryContentsListModel::on_category_content_changed(const std::string &category_name, std::vector> type_and_texture) { - if (this->name == QString::fromStdString(category_name)) { - this->beginResetModel(); - this->type_and_texture = type_and_texture; - this->endResetModel(); - } -} - -void CategoryContentsListModel::on_categories_content_changed() { - if (this->editor_mode) - this->editor_mode->announce_category_content(this->name.toStdString()); -} - -QHash CategoryContentsListModel::roleNames() const { - auto names = this->QAbstractListModel::roleNames(); - names.insert(Qt::UserRole + 1, "typeId"); - return names; -} - -int CategoryContentsListModel::rowCount(const QModelIndex&) const { - return this->type_and_texture.size(); -} - -QVariant CategoryContentsListModel::data(const QModelIndex &index, int role) const { - switch (role) { - case Qt::DisplayRole: - return std::get<1>(this->type_and_texture[index.row()]); - - case Qt::UserRole + 1: - return std::get<0>(this->type_and_texture[index.row()]); - - default: - break; - } - - return QVariant{}; -} - -}} // namespace openage::gui diff --git a/libopenage/gui/category_contents_list_model.h b/libopenage/gui/category_contents_list_model.h deleted file mode 100644 index b8dde68526..0000000000 --- a/libopenage/gui/category_contents_list_model.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include - -#include "../gamestate/old/types.h" - -#include - -namespace openage { -namespace gui { - -class EditorModeLink; - -/** - * Adaptor for the contents of a category of the Civilisation. - */ -class CategoryContentsListModel : public QAbstractListModel { - Q_OBJECT - - Q_PROPERTY(QString name READ get_name WRITE set_name) - Q_PROPERTY(openage::gui::EditorModeLink *editorMode READ get_editor_mode WRITE set_editor_mode) - -public: - CategoryContentsListModel(QObject *parent = nullptr); - virtual ~CategoryContentsListModel(); - - QString get_name() const; - void set_name(const QString &name); - - EditorModeLink *get_editor_mode() const; - void set_editor_mode(EditorModeLink *editor_mode); - -private slots: - void on_category_content_changed(const std::string &category_name, std::vector> type_and_texture); - void on_categories_content_changed(); - -private: - virtual QHash roleNames() const override; - virtual int rowCount(const QModelIndex &) const override; - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - std::vector> type_and_texture; - - QString name; - EditorModeLink *editor_mode; -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/engine_info.cpp b/libopenage/gui/engine_info.cpp deleted file mode 100644 index fad4eef3d3..0000000000 --- a/libopenage/gui/engine_info.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#include "engine_info.h" - -namespace openage { -namespace gui { - -EngineQMLInfo::EngineQMLInfo(LegacyEngine *engine, - const util::Path &asset_dir) : - engine{engine}, - asset_dir{asset_dir} {} - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/engine_info.h b/libopenage/gui/engine_info.h deleted file mode 100644 index 145821f483..0000000000 --- a/libopenage/gui/engine_info.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../presenter/legacy/legacy.h" -#include "../util/path.h" -#include "guisys/public/gui_singleton_items_info.h" - -namespace openage { -class LegacyEngine; - -namespace presenter { -class LegacyDisplay; -} - -namespace gui { - -/** - * This container is attached to the QML engine. - * - * It allows that one can access the members in the qml engine context then. - * That also means the members accessible during creation of any singleton QML item. - * - * This struct is used to link the openage Engine with QML in engine_link.cpp. - */ -class EngineQMLInfo : public qtsdl::GuiSingletonItemsInfo { -public: - EngineQMLInfo(LegacyEngine *engine, const util::Path &asset_dir); - - /** - * The openage engine, so it can be "used" in QML as a "QML Singleton". - * With this pointer, all of QML can find back to the engine. - */ - LegacyEngine *engine; - - /** - * The openage display. - */ - presenter::LegacyDisplay *display; - - /** - * Search path for finding assets n stuff. - */ - util::Path asset_dir; -}; - - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/engine_link.cpp b/libopenage/gui/engine_link.cpp deleted file mode 100644 index f98ca82ea4..0000000000 --- a/libopenage/gui/engine_link.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "engine_link.h" - -#include - -#include "../error/error.h" - -#include "../legacy_engine.h" - -#include "guisys/link/qml_engine_with_singleton_items_info.h" -#include "guisys/link/qtsdl_checked_static_cast.h" - -namespace openage::gui { - -namespace { -// this pushes the EngineLink in the QML engine. -// a qml engine calls the static provider() to obtain a handle. -const int registration = qmlRegisterSingletonType("yay.sfttech.openage", 1, 0, "LegacyEngine", &EngineLink::provider); -} // namespace - - -EngineLink::EngineLink(QObject *parent, LegacyEngine *engine) : - GuiSingletonItem{parent}, - core{engine} { - Q_UNUSED(registration); - - ENSURE(!unwrap(this)->gui_link, "Sharing singletons between QML engines is not supported for now."); - - // when the engine announces that the global key bindings - // changed, update the display. - QObject::connect( - &unwrap(this)->gui_signals, - &EngineSignals::global_binds_changed, - this, - &EngineLink::on_global_binds_changed); - - // trigger the engine signal, - // which then triggers this->on_global_binds_changed. - // unwrap(this)->announce_global_binds(); -} - -EngineLink::~EngineLink() { - unwrap(this)->gui_link = nullptr; -} - -// a qml engine requests a handle to the engine link with that static -// method we do this by extracting the per-qmlengine singleton from the -// engine (the qmlenginewithsingletoninfo), then just return the new link -// instance -QObject *EngineLink::provider(QQmlEngine *engine, QJSEngine *) { - // cast the engine to our specialization - qtsdl::QmlEngineWithSingletonItemsInfo *engine_with_singleton_items_info = qtsdl::checked_static_cast(engine); - - // get the singleton container out of the custom qml engine - auto info = static_cast( - engine_with_singleton_items_info->get_singleton_items_info()); - ENSURE(info, "qml-globals were lost or not passed to the gui subsystem"); - - // owned by the QML engine - // this handle contains the pointer to the openage engine, - // obtained through the qmlengine - return new EngineLink{nullptr, info->engine}; -} - -QStringList EngineLink::get_global_binds() const { - return this->global_binds; -} - -void EngineLink::stop() { - this->core->stop(); -} - -void EngineLink::on_global_binds_changed(const std::vector &global_binds) { - QStringList new_global_binds; - - // create the qstring list from the std string list - // which is then displayed in the ui - std::transform( - std::begin(global_binds), - std::end(global_binds), - std::back_inserter(new_global_binds), - [](const std::string &s) { - return QString::fromStdString(s); - }); - - new_global_binds.sort(); - - if (this->global_binds != new_global_binds) { - this->global_binds = new_global_binds; - emit this->global_binds_changed(); - } -} - -} // namespace openage::gui diff --git a/libopenage/gui/engine_link.h b/libopenage/gui/engine_link.h deleted file mode 100644 index dcd587035a..0000000000 --- a/libopenage/gui/engine_link.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../util/path.h" -#include "guisys/link/gui_singleton_item.h" - -QT_FORWARD_DECLARE_CLASS(QQmlEngine) -QT_FORWARD_DECLARE_CLASS(QJSEngine) - -namespace openage { -class LegacyEngine; - -namespace gui { -class EngineLink; -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::EngineLink; -}; - -template <> -struct Unwrap { - using Type = openage::LegacyEngine; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class EngineLink : public qtsdl::GuiSingletonItem { - Q_OBJECT - - /** - * The text list of global key bindings. - * displayed so one can see what keys are active. - */ - Q_PROPERTY(QStringList globalBinds - READ get_global_binds - NOTIFY global_binds_changed) - -public: - explicit EngineLink(QObject *parent, LegacyEngine *engine); - virtual ~EngineLink(); - - static QObject *provider(QQmlEngine *, QJSEngine *); - - template - U *get() const { - return core; - } - - QStringList get_global_binds() const; - - Q_INVOKABLE void stop(); - -signals: - void global_binds_changed(); - -private slots: - void on_global_binds_changed(const std::vector &global_binds); - -private: - LegacyEngine *core; - - QStringList global_binds; -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/game_control_link.cpp b/libopenage/gui/game_control_link.cpp deleted file mode 100644 index 4c41678892..0000000000 --- a/libopenage/gui/game_control_link.cpp +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "game_control_link.h" - -#include - -#include - -#include "../legacy_engine.h" -#include "../unit/action.h" -#include "../unit/unit.h" -#include "engine_link.h" -#include "game_main_link.h" - -namespace openage::gui { - -namespace { -const int registration_mode = qmlRegisterUncreatableType("yay.sfttech.openage", 1, 0, "OutputMode", "OutputMode is an abstract interface for the concrete modes like EditorMode or ActionMode."); -const int registration_create = qmlRegisterType("yay.sfttech.openage", 1, 0, "CreateMode"); -const int registration_action = qmlRegisterType("yay.sfttech.openage", 1, 0, "ActionMode"); -const int registration_editor = qmlRegisterType("yay.sfttech.openage", 1, 0, "EditorMode"); -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "GameControl"); -} // namespace - -OutputModeLink::OutputModeLink(QObject *parent) : - GuiItemQObject{parent}, - QQmlParserStatus{}, - GuiItemInterface{} { -} - -OutputModeLink::~OutputModeLink() = default; - -QString OutputModeLink::get_name() const { - return this->name; -} - -QStringList OutputModeLink::get_binds() const { - return this->binds; -} - -void OutputModeLink::on_announced(const std::string &name) { - auto new_name = QString::fromStdString(name); - - if (this->name != new_name) { - this->name = new_name; - emit this->name_changed(); - } -} - -void OutputModeLink::on_binds_changed( - const std::vector &binds) { - QStringList new_binds; - std::transform( - std::begin(binds), - std::end(binds), - std::back_inserter(new_binds), - [](const std::string &s) { - return QString::fromStdString(s); - }); - - if (this->binds != new_binds) { - this->binds = new_binds; - emit this->binds_changed(); - } -} - -void OutputModeLink::classBegin() { -} - -void OutputModeLink::on_core_adopted() { - QObject::connect(&unwrap(this)->gui_signals, - &OutputModeSignals::announced, - this, - &OutputModeLink::on_announced); - - QObject::connect(&unwrap(this)->gui_signals, - &OutputModeSignals::binds_changed, - this, - &OutputModeLink::on_binds_changed); -} - -void OutputModeLink::componentComplete() { - static auto f = [](OutputMode *_this) { - _this->announce(); - }; - this->i(f); -} - -CreateModeLink::CreateModeLink(QObject *parent) : - Inherits{parent} { - Q_UNUSED(registration_create); -} - -CreateModeLink::~CreateModeLink() = default; - -ActionModeLink::ActionModeLink(QObject *parent) : - Inherits{parent} { - Q_UNUSED(registration_action); -} - -ActionModeLink::~ActionModeLink() = default; - -QString ActionModeLink::get_ability() const { - return this->ability; -} - -QString ActionModeLink::get_population() const { - return this->population; -} - -int ActionModeLink::get_selection_size() const { - return this->selection ? this->selection->get_units_count() : 0; -} - -bool ActionModeLink::get_population_warn() const { - return this->population_warn; -} - -void ActionModeLink::act(const QString &action) { - emit this->action_triggered(action.toStdString()); -} - -void ActionModeLink::on_ability_changed(const std::string &ability) { - this->ability = QString::fromStdString(ability); - emit this->ability_changed(); -} - -void ActionModeLink::on_buttons_type_changed(const ActionButtonsType buttons_type) { - emit this->buttons_type_changed(buttons_type); -} - -void ActionModeLink::on_population_changed(int demand, int capacity, bool warn) { - this->population = QString::number(demand) + "/" + QString::number(capacity); - this->population_warn = warn; - emit this->population_changed(); -} - -void ActionModeLink::on_selection_changed(const UnitSelection *unit_selection, const Player *player) { - this->selection = unit_selection; - - if (this->selection->get_units_count() == 1) { - auto &ref = this->selection->get_first_unit(); - if (ref.is_valid()) { - Unit *u = ref.get(); - - this->selection_name = QString::fromStdString(u->unit_type->name()); - // the icons are split into two sprites - if (u->unit_type->unit_class == gamedata::unit_classes::BUILDING) { - this->selection_icon = QString::fromStdString("50706.slp.png." + std::to_string(u->unit_type->icon)); - } - else { - this->selection_icon = QString::fromStdString("50730.slp.png." + std::to_string(u->unit_type->icon)); - } - this->selection_type = QString::fromStdString("(type: " + std::to_string(u->unit_type->id()) + " " + u->top()->name() + ")"); - - if (u->has_attribute(attr_type::owner)) { - auto &own_attr = u->get_attribute(); - if (own_attr.player.civ->civ_id != 0) { // not gaia - this->selection_owner = QString::fromStdString( - own_attr.player.name + "\n" + own_attr.player.civ->civ_name + "\n" + (!player || *player == own_attr.player ? "" : player->is_ally(own_attr.player) ? "Ally" : - "Enemy")); - // TODO find the team status of the player - } - else { - this->selection_owner = QString::fromStdString(" "); - } - } - - if (u->has_attribute(attr_type::hitpoints) && u->has_attribute(attr_type::damaged)) { - auto &hp = u->get_attribute(); - auto &dm = u->get_attribute(); - // TODO replace ascii health bar with real one - if (hp.hp >= 200) { - this->selection_hp = QString::fromStdString(progress(dm.hp * 1.0f / hp.hp, 8) + " " + std::to_string(dm.hp) + "/" + std::to_string(hp.hp)); - } - else { - this->selection_hp = QString::fromStdString(progress(dm.hp * 1.0f / hp.hp, 4) + " " + std::to_string(dm.hp) + "/" + std::to_string(hp.hp)); - } - } - else { - this->selection_hp = QString::fromStdString(" "); - } - - std::string lines; - if (u->has_attribute(attr_type::resource)) { - auto &res_attr = u->get_attribute(); - lines += std::to_string((int)res_attr.amount) + " " + std::to_string(res_attr.resource_type) + "\n"; - } - if (u->has_attribute(attr_type::building)) { - auto &build_attr = u->get_attribute(); - if (build_attr.completed < 1) { - lines += "Building: " + progress(build_attr.completed, 16) + " " + std::to_string((int)(100 * build_attr.completed)) + "%\n"; - } - } - if (u->has_attribute(attr_type::garrison)) { - auto &garrison_attr = u->get_attribute(); - if (garrison_attr.content.size() > 0) { - lines += "Garrison: " + std::to_string(garrison_attr.content.size()) + " units\n"; - } - } - lines += "\n"; - if (u->has_attribute(attr_type::population)) { - auto &population_attr = u->get_attribute(); - if (population_attr.demand > 1) { - lines += "Population demand: " + std::to_string(population_attr.demand) + " units\n"; - } - if (population_attr.capacity > 0) { - lines += "Population capacity: " + std::to_string(population_attr.capacity) + " units\n"; - } - } - this->selection_attrs = QString::fromStdString(lines); - } - } - else if (this->selection->get_units_count() > 1) { - this->selection_name = QString::fromStdString( - std::to_string(this->selection->get_units_count()) + " units"); - } - - - emit this->selection_changed(); -} - -// TODO remove -std::string ActionModeLink::progress(float progress, int size) { - std::string bar = "["; - for (int i = 0; i < size; i++) { - bar += (i < progress * size ? "=" : " "); - } - return bar + "]"; -} - -void ActionModeLink::on_core_adopted() { - this->Inherits::on_core_adopted(); - QObject::connect(&unwrap(this)->gui_signals, - &ActionModeSignals::ability_changed, - this, - &ActionModeLink::on_ability_changed); - QObject::connect(&unwrap(this)->gui_signals, - &ActionModeSignals::population_changed, - this, - &ActionModeLink::on_population_changed); - QObject::connect(&unwrap(this)->gui_signals, - &ActionModeSignals::selection_changed, - this, - &ActionModeLink::on_selection_changed); - QObject::connect(&unwrap(this)->gui_signals, - &ActionModeSignals::buttons_type_changed, - this, - &ActionModeLink::on_buttons_type_changed); - QObject::connect(this, - &ActionModeLink::action_triggered, - &unwrap(this)->gui_signals, - &ActionModeSignals::on_action); -} - -EditorModeLink::EditorModeLink(QObject *parent) : - Inherits{parent}, - current_type_id{-1}, - current_terrain_id{-1}, - paint_terrain{} { - Q_UNUSED(registration_editor); -} - -EditorModeLink::~EditorModeLink() = default; - -int EditorModeLink::get_current_type_id() const { - return this->current_type_id; -} - -void EditorModeLink::set_current_type_id(int current_type_id) { - static auto f = [](EditorMode *_this, int current_type_id) { - _this->set_current_type_id(current_type_id); - }; - this->s(f, this->current_type_id, current_type_id); -} - -int EditorModeLink::get_current_terrain_id() const { - return this->current_terrain_id; -} - -void EditorModeLink::set_current_terrain_id(int current_terrain_id) { - static auto f = [](EditorMode *_this, int current_terrain_id) { - _this->set_current_terrain_id(current_terrain_id); - }; - this->s(f, this->current_terrain_id, current_terrain_id); -} - -bool EditorModeLink::get_paint_terrain() const { - return this->paint_terrain; -} - -void EditorModeLink::set_paint_terrain(bool paint_terrain) { - static auto f = [](EditorMode *_this, int paint_terrain) { - _this->set_paint_terrain(paint_terrain); - }; - this->s(f, this->paint_terrain, paint_terrain); -} - -QStringList EditorModeLink::get_categories() const { - return this->categories; -} - -void EditorModeLink::announce_category_content(const std::string &category_name) { - static auto f = [](EditorMode *_this, const std::string &category_name) { - _this->announce_category_content(category_name); - }; - this->i(f, category_name); -} - -void EditorModeLink::on_categories_changed(const std::vector &categories) { - this->categories.clear(); - std::transform(std::begin(categories), std::end(categories), std::back_inserter(this->categories), [](const std::string &s) { return QString::fromStdString(s); }); - emit this->categories_changed(); -} - -void EditorModeLink::on_core_adopted() { - this->Inherits::on_core_adopted(); - QObject::connect(&unwrap(this)->gui_signals, &EditorModeSignals::toggle, this, &EditorModeLink::toggle); - QObject::connect(&unwrap(this)->gui_signals, &EditorModeSignals::categories_changed, this, &EditorModeLink::on_categories_changed); - QObject::connect(&unwrap(this)->gui_signals, &EditorModeSignals::categories_content_changed, this, &EditorModeLink::categories_content_changed); - QObject::connect(&unwrap(this)->gui_signals, &EditorModeSignals::category_content_changed, this, &EditorModeLink::category_content_changed); -} - -GameControlLink::GameControlLink(QObject *parent) : - GuiItemQObject{parent}, - QQmlParserStatus{}, - GuiItem{this}, - mode{}, - effective_mode_index{-1}, - mode_index{-1}, - engine{}, - game{}, - current_civ_index{} { - Q_UNUSED(registration_mode); - Q_UNUSED(registration); -} - -GameControlLink::~GameControlLink() = default; - -void GameControlLink::classBegin() { -} - -void GameControlLink::on_core_adopted() { - QObject::connect(&unwrap(this)->gui_signals, &GameControlSignals::mode_changed, this, &GameControlLink::on_mode_changed); - QObject::connect(&unwrap(this)->gui_signals, &GameControlSignals::modes_changed, this, &GameControlLink::on_modes_changed); - QObject::connect(&unwrap(this)->gui_signals, &GameControlSignals::current_player_name_changed, this, &GameControlLink::on_current_player_name_changed); - QObject::connect(&unwrap(this)->gui_signals, &GameControlSignals::current_civ_index_changed, this, &GameControlLink::on_current_civ_index_changed); -} - -void GameControlLink::componentComplete() { - static auto f = [](GameControl *_this) { - _this->announce_mode(); - _this->announce_current_player_name(); - }; - this->i(f); -} - -OutputModeLink *GameControlLink::get_mode() const { - return this->mode; -} - -int GameControlLink::get_effective_mode_index() const { - return this->effective_mode_index; -} - -int GameControlLink::get_mode_index() const { - return this->mode_index; -} - -void GameControlLink::set_mode_index(int mode) { - static auto f = [](GameControl *_this, int mode) { - _this->set_mode(mode, true); - }; - - this->sf(f, this->mode_index, mode); -} - -QVariantList GameControlLink::get_modes() const { - return this->modes; -} - -void GameControlLink::set_modes(const QVariantList &modes) { - static auto f = [](GameControl *_this, const QVariantList &modes) { - std::vector new_modes; - - for (auto m : modes) - if (m.canConvert()) - new_modes.push_back(unwrap(m.value())); - - _this->set_modes(new_modes); - }; - - this->s(f, this->modes, modes); -} - -EngineLink *GameControlLink::get_engine() const { - return this->engine; -} - -void GameControlLink::set_engine(EngineLink *engine) { - static auto f = [](GameControl *_this, LegacyEngine *engine) { - _this->set_engine(engine); - }; - this->s(f, this->engine, engine); -} - -GameMainLink *GameControlLink::get_game() const { - return this->game; -} - -void GameControlLink::set_game(GameMainLink *game) { - static auto f = [](GameControl *_this, GameMainHandle *game) { - _this->set_game(game); - }; - this->s(f, this->game, game); -} - -QString GameControlLink::get_current_player_name() const { - return this->current_player_name; -} - -int GameControlLink::get_current_civ_index() const { - return this->current_civ_index; -} - -void GameControlLink::on_mode_changed(OutputMode *mode, int mode_index) { - auto new_mode = qtsdl::wrap(mode); - - if (this->mode != new_mode || this->effective_mode_index != mode_index) { - this->effective_mode_index = mode_index; - this->mode = new_mode; - emit this->mode_changed(); - } -} - -void GameControlLink::on_modes_changed(OutputMode *mode, int mode_index) { - static auto f = [](GameControl *_this, int mode) { - _this->set_mode(mode); - }; - this->i(f, this->mode_index); - - this->on_mode_changed(mode, mode_index); - emit this->modes_changed(); -} - -void GameControlLink::on_current_player_name_changed(const std::string ¤t_player_name) { - this->current_player_name = QString::fromStdString(current_player_name); - emit this->current_player_name_changed(); -} - -void GameControlLink::on_current_civ_index_changed(int current_civ_index) { - this->current_civ_index = current_civ_index; - emit this->current_civ_index_changed(); -} - -} // namespace openage::gui diff --git a/libopenage/gui/game_control_link.h b/libopenage/gui/game_control_link.h deleted file mode 100644 index 9dde68e924..0000000000 --- a/libopenage/gui/game_control_link.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../presenter/legacy/game_control.h" -#include "guisys/link/gui_item.h" - -namespace openage { -namespace gui { - -class GameControlLink; - -class OutputModeLink; - -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::OutputModeLink; -}; - -template <> -struct Unwrap { - using Type = openage::OutputMode; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class OutputModeLink : public qtsdl::GuiItemQObject - , public QQmlParserStatus - , public qtsdl::GuiItemInterface { - Q_OBJECT - - Q_INTERFACES(QQmlParserStatus) - Q_PROPERTY(QString name READ get_name NOTIFY name_changed) - Q_PROPERTY(QStringList binds READ get_binds NOTIFY binds_changed) - -public: - OutputModeLink(QObject *parent = nullptr); - virtual ~OutputModeLink(); - - QString get_name() const; - QStringList get_binds() const; - -signals: - void name_changed(); - void binds_changed(); - -private slots: - void on_announced(const std::string &name); - void on_binds_changed(const std::vector &binds); - -protected: - virtual void classBegin() override; - virtual void on_core_adopted() override; - virtual void componentComplete() override; - -private: - QString name; - QStringList binds; -}; - -class CreateModeLink; - -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::CreateModeLink; -}; - -template <> -struct Unwrap { - using Type = openage::CreateMode; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class CreateModeLink : public qtsdl::Inherits { - Q_OBJECT - -public: - CreateModeLink(QObject *parent = nullptr); - virtual ~CreateModeLink(); -}; - -class ActionModeLink; - -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::ActionModeLink; -}; - -template <> -struct Unwrap { - using Type = openage::ActionMode; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class ActionModeLink : public qtsdl::Inherits { - Q_OBJECT - - Q_PROPERTY(QString ability READ get_ability NOTIFY ability_changed) - Q_PROPERTY(QString population READ get_population NOTIFY population_changed) - Q_PROPERTY(bool population_warn READ get_population_warn NOTIFY population_changed) - - Q_PROPERTY(int selection_size READ get_selection_size NOTIFY selection_changed) - - Q_PROPERTY(QString selection_name MEMBER selection_name NOTIFY selection_changed) - Q_PROPERTY(QString selection_icon MEMBER selection_icon NOTIFY selection_changed) - Q_PROPERTY(QString selection_type MEMBER selection_type NOTIFY selection_changed) - Q_PROPERTY(QString selection_owner MEMBER selection_owner NOTIFY selection_changed) - Q_PROPERTY(QString selection_hp MEMBER selection_hp NOTIFY selection_changed) - Q_PROPERTY(QString selection_attrs MEMBER selection_attrs NOTIFY selection_changed) - -public: - ActionModeLink(QObject *parent = nullptr); - virtual ~ActionModeLink(); - - QString get_ability() const; - QString get_population() const; - bool get_population_warn() const; - int get_selection_size() const; - - Q_INVOKABLE void act(const QString &action); - -signals: - void ability_changed(); - void action_triggered(const std::string &ability); - void buttons_type_changed(const ActionButtonsType buttons_type); - void population_changed(); - void selection_changed(); - -private slots: - void on_ability_changed(const std::string &ability); - void on_buttons_type_changed(const ActionButtonsType buttons_type); - void on_population_changed(int demand, int capacity, bool warn); - void on_selection_changed(const UnitSelection *unit_selection, const Player *player); - -private: - virtual void on_core_adopted() override; - - QString ability; - QString population; - bool population_warn; - const UnitSelection *selection = nullptr; - - QString selection_name; - QString selection_icon; - QString selection_type; - QString selection_owner; - QString selection_hp; - QString selection_attrs; - - std::string progress(float progress, int size); -}; - -class EditorModeLink; - -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::EditorModeLink; -}; - -template <> -struct Unwrap { - using Type = openage::EditorMode; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class EditorModeLink : public qtsdl::Inherits { - Q_OBJECT - - Q_PROPERTY(int currentTypeId READ get_current_type_id WRITE set_current_type_id) - Q_PROPERTY(int currentTerrainId READ get_current_terrain_id WRITE set_current_terrain_id) - Q_PROPERTY(bool paintTerrain READ get_paint_terrain WRITE set_paint_terrain) - Q_PROPERTY(QStringList categories READ get_categories NOTIFY categories_changed) - -public: - EditorModeLink(QObject *parent = nullptr); - virtual ~EditorModeLink(); - - int get_current_type_id() const; - void set_current_type_id(int current_type_id); - - int get_current_terrain_id() const; - void set_current_terrain_id(int current_terrain_id); - - bool get_paint_terrain() const; - void set_paint_terrain(bool paint_terrain); - - QStringList get_categories() const; - - void announce_category_content(const std::string &category_name); - -signals: - void toggle(); - void categories_changed(); - void categories_content_changed(); - void category_content_changed(const std::string &category_name, std::vector> type_and_texture); - -private slots: - void on_categories_changed(const std::vector &categories); - -private: - virtual void on_core_adopted() override; - - int current_type_id; - int current_terrain_id; - bool paint_terrain; - QStringList categories; -}; - -class EngineLink; -class GameMainLink; -class GameControlLink; - -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::GameControlLink; -}; - -template <> -struct Unwrap { - using Type = openage::GameControl; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class GameControlLink : public qtsdl::GuiItemQObject - , public QQmlParserStatus - , public qtsdl::GuiItem { - Q_OBJECT - - Q_INTERFACES(QQmlParserStatus) - Q_PROPERTY(openage::gui::OutputModeLink *mode READ get_mode NOTIFY mode_changed) - Q_PROPERTY(int effectiveModeIndex READ get_effective_mode_index NOTIFY mode_changed) - Q_PROPERTY(int modeIndex READ get_mode_index WRITE set_mode_index) - Q_PROPERTY(QVariantList modes READ get_modes WRITE set_modes NOTIFY modes_changed) - Q_MOC_INCLUDE("gui/engine_link.h") - Q_MOC_INCLUDE("gui/game_main_link.h") - Q_PROPERTY(openage::gui::EngineLink *engine READ get_engine WRITE set_engine) - Q_PROPERTY(openage::gui::GameMainLink *game READ get_game WRITE set_game) - Q_PROPERTY(QString currentPlayerName READ get_current_player_name NOTIFY current_player_name_changed) - Q_PROPERTY(int currentCivIndex READ get_current_civ_index NOTIFY current_civ_index_changed) - -public: - explicit GameControlLink(QObject *parent = nullptr); - virtual ~GameControlLink(); - - OutputModeLink *get_mode() const; - int get_effective_mode_index() const; - - int get_mode_index() const; - void set_mode_index(int mode); - - QVariantList get_modes() const; - void set_modes(const QVariantList &modes); - - EngineLink *get_engine() const; - void set_engine(EngineLink *engine); - - GameMainLink *get_game() const; - void set_game(GameMainLink *game); - - QString get_current_player_name() const; - int get_current_civ_index() const; - -signals: - void mode_changed(); - void modes_changed(); - void current_player_name_changed(); - void current_civ_index_changed(); - -private slots: - void on_mode_changed(OutputMode *mode, int mode_index); - void on_modes_changed(OutputMode *mode, int mode_index); - void on_current_player_name_changed(const std::string ¤t_player_name); - void on_current_civ_index_changed(int current_civ_index); - -private: - virtual void classBegin() override; - virtual void on_core_adopted() override; - virtual void componentComplete() override; - - OutputModeLink *mode = nullptr; - int effective_mode_index; - int mode_index; - QVariantList modes; - // TODO: remove engine because it's already accessible through the game - EngineLink *engine = nullptr; - GameMainLink *game = nullptr; - QString current_player_name; - int current_civ_index; -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/game_creator.cpp b/libopenage/gui/game_creator.cpp deleted file mode 100644 index f187ab5ef2..0000000000 --- a/libopenage/gui/game_creator.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "game_creator.h" - -#include - -#include "../gamestate/old/game_main.h" -#include "../gamestate/old/game_spec.h" -#include "../gamestate/old/generator.h" - -#include "game_main_link.h" -#include "game_spec_link.h" -#include "generator_link.h" - -namespace openage::gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "GameCreator"); -} - -GameCreator::GameCreator(QObject *parent) - : - QObject{parent}, - game{}, - game_spec{}, - generator_parameters{} { - Q_UNUSED(registration); -} - -GameCreator::~GameCreator() = default; - -QString GameCreator::get_error_string() const { - return this->error_string; -} - -void GameCreator::activate() { - static auto f = [] (GameMainHandle *game, - GameSpecHandle *game_spec, - Generator *generator, - std::shared_ptr callback) { - - QString error_msg; - - if (game->is_game_running()) { - error_msg = "close existing game before loading"; - } - else if (not game_spec->is_ready()) { - error_msg = "game data has not finished loading"; - } - else { - auto game_main = generator->create(game_spec->get_spec()); - - if (game_main) { - game->set_game(std::move(game_main)); - } - else { - error_msg = "unknown error"; - } - } - - emit callback->error_message(error_msg); - }; - - if (this->game && this->game_spec && this->generator_parameters) { - std::shared_ptr callback = std::make_shared(); - - QObject::connect(callback.get(), &GameCreatorSignals::error_message, this, &GameCreator::on_processed); - - this->game->i(f, this->game_spec, this->generator_parameters, callback); - } else { - this->on_processed([this] { - if (!this->game) - return "provide 'game' before loading"; - if (!this->game_spec) - return "provide 'gameSpec' before loading"; - if (!this->generator_parameters) - return "provide 'generatorParameters' before loading"; - else - ENSURE(false, "unhandled case for refusal to create a game"); - - return "unknown error"; - }()); - } -} - -void GameCreator::clearErrors() { - this->error_string.clear(); - emit this->error_string_changed(); -} - -void GameCreator::on_processed(const QString &error_string) { - this->error_string = error_string; - emit this->error_string_changed(); -} - -} // namespace openage::gui diff --git a/libopenage/gui/game_creator.h b/libopenage/gui/game_creator.h deleted file mode 100644 index b3efb1ff4c..0000000000 --- a/libopenage/gui/game_creator.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace openage { -namespace gui { - -class GameMainLink; -class GameSpecLink; -class GeneratorLink; - -class GameCreator : public QObject { - Q_OBJECT - - Q_ENUMS(State) - Q_PROPERTY(QString errorString READ get_error_string NOTIFY error_string_changed) - Q_MOC_INCLUDE("gui/game_main_link.h") - Q_MOC_INCLUDE("gui/game_spec_link.h") - Q_MOC_INCLUDE("gui/generator_link.h") - Q_PROPERTY(openage::gui::GameMainLink *game MEMBER game NOTIFY game_changed) - Q_PROPERTY(openage::gui::GameSpecLink *gameSpec MEMBER game_spec NOTIFY game_spec_changed) - Q_PROPERTY(openage::gui::GeneratorLink *generatorParameters MEMBER generator_parameters NOTIFY generator_parameters_changed) - -public: - explicit GameCreator(QObject *parent = nullptr); - virtual ~GameCreator(); - - QString get_error_string() const; - - Q_INVOKABLE void activate(); - Q_INVOKABLE void clearErrors(); - -public slots: - void on_processed(const QString &error_string); - -signals: - void error_string_changed(); - void game_changed(); - void game_spec_changed(); - void generator_parameters_changed(); - -private: - QString error_string; - GameMainLink *game; - GameSpecLink *game_spec; - GeneratorLink *generator_parameters; -}; - -class GameCreatorSignals : public QObject { - Q_OBJECT - -public: -signals: - void error_message(const QString &error); -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/game_main_link.cpp b/libopenage/gui/game_main_link.cpp deleted file mode 100644 index 35b4af4c65..0000000000 --- a/libopenage/gui/game_main_link.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "game_main_link.h" - -#include - -#include "../legacy_engine.h" -#include "engine_link.h" - -namespace openage::gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "GameMain"); -} - -GameMainLink::GameMainLink(QObject *parent) : - GuiItemQObject{parent}, - QQmlParserStatus{}, - GuiItem{this}, - state{}, - active{}, - engine{} { - Q_UNUSED(registration); -} - -GameMainLink::~GameMainLink() = default; - -void GameMainLink::classBegin() { -} - -void GameMainLink::on_core_adopted() { - QObject::connect(&unwrap(this)->gui_signals, &GameMainSignals::game_running, this, &GameMainLink::on_game_running); -} - -void GameMainLink::componentComplete() { - static auto f = [](GameMainHandle *_this) { - _this->announce_running(); - }; - this->i(f); -} - -GameMainLink::State GameMainLink::get_state() const { - return this->state; -} - -EngineLink *GameMainLink::get_engine() const { - return this->engine; -} - -void GameMainLink::set_engine(EngineLink *engine) { - static auto f = [](GameMainHandle *_this, LegacyEngine *engine) { - _this->set_engine(engine); - }; - this->s(f, this->engine, engine); -} - -void GameMainLink::clear() { - static auto f = [](GameMainHandle *_this) { - _this->clear(); - }; - this->i(f); -} - -void GameMainLink::on_game_running(bool running) { - auto state = running ? State::Running : State::Null; - - if (this->state != state) { - this->state = state; - emit this->state_changed(); - } -} - -} // namespace openage::gui diff --git a/libopenage/gui/game_main_link.h b/libopenage/gui/game_main_link.h deleted file mode 100644 index 0277cab6b8..0000000000 --- a/libopenage/gui/game_main_link.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2015-2018 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "guisys/link/gui_item.h" - -#include "../gamestate/old/game_main.h" - -namespace openage { -namespace gui { - -class EngineLink; -class GameMainLink; - -}} // namespace openage::gui - -namespace qtsdl { -template<> -struct Wrap { - using Type = openage::gui::GameMainLink; -}; - -template<> -struct Unwrap { - using Type = openage::GameMainHandle; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class GameMainLink : public qtsdl::GuiItemQObject, public QQmlParserStatus, public qtsdl::GuiItem { - Q_OBJECT - - Q_INTERFACES(QQmlParserStatus) - Q_ENUMS(State) - Q_PROPERTY(State state READ get_state NOTIFY state_changed) - Q_PROPERTY(openage::gui::EngineLink* engine READ get_engine WRITE set_engine) - -public: - explicit GameMainLink(QObject *parent=nullptr); - virtual ~GameMainLink(); - - enum class State { - Null, Running - }; - - State get_state() const; - - EngineLink* get_engine() const; - void set_engine(EngineLink *engine); - - Q_INVOKABLE void clear(); - -signals: - void state_changed(); - -private slots: - void on_game_running(bool running); - -private: - virtual void classBegin() override; - virtual void on_core_adopted() override; - virtual void componentComplete() override; - - State state; - bool active; - EngineLink *engine; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/game_saver.cpp b/libopenage/gui/game_saver.cpp deleted file mode 100644 index f6793207ca..0000000000 --- a/libopenage/gui/game_saver.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016-2021 the openage authors. See copying.md for legal info. - -#include "game_saver.h" - -#include - -#include "../gamestate/old/game_save.h" -#include "../gamestate/old/game_main.h" -#include "../gamestate/old/generator.h" - -#include "game_main_link.h" -#include "generator_link.h" - -namespace openage::gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "GameSaver"); -} - -GameSaver::GameSaver(QObject *parent) - : - QObject{parent}, - game{}, - generator_parameters{} { - Q_UNUSED(registration); -} - -GameSaver::~GameSaver() = default; - -QString GameSaver::get_error_string() const { - return this->error_string; -} - -// called when the save-game button is pressed: -void GameSaver::activate() { - static auto f = [] (GameMainHandle *game, - Generator *generator, - std::shared_ptr callback) { - - QString error_msg; - - if (!game->is_game_running()) { - error_msg = "no open game to save"; - } else { - auto filename = generator->getv("load_filename"); - gameio::save(game->get_game(), filename); - } - - emit callback->error_message(error_msg); - }; - - if (this->game && this->generator_parameters) { - std::shared_ptr callback = std::make_shared(); - QObject::connect(callback.get(), - &GameSaverSignals::error_message, - this, - &GameSaver::on_processed); - - this->game->i(f, this->generator_parameters, callback); - } - else { - QString error_msg = "unknown error"; - - if (!this->game) { - error_msg = "provide 'game' before saving"; - } - - if (!this->generator_parameters) { - error_msg = "provide 'generatorParameters' before saving"; - } - else { - ENSURE(false, "unhandled case for refusal to create a game"); - } - - this->on_processed(error_msg); - } -} - -void GameSaver::clearErrors() { - this->error_string.clear(); - emit this->error_string_changed(); -} - -void GameSaver::on_processed(const QString &error_string) { - this->error_string = error_string; - emit this->error_string_changed(); -} - -} // namespace openage::gui diff --git a/libopenage/gui/game_saver.h b/libopenage/gui/game_saver.h deleted file mode 100644 index 13a4183de6..0000000000 --- a/libopenage/gui/game_saver.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2016-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace openage { -namespace gui { - -class GameMainLink; -class GeneratorLink; - -class GameSaver : public QObject { - Q_OBJECT - - Q_ENUMS(State) - Q_PROPERTY(QString errorString READ get_error_string NOTIFY error_string_changed) - Q_PROPERTY(openage::gui::GameMainLink* game MEMBER game NOTIFY game_changed) - Q_PROPERTY(openage::gui::GeneratorLink* generatorParameters MEMBER generator_parameters NOTIFY generator_parameters_changed) - -public: - explicit GameSaver(QObject *parent=nullptr); - virtual ~GameSaver(); - - QString get_error_string() const; - - Q_INVOKABLE void activate(); - Q_INVOKABLE void clearErrors(); - -public slots: - void on_processed(const QString &error_string); - -signals: - void error_string_changed(); - void game_changed(); - void generator_parameters_changed(); - -private: - QString error_string; - GameMainLink *game; - GeneratorLink *generator_parameters; -}; - -class GameSaverSignals : public QObject { - Q_OBJECT - -public: -signals: - void error_message(const QString &error); -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/game_spec_link.cpp b/libopenage/gui/game_spec_link.cpp deleted file mode 100644 index dea041ce5c..0000000000 --- a/libopenage/gui/game_spec_link.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "game_spec_link.h" - -#include - -#include "assetmanager_link.h" - -namespace openage::gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "GameSpec"); -const int registration_of_ptr = qRegisterMetaType>("shared_ptr"); -} - -GameSpecLink::GameSpecLink(QObject *parent) - : - GuiItemQObject{parent}, - QQmlParserStatus{}, - GuiItem{this}, - state{}, - active{}, - asset_manager{}, - terrain_id_count{} { - Q_UNUSED(registration); - Q_UNUSED(registration_of_ptr); -} - -GameSpecLink::~GameSpecLink() = default; - -void GameSpecLink::classBegin() { -} - -void GameSpecLink::on_core_adopted() { - auto core = unwrap(this); - QObject::connect(core->gui_signals.get(), &GameSpecSignals::load_job_finished, this, &GameSpecLink::on_load_job_finished); - QObject::connect(core->gui_signals.get(), &GameSpecSignals::game_spec_loaded, this, &GameSpecLink::on_game_spec_loaded); -} - -void GameSpecLink::componentComplete() { - this->on_load_job_finished(); -} - -void GameSpecLink::on_load_job_finished() { - static auto f = [] (GameSpecHandle *_this) { - _this->announce_spec(); - }; - this->i(f); -} - -void GameSpecLink::on_game_spec_loaded(std::shared_ptr loaded_game_spec) { - this->loaded_game_spec = loaded_game_spec; - - this->terrain_id_count = this->loaded_game_spec->get_terrain_meta()->terrain_id_count; - - this->state = State::Ready; - - emit this->state_changed(); - emit this->terrain_id_count_changed(); - emit this->game_spec_loaded(this, this->loaded_game_spec); -} - -std::shared_ptr GameSpecLink::get_loaded_spec() { - return this->loaded_game_spec; -} - -GameSpecLink::State GameSpecLink::get_state() const { - return this->state; -} - -void GameSpecLink::invalidate() { - static auto f = [] (GameSpecHandle *_this) { - _this->invalidate(); - }; - this->i(f); - - this->set_state(this->active ? State::Loading : State::Null); -} - -bool GameSpecLink::get_active() const { - return this->active; -} - -void GameSpecLink::set_active(bool active) { - static auto f = [] (GameSpecHandle *_this, bool active) { - _this->set_active(active); - }; - this->s(f, this->active, active); - - this->set_state(this->active && this->state == State::Null ? State::Loading : this->state); -} - -AssetManagerLink* GameSpecLink::get_asset_manager() const { - return this->asset_manager; -} - -void GameSpecLink::set_asset_manager(AssetManagerLink *asset_manager) { - static auto f = [] (GameSpecHandle *_this, LegacyAssetManager *asset_manager) { - _this->set_asset_manager(asset_manager); - }; - this->s(f, this->asset_manager, asset_manager); -} - -int GameSpecLink::get_terrain_id_count() const { - return this->terrain_id_count; -} - -void GameSpecLink::set_state(GameSpecLink::State state) { - if (state != this->state) { - this->state = state; - emit this->state_changed(); - } -} - -} // namespace openage::gui diff --git a/libopenage/gui/game_spec_link.h b/libopenage/gui/game_spec_link.h deleted file mode 100644 index ac2b2dd96e..0000000000 --- a/libopenage/gui/game_spec_link.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include -#include - -#include "guisys/link/gui_item.h" - -#include "../gamestate/old/game_spec.h" - -namespace openage { - -class GameSpec; - -namespace gui { - -class AssetManagerLink; -class GameSpecLink; - -} // namespace gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::GameSpecLink; -}; - -template <> -struct Unwrap { - using Type = openage::GameSpecHandle; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class GameSpecLink : public qtsdl::GuiItemQObject - , public QQmlParserStatus - , public qtsdl::GuiItem { - Q_OBJECT - - Q_INTERFACES(QQmlParserStatus) - Q_ENUMS(State) - Q_PROPERTY(State state READ get_state NOTIFY state_changed) - Q_PROPERTY(bool active READ get_active WRITE set_active) - Q_PROPERTY(openage::gui::AssetManagerLink *assetManager READ get_asset_manager WRITE set_asset_manager) - Q_PROPERTY(int terrainIdCount READ get_terrain_id_count NOTIFY terrain_id_count_changed) - -public: - explicit GameSpecLink(QObject *parent = nullptr); - virtual ~GameSpecLink(); - - enum class State { - Null, - Loading, - Ready - }; - - State get_state() const; - - bool get_active() const; - void set_active(bool active); - - AssetManagerLink *get_asset_manager() const; - void set_asset_manager(AssetManagerLink *asset_manager); - - int get_terrain_id_count() const; - - Q_INVOKABLE void invalidate(); - - std::shared_ptr get_loaded_spec(); - -signals: - /** - * Pass loaded assets to the image provider. - * - * Provider will check if it's still attached to that spec. - * Also it may be invalidated in the meantime, so share the ownership. - */ - void game_spec_loaded(GameSpecLink *game_spec, std::shared_ptr loaded_game_spec); - - void state_changed(); - void terrain_id_count_changed(); - -private slots: - void on_load_job_finished(); - void on_game_spec_loaded(std::shared_ptr loaded_game_spec); - -private: - virtual void classBegin() override; - virtual void on_core_adopted() override; - virtual void componentComplete() override; - - void set_state(State state); - - State state; - bool active; - AssetManagerLink *asset_manager; - int terrain_id_count; - - std::shared_ptr loaded_game_spec; -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/generator_link.cpp b/libopenage/gui/generator_link.cpp deleted file mode 100644 index 1b0be636aa..0000000000 --- a/libopenage/gui/generator_link.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "generator_link.h" - -#include - -#include "guisys/link/gui_property_map_impl.h" - -namespace openage::gui { - -namespace -{ -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "GeneratorParameters"); -} - -GeneratorLink::GeneratorLink(QObject *parent) - : - GuiListModel{parent}, - GuiItemListModel{this} { - Q_UNUSED(registration); -} - -GeneratorLink::~GeneratorLink() = default; - -} // namespace openage::gui diff --git a/libopenage/gui/generator_link.h b/libopenage/gui/generator_link.h deleted file mode 100644 index 7dd3f0567f..0000000000 --- a/libopenage/gui/generator_link.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gamestate/old/generator.h" - -#include "guisys/link/gui_item_list_model.h" -#include "guisys/link/gui_list_model.h" - -namespace openage { -class Generator; -namespace gui { -class GeneratorLink; -} -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::gui::GeneratorLink; -}; - -template <> -struct Unwrap { - using Type = openage::Generator; -}; - -} // namespace qtsdl - -namespace openage { -namespace gui { - -class GeneratorLink : public qtsdl::GuiListModel - , public qtsdl::GuiItemListModel { - Q_OBJECT - -public: - GeneratorLink(QObject *parent = nullptr); - virtual ~GeneratorLink(); -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/gui.cpp b/libopenage/gui/gui.cpp deleted file mode 100644 index b9b600d8c5..0000000000 --- a/libopenage/gui/gui.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -// include first to make opengl and libepoxy happy. -#include "../shader/program.h" -#include "../shader/shader.h" - -#include "gui.h" - -#include "../legacy_engine.h" -#include "../util/path.h" -#include "engine_info.h" - - -namespace openage { -namespace gui { - - -GUI::GUI(SDL_Window *window, - const std::string &source, - const std::string &rootdir, - EngineQMLInfo *info) : - application{}, - render_updater{}, - renderer{window}, - game_logic_updater{}, - image_provider_by_filename{ - &render_updater, - GuiGameSpecImageProvider::Type::ByFilename}, - image_provider_by_graphic_id{ - &render_updater, - GuiGameSpecImageProvider::Type::ByGraphicId}, - image_provider_by_terrain_id{ - &render_updater, - GuiGameSpecImageProvider::Type::ByTerrainId}, - engine{ - &renderer, - {&image_provider_by_filename, - &image_provider_by_graphic_id, - &image_provider_by_terrain_id}, - info}, - subtree{ - &renderer, - &game_logic_updater, - &engine, - source, - rootdir}, - input{&renderer, &game_logic_updater} { - info->display->register_resize_action(this); - info->display->register_input_action(this); - info->display->register_drawhud_action(this); - - util::Path shader_dir = info->asset_dir / "shaders"; - - const char *shader_header_code = "#version 120\n"; - - auto text_vert_file = (shader_dir / "identity.vert.glsl").open(); - std::string texture_vert_code = text_vert_file.read(); - auto plaintexture_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, texture_vert_code.c_str()}); - text_vert_file.close(); - - auto text_frag_file = (shader_dir / "maptexture.frag.glsl").open(); - std::string texture_frag_code = text_frag_file.read(); - auto plaintexture_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, texture_frag_code.c_str()}); - text_vert_file.close(); - - this->textured_screen_quad_shader = std::make_unique( - plaintexture_vert.get(), - plaintexture_frag.get()); - - this->textured_screen_quad_shader->link(); - this->tex_loc = this->textured_screen_quad_shader->get_uniform_id("texture"); - this->textured_screen_quad_shader->use(); - glUniform1i(this->tex_loc, 0); - this->textured_screen_quad_shader->stopusing(); - - const float screen_quad[] = { - -1.f, - -1.f, - 1.f, - -1.f, - 1.f, - 1.f, - -1.f, - 1.f, - }; - - glGenBuffers(1, &this->screen_quad_vbo); - - glBindBuffer(GL_ARRAY_BUFFER, this->screen_quad_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(screen_quad), screen_quad, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -GUI::~GUI() { - glDeleteBuffers(1, &this->screen_quad_vbo); -} - -void GUI::process_events() { - this->game_logic_updater.process_callbacks(); - this->application.processEvents(); -} - -bool GUI::on_resize(coord::viewport_delta new_size) { - this->renderer.resize(new_size.x, new_size.y); - return true; -} - -bool GUI::on_input(SDL_Event *event) { - return not this->input.process(event); -} - -namespace { -/** - * Restores blending function. - */ -class BlendPreserver { -public: - BlendPreserver() : - was_on{}, - src{}, - dst{} { - glGetBooleanv(GL_BLEND, &this->was_on); - - if (this->was_on != GL_FALSE) { - glGetIntegerv(GL_BLEND_SRC_ALPHA, &this->src); - glGetIntegerv(GL_BLEND_DST_ALPHA, &this->dst); - } - } - - ~BlendPreserver() { - if (this->was_on != GL_FALSE) { - glEnable(GL_BLEND); - glBlendFunc(this->src, this->dst); - } - else { - glDisable(GL_BLEND); - } - } - -private: - GLboolean was_on; - GLint src; - GLint dst; -}; - -} // namespace - -bool GUI::on_drawhud() { - this->render_updater.process_callbacks(); - - BlendPreserver preserve_blend; - - auto tex = this->renderer.render(); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - this->textured_screen_quad_shader->use(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex); - - glEnableVertexAttribArray(this->textured_screen_quad_shader->pos_id); - - glBindBuffer(GL_ARRAY_BUFFER, this->screen_quad_vbo); - glVertexAttribPointer( - this->textured_screen_quad_shader->pos_id, - 2, - GL_FLOAT, - GL_FALSE, - 2 * sizeof(float), - 0); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDisableVertexAttribArray(this->textured_screen_quad_shader->pos_id); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glBindTexture(GL_TEXTURE_2D, 0); - - this->textured_screen_quad_shader->stopusing(); - - return true; -} - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/gui.h b/libopenage/gui/gui.h deleted file mode 100644 index 0abb70ff5e..0000000000 --- a/libopenage/gui/gui.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "../handlers.h" -#include "guisys/public/gui_engine.h" -#include "guisys/public/gui_event_queue.h" -#include "guisys/public/gui_input.h" -#include "guisys/public/gui_renderer.h" -#include "guisys/public/gui_subtree.h" -#include "integration/public/gui_application_with_logger.h" -#include "integration/public/gui_game_spec_image_provider.h" - - -namespace qtsdl { -class GuiSingletonItemsInfo; -} // namespace qtsdl - -namespace openage { -namespace shader { -class Program; -} // namespace shader - -namespace gui { - -class EngineQMLInfo; - - -/** - * Main entry point for the openage Qt-based user interface. - * - * Legacy variant for the "old" renderer. - */ -class GUI : public InputHandler - , public ResizeHandler - , public HudHandler { -public: - explicit GUI(SDL_Window *window, - const std::string &source, - const std::string &rootdir, - EngineQMLInfo *info = nullptr); - virtual ~GUI(); - - void process_events(); - -private: - virtual bool on_resize(coord::viewport_delta new_size) override; - virtual bool on_input(SDL_Event *event) override; - virtual bool on_drawhud() override; - - GLint tex_loc; - GLuint screen_quad_vbo; - - GuiApplicationWithLogger application; - qtsdl::GuiEventQueue render_updater; - qtsdl::GuiRenderer renderer; - qtsdl::GuiEventQueue game_logic_updater; - GuiGameSpecImageProvider image_provider_by_filename; - GuiGameSpecImageProvider image_provider_by_graphic_id; - GuiGameSpecImageProvider image_provider_by_terrain_id; - qtsdl::GuiEngine engine; - qtsdl::GuiSubtree subtree; - qtsdl::GuiInput input; - - // needs to be deallocated before the GuiRenderer - // it accesses opengl api functions which require a - // current context: - std::unique_ptr textured_screen_quad_shader; -}; - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/guisys/CMakeLists.txt b/libopenage/gui/guisys/CMakeLists.txt deleted file mode 100644 index 922c3ec72c..0000000000 --- a/libopenage/gui/guisys/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -list(APPEND QT_SDL_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_item.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_list_model.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_property_map_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_singleton_item.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/link/qml_engine_with_singleton_items_info.cpp -) - -list(APPEND QT_SDL_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_application.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_engine.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_event_queue.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_image_provider.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_input.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_property_map.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_renderer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/public/gui_subtree.cpp -) - -list(APPEND QT_SDL_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/private/game_logic_caller.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_application_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_callback.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_ctx_setup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_dedicated_thread.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_engine_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_event_queue_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_image_provider_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_input_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_renderer_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_rendering_setup_routines.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/gui_subtree_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/opengl_debug_logger.cpp -) - -list(APPEND QT_SDL_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/deferred_initial_constant_property_values.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/gui_live_reloader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/recursive_directory_watcher.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/recursive_directory_watcher_worker.cpp -) - -set(QT_SDL_SOURCES ${QT_SDL_SOURCES} PARENT_SCOPE) diff --git a/libopenage/gui/guisys/link/gui_item.cpp b/libopenage/gui/guisys/link/gui_item.cpp deleted file mode 100644 index d8116501c4..0000000000 --- a/libopenage/gui/guisys/link/gui_item.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include "gui_item.h" - -namespace qtsdl { - - -QString name_tidier(const char *name) { - QString cleaner_name = QString::fromLatin1(name); - cleaner_name.remove(QRegularExpression("qtsdl|PersistentCoreHolder")); - return cleaner_name; -} - -GuiItemQObject::GuiItemQObject(QObject *parent) - : - QObject{parent}, - GuiItemBase{} { -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/link/gui_singleton_item.cpp b/libopenage/gui/guisys/link/gui_singleton_item.cpp deleted file mode 100644 index c0348a4b90..0000000000 --- a/libopenage/gui/guisys/link/gui_singleton_item.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_singleton_item.h" - -namespace qtsdl { - -GuiSingletonItem::GuiSingletonItem(QObject *parent) - : - QObject{parent}, - GuiItemLink{} { -} - -GuiSingletonItem::~GuiSingletonItem() = default; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/link/gui_singleton_item.h b/libopenage/gui/guisys/link/gui_singleton_item.h deleted file mode 100644 index 73c322ba4d..0000000000 --- a/libopenage/gui/guisys/link/gui_singleton_item.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gui_item_link.h" - -namespace qtsdl { - -class GuiSingletonItem : public QObject, public GuiItemLink { - Q_OBJECT - -public: - explicit GuiSingletonItem(QObject *parent=nullptr); - virtual ~GuiSingletonItem(); -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/link/qml_engine_with_singleton_items_info.cpp b/libopenage/gui/guisys/link/qml_engine_with_singleton_items_info.cpp deleted file mode 100644 index 8b6f403f29..0000000000 --- a/libopenage/gui/guisys/link/qml_engine_with_singleton_items_info.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include "qml_engine_with_singleton_items_info.h" - -#include - -namespace qtsdl { - -QmlEngineWithSingletonItemsInfo::QmlEngineWithSingletonItemsInfo(std::vector> &&image_providers, GuiSingletonItemsInfo *singleton_items_info) - : - QmlEngineWithSingletonItemsInfo{image_providers, singleton_items_info} { -} - -QmlEngineWithSingletonItemsInfo::QmlEngineWithSingletonItemsInfo(std::vector> &image_providers, GuiSingletonItemsInfo *singleton_items_info) - : - QQmlEngine{}, - image_providers(image_providers.size()), - singleton_items_info{singleton_items_info} { - - std::transform(std::begin(image_providers), std::end(image_providers), std::begin(this->image_providers), [] (const std::unique_ptr &image_provider) { - return image_provider.get(); - }); - - std::for_each(std::begin(image_providers), std::end(image_providers), [this] (std::unique_ptr &image_provider) { - auto id = image_provider->get_id(); - this->addImageProvider(id, image_provider.release()); - }); -} - -QmlEngineWithSingletonItemsInfo::~QmlEngineWithSingletonItemsInfo() { - std::for_each(std::begin(this->image_providers), std::end(this->image_providers), [this] (GuiImageProviderImpl *image_provider) { - image_provider->give_up(); - this->removeImageProvider(image_provider->get_id()); - }); -} - -GuiSingletonItemsInfo* QmlEngineWithSingletonItemsInfo::get_singleton_items_info() const { - return this->singleton_items_info; -} - -std::vector QmlEngineWithSingletonItemsInfo::get_image_providers() const { - return this->image_providers; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/link/qml_engine_with_singleton_items_info.h b/libopenage/gui/guisys/link/qml_engine_with_singleton_items_info.h deleted file mode 100644 index 2470f24cce..0000000000 --- a/libopenage/gui/guisys/link/qml_engine_with_singleton_items_info.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -#include "../private/gui_image_provider_impl.h" - -namespace qtsdl { - -class GuiSingletonItemsInfo; - -/** - * The Qml Engine used by openage. - * - * It's extended to contain the "singleton items info" and a list of image providers. - * The singleton item info is just a struct that allows to carry some variables - * in the qml-engine, namely the openage-engine. - * - * That way, the openage-engine and the qml-engine have a 1:1 relation and - * qml can access the main engine directly. - */ -class QmlEngineWithSingletonItemsInfo : public QQmlEngine { - Q_OBJECT - -public: - explicit QmlEngineWithSingletonItemsInfo(std::vector> &&image_providers, GuiSingletonItemsInfo *singleton_items_info=nullptr); - explicit QmlEngineWithSingletonItemsInfo(std::vector> &image_providers, GuiSingletonItemsInfo *singleton_items_info=nullptr); - virtual ~QmlEngineWithSingletonItemsInfo(); - - GuiSingletonItemsInfo* get_singleton_items_info() const; - std::vector get_image_providers() const; - -private: - std::vector image_providers; - GuiSingletonItemsInfo *singleton_items_info; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/link/qtsdl_checked_static_cast.h b/libopenage/gui/guisys/link/qtsdl_checked_static_cast.h deleted file mode 100644 index ecd5506984..0000000000 --- a/libopenage/gui/guisys/link/qtsdl_checked_static_cast.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace qtsdl { - -template -T checked_static_cast(U *u) { - assert(dynamic_cast(u)); - return static_cast(u); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/game_logic_caller.cpp b/libopenage/gui/guisys/private/game_logic_caller.cpp deleted file mode 100644 index 3e277f686b..0000000000 --- a/libopenage/gui/guisys/private/game_logic_caller.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "game_logic_caller.h" - -#include "gui_callback.h" - -namespace qtsdl { - -GameLogicCaller::GameLogicCaller() - : - QObject{} { -} - -void GameLogicCaller::set_game_logic_callback(GuiCallback *game_logic_callback) { - QObject::disconnect(this, &GameLogicCaller::in_game_logic_thread, nullptr, nullptr); - QObject::disconnect(this, &GameLogicCaller::in_game_logic_thread_blocking, nullptr, nullptr); - QObject::connect(this, &GameLogicCaller::in_game_logic_thread, game_logic_callback, &GuiCallback::process); - QObject::connect(this, &GameLogicCaller::in_game_logic_thread_blocking, game_logic_callback, &GuiCallback::process_blocking, Qt::DirectConnection); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/game_logic_caller.h b/libopenage/gui/guisys/private/game_logic_caller.h deleted file mode 100644 index ef858b67b4..0000000000 --- a/libopenage/gui/guisys/private/game_logic_caller.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -namespace qtsdl { - -class GuiCallback; - -/** - * Attaches to the GuiCallbackImpl. - */ -class GameLogicCaller : public QObject { - Q_OBJECT - -public: - explicit GameLogicCaller(); - - /** - * Set up signal to be able to run code in the game logic thread. - */ - void set_game_logic_callback(GuiCallback *game_logic_callback); - -signals: - void in_game_logic_thread(const std::function& f) const; - void in_game_logic_thread_blocking(const std::function& f) const; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_application_impl.cpp b/libopenage/gui/guisys/private/gui_application_impl.cpp deleted file mode 100644 index bd5f6eeb78..0000000000 --- a/libopenage/gui/guisys/private/gui_application_impl.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_application_impl.h" - -#include -#include - -#include -#include -#include - -namespace qtsdl { - -std::weak_ptr GuiApplicationImpl::instance; - -std::shared_ptr GuiApplicationImpl::get() { - std::shared_ptr candidate = GuiApplicationImpl::instance.lock(); - - assert(!candidate || std::this_thread::get_id() == candidate->owner); - - // Ensure that OpenGL is used and not OpenGL ES. - // This occurred in macos. See issue #1177 (PR #1179) - if (!candidate) { - QSurfaceFormat format; - format.setRenderableType(QSurfaceFormat::OpenGL); - QSurfaceFormat::setDefaultFormat(format); - } - - return candidate ? candidate : std::shared_ptr{new GuiApplicationImpl}; -} - -GuiApplicationImpl::~GuiApplicationImpl() { - assert(std::this_thread::get_id() == this->owner); -} - -void GuiApplicationImpl::processEvents() { - assert(std::this_thread::get_id() == this->owner); -#ifndef __APPLE__ - this->app.processEvents(); -#endif -} - -namespace { - int argc = 1; - char arg[] = "qtsdl"; - char *argv = &arg[0]; -} - -GuiApplicationImpl::GuiApplicationImpl() - : -#ifndef NDEBUG - owner{std::this_thread::get_id()}, -#endif - app{argc, &argv} -{ - // Set locale back to POSIX for the decimal point parsing (see qcoreapplication.html#locale-settings). - std::locale::global(std::locale().combine>(std::locale::classic())); - - qInfo() << "Compiled with Qt" << QT_VERSION_STR << "and run with Qt" << qVersion(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_application_impl.h b/libopenage/gui/guisys/private/gui_application_impl.h deleted file mode 100644 index 14cd858691..0000000000 --- a/libopenage/gui/guisys/private/gui_application_impl.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include - -namespace qtsdl { - -/** - * Houses gui logic event queue. - * - * To launch it in a dedicated thread, use qtsdl::GuiDedicatedThread instead. - */ -class GuiApplicationImpl { -public: - static std::shared_ptr get(); - - ~GuiApplicationImpl(); - - void processEvents(); - -private: - GuiApplicationImpl(); - - GuiApplicationImpl(const GuiApplicationImpl&) = delete; - GuiApplicationImpl& operator=(const GuiApplicationImpl&) = delete; - -#ifndef NDEBUG - const std::thread::id owner; -#endif - - QGuiApplication app; - - static std::weak_ptr instance; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_callback.cpp b/libopenage/gui/guisys/private/gui_callback.cpp deleted file mode 100644 index 57c63ee01c..0000000000 --- a/libopenage/gui/guisys/private/gui_callback.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_callback.h" - -#include - -namespace qtsdl { - -namespace { -const int registration = qRegisterMetaType>("function"); -} - -GuiCallback::GuiCallback() - : - QObject{} { - Q_UNUSED(registration); -} - -GuiCallback::~GuiCallback() = default; - -void GuiCallback::process(const std::function &f) { - f(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_callback.h b/libopenage/gui/guisys/private/gui_callback.h deleted file mode 100644 index e42515b15f..0000000000 --- a/libopenage/gui/guisys/private/gui_callback.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include -#include - -namespace qtsdl { - -class GuiCallback : public QObject { - Q_OBJECT - -public: - GuiCallback(); - virtual ~GuiCallback(); - -signals: - void process_blocking(const std::function &f); - -public slots: - void process(const std::function &f); -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_ctx_setup.cpp b/libopenage/gui/guisys/private/gui_ctx_setup.cpp deleted file mode 100644 index aea120b89c..0000000000 --- a/libopenage/gui/guisys/private/gui_ctx_setup.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#include "gui_ctx_setup.h" - -#include - -#include - -#include "opengl_debug_logger.h" -#include "platforms/context_extraction.h" - -namespace qtsdl { - -CtxExtractionException::CtxExtractionException(const std::string &what_arg) : - std::runtime_error{what_arg} { -} - -QOpenGLContext *CtxExtractionMode::get_ctx() { - return &this->ctx; -} - -GuiUniqueRenderingContext::GuiUniqueRenderingContext(SDL_Window *window) : - CtxExtractionMode{} { - QVariant handle; - WId id; - - // std::tie(handle, id) = extract_native_context(window); - - // if (handle.isValid()) { - // // pass the SDL opengl context so qt can use it - // this->ctx.setNativeHandle(handle); - this->ctx.create(); - assert(this->ctx.isValid()); - - // reuse the sdl window - QWindow *w = QWindow::fromWinId(id); // fails on Wayland! - w->setSurfaceType(QSurface::OpenGLSurface); - - if (this->ctx.makeCurrent(w)) { - return; - } - // } - - throw CtxExtractionException("adding GUI to the main rendering context failed"); -} - -void GuiUniqueRenderingContext::pre_render() { -} - -void GuiUniqueRenderingContext::post_render() { -} - -GuiSeparateRenderingContext::GuiSeparateRenderingContext(SDL_Window *window) : - CtxExtractionMode{} { - QVariant handle; - - // std::tie(handle, this->make_current_back) = extract_native_context_and_switchback_func(window); - - // if (handle.isValid()) { - // this->main_ctx.setNativeHandle(handle); - this->main_ctx.create(); - assert(this->main_ctx.isValid()); - - auto context_debug_parameters = get_current_opengl_debug_parameters(this->main_ctx); - - this->ctx.setFormat(this->main_ctx.format()); - this->ctx.setShareContext(&this->main_ctx); - this->ctx.create(); - assert(this->ctx.isValid()); - assert(!(this->main_ctx.format().options() ^ this->ctx.format().options()).testFlag(QSurfaceFormat::DebugContext)); - - this->offscreen_surface.setFormat(this->ctx.format()); - this->offscreen_surface.create(); - - this->pre_render(); - apply_opengl_debug_parameters(context_debug_parameters, this->ctx); - this->post_render(); - // } - // else { - // throw CtxExtractionException("creating separate context for GUI failed"); - // } -} - -GuiSeparateRenderingContext::~GuiSeparateRenderingContext() { - this->pre_render(); - this->ctx_logger.reset(); - this->post_render(); -} - -void GuiSeparateRenderingContext::pre_render() { - if (!this->ctx.makeCurrent(&this->offscreen_surface)) { - assert(false); - return; - } -} - -void GuiSeparateRenderingContext::post_render() { - this->make_current_back(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_ctx_setup.h b/libopenage/gui/guisys/private/gui_ctx_setup.h deleted file mode 100644 index bcc88e932a..0000000000 --- a/libopenage/gui/guisys/private/gui_ctx_setup.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include -#include - -struct SDL_Window; - -QT_FORWARD_DECLARE_CLASS(QOpenGLDebugLogger) - -namespace qtsdl { - -class CtxExtractionException : public std::runtime_error { -public: - explicit CtxExtractionException(const std::string &what_arg); -}; - -/** - * Abstract base for the method of getting a Qt-usable context. - */ -class CtxExtractionMode { -public: - virtual ~CtxExtractionMode() { - } - - /** - * @return context that can be used by Qt - */ - QOpenGLContext* get_ctx(); - - /** - * Function that must be called before rendering the GUI. - */ - virtual void pre_render() = 0; - - /** - * Function that must be called after rendering the GUI. - */ - virtual void post_render() = 0; - -protected: - QOpenGLContext ctx; -}; - -/** - * Use the same context to render the GUI. - */ -class GuiUniqueRenderingContext : public CtxExtractionMode { -public: - explicit GuiUniqueRenderingContext(SDL_Window *window); - - virtual void pre_render() override; - virtual void post_render() override; -}; - -/** - * Create a separate context to render the GUI, make it shared with the main context. - */ -class GuiSeparateRenderingContext : public CtxExtractionMode { -public: - explicit GuiSeparateRenderingContext(SDL_Window *window); - virtual ~GuiSeparateRenderingContext(); - - virtual void pre_render() override; - virtual void post_render() override; - -private: - /** - * GL context of the game - */ - QOpenGLContext main_ctx; - - /** - * GL debug logger of the GL context of the GUI - */ - std::unique_ptr ctx_logger; - - /** - * Function to make the game context current - */ - std::function make_current_back; - - /** - * Surface that is needed to make the GUI context current - */ - QOffscreenSurface offscreen_surface; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_dedicated_thread.cpp b/libopenage/gui/guisys/private/gui_dedicated_thread.cpp deleted file mode 100644 index 5eab4a77d0..0000000000 --- a/libopenage/gui/guisys/private/gui_dedicated_thread.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include "gui_dedicated_thread.h" - -#include -#include - -#include - -#include "gui_application_impl.h" - -namespace qtsdl { - -std::weak_ptr GuiDedicatedThread::instance; - -bool GuiDedicatedThread::exists = false; -std::mutex GuiDedicatedThread::existence_guard; -std::condition_variable GuiDedicatedThread::destroyed; - -GuiDedicatedThread::GuiDedicatedThread() - : - worker{} { - - bool gui_started = false; - std::mutex gui_started_guard; - std::unique_lock lck{gui_started_guard}; - - std::condition_variable proceed_cond; - - this->worker = std::thread{[&] { - auto app = GuiApplicationImpl::get(); - - { - std::unique_lock lckInGui{gui_started_guard}; - gui_started = true; - } - - proceed_cond.notify_one(); - - QCoreApplication::instance()->exec(); - }}; - - proceed_cond.wait(lck, [&] {return gui_started;}); -} - -GuiDedicatedThread::~GuiDedicatedThread() { - QCoreApplication::instance()->quit(); - this->worker.join(); -} - -std::shared_ptr GuiDedicatedThread::get() { - std::shared_ptr candidate; - - std::unique_lock lck{GuiDedicatedThread::existence_guard}; - - GuiDedicatedThread::destroyed.wait(lck, [&candidate] { - return (candidate = GuiDedicatedThread::instance.lock()) || !GuiDedicatedThread::exists; - }); - - if (!candidate) { - GuiDedicatedThread::instance = candidate = std::shared_ptr{new GuiDedicatedThread, [] (GuiDedicatedThread *p) { - delete p; - - if (p) { - std::unique_lock dlck{GuiDedicatedThread::existence_guard}; - GuiDedicatedThread::exists = false; - - dlck.unlock(); - GuiDedicatedThread::destroyed.notify_all(); - } - }}; - - GuiDedicatedThread::exists = true; - - lck.unlock(); - GuiDedicatedThread::destroyed.notify_all(); - } - - return candidate; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_dedicated_thread.h b/libopenage/gui/guisys/private/gui_dedicated_thread.h deleted file mode 100644 index f96339b5c7..0000000000 --- a/libopenage/gui/guisys/private/gui_dedicated_thread.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include - -namespace qtsdl { - -/** - * Runs the gui logic in separate thread. - * - * For sharing the thread with something else, use qtsdl::GuiApplicationImpl instead. - */ -class GuiDedicatedThread { -public: - static std::shared_ptr get(); - - ~GuiDedicatedThread(); - -private: - GuiDedicatedThread(); - - std::thread worker; - - static std::weak_ptr instance; - - static bool exists; - static std::mutex existence_guard; - static std::condition_variable destroyed; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_engine_impl.cpp b/libopenage/gui/guisys/private/gui_engine_impl.cpp deleted file mode 100644 index e83141fb13..0000000000 --- a/libopenage/gui/guisys/private/gui_engine_impl.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_engine_impl.h" - -#include - -#include -#include -#include - -#include "../public/gui_engine.h" -#include "gui_image_provider_impl.h" -#include "gui_renderer_impl.h" - -namespace qtsdl { - -GuiEngineImpl::GuiEngineImpl(GuiRenderer *renderer, - const std::vector &image_providers, - GuiSingletonItemsInfo *singleton_items_info) - : - QObject{}, - renderer{}, - engine{GuiImageProviderImpl::take_ownership(image_providers), singleton_items_info} { - - QThread *gui_thread = QCoreApplication::instance()->thread(); - this->moveToThread(gui_thread); - this->engine.moveToThread(gui_thread); - this->watcher.moveToThread(gui_thread); - - assert(!this->engine.incubationController()); - this->attach_to(GuiRendererImpl::impl(renderer)); - - QObject::connect(this, - &GuiEngineImpl::rootDirsPathsChanged, - &this->watcher, - &RecursiveDirectoryWatcher::rootDirsPathsChanged); - - QObject::connect(&this->watcher, - &RecursiveDirectoryWatcher::changeDetected, - this, - &GuiEngineImpl::onReload); -} - -GuiEngineImpl::~GuiEngineImpl() = default; - -GuiEngineImpl* GuiEngineImpl::impl(GuiEngine *engine) { - return engine->impl.get(); -} - -void GuiEngineImpl::attach_to(GuiRendererImpl *renderer) { - this->renderer = renderer; - this->engine.setIncubationController(this->renderer->get_window()->incubationController()); -} - -QQmlEngine* GuiEngineImpl::get_qml_engine() { - return &this->engine; -} - -void GuiEngineImpl::onReload() { - qDebug("reloading GUI"); - this->engine.clearComponentCache(); - emit this->reload(); -} - -void GuiEngineImpl::add_root_dir_path(const QString &root_dir_path) { - this->root_dirs_paths.push_back(root_dir_path); - emit this->rootDirsPathsChanged(this->root_dirs_paths); -} - -void GuiEngineImpl::remove_root_dir_path(const QString &root_dir_path) { - if (this->root_dirs_paths.removeOne(root_dir_path)) - emit this->rootDirsPathsChanged(this->root_dirs_paths); - else - qWarning() << "Failed to remove path watched by ReloadableQmlEngine."; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_engine_impl.h b/libopenage/gui/guisys/private/gui_engine_impl.h deleted file mode 100644 index 57f78569aa..0000000000 --- a/libopenage/gui/guisys/private/gui_engine_impl.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "../link/qml_engine_with_singleton_items_info.h" -#include "livereload/recursive_directory_watcher.h" - -QT_FORWARD_DECLARE_CLASS(QQuickWindow) - -namespace qtsdl { - -class GuiRenderer; -class GuiRendererImpl; -class GuiImageProvider; -class GuiEngine; -class GuiSingletonItemsInfo; - -class GuiEngineImpl : public QObject { - Q_OBJECT - -public: - explicit GuiEngineImpl(GuiRenderer *renderer, - const std::vector &image_providers=std::vector(), - GuiSingletonItemsInfo *singleton_items_info=nullptr); - virtual ~GuiEngineImpl(); - - static GuiEngineImpl* impl(GuiEngine *engine); - - QQmlEngine* get_qml_engine(); - - void add_root_dir_path(const QString &root_dir_path); - void remove_root_dir_path(const QString &root_dir_path); - -signals: - void reload(); - void rootDirsPathsChanged(const QStringList&); - -public slots: - void attach_to(GuiRendererImpl *renderer); - void onReload(); - -private: - GuiRendererImpl *renderer; - - QmlEngineWithSingletonItemsInfo engine; - RecursiveDirectoryWatcher watcher; - - QStringList root_dirs_paths; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_event_queue_impl.cpp b/libopenage/gui/guisys/private/gui_event_queue_impl.cpp deleted file mode 100644 index bef677b91d..0000000000 --- a/libopenage/gui/guisys/private/gui_event_queue_impl.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_event_queue_impl.h" - -#include - -#ifdef __APPLE__ -#include -#endif -#include - -#include "../public/gui_event_queue.h" - -namespace qtsdl { - -GuiEventQueueImpl::GuiEventQueueImpl() - : - thread{QThread::currentThread()} { -} - -GuiEventQueueImpl::~GuiEventQueueImpl() = default; - -GuiEventQueueImpl* GuiEventQueueImpl::impl(GuiEventQueue *event_queue) { - return event_queue->impl.get(); -} - -void GuiEventQueueImpl::process_callbacks() { - assert(QThread::currentThread() == this->thread); -#ifdef __APPLE__ - if (QThread::currentThread() != QCoreApplication::instance()->thread()) this->callback_processor.processEvents(); -#else - this->callback_processor.processEvents(); -#endif -} - -QThread* GuiEventQueueImpl::get_thread() { - return this->thread; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_event_queue_impl.h b/libopenage/gui/guisys/private/gui_event_queue_impl.h deleted file mode 100644 index 5c97155f0d..0000000000 --- a/libopenage/gui/guisys/private/gui_event_queue_impl.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -QT_FORWARD_DECLARE_CLASS(QThread) - -namespace qtsdl { - -class GuiEventQueue; - -/** - * Provides synchronization with some game thread. - */ -class GuiEventQueueImpl { -public: - explicit GuiEventQueueImpl(); - ~GuiEventQueueImpl(); - - static GuiEventQueueImpl* impl(GuiEventQueue *event_queue); - - void process_callbacks(); - - QThread* get_thread(); - -private: - QThread * const thread; - QEventLoop callback_processor; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_image_provider_impl.cpp b/libopenage/gui/guisys/private/gui_image_provider_impl.cpp deleted file mode 100644 index 1badada7d2..0000000000 --- a/libopenage/gui/guisys/private/gui_image_provider_impl.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_image_provider_impl.h" - -#include - -#include "../public/gui_image_provider.h" - -namespace qtsdl { - -GuiImageProviderImpl::GuiImageProviderImpl() - : - QQuickImageProvider{QQmlImageProviderBase::Texture, QQuickImageProvider::ForceAsynchronousImageLoading} { -} - -GuiImageProviderImpl::~GuiImageProviderImpl() = default; - -std::unique_ptr GuiImageProviderImpl::take_ownership(GuiImageProvider *image_provider) { - std::unique_ptr ptr{image_provider->impl.release()}; - image_provider->impl = decltype(image_provider->impl) {ptr.get(), [] (GuiImageProviderImpl*) {}}; - return ptr; -} - -std::vector> GuiImageProviderImpl::take_ownership(const std::vector &image_providers) { - std::vector> image_provider_owning_ptrs(image_providers.size()); - - std::transform(std::begin(image_providers), std::end(image_providers), std::begin(image_provider_owning_ptrs), static_cast(*)(GuiImageProvider*)>(GuiImageProviderImpl::take_ownership)); - - return image_provider_owning_ptrs; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_image_provider_impl.h b/libopenage/gui/guisys/private/gui_image_provider_impl.h deleted file mode 100644 index 409fa1815e..0000000000 --- a/libopenage/gui/guisys/private/gui_image_provider_impl.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include - -namespace qtsdl { - -class GuiImageProvider; - -class GuiImageProviderImpl : public QQuickImageProvider { -public: - explicit GuiImageProviderImpl(); - virtual ~GuiImageProviderImpl(); - - static std::unique_ptr take_ownership(GuiImageProvider *image_provider); - static std::vector> take_ownership(const std::vector &image_providers); - - virtual const char* get_id() const = 0; - - virtual void give_up() = 0; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_input_impl.cpp b/libopenage/gui/guisys/private/gui_input_impl.cpp deleted file mode 100644 index a92daf4134..0000000000 --- a/libopenage/gui/guisys/private/gui_input_impl.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "gui_input_impl.h" - -#include -#include -#include - -#include - -#include "../public/gui_event_queue.h" -#include "../public/gui_renderer.h" -#include "gui_event_queue_impl.h" -#include "gui_renderer_impl.h" - -namespace qtsdl { - -GuiInputImpl::GuiInputImpl(GuiRenderer *renderer, GuiEventQueue *game_logic_updater) : - QObject{}, - mouse_buttons_state{}, - game_logic_updater{GuiEventQueueImpl::impl(game_logic_updater)} { - const bool logic_diff_input = this->game_logic_updater->get_thread() != QThread::currentThread(); - const bool gui_diff_input = QCoreApplication::instance()->thread() != QThread::currentThread(); - const Qt::ConnectionType input_to_gui = gui_diff_input ? logic_diff_input ? Qt::BlockingQueuedConnection : Qt::QueuedConnection : Qt::DirectConnection; - - QObject::connect(this, &GuiInputImpl::input_event, GuiRendererImpl::impl(renderer)->get_window(), &EventHandlingQuickWindow::on_input_event, input_to_gui); -} - -GuiInputImpl::~GuiInputImpl() = default; - -namespace { -static_assert(!(Qt::LeftButton & (static_cast(Qt::LeftButton) - 1)), "Qt non-one-bit mask."); -static_assert(!(Qt::RightButton & (static_cast(Qt::RightButton) - 1)), "Qt non-one-bit mask."); -static_assert(!(Qt::MiddleButton & (static_cast(Qt::MiddleButton) - 1)), "Qt non-one-bit mask."); -static_assert(!(Qt::XButton1 & (static_cast(Qt::XButton1) - 1)), "Qt non-one-bit mask."); -static_assert(!(Qt::XButton2 & (static_cast(Qt::XButton2) - 1)), "Qt non-one-bit mask."); - -static_assert(SDL_BUTTON_LMASK == Qt::LeftButton, "SDL/Qt mouse button mask incompatibility."); -static_assert(1 << (SDL_BUTTON_LEFT - 1) == Qt::LeftButton, "SDL/Qt mouse button mask incompatibility."); - -// Right and middle are swapped. -static_assert(SDL_BUTTON_RMASK == Qt::MiddleButton, "SDL/Qt mouse button mask incompatibility."); -static_assert(1 << (SDL_BUTTON_RIGHT - 1) == Qt::MiddleButton, "SDL/Qt mouse button mask incompatibility."); - -static_assert(SDL_BUTTON_MMASK == Qt::RightButton, "SDL/Qt mouse button mask incompatibility."); -static_assert(1 << (SDL_BUTTON_MIDDLE - 1) == Qt::RightButton, "SDL/Qt mouse button mask incompatibility."); - -static_assert(SDL_BUTTON_X1MASK == Qt::XButton1, "SDL/Qt mouse button mask incompatibility."); -static_assert(1 << (SDL_BUTTON_X1 - 1) == Qt::XButton1, "SDL/Qt mouse button mask incompatibility."); - -static_assert(SDL_BUTTON_X2MASK == Qt::XButton2, "SDL/Qt mouse button mask incompatibility."); -static_assert(1 << (SDL_BUTTON_X2 - 1) == Qt::XButton2, "SDL/Qt mouse button mask incompatibility."); - -static_assert(Qt::MiddleButton >> 1 == Qt::RightButton, "Qt::RightButton or Qt::MiddleButton has moved."); - -int sdl_mouse_mask_to_qt(Uint32 state) { - return (state & (Qt::LeftButton | Qt::XButton1 | Qt::XButton2)) | ((state & Qt::RightButton) << 1) | ((state & Qt::MiddleButton) >> 1); -} - -Qt::MouseButtons sdl_mouse_state_to_qt(Uint32 state) { - return static_cast(sdl_mouse_mask_to_qt(state)); -} - -Qt::MouseButton sdl_mouse_btn_to_qt(Uint8 button) { - return static_cast(sdl_mouse_mask_to_qt(1 << (button - 1))); -} - -int sdl_key_to_qt(SDL_Keycode sym) { - switch (sym) { - case SDLK_BACKSPACE: - return Qt::Key_Backspace; - case SDLK_DELETE: - return Qt::Key_Delete; - default: - return 0; - } -} -} // namespace - -bool GuiInputImpl::process(SDL_Event *e) { - switch (e->type) { - case SDL_MOUSEMOTION: { - QMouseEvent ev{QEvent::MouseMove, QPoint{e->motion.x, e->motion.y}, Qt::MouseButton::NoButton, this->mouse_buttons_state = sdl_mouse_state_to_qt(e->motion.state), Qt::KeyboardModifier::NoModifier}; - ev.setAccepted(false); - - // Allow dragging stuff under the gui overlay. - return relay_input_event(&ev, e->motion.state & (SDL_BUTTON_LMASK | SDL_BUTTON_MMASK | SDL_BUTTON_RMASK)); - } - - case SDL_MOUSEBUTTONDOWN: { - auto button = sdl_mouse_btn_to_qt(e->button.button); - QMouseEvent ev{QEvent::MouseButtonPress, QPoint{e->button.x, e->button.y}, button, this->mouse_buttons_state |= button, Qt::KeyboardModifier::NoModifier}; - ev.setAccepted(false); - - bool accepted = relay_input_event(&ev); - - if (e->button.clicks == 2) { - QMouseEvent ev_dbl{QEvent::MouseButtonDblClick, QPoint{e->button.x, e->button.y}, button, this->mouse_buttons_state, Qt::KeyboardModifier::NoModifier}; - ev_dbl.setAccepted(false); - accepted = relay_input_event(&ev_dbl) || accepted; - } - - return accepted; - } - - case SDL_MOUSEBUTTONUP: { - auto button = sdl_mouse_btn_to_qt(e->button.button); - QMouseEvent ev{QEvent::MouseButtonRelease, QPoint{e->button.x, e->button.y}, button, this->mouse_buttons_state &= ~button, Qt::KeyboardModifier::NoModifier}; - ev.setAccepted(false); - - // Allow dragging stuff under the gui overlay: when no item is grabbed, it probably means that initial MousButtonPress was outside gui. - return relay_input_event(&ev, true); - } - - case SDL_MOUSEWHEEL: { - QPoint pos; - SDL_GetMouseState(&pos.rx(), &pos.ry()); - - QWheelEvent ev{ - pos, - pos, - QPoint{}, - QPoint{e->wheel.x, e->wheel.y}, - this->mouse_buttons_state, - Qt::KeyboardModifier::NoModifier, // Correct states? - Qt::ScrollPhase::NoScrollPhase, // ^ - false, - }; - ev.setAccepted(false); - - return relay_input_event(&ev); - } - - case SDL_KEYDOWN: { - QKeyEvent ev{QEvent::KeyPress, sdl_key_to_qt(e->key.keysym.sym), Qt::NoModifier, QChar(static_cast(e->key.keysym.sym))}; - ev.setAccepted(false); - return relay_input_event(&ev); - } - - case SDL_KEYUP: { - QKeyEvent ev{QEvent::KeyRelease, sdl_key_to_qt(e->key.keysym.sym), Qt::NoModifier, QChar(static_cast(e->key.keysym.sym))}; - ev.setAccepted(false); - return relay_input_event(&ev); - } - - default: - return false; - } -} - -bool GuiInputImpl::relay_input_event(QEvent *ev, bool only_if_grabbed) { - const bool logic_diff_input = this->game_logic_updater->get_thread() != QThread::currentThread(); - std::atomic processed{false}; - - emit this->input_event(&processed, ev, only_if_grabbed); - - // We have sent an event to the gui thread and want a response about collision. But the gui can be - // executing a getter that blocks the gui thread while doing something in the logic thread. - // So, if the logic thread is the same as the input thread, it should be running somehow. - // - // TODO: if/when the logic thread or input thread of the main game is made separate, give mutex or - // queue to the gui in order to replace this busy wait. - if (!logic_diff_input) - while (!processed) { - this->game_logic_updater->process_callbacks(); - QThread::usleep(1); - } - - return ev->isAccepted(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_input_impl.h b/libopenage/gui/guisys/private/gui_input_impl.h deleted file mode 100644 index c3665159a5..0000000000 --- a/libopenage/gui/guisys/private/gui_input_impl.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -#include - -namespace qtsdl { - -class GuiRenderer; -class GuiEventQueue; -class GuiEventQueueImpl; - -class GuiInputImpl : public QObject { - Q_OBJECT - -public: - explicit GuiInputImpl(GuiRenderer *renderer, GuiEventQueue *game_logic_updater); - virtual ~GuiInputImpl(); - - /** - * Returns true if the event was accepted. - */ - bool process(SDL_Event *e); - -signals: - void input_event(std::atomic *processed, QEvent *ev, bool only_if_grabbed=false); - -private: - bool relay_input_event(QEvent *ev, bool only_if_grabbed=false); - - Qt::MouseButtons mouse_buttons_state; - GuiEventQueueImpl *game_logic_updater; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_renderer_impl.cpp b/libopenage/gui/guisys/private/gui_renderer_impl.cpp deleted file mode 100644 index cf3bed6a63..0000000000 --- a/libopenage/gui/guisys/private/gui_renderer_impl.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "gui_renderer_impl.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../public/gui_renderer.h" - - -namespace qtsdl { - -namespace { -const int registration = qRegisterMetaType *>("atomic_bool_ptr"); -} - -EventHandlingQuickWindow::EventHandlingQuickWindow(QQuickRenderControl *render_control) : - QQuickWindow{render_control}, - focused_item{} { - Q_UNUSED(registration); -} - -EventHandlingQuickWindow::~EventHandlingQuickWindow() = default; - -void EventHandlingQuickWindow::on_input_event(std::atomic *processed, QEvent *event, bool only_if_grabbed) { - if (!only_if_grabbed || this->mouseGrabberItem()) { - if (this->focused_item && (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)) { - QCoreApplication::instance()->sendEvent(this->focused_item, event); - } - else { - QCoreApplication::instance()->sendEvent(this, event); - - auto change_focus = [this](QQuickItem *item) { - if (this->focused_item != item) { - if (this->focused_item) { - QFocusEvent focus_out{QEvent::FocusOut, Qt::ActiveWindowFocusReason}; - QCoreApplication::instance()->sendEvent(this->focused_item, &focus_out); - } - - if (item) { - QFocusEvent focus_in{QEvent::FocusIn, Qt::ActiveWindowFocusReason}; - QCoreApplication::instance()->sendEvent(item, &focus_in); - } - } - - this->focused_item = item; - }; - - // Loose keyboard focus when clicked outside of gui. - if (event->type() == QEvent::MouseButtonPress && !event->isAccepted()) - change_focus(nullptr); - - // Normally, the QQuickWindow would handle keyboard focus automatically, but it can't because neither QQuickWindow nor - // its target QWindow respond to requestActivate(). Which means no focus event propagation when injecting mouse clicks. - // So, the workaround is to look specifically for TextFields and give them focus directly. - // TODO: to remove when the proper focus for the foreign (that obtained from QWindow::fromWinId()) windows is implemented (Qt 5.6). - if (this->mouseGrabberItem() && this->mouseGrabberItem()->metaObject()->superClass() && this->mouseGrabberItem()->metaObject()->superClass()->className() == QString("QQuickTextInput") && (event->type() == QEvent::MouseButtonPress)) - change_focus(this->mouseGrabberItem()); - } - } - - *processed = true; -} - -void EventHandlingQuickWindow::on_resized(const QSize &size) { - this->resize(size); -} - -GuiRendererImpl::GuiRendererImpl(SDL_Window *window) : - QObject{}, - gui_rendering_setup_routines{window}, - need_fbo_resize{true}, - need_sync{}, - need_render{}, - gui_locked{}, - renderer_waiting_on_cond{} { - this->moveToThread(QCoreApplication::instance()->thread()); - - QObject::connect(&this->render_control, &QQuickRenderControl::renderRequested, [&]() { - this->need_render = true; - }); - - QObject::connect(&this->render_control, &QQuickRenderControl::sceneChanged, this, &GuiRendererImpl::on_scene_changed); - - this->window = std::make_unique(&this->render_control); - this->window->moveToThread(QCoreApplication::instance()->thread()); - QObject::connect(this, &GuiRendererImpl::resized, this->window.get(), &EventHandlingQuickWindow::on_resized); - // this->window->setClearBeforeRendering(true); - this->window->setColor(QColor{0, 0, 0, 0}); - - QObject::connect(&*this->window, &QQuickWindow::sceneGraphInitialized, this, [this] { - std::tie(this->new_fbo_width, this->new_fbo_height) = std::make_tuple(this->window->width(), this->window->height()); - this->need_fbo_resize = true; - }); - - QObject::connect(&*this->window, &QQuickWindow::widthChanged, [this] { this->new_fbo_width = this->window->width(); this->need_fbo_resize = true; }); - QObject::connect(&*this->window, &QQuickWindow::heightChanged, [this] { this->new_fbo_height = this->window->height(); this->need_fbo_resize = true; }); - - GuiRenderingCtxActivator activate_render(this->gui_rendering_setup_routines); - - // TODO: Make independent from OpenGL - this->window->setGraphicsDevice( - QQuickGraphicsDevice::fromOpenGLContext(this->gui_rendering_setup_routines.get_ctx())); - this->render_control.initialize(); -} - -void GuiRendererImpl::on_scene_changed() { - this->need_sync = true; - this->need_render = true; - this->render_control.polishItems(); -} - -void GuiRendererImpl::reinit_fbo_if_needed() { - assert(QThread::currentThread() == this->gui_rendering_setup_routines.get_ctx()->thread()); - - if (this->need_fbo_resize) { - this->fbo = std::make_unique(QSize(this->new_fbo_width, this->new_fbo_height), QOpenGLFramebufferObject::CombinedDepthStencil); - - // dirty workaround; texture id from our own implementation should be passed here - QQuickRenderTarget target = QQuickRenderTarget::fromOpenGLTexture(this->fbo->texture(), this->fbo->size()); - - this->window->setRenderTarget(target); - this->need_fbo_resize = false; - } - - assert(this->fbo); -} - -GuiRendererImpl::~GuiRendererImpl() { - // TODO: MAYBE: - // the this->ctx member frees the - // gl context even though that's SDL's job. - // - // the qt doc says that a native context isn't destroyed! - // but somehow it is lost or destroyed! - // https://doc.qt.io/qt-5/qopenglcontext.html#setNativeHandle -} - -GuiRendererImpl *GuiRendererImpl::impl(GuiRenderer *renderer) { - return renderer->impl.get(); -} - -GLuint GuiRendererImpl::render() { - GuiRenderingCtxActivator activate_render(this->gui_rendering_setup_routines); - - this->reinit_fbo_if_needed(); - - this->render_control.beginFrame(); - - // QQuickRenderControl::sync() must be called from the render thread while the gui thread is stopped. - if (this->need_sync) { - if (QCoreApplication::instance()->thread() != QThread::currentThread()) { - std::unique_lock lck{this->gui_guard}; - - if (this->need_sync) { - QCoreApplication::instance()->postEvent(this, new QEvent{QEvent::User}, INT_MAX); - - this->renderer_waiting_on_cond = true; - this->gui_locked_cond.wait(lck, [this] { return this->gui_locked; }); - this->renderer_waiting_on_cond = false; - - this->render_control.sync(); - - this->need_sync = false; - this->gui_locked = false; - - lck.unlock(); - this->gui_locked_cond.notify_one(); - } - } - else { - this->render_control.sync(); - } - } - - this->render_control.render(); - this->render_control.endFrame(); - - // this->window->resetOpenGLState(); - - return this->fbo->texture(); -} - -void GuiRendererImpl::make_sure_render_thread_unlocked() { - assert(QThread::currentThread() == QCoreApplication::instance()->thread()); - - if (this->need_sync && QThread::currentThread() != this->render_control.thread()) { - std::unique_lock lck{this->gui_guard}; - - if (this->renderer_waiting_on_cond) { - this->process_freeze(std::move(lck)); - QCoreApplication::instance()->removePostedEvents(this, QEvent::User); - } - } -} - -bool GuiRendererImpl::make_sure_render_thread_wont_sync() { - assert(QThread::currentThread() == QCoreApplication::instance()->thread()); - - if (this->need_sync && QThread::currentThread() != this->render_control.thread()) { - std::unique_lock lck{this->gui_guard}; - - if (this->renderer_waiting_on_cond) { - this->process_freeze(std::move(lck)); - QCoreApplication::instance()->removePostedEvents(this, QEvent::User); - assert(!this->need_sync); - } - else { - assert(this->need_sync); - this->need_sync = false; - return true; - } - } - - return false; -} - -void GuiRendererImpl::demand_sync() { - assert(QThread::currentThread() == QCoreApplication::instance()->thread()); - this->need_sync = true; -} - -bool GuiRendererImpl::event(QEvent *e) { - if (e->type() == QEvent::User) { - std::unique_lock lck{this->gui_guard}; - this->process_freeze(std::move(lck)); - return true; - } - else { - return this->QObject::event(e); - } -} - -void GuiRendererImpl::process_freeze(std::unique_lock lck) { - this->gui_locked = true; - - lck.unlock(); - this->gui_locked_cond.notify_one(); - - lck.lock(); - this->gui_locked_cond.wait(lck, [this] { return !this->gui_locked; }); -} - -EventHandlingQuickWindow *GuiRendererImpl::get_window() { - return &*this->window; -} - -void GuiRendererImpl::resize(const QSize &size) { - emit this->resized(size); -} - -TemporaryDisableGuiRendererSync::TemporaryDisableGuiRendererSync(GuiRendererImpl &renderer) : - renderer{renderer}, - need_sync{renderer.make_sure_render_thread_wont_sync()} { -} - -TemporaryDisableGuiRendererSync::~TemporaryDisableGuiRendererSync() { - if (this->need_sync) - renderer.demand_sync(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_renderer_impl.h b/libopenage/gui/guisys/private/gui_renderer_impl.h deleted file mode 100644 index 31c1330eea..0000000000 --- a/libopenage/gui/guisys/private/gui_renderer_impl.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#ifndef __APPLE__ -#ifdef _MSC_VER -#define NOMINMAX -#include -#endif //_MSC_VER -#include -#else // __APPLE__ -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "gui_rendering_setup_routines.h" - -struct SDL_Window; - -QT_FORWARD_DECLARE_CLASS(QOpenGLFramebufferObject) - -namespace qtsdl { - -class GuiRenderer; - -class EventHandlingQuickWindow : public QQuickWindow { - Q_OBJECT - -public: - explicit EventHandlingQuickWindow(QQuickRenderControl *render_control); - virtual ~EventHandlingQuickWindow(); - -public slots: - void on_input_event(std::atomic *processed, QEvent *event, bool only_if_grabbed); - void on_resized(const QSize &size); - -private: - // TODO: to remove when the proper focus for the foreign (that obtained from QWindow::fromWinId()) windows is implemented (Qt 5.6). - QQuickItem *focused_item; -}; - -/** - * Passes the native graphic context to Qt. - */ -class GuiRendererImpl : public QObject { - Q_OBJECT - -public: - explicit GuiRendererImpl(SDL_Window *window); - ~GuiRendererImpl(); - - static GuiRendererImpl *impl(GuiRenderer *renderer); - - /** - * @return texture ID where GUI was rendered - */ - GLuint render(); - - void resize(const QSize &size); - - EventHandlingQuickWindow *get_window(); - - /** - * When render thread is locked waiting for the gui thread to finish its current event and - * go to the high-priority 'freeze' event; but the gui thread can't finish the current event - * because it's going to lock the game-logic thread that will lock the render thread somehow. - * - * In this situation the gui thread should call this function to immediately process the 'freeze' - * event handler inside current event and remove the event from the gui queue. - * - * 'GuiRendererImpl::need_sync' is only set from the gui thread, so after the calling this function, - * we are fine for entire duration of the processing of the current event. - * - * If 'GuiRendererImpl::need_sync' is set, this function blocks until the render thread comes around - * to do the 'QQuickRenderControl::sync()'. If it's not good enough, it's possible to implement two - * separate functions to set 'GuiRendererImpl::need_sync' to false and then back to true. - */ - void make_sure_render_thread_unlocked(); - - /** - * Assures that the render thread won't try to stop the gui thread for syncing. - * - * Must be called from the gui thread. - * - * @return true if need_sync was set to false (you should restore it with the demand_sync()) - */ - bool make_sure_render_thread_wont_sync(); - - /** - * Sets 'GuiRendererImpl::need_sync' to true. - * - * Must be called from the gui thread. - */ - void demand_sync(); - -signals: - void resized(const QSize &size); - -private: - virtual bool event(QEvent *e) override; - - void process_freeze(std::unique_lock lck); - -private slots: - void on_scene_changed(); - -private: - /** - * If size changes, then create a new FBO for GUI rendering - */ - void reinit_fbo_if_needed(); - - /** - * Contains rendering context - * Use GuiRenderingCtxActivator to enable it - */ - GuiRenderingSetupRoutines gui_rendering_setup_routines; - - /** - * Contains scene graph of the GUI - */ - std::unique_ptr window; - - /** - * Object for sending render command to Qt - */ - QQuickRenderControl render_control; - - /** - * FBO where the GUI is rendered - */ - std::unique_ptr fbo; - - std::atomic new_fbo_width; - std::atomic new_fbo_height; - std::atomic need_fbo_resize; - - std::atomic need_sync; - std::atomic need_render; - - bool gui_locked; - std::mutex gui_guard; - std::condition_variable gui_locked_cond; - bool renderer_waiting_on_cond; -}; - -class TemporaryDisableGuiRendererSync { -public: - explicit TemporaryDisableGuiRendererSync(GuiRendererImpl &renderer); - ~TemporaryDisableGuiRendererSync(); - -private: - TemporaryDisableGuiRendererSync(const TemporaryDisableGuiRendererSync &) = delete; - TemporaryDisableGuiRendererSync &operator=(const TemporaryDisableGuiRendererSync &) = delete; - - GuiRendererImpl &renderer; - const bool need_sync; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_rendering_setup_routines.cpp b/libopenage/gui/guisys/private/gui_rendering_setup_routines.cpp deleted file mode 100644 index cfb6745438..0000000000 --- a/libopenage/gui/guisys/private/gui_rendering_setup_routines.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2017-2019 the openage authors. See copying.md for legal info. - -#include "gui_rendering_setup_routines.h" - -#include - -#include - -#include "gui_ctx_setup.h" - -namespace qtsdl { - -GuiRenderingSetupRoutines::GuiRenderingSetupRoutines(SDL_Window *window) { - try { - this->ctx_extraction_mode = std::make_unique(window); - } catch (const CtxExtractionException&) { - - qInfo() << "Falling back to separate render context for GUI"; - - try { - this->ctx_extraction_mode = std::make_unique(window); - } catch (const CtxExtractionException&) { - assert(false && "setting up context for GUI failed"); - } - } -} - -GuiRenderingSetupRoutines::~GuiRenderingSetupRoutines() = default; - -QOpenGLContext* GuiRenderingSetupRoutines::get_ctx() { - return this->ctx_extraction_mode->get_ctx(); -} - -void GuiRenderingSetupRoutines::pre_render() { - this->ctx_extraction_mode->pre_render(); -} - -void GuiRenderingSetupRoutines::post_render() { - this->ctx_extraction_mode->post_render(); -} - -GuiRenderingCtxActivator::GuiRenderingCtxActivator(GuiRenderingSetupRoutines &rendering_setup_routines) - : - rendering_setup_routines{&rendering_setup_routines} { - - this->rendering_setup_routines->pre_render(); -} - -GuiRenderingCtxActivator::~GuiRenderingCtxActivator() { - if (this->rendering_setup_routines) - this->rendering_setup_routines->post_render(); -} - -GuiRenderingCtxActivator::GuiRenderingCtxActivator(GuiRenderingCtxActivator&& o) - : - rendering_setup_routines{o.rendering_setup_routines} { - - o.rendering_setup_routines = nullptr; -} - -GuiRenderingCtxActivator& GuiRenderingCtxActivator::operator=(GuiRenderingCtxActivator&& o) { - this->rendering_setup_routines = o.rendering_setup_routines; - o.rendering_setup_routines = nullptr; - return *this; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_rendering_setup_routines.h b/libopenage/gui/guisys/private/gui_rendering_setup_routines.h deleted file mode 100644 index e392d70cb1..0000000000 --- a/libopenage/gui/guisys/private/gui_rendering_setup_routines.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -struct SDL_Window; - -QT_FORWARD_DECLARE_CLASS(QOpenGLContext) - -namespace qtsdl { - -class CtxExtractionMode; - -class GuiRenderingCtxActivator; - -/** - * Returns a GL context usable by Qt classes. - * Provides pre- and post-rendering functions to make the context usable for GUI rendering. - */ -class GuiRenderingSetupRoutines { -public: - explicit GuiRenderingSetupRoutines(SDL_Window *window); - ~GuiRenderingSetupRoutines(); - - QOpenGLContext* get_ctx(); - -private: - friend class GuiRenderingCtxActivator; - void pre_render(); - void post_render(); - - std::unique_ptr ctx_extraction_mode; -}; - -/** - * Prepares the context for rendering the GUI for one frame. - * Activator must be destroyed as soon as the GUI has executed its frame render call. - */ -class GuiRenderingCtxActivator { -public: - explicit GuiRenderingCtxActivator(GuiRenderingSetupRoutines &rendering_setup_routines); - ~GuiRenderingCtxActivator(); - - GuiRenderingCtxActivator(GuiRenderingCtxActivator&& o); - GuiRenderingCtxActivator& operator=(GuiRenderingCtxActivator&& o); - -private: - GuiRenderingCtxActivator(const GuiRenderingCtxActivator&) = delete; - GuiRenderingCtxActivator& operator=(const GuiRenderingCtxActivator&) = delete; - - GuiRenderingSetupRoutines *rendering_setup_routines; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_subtree_impl.cpp b/libopenage/gui/guisys/private/gui_subtree_impl.cpp deleted file mode 100644 index 5bfcb73fa9..0000000000 --- a/libopenage/gui/guisys/private/gui_subtree_impl.cpp +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_subtree_impl.h" -#include "gui_renderer_impl.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gui_engine_impl.h" -#include "../link/gui_item.h" -#include "../public/gui_subtree.h" -#include "gui_event_queue_impl.h" - -namespace qtsdl { - - -GuiSubtreeImpl::GuiSubtreeImpl(GuiRenderer *renderer, - GuiEventQueue *game_logic_updater, - GuiEngine *engine, - const QString &source, - const QString &rootdir) - : - QObject{}, - renderer{}, - engine{}, - root{} { - - QObject::connect( - &this->game_logic_callback, - &GuiCallback::process_blocking, - this, - &GuiSubtreeImpl::on_process_game_logic_callback_blocking, - Qt::DirectConnection - ); - - QObject::connect( - this, - &GuiSubtreeImpl::process_game_logic_callback_blocking, - &this->game_logic_callback, - &GuiCallback::process, - (QCoreApplication::instance()->thread() != QThread::currentThread() - ? Qt::BlockingQueuedConnection - : Qt::DirectConnection) - ); - - this->moveToThread(QCoreApplication::instance()->thread()); - this->attach_to(GuiEventQueueImpl::impl(game_logic_updater)); - this->attach_to(GuiRendererImpl::impl(renderer)); - this->attach_to(GuiEngineImpl::impl(engine), rootdir); - - // Should now be initialized by the engine-attaching - assert(this->root_component); - - // Need to queue the loading because some underlying game logic elements - // require the loop to be running (maybe some things that are created after - // the gui). - QMetaObject::invokeMethod(this->root_component.get(), - "loadUrl", Qt::QueuedConnection, - Q_ARG(QUrl, QUrl::fromLocalFile(source))); -} - -GuiSubtreeImpl::~GuiSubtreeImpl() = default; - -void GuiSubtreeImpl::onEngineReloaded() { - const QUrl source = this->root_component->url(); - - this->destroy_root(); - - this->root_component = std::make_unique(this->engine.get_qml_engine()); - - QObject::connect( - this->root_component.get(), - &QQmlComponent::statusChanged, - this, - &GuiSubtreeImpl::component_status_changed - ); - - this->root_component->loadUrl(source); -} - -void GuiSubtreeImpl::attach_to(GuiEventQueueImpl *game_logic_updater) { - this->game_logic_callback.moveToThread(game_logic_updater->get_thread()); -} - -void GuiSubtreeImpl::attach_to(GuiRendererImpl *renderer) { - assert(renderer); - - if (this->renderer) - QObject::disconnect(this->renderer, nullptr, this, nullptr); - - this->renderer = renderer; - - QObject::connect( - this->renderer, - &GuiRendererImpl::resized, - this, - &GuiSubtreeImpl::on_resized - ); - this->reparent_root(); -} - -void GuiSubtreeImpl::attach_to(GuiEngineImpl *engine_impl, const QString &root_dir) { - if (this->engine.has_subtree()) { - this->destroy_root(); - this->engine = GuiEngineImplConnection{}; - } - - this->root_component = std::make_unique(engine_impl->get_qml_engine()); - - QObject::connect( - this->root_component.get(), - &QQmlComponent::statusChanged, - this, - &GuiSubtreeImpl::component_status_changed - ); - - // operator = && - this->engine = GuiEngineImplConnection{this, engine_impl, root_dir}; - - this->root_component->moveToThread(QCoreApplication::instance()->thread()); -} - -void GuiSubtreeImpl::component_status_changed(QQmlComponent::Status status) { - if (QQmlComponent::Error == status) { - qCritical("%s", qUtf8Printable(this->root_component->errorString())); - return; - } - - if (QQmlComponent::Ready == status) { - assert(!this->root); - - this->root = qobject_cast(this->root_component->beginCreate(this->engine.rootContext())); - assert(this->root); - - this->init_persistent_items(); - - this->root_component->completeCreate(); - - this->reparent_root(); - } -} - -void GuiSubtreeImpl::on_resized(const QSize &size) { - if (this->root) - this->root->setSize(size); -} - -void GuiSubtreeImpl::on_process_game_logic_callback_blocking(const std::function &f) { - TemporaryDisableGuiRendererSync {*this->renderer}; - emit this->process_game_logic_callback_blocking(f); -} - -void GuiSubtreeImpl::init_persistent_items() { - auto persistent = this->root->findChildren(); - - for (auto ap : persistent) - ap->get_attachee()->set_game_logic_callback(&this->game_logic_callback); - - this->reloader.init_persistent_items(persistent); -} - -void GuiSubtreeImpl::reparent_root() { - if (this->root) { - QQuickWindow *window = this->renderer->get_window(); - - this->root->setParentItem(window->contentItem()); - this->root->setSize(QSize{window->width(), window->height()}); - } -} - -void GuiSubtreeImpl::destroy_root() { - if (this->root) { - this->root->setParent(nullptr); - this->root->setParentItem(nullptr); - this->root->deleteLater(); - this->root = nullptr; - } -} - -GuiEngineImplConnection::GuiEngineImplConnection() - : - subtree{}, - engine{} { -} - -GuiEngineImplConnection::GuiEngineImplConnection(GuiSubtreeImpl *subtree, - GuiEngineImpl *engine, - QString root_dir) - : - subtree{subtree}, - engine{engine}, - root_dir{std::move(root_dir)} { - - assert(this->subtree); - assert(this->engine); - - QObject::connect( - this->engine, - &GuiEngineImpl::reload, - this->subtree, - &GuiSubtreeImpl::onEngineReloaded - ); - - // add the directory so it can be watched for changes. - this->engine->add_root_dir_path(this->root_dir); -} - -GuiEngineImplConnection::~GuiEngineImplConnection() { - this->disconnect(); -} - -void GuiEngineImplConnection::disconnect() { - if (this->has_subtree()) { - assert(this->engine); - - QObject::disconnect( - this->engine, - &GuiEngineImpl::reload, - this->subtree, - &GuiSubtreeImpl::onEngineReloaded - ); - - if (not this->root_dir.isEmpty()) { - this->engine->remove_root_dir_path(this->root_dir); - } - } -} - -GuiEngineImplConnection::GuiEngineImplConnection(GuiEngineImplConnection &&cnx) noexcept - : - subtree{cnx.subtree}, - engine{cnx.engine} { - - cnx.subtree = nullptr; - cnx.engine = nullptr; -} - -GuiEngineImplConnection& GuiEngineImplConnection::operator=(GuiEngineImplConnection &&cnx) noexcept { - this->disconnect(); - - this->subtree = cnx.subtree; - this->engine = cnx.engine; - - cnx.subtree = nullptr; - cnx.engine = nullptr; - - return *this; -} - -bool GuiEngineImplConnection::has_subtree() const { - return this->subtree != nullptr; -} - -QQmlContext* GuiEngineImplConnection::rootContext() const { - assert(this->subtree); - assert(this->engine); - return this->engine->get_qml_engine()->rootContext(); -} - -QQmlEngine* GuiEngineImplConnection::get_qml_engine() const { - assert(this->subtree); - assert(this->engine); - return this->engine->get_qml_engine(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/gui_subtree_impl.h b/libopenage/gui/guisys/private/gui_subtree_impl.h deleted file mode 100644 index 6c737c11f1..0000000000 --- a/libopenage/gui/guisys/private/gui_subtree_impl.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include -#include - -#include "gui_callback.h" -#include "livereload/gui_live_reloader.h" - -QT_FORWARD_DECLARE_CLASS(QQuickItem) - -namespace qtsdl { - -class GuiRenderer; -class GuiRendererImpl; -class GuiEventQueue; -class GuiEventQueueImpl; -class GuiEngine; -class GuiEngineImpl; -class GuiSubtreeImpl; - -class GuiEngineImplConnection { -public: - GuiEngineImplConnection(); - explicit GuiEngineImplConnection(GuiSubtreeImpl *subtree, - GuiEngineImpl *engine, - QString root_dir); - ~GuiEngineImplConnection(); - - GuiEngineImplConnection(GuiEngineImplConnection &&cnx) noexcept; - GuiEngineImplConnection& operator=(GuiEngineImplConnection &&cnx) noexcept; - - bool has_subtree() const; - - QQmlContext* rootContext() const; - QQmlEngine* get_qml_engine() const; - -private: - GuiEngineImplConnection(const GuiEngineImplConnection &cnx) = delete; - GuiEngineImplConnection& operator=(const GuiEngineImplConnection &cnx) = delete; - - void disconnect(); - - GuiSubtreeImpl *subtree; - GuiEngineImpl *engine; - QString root_dir; -}; - - -class GuiSubtreeImpl : public QObject { - Q_OBJECT - -public: - explicit GuiSubtreeImpl(GuiRenderer *renderer, - GuiEventQueue *game_logic_updater, - GuiEngine *engine, - const QString &source, - const QString &rootdir); - virtual ~GuiSubtreeImpl(); - -public slots: - void onEngineReloaded(); - - void attach_to(GuiEventQueueImpl *game_logic_updater); - void attach_to(GuiRendererImpl *renderer); - void attach_to(GuiEngineImpl *engine, const QString &source); - -private slots: - void component_status_changed(QQmlComponent::Status status); - void on_resized(const QSize &size); - void on_process_game_logic_callback_blocking(const std::function &f); - -signals: - void process_game_logic_callback_blocking(const std::function &f); - -private: - void init_persistent_items(); - - void reparent_root(); - void destroy_root(); - - GuiRendererImpl *renderer; - GuiEngineImplConnection engine; - GuiLiveReloader reloader; - - GuiCallback game_logic_callback; - - std::unique_ptr root_component; - QQuickItem *root; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher.cpp b/libopenage/gui/guisys/private/livereload/recursive_directory_watcher.cpp deleted file mode 100644 index 6e3422dc0c..0000000000 --- a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include "recursive_directory_watcher.h" - -#include -#include - -#include "recursive_directory_watcher_worker.h" - -namespace qtsdl { - -RecursiveDirectoryWatcher::RecursiveDirectoryWatcher(QObject *parent) - : - QObject{parent} { - - QSemaphore wait_worker_started; - - this->worker = std::async(std::launch::async, [this, &wait_worker_started] { - QEventLoop loop; - QObject::connect(this, &RecursiveDirectoryWatcher::quit, &loop, &QEventLoop::quit); - - RecursiveDirectoryWatcherWorker watcher; - QObject::connect(&watcher, &RecursiveDirectoryWatcherWorker::changeDetected, this, &RecursiveDirectoryWatcher::changeDetected); - QObject::connect(this, &RecursiveDirectoryWatcher::rootDirsPathsChanged, &watcher, &RecursiveDirectoryWatcherWorker::onRootDirsPathsChanged); - - wait_worker_started.release(); - - loop.exec(); - }); - - wait_worker_started.acquire(); -} - -RecursiveDirectoryWatcher::~RecursiveDirectoryWatcher() { - emit this->quit(); - this->worker.wait(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher.h b/libopenage/gui/guisys/private/livereload/recursive_directory_watcher.h deleted file mode 100644 index d55e7b8f99..0000000000 --- a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include -#include - -namespace qtsdl { - -/** - * Emits a signal when anything changes in the directories. - */ -class RecursiveDirectoryWatcher : public QObject { - Q_OBJECT - -public: - explicit RecursiveDirectoryWatcher(QObject *parent = nullptr); - virtual ~RecursiveDirectoryWatcher(); - -signals: - void changeDetected(); - void rootDirsPathsChanged(const QStringList&); - void quit(); - -private: - std::future worker; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher_worker.cpp b/libopenage/gui/guisys/private/livereload/recursive_directory_watcher_worker.cpp deleted file mode 100644 index ff8e9f7242..0000000000 --- a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher_worker.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include "recursive_directory_watcher_worker.h" - -#include - -#include -#include - -namespace qtsdl { - -namespace { -const int batch_ms = 100; -} - -RecursiveDirectoryWatcherWorker::RecursiveDirectoryWatcherWorker() - : - QObject{} { - - this->batching_timer.setInterval(batch_ms); - this->batching_timer.setSingleShot(true); - QObject::connect(&this->batching_timer, &QTimer::timeout, this, &RecursiveDirectoryWatcherWorker::changeDetected); - QObject::connect(&this->batching_timer, &QTimer::timeout, this, &RecursiveDirectoryWatcherWorker::restartWatching); -} - -void RecursiveDirectoryWatcherWorker::onRootDirsPathsChanged(const QStringList &root_dirs_paths) { - if (this->root_dirs_paths != root_dirs_paths) { - this->root_dirs_paths = root_dirs_paths; - this->restartWatching(); - } -} - -namespace { -QStringList collect_entries_to_watch(const QStringList &root_dirs_paths) { - QStringList root_dirs_paths_no_duplicates = root_dirs_paths; - root_dirs_paths_no_duplicates.removeDuplicates(); - - QStringList entries_to_watch; - - std::for_each(std::begin(root_dirs_paths_no_duplicates), std::end(root_dirs_paths_no_duplicates), [&entries_to_watch] (const QString& root_dir_path) { - QDirIterator it{root_dir_path, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks}; - - while (it.hasNext()) { - entries_to_watch.append(it.next()); - } - }); - - return entries_to_watch; -} -} - -void RecursiveDirectoryWatcherWorker::restartWatching() { - this->restart_watching(collect_entries_to_watch(this->root_dirs_paths)); -} - -void RecursiveDirectoryWatcherWorker::restart_watching(const QStringList &entries_to_watch) { - this->watcher.reset(); - this->watcher = std::make_unique(); - - QObject::connect(&*this->watcher, &QFileSystemWatcher::directoryChanged, this, &RecursiveDirectoryWatcherWorker::onEntryChanged); - - if (entries_to_watch.empty()) - qWarning() << "RecursiveDirectoryWatcheWorker hasn't found any files to watch."; - else - this->watcher->addPaths(entries_to_watch); -} - -void RecursiveDirectoryWatcherWorker::onEntryChanged() { - if (!this->batching_timer.isActive()) - this->batching_timer.start(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher_worker.h b/libopenage/gui/guisys/private/livereload/recursive_directory_watcher_worker.h deleted file mode 100644 index 88af26d97d..0000000000 --- a/libopenage/gui/guisys/private/livereload/recursive_directory_watcher_worker.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include -#include -#include - -namespace qtsdl { - -/** - * Emits a signal when anything changes in the directories. - */ -class RecursiveDirectoryWatcherWorker : public QObject { - Q_OBJECT - -public: - RecursiveDirectoryWatcherWorker(); - -signals: - void changeDetected(); - -public slots: - void onRootDirsPathsChanged(const QStringList &root_dirs_paths); - void restartWatching(); - -private slots: - void onEntryChanged(); - -private: - void restart_watching(const QStringList &entries_to_watch); - - /** - * Actual watcher. - * Its event processing and destruction has to be in the same separate thread. - */ - std::unique_ptr watcher; - - /** - * Waits to glue multiple changes into one event. - */ - QTimer batching_timer; - - QStringList root_dirs_paths; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/opengl_debug_logger.cpp b/libopenage/gui/guisys/private/opengl_debug_logger.cpp deleted file mode 100644 index b61bc58f20..0000000000 --- a/libopenage/gui/guisys/private/opengl_debug_logger.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#include "opengl_debug_logger.h" - -#include -#include -#include - -#ifdef __APPLE__ -// from https://www.khronos.org/registry/OpenGL/api/GL/glext.h -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#define GL_DEBUG_TYPE_ERROR 0x824C -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#endif - -namespace qtsdl { - -gl_debug_parameters get_current_opengl_debug_parameters(QOpenGLContext ¤t_source_context) { - gl_debug_parameters params{}; - - if (QOpenGLVersionFunctionsFactory::get(¤t_source_context)) - if ((params.is_debug = current_source_context.format().options().testFlag(QSurfaceFormat::DebugContext))) { - glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, ¶ms.callback); - params.synchronous = glIsEnabled(GL_DEBUG_OUTPUT_SYNCHRONOUS); - } - - return params; -} - -void apply_opengl_debug_parameters(gl_debug_parameters params, QOpenGLContext ¤t_dest_context) { - if (params.is_debug && params.callback) { - if (auto functions = QOpenGLVersionFunctionsFactory::get(¤t_dest_context)) { - functions->initializeOpenGLFunctions(); - - functions->glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_FALSE); - - functions->glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0, nullptr, GL_TRUE); - functions->glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DONT_CARE, 0, nullptr, GL_TRUE); - - functions->glDebugMessageCallback((GLDEBUGPROC)params.callback, nullptr); - - if (params.synchronous) - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - } - } -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/opengl_debug_logger.h b/libopenage/gui/guisys/private/opengl_debug_logger.h deleted file mode 100644 index 7fda1cad80..0000000000 --- a/libopenage/gui/guisys/private/opengl_debug_logger.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -QT_FORWARD_DECLARE_CLASS(QOpenGLContext) - -namespace qtsdl { -struct gl_debug_parameters { - /** - * True if the GL context is a debug context - */ - bool is_debug; - - /** - * Function that GL context uses to report debug messages - */ - GLvoid *callback; - - /** - * True if debug callback calling method is chosen to be synchronous - */ - bool synchronous; -}; - -/** - * Get debugging settings of the current GL context - * - * @param current_source_context current GL context - * @return debugging settings - */ -gl_debug_parameters get_current_opengl_debug_parameters(QOpenGLContext ¤t_source_context); - -/** - * Create a GL logger in the current GL context - * - * @param params debugging settings - * @param current_dest_context current GL context to which parameters will be applied - */ -void apply_opengl_debug_parameters(gl_debug_parameters params, QOpenGLContext ¤t_dest_context); - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/platforms/context_extraction.h b/libopenage/gui/guisys/private/platforms/context_extraction.h deleted file mode 100644 index baf13818bb..0000000000 --- a/libopenage/gui/guisys/private/platforms/context_extraction.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include -#include - -struct SDL_Window; - -namespace qtsdl { - -/** - * @return current context (or null) and id of the window - */ -std::tuple extract_native_context(SDL_Window *window); - -/** - * @return current context (or null) and function to get it back to the window - */ -std::tuple> extract_native_context_and_switchback_func(SDL_Window *window); - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/platforms/context_extraction_cocoa.mm b/libopenage/gui/guisys/private/platforms/context_extraction_cocoa.mm deleted file mode 100644 index 076924d8af..0000000000 --- a/libopenage/gui/guisys/private/platforms/context_extraction_cocoa.mm +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include - -#include "context_extraction.h" - -#include - -#include "SDL_syswm.h" -#import - -namespace qtsdl { - -std::tuple extract_native_context(SDL_Window *window) { - - assert(window); - - NSOpenGLContext *current_context = [NSOpenGLContext currentContext]; - assert(current_context); - - NSView *view = nullptr; - - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); - - - if (SDL_GetWindowWMInfo(window, &wm_info)) { - NSWindow *ns_window = wm_info.info.cocoa.window; - view = [ns_window contentView]; - assert(view); - } - return std::make_tuple(QVariant::fromValue(QCocoaNativeContext(current_context)), reinterpret_cast(view)); -} - -std::tuple> extract_native_context_and_switchback_func(SDL_Window *window) { - assert(window); - - NSOpenGLContext *current_context = [NSOpenGLContext currentContext]; - assert(current_context); - - NSView *view = nullptr; - - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); - - if (SDL_GetWindowWMInfo(window, &wm_info)) { - NSWindow *ns_window = wm_info.info.cocoa.window; - view = [ns_window contentView]; - assert(view); - - return std::make_tuple(QVariant::fromValue(QCocoaNativeContext(current_context)), [current_context] { - [current_context makeCurrentContext]; - }); - } - - return std::tuple>{}; -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/platforms/context_extraction_win32.cpp b/libopenage/gui/guisys/private/platforms/context_extraction_win32.cpp deleted file mode 100644 index 86aba09703..0000000000 --- a/libopenage/gui/guisys/private/platforms/context_extraction_win32.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#include - -#include -#include "context_extraction.h" - -#include -#include -#include - -namespace qtsdl { - -std::tuple extract_native_context(SDL_Window *window) { - assert(window); - - HGLRC current_context; - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); - if (SDL_GetWindowWMInfo(window, &wm_info)) { - current_context = wglGetCurrentContext(); - assert(current_context); - } - QWGLNativeContext nativeContext(current_context, wm_info.info.win.window); - return {QVariant::fromValue(nativeContext), reinterpret_cast(wm_info.info.win.window)}; -} - -std::tuple> extract_native_context_and_switchback_func(SDL_Window *window) { - assert(window); - - HGLRC current_context; - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); - if (SDL_GetWindowWMInfo(window, &wm_info)) { - current_context = wglGetCurrentContext(); - assert(current_context); - - return std::make_tuple(QVariant::fromValue(QWGLNativeContext(current_context, wm_info.info.win.window)), [wm_info, current_context] { - wglMakeCurrent(wm_info.info.win.hdc, current_context); - }); - } - - return std::tuple>{}; -} - - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/private/platforms/context_extraction_x11.cpp b/libopenage/gui/guisys/private/platforms/context_extraction_x11.cpp deleted file mode 100644 index e320c9b6e4..0000000000 --- a/libopenage/gui/guisys/private/platforms/context_extraction_x11.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include - -#include "context_extraction.h" - -// #include -#include -#include - -// DO NOT INCLUDE ANYTHING HERE, X11 HEADERS BREAK STUFF - -namespace qtsdl { - -// std::tuple extract_native_context(SDL_Window *window) { -// assert(window); - -// GLXContext current_context = nullptr; -// SDL_SysWMinfo wm_info; -// SDL_VERSION(&wm_info.version); - -// if (SDL_GetWindowWMInfo(window, &wm_info)) { -// assert(wm_info.info.x11.display); - -// current_context = glXGetCurrentContext(); -// assert(current_context); - -// return std::make_tuple( -// QVariant::fromValue( -// QGLXNativeContext(current_context, -// wm_info.info.x11.display, -// wm_info.info.x11.window)), -// wm_info.info.x11.window -// ); -// } - -// return std::tuple{}; -// } - -// std::tuple> extract_native_context_and_switchback_func(SDL_Window *window) { -// assert(window); - -// GLXContext current_context; -// SDL_SysWMinfo wm_info; -// SDL_VERSION(&wm_info.version); - -// if (SDL_GetWindowWMInfo(window, &wm_info)) { -// assert(wm_info.info.x11.display); - -// current_context = glXGetCurrentContext(); -// assert(current_context); - -// return std::make_tuple(QVariant::fromValue(QGLXNativeContext(current_context, wm_info.info.x11.display, wm_info.info.x11.window)), [wm_info, current_context] { -// glXMakeCurrent(wm_info.info.x11.display, wm_info.info.x11.window, current_context); -// }); -// } - -// return std::tuple>{}; -// } - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_application.cpp b/libopenage/gui/guisys/public/gui_application.cpp deleted file mode 100644 index 1b7a511095..0000000000 --- a/libopenage/gui/guisys/public/gui_application.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include - -#include "../public/gui_application.h" - -#include "../private/gui_application_impl.h" - -namespace qtsdl { - -GuiApplication::GuiApplication() - : - application{GuiApplicationImpl::get()} { -} - -GuiApplication::GuiApplication(std::shared_ptr application) - : - application{application} { -} - -GuiApplication::~GuiApplication() = default; - -void GuiApplication::processEvents() { - this->application->processEvents(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_application.h b/libopenage/gui/guisys/public/gui_application.h deleted file mode 100644 index 6b64e6b111..0000000000 --- a/libopenage/gui/guisys/public/gui_application.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace qtsdl { - -class GuiApplicationImpl; - -/** - * Houses gui logic event queue. - */ -class GuiApplication { -public: - GuiApplication(); - GuiApplication(std::shared_ptr application); - ~GuiApplication(); - - void processEvents(); - -private: - std::shared_ptr application; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_engine.cpp b/libopenage/gui/guisys/public/gui_engine.cpp deleted file mode 100644 index 689a4ff87f..0000000000 --- a/libopenage/gui/guisys/public/gui_engine.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "../public/gui_engine.h" - -#include "../private/gui_engine_impl.h" - -namespace qtsdl { - -GuiEngine::GuiEngine(GuiRenderer *renderer, const std::vector &image_providers, GuiSingletonItemsInfo *singleton_items_info) - : - impl{std::make_unique(renderer, image_providers, singleton_items_info)} { -} - -GuiEngine::~GuiEngine() = default; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_engine.h b/libopenage/gui/guisys/public/gui_engine.h deleted file mode 100644 index 153ceb11ab..0000000000 --- a/libopenage/gui/guisys/public/gui_engine.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -namespace qtsdl { - -class GuiRenderer; -class GuiImageProvider; -class GuiEngineImpl; -class GuiSingletonItemsInfo; - -/** - * Represents one QML execution environment. - */ -class GuiEngine { -public: - explicit GuiEngine(GuiRenderer *renderer, - const std::vector &image_providers = std::vector(), - GuiSingletonItemsInfo *singleton_items_info = nullptr); - ~GuiEngine(); - -private: - friend class GuiEngineImpl; - std::unique_ptr impl; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_event_queue.cpp b/libopenage/gui/guisys/public/gui_event_queue.cpp deleted file mode 100644 index 4b9866c1a9..0000000000 --- a/libopenage/gui/guisys/public/gui_event_queue.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "../public/gui_event_queue.h" - -#include "../private/gui_event_queue_impl.h" - -namespace qtsdl { - -GuiEventQueue::GuiEventQueue() - : - impl{std::make_unique()} { -} - -GuiEventQueue::~GuiEventQueue() = default; - -void GuiEventQueue::process_callbacks() { - this->impl->process_callbacks(); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_event_queue.h b/libopenage/gui/guisys/public/gui_event_queue.h deleted file mode 100644 index d7b6076e9a..0000000000 --- a/libopenage/gui/guisys/public/gui_event_queue.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace qtsdl { - -class GuiEventQueueImpl; - -/** - * Provides synchronization with some game thread. - */ -class GuiEventQueue { -public: - explicit GuiEventQueue(); - ~GuiEventQueue(); - - void process_callbacks(); - -private: - friend class GuiEventQueueImpl; - std::unique_ptr impl; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_image_provider.cpp b/libopenage/gui/guisys/public/gui_image_provider.cpp deleted file mode 100644 index 961a0f3c20..0000000000 --- a/libopenage/gui/guisys/public/gui_image_provider.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "../public/gui_image_provider.h" - -#include "../private/gui_image_provider_impl.h" - -namespace qtsdl { - -GuiImageProvider::GuiImageProvider(std::unique_ptr impl) - : - impl{impl.release(), std::default_delete()} { -} - -GuiImageProvider::~GuiImageProvider() = default; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_image_provider.h b/libopenage/gui/guisys/public/gui_image_provider.h deleted file mode 100644 index 6a5e074769..0000000000 --- a/libopenage/gui/guisys/public/gui_image_provider.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -namespace qtsdl { - -class GuiImageProviderImpl; - -class GuiImageProvider { -public: - explicit GuiImageProvider(std::unique_ptr impl); - ~GuiImageProvider(); - -private: - friend class GuiImageProviderImpl; - std::unique_ptr> impl; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_input.cpp b/libopenage/gui/guisys/public/gui_input.cpp deleted file mode 100644 index c2e007d944..0000000000 --- a/libopenage/gui/guisys/public/gui_input.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "../public/gui_input.h" - -#include "../private/gui_input_impl.h" - -namespace qtsdl { - -GuiInput:: GuiInput(GuiRenderer *renderer, GuiEventQueue *game_logic_updater) - : - impl{std::make_unique(renderer, game_logic_updater)} { -} - -GuiInput::~GuiInput() = default; - -bool GuiInput::process(SDL_Event *event) { - return this->impl->process(event); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_input.h b/libopenage/gui/guisys/public/gui_input.h deleted file mode 100644 index 74e8adb118..0000000000 --- a/libopenage/gui/guisys/public/gui_input.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -namespace qtsdl { - -class GuiRenderer; -class GuiEventQueue; -class GuiInputImpl; - -/** - * Converts SDL input events into Qt events. - */ -class GuiInput { -public: - explicit GuiInput(GuiRenderer *renderer, GuiEventQueue *game_logic_updater); - ~GuiInput(); - - /** - * Returns true if the event was accepted. - */ - bool process(SDL_Event *event); - -private: - friend class GuiInputImpl; - std::unique_ptr impl; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_property_map.cpp b/libopenage/gui/guisys/public/gui_property_map.cpp deleted file mode 100644 index b52b3a31b3..0000000000 --- a/libopenage/gui/guisys/public/gui_property_map.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "gui_property_map.h" - -#include -#include -#include -#include - -#include -#include - -#include - -#include "../link/gui_property_map_impl.h" - -namespace qtsdl { - -GuiPropertyMap::GuiPropertyMap() : - impl{std::make_unique()} { - assert(QCoreApplication::instance()); -} - -GuiPropertyMap::~GuiPropertyMap() = default; - -namespace { -template -T getter(const QObject &map, const char *name) { - auto v = map.property(name); - - if (!v.isValid()) - return T(); - - using namespace std::string_literals; - - if (!v.canConvert()) - throw std::runtime_error("Can't interpret a property '"s + name + "' of type '"s + v.typeName() + "' as '"s + typeid(T).name() + "'."s); - - return v.value(); -} - -template -void setter(QObject &map, const char *name, T v) { - map.setProperty(name, QVariant::fromValue(v)); -} - -template <> -void setter(QObject &map, const char *name, const char *v) { - map.setProperty(name, v); -} - -std::vector strings_to_vector(const QStringList &strings) { - std::vector result(strings.size()); - std::transform(std::begin(strings), std::end(strings), std::begin(result), [](const QString &s) { return s.toStdString(); }); - - return result; -} - -QStringList vector_to_strings(const std::vector &v) { - QStringList strings; - std::transform(std::begin(v), std::end(v), std::back_inserter(strings), [](const std::string &s) { return QString::fromStdString(s); }); - - return strings; -} -} // namespace - -template <> -bool GuiPropertyMap::getv(const char *name) const { - return getter(*this->impl, name); -} - -template <> -void GuiPropertyMap::setv(const char *name, bool v) { - setter(*this->impl, name, v); -} - -template <> -int GuiPropertyMap::getv(const char *name) const { - return getter(*this->impl, name); -} - -template <> -void GuiPropertyMap::setv(const char *name, int v) { - setter(*this->impl, name, v); -} - -template <> -double GuiPropertyMap::getv(const char *name) const { - return getter(*this->impl, name); -} - -template <> -void GuiPropertyMap::setv(const char *name, double v) { - setter(*this->impl, name, v); -} - -template <> -std::string GuiPropertyMap::getv(const char *name) const { - return getter(*this->impl, name).toStdString(); -} - -template <> -void GuiPropertyMap::setv(const char *name, const std::string &v) { - setter(*this->impl, name, QString::fromStdString(v)); -} - -template <> -void GuiPropertyMap::setv(const char *name, const char *v) { - setter(*this->impl, name, v); -} - -template <> -std::vector GuiPropertyMap::getv>(const char *name) const { - return strings_to_vector(getter(*this->impl, name)); -} - -template <> -void GuiPropertyMap::setv &>(const char *name, const std::vector &v) { - setter(*this->impl, name, vector_to_strings(v)); -} - -template <> -QString GuiPropertyMap::getv(const char *name) const { - return getter(*this->impl, name); -} - -template <> -void GuiPropertyMap::setv(const char *name, const QString &v) { - setter(*this->impl, name, v); -} - -template <> -QStringList GuiPropertyMap::getv(const char *name) const { - return getter(*this->impl, name); -} - -template <> -void GuiPropertyMap::setv(const char *name, const QStringList &v) { - setter(*this->impl, name, v); -} - -void GuiPropertyMap::setv(const char *name, const std::string &v) { - this->setv(name, v); -} - -void GuiPropertyMap::setv(const std::string &name, const std::string &v) { - this->setv(name.c_str(), v); -} - -void GuiPropertyMap::setv(const char *name, const std::vector &v) { - this->setv &>(name, v); -} - -void GuiPropertyMap::setv(const std::string &name, const std::vector &v) { - this->setv &>(name.c_str(), v); -} - -std::vector GuiPropertyMap::get_csv(const char *name) const { - return strings_to_vector(getter(*this->impl, name).split(QRegularExpression("\\s*,\\s*"))); -} - -void GuiPropertyMap::set_csv(const char *name, const std::vector &v) { - setter(*this->impl, name, vector_to_strings(v).join(", ")); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_property_map.h b/libopenage/gui/guisys/public/gui_property_map.h deleted file mode 100644 index 7c67238027..0000000000 --- a/libopenage/gui/guisys/public/gui_property_map.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -namespace qtsdl { - -class GuiPropertyMapImpl; - -struct GuiPropertyMap { - GuiPropertyMap(); - ~GuiPropertyMap(); - - template - T getv(const char *name) const; - - template - T getv(const std::string &name) const { - return this->getv(name.c_str()); - } - - std::vector get_csv(const char *name) const; - - std::vector get_csv(const std::string &name) const { - return this->get_csv(name.c_str()); - } - - template - void setv(const char *name, T v); - - template - void setv(const std::string &name, T v) { - this->setv(name.c_str(), v); - } - - void set_csv(const char *name, const std::vector &v); - - void set_csv(const std::string &name, const std::vector &v) { - this->set_csv(name.c_str(), v); - } - - void setv(const char *name, const std::string &v); - void setv(const std::string &name, const std::string &v); - - void setv(const char *name, const std::vector &v); - void setv(const std::string &name, const std::vector &v); - - std::unique_ptr impl; -}; - -template<> -bool GuiPropertyMap::getv(const char *name) const; - -template<> -void GuiPropertyMap::setv(const char *name, bool v); - -template<> -int GuiPropertyMap::getv(const char *name) const; - -template<> -void GuiPropertyMap::setv(const char *name, int v); - -template<> -double GuiPropertyMap::getv(const char *name) const; - -template<> -void GuiPropertyMap::setv(const char *name, double v); - -template<> -std::string GuiPropertyMap::getv(const char *name) const; - -template<> -void GuiPropertyMap::setv(const char *name, const std::string &v); - -template<> -void GuiPropertyMap::setv(const char *name, const char *v); - -template<> -std::vector GuiPropertyMap::getv>(const char *name) const; - -template<> -void GuiPropertyMap::setv&>(const char *name, const std::vector &v); - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_renderer.cpp b/libopenage/gui/guisys/public/gui_renderer.cpp deleted file mode 100644 index 7fb182f0b0..0000000000 --- a/libopenage/gui/guisys/public/gui_renderer.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "../public/gui_renderer.h" - -#include - -#include "../private/gui_renderer_impl.h" - -namespace qtsdl { - -GuiRenderer::GuiRenderer(SDL_Window *window) - : - impl{std::make_unique(window)} { -} - -GuiRenderer::~GuiRenderer() = default; - -GLuint GuiRenderer::render() { - return this->impl->render(); -} - -void GuiRenderer::resize(int w, int h) { - this->impl->resize(QSize{w, h}); -} - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_renderer.h b/libopenage/gui/guisys/public/gui_renderer.h deleted file mode 100644 index 7139dee405..0000000000 --- a/libopenage/gui/guisys/public/gui_renderer.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#ifndef __APPLE__ -#ifdef _MSC_VER -#define NOMINMAX -#include -#endif //_MSC_VER -#include -#else // __APPLE__ -#include -#endif - -struct SDL_Window; - -namespace qtsdl { - -class GuiRendererImpl; - -/** - * Passes the native graphic context to Qt. - */ -class GuiRenderer { -public: - // TODO: allow FBO variant - explicit GuiRenderer(SDL_Window *window); - ~GuiRenderer(); - - GLuint render(); - void resize(int w, int h); - -private: - friend class GuiRendererImpl; - std::unique_ptr impl; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_singleton_items_info.h b/libopenage/gui/guisys/public/gui_singleton_items_info.h deleted file mode 100644 index 1889b4c2c0..0000000000 --- a/libopenage/gui/guisys/public/gui_singleton_items_info.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -namespace qtsdl { - -/** - * Accessible during creation of any singleton QML item. - */ -class GuiSingletonItemsInfo { -}; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_subtree.cpp b/libopenage/gui/guisys/public/gui_subtree.cpp deleted file mode 100644 index 00abcedab1..0000000000 --- a/libopenage/gui/guisys/public/gui_subtree.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_subtree.h" - -#include "../private/gui_subtree_impl.h" - -namespace qtsdl { - -GuiSubtree::GuiSubtree(GuiRenderer *renderer, - GuiEventQueue *game_logic_updater, - GuiEngine *engine, - const std::string &source, - const std::string &rootdir) - : - impl{std::make_unique( - renderer, - game_logic_updater, - engine, - QString::fromStdString(source), - QString::fromStdString(rootdir) - )} {} - -GuiSubtree::~GuiSubtree() = default; - -} // namespace qtsdl diff --git a/libopenage/gui/guisys/public/gui_subtree.h b/libopenage/gui/guisys/public/gui_subtree.h deleted file mode 100644 index ffd4141b2a..0000000000 --- a/libopenage/gui/guisys/public/gui_subtree.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - - -namespace qtsdl { - -class GuiRenderer; -class GuiEventQueue; -class GuiEngine; -class GuiSubtreeImpl; - - -/** - * A root item that loads its code from source url. - * - * rootdir is the qml file root folder which is watched for changes. - */ -class GuiSubtree { -public: - explicit GuiSubtree(GuiRenderer *renderer, - GuiEventQueue *game_logic_updater, - GuiEngine *engine, - const std::string &source, - const std::string &rootdir); - - ~GuiSubtree(); - -private: - friend class GuiSubtreeImpl; - std::unique_ptr impl; -}; - -} // namespace qtsdl diff --git a/libopenage/gui/integration/CMakeLists.txt b/libopenage/gui/integration/CMakeLists.txt deleted file mode 100644 index 0bb272b5c5..0000000000 --- a/libopenage/gui/integration/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory("private") -add_subdirectory("public") diff --git a/libopenage/gui/integration/private/CMakeLists.txt b/libopenage/gui/integration/private/CMakeLists.txt deleted file mode 100644 index 97f03fc4f4..0000000000 --- a/libopenage/gui/integration/private/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_sources(libopenage - gui_filled_texture_handles.cpp - gui_game_spec_image_provider_by_filename_impl.cpp - gui_game_spec_image_provider_by_graphic_id_impl.cpp - gui_game_spec_image_provider_by_id_impl.cpp - gui_game_spec_image_provider_by_terrain_id_impl.cpp - gui_game_spec_image_provider_impl.cpp - gui_image_provider_link.cpp - gui_log.cpp - gui_make_standalone_subtexture.cpp - gui_standalone_subtexture.cpp - gui_texture.cpp - gui_texture_factory.cpp - gui_texture_handle.cpp -) diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_filename_impl.cpp b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_filename_impl.cpp deleted file mode 100644 index 216422e5ba..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_filename_impl.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "gui_game_spec_image_provider_by_filename_impl.h" - -#include "../../../error/error.h" - -#include "../../../gamestate/old/game_spec.h" - -namespace openage::gui { - -GuiGameSpecImageProviderByFilenameImpl::GuiGameSpecImageProviderByFilenameImpl(qtsdl::GuiEventQueue *render_updater) - : - GuiGameSpecImageProviderImpl{render_updater} { -} - -GuiGameSpecImageProviderByFilenameImpl::~GuiGameSpecImageProviderByFilenameImpl() = default; - -const char* GuiGameSpecImageProviderByFilenameImpl::id() { - return "by-filename"; -} - -const char* GuiGameSpecImageProviderByFilenameImpl::get_id() const { - return GuiGameSpecImageProviderByFilenameImpl::id(); -} - -TextureHandle GuiGameSpecImageProviderByFilenameImpl::get_texture_handle(const QString &id) { - ENSURE(this->loaded_game_spec, "trying to actually get a texture from a non-loaded spec"); - - auto filename = id.section(".", 0, -2); - auto subid_str = id.section(".", -1, -1); - - bool ok = false; - const int subid = subid_str.toInt(&ok); - - if (not filename.isEmpty() and ok) { - auto tex = this->loaded_game_spec->get_texture(filename.toStdString()); - - if (tex != nullptr) { - return TextureHandle{tex, subid}; - } - else { - return this->get_missing_texture(); - } - } else { - qWarning("Invalid texture id: 'image://%s/%s'. Example formatting: 'image://%s/myfile.png.18'.", this->get_id(), qUtf8Printable(id), this->get_id()); - return this->get_missing_texture(); - } -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_filename_impl.h b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_filename_impl.h deleted file mode 100644 index 0def78ae82..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_filename_impl.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gui_game_spec_image_provider_impl.h" - -namespace openage { -namespace gui { - -/** - * Exposes game textures to the Qt by their file name. - * - * Id has a form of . where is an integer. - */ -class GuiGameSpecImageProviderByFilenameImpl : public GuiGameSpecImageProviderImpl { -public: - explicit GuiGameSpecImageProviderByFilenameImpl(qtsdl::GuiEventQueue *render_updater); - virtual ~GuiGameSpecImageProviderByFilenameImpl(); - - static const char* id(); - -private: - virtual const char* get_id() const override; - virtual TextureHandle get_texture_handle(const QString &id) override; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_graphic_id_impl.cpp b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_graphic_id_impl.cpp deleted file mode 100644 index ede6e5ef21..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_graphic_id_impl.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "gui_game_spec_image_provider_by_graphic_id_impl.h" - -#include "../../../error/error.h" - -#include "../../../gamestate/old/game_spec.h" - -namespace openage::gui { - -GuiGameSpecImageProviderByGraphicIdImpl::GuiGameSpecImageProviderByGraphicIdImpl(qtsdl::GuiEventQueue *render_updater) - : - GuiGameSpecImageProviderByIdImpl{render_updater} { -} - -GuiGameSpecImageProviderByGraphicIdImpl::~GuiGameSpecImageProviderByGraphicIdImpl() = default; - -const char* GuiGameSpecImageProviderByGraphicIdImpl::id() { - return "by-graphic-id"; -} - -const char* GuiGameSpecImageProviderByGraphicIdImpl::get_id() const { - return GuiGameSpecImageProviderByGraphicIdImpl::id(); -} - -openage::Texture* GuiGameSpecImageProviderByGraphicIdImpl::get_texture(int texture_id) { - ENSURE(this->loaded_game_spec, "trying to actually get a texture from a non-loaded spec"); - return this->loaded_game_spec->get_texture(texture_id); -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_graphic_id_impl.h b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_graphic_id_impl.h deleted file mode 100644 index 02e1c1be4b..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_graphic_id_impl.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gui_game_spec_image_provider_by_id_impl.h" - -namespace openage { -namespace gui { - -/** - * Exposes game textures to the Qt by their id. - * - * Numeric id has a form of .. - */ -class GuiGameSpecImageProviderByGraphicIdImpl : public GuiGameSpecImageProviderByIdImpl { -public: - explicit GuiGameSpecImageProviderByGraphicIdImpl(qtsdl::GuiEventQueue *render_updater); - virtual ~GuiGameSpecImageProviderByGraphicIdImpl(); - - static const char* id(); - -private: - virtual const char* get_id() const override; - virtual openage::Texture* get_texture(int texture_id) override; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_id_impl.cpp b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_id_impl.cpp deleted file mode 100644 index 82752e06de..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_id_impl.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "gui_game_spec_image_provider_by_id_impl.h" - -#include "../../../error/error.h" - -#include "../../../gamestate/old/game_spec.h" -#include "gui_texture_factory.h" - -namespace openage::gui { - -GuiGameSpecImageProviderByIdImpl::GuiGameSpecImageProviderByIdImpl(qtsdl::GuiEventQueue *render_updater) : - GuiGameSpecImageProviderImpl{render_updater} { -} - -GuiGameSpecImageProviderByIdImpl::~GuiGameSpecImageProviderByIdImpl() = default; - -TextureHandle GuiGameSpecImageProviderByIdImpl::get_texture_handle(const QString &id) { - ENSURE(this->loaded_game_spec, "trying to actually get a texture from a non-loaded spec"); - - auto ids = id.split("."); - - if (ids.size() == 2) { - bool id_ok = false, subid_ok = false; - const int texture_id = ids[0].toInt(&id_ok); - const int subid = ids[1].toInt(&subid_ok); - - auto tex = (id_ok and subid_ok) ? - this->get_texture(texture_id) : - nullptr; - - if (tex != nullptr and subid < static_cast(tex->get_subtexture_count())) { - return TextureHandle{tex, subid}; - } - else { - return this->get_missing_texture(); - } - } - else { - qWarning("Invalid texture id: 'image://%s/%s'. Example formatting: 'image://%s/7366.18'.", this->get_id(), qUtf8Printable(id), this->get_id()); - return this->get_missing_texture(); - } -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_id_impl.h b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_id_impl.h deleted file mode 100644 index d52402a669..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_id_impl.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gui_game_spec_image_provider_impl.h" - -namespace openage { -namespace gui { - -/** - * Base for providers that expose textures to the Qt by their id. - * - * Numeric id has a form of .. - */ -class GuiGameSpecImageProviderByIdImpl : public GuiGameSpecImageProviderImpl { -public: - explicit GuiGameSpecImageProviderByIdImpl(qtsdl::GuiEventQueue *render_updater); - virtual ~GuiGameSpecImageProviderByIdImpl(); - -private: - virtual TextureHandle get_texture_handle(const QString &id) override; - virtual openage::Texture* get_texture(int texture_id) = 0; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_terrain_id_impl.cpp b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_terrain_id_impl.cpp deleted file mode 100644 index f875118636..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_terrain_id_impl.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "gui_game_spec_image_provider_by_terrain_id_impl.h" - -#include "../../../error/error.h" - -#include "../../../gamestate/old/game_spec.h" - -namespace openage::gui { - -GuiGameSpecImageProviderByTerrainIdImpl::GuiGameSpecImageProviderByTerrainIdImpl(qtsdl::GuiEventQueue *render_updater) - : - GuiGameSpecImageProviderByIdImpl{render_updater} { -} - -GuiGameSpecImageProviderByTerrainIdImpl::~GuiGameSpecImageProviderByTerrainIdImpl() = default; - -const char* GuiGameSpecImageProviderByTerrainIdImpl::id() { - return "by-terrain-id"; -} - -const char* GuiGameSpecImageProviderByTerrainIdImpl::get_id() const { - return GuiGameSpecImageProviderByTerrainIdImpl::id(); -} - -openage::Texture* GuiGameSpecImageProviderByTerrainIdImpl::get_texture(int texture_id) { - ENSURE(this->loaded_game_spec, "trying to actually get a texture from a non-loaded spec"); - auto meta = this->loaded_game_spec->get_terrain_meta(); - return meta && texture_id >=0 && texture_id < std::distance(std::begin(meta->textures), std::end(meta->textures)) ? meta->textures[texture_id] : nullptr; -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_terrain_id_impl.h b/libopenage/gui/integration/private/gui_game_spec_image_provider_by_terrain_id_impl.h deleted file mode 100644 index d5aba95279..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_by_terrain_id_impl.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gui_game_spec_image_provider_by_id_impl.h" - -namespace openage { -namespace gui { - -/** - * Exposes terrain textures to the Qt by their id. - * - * Numeric id has a form of . where texture-id is the position in the terrain_meta. - */ -class GuiGameSpecImageProviderByTerrainIdImpl : public GuiGameSpecImageProviderByIdImpl { -public: - explicit GuiGameSpecImageProviderByTerrainIdImpl(qtsdl::GuiEventQueue *render_updater); - virtual ~GuiGameSpecImageProviderByTerrainIdImpl(); - - static const char* id(); - -private: - virtual const char* get_id() const override; - virtual openage::Texture* get_texture(int texture_id) override; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_impl.cpp b/libopenage/gui/integration/private/gui_game_spec_image_provider_impl.cpp deleted file mode 100644 index 4be3693854..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_impl.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "gui_game_spec_image_provider_impl.h" - -#include - -#include - -#include "../../../error/error.h" - -#include "../../../gamestate/old/game_spec.h" -#include "../../guisys/private/gui_event_queue_impl.h" - -#include "gui_texture_factory.h" -#include "gui_filled_texture_handles.h" - -namespace openage::gui { - -GuiGameSpecImageProviderImpl::GuiGameSpecImageProviderImpl(qtsdl::GuiEventQueue *render_updater) - : - GuiImageProviderImpl{}, - invalidated{}, - filled_handles{std::make_shared()}, - ended{} { - - QThread *render_thread = qtsdl::GuiEventQueueImpl::impl(render_updater)->get_thread(); - this->render_thread_callback.moveToThread(render_thread); - QObject::connect(&this->render_thread_callback, &qtsdl::GuiCallback::process_blocking, &this->render_thread_callback, &qtsdl::GuiCallback::process, render_thread != QThread::currentThread() ? Qt::BlockingQueuedConnection : Qt::DirectConnection); -} - -GuiGameSpecImageProviderImpl::~GuiGameSpecImageProviderImpl() = default; - -void GuiGameSpecImageProviderImpl::on_game_spec_loaded(const std::shared_ptr& loaded_game_spec) { - ENSURE(loaded_game_spec, "spec hasn't been checked or was invalidated"); - - std::unique_lock lck{this->loaded_game_spec_mutex}; - - if (invalidated || loaded_game_spec != this->loaded_game_spec) { - migrate_to_new_game_spec(loaded_game_spec); - invalidated = false; - - lck.unlock(); - this->loaded_game_spec_cond.notify_one(); - } -} - -void GuiGameSpecImageProviderImpl::migrate_to_new_game_spec(const std::shared_ptr& loaded_game_spec) { - ENSURE(loaded_game_spec, "spec hasn't been checked or was invalidated"); - - if (this->loaded_game_spec) { - auto keep_old_game_spec = this->loaded_game_spec; - - // Need to set up this because the load functions use this->loaded_game_spec internally. - this->loaded_game_spec = loaded_game_spec; - - emit this->render_thread_callback.process_blocking([this] { - using namespace std::placeholders; - this->filled_handles->refresh_all_handles_with_texture(std::bind(&GuiGameSpecImageProviderImpl::overwrite_texture_handle, this, _1, _2, _3)); - }); - } else { - this->loaded_game_spec = loaded_game_spec; - } -} - -void GuiGameSpecImageProviderImpl::overwrite_texture_handle(const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle) { - const TextureHandle texture_handle = this->get_texture_handle(id); - *filled_handle = {texture_handle, aspect_fit_size(texture_handle, requested_size)}; -} - -void GuiGameSpecImageProviderImpl::on_game_spec_invalidated() { - std::unique_lock lck{this->loaded_game_spec_mutex}; - - if (this->loaded_game_spec) { - const TextureHandle missing_texture = get_missing_texture(); - - emit this->render_thread_callback.process_blocking([this, &missing_texture] { - this->filled_handles->fill_all_handles_with_texture(missing_texture); - }); - - invalidated = true; - } -} - -GuiFilledTextureHandleUser GuiGameSpecImageProviderImpl::fill_texture_handle(const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle) { - this->overwrite_texture_handle(id, requested_size, filled_handle); - return GuiFilledTextureHandleUser(this->filled_handles, id, requested_size, filled_handle); -} - -TextureHandle GuiGameSpecImageProviderImpl::get_missing_texture() { - return TextureHandle{this->loaded_game_spec->get_texture("missing.png", false), -1}; -} - -QQuickTextureFactory* GuiGameSpecImageProviderImpl::requestTexture(const QString &id, QSize *size, const QSize &requestedSize) { - std::unique_lock lck{this->loaded_game_spec_mutex}; - - this->loaded_game_spec_cond.wait(lck, [this] {return this->ended || this->loaded_game_spec;}); - - if (this->ended) { - qWarning("ImageProvider was stopped during the load, so it'll appear like the requestTexture() isn't implemented."); - return this->GuiImageProviderImpl::requestTexture(id, size, requestedSize); - } else { - auto tex_factory = new GuiTextureFactory{this, id, requestedSize}; - *size = tex_factory->textureSize(); - return tex_factory; - } -} - -void GuiGameSpecImageProviderImpl::give_up() { - { - std::unique_lock lck{this->loaded_game_spec_mutex}; - this->ended = true; - } - - this->loaded_game_spec_cond.notify_one(); -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_game_spec_image_provider_impl.h b/libopenage/gui/integration/private/gui_game_spec_image_provider_impl.h deleted file mode 100644 index 4882d67447..0000000000 --- a/libopenage/gui/integration/private/gui_game_spec_image_provider_impl.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include - -#include "../../guisys/private/gui_image_provider_impl.h" -#include "../../guisys/private/gui_callback.h" -#include "gui_texture_handle.h" -#include "gui_filled_texture_handles.h" - -namespace qtsdl { - -class GuiEventQueue; -class GuiEventQueueImpl; - -} // namespace qtsdl - -namespace openage { - -class GameSpec; -class Texture; - -namespace gui { - -class GuiTexture; - -/** - * Exposes game textures to the Qt. - */ -class GuiGameSpecImageProviderImpl : public qtsdl::GuiImageProviderImpl { -public: - explicit GuiGameSpecImageProviderImpl(qtsdl::GuiEventQueue *render_updater); - virtual ~GuiGameSpecImageProviderImpl(); - - /** - * Unblocks the provider. - * - * Refreshes already loaded assets (if this->loaded_game_spec wasn't null before the call). - * - * @param loaded_game_spec new source (can't be null) - */ - void on_game_spec_loaded(const std::shared_ptr& loaded_game_spec); - - /** - * Set to every sprite the 'missing texture' from current spec. - * - * Needed as a visible reaction to setting the property to null. - * We can't unload the textures without recreating the engine, so we keep the old source. - */ - void on_game_spec_invalidated(); - - /** - * Fills in the provided handle object. - * - * Memorizes pointer to it in order to update it if the source changes. - * - * @return pointer to all memorized handles, so the client can unsubscribe. - */ - GuiFilledTextureHandleUser fill_texture_handle(const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle); - -protected: - TextureHandle get_missing_texture(); - - std::shared_ptr loaded_game_spec; - - /** - * When true, still uses the old source but shows the 'missing texture'. - */ - bool invalidated; - -private: - virtual TextureHandle get_texture_handle(const QString &id) = 0; - virtual QQuickTextureFactory* requestTexture(const QString &id, QSize *size, const QSize &requestedSize) override; - virtual void give_up() override; - - /** - * Change the already produced texture handles to use new source. - */ - void migrate_to_new_game_spec(const std::shared_ptr& loaded_game_spec); - - void overwrite_texture_handle(const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle); - - /** - * Changing the texture handles underneath the QSGTexture to reflect the reload of the GameSpec. - * - * It's not a proper Qt usage, so the live reload of the game assets for the gui may break in future Qt releases. - * When it breaks, this feature should be implemented via the recreation of the qml engine. - */ - std::shared_ptr filled_handles; - - std::mutex loaded_game_spec_mutex; - std::condition_variable loaded_game_spec_cond; - bool ended; - - qtsdl::GuiCallback render_thread_callback; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_image_provider_link.cpp b/libopenage/gui/integration/private/gui_image_provider_link.cpp deleted file mode 100644 index a0454449c7..0000000000 --- a/libopenage/gui/integration/private/gui_image_provider_link.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_image_provider_link.h" - -#include - -#include - -#include "../../../error/error.h" - -#include "../../guisys/link/qml_engine_with_singleton_items_info.h" -#include "../../guisys/link/qtsdl_checked_static_cast.h" - -#include "../../game_spec_link.h" -#include "gui_game_spec_image_provider_impl.h" - -#include "gui_game_spec_image_provider_by_filename_impl.h" -#include "gui_game_spec_image_provider_by_graphic_id_impl.h" -#include "gui_game_spec_image_provider_by_terrain_id_impl.h" - -namespace openage::gui { - -namespace { -const int registration_by_filename = qmlRegisterSingletonType("yay.sfttech.openage", 1, 0, "ImageProviderByFilename", &GuiImageProviderLink::provider_by_filename); -const int registration_by_id = qmlRegisterSingletonType("yay.sfttech.openage", 1, 0, "ImageProviderById", &GuiImageProviderLink::provider_by_graphic_id); -const int registration_by_terrain_id = qmlRegisterSingletonType("yay.sfttech.openage", 1, 0, "ImageProviderByTerrainId", &GuiImageProviderLink::provider_by_terrain_id); -} - -GuiImageProviderLink::GuiImageProviderLink(QObject *parent, GuiGameSpecImageProviderImpl &image_provider) - : - QObject{parent}, - image_provider{image_provider}, - game_spec{} { - Q_UNUSED(registration_by_filename); - Q_UNUSED(registration_by_id); - Q_UNUSED(registration_by_terrain_id); -} - -GuiImageProviderLink::~GuiImageProviderLink() = default; - -GameSpecLink* GuiImageProviderLink::get_game_spec() const { - return this->game_spec; -} - -void GuiImageProviderLink::set_game_spec(GameSpecLink *game_spec) { - if (this->game_spec != game_spec) { - if (this->game_spec) - QObject::disconnect(this->game_spec.data(), &GameSpecLink::game_spec_loaded, this, &GuiImageProviderLink::on_game_spec_loaded); - - if (!game_spec) - this->image_provider.on_game_spec_invalidated(); - - this->game_spec = game_spec; - - if (this->game_spec) { - QObject::connect(this->game_spec.data(), &GameSpecLink::game_spec_loaded, this, &GuiImageProviderLink::on_game_spec_loaded); - - if (std::shared_ptr spec = this->game_spec->get_loaded_spec()) - this->image_provider.on_game_spec_loaded(spec); - } - } -} - -QObject* GuiImageProviderLink::provider(QQmlEngine *engine, const char *id) { - qtsdl::QmlEngineWithSingletonItemsInfo *engine_with_singleton_items_info = qtsdl::checked_static_cast(engine); - auto image_providers = engine_with_singleton_items_info->get_image_providers(); - - auto found_it = std::find_if(std::begin(image_providers), std::end(image_providers), [id] (qtsdl::GuiImageProviderImpl *image_provider) { - return image_provider->get_id() == id; - }); - - ENSURE(found_it != std::end(image_providers), "The image provider '" << id << "' wasn't created or wasn't passed to the QML engine creation function."); - - // owned by the QML engine - return new GuiImageProviderLink{nullptr, *qtsdl::checked_static_cast(*found_it)}; -} - -QObject* GuiImageProviderLink::provider_by_filename(QQmlEngine *engine, QJSEngine*) { - return GuiImageProviderLink::provider(engine, GuiGameSpecImageProviderByFilenameImpl::id()); -} - -QObject* GuiImageProviderLink::provider_by_graphic_id(QQmlEngine *engine, QJSEngine*) { - return GuiImageProviderLink::provider(engine, GuiGameSpecImageProviderByGraphicIdImpl::id()); -} - -QObject* GuiImageProviderLink::provider_by_terrain_id(QQmlEngine *engine, QJSEngine*) { - return GuiImageProviderLink::provider(engine, GuiGameSpecImageProviderByTerrainIdImpl::id()); -} - -void GuiImageProviderLink::on_game_spec_loaded(GameSpecLink *game_spec, std::shared_ptr loaded_game_spec) { - if (this->game_spec == game_spec) - this->image_provider.on_game_spec_loaded(loaded_game_spec); -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_image_provider_link.h b/libopenage/gui/integration/private/gui_image_provider_link.h deleted file mode 100644 index d0f4c3e944..0000000000 --- a/libopenage/gui/integration/private/gui_image_provider_link.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include -#include - -QT_FORWARD_DECLARE_CLASS(QQmlEngine) -QT_FORWARD_DECLARE_CLASS(QJSEngine) - -namespace openage { - -class GameSpec; - -namespace gui { - -class GuiGameSpecImageProviderImpl; -class GameSpecLink; - -class GuiImageProviderLink : public QObject { - Q_OBJECT - - Q_PROPERTY(openage::gui::GameSpecLink* gameSpec READ get_game_spec WRITE set_game_spec) - -public: - explicit GuiImageProviderLink(QObject *parent, GuiGameSpecImageProviderImpl &image_provider); - virtual ~GuiImageProviderLink(); - - GameSpecLink* get_game_spec() const; - - /** - * Sets the game spec to load textures from. - * - * Setting to null doesn't detach from the spec, but picks the - * 'missing texture' from that spec and sets it to every sprite. - */ - void set_game_spec(GameSpecLink *game_spec); - - static QObject* provider(QQmlEngine*, const char *id); - static QObject* provider_by_filename(QQmlEngine*, QJSEngine*); - static QObject* provider_by_graphic_id(QQmlEngine*, QJSEngine*); - static QObject* provider_by_terrain_id(QQmlEngine*, QJSEngine*); - -private slots: - /** - * Pass loaded assets to the image provider. - * - * Need to check if we still attached to that spec. - * Also it may be invalidated in the meantime, so share the ownership. - */ - void on_game_spec_loaded(GameSpecLink *game_spec, std::shared_ptr loaded_game_spec); - -private: - GuiGameSpecImageProviderImpl &image_provider; - QPointer game_spec; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_log.cpp b/libopenage/gui/integration/private/gui_log.cpp deleted file mode 100644 index 481374f9de..0000000000 --- a/libopenage/gui/integration/private/gui_log.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "../../integration/private/gui_log.h" - -#include - -#include "../../../log/log.h" -#include "log/message.h" - - -namespace openage { -namespace gui { - -void gui_log(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - log::level msg_lvl; - - switch (type) { - case QtDebugMsg: - msg_lvl = log::level::dbg; - break; - case QtInfoMsg: - msg_lvl = log::level::info; - break; - case QtWarningMsg: - msg_lvl = log::level::warn; - break; - case QtCriticalMsg: - msg_lvl = log::level::err; - break; - case QtFatalMsg: - msg_lvl = log::level::crit; - break; - default: - msg_lvl = log::level::warn; - break; - } - - log::MessageBuilder builder{ - context.file != nullptr ? context.file : "", - static_cast(context.line), - context.function != nullptr ? context.function : "", - msg_lvl}; - - // TODO: maybe it's not UTF-8 - // TODO: Qt should become a LogSource - log::log(builder << msg.toUtf8().data()); - - if (type == QtFatalMsg) - abort(); -} - -} // namespace gui -} // namespace openage diff --git a/libopenage/gui/integration/private/gui_log.h b/libopenage/gui/integration/private/gui_log.h deleted file mode 100644 index 4966f5e182..0000000000 --- a/libopenage/gui/integration/private/gui_log.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace openage { -namespace gui { - -void gui_log(QtMsgType type, const QMessageLogContext &context, const QString &msg); - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_make_standalone_subtexture.cpp b/libopenage/gui/integration/private/gui_make_standalone_subtexture.cpp deleted file mode 100644 index 854f5a65bc..0000000000 --- a/libopenage/gui/integration/private/gui_make_standalone_subtexture.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include "gui_make_standalone_subtexture.h" -#include "gui_standalone_subtexture.h" - -namespace openage { -namespace gui { - -std::unique_ptr make_standalone_subtexture(GLuint id, const QSize &size) { - return std::make_unique(id, size); -} - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_texture.cpp b/libopenage/gui/integration/private/gui_texture.cpp deleted file mode 100644 index 7890981918..0000000000 --- a/libopenage/gui/integration/private/gui_texture.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include - -#include - -#include "../../../texture.h" -#include "gui_make_standalone_subtexture.h" -#include "gui_texture.h" - -namespace openage::gui { - -GuiTexture::GuiTexture(const SizedTextureHandle &texture_handle) : - QSGTexture{}, - texture_handle(texture_handle) { -} - -GuiTexture::~GuiTexture() = default; - -void GuiTexture::bind() { - glBindTexture(GL_TEXTURE_2D, this->textureId()); -} - -qint64 GuiTexture::comparisonKey() const { - // TODO: Qt5 What does this do?????? - return 0; -} - -bool GuiTexture::hasAlphaChannel() const { - // assume 32bit textures - return true; -} - -bool GuiTexture::hasMipmaps() const { - return false; -} - -bool GuiTexture::isAtlasTexture() const { - return openage::gui::isAtlasTexture(this->texture_handle); -} - -namespace { -GLuint create_compatible_texture(GLuint texture_id, GLsizei w, GLsizei h) { - glBindTexture(GL_TEXTURE_2D, texture_id); - - GLint min_filter; - GLint mag_filter; - GLint iformat; - - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &min_filter); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &mag_filter); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &iformat); - - GLuint new_texture_id; - glGenTextures(1, &new_texture_id); - glBindTexture(GL_TEXTURE_2D, new_texture_id); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter); - - glTexImage2D(GL_TEXTURE_2D, 0, iformat, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - - glBindTexture(GL_TEXTURE_2D, 0); - - return new_texture_id; -} -} // namespace - -QSGTexture *GuiTexture::removedFromAtlas(QRhiResourceUpdateBatch *resourceUpdates /* = nullptr */) const { - if (this->isAtlasTexture()) { - if (!this->standalone) { - auto tex = this->texture_handle.texture; - auto sub = tex->get_subtexture(this->texture_handle.subid); - - GLuint sub_texture_id = create_compatible_texture(tex->get_texture_id(), sub->w, sub->h); - - std::array fbo; - glGenFramebuffers(fbo.size(), &fbo.front()); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->textureId(), 0); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sub_texture_id, 0); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - glBlitFramebuffer(sub->x, sub->y, sub->x + sub->w, sub->y + sub->h, 0, 0, sub->w, sub->h, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glDeleteFramebuffers(fbo.size(), &fbo.front()); - - this->standalone = make_standalone_subtexture(sub_texture_id, QSize(sub->w, sub->h)); - } - - return this->standalone.get(); - } - - return nullptr; -} - -QRectF GuiTexture::normalizedTextureSubRect() const { - if (this->isAtlasTexture()) { - auto tex = this->texture_handle.texture; - auto sub = tex->get_subtexture(this->texture_handle.subid); - return QTransform::fromScale(tex->w, tex->h).inverted().mapRect(QRectF(sub->x, sub->y, sub->w, sub->h)); - } - else { - return QSGTexture::normalizedTextureSubRect(); - } -} - -int GuiTexture::textureId() const { - return this->texture_handle.texture->get_texture_id(); -} - -QSize GuiTexture::textureSize() const { - return openage::gui::textureSize(this->texture_handle); -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_texture_factory.cpp b/libopenage/gui/integration/private/gui_texture_factory.cpp deleted file mode 100644 index 06abcdada3..0000000000 --- a/libopenage/gui/integration/private/gui_texture_factory.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_texture_factory.h" - -#include "gui_game_spec_image_provider_impl.h" -#include "../../../texture.h" -#include "gui_texture.h" -#include "gui_filled_texture_handles.h" - -namespace openage::gui { - -GuiTextureFactory::GuiTextureFactory(GuiGameSpecImageProviderImpl *provider, const QString &id, const QSize &requested_size) - : - texture_handle(), - texture_handle_user{provider->fill_texture_handle(id, requested_size, &this->texture_handle)} { -} - -GuiTextureFactory::~GuiTextureFactory() = default; - -QSGTexture* GuiTextureFactory::createTexture(QQuickWindow *window) const { - Q_UNUSED(window); - return new GuiTexture{this->texture_handle}; -} - -int GuiTextureFactory::textureByteCount() const { - // assume 32bit textures - return this->texture_handle.texture->w * this->texture_handle.texture->h * 4; -} - -QSize GuiTextureFactory::textureSize() const { - return openage::gui::textureSize(this->texture_handle); -} - -} // namespace openage::gui diff --git a/libopenage/gui/integration/private/gui_texture_factory.h b/libopenage/gui/integration/private/gui_texture_factory.h deleted file mode 100644 index bf4007c0a3..0000000000 --- a/libopenage/gui/integration/private/gui_texture_factory.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -#include "gui_texture_handle.h" -#include "gui_filled_texture_handles.h" - -namespace openage { -namespace gui { - -class GuiGameSpecImageProviderImpl; - -class GuiTextureFactory : public QQuickTextureFactory { - Q_OBJECT - -public: - explicit GuiTextureFactory(GuiGameSpecImageProviderImpl *provider, const QString &id, const QSize &requested_size); - virtual ~GuiTextureFactory(); - - virtual QSGTexture* createTexture(QQuickWindow *window) const override; - virtual int textureByteCount() const override; - virtual QSize textureSize() const override; - -private: - SizedTextureHandle texture_handle; - GuiFilledTextureHandleUser texture_handle_user; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/public/CMakeLists.txt b/libopenage/gui/integration/public/CMakeLists.txt deleted file mode 100644 index c7a535bb1f..0000000000 --- a/libopenage/gui/integration/public/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_sources(libopenage - gui_application_with_logger.cpp - gui_game_spec_image_provider.cpp -) diff --git a/libopenage/gui/integration/public/gui_application_with_logger.cpp b/libopenage/gui/integration/public/gui_application_with_logger.cpp deleted file mode 100644 index 0b845f42fc..0000000000 --- a/libopenage/gui/integration/public/gui_application_with_logger.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_application_with_logger.h" - -#include "../../guisys/private/gui_application_impl.h" -#include "../private/gui_log.h" - -namespace openage::gui { - -namespace { -std::shared_ptr create() { - qInstallMessageHandler(gui_log); - return qtsdl::GuiApplicationImpl::get(); -} -} - -GuiApplicationWithLogger::GuiApplicationWithLogger() - : - GuiApplication{create()} { -} - -GuiApplicationWithLogger::~GuiApplicationWithLogger() = default; - -} // namespace openage::gui diff --git a/libopenage/gui/integration/public/gui_application_with_logger.h b/libopenage/gui/integration/public/gui_application_with_logger.h deleted file mode 100644 index 69a074a196..0000000000 --- a/libopenage/gui/integration/public/gui_application_with_logger.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../../guisys/public/gui_application.h" - -namespace openage { -namespace gui { - -/** - * Houses gui logic event queue and attaches to game logger. - */ -class GuiApplicationWithLogger : public qtsdl::GuiApplication { -public: - GuiApplicationWithLogger(); - ~GuiApplicationWithLogger(); -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/integration/public/gui_game_spec_image_provider.cpp b/libopenage/gui/integration/public/gui_game_spec_image_provider.cpp deleted file mode 100644 index 0fb622807b..0000000000 --- a/libopenage/gui/integration/public/gui_game_spec_image_provider.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "gui_game_spec_image_provider.h" - -#include "../../../error/error.h" - -#include "../private/gui_game_spec_image_provider_by_filename_impl.h" -#include "../private/gui_game_spec_image_provider_by_graphic_id_impl.h" -#include "../private/gui_game_spec_image_provider_by_terrain_id_impl.h" - -namespace openage::gui { - -GuiGameSpecImageProvider::GuiGameSpecImageProvider(qtsdl::GuiEventQueue *render_updater, Type type) - : - GuiImageProvider{[render_updater, type] () -> std::unique_ptr { - switch(type) { - case Type::ByFilename: - return std::make_unique(render_updater); - - case Type::ByGraphicId: - return std::make_unique(render_updater); - - case Type::ByTerrainId: - return std::make_unique(render_updater); - - default: - break; - } - - ENSURE(false, "unhandled image provider type"); - return std::unique_ptr{}; - }()} { -} - -GuiGameSpecImageProvider::~GuiGameSpecImageProvider() = default; - -} // namespace openage::gui diff --git a/libopenage/gui/integration/public/gui_game_spec_image_provider.h b/libopenage/gui/integration/public/gui_game_spec_image_provider.h deleted file mode 100644 index 2727d90af6..0000000000 --- a/libopenage/gui/integration/public/gui_game_spec_image_provider.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../../guisys/public/gui_image_provider.h" - -namespace qtsdl { -class GuiEventQueue; -} // namespace qtsdl - -namespace openage { -namespace gui { - -class GuiGameSpecImageProvider : public qtsdl::GuiImageProvider { -public: - enum class Type { - ByFilename, - ByGraphicId, - ByTerrainId, - }; - - explicit GuiGameSpecImageProvider(qtsdl::GuiEventQueue *render_updater, Type type); - ~GuiGameSpecImageProvider(); -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/main_args_link.cpp b/libopenage/gui/main_args_link.cpp deleted file mode 100644 index 8d7b11daa4..0000000000 --- a/libopenage/gui/main_args_link.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. - -#include "main_args_link.h" - -#include - -#include "../error/error.h" - -#include "engine_info.h" -#include "guisys/link/qml_engine_with_singleton_items_info.h" -#include "guisys/link/qtsdl_checked_static_cast.h" - -namespace openage::gui { - -namespace { -// register "MainArgs" in the qml engine to be used globally. -const int registration = qmlRegisterSingletonType("yay.sfttech.openage", 1, 0, "MainArgs", &MainArgsLink::provider); -} - - -MainArgsLink::MainArgsLink(QObject *parent, const util::Path &asset_dir) - : - QObject{parent}, - asset_dir{asset_dir} { - Q_UNUSED(registration); -} - - -QObject* MainArgsLink::provider(QQmlEngine *engine, QJSEngine*) { - auto *engine_with_singleton_items_info = qtsdl::checked_static_cast(engine); - auto info = static_cast(engine_with_singleton_items_info->get_singleton_items_info()); - ENSURE(info, "globals were lost or not passed to the gui subsystem"); - - // owned by the QML engine - return new MainArgsLink{nullptr, info->asset_dir}; -} - -} // namespace openage::gui diff --git a/libopenage/gui/main_args_link.h b/libopenage/gui/main_args_link.h deleted file mode 100644 index a615860d23..0000000000 --- a/libopenage/gui/main_args_link.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../util/path.h" - -QT_FORWARD_DECLARE_CLASS(QQmlEngine) -QT_FORWARD_DECLARE_CLASS(QJSEngine) - -namespace openage { -namespace gui { - -/** - * Used to make arguments of the game available in QML. - */ -class MainArgsLink : public QObject { - Q_OBJECT - - Q_PROPERTY(openage::util::Path assetDir MEMBER asset_dir CONSTANT) - -public: - explicit MainArgsLink(QObject *parent, const util::Path &asset_dir); - virtual ~MainArgsLink() = default; - - /** - * Generates the MainArgsLink object which is then used within QML. - */ - static QObject* provider(QQmlEngine*, QJSEngine*); - -private: - util::Path asset_dir; -}; - -}} // namespace openage::gui diff --git a/libopenage/gui/registrations.cpp b/libopenage/gui/registrations.cpp deleted file mode 100644 index d3325f9416..0000000000 --- a/libopenage/gui/registrations.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "registrations.h" - -#include - -namespace openage { -namespace gui { - -const int reg_path = qRegisterMetaType("util::Path"); - -}} // openage::gui diff --git a/libopenage/gui/registrations.h b/libopenage/gui/registrations.h deleted file mode 100644 index 2bc595ceb9..0000000000 --- a/libopenage/gui/registrations.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../util/path.h" - -namespace openage { -namespace gui { - - -}} // openage::gui - -Q_DECLARE_METATYPE(openage::util::Path) diff --git a/libopenage/gui/resources_list_model.cpp b/libopenage/gui/resources_list_model.cpp deleted file mode 100644 index ad0106663d..0000000000 --- a/libopenage/gui/resources_list_model.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2016-2023 the openage authors. See copying.md for legal info. - -#include "resources_list_model.h" - -#include -#include - -#include - -#include "../error/error.h" - -#include "../presenter/legacy/game_control.h" -#include "game_control_link.h" - -namespace openage::gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "Resources"); - -const auto resource_type_count = static_cast::type>(game_resource::RESOURCE_TYPE_COUNT); - -} // namespace - -ResourcesListModel::ResourcesListModel(QObject *parent) : - QAbstractListModel(parent), - amounts(resource_type_count), - action_mode() { - Q_UNUSED(registration); -} - -ResourcesListModel::~ResourcesListModel() = default; - -ActionModeLink *ResourcesListModel::get_action_mode() const { - return this->action_mode; -} - -void ResourcesListModel::set_action_mode(ActionModeLink *action_mode) { - if (this->action_mode != action_mode) { - if (this->action_mode) { - QObject::disconnect(&unwrap(this->action_mode)->gui_signals, &ActionModeSignals::resource_changed, this, &ResourcesListModel::on_resource_changed); - } - - this->action_mode = action_mode; - - if (this->action_mode) { - QObject::connect(&unwrap(this->action_mode)->gui_signals, &ActionModeSignals::resource_changed, this, &ResourcesListModel::on_resource_changed); - } - } -} - -void ResourcesListModel::on_resource_changed(game_resource resource, int amount) { - int i = static_cast(resource); - ENSURE(i >= 0 && i < std::distance(std::begin(this->amounts), std::end(this->amounts)), "Res type index is out of range: '" << i << "'."); - - if (this->amounts[i] != amount) { - auto model_index = this->index(i); - - this->amounts[i] = amount; - emit this->dataChanged(model_index, model_index, QVector{Qt::DisplayRole}); - } -} - -int ResourcesListModel::rowCount(const QModelIndex &) const { - ENSURE(resource_type_count == this->amounts.size(), "Res type count is compile-time const '" << resource_type_count << "', but got '" << this->amounts.size() << "'."); - return this->amounts.size(); -} - -QVariant ResourcesListModel::data(const QModelIndex &index, int role) const { - const int i = index.row(); - - switch (role) { - case Qt::DisplayRole: - ENSURE(i >= 0 && i < std::distance(std::begin(this->amounts), std::end(this->amounts)), "Res type index is out of range: '" << i << "'."); - return this->amounts[index.row()]; - - default: - return QVariant{}; - } -} - -} // namespace openage::gui diff --git a/libopenage/gui/resources_list_model.h b/libopenage/gui/resources_list_model.h deleted file mode 100644 index 574618fb78..0000000000 --- a/libopenage/gui/resources_list_model.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016-2018 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include - -#include "../gamestate/old/resource.h" - -namespace openage { -namespace gui { - -class ActionModeLink; - -/** - * Resource table for the gui. - */ -class ResourcesListModel : public QAbstractListModel { - Q_OBJECT - - Q_PROPERTY(openage::gui::ActionModeLink* actionMode READ get_action_mode WRITE set_action_mode) - -public: - ResourcesListModel(QObject *parent=nullptr); - virtual ~ResourcesListModel(); - - ActionModeLink* get_action_mode() const; - void set_action_mode(ActionModeLink *action_mode); - -private slots: - void on_resource_changed(game_resource resource, int amount); - -private: - virtual int rowCount(const QModelIndex&) const override; - virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override; - - std::vector amounts; - - ActionModeLink *action_mode; -}; - -}} // namespace openage::gui diff --git a/libopenage/handlers.cpp b/libopenage/handlers.cpp deleted file mode 100644 index 8ced9fecfa..0000000000 --- a/libopenage/handlers.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2014-2015 the openage authors. See copying.md for legal info. - -#include "handlers.h" - -namespace openage { - -} // namespace openage diff --git a/libopenage/handlers.h b/libopenage/handlers.h deleted file mode 100644 index 7df7300d45..0000000000 --- a/libopenage/handlers.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "coord/pixel.h" - - -namespace openage { - -class LegacyEngine; - -/** - * superclass for all possible drawing operations in the game. - */ -class DrawHandler { -public: - virtual ~DrawHandler() = default; - - /** - * execute the drawing action. - */ - virtual bool on_draw() = 0; -}; - -/** - * superclass for all possible drawing operations in the game. - */ -class HudHandler { -public: - virtual ~HudHandler() = default; - - /** - * execute the drawing action. - */ - virtual bool on_drawhud() = 0; -}; - -/** - * superclass for all calculations being done on engine tick. - */ -class TickHandler { -public: - virtual ~TickHandler() = default; - - /** - * execute the tick action. - */ - virtual bool on_tick() = 0; -}; - -/** - * superclass for handling any input event. - */ -class InputHandler { -public: - virtual ~InputHandler() = default; - - /** - * execute the input handler. - */ - virtual bool on_input(SDL_Event *event) = 0; -}; - -/** - * superclass for handling a window resize event. - */ -class ResizeHandler { -public: - virtual ~ResizeHandler() = default; - - /** - * execute the resize handler. - */ - virtual bool on_resize(coord::viewport_delta new_size) = 0; -}; - -} // namespace openage diff --git a/libopenage/input/CMakeLists.txt b/libopenage/input/CMakeLists.txt index d27770d98a..f24e810608 100644 --- a/libopenage/input/CMakeLists.txt +++ b/libopenage/input/CMakeLists.txt @@ -7,5 +7,4 @@ add_sources(libopenage text_to_event.cpp ) -add_subdirectory("legacy") add_subdirectory("controller") diff --git a/libopenage/input/controller/game/binding.h b/libopenage/input/controller/game/binding.h index abddb2385f..8b94dd8875 100644 --- a/libopenage/input/controller/game/binding.h +++ b/libopenage/input/controller/game/binding.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include "event/event.h" @@ -14,7 +15,7 @@ class Controller; using binding_flags_t = std::unordered_map; using binding_func_t = std::function(const event_arguments &, - const Controller &)>; + const std::shared_ptr)>; /** diff --git a/libopenage/input/controller/game/controller.cpp b/libopenage/input/controller/game/controller.cpp index d12f7e1135..7a17de186a 100644 --- a/libopenage/input/controller/game/controller.cpp +++ b/libopenage/input/controller/game/controller.cpp @@ -60,7 +60,8 @@ bool Controller::process(const event_arguments &ev_args, const std::shared_ptrlookup(ev_args.e); - auto game_event = bind.transform(ev_args, *this); + auto controller = this->shared_from_this(); + auto game_event = bind.transform(ev_args, controller); switch (bind.action_type) { case forward_action_t::SEND: @@ -90,15 +91,14 @@ void setup_defaults(const std::shared_ptr &ctx, const std::shared_ptr &simulation, const std::shared_ptr &camera) { binding_func_t create_entity_event{[&](const event_arguments &args, - const Controller &controller) { + const std::shared_ptr controller) { auto mouse_pos = args.mouse.to_phys3(camera); event::EventHandler::param_map::map_t params{ {"position", mouse_pos}, - {"owner", controller.get_controlled()}, + {"owner", controller->get_controlled()}, // TODO: Remove - {"select_cb", std::function{[&controller](gamestate::entity_id_t id) { - auto &mut_controller = const_cast(controller); - mut_controller.set_selected({id}); + {"select_cb", std::function{[controller](gamestate::entity_id_t id) { + controller->set_selected({id}); }}}, }; @@ -117,12 +117,12 @@ void setup_defaults(const std::shared_ptr &ctx, ctx->bind(ev_mouse_lmb, create_entity_action); binding_func_t move_entity{[&](const event_arguments &args, - const Controller &controller) { + const std::shared_ptr controller) { auto mouse_pos = args.mouse.to_phys3(camera); event::EventHandler::param_map::map_t params{ {"type", gamestate::component::command::command_t::MOVE}, {"target", mouse_pos}, - {"entity_ids", controller.get_selected()}, + {"entity_ids", controller->get_selected()}, }; auto event = simulation->get_event_loop()->create_event( diff --git a/libopenage/input/controller/game/controller.h b/libopenage/input/controller/game/controller.h index 2ef4439087..847a5999f5 100644 --- a/libopenage/input/controller/game/controller.h +++ b/libopenage/input/controller/game/controller.h @@ -2,6 +2,7 @@ #pragma once +#include #include #include @@ -32,7 +33,7 @@ class BindingContext; * * TODO: Connection to engine */ -class Controller { +class Controller : public std::enable_shared_from_this { public: Controller(const std::unordered_set &controlled_factions, size_t active_faction_id); diff --git a/libopenage/input/input_manager.h b/libopenage/input/input_manager.h index 7b6403eeaa..f81a5a5bc4 100644 --- a/libopenage/input/input_manager.h +++ b/libopenage/input/input_manager.h @@ -24,7 +24,7 @@ class Controller; namespace game { class Controller; -} // namespace engine +} // namespace game class InputContext; diff --git a/libopenage/input/legacy/CMakeLists.txt b/libopenage/input/legacy/CMakeLists.txt deleted file mode 100644 index 799b91e1ee..0000000000 --- a/libopenage/input/legacy/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_sources(libopenage - action.cpp - event.cpp - input_context.cpp - input_manager.cpp - text_to_event.cpp -) - -pxdgen( - input_manager.h -) diff --git a/libopenage/input/legacy/action.cpp b/libopenage/input/legacy/action.cpp deleted file mode 100644 index 83d324f161..0000000000 --- a/libopenage/input/legacy/action.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "action.h" - -#include - -#include "cvar/cvar.h" -#include "input/legacy/input_manager.h" -#include "log/log.h" -#include "log/message.h" -#include "util/repr.h" - - -namespace openage { -namespace input::legacy { - -namespace { - - -// the list of action names that will be added during the constructor of ActionManager. -const std::vector DEFAULT_ACTIONS = { - "START_GAME", - "STOP_GAME", - "TOGGLE_HUD", - "SCREENSHOT", - "TOGGLE_DEBUG_OVERLAY", - "TOGGLE_DEBUG_GRID", - "QUICK_SAVE", - "QUICK_LOAD", - "TOGGLE_MODE", - "TOGGLE_MENU", - "TOGGLE_ITEM", - "TOGGLE_BLENDING", - "TOGGLE_PROFILER", - "TOGGLE_CONSTRUCT_MODE", - "TOGGLE_UNIT_DEBUG", - "TRAIN_OBJECT", - "ENABLE_BUILDING_PLACEMENT", - "DISABLE_SET_ABILITY", - "SET_ABILITY_MOVE", - "SET_ABILITY_GATHER", - "SET_ABILITY_GARRISON", - "TOGGLE_CONSOLE", - "SPAWN_VILLAGER", - "KILL_UNIT", - "BUILD_MENU", - "BUILD_MENU_MIL", - "CANCEL", - "BUILDING_HOUS", - "BUILDING_MILL", - "BUILDING_MINE", - "BUILDING_SMIL", - "BUILDING_DOCK", - "BUILDING_FARM", - "BUILDING_BLAC", - "BUILDING_MRKT", - "BUILDING_CRCH", - "BUILDING_UNIV", - "BUILDING_RTWC", - "BUILDING_WNDR", - "BUILDING_BRKS", - "BUILDING_ARRG", - "BUILDING_STBL", - "BUILDING_SIWS", - "BUILDING_WCTWX", - "BUILDING_WALL", - "BUILDING_WALL2", - "BUILDING_WCTW", - "BUILDING_WCTW4", - "BUILDING_GTCA2", - "BUILDING_CSTL", - "BUILDING_TOWN_CENTER", - "SWITCH_TO_PLAYER_1", - "SWITCH_TO_PLAYER_2", - "SWITCH_TO_PLAYER_3", - "SWITCH_TO_PLAYER_4", - "SWITCH_TO_PLAYER_5", - "SWITCH_TO_PLAYER_6", - "SWITCH_TO_PLAYER_7", - "SWITCH_TO_PLAYER_8", - "UP_ARROW", - "DOWN_ARROW", - "LEFT_ARROW", - "RIGHT_ARROW", - "SELECT", - "DESELECT", - "BEGIN_SELECTION", - "END_SELECTION", - "FORWARD", - "BACK", - "PAINT_TERRAIN", - "BUILDING_5", - "BUILDING_6", - "BUILDING_7", - "BUILDING_8", - "BUILD", - "KEEP_BUILDING", - "INCREASE_SELECTION", - "ORDER_SELECT"}; - -} // anonymous namespace - - -ActionManager::ActionManager(InputManager *input_manager, - const std::shared_ptr &cvar_manager) : - input_manager{input_manager}, - cvar_manager{cvar_manager} { - this->create("UNDEFINED"); - - for (auto &type : DEFAULT_ACTIONS) { - this->create(type); - } -} // anonymous namespace - - -bool ActionManager::create(const std::string &type) { - if (this->actions.find(type) != this->actions.end()) { - // that action is already in the list. fail. - // TODO: throw an exception instead? - // for now, just print a warning log message - log::log(WARN << "can not create action " - << util::repr(type) << ": already exists"); - return false; - } - - action_t action_id = this->next_action_id++; - - this->reverse_map[action_id] = type; - this->actions[type] = action_id; - - // and the corresponding cvar, which modifies the action bindings - // TODO: this has nothing to do with the actionmanager! - // remove the cvarmanager-access here! - this->cvar_manager->create(type, std::make_pair( - // the cvar's getter - [type, this]() { - return this->input_manager->get_bind(type); - }, - // the cvar's setter - [type, this](const std::string &value) { - this->input_manager->set_bind(value.c_str(), type); - })); - - return true; -} - - -action_t ActionManager::get(const std::string &type) { - auto it = this->actions.find(type); - if (it != this->actions.end()) { - return it->second; - } - else { - return this->actions.at("UNDEFINED"); - } -} - - -std::string ActionManager::get_name(const action_t action) { - auto it = this->reverse_map.find(action); - if (it != this->reverse_map.end()) { - return it->second; - } - else { - return "UNDEFINED"; - } -} - - -bool ActionManager::is(const std::string &type, const action_t action) { - return this->get(type) == action; -} - - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/action.h b/libopenage/input/legacy/action.h deleted file mode 100644 index dadd618ef9..0000000000 --- a/libopenage/input/legacy/action.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "coord/pixel.h" -#include "input/legacy/event.h" - -namespace openage { - -class LegacyEngine; - -namespace cvar { -class CVarManager; -} // namespace cvar - -namespace input::legacy { - -class InputManager; - -/** - * Used to identify actions. - */ -using action_t = unsigned int; - - -// TODO this whole class seems rather obsolete... -// remove it and instead provide a proper class for action_t? -/** - * The action manager manages all the actions allow creation, access - * information and equality. - */ -class ActionManager { -public: - ActionManager(InputManager *input_manager, - const std::shared_ptr &cvar_manager); - -public: - action_t get(const std::string &type); - std::string get_name(const action_t action); - bool is(const std::string &type, const action_t action); - -private: - bool create(const std::string &type); - - // mapping from action name to numbers - std::unordered_map actions; - // for high-speed reverse lookups (action number -> name) - std::unordered_map reverse_map; - - InputManager *const input_manager; - const std::shared_ptr cvar_manager; - - // the id of the next action that is added via create(). - action_t next_action_id = 0; -}; - - -// TODO: use action_hint_t = std::pair -// for example a building command -// std::make_pair(action_t::BUILD, 123) -using action_id_t = action_t; - - -/** - * Contains information about a triggered event. - */ -struct action_arg_t { - // Triggering event - const Event e; - - // Mouse position - const coord::input mouse; - const coord::input_delta motion; - - // hints for arg receiver - // these get set globally in input manager - std::vector hints; -}; - - -/** - * Performs the effect of an action. - */ -using action_func_t = std::function; - - -/** - * For receivers of sets of events a bool is returned - * to indicate if the event was used. - */ -using action_check_t = std::function; - - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/event.cpp b/libopenage/input/legacy/event.cpp deleted file mode 100644 index a2c5d1c004..0000000000 --- a/libopenage/input/legacy/event.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "event.h" - -#include -#include - -namespace openage::input::legacy { - -ClassCode::ClassCode(event_class cl, code_t code) : - eclass(cl), - code(code) { -} - - -std::vector ClassCode::get_classes() const { - std::vector result; - - // use event_base to traverse up the class tree - event_class ec = this->eclass; - result.push_back(ec); - while (event_base.count(ec) > 0) { - ec = event_base.at(ec); - result.push_back(ec); - } - return result; -} - - -bool ClassCode::has_class(const event_class &ec) const { - for (auto c : this->get_classes()) { - if (c == ec) { - return true; - } - } - return false; -} - - -bool operator==(ClassCode a, ClassCode b) { - return a.eclass == b.eclass && a.code == b.code; -} - - -Event::Event(event_class cl, code_t code, modset_t mod) : - cc(cl, code), - mod(std::move(mod)) {} - - -Event::Event(event_class cl, std::string text, modset_t mod) : - cc(cl, 0), - mod(std::move(mod)), - utf8(std::move(text)) {} - - -char Event::as_char() const { - return (cc.code & 0xff); -} - - -std::string Event::as_utf8() const { - return utf8; -} - - -std::string Event::info() const { - std::string result; - result += "[Event: "; - result += std::to_string(static_cast(this->cc.eclass)); - result += ", "; - result += std::to_string(this->cc.code); - result += ", "; - result += this->as_char(); - result += " ("; - result += std::to_string(this->mod.size()); - result += ")]"; - return result; -} - - -bool Event::operator==(const Event &other) const { - return this->cc == other.cc && this->mod == other.mod && this->utf8 == other.utf8; -} - - -int event_hash::operator()(const Event &e) const { - return class_code_hash()(e.cc); // ^ std::hash()(e.mod) * 3664657; -} - - -int event_class_hash::operator()(const event_class &c) const { - return std::hash()(static_cast(c)); -} - - -int modifier_hash::operator()(const modifier &m) const { - return std::hash()(static_cast(m)); -} - - -int class_code_hash::operator()(const ClassCode &e) const { - return event_class_hash()(e.eclass) ^ std::hash()(e.code) * 3664657; -} - - -modset_t sdl_mod(SDL_Keymod mod) { - // Remove modifiers like num lock and caps lock - // mod = static_cast(mod & this->used_keymods); - modset_t result; - if (mod & KMOD_CTRL) { - result.emplace(modifier::CTRL); - } - if (mod & KMOD_SHIFT) { - result.emplace(modifier::SHIFT); - } - if (mod & KMOD_ALT) { - result.emplace(modifier::ALT); - } - return result; -} - - -Event sdl_key(SDL_Keycode code, SDL_Keymod mod) { - // sdl values for non printable keys - if (code & (1 << 30)) { - return Event(event_class::OTHER, code, sdl_mod(mod)); - } - else { - event_class ec; - char c = (code & 0xff); - if (isdigit(c)) { - ec = event_class::DIGIT; - } - else if (isalpha(c)) { - ec = event_class::ALPHA; - } - else if (isprint(c)) { - ec = event_class::PRINT; - } - else { - ec = event_class::NONPRINT; - } - return Event(ec, code, sdl_mod(mod)); - } -} - -Event utf8(const std::string &text) { - return Event(event_class::UTF8, text, modset_t()); -} - -Event sdl_mouse(int button, SDL_Keymod mod) { - return Event(event_class::MOUSE_BUTTON, button, sdl_mod(mod)); -} - -Event sdl_mouse_up_down(int button, bool up, SDL_Keymod mod) { - return Event(up ? event_class::MOUSE_BUTTON_UP : event_class::MOUSE_BUTTON_DOWN, button, sdl_mod(mod)); -} - -Event sdl_wheel(int direction, SDL_Keymod mod) { - return Event(event_class::MOUSE_WHEEL, direction, sdl_mod(mod)); -} - - -} // namespace openage::input::legacy diff --git a/libopenage/input/legacy/event.h b/libopenage/input/legacy/event.h deleted file mode 100644 index 82d8e9a62e..0000000000 --- a/libopenage/input/legacy/event.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include - -#include - -namespace openage { -namespace input::legacy { - -/** - * highest level classes of input - */ -enum class event_class { - ANY, - KEYBOARD, - CHAR, // basic keycodes (lower-case, non-modified) - ALPHA, // abc - DIGIT, // 123 - PRINT, // remaining printable chars - NONPRINT, // tab, return, backspace, delete - OTHER, // arrows, home, end - UTF8, // events with utf8 encoded data - MOUSE, - MOUSE_BUTTON, - MOUSE_BUTTON_UP, - MOUSE_BUTTON_DOWN, - MOUSE_WHEEL, - MOUSE_MOTION -}; - - -struct event_class_hash { - int operator()(const event_class &s) const; -}; - - -/** - * each event type mapped to parent type - */ -static std::unordered_map event_base{ - {event_class::KEYBOARD, event_class::ANY}, - {event_class::CHAR, event_class::KEYBOARD}, - {event_class::ALPHA, event_class::CHAR}, - {event_class::DIGIT, event_class::CHAR}, - {event_class::PRINT, event_class::CHAR}, - {event_class::NONPRINT, event_class::KEYBOARD}, - {event_class::OTHER, event_class::KEYBOARD}, - {event_class::UTF8, event_class::KEYBOARD}, - {event_class::MOUSE, event_class::ANY}, - {event_class::MOUSE_BUTTON, event_class::MOUSE}, - {event_class::MOUSE_WHEEL, event_class::MOUSE}, - {event_class::MOUSE_MOTION, event_class::MOUSE}, -}; - -/** - * mods set on an event - */ -enum class modifier { - CTRL, - ALT, - SHIFT -}; - - -struct modifier_hash { - int operator()(const modifier &s) const; -}; - - -/** - * types used by events - */ -using code_t = int; -using modset_t = std::unordered_set; - - -/** - * base event type containing event handler and event code - */ -class ClassCode { -public: - ClassCode(event_class cl, code_t code); - - /** - * classes ordered with most specific first - */ - std::vector get_classes() const; - bool has_class(const event_class &c) const; - - const event_class eclass; - const code_t code; -}; - - -bool operator==(ClassCode a, ClassCode b); - - -struct class_code_hash { - int operator()(const ClassCode &k) const; -}; - - -/** - * Input event, as triggered by some input device like - * mouse, kezb, joystick, tablet, microwave or dildo. - * Some modifier keys may also be pressed during the event. - */ -class Event { -public: - Event(event_class cl, code_t code, modset_t mod); - Event(event_class cl, std::string, modset_t mod); - - /** - * Return keyboard text as char - * returns 0 for non-text events - */ - char as_char() const; - - /** - * Returns a utf encoded char - * or an empty string for non-utf8 events - */ - std::string as_utf8() const; - - /** - * logable debug info - */ - std::string info() const; - - bool operator==(const Event &other) const; - - const ClassCode cc; - const modset_t mod; - const std::string utf8; -}; - - -struct event_hash { - int operator()(const Event &e) const; -}; - - -using event_set_t = std::unordered_set; - - -// SDL mapping functions - -modset_t sdl_mod(SDL_Keymod mod); -Event sdl_key(SDL_Keycode code, SDL_Keymod mod = KMOD_NONE); -Event utf8(const std::string &text); -Event sdl_mouse(int button, SDL_Keymod mod = KMOD_NONE); -Event sdl_mouse_up_down(int button, bool up, SDL_Keymod mod = KMOD_NONE); -Event sdl_wheel(int direction, SDL_Keymod mod = KMOD_NONE); - - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/input_context.cpp b/libopenage/input/legacy/input_context.cpp deleted file mode 100644 index b77ae592fe..0000000000 --- a/libopenage/input/legacy/input_context.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "input_context.h" - -#include "input/legacy/input_manager.h" - - -namespace openage { -namespace input::legacy { - - -InputContext::InputContext() : - InputContext{nullptr} {} - - -InputContext::InputContext(InputManager *manager) : - utf8_mode{false} { - this->register_to(manager); -} - - -std::vector InputContext::active_binds() const { - if (this->input_manager == nullptr) { - return {}; - } - - // TODO: try to purge this backpointer to the input manager. - return this->input_manager->active_binds(this->by_type); -} - -void InputContext::bind(action_t type, const action_func_t act) { - this->by_type.emplace(std::make_pair(type, act)); -} - -void InputContext::bind(const Event &ev, const action_func_t act) { - this->by_event.emplace(std::make_pair(ev, act)); -} - -void InputContext::bind(event_class ec, const action_check_t act) { - this->by_class.emplace(std::make_pair(ec, act)); -} - -bool InputContext::execute_if_bound(const action_arg_t &arg) { - // arg type hints are highest priority - for (auto &h : arg.hints) { - auto action = this->by_type.find(h); - if (action != this->by_type.end()) { - action->second(arg); - return true; - } - } - - // specific event mappings - auto action = this->by_event.find(arg.e); - if (action != this->by_event.end()) { - action->second(arg); - return true; - } - - // check all possible class mappings - for (auto &c : arg.e.cc.get_classes()) { - auto action = this->by_class.find(c); - if (action != this->by_class.end() && action->second(arg)) { - return true; - } - } - - return false; -} - - -void InputContext::register_to(InputManager *manager) { - this->input_manager = manager; -} - - -void InputContext::unregister() { - this->input_manager = nullptr; -} - - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/input_context.h b/libopenage/input/legacy/input_context.h deleted file mode 100644 index ccd0f32cd1..0000000000 --- a/libopenage/input/legacy/input_context.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include - -#include "input/legacy/action.h" -#include "input/legacy/event.h" - -namespace openage { -namespace input::legacy { - -class InputManager; - - -/** - * An input context contains all keybindings and actions - * active in e.g. the HUD only. - * For the console, there's a different input context. - * That way, each context can have the same keys - * assigned to different actions, the active context - * decides, which one to trigger. - */ -class InputContext { -public: - /** - * Create an unbound input context. - */ - InputContext(); - - /** - * Create a bound context, assigned to its manager. - */ - InputContext(InputManager *manager); - - virtual ~InputContext() = default; - - /** - * a list of all keys of this context - * which are bound currently in the active context. - * - * TODO: move this method to the input manager. - * as InputManager::active_binds(const InputContext &) const; - */ - std::vector active_binds() const; - - /** - * bind a specific action idetifier - * this is the highest matching priority - */ - void bind(action_t type, const action_func_t act); - - /** - * bind a specific event - * this is the second matching priority - */ - void bind(const Event &ev, const action_func_t act); - - /** - * bind all events of a specific class - * this is the lowest matching priority - */ - void bind(event_class ec, const action_check_t act); - - /** - * lookup an action. If it is bound, execute it. - * @return true when the action is executed, false else. - */ - bool execute_if_bound(const action_arg_t &e); - - /** - * Called by the InputManager where this context - * shall be registered to. - */ - void register_to(InputManager *manager); - - /** - * Remove the registration to an input manager. - */ - void unregister(); - - - /** - * Affects which keyboard events are received: - * true to accpet utf8 text events, - * false to receive regular char events - */ - bool utf8_mode; - -private: - /** - * Input manager this context is bound to. - */ - InputManager *input_manager; - - /** - * Maps an action id to a event execution function. - */ - std::unordered_map by_type; - - /** - * map specific overriding events - */ - std::unordered_map by_event; - - /** - * event to action map - * event_class as key, to ensure all events can be mapped - */ - std::unordered_map by_class; -}; - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/input_manager.cpp b/libopenage/input/legacy/input_manager.cpp deleted file mode 100644 index f8ce7e2999..0000000000 --- a/libopenage/input/legacy/input_manager.cpp +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include -#include - -#include "input/legacy/action.h" -#include "input/legacy/input_manager.h" -#include "input/legacy/text_to_event.h" -#include "log/log.h" - - -namespace openage::input::legacy { - -InputManager::InputManager(ActionManager *action_manager) : - action_manager{action_manager}, - global_context{this}, - relative_mode{false} { - this->global_context.register_to(this); -} - - -namespace { - -std::string mod_set_string(modset_t mod) { - if (not mod.empty()) { - for (auto &it : mod) { - switch (it) { - case modifier::ALT: - return "ALT + "; - case modifier::CTRL: - return "CTRL + "; - case modifier::SHIFT: - return "SHIFT + "; - default: - break; - } - } - } - return ""; -} - -std::string event_as_string(const Event &event) { - if (not event.as_utf8().empty()) { - return mod_set_string(event.mod) + event.as_utf8(); - } - else { - if (event.cc.eclass == event_class::MOUSE_WHEEL) { - if (event.cc.code == -1) { - return mod_set_string(event.mod) + "Wheel down"; - } - else { - return mod_set_string(event.mod) + "Wheel up"; - } - } - return mod_set_string(event.mod) + SDL_GetKeyName(event.cc.code); - } -} - -} // namespace - - -std::string InputManager::get_bind(const std::string &action_str) { - action_t action = this->action_manager->get(action_str); - if (this->action_manager->is("UNDEFINED", action)) { - return ""; - } - - auto it = this->keys.find(action); - if (it == this->keys.end()) { - return " "; - } - - switch (it->second.cc.eclass) { - case event_class::MOUSE_BUTTON: - return this->mouse_bind_to_string(it->second); - case event_class::MOUSE_WHEEL: - return this->wheel_bind_to_string(it->second); - default: - return this->key_bind_to_string(it->second); - } -} - -bool InputManager::set_bind(const std::string &bind_str, const std::string &action_str) { - try { - action_t action = this->action_manager->get(action_str); - if (this->action_manager->is("UNDEFINED", action)) { - return false; - } - - Event ev = text_to_event(bind_str); - - auto it = this->keys.find(action); - if (it != this->keys.end()) { - this->keys.erase(it); - } - this->keys.emplace(std::make_pair(action, ev)); - - return true; - } - catch (int error) { - return false; - } -} - -std::string InputManager::key_bind_to_string(const Event &ev) { - std::string key_str = std::string(SDL_GetKeyName(ev.cc.code)); - - auto end = ev.mod.end(); - if (ev.mod.find(modifier::ALT) != end) { - key_str = "Alt " + key_str; - } - if (ev.mod.find(modifier::SHIFT) != end) { - key_str = "Shift " + key_str; - } - if (ev.mod.find(modifier::CTRL) != end) { - key_str = "Ctrl " + key_str; - } - return key_str; -} - -std::string InputManager::mouse_bind_to_string(const Event &ev) { - return "MOUSE " + std::to_string(ev.cc.code); -} - -std::string InputManager::wheel_bind_to_string(const Event &ev) { - std::string base = "WHEEL "; - switch (ev.cc.code) { - case 1: - return base + "UP"; - case -1: - return base + "DOWN"; - default: - return ""; - } -} - -InputContext &InputManager::get_global_context() { - return this->global_context; -} - -InputContext &InputManager::get_top_context() { - // return the global input context - // if no override is pushed - if (this->contexts.empty()) { - return this->global_context; - } - return *this->contexts.back(); -} - -void InputManager::push_context(InputContext *context) { - // push the context to the top - this->contexts.push_back(context); - - context->register_to(this); -} - - -void InputManager::remove_context(InputContext *context) { - if (this->contexts.empty()) { - return; - } - - for (auto it = this->contexts.begin(); it != this->contexts.end(); ++it) { - if ((*it) == context) { - this->contexts.erase(it); - context->unregister(); - return; - } - } -} - - -bool InputManager::ignored(const Event &e) { - // filter duplicate utf8 events - // these are ignored unless the top mode enables - // utf8 mode, in which case regular char codes are ignored - return ((e.cc.has_class(event_class::CHAR) || e.cc.has_class(event_class::UTF8)) && this->get_top_context().utf8_mode != e.cc.has_class(event_class::UTF8)); -} - - -bool InputManager::trigger(const Event &e) { - if (this->ignored(e)) { - return false; - } - - // arg passed to receivers - action_arg_t arg{e, this->mouse_position, this->mouse_motion, {}}; - - for (auto &it : this->keys) { - if (e == it.second) { - arg.hints.emplace_back(it.first); - } - } - - // Check context list on top of the stack (most recent bound first) - for (auto it = this->contexts.rbegin(); it != this->contexts.rend(); ++it) { - if ((*it)->execute_if_bound(arg)) { - return true; - } - } - - // If no local keybinds were bound, check the global keybinds - return this->global_context.execute_if_bound(arg); -} - - -void InputManager::set_state(const Event &ev, bool is_down) { - if (this->ignored(ev)) { - return; - } - - // update key states - this->keymod = ev.mod; - bool was_down = this->states[ev.cc]; - this->states[ev.cc] = is_down; - - // a key going from pressed to unpressed - // will automatically trigger event handling - if (was_down && !is_down) { - this->trigger(ev); - } -} - - -void InputManager::set_mouse(int x, int y) { - auto last_position = this->mouse_position; - this->mouse_position = coord::input{coord::pixel_t{x}, coord::pixel_t{y}}; - this->mouse_motion = this->mouse_position - last_position; -} - - -void InputManager::set_motion(int x, int y) { - this->mouse_motion.x = x; - this->mouse_motion.y = y; -} - - -void InputManager::set_relative(bool mode) { - if (this->relative_mode == mode) { - return; - } - - // change mode - this->relative_mode = mode; - if (this->relative_mode) { - SDL_SetRelativeMouseMode(SDL_TRUE); - } - else { - SDL_SetRelativeMouseMode(SDL_FALSE); - } -} - -bool InputManager::is_mouse_at_edge(Edge edge, int window_size) { - int x, y; - SDL_GetMouseState(&x, &y); - - // Border width to consider screen edges for scrolling. - // AoE II appears to be approx 10px. - // TODO: make configurable through cvar. - const int edge_offset = 10; - - if (edge == Edge::LEFT && x <= edge_offset) { - return true; - } - if (edge == Edge::RIGHT && x >= window_size - edge_offset - 1) { - return true; - } - if (edge == Edge::UP && y <= edge_offset) { - return true; - } - if (edge == Edge::DOWN && y >= window_size - edge_offset - 1) { - return true; - } - - return false; -} - -bool InputManager::is_down(const ClassCode &cc) const { - auto it = this->states.find(cc); - if (it != this->states.end()) { - return it->second; - } - return false; -} - - -bool InputManager::is_down(event_class ec, code_t code) const { - return is_down(ClassCode(ec, code)); -} - - -bool InputManager::is_down(SDL_Keycode k) const { - return is_down(sdl_key(k).cc); -} - - -bool InputManager::is_mod_down(modifier mod) const { - return (this->keymod.count(mod) > 0); -} - - -modset_t InputManager::get_mod() const { - SDL_Keymod mod = SDL_GetModState(); - return sdl_mod(mod); -} - - -bool InputManager::on_input(SDL_Event *e) { - // top level input handler - switch (e->type) { - case SDL_KEYUP: { - SDL_Keycode code = reinterpret_cast(e)->keysym.sym; - Event ev = sdl_key(code, SDL_GetModState()); - this->set_state(ev, false); - break; - } // case SDL_KEYUP - - case SDL_KEYDOWN: { - SDL_Keycode code = reinterpret_cast(e)->keysym.sym; - this->set_state(sdl_key(code, SDL_GetModState()), true); - break; - } // case SDL_KEYDOWN - - case SDL_TEXTINPUT: { - this->trigger(utf8(e->text.text)); - break; - } // case SDL_TEXTINPUT - - case SDL_MOUSEBUTTONUP: { - this->set_relative(false); - this->trigger(sdl_mouse_up_down(e->button.button, true, SDL_GetModState())); - Event ev = sdl_mouse(e->button.button, SDL_GetModState()); - this->set_state(ev, false); - break; - } // case SDL_MOUSEBUTTONUP - - case SDL_MOUSEBUTTONDOWN: { - // TODO: set which buttons - if (e->button.button == 2) { - this->set_relative(true); - } - this->trigger(sdl_mouse_up_down(e->button.button, false, SDL_GetModState())); - Event ev = sdl_mouse(e->button.button, SDL_GetModState()); - this->set_state(ev, true); - break; - } // case SDL_MOUSEBUTTONDOWN - - case SDL_MOUSEMOTION: { - if (this->relative_mode) { - this->set_motion(e->motion.xrel, e->motion.yrel); - } - else { - this->set_mouse(e->button.x, e->button.y); - } - - // must occur after setting mouse position - Event ev(event_class::MOUSE_MOTION, 0, this->get_mod()); - this->trigger(ev); - break; - } // case SDL_MOUSEMOTION - - case SDL_MOUSEWHEEL: { - Event ev = sdl_wheel(e->wheel.y, SDL_GetModState()); - this->trigger(ev); - break; - } // case SDL_MOUSEWHEEL - - } // switch (e->type) - - return true; -} - - -std::vector InputManager::active_binds(const std::unordered_map &ctx_actions) const { - std::vector result; - - // TODO: this only checks the by_type mappings, the others are missing! - for (auto &action : ctx_actions) { - std::string keyboard_key; - - for (auto &key : this->keys) { - if (key.first == action.first) { - keyboard_key = event_as_string(key.second); - break; - } - } - - // this is only possible if the action is registered, - // then this->input_manager != nullptr. - // TODO: try to purge the action manager access here. - // TODO: get_name takes O(n) time - std::string action_type_str = this->get_action_manager()->get_name(action.first); - - result.push_back(keyboard_key + " : " + action_type_str); - } - - return result; -} - - -ActionManager *InputManager::get_action_manager() const { - return this->action_manager; -} - - -} // namespace openage::input::legacy diff --git a/libopenage/input/legacy/input_manager.h b/libopenage/input/legacy/input_manager.h deleted file mode 100644 index 92a0044524..0000000000 --- a/libopenage/input/legacy/input_manager.h +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -// pxd: from libcpp cimport bool -#include -// pxd: from libcpp.string cimport string -#include -#include - -#include "handlers.h" -#include "input/legacy/action.h" -#include "input/legacy/event.h" -#include "input/legacy/input_context.h" - - -namespace openage { - - -/** - * The openage input layer. - * It gets all the events and processes them accordingly. - */ -namespace input::legacy { - -/** - * maps actions to events. - */ -using binding_map_t = std::unordered_map; - - -/** - * The input manager manages all input layers (hud, game, ...) - * and triggers the registered actions depending on the active layer. - * - * pxd: - * - * cppclass InputManager: - * bool set_bind(char* bind_char, string action) except + - * string get_bind(string action) except + - */ -class InputManager : public InputHandler { -public: - /** - * Screen edges used for edge scrolling. - */ - enum class Edge { - LEFT, - RIGHT, - UP, - DOWN - }; - - InputManager(ActionManager *action_manager); - - /** - * Return the string representation of the bind assignated to an action. - */ - std::string get_bind(const std::string &action); - - /** - * Set the given action to be triggered by the given bind (key/mouse - * /wheel). Remove previous assignation. Do nothing if either they - * given bind or action is invalid/unknow. - */ - bool set_bind(const std::string &bind_str, const std::string &action); - - /** - * Return the string representation of the key event. - */ - std::string key_bind_to_string(const Event &ev); - - /** - * Return the string representation of the mouse event. - */ - std::string mouse_bind_to_string(const Event &ev); - - /** - * Return the key representation of the event. - */ - std::string wheel_bind_to_string(const Event &ev); - - /** - * returns the global keybind context. - * actions bound here will be retained even when override_context is called. - */ - InputContext &get_global_context(); - - /** - * Returns the context on top. - * Note there is always a top context - * since the global context will be - * considered on top when none are registered - */ - InputContext &get_top_context(); - - /** - * register a hotkey context by pushing it onto the stack. - * - * this adds the given pointer to the `contexts` list. - * that way the context lays on "top". - * - * if other contexts are registered afterwards, - * it wanders down the stack, i.e. looses priority. - */ - void push_context(InputContext *context); - - /** - * removes any matching registered context from the stack. - * - * the removal is done by finding the given pointer - * in the `contexts` lists, then deleting it in there. - */ - void remove_context(InputContext *context); - - /** - * true if the given event type is being ignored - */ - bool ignored(const Event &e); - - /** - * manages the pressing of an input event (key, mouse, ...). - * first checks whether an action is bound to it. - * if it is, look for an handler to execute that handler. - * returns true if the event was responded to - */ - bool trigger(const Event &e); - - /** - * sets the state of a specific key - */ - void set_state(const Event &ev, bool is_down); - - /** - * updates mouse position state and motion - */ - void set_mouse(int x, int y); - - /** - * updates mouse motion only - */ - void set_motion(int x, int y); - - /** - * enable relative mouse mode - */ - void set_relative(bool mode); - - /** - * Query whether cursor is at edgo of screen - * - * edge variable is enum Edges - * - * @return true when the mouse is at the queried screen edge, false else. - */ - bool is_mouse_at_edge(Edge edge, int window_size); - - /** - * Query stored pressing stat for a key. - * - * note that the function stores a unknown/new keycode - * as 'not pressed' if requested - * @return true when the key is pressed, false else. - */ - bool is_down(const ClassCode &cc) const; - bool is_down(event_class ec, code_t code) const; - - /** - * Most cases should use above is_down(class, code) - * instead to avoid relying on sdl types - * - * Query stored pressing stat for a key. - * @return true when the key is pressed, false else. - */ - bool is_down(SDL_Keycode k) const; - - /** - * Checks whether a key modifier is held down. - */ - bool is_mod_down(modifier mod) const; - - /** - * When a SDL event happens, this is called. - */ - bool on_input(SDL_Event *e) override; - - /** - * Return a string representation of active key bindings - * from the given context. - */ - std::vector active_binds(const std::unordered_map &ctx_actions) const; - - /** - * Get the action manager attached to this input manager. - */ - ActionManager *get_action_manager() const; - -private: - modset_t get_mod() const; - - /** - * The action manager to used for keybind action lookups. - */ - ActionManager *action_manager; - - /** - * The global context. Used as fallback. - */ - InputContext global_context; - - /** - * Maps actions to events. - */ - binding_map_t keys; - - /** - * Stack of active input contexts. - * The most recent entry is pushed on top of the stack. - */ - std::vector contexts; - - /** - * key to is_down map. - * stores a mapping between keycodes and its pressing state. - * a true value means the key is currently pressed, - * false indicates the key is untouched. - */ - std::unordered_map states; - - /** - * Current key modifiers. - * Included ALL modifiers including num lock and caps lock. - */ - modset_t keymod; - - /** - * mode where mouse position is ignored - * used for map scrolling - */ - bool relative_mode; - - /** - * mouse position in the window - */ - coord::input mouse_position{0, 0}; - - /** - * mouse position relative to the last frame position. - */ - coord::input_delta mouse_motion{0, 0}; - - friend InputContext; -}; - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/text_to_event.cpp b/libopenage/input/legacy/text_to_event.cpp deleted file mode 100644 index c0d410456b..0000000000 --- a/libopenage/input/legacy/text_to_event.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2016-2023 the openage authors. See copying.md for legal info. - -#include "text_to_event.h" - -#include -#include -#include - -#include "error/error.h" -#include "log/log.h" -#include "testing/testing.h" - - -namespace openage { -namespace input::legacy { - -namespace { -const std::vector modifiers{ - KMOD_LCTRL, KMOD_LSHIFT, KMOD_RCTRL, KMOD_RSHIFT, KMOD_LALT, KMOD_RALT, KMOD_LGUI, KMOD_RGUI, KMOD_CTRL, KMOD_SHIFT, KMOD_ALT, KMOD_GUI, KMOD_MODE, KMOD_CAPS, KMOD_NUM}; - -const std::regex event_pattern{ - "(?:(?:(LCtrl)|(LShift)|(RCtrl)|(RShift)|(LAlt)|(RAlt)|(LGui)|(RGUI)|(Ctrl)|(Shift)|(Alt)|(Gui)|(AltGr)|(Caps)|(NumLck))[[:space:]]+)?" // modifier (optional) - "([^[:space:]]+)" // key - "(?:[[:space:]]+([^[:space:]]+))?" // parameter, like direction (optional) - "[[:space:]]*"}; - -void check_modifiers_once() { - static bool checked = false; - - if (!checked) { - checked = true; - ENSURE(event_pattern.mark_count() == modifiers.size() + 2, "Groups in the input event regex pattern: one per key modifier, key itself and amount."); - } -} - -Event to_event(const std::string &event_type, const std::string ¶m, const int mod) { - try { - if (event_type == "MOUSE") - return sdl_mouse(std::stoi(param), static_cast(mod)); - else if (event_type == "MOUSE_UP") - return sdl_mouse_up_down(std::stoi(param), true, static_cast(mod)); - else if (event_type == "MOUSE_DOWN") - return sdl_mouse_up_down(std::stoi(param), false, static_cast(mod)); - } - catch (std::logic_error &) { - throw Error(MSG(err) << "could not parse mouse button '" << param << "'!"); - } - - if (event_type == "WHEEL") { - if (param == "1" || param == "UP") { - return sdl_wheel(1, static_cast(mod)); - } - else if (param == "-1" || param == "DOWN") { - return sdl_wheel(-1, static_cast(mod)); - } - - throw Error(MSG(err) << "could not parse mouse wheel amount '" << param << "'!"); - } - - SDL_Keycode key_code = SDL_GetKeyFromName(event_type.c_str()); - if (key_code == SDLK_UNKNOWN) { - throw Error(MSG(err) << "could not parse key '" << event_type << "'!"); - } - - if (!param.empty()) - log::log(MSG(warn) << "nothing expected after key name '" << event_type << "', but got '" << param << "'."); - - return sdl_key(key_code, static_cast(mod)); -} - -} // namespace - -/** - * Convert a string to an event, throw if the string is not a valid event. - */ -Event text_to_event(const std::string &event_str) { - check_modifiers_once(); - ENSURE(event_str.find('\n'), "Input event string representation must be one line, got '" << event_str << "'."); - - int mod = 0; - std::smatch event_elements; - - if (std::regex_match(event_str, event_elements, event_pattern)) { - /** - * First element is the entire match, so search from the second. - */ - auto groups_it = std::begin(event_elements) + 1; - - auto first_non_empty = std::find_if(groups_it, std::end(event_elements), [](const std::ssub_match &element) { - return element.length(); - }); - - ENSURE(first_non_empty != std::end(event_elements), "Nothing captured from string representation of event '" << event_str << "': regex pattern is broken."); - - auto index_first_non_empty = std::distance(groups_it, first_non_empty); - - if (index_first_non_empty < std::distance(std::begin(modifiers), std::end(modifiers))) - mod = modifiers[index_first_non_empty]; - - auto event_type = groups_it[modifiers.size()].str(); - ENSURE(!event_type.empty(), "Empty group where key was expected in string representation of event '" << event_str << "': regex pattern is broken."); - - auto param = groups_it[modifiers.size() + 1].str(); - - return to_event(event_type, param, mod); - } - else { - throw Error(MSG(err) << "could not parse keybinding '" << event_str << "'!"); - } -} - -namespace tests { -void parse_event_string() { - text_to_event("q") == Event{event_class::ALPHA, SDL_GetKeyFromName("q"), modset_t{}} || TESTFAIL; - text_to_event("Return") == Event{event_class::NONPRINT, SDL_GetKeyFromName("Return"), modset_t{}} || TESTFAIL; - text_to_event("Ctrl p") == Event{event_class::ALPHA, SDL_GetKeyFromName("p"), sdl_mod(static_cast(KMOD_CTRL))} || TESTFAIL; - text_to_event("Shift MOUSE 1") == Event{event_class::MOUSE_BUTTON, 1, sdl_mod(static_cast(KMOD_SHIFT))} || TESTFAIL; - text_to_event("MOUSE_UP 1") == Event{event_class::MOUSE_BUTTON_UP, 1, modset_t{}} || TESTFAIL; - text_to_event("WHEEL -1") == Event{event_class::MOUSE_WHEEL, -1, modset_t{}} || TESTFAIL; - TESTTHROWS(text_to_event("")); - TESTTHROWS(text_to_event("WHEEL")); - TESTTHROWS(text_to_event("MOUSE")); - TESTTHROWS(text_to_event("MOUSE_DOWN")); - TESTTHROWS(text_to_event("Blurb MOUSE 1")); - TESTTHROWS(text_to_event("Shift MICKEY_MOUSE 1")); - TESTTHROWS(text_to_event("WHEEL TEAR_OFF")); -} - -} // namespace tests - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/input/legacy/text_to_event.h b/libopenage/input/legacy/text_to_event.h deleted file mode 100644 index 745f33e04b..0000000000 --- a/libopenage/input/legacy/text_to_event.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "input/legacy/event.h" - -namespace openage { -namespace input::legacy { - -/** - * Convert a string to an event, throw if the string is not a valid event. - */ -Event text_to_event(const std::string &event_str); - -} // namespace input::legacy -} // namespace openage diff --git a/libopenage/legacy_engine.cpp b/libopenage/legacy_engine.cpp deleted file mode 100644 index af5480032b..0000000000 --- a/libopenage/legacy_engine.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#include "legacy_engine.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "error/error.h" -#include "log/log.h" -#include "presenter/legacy/legacy.h" -#include "version.h" -#include "versions/compiletime.h" - -namespace openage { - -LegacyEngine::LegacyEngine(enum mode mode, - const util::Path &root_dir, - const std::shared_ptr &cvar_manager) : - running{false}, - run_mode{mode}, - root_dir{root_dir}, - job_manager{SDL_GetCPUCount()}, - qml_info{this, root_dir["assets"]}, - cvar_manager{cvar_manager}, - profiler{this}, - gui_link{} { - if (mode == mode::LEGACY) { - this->old_display = std::make_unique(root_dir, this); - return; - } - - // TODO: implement FULL and HEADLESS mode :) -} - - -LegacyEngine::~LegacyEngine() {} - - -void LegacyEngine::run() { - try { - this->job_manager.start(); - this->running = true; - - if (this->run_mode == mode::LEGACY) { - this->old_display->loop(); - } - - this->running = false; - } - catch (...) { - this->job_manager.stop(); - throw; - } -} - - -void LegacyEngine::stop() { - this->job_manager.stop(); - this->running = false; -} - - -const util::Path &LegacyEngine::get_root_dir() { - return this->root_dir; -} - - -job::JobManager *LegacyEngine::get_job_manager() { - return &this->job_manager; -} - - -std::shared_ptr LegacyEngine::get_cvar_manager() { - return this->cvar_manager; -} - -gui::EngineQMLInfo LegacyEngine::get_qml_info() { - return this->qml_info; -} - -} // namespace openage diff --git a/libopenage/legacy_engine.h b/libopenage/legacy_engine.h deleted file mode 100644 index bc8b187dff..0000000000 --- a/libopenage/legacy_engine.h +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "log/file_logsink.h" -#include "log/log.h" -// pxd: from libopenage.cvar cimport CVarManager -#include "cvar/cvar.h" -#include "gui/engine_info.h" -#include "handlers.h" -#include "input/legacy/action.h" -#include "job/job_manager.h" -#include "options.h" -#include "unit/selection.h" -#include "util/externalprofiler.h" -#include "util/path.h" -#include "util/profiler.h" -#include "util/strings.h" - - -/** - * Main openage namespace to store all things that make the have to do with the game. - * - * Game entity management, graphics drawing, gui stuff, input handling etc. - * So basically everything that makes the game work lies in here... - */ -namespace openage { - -namespace gui { -class GuiItemLink; -} // namespace gui - -namespace presenter { -class LegacyDisplay; -} // namespace presenter - - -/** - * Qt signals for the engine. - */ -class EngineSignals : public QObject { - Q_OBJECT - -public: -signals: - void global_binds_changed(const std::vector &global_binds); -}; - - -/** - * main engine container. - * - * central foundation for everything the openage engine is capable of. - * - * pxd: - * - * cppclass LegacyEngine: - * - * InputManager &get_input_manager() except + - * CVarManager &get_cvar_manager() except + - */ -class LegacyEngine final { -public: - enum class mode { - LEGACY, - HEADLESS, - FULL, - }; - - LegacyEngine(); - - /** - * engine initialization method. - * starts the engine subsystems depending on the requested run mode. - */ - LegacyEngine(mode mode, - const util::Path &root_dir, - const std::shared_ptr &cvar_manager); - - /** - * engine copy constructor. - */ - LegacyEngine(const LegacyEngine ©) = delete; - - /** - * engine assignment operator. - */ - LegacyEngine &operator=(const LegacyEngine ©) = delete; - - /** - * engine move constructor. - */ - LegacyEngine(LegacyEngine &&other) = delete; - - /** - * engine move operator. - */ - LegacyEngine &operator=(LegacyEngine &&other) = delete; - -public: - /** - * engine destructor, cleans up memory etc. - * deletes opengl context, the SDL window, and engine variables. - */ - ~LegacyEngine(); - - /** - * starts the engine loop. - */ - void run(); - - /** - * enqueues the stop of the main loop. - */ - void stop(); - - /** - * return the data directory where the engine was started from. - */ - const util::Path &get_root_dir(); - - /** - * return this engine's job manager. - * - * TODO: remove ptr access - */ - job::JobManager *get_job_manager(); - - /** - * return this engine's cvar manager. - */ - std::shared_ptr get_cvar_manager(); - - /** - * return this engine's qml info. - */ - gui::EngineQMLInfo get_qml_info(); - - /** - * current engine state variable. - * to be set to false to stop the engine loop. - */ - bool running; - - /** - * profiler used by the engine - */ - util::ExternalProfiler external_profiler; - -private: - /** - * Run-mode of the engine, this determines the basic modules to be loaded. - */ - mode run_mode; - - /** - * The engine root directory. - * Uses the openage fslike path abstraction that can mount paths into one. - * - * This means that this path does simulataneously lead to global assets, - * home-folder-assets, settings, and basically the whole filesystem access. - * - * TODO: move this to a settings class, which then also hosts cvar and the options system. - */ - util::Path root_dir; - - /** - * the engine's job manager, for asynchronous background task queuing. - */ - job::JobManager job_manager; - - - /** - * This stores information to be accessible from the QML engine. - * - * Information in there (such as a pointer to the this engine) - * is then usable from within qml files, after some additional magic. - */ - gui::EngineQMLInfo qml_info; - - /** - * the engine's cvar manager. - */ - std::shared_ptr cvar_manager; - - - /** - * the engines profiler - */ - util::Profiler profiler; - - /** - * Logsink to store messages to the filesystem. - */ - std::unique_ptr logsink_file; - - /** - * old, deprecated, and initial implementation of the renderer and game simulation. - * TODO: remove - */ - std::unique_ptr old_display; - -public: - /** - * Signal emitting capability for the engine. - */ - EngineSignals gui_signals; - - /** - * Link to the Qt GUI. - */ - gui::GuiItemLink *gui_link; -}; - -} // namespace openage diff --git a/libopenage/nyan/db.h b/libopenage/nyan/db.h deleted file mode 100644 index 23a39980a6..0000000000 --- a/libopenage/nyan/db.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2018-2019 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../log/log.h" -#include "../error/error.h" - -namespace openage::nyan { - -} diff --git a/libopenage/options.h b/libopenage/options.h index 320b14a54d..0798007f7b 100644 --- a/libopenage/options.h +++ b/libopenage/options.h @@ -36,10 +36,11 @@ using option_list = std::vector; /** * stores a type and value + * + * TODO: What is this used for? */ class OptionValue { public: - /** * value ownership managed by this */ @@ -71,13 +72,13 @@ class OptionValue { /** * Checks equality */ - bool operator ==(const OptionValue &other) const; + bool operator==(const OptionValue &other) const; /** * Assignment, reference values share their values * non reference values are copied */ - const OptionValue &operator =(const OptionValue &other); + const OptionValue &operator=(const OptionValue &other); /** * Value converted to a string @@ -87,7 +88,7 @@ class OptionValue { /** * read inner type - the templated type must match */ - template + template const T &value() const { return var->get(); } @@ -95,13 +96,12 @@ class OptionValue { const option_type type; private: - /** * set the value */ void set(const OptionValue &other); - template + template void set_value(const OptionValue &other) { const T &other_value = other.value(); if (this->var) { @@ -125,7 +125,6 @@ class OptionValue { */ bool owner; util::VariableBase *var; - }; OptionValue parse(option_type t, const std::string &s); @@ -152,7 +151,6 @@ class OptionAction { private: const opt_func_t function; - }; /** @@ -162,8 +160,9 @@ class OptionAction { * with console interaction or gui elements */ class OptionNode { - template + template friend class Var; + public: OptionNode(std::string panel_name); virtual ~OptionNode(); @@ -171,7 +170,7 @@ class OptionNode { /** * lists all available options in a readable format */ - std::vector list_options(bool recurse=false, const std::string &indent=""); + std::vector list_options(bool recurse = false, const std::string &indent = ""); /** * shows all available variable names @@ -189,7 +188,7 @@ class OptionNode { /** * shortcut for get_variable(name).value() */ - template + template const T &getv(const std::string &name) { return this->get_variable(name).value(); } @@ -217,7 +216,6 @@ class OptionNode { const std::string name; protected: - /** * add types to the interface */ @@ -226,7 +224,6 @@ class OptionNode { void add_action(const OptionAction &action); private: - /** * add child nodes */ @@ -264,13 +261,11 @@ class OptionNode { * option node allowing reflection, while also * being directly accessable as a typed member */ -template +template class Var : public util::Variable { public: - Var(OptionNode *owner, const std::string &name, const T &init) - : + Var(OptionNode *owner, const std::string &name, const T &init) : util::Variable{init} { - owner->add(name, this->value); } }; diff --git a/libopenage/pathfinding/a_star.cpp b/libopenage/pathfinding/a_star.cpp index 03b85def97..f80879eb91 100644 --- a/libopenage/pathfinding/a_star.cpp +++ b/libopenage/pathfinding/a_star.cpp @@ -1,4 +1,4 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. /** @file * @@ -16,11 +16,9 @@ #include "../datastructure/pairing_heap.h" #include "../log/log.h" -#include "../terrain/terrain.h" -#include "../terrain/terrain_object.h" #include "../util/strings.h" -#include "path.h" #include "heuristics.h" +#include "path.h" namespace openage { @@ -30,7 +28,6 @@ namespace path { Path to_point(coord::phys3 start, coord::phys3 end, std::function passable) { - auto valid_end = [&](const coord::phys3 &point) -> bool { return euclidean_squared_cost(point, end) < path_grid_size.to_float(); }; @@ -40,21 +37,6 @@ Path to_point(coord::phys3 start, return a_star(start, valid_end, heuristic, passable); } - -Path to_object(openage::TerrainObject *to_move, - openage::TerrainObject *end, - coord::phys_t rad) { - coord::phys3 start = to_move->pos.draw; - auto valid_end = [&](const coord::phys3 &pos) -> bool { - return end->from_edge(pos) < rad; - }; - auto heuristic = [&](const coord::phys3 &pos) -> cost_t { - return (end->from_edge(pos) - to_move->min_axis() / 2L).to_float(); - }; - return a_star(start, valid_end, heuristic, to_move->passable); -} - - Path find_nearest(coord::phys3 start, std::function valid_end, std::function passable) { @@ -67,7 +49,6 @@ Path a_star(coord::phys3 start, std::function valid_end, std::function heuristic, std::function passable) { - // path node storage, always provides cheapest next node. heap_t node_candidates; @@ -93,9 +74,7 @@ Path a_star(coord::phys3 start, // node to terminate the search was found if (valid_end(best_candidate->position)) { - log::log(MSG(dbg) << - "path cost is " << - util::FloatFixed<3, 8>{closest_node->future_cost}); + log::log(MSG(dbg) << "path cost is " << util::FloatFixed<3, 8>{closest_node->future_cost}); return best_candidate->generate_backtrace(); } @@ -128,26 +107,26 @@ Path a_star(coord::phys3 start, } // update new cost knowledge - neighbor->past_cost = new_past_cost; - neighbor->future_cost = neighbor->past_cost + neighbor->heuristic_cost; + neighbor->past_cost = new_past_cost; + neighbor->future_cost = neighbor->past_cost + neighbor->heuristic_cost; neighbor->path_predecessor = best_candidate; if (not_visited) { neighbor->heap_node = node_candidates.push(neighbor); visited_tiles[neighbor->position] = neighbor; - } else { + } + else { node_candidates.decrease(neighbor->heap_node); } } } } - log::log(MSG(dbg) << - "incomplete path cost is " << - util::FloatFixed<3, 8>{closest_node->future_cost}); + log::log(MSG(dbg) << "incomplete path cost is " << util::FloatFixed<3, 8>{closest_node->future_cost}); return closest_node->generate_backtrace(); } -}} // namespace openage::path +} // namespace path +} // namespace openage diff --git a/libopenage/pathfinding/a_star.h b/libopenage/pathfinding/a_star.h index 15d95066e1..23d3e76747 100644 --- a/libopenage/pathfinding/a_star.h +++ b/libopenage/pathfinding/a_star.h @@ -1,4 +1,4 @@ -// Copyright 2014-2016 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. #pragma once @@ -9,8 +9,6 @@ namespace openage { -class TerrainObject; - namespace path { /** @@ -20,13 +18,6 @@ Path to_point(coord::phys3 start, coord::phys3 end, std::function passable); -/** - * path between 2 objects, with how close to come to end point - */ -Path to_object(TerrainObject *to_move, - TerrainObject *end, - coord::phys_t rad); - /** * path to nearest object with lambda */ diff --git a/libopenage/pathfinding/path.cpp b/libopenage/pathfinding/path.cpp index c04e5876c4..f1da51af78 100644 --- a/libopenage/pathfinding/path.cpp +++ b/libopenage/pathfinding/path.cpp @@ -1,21 +1,19 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. #include #include "path.h" -#include "../terrain/terrain.h" namespace openage::path { -bool compare_node_cost::operator ()(const node_pt &lhs, const node_pt &rhs) const { +bool compare_node_cost::operator()(const node_pt &lhs, const node_pt &rhs) const { // TODO: use node operator < return lhs->future_cost < rhs->future_cost; } -Node::Node(const coord::phys3 &pos, node_pt prev) - : +Node::Node(const coord::phys3 &pos, node_pt prev) : position(pos), tile_position(pos.to_tile3().to_tile()), direction{}, @@ -24,22 +22,17 @@ Node::Node(const coord::phys3 &pos, node_pt prev) factor{1.0f}, path_predecessor{prev}, heap_node(nullptr) { - if (prev) { this->direction = (this->position - prev->position).normalize(); // TODO: add dot product to coord - cost_t similarity = ((this->direction.ne.to_float() * - prev->direction.ne.to_float()) + - (this->direction.se.to_float() * - prev->direction.se.to_float())); + cost_t similarity = ((this->direction.ne.to_float() * prev->direction.ne.to_float()) + (this->direction.se.to_float() * prev->direction.se.to_float())); this->factor += (1 - similarity); } } -Node::Node(const coord::phys3 &pos, node_pt prev, cost_t past, cost_t heuristic) - : +Node::Node(const coord::phys3 &pos, node_pt prev, cost_t past, cost_t heuristic) : Node{pos, prev} { this->past_cost = past; this->heuristic_cost = heuristic; @@ -47,12 +40,12 @@ Node::Node(const coord::phys3 &pos, node_pt prev, cost_t past, cost_t heuristic) } -bool Node::operator <(const Node &other) const { +bool Node::operator<(const Node &other) const { return this->future_cost < other.future_cost; } -bool Node::operator ==(const Node &other) const { +bool Node::operator==(const Node &other) const { return this->position == other.position; } @@ -72,7 +65,8 @@ Path Node::generate_backtrace() { Node other = *current; waypoints.push_back(*current); current = current->path_predecessor; - } while (current != nullptr); + } + while (current != nullptr); waypoints.pop_back(); // remove start return {waypoints}; @@ -86,10 +80,10 @@ std::vector Node::get_neighbors(const nodemap_t &nodes, float scale) { coord::phys3 n_pos = this->position + (neigh_phys[n] * scale); if (nodes.count(n_pos) > 0) { - neighbors.push_back( nodes.at(n_pos) ); + neighbors.push_back(nodes.at(n_pos)); } else { - neighbors.push_back( std::make_shared(n_pos, this->shared_from_this()) ); + neighbors.push_back(std::make_shared(n_pos, this->shared_from_this())); } } return neighbors; @@ -114,22 +108,8 @@ bool passable_line(node_pt start, node_pt end, std::function &nodes) - : +Path::Path(const std::vector &nodes) : waypoints{nodes} {} -void Path::draw_path(const coord::CoordManager &mgr) { - glLineWidth(1); - glColor3f(0.3, 1.0, 0.3); - glBegin(GL_LINES); { - for (Node &n : waypoints) { - coord::viewport draw_pos = n.position.to_viewport(mgr); - glVertex3f(draw_pos.x, draw_pos.y, 0); - } - } - glEnd(); -} - - -} // openage::path +} // namespace openage::path diff --git a/libopenage/pathfinding/path.h b/libopenage/pathfinding/path.h index 16784cbd90..e41ddbcc28 100644 --- a/libopenage/pathfinding/path.h +++ b/libopenage/pathfinding/path.h @@ -1,4 +1,4 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. #pragma once @@ -10,17 +10,12 @@ #include "../coord/phys.h" #include "../coord/tile.h" #include "../datastructure/pairing_heap.h" -#include "../util/misc.h" #include "../util/hash.h" - +#include "../util/misc.h" namespace openage { -namespace coord { -class CoordManager; -} - namespace path { class Node; @@ -48,7 +43,7 @@ using nodemap_t = std::unordered_map; * Calls operator < on Node. */ struct compare_node_cost { - bool operator ()(const node_pt &lhs, const node_pt &rhs) const; + bool operator()(const node_pt &lhs, const node_pt &rhs) const; }; /** @@ -59,31 +54,30 @@ using heap_t = datastructure::PairingHeap; /** * Size of phys-coord grid for path nodes. */ -constexpr coord::phys_t path_grid_size{1.f/8}; +constexpr coord::phys_t path_grid_size{1.f / 8}; /** * Phys3 delta coordinates to select for path neighbors. */ constexpr coord::phys3_delta const neigh_phys[] = { - {path_grid_size * 1, path_grid_size * -1, 0}, - {path_grid_size * 1, path_grid_size * 0, 0}, - {path_grid_size * 1, path_grid_size * 1, 0}, - {path_grid_size * 0, path_grid_size * 1, 0}, - {path_grid_size * -1, path_grid_size * 1, 0}, - {path_grid_size * -1, path_grid_size * 0, 0}, + {path_grid_size * 1, path_grid_size * -1, 0}, + {path_grid_size * 1, path_grid_size * 0, 0}, + {path_grid_size * 1, path_grid_size * 1, 0}, + {path_grid_size * 0, path_grid_size * 1, 0}, + {path_grid_size * -1, path_grid_size * 1, 0}, + {path_grid_size * -1, path_grid_size * 0, 0}, {path_grid_size * -1, path_grid_size * -1, 0}, - {path_grid_size * 0, path_grid_size * -1, 0} -}; + {path_grid_size * 0, path_grid_size * -1, 0}}; /** * */ -bool passable_line(node_pt start, node_pt end, std::functionpassable, float samples=5.0f); +bool passable_line(node_pt start, node_pt end, std::function passable, float samples = 5.0f); /** * One navigation waypoint in a path. */ -class Node: public std::enable_shared_from_this { +class Node : public std::enable_shared_from_this { public: Node(const coord::phys3 &pos, node_pt prev); Node(const coord::phys3 &pos, node_pt prev, cost_t past, cost_t heuristic); @@ -91,13 +85,13 @@ class Node: public std::enable_shared_from_this { /** * Orders nodes according to their future cost value. */ - bool operator <(const Node &other) const; + bool operator<(const Node &other) const; /** * Compare the node to another one. * They are the same if their position is. */ - bool operator ==(const Node &other) const; + bool operator==(const Node &other) const; /** * Calculates the actual movement cose to another node. @@ -112,7 +106,7 @@ class Node: public std::enable_shared_from_this { /** * Get all neighbors of this graph node. */ - std::vector get_neighbors(const nodemap_t &, float scale=1.0f); + std::vector get_neighbors(const nodemap_t &, float scale = 1.0f); /** * The tile position this node is associated to. @@ -184,8 +178,6 @@ class Path { Path() = default; Path(const std::vector &nodes); - void draw_path(const coord::CoordManager &mgr); - /** * These are the waypoints to navigate in order. * Includes the start and end node. @@ -203,9 +195,9 @@ namespace std { * Hash function for path nodes. * Just uses their position. */ -template<> +template <> struct hash { - size_t operator ()(const openage::path::Node &x) const { + size_t operator()(const openage::path::Node &x) const { openage::coord::phys3 node_pos = x.position; size_t hash = openage::util::type_hash(); hash = openage::util::hash_combine(hash, std::hash{}(node_pos.ne)); diff --git a/libopenage/presenter/CMakeLists.txt b/libopenage/presenter/CMakeLists.txt index d0fc81f7be..5a824fab5a 100644 --- a/libopenage/presenter/CMakeLists.txt +++ b/libopenage/presenter/CMakeLists.txt @@ -1,6 +1,3 @@ add_sources(libopenage presenter.cpp ) - -add_subdirectory("legacy") -add_subdirectory("assets") diff --git a/libopenage/presenter/assets/CMakeLists.txt b/libopenage/presenter/assets/CMakeLists.txt deleted file mode 100644 index 59346cbc3e..0000000000 --- a/libopenage/presenter/assets/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_sources(libopenage - asset_manager.cpp -) diff --git a/libopenage/presenter/assets/asset_manager.cpp b/libopenage/presenter/assets/asset_manager.cpp deleted file mode 100644 index 0077d0db95..0000000000 --- a/libopenage/presenter/assets/asset_manager.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#include "asset_manager.h" - -#if WITH_INOTIFY -#include /* for NAME_MAX */ -#include -#include -#endif - -#include "error/error.h" -#include "log/log.h" -#include "texture.h" -#include "util/compiler.h" -#include "util/file.h" - -namespace openage::presenter { - -AssetManager::AssetManager() : - missing_tex{nullptr} { -#if WITH_INOTIFY - // initialize the inotify instance - this->inotify_fd = inotify_init1(IN_NONBLOCK); - if (this->inotify_fd < 0) { - throw Error{MSG(err) << "Failed to initialize inotify!"}; - } -#endif -} - -AssetManager::AssetManager(const util::Path &asset_dir) : - asset_dir{asset_dir}, - missing_tex{nullptr} { -#if WITH_INOTIFY - // initialize the inotify instance - this->inotify_fd = inotify_init1(IN_NONBLOCK); - if (this->inotify_fd < 0) { - throw Error{MSG(err) << "Failed to initialize inotify!"}; - } -#endif -} - - -const util::Path &AssetManager::get_asset_dir() { - return this->asset_dir; -} - - -void AssetManager::set_asset_dir(const util::Path &new_path) { - if (this->asset_dir != new_path) { - this->asset_dir = new_path; - this->clear(); - } -} - - -std::shared_ptr AssetManager::load_texture(const std::string &name, - bool use_metafile, - bool null_if_missing) { - // the texture to be associated with the given filename - std::shared_ptr tex; - - util::Path tex_path = this->asset_dir[name]; - - // try to open the texture filename. - if (not tex_path.is_file()) { - // TODO: add/fetch inotify watch on the containing folder - // to display the tex as soon at it exists. - - if (null_if_missing) { - return nullptr; - } - else { - // return the big X texture instead - tex = this->get_missing_tex(); - } - } - else { - // create the texture! - tex = std::make_shared(tex_path, use_metafile); - -#if WITH_INOTIFY - std::string native_path = tex_path.resolve_native_path(); - - if (native_path.size() > 0) { - // create inotify update trigger for the requested file - - // TODO: let util::Path do the file watching - int wd = inotify_add_watch( - this->inotify_fd, - native_path.c_str(), - IN_CLOSE_WRITE); - - if (wd < 0) { - log::log(WARN << "Failed to add inotify watch for " << native_path); - } - else { - this->watch_fds[wd] = tex; - } - } -#endif - } - - // pass back the shared_ptr - return tex; -} - - -Texture *AssetManager::get_texture(const std::string &name, bool use_metafile, bool null_if_missing) { - // check whether the requested texture was loaded already - auto tex_it = this->textures.find(name); - - // the texture was not loaded yet: - if (tex_it == this->textures.end()) { - auto tex = this->load_texture(name, use_metafile, null_if_missing); - - if (tex.get() != nullptr) { - // insert the texture into the map - this->textures.insert(std::make_pair(name, tex)); - } - - // and return the texture pointer. - return tex.get(); - } - - return tex_it->second.get(); -} - - -void AssetManager::check_updates() { -#if WITH_INOTIFY - // buffer for at least 4 inotify events - char buf[4 * (sizeof(struct inotify_event) + NAME_MAX + 1)]; - ssize_t len; - - while (true) { - // fetch all events, the kernel won't write "half" structs. - len = read(this->inotify_fd, buf, sizeof(buf)); - - if (len == -1) { - if (errno == EAGAIN) { - // no events, nothing to do. - break; - } - else { - // something went wrong - log::log(WARN << "Failed to read inotify events!"); - break; - } - } - - // process fetched events, - // the kernel guarantees complete events in the buffer. - char *ptr = buf; - while (ptr < buf + len) { - auto *event = reinterpret_cast(ptr); - - if (event->mask & IN_CLOSE_WRITE) { - // TODO: this should invoke callback functions - this->watch_fds[event->wd]->reload(); - } - - // move the buffer ptr to the next event. - ptr += sizeof(struct inotify_event) + event->len; - } - } -#endif -} - -std::shared_ptr AssetManager::get_missing_tex() { - // if not loaded, fetch the "missing" texture (big red X). - if (this->missing_tex.get() == nullptr) [[unlikely]] { - this->missing_tex = std::make_shared( - this->asset_dir["test"]["textures"]["missing.png"], - false); - } - - return this->missing_tex; -} - -void AssetManager::clear() { -#if WITH_INOTIFY - for (auto &watch_fd : this->watch_fds) { - int result = inotify_rm_watch(this->inotify_fd, watch_fd.first); - if (result < 0) { - log::log(WARN << "Failed to remove inotify watches"); - } - } - this->watch_fds.clear(); -#endif - - this->textures.clear(); -} - -} // namespace openage::presenter diff --git a/libopenage/presenter/assets/asset_manager.h b/libopenage/presenter/assets/asset_manager.h deleted file mode 100644 index 48075eeaeb..0000000000 --- a/libopenage/presenter/assets/asset_manager.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "config.h" - -#include -#include -#include - -#include "util/path.h" - -namespace qtsdl { -class GuiItemLink; -} // namespace qtsdl - -namespace openage { -class Texture; -} // namespace openage - -namespace openage::presenter { - -/** - * Container class for all available assets. - * Responsible for loading, providing and updating requested files. - */ -class AssetManager final { -public: - AssetManager(); - AssetManager(const util::Path &asset_dir); - - /** - * Return the path where assets are found in. - */ - const util::Path &get_asset_dir(); - - /** - * Set the asset search path. - */ - void set_asset_dir(const util::Path &new_path); - - /** - * Query the Texture for a given filename. - * - * @param name: the asset file name relative to the asset root. - * @param use_metafile: load subtexture information from meta file - * @param null_if_missing: instead of providing the "missing texture", - * return nullptr. - * @returns the queried texture handle. - */ - Texture *get_texture(const std::string &name, - bool use_metafile = true, - bool null_if_missing = false); - - /** - * Ask the kernel whether there were updates to watched files. - */ - void check_updates(); - -protected: - /** - * Create an internal texture handle. - */ - std::shared_ptr load_texture(const std::string &name, - bool use_metafile = true, - bool null_if_missing = false); - - /** - * Retrieves the texture for missing textures. - */ - std::shared_ptr get_missing_tex(); - -private: - void clear(); - - /** - * The root directory for the available assets. - */ - util::Path asset_dir; - - /** - * The replacement texture for missing textures. - */ - std::shared_ptr missing_tex; - - /** - * Map from texture filename to texture instance ptr. - */ - std::unordered_map> textures; - -#if WITH_INOTIFY - /** - * The file descriptor pointing to the inotify instance. - */ - int inotify_fd; - - /** - * Map from inotify watch handle fd to texture instance ptr. - * The kernel returns the handle fd when events are triggered. - */ - std::unordered_map> watch_fds; -#endif -}; - -} // namespace openage::presenter diff --git a/libopenage/presenter/legacy/CMakeLists.txt b/libopenage/presenter/legacy/CMakeLists.txt deleted file mode 100644 index d4add0acd2..0000000000 --- a/libopenage/presenter/legacy/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_sources(libopenage - game_control.cpp - legacy.cpp - legacy_renderer.cpp -) - -pxdgen( - legacy.h -) diff --git a/libopenage/presenter/legacy/game_control.cpp b/libopenage/presenter/legacy/game_control.cpp deleted file mode 100644 index 91255b1b54..0000000000 --- a/libopenage/presenter/legacy/game_control.cpp +++ /dev/null @@ -1,916 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "game_control.h" - -#include "error/error.h" -#include "gamestate/old/game_spec.h" -#include "legacy_engine.h" -#include "log/log.h" -#include "renderer/color.h" -#include "terrain/terrain_chunk.h" -#include "util/strings.h" - - -namespace openage { - -OutputMode::OutputMode(qtsdl::GuiItemLink *gui_link) : - game_control{nullptr}, - gui_link{gui_link} { -} - -OutputMode::~OutputMode() { - // An empty deconstructor prevents our clients from needing - // to implement one. - // - // The deconstructor is needed in the first place to stop - // the compiler from generating ud2 (undefined) instructors - // for the body of this method. -} - -void OutputMode::announce() { - emit this->gui_signals.announced(this->name()); - - emit this->gui_signals.binds_changed(this->active_binds()); -} - -void OutputMode::set_game_control(GameControl *game_control) { - this->game_control = game_control; - - this->on_game_control_set(); - this->announce(); -} - -CreateMode::CreateMode(qtsdl::GuiItemLink *gui_link) : - OutputMode{gui_link} {} - -bool CreateMode::available() const { - return true; -} - -std::string CreateMode::name() const { - return "Creation Mode"; -} - -void CreateMode::on_game_control_set() {} - -void CreateMode::on_enter() {} - -void CreateMode::on_exit() {} - -void CreateMode::render() {} - - -ActionModeSignals::ActionModeSignals(ActionMode *action_mode) : - action_mode(action_mode) { -} - -void ActionModeSignals::on_action(const std::string &action_name) { - presenter::LegacyDisplay *display = this->action_mode->game_control->get_display(); - - const input::legacy::action_t &action = display->get_action_manager().get(action_name); - input::legacy::InputContext *top_ctxt = &display->get_input_manager().get_top_context(); - - if (top_ctxt == this->action_mode || top_ctxt == &this->action_mode->building_context || top_ctxt == &this->action_mode->build_menu_context || top_ctxt == &this->action_mode->build_menu_mil_context) { - // create an action that just relays the action. - input::legacy::action_arg_t action_arg{ - input::legacy::Event{input::legacy::event_class::ANY, 0, input::legacy::modset_t{}}, - coord::input{0, 0}, - coord::input_delta{0, 0}, - {action}}; - top_ctxt->execute_if_bound(action_arg); - } -} - -ActionMode::ActionMode(qtsdl::GuiItemLink *gui_link) : - OutputMode{gui_link}, - selection{nullptr}, - use_set_ability{false}, - type_focus{nullptr}, - selecting{false}, - rng{rng::random_seed()}, - gui_signals{this} {} - - -void ActionMode::on_game_control_set() { - ENSURE(this->game_control != nullptr, "no control was actually set"); - - LegacyEngine *engine = this->game_control->get_engine(); - presenter::LegacyDisplay *display = this->game_control->get_display(); - ENSURE(engine != nullptr, "engine must be known!"); - - auto &action = display->get_action_manager(); - auto input = &display->get_input_manager(); - coord::CoordManager &coord = display->coord; - - // TODO: the selection should not be used in here! - this->selection = display->get_unit_selection(); - ENSURE(this->selection != nullptr, "selection must be fetched!"); - - this->bind(action.get("TRAIN_OBJECT"), - [this](const input::legacy::action_arg_t &) { - // attempt to train editor selected object - - // randomly select between male and female villagers - auto player = this->game_control->get_current_player(); - auto type = player->get_type(this->rng.probability(0.5) ? 83 : 293); - - Command cmd(*player, type); - cmd.add_flag(command_flag::interrupt); - this->selection->all_invoke(cmd); - }); - - this->bind(action.get("ENABLE_BUILDING_PLACEMENT"), - [](const input::legacy::action_arg_t &) { - // this->building_placement = true; - }); - - this->bind(action.get("DISABLE_SET_ABILITY"), - [this](const input::legacy::action_arg_t &) { - this->use_set_ability = false; - }); - - this->bind(action.get("SET_ABILITY_MOVE"), - [this](const input::legacy::action_arg_t &) { - this->use_set_ability = true; - this->ability = ability_type::move; - emit this->gui_signals.ability_changed(std::to_string(this->ability)); - }); - - this->bind(action.get("SET_ABILITY_GATHER"), - [this](const input::legacy::action_arg_t &) { - this->use_set_ability = true; - this->ability = ability_type::gather; - emit this->gui_signals.ability_changed(std::to_string(this->ability)); - }); - - this->bind(action.get("SET_ABILITY_GARRISON"), - [this](const input::legacy::action_arg_t &) { - this->use_set_ability = true; - this->ability = ability_type::garrison; - emit this->gui_signals.ability_changed(std::to_string(this->ability)); - }); - - this->bind(action.get("SET_ABILITY_REPAIR"), [this](const input::legacy::action_arg_t &) { - this->use_set_ability = true; - this->ability = ability_type::repair; - emit this->gui_signals.ability_changed(std::to_string(this->ability)); - }); - - this->bind(action.get("SPAWN_VILLAGER"), - [this, display](const input::legacy::action_arg_t &) { - auto player = this->game_control->get_current_player(); - - if (player->type_count() > 0) { - UnitType &type = *player->get_type(590); - - // TODO tile position - display->get_game()->placed_units.new_unit(type, *player, this->mousepos_phys3); - } - }); - - this->bind(action.get("KILL_UNIT"), - [this](const input::legacy::action_arg_t &) { - this->selection->kill_unit(*this->game_control->get_current_player()); - }); - - this->bind(action.get("BUILD_MENU"), - [this, input](const input::legacy::action_arg_t &) { - log::log(MSG(dbg) << "Opening build menu"); - input->push_context(&this->build_menu_context); - this->announce_buttons_type(); - }); - - this->bind(action.get("BUILD_MENU_MIL"), - [this, input](const input::legacy::action_arg_t &) { - log::log(MSG(dbg) << "Opening military build menu"); - input->push_context(&this->build_menu_mil_context); - this->announce_buttons_type(); - }); - - this->build_menu_context.bind(action.get("CANCEL"), - [this, input](const input::legacy::action_arg_t &) { - input->remove_context(&this->build_menu_context); - this->announce_buttons_type(); - }); - - this->build_menu_mil_context.bind(action.get("CANCEL"), - [this, input](const input::legacy::action_arg_t &) { - input->remove_context(&this->build_menu_mil_context); - this->announce_buttons_type(); - }); - - // Villager build commands - auto bind_building_key = [this, input](input::legacy::action_t action, int building, input::legacy::InputContext *ctxt) { - ctxt->bind(action, [this, building, ctxt, input](const input::legacy::action_arg_t &) { - auto player = this->game_control->get_current_player(); - if (this->selection->contains_builders(*player)) { - auto player = this->game_control->get_current_player(); - this->type_focus = player->get_type(building); - - if (player->can_make(*this->type_focus)) { - if (&input->get_top_context() != &this->building_context) { - input->remove_context(ctxt); - input->push_context(&this->building_context); - this->announce_buttons_type(); - } - } - else { - // TODO show in game error message - } - } - }); - }; - - bind_building_key(action.get("BUILDING_HOUS"), 70, &this->build_menu_context); // House - bind_building_key(action.get("BUILDING_MILL"), 68, &this->build_menu_context); // Mill - bind_building_key(action.get("BUILDING_MINE"), 584, &this->build_menu_context); // Mining Camp - bind_building_key(action.get("BUILDING_SMIL"), 562, &this->build_menu_context); // Lumber Camp - bind_building_key(action.get("BUILDING_DOCK"), 47, &this->build_menu_context); // Dock - // TODO: Doesn't show until it is placed - bind_building_key(action.get("BUILDING_FARM"), 50, &this->build_menu_context); // Farm - bind_building_key(action.get("BUILDING_BLAC"), 103, &this->build_menu_context); // Blacksmith - bind_building_key(action.get("BUILDING_MRKT"), 84, &this->build_menu_context); // Market - bind_building_key(action.get("BUILDING_CRCH"), 104, &this->build_menu_context); // Monastery - bind_building_key(action.get("BUILDING_UNIV"), 209, &this->build_menu_context); // University - bind_building_key(action.get("BUILDING_RTWC"), 109, &this->build_menu_context); // Town Center - bind_building_key(action.get("BUILDING_WNDR"), 276, &this->build_menu_context); // Wonder - - bind_building_key(action.get("BUILDING_BRKS"), 12, &this->build_menu_mil_context); // Barracks - bind_building_key(action.get("BUILDING_ARRG"), 87, &this->build_menu_mil_context); // Archery Range - bind_building_key(action.get("BUILDING_STBL"), 101, &this->build_menu_mil_context); // Stable - bind_building_key(action.get("BUILDING_SIWS"), 49, &this->build_menu_mil_context); // Siege Workshop - bind_building_key(action.get("BUILDING_WCTWX"), 598, &this->build_menu_mil_context); // Outpost - // TODO for palisade and stone wall: Drag walls, automatically adjust orientation - // TODO: This just cycles through all palisade textures - bind_building_key(action.get("BUILDING_WALL"), 72, &this->build_menu_mil_context); // Palisade Wall - // TODO: Fortified wall has a different ID - bind_building_key(action.get("BUILDING_WALL2"), 117, &this->build_menu_mil_context); // Stone Wall - // TODO: Upgraded versions have different IDs - bind_building_key(action.get("BUILDING_WCTW"), 79, &this->build_menu_mil_context); // Watch Tower - bind_building_key(action.get("BUILDING_WCTW4"), 236, &this->build_menu_mil_context); // Bombard Tower - // TODO: Gate placement - 659 is horizontal closed - bind_building_key(action.get("BUILDING_GTCA2"), 659, &this->build_menu_mil_context); // Gate - bind_building_key(action.get("BUILDING_CSTL"), 82, &this->build_menu_mil_context); // Castle - - this->building_context.bind(action.get("CANCEL"), - [this, input](const input::legacy::action_arg_t &) { - input->remove_context(&this->building_context); - this->announce_buttons_type(); - this->type_focus = nullptr; - }); - - auto bind_build = [this, input, &coord](input::legacy::action_t action, const bool increase) { - this->building_context.bind(action, [this, increase, input, &coord](const input::legacy::action_arg_t &arg) { - this->mousepos_phys3 = arg.mouse.to_phys3(coord, 0); - this->mousepos_tile = this->mousepos_phys3.to_tile(); - - bool placed = this->place_selection(this->mousepos_phys3); - - if (placed && !increase) { - this->type_focus = nullptr; - input->remove_context(&this->building_context); - this->announce_buttons_type(); - } - }); - }; - - bind_build(action.get("BUILD"), false); - bind_build(action.get("KEEP_BUILDING"), true); - - auto bind_select = [this, input, display](input::legacy::action_t action, const bool increase) { - this->bind(action, [this, increase, input, display](const input::legacy::action_arg_t &arg) { - auto mousepos_camgame = arg.mouse.to_camgame(display->coord); - Terrain *terrain = display->get_game()->terrain.get(); - - this->selection->drag_update(mousepos_camgame); - this->selection->drag_release(*this->game_control->get_current_player(), terrain, increase); - InputContext *top_ctxt = &input->get_top_context(); - - if ((this->selection->get_selection_type() != selection_type_t::own_units or this->selection->contains_military(*this->game_control->get_current_player())) - and (top_ctxt == &this->build_menu_context || top_ctxt == &this->build_menu_mil_context)) { - input->remove_context(top_ctxt); - } - this->announce_buttons_type(); - this->announce_current_selection(); - }); - }; - - bind_select(action.get("SELECT"), false); - bind_select(action.get("INCREASE_SELECTION"), true); - - this->bind(action.get("ORDER_SELECT"), [this, input, &coord](const input::legacy::action_arg_t &arg) { - if (this->type_focus) { - // right click can cancel building placement - this->type_focus = nullptr; - input->remove_context(&this->building_context); - this->announce_buttons_type(); - } - - auto cmd = this->get_action(arg.mouse.to_phys3(coord)); - cmd.add_flag(command_flag::interrupt); - this->selection->all_invoke(cmd); - this->use_set_ability = false; - }); - - this->bind(action.get("BEGIN_SELECTION"), [this](const input::legacy::action_arg_t &) { - this->selecting = true; - }); - - this->bind(action.get("END_SELECTION"), [this](const input::legacy::action_arg_t &) { - this->selecting = false; - }); - - this->bind(input::legacy::event_class::MOUSE, [this, &coord](const input::legacy::action_arg_t &arg) { - auto mousepos_camgame = arg.mouse.to_camgame(coord); - this->mousepos_phys3 = mousepos_camgame.to_phys3(coord); - this->mousepos_tile = this->mousepos_phys3.to_tile(); - - // drag selection box - if (arg.e.cc == input::legacy::ClassCode(input::legacy::event_class::MOUSE_MOTION, 0) && this->selecting && !this->type_focus) { - this->selection->drag_update(mousepos_camgame); - this->announce_current_selection(); - return true; - } - return false; - }); -} - -bool ActionMode::available() const { - if (this->game_control == nullptr) { - log::log(MSG(warn) << "ActionMode::available() queried without " - "game control being attached."); - return false; - } - - presenter::LegacyDisplay *display = this->game_control->get_display(); - if (display->get_game() != nullptr) { - return true; - } - else { - log::log(MSG(warn) << "Cannot enter action mode without a game"); - return false; - } -} - -void ActionMode::on_enter() {} - -void ActionMode::on_exit() { - // Since on_exit is called after removing the active mode, if the top context isn't the global one then it must - // be either a build menu or the building context - presenter::LegacyDisplay *display = this->game_control->get_display(); - auto *input_manager = &display->get_input_manager(); - InputContext *top_ctxt = &input_manager->get_top_context(); - if (top_ctxt != &input_manager->get_global_context()) { - if (top_ctxt == &this->building_context) { - this->type_focus = nullptr; - } - input_manager->remove_context(top_ctxt); - this->announce_buttons_type(); - } - this->selecting = false; -} - -Command ActionMode::get_action(const coord::phys3 &pos) const { - presenter::LegacyDisplay *display = this->game_control->get_display(); - GameMain *game = display->get_game(); - - auto obj = game->terrain->obj_at_point(pos); - if (obj) { - Command c(*this->game_control->get_current_player(), &obj->unit, pos); - if (this->use_set_ability) { - c.set_ability(ability); - } - return c; - } - else { - Command c(*this->game_control->get_current_player(), pos); - if (this->use_set_ability) { - c.set_ability(ability); - } - return c; - } -} - -bool ActionMode::place_selection(coord::phys3 point) { - if (this->type_focus) { - auto player = this->game_control->get_current_player(); - - if (player->can_make(*this->type_focus)) { - // confirm building placement with left click - // first create foundation using the producer - presenter::LegacyDisplay *display = this->game_control->get_display(); - - UnitContainer *container = &display->get_game()->placed_units; - UnitReference new_building = container->new_unit(*this->type_focus, *player, point); - - // task all selected villagers to build - // TODO: editor placed objects are completed already - if (new_building.is_valid()) { - player->deduct(this->type_focus->cost.get(*player)); // TODO change, move elsewheres - - Command cmd(*player, new_building.get()); - cmd.set_ability(ability_type::build); - cmd.add_flag(command_flag::interrupt); - this->selection->all_invoke(cmd); - return true; - } - } - else { - // TODO show in game error message - return false; - } - } - return false; -} - -void ActionMode::render() { - ENSURE(this->game_control != nullptr, "game_control is unset"); - LegacyEngine *engine = this->game_control->get_engine(); - presenter::LegacyDisplay *display = this->game_control->get_display(); - - ENSURE(engine != nullptr, "engine is needed to render ActionMode"); - - if (GameMain *game = display->get_game()) { - Player *player = this->game_control->get_current_player(); - - this->announce_resources(); - - if (this->selection && this->selection->get_units_count() > 0) { - this->announce_current_selection(); - } - - // when a building is being placed - if (this->type_focus) { - auto txt = this->type_focus->default_texture(); - auto size = this->type_focus->foundation_size; - - tile_range center = building_center(this->mousepos_phys3, size, *game->terrain); - txt->sample(display->coord, center.draw.to_camhud(display->coord), player->color); - } - } - else { - display->render_text({0, 140}, 12, renderer::Colors::WHITE, "Action Mode requires a game"); - } - - ENSURE(this->selection != nullptr, "selection not set"); - - this->selection->on_drawhud(); -} - -std::string ActionMode::name() const { - return "Action Mode"; -} - -void ActionMode::announce() { - this->OutputMode::announce(); - - this->announce_resources(); - emit this->gui_signals.ability_changed( - this->use_set_ability ? std::to_string(this->ability) : ""); -} - -void ActionMode::announce_resources() { - if (this->game_control) { - if (Player *player = this->game_control->get_current_player()) { - for (auto i = static_cast::type>(game_resource::RESOURCE_TYPE_COUNT); i != 0; --i) { - auto resource_type = static_cast(i - 1); - - emit this->gui_signals.resource_changed( - resource_type, - static_cast(player->amount(resource_type))); - } - emit this->gui_signals.population_changed(player->population.get_demand(), player->population.get_capacity(), player->population.get_space() <= 0 && !player->population.is_capacity_maxed()); - } - } -} - -void ActionMode::announce_buttons_type() { - ActionButtonsType buttons_type; - presenter::LegacyDisplay *display = this->game_control->get_display(); - InputContext *top_ctxt = &display->get_input_manager().get_top_context(); - if (top_ctxt == &this->build_menu_context) { - buttons_type = ActionButtonsType::BuildMenu; - } - else if (top_ctxt == &this->build_menu_mil_context) { - buttons_type = ActionButtonsType::MilBuildMenu; - } - else if (top_ctxt == &this->building_context || this->selection->get_selection_type() != selection_type_t::own_units) { - buttons_type = ActionButtonsType::None; - } - else if (this->selection->contains_military(*this->game_control->get_current_player())) { - buttons_type = ActionButtonsType::MilitaryUnits; - } - else { - buttons_type = ActionButtonsType::CivilianUnits; - } - - if (buttons_type != this->buttons_type) { - this->buttons_type = buttons_type; - emit this->gui_signals.buttons_type_changed(buttons_type); - - // announce the changed input context - this->announce(); - } -} - -EditorModeSignals::EditorModeSignals(EditorMode *editor_mode) : - editor_mode{editor_mode} { -} - -void EditorModeSignals::on_current_player_name_changed() { - this->editor_mode->announce_categories(); -} - -EditorMode::EditorMode(qtsdl::GuiItemLink *gui_link) : - OutputMode{gui_link}, - editor_current_terrain{-1}, - current_type_id{-1}, - paint_terrain{}, - gui_signals{this} {} - - -void EditorMode::on_game_control_set() { - presenter::LegacyDisplay *display = this->game_control->get_display(); - auto &action = display->get_action_manager(); - - // bind required hotkeys - this->bind(action.get("ENABLE_BUILDING_PLACEMENT"), [this](const input::legacy::action_arg_t &) { - log::log(MSG(dbg) << "change category"); - emit this->gui_signals.toggle(); - }); - - this->bind(input::legacy::event_class::MOUSE, [this, display](const input::legacy::action_arg_t &arg) { - if (arg.e.cc == input::legacy::ClassCode(input::legacy::event_class::MOUSE_BUTTON, 1) || display->get_input_manager().is_down(input::legacy::event_class::MOUSE_BUTTON, 1)) { - if (this->paint_terrain) { - this->paint_terrain_at(arg.mouse.to_viewport(display->coord)); - } - else { - this->paint_entity_at(arg.mouse.to_viewport(display->coord), false); - } - return true; - } - else if (arg.e.cc == input::legacy::ClassCode(input::legacy::event_class::MOUSE_BUTTON, 3) || display->get_input_manager().is_down(input::legacy::event_class::MOUSE_BUTTON, 3)) { - if (!this->paint_terrain) { - this->paint_entity_at(arg.mouse.to_viewport(display->coord), true); - } - return true; - } - return false; - }); -} - -bool EditorMode::available() const { - if (this->game_control == nullptr) { - log::log(MSG(warn) << "game_control not yet linked to EditorMode"); - return false; - } - else if (this->game_control->get_display()->get_game() != nullptr) { - return true; - } - else { - log::log(MSG(warn) << "Cannot enter editor mode without a game"); - return false; - } -} - -void EditorMode::on_enter() {} - -void EditorMode::on_exit() {} - -void EditorMode::render() {} - -std::string EditorMode::name() const { - return "Editor mode"; -} - -void EditorMode::set_current_type_id(int current_type_id) { - this->current_type_id = current_type_id; -} - -void EditorMode::set_current_terrain_id(terrain_t current_terrain_id) { - this->editor_current_terrain = current_terrain_id; -} - -void EditorMode::set_paint_terrain(bool paint_terrain) { - this->paint_terrain = paint_terrain; -} - -void EditorMode::paint_terrain_at(const coord::viewport &point) { - presenter::LegacyDisplay *display = this->game_control->get_display(); - Terrain *terrain = display->get_game()->terrain.get(); - - auto mousepos_tile = point.to_tile(display->coord); - - TerrainChunk *chunk = terrain->get_create_chunk(mousepos_tile); - chunk->get_data(mousepos_tile.get_pos_on_chunk())->terrain_id = editor_current_terrain; -} - -void EditorMode::paint_entity_at(const coord::viewport &point, const bool del) { - presenter::LegacyDisplay *display = this->game_control->get_display(); - GameMain *game = display->get_game(); - Terrain *terrain = game->terrain.get(); - - auto mousepos_phys3 = point.to_phys3(display->coord); - auto mousepos_tile = mousepos_phys3.to_tile(); - - TerrainChunk *chunk = terrain->get_create_chunk(mousepos_tile); - // TODO : better detection of presence of unit - if (!chunk->get_data(mousepos_tile.get_pos_on_chunk())->obj.empty()) { - if (del) { - // delete first object currently standing at the clicked position - TerrainObject *obj = chunk->get_data(mousepos_tile.get_pos_on_chunk())->obj[0]; - obj->remove(); - } - } - else if (!del && this->current_type_id != -1) { - Player *player = this->game_control->get_current_player(); - UnitType *selected_type = player->get_type(this->current_type_id); - - // tile is empty so try creating a unit - UnitContainer *container = &game->placed_units; - container->new_unit(*selected_type, *this->game_control->get_current_player(), mousepos_phys3); - } -} - -void EditorMode::announce_categories() { - if (this->game_control) - if (auto player = this->game_control->get_current_player()) - emit this->gui_signals.categories_changed(player->civ->get_type_categories()); - - emit this->gui_signals.categories_content_changed(); -} - -void EditorMode::announce_category_content(const std::string &category_name) { - if (this->game_control) - if (auto player = this->game_control->get_current_player()) { - auto inds = player->civ->get_category(category_name); - std::vector> type_and_texture(inds.size()); - - auto it = std::begin(type_and_texture); - - std::for_each(std::begin(inds), std::end(inds), [player, &it](auto index) { - *it++ = std::make_tuple(index, player->get_type(index)->default_texture()->id); - }); - - emit this->gui_signals.category_content_changed(category_name, type_and_texture); - } -} - -void EditorMode::announce() { - OutputMode::announce(); - this->announce_categories(); -} - -void EditorMode::set_game_control(GameControl *game_control) { - if (this->game_control != game_control) { - if (this->game_control) - QObject::disconnect( - &this->game_control->gui_signals, - &GameControlSignals::current_player_name_changed, - &this->gui_signals, - &EditorModeSignals::on_current_player_name_changed); - - // actually set the control - OutputMode::set_game_control(game_control); - - if (this->game_control) - QObject::connect( - &this->game_control->gui_signals, - &GameControlSignals::current_player_name_changed, - &this->gui_signals, - &EditorModeSignals::on_current_player_name_changed); - - this->announce_categories(); - } - else { - // just set the control - OutputMode::set_game_control(game_control); - } -} - -GameControlSignals::GameControlSignals(GameControl *game_control) : - game_control{game_control} { -} - -void GameControlSignals::on_game_running(bool running) { - if (running) - this->game_control->announce_current_player_name(); -} - -GameControl::GameControl(qtsdl::GuiItemLink *gui_link) : - engine{nullptr}, - game{nullptr}, - active_mode{nullptr}, - active_mode_index{-1}, - current_player{1}, - gui_signals{this}, - gui_link{gui_link} { -} - -void GameControl::set_engine(LegacyEngine *engine) { - // TODO: decide to either go for a full Engine QML-singleton or for a regular object - ENSURE(!this->engine || this->engine == engine, "relinking GameControl to another engine is not supported and not caught properly"); - - if (not this->engine) { - this->engine = engine; - - // add handlers - this->display->register_drawhud_action(this, -1); - - auto &action = this->display->get_action_manager(); - - auto &global_input_context = display->get_input_manager().get_global_context(); - - // advance the active mode - global_input_context.bind(action.get("TOGGLE_CONSTRUCT_MODE"), [this](const input::legacy::action_arg_t &) { - this->set_mode((this->active_mode_index + 1) % this->modes.size()); - }); - - // Switching between players with the 1-8 keys - auto bind_player_switch = [this, &global_input_context](input::legacy::action_t action, size_t player_index) { - global_input_context.bind(action, [this, player_index](const input::legacy::action_arg_t &) { - if (this->current_player != player_index) - if (auto game = this->display->get_game()) - if (player_index < game->player_count()) { - this->current_player = player_index; - this->announce_current_player_name(); - } - }); - }; - - bind_player_switch(action.get("SWITCH_TO_PLAYER_1"), 0); - bind_player_switch(action.get("SWITCH_TO_PLAYER_2"), 1); - bind_player_switch(action.get("SWITCH_TO_PLAYER_3"), 2); - bind_player_switch(action.get("SWITCH_TO_PLAYER_4"), 3); - bind_player_switch(action.get("SWITCH_TO_PLAYER_5"), 4); - bind_player_switch(action.get("SWITCH_TO_PLAYER_6"), 5); - bind_player_switch(action.get("SWITCH_TO_PLAYER_7"), 6); - bind_player_switch(action.get("SWITCH_TO_PLAYER_8"), 7); - - this->display->announce_global_binds(); - } -} -void GameControl::set_display(presenter::LegacyDisplay *display) { - this->display = display; -} - -void GameControl::set_game(GameMainHandle *game) { - if (this->game != game) { - if (this->game) - QObject::disconnect(&this->game->gui_signals, - &GameMainSignals::game_running, - &this->gui_signals, - &GameControlSignals::on_game_running); - - this->game = game; - - if (this->game) - QObject::connect(&this->game->gui_signals, - &GameMainSignals::game_running, - &this->gui_signals, - &GameControlSignals::on_game_running); - } -} - -void GameControl::set_modes(const std::vector &modes) { - const int old_mode_index = this->active_mode_index; - - this->set_mode(-1); - this->modes = modes; - - for (auto mode : this->modes) { - // link the controller to the mode - mode->set_game_control(this); - } - - // announce the newly set modes - emit this->gui_signals.modes_changed(this->active_mode, - this->active_mode_index); - - // try to enter the mode we were in before - // assuming its index didn't change. - if (old_mode_index != -1) { - if (old_mode_index < std::distance(std::begin(this->modes), - std::end(this->modes))) { - this->set_mode(old_mode_index, true); - } - else { - log::log(MSG(warn) << "couldn't enter previous gui mode #" - << old_mode_index << " as it vanished."); - } - } -} - -void GameControl::announce_mode() { - emit this->gui_signals.mode_changed(this->active_mode, - this->active_mode_index); - - if (this->active_mode != nullptr) { - emit this->active_mode->announce(); - } -} - -void GameControl::announce_current_player_name() { - if (Player *player = this->get_current_player()) { - emit this->gui_signals.current_player_name_changed( - "[" + std::to_string(player->color) + "] " + player->name); - emit this->gui_signals.current_civ_index_changed(player->civ->civ_id); - } -} - -void ActionMode::announce_current_selection() { - Player *player = this->game_control->get_current_player(); - emit this->gui_signals.selection_changed(this->selection, player); -} - -bool GameControl::on_drawhud() { - // render the active mode - if (this->active_mode) - this->active_mode->render(); - - return true; -} - -Player *GameControl::get_current_player() const { - if (auto game = this->display->get_game()) { - unsigned int number = game->player_count(); - return game->get_player(this->current_player % number); - } - return nullptr; -} - -void GameControl::set_mode(int mode_index, bool signal_if_unchanged) { - bool need_to_signal = signal_if_unchanged; - - // do we wanna set a new mode? - if (mode_index != -1) { - // if the new mode is valid, available and not active at the moment - if (mode_index < std::distance(std::begin(this->modes), - std::end(this->modes)) - && this->modes[mode_index]->available() - && this->active_mode_index != mode_index) { - ENSURE(!this->active_mode == (this->active_mode_index == -1), - "inconsistency between the active mode index and pointer"); - - // exit from the old mode - if (this->active_mode) { - this->display->get_input_manager().remove_context( - this->active_mode); - - // trigger the exit callback of the mode - if (this->active_mode) { - this->active_mode->on_exit(); - } - } - - // set the new active mode - this->active_mode_index = mode_index; - this->active_mode = this->modes[mode_index]; - - // trigger the entry callback - this->active_mode->on_enter(); - - // add the mode-local input context - this->display->get_input_manager().push_context( - this->active_mode); - - need_to_signal = true; - } - } - else { - // unassign the active mode - if (this->active_mode) { - // remove the input context - this->display->get_input_manager().remove_context( - this->active_mode); - - this->active_mode_index = -1; - this->active_mode = nullptr; - - need_to_signal = true; - } - } - - if (need_to_signal) { - this->announce_mode(); - } -} - -LegacyEngine *GameControl::get_engine() const { - if (this->engine == nullptr) { - throw Error{MSG(err) << "game control doesn't have a valid engine pointer yet"}; - } - - return this->engine; -} - -presenter::LegacyDisplay *GameControl::get_display() const { - if (this->engine == nullptr) { - throw Error{MSG(err) << "game control doesn't have a valid engine pointer yet"}; - } - - return this->display; -} - - -} // namespace openage diff --git a/libopenage/presenter/legacy/game_control.h b/libopenage/presenter/legacy/game_control.h deleted file mode 100644 index cad9deab7b..0000000000 --- a/libopenage/presenter/legacy/game_control.h +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -#include "coord/pixel.h" -#include "gamestate/old/game_main.h" -#include "gui/guisys/link/gui_item_link.h" -#include "handlers.h" -#include "input/legacy/input_context.h" -#include "presenter/legacy/legacy.h" -#include "rng/rng.h" -#include "unit/command.h" -#include "unit/selection.h" -#include "unit/unit_type.h" - -namespace qtsdl { -class GuiItemLink; -} // namespace qtsdl - -namespace openage { - -class ActionMode; -class EditorMode; -class LegacyEngine; -class GameControl; - - -/** - * Signals for a gui mode. - */ -class OutputModeSignals : public QObject { - Q_OBJECT - -public: -signals: - /** - * Signal is triggered to anounce a new output mode. - * name: name of the gui mode. - */ - void announced(const std::string &name); - - /** - * Signal is triggered when the bindings of the mode change. - * binds: list of strings that describe keybindings. - */ - void binds_changed(const std::vector &binds); -}; - - -/** - * A target for input handling and gui rendering. - * This allows to switch to different display UIs. - */ -class OutputMode : public input::legacy::InputContext { -public: - explicit OutputMode(qtsdl::GuiItemLink *gui_link); - virtual ~OutputMode(); - - /** - * Is this mode able to be used? - */ - virtual bool available() const = 0; - - /** - * Called when switching to this mode. - */ - virtual void on_enter() = 0; - - /** - * Called when the mode is left. - */ - virtual void on_exit() = 0; - - /** - * Display this mode. - */ - virtual void render() = 0; - - /** - * Used for displaying the current mode. - */ - virtual std::string name() const = 0; - - /** - * Emit the "announced" signal with (name, InputContext::active_binds). - */ - virtual void announce(); - - /** - * Called when the GameControl is set in QML. - */ - virtual void set_game_control(GameControl *game_control); - - /** - * Called after GameControl has been set by QML from `set_game_control`. - */ - virtual void on_game_control_set() = 0; - -protected: - GameControl *game_control; - -public: - /** - * Signals to be triggered when the mode canges. - */ - OutputModeSignals gui_signals; - - qtsdl::GuiItemLink *gui_link; -}; - - -/** - * This is mainly the game editor. - * Shows menus to choose units to build. - */ -class CreateMode : public OutputMode { -public: - CreateMode(qtsdl::GuiItemLink *gui_link); - - bool available() const override; - void on_enter() override; - void on_exit() override; - void render() override; - std::string name() const override; - void on_game_control_set() override; -}; - -enum class ActionButtonsType { - None, - MilitaryUnits, - CivilianUnits, - BuildMenu, - MilBuildMenu -}; - - -class ActionModeSignals : public QObject { - Q_OBJECT - -public: - explicit ActionModeSignals(ActionMode *action_mode); - -public slots: - void on_action(const std::string &action_name); - -signals: - void resource_changed(game_resource resource, int amount); - void population_changed(int demand, int capacity, bool warn); - void selection_changed(const UnitSelection *unit_selection, const Player *player); - void ability_changed(const std::string &ability); - void buttons_type_changed(const ActionButtonsType type); - -private: - ActionMode *action_mode; -}; - - -/** - * This is the main game UI. - * - * Used to control units, issue commands, basically this is where you - * sink your time in when playing. - */ -class ActionMode : public OutputMode { -public: - ActionMode(qtsdl::GuiItemLink *gui_link); - - bool available() const override; - void on_enter() override; - void on_exit() override; - void render() override; - std::string name() const override; - void on_game_control_set() override; - -private: - friend ActionModeSignals; - /** - * sends to gui the properties that it needs - */ - virtual void announce() override; - - /** - * sends to gui the amounts of resources - */ - void announce_resources(); - - /** - * sends to gui the buttons it should use for the action buttons - * (if changed) - */ - void announce_buttons_type(); - - void announce_current_selection(); - - /** - * decides which type of right mouse click command - * to issue based on position. - * - * if a unit is at the position the command should target the unit, - * otherwise target ground position - */ - Command get_action(const coord::phys3 &pos) const; - - /** - * Register the keybindings. - */ - void create_binds(); - - /** - * used after opening the build menu - */ - InputContext build_menu_context; - - /** - * used after opening the military build menu - */ - InputContext build_menu_mil_context; - - /** - * used when selecting the building placement - */ - InputContext building_context; - - /** - * places hovering building - */ - bool place_selection(coord::phys3 point); - - // currently selected units - UnitSelection *selection; - - // restrict command abilities - bool use_set_ability; - ability_type ability; - - // a selected type for placement - UnitType *type_focus; - - // TODO these shouldn't be here. remove them ASAP. - // they are used to carry over mouse information - // into some of the game control lambda functions - coord::phys3 mousepos_phys3{0, 0, 0}; - coord::tile mousepos_tile{0, 0}; - bool selecting; - - ActionButtonsType buttons_type; - - // used for random type creation - rng::RNG rng; - -public: - ActionModeSignals gui_signals; -}; - - -class EditorModeSignals : public QObject { - Q_OBJECT - -public: - explicit EditorModeSignals(EditorMode *editor_mode); - -public slots: - void on_current_player_name_changed(); - -signals: - void toggle(); - void categories_changed(const std::vector &categories); - void categories_content_changed(); - void category_content_changed(const std::string &category_name, std::vector> &type_and_texture); - -private: - EditorMode *editor_mode; -}; - -/** - * UI mode to provide an interface for map editing. - */ -class EditorMode : public OutputMode { -public: - explicit EditorMode(qtsdl::GuiItemLink *gui_link); - - bool available() const override; - void on_enter() override; - void on_exit() override; - void render() override; - std::string name() const override; - void on_game_control_set() override; - - void set_current_type_id(int current_type_id); - void set_current_terrain_id(openage::terrain_t current_terrain_id); - void set_paint_terrain(bool paint_terrain); - - bool on_single_click(int button, coord::viewport point); - - void announce_categories(); - void announce_category_content(const std::string &category_name); - -private: - virtual void announce() override; - virtual void set_game_control(GameControl *game_control) override; - - void paint_terrain_at(const coord::viewport &point); - void paint_entity_at(const coord::viewport &point, const bool del); - - /** - * currently selected terrain id - */ - terrain_t editor_current_terrain; - int current_type_id; - std::string category; - - /** - * mouse click mode: - * true = terrain painting, - * false = unit placement - */ - bool paint_terrain; - -public: - EditorModeSignals gui_signals; -}; - - -class GameControlSignals : public QObject { - Q_OBJECT - -public: - explicit GameControlSignals(GameControl *game_control); - -public slots: - void on_game_running(bool running); - -signals: - void mode_changed(OutputMode *mode, int mode_index); - void modes_changed(OutputMode *mode, int mode_index); - - void current_player_name_changed(const std::string ¤t_player_name); - void current_civ_index_changed(int current_civ_index); - void is_selected_unit_changed(bool is_selected_unit); - -private: - GameControl *game_control; -}; - - -/** - * connects the gui system with the game engine - * switches between contexts such as editor mode and - * action mode - * - * hud rendering and input handling is redirected to the active mode - */ -class GameControl : public openage::HudHandler { -public: - explicit GameControl(qtsdl::GuiItemLink *gui_link); - - void set_engine(LegacyEngine *engine); - void set_display(presenter::LegacyDisplay *engine); - void set_game(GameMainHandle *game); - - void set_modes(const std::vector &modes); - - void set_mode(int mode, bool signal_if_unchanged = false); - void announce_mode(); - void announce_current_player_name(); - - bool on_drawhud() override; - - Player *get_current_player() const; - LegacyEngine *get_engine() const; - presenter::LegacyDisplay *get_display() const; - -private: - LegacyEngine *engine; - presenter::LegacyDisplay *display; - GameMainHandle *game; - - // control modes - std::vector modes; - - OutputMode *active_mode; - int active_mode_index; - - size_t current_player; - -public: - GameControlSignals gui_signals; - qtsdl::GuiItemLink *gui_link; -}; - -} // namespace openage diff --git a/libopenage/presenter/legacy/legacy.cpp b/libopenage/presenter/legacy/legacy.cpp deleted file mode 100644 index a959b1da35..0000000000 --- a/libopenage/presenter/legacy/legacy.cpp +++ /dev/null @@ -1,550 +0,0 @@ -// Copyright 2020-2023 the openage authors. See copying.md for legal info. - -#include "legacy.h" -#include - -#include "../../config.h" -#include "../../error/error.h" -#include "../../gamestate/old/game_main.h" -#include "../../gamestate/old/generator.h" -#include "../../gui/gui.h" -#include "../../log/log.h" -#include "../../texture.h" -#include "../../unit/selection.h" -#include "../../util/color.h" -#include "../../util/fps.h" -#include "../../util/opengl.h" -#include "../../util/strings.h" -#include "../../util/timer.h" -#include "../../version.h" -#include "legacy_engine.h" - -namespace openage::presenter { - - -LegacyDisplay::LegacyDisplay(const util::Path &path, LegacyEngine *engine) : - OptionNode{"Engine"}, - drawing_debug_overlay{this, "drawing_debug_overlay", false}, - drawing_huds{this, "drawing_huds", true}, - screenshot_manager{engine->get_job_manager()}, - action_manager{&this->input_manager, std::shared_ptr(engine->get_cvar_manager())}, - audio_manager{engine->get_job_manager()}, - input_manager{&this->action_manager} { - // TODO get this from config system (cvar) - int32_t fps_limit = 0; - if (fps_limit > 0) { - this->ns_per_frame = 1e9 / fps_limit; - } - else { - this->ns_per_frame = 0; - } - - this->font_manager = std::make_unique(); - for (uint32_t size : {12, 14, 20}) { - fonts[size] = this->font_manager->get_font("DejaVu Serif", "Book", size); - } - - // enqueue the engine's own input handler to the - // execution list. - this->register_resize_action(this); - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - throw Error(MSG(err) << "SDL video initialization: " << SDL_GetError()); - } - else { - log::log(MSG(info) << "Initialized SDL video subsystems."); - } - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - - int32_t window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED; - this->window = SDL_CreateWindow( - "openage", - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - this->coord.viewport_size.x, - this->coord.viewport_size.y, - window_flags); - - if (this->window == nullptr) { - throw Error(MSG(err) << "Failed to create SDL window: " << SDL_GetError()); - } - - // load support for the PNG image formats, jpg bit: IMG_INIT_JPG - int wanted_image_formats = IMG_INIT_PNG; - int sdlimg_inited = IMG_Init(wanted_image_formats); - if ((sdlimg_inited & wanted_image_formats) != wanted_image_formats) { - throw Error(MSG(err) << "Failed to init PNG support: " << IMG_GetError()); - } - - if (false) { - this->glcontext = error::create_debug_context(this->window); - } - else { - this->glcontext = SDL_GL_CreateContext(this->window); - } - - if (this->glcontext == nullptr) { - throw Error(MSG(err) << "Failed creating OpenGL context: " << SDL_GetError()); - } - - // check the OpenGL version, for shaders n stuff - if (!epoxy_is_desktop_gl() || epoxy_gl_version() < 21) { - throw Error(MSG(err) << "OpenGL 2.1 not available"); - } - - // to quote the standard doc: - // 'The value gives a rough estimate - // of the largest texture that the GL can handle' - // -> wat? - // anyways, we need at least 1024x1024. - int max_texture_size; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - log::log(MSG(dbg) << "Maximum supported texture size: " << max_texture_size); - if (max_texture_size < 1024) { - throw Error(MSG(err) << "Maximum supported texture size too small: " << max_texture_size); - } - - int max_texture_units; - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_texture_units); - log::log(MSG(dbg) << "Maximum supported texture units: " << max_texture_units); - if (max_texture_units < 2) { - throw Error(MSG(err) << "Your GPU has not enough texture units: " << max_texture_units); - } - - // vsync on - SDL_GL_SetSwapInterval(1); - - // enable alpha blending - glEnable(GL_BLEND); - - // order of drawing relevant for depth - // what gets drawn last is displayed on top. - glDisable(GL_DEPTH_TEST); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - //// -- initialize the gui - util::Path qml_root = engine->get_root_dir() / "assets" / "qml"; - if (not qml_root.is_dir()) { - throw Error{ERR << "could not find qml root folder " << qml_root}; - } - - util::Path qml_root_file = qml_root / "main.qml"; - if (not qml_root_file.is_file()) { - throw Error{ERR << "could not find main.qml file " << qml_root_file}; - } - - // TODO: in order to support qml-mods, the fslike and filelike - // library has to be integrated into qt. For now, - // figure out the absolute paths here and pass them in. - - std::string qml_root_str = qml_root.resolve_native_path(); - std::string qml_root_file_str = qml_root_file.resolve_native_path(); - - this->gui = std::make_unique( - this->window, // sdl window for the gui - qml_root_file_str, // entry qml file, absolute path. - qml_root_str // directory to watch for qml file changes - // &engine->get_qml_info() // qml data: Engine *, the data directory, ... - ); - //// -- gui initialization - - - // register the engines input manager - this->register_input_action(&this->input_manager); - - - // initialize engine related global keybinds - auto &global_input_context = this->get_input_manager().get_global_context(); - - input::legacy::ActionManager &action = this->get_action_manager(); - global_input_context.bind(action.get("STOP_GAME"), [engine](const input::legacy::action_arg_t &) { - engine->stop(); - }); - global_input_context.bind(action.get("TOGGLE_HUD"), [this](const input::legacy::action_arg_t &) { - this->drawing_huds.value = !this->drawing_huds.value; - }); - global_input_context.bind(action.get("SCREENSHOT"), [this](const input::legacy::action_arg_t &) { - this->get_screenshot_manager().save_screenshot(this->coord.viewport_size); - }); - global_input_context.bind(action.get("TOGGLE_DEBUG_OVERLAY"), [this](const input::legacy::action_arg_t &) { - this->drawing_debug_overlay.value = !this->drawing_debug_overlay.value; - }); - global_input_context.bind(action.get("TOGGLE_PROFILER"), [engine](const input::legacy::action_arg_t &) { - if (engine->external_profiler.currently_profiling) { - engine->external_profiler.stop(); - engine->external_profiler.show_results(); - } - else { - engine->external_profiler.start(); - } - }); - global_input_context.bind(input::legacy::event_class::MOUSE, [this](const input::legacy::action_arg_t &arg) { - if (arg.e.cc.has_class(input::legacy::event_class::MOUSE_MOTION) && this->get_input_manager().is_down(input::legacy::event_class::MOUSE_BUTTON, 2)) { - this->move_phys_camera(arg.motion.x, arg.motion.y); - return true; - } - return false; - }); - - this->text_renderer = std::make_unique(); - this->unit_selection = std::make_unique(engine); -} - - -LegacyDisplay::~LegacyDisplay() { - // deallocate the gui system - // this looses the opengl context in the qtsdl::GuiRenderer - // deallocation (of the QtOpenGLContext). - // so no gl* functions will be called after the gl context is gone. - this->gui.reset(nullptr); - - SDL_GL_DeleteContext(this->glcontext); - SDL_DestroyWindow(this->window); - IMG_Quit(); - SDL_Quit(); -} - - -bool LegacyDisplay::draw_debug_overlay() { - // Draw FPS counter in the lower right corner - this->render_text( - {this->coord.viewport_size.x - 70, 15}, - 20, - renderer::Colors::WHITE, - "%.0f fps", - this->fps_counter.display_fps); - - // Draw version string in the lower left corner - this->render_text( - {5, 35}, - 20, - renderer::Colors::WHITE, - "openage %s", - version::version); - this->render_text( - {5, 15}, - 12, - renderer::Colors::WHITE, - "%s", - config::config_option_string); - - // this->profiler.show(true); - - return true; -} - - -void LegacyDisplay::register_input_action(InputHandler *handler) { - this->on_input_event.push_back(handler); -} - - -void LegacyDisplay::register_tick_action(TickHandler *handler) { - this->on_engine_tick.push_back(handler); -} - - -void LegacyDisplay::register_drawhud_action(HudHandler *handler, int order) { - if (order < 0) { - this->on_drawhud.insert(this->on_drawhud.begin(), handler); - } - else { - this->on_drawhud.push_back(handler); - } -} - - -void LegacyDisplay::register_draw_action(DrawHandler *handler) { - this->on_drawgame.push_back(handler); -} - - -void LegacyDisplay::register_resize_action(ResizeHandler *handler) { - this->on_resize_handler.push_back(handler); -} - - -bool LegacyDisplay::on_resize(coord::viewport_delta new_size) { - // TODO: move all this to the renderer! - - log::log(MSG(dbg) << "engine window resize to " - << new_size.x << "x" << new_size.y); - - // update engine window size - this->coord.viewport_size = new_size; - - // update camgame window position, set it to center. - this->coord.camgame_viewport = coord::viewport{0, 0} + (this->coord.viewport_size / 2); - - // update camhud window position, set to lower left corner - this->coord.camhud_viewport = {0, coord::pixel_t{this->coord.viewport_size.y}}; - - // reset previous projection matrix - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // update OpenGL viewport: the rendering area - glViewport(0, 0, this->coord.viewport_size.x, this->coord.viewport_size.y); - - // set orthographic projection: left, right, bottom, top, near_val, far_val - glOrtho(0, this->coord.viewport_size.x, 0, this->coord.viewport_size.y, 9001, -1); - - // reset the modelview matrix - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - return true; -} - - -renderer::TextRenderer *LegacyDisplay::get_text_renderer() { - return this->text_renderer.get(); -} - - -time_nsec_t LegacyDisplay::lastframe_duration_nsec() const { - return this->fps_counter.nsec_lastframe; -} - - -void LegacyDisplay::announce_global_binds() { - // emit this->gui_signals.global_binds_changed( - // this->get_input_manager().get_global_context().active_binds()); -} - - -UnitSelection *LegacyDisplay::get_unit_selection() { - return this->unit_selection.get(); -} - - -void LegacyDisplay::render_text(coord::viewport position, size_t size, const renderer::Color &color, const char *format, ...) { - auto it = this->fonts.find(size); - if (it == this->fonts.end()) { - throw Error(MSG(err) << "Unknown font size requested: " << size); - } - - renderer::Font *font = it->second; - - std::string buf; - va_list vl; - va_start(vl, format); - util::vsformat(format, vl, buf); - va_end(vl); - - this->text_renderer->set_font(font); - this->text_renderer->set_color(color); - this->text_renderer->draw(position.x, position.y, buf); -} - - -void LegacyDisplay::move_phys_camera(float x, float y, float amount) { - // calculate camera position delta from velocity and frame duration - coord::camgame_delta cam_delta{ - static_cast(+x * amount), - static_cast(-y * amount)}; - - // update camera phys position - this->coord.camgame_phys += cam_delta.to_phys3(this->coord, 0); -} - - -GameMain *LegacyDisplay::get_game() { - return this->game.get(); -} - - -void LegacyDisplay::start_game(std::unique_ptr &&game) { - // TODO: maybe implement a proper 1-to-1 connection - ENSURE(game, "linking game to engine problem"); - - this->game = std::move(game); - this->game->set_parent(this); -} - - -void LegacyDisplay::start_game(const Generator &generator) { - this->game = std::make_unique(generator); - this->game->set_parent(this); -} - - -void LegacyDisplay::end_game() { - this->game = nullptr; - this->unit_selection->clear(); -} - - -void LegacyDisplay::loop() { - //SDL_Event event; - //util::Timer cap_timer; - // - //while (this->running) { - // this->profiler.start_frame_measure(); - // this->fps_counter.frame(); - // cap_timer.reset(false); - // - // this->job_manager.execute_callbacks(); - // - // this->profiler.start_measure("events", {1.0, 0.0, 0.0}); - // // top level input handling - // while (SDL_PollEvent(&event)) { - // switch (event.type) { - // case SDL_QUIT: - // this->stop(); - // break; - // - // case SDL_WINDOWEVENT: { - // if (event.window.event == SDL_WINDOWEVENT_RESIZED) { - // coord::viewport_delta new_size{event.window.data1, event.window.data2}; - // - // // call additional handlers for the resize event - // for (auto &handler : on_resize_handler) { - // if (!handler->on_resize(new_size)) { - // break; - // } - // } - // } - // break; - // } - // - // default: - // for (auto &action : this->on_input_event) { - // if (false == action->on_input(&event)) { - // break; - // } - // } - // } // switch event - // } - // - // // here, call to Qt and process all the gui events. - // this->gui->process_events(); - // - // if (this->game) { - // // read camera movement input keys and/or cursor location, - // // and move camera accordingly. - // - // // camera movement speed, in pixels per millisecond - // // one pixel per millisecond equals 14.3 tiles/second - // float mov_x = 0.0, mov_y = 0.0, cam_movement_speed_keyboard = 0.5; - // Uint32 win_flags = SDL_GetWindowFlags(this->window); - // bool inp_focus = win_flags & SDL_WINDOW_INPUT_FOCUS; - // - // input::InputManager &input = this->get_input_manager(); - // using Edge = input::InputManager::Edge; - // - // if (inp_focus and (input.is_down(SDLK_LEFT) or input.is_mouse_at_edge(Edge::LEFT, coord.viewport_size.x))) { - // mov_x = -cam_movement_speed_keyboard; - // } - // if (inp_focus and (input.is_down(SDLK_RIGHT) or input.is_mouse_at_edge(Edge::RIGHT, coord.viewport_size.x))) { - // mov_x = cam_movement_speed_keyboard; - // } - // if (inp_focus and (input.is_down(SDLK_DOWN) or input.is_mouse_at_edge(Edge::DOWN, coord.viewport_size.y))) { - // mov_y = cam_movement_speed_keyboard; - // } - // if (inp_focus and (input.is_down(SDLK_UP) or input.is_mouse_at_edge(Edge::UP, coord.viewport_size.y))) { - // mov_y = -cam_movement_speed_keyboard; - // } - // - // // perform camera movement - // this->move_phys_camera( - // mov_x, - // mov_y, - // static_cast(this->lastframe_duration_nsec()) / 1e6); - // - // // update the currently running game - // this->game->update(this->lastframe_duration_nsec()); - // } - // this->profiler.end_measure("events"); - // - // // call engine tick callback methods - // for (auto &action : this->on_engine_tick) { - // if (false == action->on_tick()) { - // break; - // } - // } - // - // this->profiler.start_measure("rendering", {0.0, 1.0, 0.0}); - // - // // clear the framebuffer to black - // // in the future, we might disable it for lazy drawing - // glClearColor(0.0, 0.0, 0.0, 0.0); - // glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - // - // // invoke all game drawing handlers - // for (auto &action : this->on_drawgame) { - // if (false == action->on_draw()) { - // break; - // } - // } - // - // util::gl_check_error(); - // - // // draw the fps overlay - // if (this->drawing_debug_overlay.value) { - // this->draw_debug_overlay(); - // } - // - // // invoke all hud drawing callback methods - // if (this->drawing_huds.value) { - // for (auto &action : this->on_drawhud) { - // if (false == action->on_drawhud()) { - // break; - // } - // } - // } - // - // this->text_renderer->render(); - // - // util::gl_check_error(); - // - // this->profiler.end_measure("rendering"); - // - // this->profiler.start_measure("idle", {0.0, 0.0, 1.0}); - // - // // the rendering is done - // // swap the drawing buffers to actually show the frame - // SDL_GL_SwapWindow(window); - // - // if (this->ns_per_frame != 0) { - // uint64_t ns_for_current_frame = cap_timer.getval(); - // if (ns_for_current_frame < this->ns_per_frame) { - // SDL_Delay((this->ns_per_frame - ns_for_current_frame) / 1e6); - // } - // } - // - // this->profiler.end_measure("idle"); - // - // this->profiler.end_frame_measure(); - //} -} - - -audio::AudioManager &LegacyDisplay::get_audio_manager() { - return this->audio_manager; -} - - -ScreenshotManager &LegacyDisplay::get_screenshot_manager() { - return this->screenshot_manager; -} - - -input::legacy::ActionManager &LegacyDisplay::get_action_manager() { - return this->action_manager; -} - - -input::legacy::InputManager &LegacyDisplay::get_input_manager() { - return this->input_manager; -} - - -} // namespace openage::presenter diff --git a/libopenage/presenter/legacy/legacy.h b/libopenage/presenter/legacy/legacy.h deleted file mode 100644 index b4a82443fd..0000000000 --- a/libopenage/presenter/legacy/legacy.h +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2020-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "../../audio/audio_manager.h" -// pxd: from libopenage.coord.coordmanager cimport CoordManager -#include "../../coord/coordmanager.h" -#include "../../error/gl_debug.h" -#include "../../handlers.h" -// pxd: from libopenage.input.input_manager cimport InputManager -#include "../../input/legacy/input_manager.h" -#include "../../options.h" -#include "../../renderer/font/font.h" -#include "../../renderer/font/font_manager.h" -#include "../../renderer/text.h" -#include "../../screenshot.h" -#include "../../util/fps.h" -#include "../../util/path.h" -#include "../../util/timing.h" - - -namespace openage { - -class DrawHandler; -class TickHandler; -class ResizeHandler; - -class Generator; -class GameSpec; -class GameMain; -class UnitSelection; - -namespace gui { -class GUI; -} // namespace gui - -namespace renderer { - -class Font; -class FontManager; -class TextRenderer; -class Color; - -} // namespace renderer - - -namespace presenter { - -/** - * Temporary container class for the legacy renderer implementation. - */ -class LegacyDisplay final : public ResizeHandler - , public options::OptionNode { -public: - LegacyDisplay(const util::Path &path, LegacyEngine *engine); - - ~LegacyDisplay(); - - /** - * Draw the game version and the current FPS on screen. - */ - bool draw_debug_overlay(); - - /** - * register a new input event handler, run for each input event. - */ - void register_input_action(InputHandler *handler); - - /** - * register a tick action, executed upon engine tick. - */ - void register_tick_action(TickHandler *handler); - - /** - * register a hud drawing handler, drawn in hud coordinates. - * order: 1 above, -1 below - */ - void register_drawhud_action(HudHandler *handler, int order = 1); - - /** - * register a draw handler, run in game coordinates. - */ - void register_draw_action(DrawHandler *handler); - - /** - * register a resize handler, run when the window size changes. - */ - void register_resize_action(ResizeHandler *handler); - - /** - * window resize handler function. - * recalculates opengl settings like viewport and projection matrices. - */ - bool on_resize(coord::viewport_delta new_size) override; - - /** - * return this engine's text renderer. - */ - renderer::TextRenderer *get_text_renderer(); - - /** - * return the number of nanoseconds that have passed - * for rendering the last frame. - * - * use that for fps-independent input actions. - */ - time_nsec_t lastframe_duration_nsec() const; - - /** - * send keybindings help string to gui. - */ - void announce_global_binds(); - - /** - * return this engine's unit selection. - */ - UnitSelection *get_unit_selection(); - - /** - * render text at a position with the specified font size - */ - void render_text(coord::viewport position, size_t size, const renderer::Color &color, const char *format, ...) ATTRIBUTE_FORMAT(5, 6); - - /** - * move the phys3 camera incorporated in the engine - */ - void move_phys_camera(float x, float y, float amount = 1.0); - - /** - * Start a game with the given game generator. - */ - void start_game(const Generator &generator); - - /** - * Start a game with the given initialized game. - */ - void start_game(std::unique_ptr &&game); - - /** - * Stop the running game. - */ - void end_game(); - - /** - * return currently running game or null if a game is not - * currently running - */ - GameMain *get_game(); - - /** - * legacy engine loop function. - * this will be looped once per frame when the game is running. - * - * the loop invokes fps counting, SDL event handling, - * view translation, and calling the main draw_method. - */ - void loop(); - -public: - /** - * return this engine's audio manager. - */ - audio::AudioManager &get_audio_manager(); - - /** - * return this engine's screenshot manager. - */ - ScreenshotManager &get_screenshot_manager(); - - /** - * return this engine's action manager. - */ - input::legacy::ActionManager &get_action_manager(); - - /** - * return this engine's keybind manager. - */ - input::legacy::InputManager &get_input_manager(); - - /** - * FPS and game version are drawn when this is true. - */ - options::Var drawing_debug_overlay; - - /** - * this allows to disable drawing of every registered hud. - */ - options::Var drawing_huds; - - /** - * The coordinate state. - */ - coord::CoordManager coord; - -private: - /** - * the currently running game - */ - std::unique_ptr game; - - /** - * how many nanoseconds are in a frame (1e9 / fps_limit). - * 0 if there is no fps limit. - */ - time_nsec_t ns_per_frame; - - /** - * input event processor objects. - * called for each captured sdl input event. - */ - std::vector on_input_event; - - /** - * run every time the game is being drawn, - * with the renderer set to the camgame system - */ - std::vector on_drawgame; - - /** - * run every time the hud is being drawn, - * with the renderer set to the camhud system - */ - std::vector on_drawhud; - - /** - * list of handlers that are executed upon a resize event. - */ - std::vector on_resize_handler; - - /** - * run on every engine tick, after input handling, before rendering - */ - std::vector on_engine_tick; - - /** - * the frame counter measuring fps. - */ - util::FrameCounter fps_counter; - - /** - * the engine's screenshot manager. - */ - ScreenshotManager screenshot_manager; - - /** - * the engine's action manager. - */ - input::legacy::ActionManager action_manager; - - /** - * the engine's audio manager. - */ - audio::AudioManager audio_manager; - - /** - * the engine's keybind manager. - */ - input::legacy::InputManager input_manager; - - /** - * the engine's unit selection. - */ - std::unique_ptr unit_selection; - - /** - * the text fonts to be used for (can you believe it?) texts. - * maps fontsize -> font - */ - std::unordered_map fonts; - - /** - * SDL window where everything is displayed within. - */ - SDL_Window *window; - - /** - * SDL OpenGL context, we'll only have one, - * but it would allow having multiple ones. - * - * This is actually a void * but sdl2 thought it was a good idea to - * name it like a differently. - */ - SDL_GLContext glcontext; - - /** - * Qt GUI system - */ - std::unique_ptr gui; - - /** - * ttf font loading manager - */ - std::unique_ptr font_manager; - - /** - * 2d text renderer - */ - std::unique_ptr text_renderer; -}; - -} // namespace presenter -} // namespace openage diff --git a/libopenage/presenter/legacy/legacy_renderer.cpp b/libopenage/presenter/legacy/legacy_renderer.cpp deleted file mode 100644 index 3e65693f36..0000000000 --- a/libopenage/presenter/legacy/legacy_renderer.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "legacy_renderer.h" - -#include -#include -#include -#include -#include - -#include "../../console/console.h" -#include "../../gamedata/color_dummy.h" -#include "../../gamestate/old/game_main.h" -#include "../../gamestate/old/game_spec.h" -#include "../../input/legacy/input_manager.h" -#include "../../legacy_engine.h" -#include "../../log/log.h" -#include "../../renderer/text.h" -#include "../../unit/action.h" -#include "../../unit/command.h" -#include "../../unit/producer.h" -#include "../../unit/unit.h" -#include "../../unit/unit_texture.h" -#include "../../util/externalprofiler.h" -#include "../../util/timer.h" -#include "legacy.h" - -namespace openage { - - -RenderOptions::RenderOptions() : - OptionNode{"RendererOptions"}, - draw_debug{this, "draw_debug", false}, - terrain_blending{this, "terrain_blending", true} {} - - -LegacyRenderer::LegacyRenderer(LegacyEngine *e, presenter::LegacyDisplay *d) : - engine{e}, - display{d} { - // set options structure - this->settings.set_parent(this->display); - - // display callbacks - this->display->register_draw_action(this); - - // fetch asset loading dir - util::Path asset_dir = this->engine->get_root_dir()["assets"]; - - // load textures and stuff - gaben = new Texture{asset_dir["test"]["textures"]["gaben.png"]}; - - std::vector player_color_lines = util::read_csv_file( - asset_dir["converted/player_palette.docx"]); - - std::unique_ptr playercolors = std::make_unique(player_color_lines.size() * 4); - for (size_t i = 0; i < player_color_lines.size(); i++) { - auto line = &player_color_lines[i]; - playercolors[i * 4] = line->r / 255.0; - playercolors[i * 4 + 1] = line->g / 255.0; - playercolors[i * 4 + 2] = line->b / 255.0; - playercolors[i * 4 + 3] = line->a / 255.0; - } - - // shader initialisation - // read shader source codes and create shader objects for wrapping them. - const char *shader_header_code = "#version 120\n"; - std::string equals_epsilon_code = asset_dir["shaders/equalsEpsilon.glsl"].open().read(); - std::string texture_vert_code = asset_dir["shaders/maptexture.vert.glsl"].open().read(); - auto plaintexture_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, texture_vert_code.c_str()}); - - std::string texture_frag_code = asset_dir["shaders/maptexture.frag.glsl"].open().read(); - auto plaintexture_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, texture_frag_code.c_str()}); - - std::string teamcolor_frag_code = asset_dir["shaders/teamcolors.frag.glsl"].open().read(); - std::stringstream ss; - ss << player_color_lines.size(); - auto teamcolor_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{ - shader_header_code, - ("#define NUM_OF_PLAYER_COLORS " + ss.str() + "\n").c_str(), - equals_epsilon_code.c_str(), - teamcolor_frag_code.c_str()}); - - std::string alphamask_vert_code = asset_dir["shaders/alphamask.vert.glsl"].open().read(); - auto alphamask_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, alphamask_vert_code.c_str()}); - - std::string alphamask_frag_code = asset_dir["shaders/alphamask.frag.glsl"].open().read(); - auto alphamask_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, alphamask_frag_code.c_str()}); - - std::string texturefont_vert_code = asset_dir["shaders/texturefont.vert.glsl"].open().read(); - auto texturefont_vert = std::make_unique( - GL_VERTEX_SHADER, - std::initializer_list{shader_header_code, texturefont_vert_code.c_str()}); - - std::string texturefont_frag_code = asset_dir["shaders/texturefont.frag.glsl"].open().read(); - auto texturefont_frag = std::make_unique( - GL_FRAGMENT_SHADER, - std::initializer_list{shader_header_code, texturefont_frag_code.c_str()}); - - // create program for rendering simple textures - texture_shader::program = new shader::Program(plaintexture_vert.get(), plaintexture_frag.get()); - texture_shader::program->link(); - texture_shader::texture = texture_shader::program->get_uniform_id("texture"); - texture_shader::tex_coord = texture_shader::program->get_attribute_id("tex_coordinates"); - texture_shader::program->use(); - glUniform1i(texture_shader::texture, 0); - texture_shader::program->stopusing(); - - - // create program for tinting textures at alpha-marked pixels - // with team colors - teamcolor_shader::program = new shader::Program(plaintexture_vert.get(), teamcolor_frag.get()); - teamcolor_shader::program->link(); - teamcolor_shader::texture = teamcolor_shader::program->get_uniform_id("texture"); - teamcolor_shader::tex_coord = teamcolor_shader::program->get_attribute_id("tex_coordinates"); - teamcolor_shader::player_id_var = teamcolor_shader::program->get_uniform_id("player_number"); - teamcolor_shader::alpha_marker_var = teamcolor_shader::program->get_uniform_id("alpha_marker"); - teamcolor_shader::player_color_var = teamcolor_shader::program->get_uniform_id("player_color"); - teamcolor_shader::program->use(); - glUniform1i(teamcolor_shader::texture, 0); - glUniform1f(teamcolor_shader::alpha_marker_var, 254.0 / 255.0); - // fill the teamcolor shader's player color table: - glUniform4fv(teamcolor_shader::player_color_var, 64, playercolors.get()); - teamcolor_shader::program->stopusing(); - - - // create program for drawing textures that are alpha-masked before - alphamask_shader::program = new shader::Program(alphamask_vert.get(), alphamask_frag.get()); - alphamask_shader::program->link(); - alphamask_shader::base_coord = alphamask_shader::program->get_attribute_id("base_tex_coordinates"); - alphamask_shader::mask_coord = alphamask_shader::program->get_attribute_id("mask_tex_coordinates"); - alphamask_shader::show_mask = alphamask_shader::program->get_uniform_id("show_mask"); - alphamask_shader::base_texture = alphamask_shader::program->get_uniform_id("base_texture"); - alphamask_shader::mask_texture = alphamask_shader::program->get_uniform_id("mask_texture"); - alphamask_shader::program->use(); - glUniform1i(alphamask_shader::base_texture, 0); - glUniform1i(alphamask_shader::mask_texture, 1); - alphamask_shader::program->stopusing(); - - // Create program for texture based font rendering - texturefont_shader::program = new shader::Program(texturefont_vert.get(), texturefont_frag.get()); - texturefont_shader::program->link(); - texturefont_shader::texture = texturefont_shader::program->get_uniform_id("texture"); - texturefont_shader::color = texturefont_shader::program->get_uniform_id("color"); - texturefont_shader::tex_coord = texturefont_shader::program->get_attribute_id("tex_coordinates"); - texturefont_shader::program->use(); - glUniform1i(texturefont_shader::texture, 0); - texturefont_shader::program->stopusing(); - - // Renderer keybinds - // TODO: a renderer settings struct - // would allow these to be put somewhere better - input::legacy::ActionManager &action = this->display->get_action_manager(); - auto &global_input_context = this->display->get_input_manager().get_global_context(); - global_input_context.bind(action.get("TOGGLE_BLENDING"), [this](const input::legacy::action_arg_t &) { - this->settings.terrain_blending.value = !this->settings.terrain_blending.value; - }); - global_input_context.bind(action.get("TOGGLE_UNIT_DEBUG"), [this](const input::legacy::action_arg_t &) { - this->settings.draw_debug.value = !this->settings.draw_debug.value; - - log::log(MSG(dbg) << "Toggle debug grid"); - - // TODO remove this hack, use render settings instead - UnitAction::show_debug = !UnitAction::show_debug; - }); - - log::log(MSG(dbg) << "Loaded Renderer"); -} - -LegacyRenderer::~LegacyRenderer() { - // oh noes, release hl3 before that! - delete this->gaben; - - delete texture_shader::program; - delete teamcolor_shader::program; - delete alphamask_shader::program; - delete texturefont_shader::program; -} - - -bool LegacyRenderer::on_draw() { - // draw terrain - GameMain *game = this->display->get_game(); - - if (game) { - // draw gaben, our great and holy protector, bringer of the half-life 3. - gaben->draw(this->display->coord, coord::camgame{0, 0}); - - // TODO move render code out of terrain - if (game->terrain) { - game->terrain->draw(this->display, &this->settings); - } - } - return true; -} - -GameMain *LegacyRenderer::game() const { - return this->display->get_game(); -} - -GameSpec *LegacyRenderer::game_spec() const { - return this->game()->get_spec(); -} - -} // namespace openage diff --git a/libopenage/presenter/legacy/legacy_renderer.h b/libopenage/presenter/legacy/legacy_renderer.h deleted file mode 100644 index ea60a76623..0000000000 --- a/libopenage/presenter/legacy/legacy_renderer.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include - -#include "../../coord/tile.h" -#include "../../gamestate/old/game_spec.h" -#include "../../handlers.h" -#include "../../options.h" -#include "legacy.h" - -namespace openage { - -class GameMain; - -/** - * Options for the renderer. - * These will be included in the user interface - * via reflection, so adding new members will - * always be visible - * - * TODO include fog drawing etc - */ -class RenderOptions : public options::OptionNode { -public: - RenderOptions(); - - options::Var draw_debug; - options::Var terrain_blending; -}; - -/** - * renders the editor and action views - */ -class LegacyRenderer : DrawHandler { -public: - LegacyRenderer(LegacyEngine *e, presenter::LegacyDisplay *d); - ~LegacyRenderer(); - - bool on_draw() override; - - /** - * the game this renderer is using - */ - GameMain *game() const; - - /** - * GameSpec used by this renderer - */ - GameSpec *game_spec() const; - - Texture *gaben; - - RenderOptions settings; - -private: - LegacyEngine *engine; - presenter::LegacyDisplay *display; -}; - -} // namespace openage diff --git a/libopenage/presenter/presenter.cpp b/libopenage/presenter/presenter.cpp index 925d2d650d..06498e51c6 100644 --- a/libopenage/presenter/presenter.cpp +++ b/libopenage/presenter/presenter.cpp @@ -18,7 +18,6 @@ #include "renderer/camera/camera.h" #include "renderer/gui/gui.h" #include "renderer/gui/integration/public/gui_application_with_logger.h" -#include "renderer/gui/qml_info.h" #include "renderer/render_factory.h" #include "renderer/resources/assets/asset_manager.h" #include "renderer/resources/shader_source.h" diff --git a/libopenage/renderer/CMakeLists.txt b/libopenage/renderer/CMakeLists.txt index 8a889de978..756e9e4d98 100644 --- a/libopenage/renderer/CMakeLists.txt +++ b/libopenage/renderer/CMakeLists.txt @@ -1,12 +1,10 @@ add_sources(libopenage - animation.cpp color.cpp definitions.cpp geometry.cpp render_factory.cpp renderer.cpp shader_program.cpp - text.cpp texture.cpp texture_array.cpp types.cpp diff --git a/libopenage/renderer/animation.cpp b/libopenage/renderer/animation.cpp deleted file mode 100644 index a9b0a54e37..0000000000 --- a/libopenage/renderer/animation.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2021-2021 the openage authors. See copying.md for legal info. - -#include "animation.h" - -namespace openage::renderer { - -Animation2d::Animation2d(const resources::Animation2dInfo &info) : - info{info} {} - -const resources::Animation2dInfo &Animation2d::get_info() const { - return this->info; -} - -} // namespace openage::renderer diff --git a/libopenage/renderer/animation.h b/libopenage/renderer/animation.h deleted file mode 100644 index aa5e27f8cf..0000000000 --- a/libopenage/renderer/animation.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2021-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "renderer/resources/animation/animation_info.h" - -namespace openage::renderer { - -class Animation2d { -public: - Animation2d() = default; - ~Animation2d() = default; - - /** - * Get the animation information. - * - * @return Animation information. - */ - const resources::Animation2dInfo &get_info() const; - -protected: - /** - * Creates a 2D animation. - */ - Animation2d(const resources::Animation2dInfo &info); - - /** - * Information about the animation layers, angles and frames. - */ - resources::Animation2dInfo info; -}; - -} // namespace openage::renderer diff --git a/libopenage/renderer/demo/demo_3.cpp b/libopenage/renderer/demo/demo_3.cpp index 6e0dc1f5ca..9dbaa9b93e 100644 --- a/libopenage/renderer/demo/demo_3.cpp +++ b/libopenage/renderer/demo/demo_3.cpp @@ -5,6 +5,7 @@ #include #include +#include "coord/tile.h" #include "renderer/camera/camera.h" #include "renderer/gui/integration/public/gui_application_with_logger.h" #include "renderer/opengl/window.h" @@ -21,6 +22,7 @@ #include "renderer/uniform_buffer.h" #include "time/clock.h" + namespace openage::renderer::tests { void renderer_demo_3(const util::Path &path) { @@ -113,37 +115,36 @@ void renderer_demo_3(const util::Path &path) { // Create some entities to populate the scene auto render_factory = std::make_shared(terrain_renderer, world_renderer); - // Terrain - auto terrain0 = render_factory->add_terrain_render_entity(); - // Fill a 10x10 terrain grid with height values auto terrain_size = util::Vector2s{10, 10}; - std::vector height_map{}; - height_map.reserve(terrain_size[0] * terrain_size[1]); + std::vector> tiles{}; + tiles.reserve(terrain_size[0] * terrain_size[1]); for (size_t i = 0; i < terrain_size[0] * terrain_size[1]; ++i) { - height_map.push_back(0.0f); + tiles.emplace_back(0.0f, "./textures/test_terrain.terrain"); } + // Create entity for terrain rendering + auto terrain0 = render_factory->add_terrain_render_entity(terrain_size, + coord::tile_delta{0, 0}); + // Create "test bumps" in the terrain to check if rendering works - height_map[11] = 1.0f; - height_map[23] = 2.3f; - height_map[42] = 4.2f; - height_map[69] = 6.9f; // nice + tiles[11].first = 1.0f; + tiles[23].first = 2.3f; + tiles[42].first = 4.2f; + tiles[69].first = 6.9f; // nice // A hill - height_map[55] = 3.0f; // center - height_map[45] = 2.0f; // bottom left slope - height_map[35] = 1.0f; - height_map[56] = 1.0f; // bottom right slope (little steeper) - height_map[65] = 2.0f; // top right slope - height_map[75] = 1.0f; - height_map[54] = 2.0f; // top left slope - height_map[53] = 1.0f; + tiles[55].first = 3.0f; // center + tiles[45].first = 2.0f; // bottom left slope + tiles[35].first = 1.0f; + tiles[56].first = 1.0f; // bottom right slope (little steeper) + tiles[65].first = 2.0f; // top right slope + tiles[75].first = 1.0f; + tiles[54].first = 2.0f; // top left slope + tiles[53].first = 1.0f; // send the terrain data to the terrain renderer - terrain0->update(terrain_size, - height_map, - "./textures/test_terrain.terrain"); + terrain0->update(terrain_size, tiles); // World entities auto world0 = render_factory->add_world_render_entity(); diff --git a/libopenage/renderer/demo/demo_5.cpp b/libopenage/renderer/demo/demo_5.cpp index b8adc896e3..afea99a30b 100644 --- a/libopenage/renderer/demo/demo_5.cpp +++ b/libopenage/renderer/demo/demo_5.cpp @@ -78,7 +78,7 @@ void renderer_demo_5(const util::Path &path) { auto const vert_data_size = verts.size() * sizeof(float); std::vector vert_data(vert_data_size); - std::memcpy(vert_data.data(), reinterpret_cast(verts.data()), vert_data_size); + std::memcpy(vert_data.data(), verts.data(), vert_data_size); resources::MeshData meshdata{std::move(vert_data), info}; diff --git a/libopenage/renderer/demo/stresstest_0.cpp b/libopenage/renderer/demo/stresstest_0.cpp index 77b8f0f33b..b33abb9685 100644 --- a/libopenage/renderer/demo/stresstest_0.cpp +++ b/libopenage/renderer/demo/stresstest_0.cpp @@ -4,6 +4,7 @@ #include +#include "coord/tile.h" #include "renderer/camera/camera.h" #include "renderer/gui/integration/public/gui_application_with_logger.h" #include "renderer/opengl/window.h" @@ -116,21 +117,20 @@ void renderer_stresstest_0(const util::Path &path) { // Create some entities to populate the scene auto render_factory = std::make_shared(terrain_renderer, world_renderer); - // Terrain - auto terrain0 = render_factory->add_terrain_render_entity(); - // Fill a 10x10 terrain grid with height values auto terrain_size = util::Vector2s{10, 10}; - std::vector height_map{}; - height_map.reserve(terrain_size[0] * terrain_size[1]); + std::vector> tiles{}; + tiles.reserve(terrain_size[0] * terrain_size[1]); for (size_t i = 0; i < terrain_size[0] * terrain_size[1]; ++i) { - height_map.push_back(0.0f); + tiles.emplace_back(0.0f, "./textures/test_terrain.terrain"); } + // Create entity for terrain rendering + auto terrain0 = render_factory->add_terrain_render_entity(terrain_size, + coord::tile_delta{0, 0}); + // send the terrain data to the terrain renderer - terrain0->update(terrain_size, - height_map, - "./textures/test_terrain.terrain"); + terrain0->update(terrain_size, tiles); // World entities std::vector> render_entities{}; diff --git a/libopenage/renderer/gui/CMakeLists.txt b/libopenage/renderer/gui/CMakeLists.txt index 60a1676d76..fdddb92d06 100644 --- a/libopenage/renderer/gui/CMakeLists.txt +++ b/libopenage/renderer/gui/CMakeLists.txt @@ -1,8 +1,5 @@ add_sources(libopenage - assetmanager_link.cpp - engine_link.cpp gui.cpp - qml_info.cpp ) add_subdirectory("guisys") diff --git a/libopenage/renderer/gui/assetmanager_link.cpp b/libopenage/renderer/gui/assetmanager_link.cpp deleted file mode 100644 index 600cf51ffb..0000000000 --- a/libopenage/renderer/gui/assetmanager_link.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "assetmanager_link.h" - -#include - -#include "renderer/gui/engine_link.h" - -namespace openage { - -class LegacyEngine; - -namespace renderer { -namespace gui { - -namespace { -const int registration = qmlRegisterType("yay.sfttech.openage", 1, 0, "AssetManager"); -} - -AssetManagerLink::AssetManagerLink(QObject *parent) : - GuiItemQObject{parent}, - GuiItem{this} { - Q_UNUSED(registration); -} - -AssetManagerLink::~AssetManagerLink() = default; - - -const util::Path &AssetManagerLink::get_asset_dir() const { - return this->asset_dir; -} - - -void AssetManagerLink::set_asset_dir(const util::Path &asset_dir) { - static auto f = [](AssetManager *_this, const util::Path &dir) { - _this->set_asset_dir(dir); - }; - this->s(f, this->asset_dir, asset_dir); -} - - -EngineLink *AssetManagerLink::get_engine() const { - return this->engine; -} - - -void AssetManagerLink::set_engine(EngineLink *engine_link) { - static auto f = [](AssetManager *_this, gamestate::GameSimulation *engine) { - _this->set_engine(engine); - }; - this->s(f, this->engine, engine_link); -} - - -} // namespace gui -} // namespace renderer -} // namespace openage diff --git a/libopenage/renderer/gui/assetmanager_link.h b/libopenage/renderer/gui/assetmanager_link.h deleted file mode 100644 index 3378558855..0000000000 --- a/libopenage/renderer/gui/assetmanager_link.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "assets/assetmanager.h" -#include "gui/guisys/link/gui_item.h" -#include "util/path.h" - - -namespace openage { -namespace renderer::gui { -class AssetManagerLink; -class EngineLink; -} // namespace renderer::gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::renderer::gui::AssetManagerLink; -}; - -template <> -struct Unwrap { - using Type = openage::AssetManager; -}; - -} // namespace qtsdl - - -namespace openage { -namespace renderer { -namespace gui { - -class AssetManagerLink : public qtsdl::GuiItemQObject - , public qtsdl::GuiItem { - Q_OBJECT - - Q_PROPERTY(openage::util::Path assetDir READ get_asset_dir WRITE set_asset_dir) - Q_MOC_INCLUDE("renderer/gui/engine_link.h") - Q_PROPERTY(EngineLink *engine READ get_engine WRITE set_engine) - -public: - explicit AssetManagerLink(QObject *parent = nullptr); - virtual ~AssetManagerLink(); - - const util::Path &get_asset_dir() const; - void set_asset_dir(const util::Path &data_dir); - - EngineLink *get_engine() const; - void set_engine(EngineLink *engine); - -private: - util::Path asset_dir; - EngineLink *engine; -}; - -} // namespace gui -} // namespace renderer -} // namespace openage diff --git a/libopenage/renderer/gui/engine_link.cpp b/libopenage/renderer/gui/engine_link.cpp deleted file mode 100644 index b4045a583c..0000000000 --- a/libopenage/renderer/gui/engine_link.cpp +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "engine_link.h" - -#include - -#include "error/error.h" - -#include "gamestate/simulation.h" - -#include "gui/guisys/link/qml_engine_with_singleton_items_info.h" -#include "gui/guisys/link/qtsdl_checked_static_cast.h" -#include "renderer/gui/qml_info.h" - -namespace openage::renderer::gui { - -namespace { -// this pushes the EngineLink in the QML engine. -// a qml engine calls the static provider() to obtain a handle. -const int registration = qmlRegisterSingletonType("yay.sfttech.openage", 1, 0, "Engine", &EngineLink::provider); -} // namespace - - -EngineLink::EngineLink(QObject *parent, gamestate::GameSimulation *engine) : - GuiSingletonItem{parent}, - core{engine} { - Q_UNUSED(registration); - - // ENSURE(!unwrap(this)->gui_link, "Sharing singletons between QML engines is not supported for now."); - - // when the engine announces that the global key bindings - // changed, update the display. - // QObject::connect( - // &unwrap(this)->gui_signals, - // &EngineSignals::global_binds_changed, - // this, - // &EngineLink::on_global_binds_changed); - - // trigger the engine signal, - // which then triggers this->on_global_binds_changed. - // unwrap(this)->announce_global_binds(); -} - -EngineLink::~EngineLink() { - // unwrap(this)->gui_link = nullptr; -} - -// a qml engine requests a handle to the engine link with that static -// method we do this by extracting the per-qmlengine singleton from the -// engine (the qmlenginewithsingletoninfo), then just return the new link -// instance -QObject *EngineLink::provider(QQmlEngine *engine, QJSEngine *) { - // cast the engine to our specialization - qtsdl::QmlEngineWithSingletonItemsInfo *engine_with_singleton_items_info = qtsdl::checked_static_cast(engine); - - // get the singleton container out of the custom qml engine - auto info = static_cast( - engine_with_singleton_items_info->get_singleton_items_info()); - ENSURE(info, "qml-globals were lost or not passed to the gui subsystem"); - - // owned by the QML engine - // this handle contains the pointer to the openage engine, - // obtained through the qmlengine - return new EngineLink{nullptr, info->engine}; -} - -QStringList EngineLink::get_global_binds() const { - return this->global_binds; -} - -void EngineLink::stop() { - this->core->stop(); -} - -void EngineLink::on_global_binds_changed(const std::vector &global_binds) { - QStringList new_global_binds; - - // create the qstring list from the std string list - // which is then displayed in the ui - std::transform( - std::begin(global_binds), - std::end(global_binds), - std::back_inserter(new_global_binds), - [](const std::string &s) { - return QString::fromStdString(s); - }); - - new_global_binds.sort(); - - if (this->global_binds != new_global_binds) { - this->global_binds = new_global_binds; - emit this->global_binds_changed(); - } -} - -} // namespace openage::renderer::gui diff --git a/libopenage/renderer/gui/engine_link.h b/libopenage/renderer/gui/engine_link.h deleted file mode 100644 index 9b0b7089cf..0000000000 --- a/libopenage/renderer/gui/engine_link.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "gui/guisys/link/gui_singleton_item.h" -#include "util/path.h" - -QT_FORWARD_DECLARE_CLASS(QQmlEngine) -QT_FORWARD_DECLARE_CLASS(QJSEngine) - -namespace openage { - -namespace gamestate { -class GameSimulation; -} - -namespace renderer::gui { -class EngineLink; -} // namespace renderer::gui -} // namespace openage - -namespace qtsdl { -template <> -struct Wrap { - using Type = openage::renderer::gui::EngineLink; -}; - -template <> -struct Unwrap { - using Type = openage::gamestate::GameSimulation; -}; - -} // namespace qtsdl - -namespace openage { -namespace renderer { -namespace gui { - -class EngineLink : public qtsdl::GuiSingletonItem { - Q_OBJECT - - /** - * The text list of global key bindings. - * displayed so one can see what keys are active. - */ - Q_PROPERTY(QStringList globalBinds - READ get_global_binds - NOTIFY global_binds_changed) - -public: - explicit EngineLink(QObject *parent, gamestate::GameSimulation *engine); - virtual ~EngineLink(); - - static QObject *provider(QQmlEngine *, QJSEngine *); - - template - U *get() const { - return core; - } - - QStringList get_global_binds() const; - - Q_INVOKABLE void stop(); - -signals: - void global_binds_changed(); - -private slots: - void on_global_binds_changed(const std::vector &global_binds); - -private: - gamestate::GameSimulation *core; - - QStringList global_binds; -}; - -} // namespace gui -} // namespace renderer -} // namespace openage diff --git a/libopenage/renderer/gui/gui.cpp b/libopenage/renderer/gui/gui.cpp index c877c4a537..f51320c24c 100644 --- a/libopenage/renderer/gui/gui.cpp +++ b/libopenage/renderer/gui/gui.cpp @@ -6,7 +6,6 @@ #include "renderer/gui/guisys/public/gui_input.h" #include "renderer/gui/guisys/public/gui_renderer.h" #include "renderer/gui/integration/public/gui_application_with_logger.h" -#include "renderer/gui/qml_info.h" #include "renderer/opengl/context.h" #include "renderer/renderer.h" #include "renderer/resources/shader_source.h" @@ -24,8 +23,6 @@ GUI::GUI(std::shared_ptr app, const util::Path &assetdir, const std::shared_ptr &renderer) : application{app}, - render_updater{}, - game_logic_updater{}, gui_renderer{std::make_shared(window)}, gui_input{std::make_shared(gui_renderer)}, engine{std::make_shared(gui_renderer)}, diff --git a/libopenage/renderer/gui/gui.h b/libopenage/renderer/gui/gui.h index bb83217c48..1cecfb7bd6 100644 --- a/libopenage/renderer/gui/gui.h +++ b/libopenage/renderer/gui/gui.h @@ -6,8 +6,6 @@ #include #include -#include "gui/guisys/public/gui_event_queue.h" -#include "gui/integration/public/gui_game_spec_image_provider.h" #include "renderer/gui/guisys/public/gui_subtree.h" namespace qtgui { @@ -31,8 +29,6 @@ class UniformInput; namespace gui { -class QMLInfo; - /** * Interface (= HUD) of the game. * @@ -100,15 +96,6 @@ class GUI { */ std::shared_ptr application; - /** - * TODO - */ - qtsdl::GuiEventQueue render_updater; - /** - * TODO - */ - qtsdl::GuiEventQueue game_logic_updater; - /** * Qt-based renderer for the GUI texture. Draws into * \p gui_texture. @@ -130,8 +117,6 @@ class GUI { */ qtgui::GuiSubtree subtree; - // openage::gui::GuiGameSpecImageProvider image_provider_by_filename; - /** * Reference to the openage renderer. * Used to fetch texture objects for the GUI texture. diff --git a/libopenage/renderer/gui/guisys/CMakeLists.txt b/libopenage/renderer/gui/guisys/CMakeLists.txt index d4f5349e29..3b454bfec5 100644 --- a/libopenage/renderer/gui/guisys/CMakeLists.txt +++ b/libopenage/renderer/gui/guisys/CMakeLists.txt @@ -1,4 +1,13 @@ +list(APPEND QT_SDL_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_item.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_list_model.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_property_map_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/link/gui_singleton_item.cpp +) + list(APPEND QTGUI_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/deferred_initial_constant_property_values.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/gui_live_reloader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/recursive_directory_watcher_worker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/private/livereload/recursive_directory_watcher.cpp ) diff --git a/libopenage/renderer/gui/guisys/link/gui_item.cpp b/libopenage/renderer/gui/guisys/link/gui_item.cpp new file mode 100644 index 0000000000..20bbb7c8c0 --- /dev/null +++ b/libopenage/renderer/gui/guisys/link/gui_item.cpp @@ -0,0 +1,20 @@ +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + +#include "gui_item.h" + + +namespace qtgui { + + +QString name_tidier(const char *name) { + QString cleaner_name = QString::fromLatin1(name); + cleaner_name.remove(QRegularExpression("qtgui|PersistentCoreHolder")); + return cleaner_name; +} + +GuiItemQObject::GuiItemQObject(QObject *parent) : + QObject{parent}, + GuiItemBase{} { +} + +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_item.h b/libopenage/renderer/gui/guisys/link/gui_item.h similarity index 61% rename from libopenage/gui/guisys/link/gui_item.h rename to libopenage/renderer/gui/guisys/link/gui_item.h index 00d252dba3..9f8a5bd59f 100644 --- a/libopenage/gui/guisys/link/gui_item.h +++ b/libopenage/renderer/gui/guisys/link/gui_item.h @@ -1,29 +1,28 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once -#include #include #include +#include #include #include #include -#include +#include #include +#include #include -#include -#include "../private/game_logic_caller.h" -#include "../private/livereload/deferred_initial_constant_property_values.h" -#include "qtsdl_checked_static_cast.h" -#include "gui_item_link.h" +#include "renderer/gui/guisys/link/gui_item_link.h" +#include "renderer/gui/guisys/link/qtgui_checked_static_cast.h" +#include "renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.h" -namespace qtsdl { +namespace qtgui { /** - * Cleans a text from unneeded content like "qtsdl". + * Cleans a text from unneeded content like "qtgui". */ QString name_tidier(const char *name); @@ -43,17 +42,15 @@ class PersistentCoreHolderBase { virtual void adopt_shell(GuiItemLink *link) = 0; }; -template +template class PersistentCoreHolder : public PersistentCoreHolderBase { public: - PersistentCoreHolder(std::unique_ptr core) - : + PersistentCoreHolder(std::unique_ptr core) : PersistentCoreHolderBase{}, core{std::move(core)} { } - explicit PersistentCoreHolder() - : + explicit PersistentCoreHolder() : PersistentCoreHolderBase{} { } @@ -74,13 +71,13 @@ class GuiItemBase : public DeferredInitialConstantPropertyValues { friend class GuiLiveReloader; friend class GuiSubtreeImpl; - template + template friend class GuiItemMethods; - template + template friend class GuiItemCoreInstantiator; - template + template friend class GuiItemListModel; /** @@ -109,26 +106,18 @@ class GuiItemBase : public DeferredInitialConstantPropertyValues { virtual void on_core_adopted() { } - /** - * Set up signal to be able to run code in the game logic thread. - */ - void set_game_logic_callback(GuiCallback *game_logic_callback) { - this->game_logic_caller.set_game_logic_callback(game_logic_callback); - } - protected: - GameLogicCaller game_logic_caller; std::function()> instantiate_core_func; - std::function do_adopt_core_func; + std::function do_adopt_core_func; std::function on_core_adopted_func; }; -template +template class GuiItemOrigin { - template + template friend class GuiItemMethods; - template + template friend class GuiItemCoreInstantiator; /** @@ -140,10 +129,9 @@ class GuiItemOrigin { /** * Member function of the GuiPersistentItem */ -template +template class GuiItemMethods { public: - #ifndef NDEBUG virtual ~GuiItemMethods() { } @@ -152,12 +140,13 @@ class GuiItemMethods { /** * Get core. */ - template - U* get() const { - if (checked_static_cast(this)->holder->core) { - assert(checked_static_cast(checked_static_cast(this)->holder->core.get())); - return checked_static_cast(checked_static_cast(this)->holder->core.get()); - } else { + template + U *get() const { + if (checked_static_cast(this)->holder->core) { + assert(checked_static_cast(checked_static_cast(this)->holder->core.get())); + return checked_static_cast(checked_static_cast(this)->holder->core.get()); + } + else { return nullptr; } } @@ -165,12 +154,13 @@ class GuiItemMethods { /** * Get core. */ - template - U* get() { - if (checked_static_cast(this)->holder->core) { - assert(checked_static_cast(checked_static_cast(this)->holder->core.get())); - return checked_static_cast(checked_static_cast(this)->holder->core.get()); - } else { + template + U *get() { + if (checked_static_cast(this)->holder->core) { + assert(checked_static_cast(checked_static_cast(this)->holder->core.get())); + return checked_static_cast(checked_static_cast(this)->holder->core.get()); + } + else { return nullptr; } } @@ -178,21 +168,16 @@ class GuiItemMethods { /** * Invoke a function in the logic thread (the thread of the core of this object). */ - template - void i(F f, Args&& ... args) { - GuiItemBase *base = checked_static_cast(checked_static_cast(this)); - - emit base->game_logic_caller.in_game_logic_thread([=, this] { - static_assert_about_unwrapping(this))), decltype(unwrap_if_can(args))...>(); - f(unwrap(checked_static_cast(this)), unwrap_if_can(args)...); - }); + template + void i(F f, Args &&...args) { + GuiItemBase *base = checked_static_cast(checked_static_cast(this)); } protected: /** * Set property. */ - template + template void s(F f, P &p, A &&arg) { if (p != arg) { p = std::forward(arg); @@ -203,7 +188,7 @@ class GuiItemMethods { /** * Set property even if it's the same. */ - template + template void sf(F f, P &p, A &&arg) { p = std::forward(arg); this->assign_while_catching_constant_properies_inits(f, p); @@ -213,38 +198,32 @@ class GuiItemMethods { /** * Static QML properties assignments during the init phase are stored for a batch assignment at the end of the init phase. */ - template + template void assign_while_catching_constant_properies_inits(F f, A &&arg) { - GuiItemBase *base = checked_static_cast(checked_static_cast(this)); + GuiItemBase *base = checked_static_cast(checked_static_cast(this)); - static_assert_about_unwrapping(this))), decltype(unwrap_if_can(arg))>(); - - if (base->init_over) - emit base->game_logic_caller.in_game_logic_thread([=, this] {f(unwrap(checked_static_cast(this)), unwrap_if_can(arg));}); - else - base->static_properties_assignments.push_back([=, this] { - emit base->game_logic_caller.in_game_logic_thread([=, this] {f(unwrap(checked_static_cast(this)), unwrap_if_can(arg));}); - }); + static_assert_about_unwrapping(this))), decltype(unwrap_if_can(arg))>(); } }; -class GuiItemQObject : public QObject, public GuiItemBase, public GuiItemLink { +class GuiItemQObject : public QObject + , public GuiItemBase + , public GuiItemLink { Q_OBJECT public: - explicit GuiItemQObject(QObject *parent=nullptr); + explicit GuiItemQObject(QObject *parent = nullptr); }; -template +template class GuiItemCoreInstantiator : public GuiItemMethods { public: /** * Sets up a factory for the type T. */ - explicit GuiItemCoreInstantiator(GuiItemBase *item_base) - : - GuiItemMethods{} { - + explicit GuiItemCoreInstantiator(GuiItemBase *item_base) : + GuiItemMethods {} + { using namespace std::placeholders; item_base->instantiate_core_func = std::bind(&GuiItemCoreInstantiator::instantiate_core, this); @@ -256,11 +235,12 @@ class GuiItemCoreInstantiator : public GuiItemMethods { * Creates and returns a core object of type Unwrap::Type inside a holder. */ std::unique_ptr instantiate_core() { - T *origin = checked_static_cast(this); + T *origin = checked_static_cast(this); if (origin->holder) { return std::unique_ptr(); - } else { + } + else { auto core = std::make_unique::Type>(origin); return std::make_uniqueholder)>::type>(std::move(core)); } @@ -272,11 +252,12 @@ class GuiItemCoreInstantiator : public GuiItemMethods { void do_adopt_core(PersistentCoreHolderBase *holder, const QString &tag) { assert(holder); - T *origin = checked_static_cast(this); + T *origin = checked_static_cast(this); if (origin->holder) { qFatal("Error in QML code: GuiLiveReloader was asked to use same tag '%s' for multiple objects.", qUtf8Printable(tag)); - } else { + } + else { if (typeid(decltype(*origin->holder)) != typeid(*holder)) { qFatal( "Error in QML code: GuiLiveReloader was asked " @@ -284,17 +265,17 @@ class GuiItemCoreInstantiator : public GuiItemMethods { "using tag '%s'.", qUtf8Printable(name_tidier(typeid(decltype(*origin->holder)).name())), qUtf8Printable(name_tidier(typeid(*holder).name())), - qUtf8Printable(tag) - ); - } else { + qUtf8Printable(tag)); + } + else { origin->holder = checked_static_castholder)>(holder); origin->holder->adopt_shell(origin); } } } - GuiItemCoreInstantiator(const GuiItemCoreInstantiator&) = delete; - GuiItemCoreInstantiator& operator=(const GuiItemCoreInstantiator&) = delete; + GuiItemCoreInstantiator(const GuiItemCoreInstantiator &) = delete; + GuiItemCoreInstantiator &operator=(const GuiItemCoreInstantiator &) = delete; }; /** @@ -308,26 +289,30 @@ class GuiItemCoreInstantiator : public GuiItemMethods { * * @tparam T type of the concrete shell class (pass the descendant class) */ -template -class GuiItem : public GuiItemOrigin, public GuiItemCoreInstantiator { +template +class GuiItem : public GuiItemOrigin + , public GuiItemCoreInstantiator { public: /** * Creates an empty QObject shell for a core that is wrappable into a type *T. */ - explicit GuiItem(GuiItemBase *item_base) - : + explicit GuiItem(GuiItemBase *item_base) : GuiItemOrigin{}, - GuiItemCoreInstantiator{item_base} { + GuiItemCoreInstantiator { + item_base + } + { } }; -template -class GuiItemInterface : public GuiItemOrigin, public GuiItemMethods { +template +class GuiItemInterface : public GuiItemOrigin + , public GuiItemMethods { public: - explicit GuiItemInterface() - : + explicit GuiItemInterface() : GuiItemOrigin{}, - GuiItemMethods{} { + GuiItemMethods {} + { } }; @@ -335,16 +320,15 @@ namespace { class NullClass { NullClass() = delete; }; -} +} // namespace /** * Shadows inherited member functions. */ -template -class Shadow: public T { +template +class Shadow : public T { public: - Shadow(QObject *parent=nullptr) - : + Shadow(QObject *parent = nullptr) : T{parent} { } @@ -357,8 +341,9 @@ class Shadow: public T { /** * Switches the factory to production of the instances of the derived class. */ -template -class Inherits: public Shadow, public GuiItemCoreInstantiator

{ +template +class Inherits : public Shadow + , public GuiItemCoreInstantiator

{ public: using Shadow::get; using GuiItemCoreInstantiator

::get; @@ -369,14 +354,16 @@ class Inherits: public Shadow, public GuiItemCoreInstantiator

{ using Shadow::sf; using GuiItemCoreInstantiator

::sf; - Inherits(QObject *parent=nullptr) - : + Inherits(QObject *parent = nullptr) : Shadow{parent}, - GuiItemCoreInstantiator

{this} { + GuiItemCoreInstantiator

{ + this + } + { } virtual ~Inherits() { } }; -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_item_link.h b/libopenage/renderer/gui/guisys/link/gui_item_link.h similarity index 62% rename from libopenage/gui/guisys/link/gui_item_link.h rename to libopenage/renderer/gui/guisys/link/gui_item_link.h index 43191ea2ec..0965aa2b4d 100644 --- a/libopenage/gui/guisys/link/gui_item_link.h +++ b/libopenage/renderer/gui/guisys/link/gui_item_link.h @@ -1,12 +1,14 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once #include +#include -#include "qtsdl_checked_static_cast.h" +#include "renderer/gui/guisys/link/qtgui_checked_static_cast.h" -namespace qtsdl { + +namespace qtgui { /** * Base for QObject wrapper of the domain-specific classes. @@ -22,30 +24,30 @@ class GuiItemLink { /** * If the core 'MyClass' has a shell 'MyClassLink' then 'Wrap' must have a 'using Type = MyClassLink' */ -template +template struct Wrap { }; /** * If the core 'MyClass' has a shell 'MyClassLink' then 'Unwrap' must have a 'using Type = MyClass' */ -template +template struct Unwrap { }; -template -typename Unwrap::Type* unwrap(T *t) { +template +typename Unwrap::Type *unwrap(T *t) { return t ? t->template get::Type>() : nullptr; } -template -const typename Unwrap::Type* unwrap(const T *t) { +template +const typename Unwrap::Type *unwrap(const T *t) { return t ? t->template get::Type>() : nullptr; } -template -const typename Wrap::Type* wrap(const U *u) { - return checked_static_cast::Type*>(u->gui_link); +template +const typename Wrap::Type *wrap(const U *u) { + return checked_static_cast::Type *>(u->gui_link); } /** @@ -53,33 +55,33 @@ const typename Wrap::Type* wrap(const U *u) { */ class GuiSingletonItem; -template -typename Wrap::Type* wrap(U *u, typename std::enable_if::Type>::value>::type* = nullptr) { - return u ? checked_static_cast::Type*>(u->gui_link) : nullptr; +template +typename Wrap::Type *wrap(U *u, typename std::enable_if::Type>::value>::type * = nullptr) { + return u ? checked_static_cast::Type *>(u->gui_link) : nullptr; } -template -typename Wrap::Type* wrap(U *u, typename std::enable_if::Type>::value>::type* = nullptr) { - return u ? checked_static_cast::Type*>(u->gui_link) : nullptr; +template +typename Wrap::Type *wrap(U *u, typename std::enable_if::Type>::value>::type * = nullptr) { + return u ? checked_static_cast::Type *>(u->gui_link) : nullptr; } -template -constexpr P&& wrap_if_can(typename std::remove_reference

::type&& p) noexcept { +template +constexpr P &&wrap_if_can(typename std::remove_reference

::type &&p) noexcept { return std::forward

(p); } -template +template T wrap_if_can(typename Unwrap::type>::Type *u) { return wrap(u); } -template -P unwrap_if_can(P& p) { +template +P unwrap_if_can(P &p) { return p; } -template::Type* = nullptr> -typename Unwrap::Type* unwrap_if_can(T *t) { +template ::Type * = nullptr> +typename Unwrap::Type *unwrap_if_can(T *t) { return unwrap(t); } @@ -87,10 +89,10 @@ typename Unwrap::Type* unwrap_if_can(T *t) { * Checking that callable can be called with given argument types. */ struct can_call_test { - template + template static decltype(std::declval()(std::declval()...), std::true_type()) f(int); - template + template static std::false_type f(...); }; @@ -100,7 +102,7 @@ struct can_call_test { * @tparam F callable * @tparam A arguments to test against the callable */ -template +template struct can_call : decltype(can_call_test::f(0)) { }; @@ -113,9 +115,9 @@ struct can_call : decltype(can_call_test::f(0)) { * @tparam F callable * @tparam A arguments to test against the callable */ -template +template constexpr void static_assert_about_unwrapping() { static_assert(can_call{}, "One of possible causes: if you're passing SomethingLink*, then don't forget to #include \"something_link.h\"."); } -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_item_list_model.h b/libopenage/renderer/gui/guisys/link/gui_item_list_model.h similarity index 68% rename from libopenage/gui/guisys/link/gui_item_list_model.h rename to libopenage/renderer/gui/guisys/link/gui_item_list_model.h index 38e902d4d3..7158247ccd 100644 --- a/libopenage/gui/guisys/link/gui_item_list_model.h +++ b/libopenage/renderer/gui/guisys/link/gui_item_list_model.h @@ -1,27 +1,29 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once #include -#include "gui_item.h" -#include "gui_property_map_impl.h" -#include "gui_list_model.h" +#include "renderer/gui/guisys/link/gui_item.h" +#include "renderer/gui/guisys/link/gui_list_model.h" +#include "renderer/gui/guisys/link/gui_property_map_impl.h" -namespace qtsdl { + +namespace qtgui { /** * A shell object fir cores inherited from GuiPropertyMap * * Core can use a key-value interface while in QML it looks like a ListModel. */ -template +template class GuiItemListModel : public GuiItem { public: - explicit GuiItemListModel(GuiItemBase *item_base) - : - GuiItem{item_base} { - + explicit GuiItemListModel(GuiItemBase *item_base) : + GuiItem { + item_base + } + { item_base->on_core_adopted_func = std::bind(&GuiItemListModel::on_core_adopted, this); } @@ -33,9 +35,9 @@ class GuiItemListModel : public GuiItem { } void establish_from_gui_propagation() { - auto _this = checked_static_cast(this); + auto _this = checked_static_cast(this); - QObject::connect(_this, &GuiListModel::changed_from_gui, [_this] (const QByteArray &name, const QVariant &value) { + QObject::connect(_this, &GuiListModel::changed_from_gui, [_this](const QByteArray &name, const QVariant &value) { emit _this->game_logic_caller.in_game_logic_thread_blocking([&] { unwrap(_this)->impl->setProperty(name, value); }); @@ -43,14 +45,14 @@ class GuiItemListModel : public GuiItem { } void establish_to_gui_propagation() { - auto _this = checked_static_cast(this); + auto _this = checked_static_cast(this); auto properties = unwrap(_this)->impl.get(); QObject::connect(properties, &GuiPropertyMapImpl::property_changed, _this, &GuiListModel::on_property_changed); } void do_initial_to_gui_propagation() { - auto _this = checked_static_cast(this); + auto _this = checked_static_cast(this); auto properties = unwrap(_this)->impl.get(); auto property_names = properties->dynamicPropertyNames(); @@ -58,7 +60,7 @@ class GuiItemListModel : public GuiItem { std::vector> values; values.reserve(property_names.size()); - std::transform(std::begin(property_names), std::end(property_names), std::back_inserter(values), [properties] (const QByteArray &name) { + std::transform(std::begin(property_names), std::end(property_names), std::back_inserter(values), [properties](const QByteArray &name) { return std::make_tuple(name, properties->property(name)); }); @@ -66,4 +68,4 @@ class GuiItemListModel : public GuiItem { } }; -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_list_model.cpp b/libopenage/renderer/gui/guisys/link/gui_list_model.cpp similarity index 85% rename from libopenage/gui/guisys/link/gui_list_model.cpp rename to libopenage/renderer/gui/guisys/link/gui_list_model.cpp index 72bbf20663..467468020b 100644 --- a/libopenage/gui/guisys/link/gui_list_model.cpp +++ b/libopenage/renderer/gui/guisys/link/gui_list_model.cpp @@ -1,13 +1,13 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #include "gui_list_model.h" #include -namespace qtsdl { -GuiListModel::GuiListModel(QObject *parent) - : +namespace qtgui { + +GuiListModel::GuiListModel(QObject *parent) : QAbstractListModel{parent} { } @@ -20,7 +20,7 @@ void GuiListModel::set(const std::vector> &valu } void GuiListModel::on_property_changed(const QByteArray &name, const QVariant &value) { - auto foundIt = std::find_if(std::begin(this->values), std::end(this->values), [&name] (std::tuple& p) { + auto foundIt = std::find_if(std::begin(this->values), std::end(this->values), [&name](std::tuple &p) { return std::get(p) == name; }); @@ -33,14 +33,15 @@ void GuiListModel::on_property_changed(const QByteArray &name, const QVariant &v auto i = this->index(std::distance(std::begin(this->values), foundIt)); emit this->dataChanged(i, i, {Qt::EditRole}); } - } else { + } + else { this->beginInsertRows(QModelIndex(), this->values.size(), this->values.size()); this->values.emplace(std::end(this->values), name, value); this->endInsertRows(); } } -int GuiListModel::rowCount(const QModelIndex&) const { +int GuiListModel::rowCount(const QModelIndex &) const { return values.size(); } @@ -71,4 +72,4 @@ bool GuiListModel::setData(const QModelIndex &index, const QVariant &value, int return false; } -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_list_model.h b/libopenage/renderer/gui/guisys/link/gui_list_model.h similarity index 58% rename from libopenage/gui/guisys/link/gui_list_model.h rename to libopenage/renderer/gui/guisys/link/gui_list_model.h index 6f93ce48b2..3a3b85c52e 100644 --- a/libopenage/gui/guisys/link/gui_list_model.h +++ b/libopenage/renderer/gui/guisys/link/gui_list_model.h @@ -1,24 +1,27 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once -#include #include +#include #include -#include "gui_item.h" +#include "renderer/gui/guisys/link/gui_item.h" + -namespace qtsdl { +namespace qtgui { /** * Adapts core that uses a property map to QAbstractListModel interface. */ -class GuiListModel : public QAbstractListModel, public GuiItemBase, public GuiItemLink { +class GuiListModel : public QAbstractListModel + , public GuiItemBase + , public GuiItemLink { Q_OBJECT public: - GuiListModel(QObject *parent=nullptr); + GuiListModel(QObject *parent = nullptr); virtual ~GuiListModel(); void set(const std::vector> &values); @@ -30,12 +33,12 @@ public slots: void changed_from_gui(const char *name, const QVariant &value); private: - virtual int rowCount(const QModelIndex&) const override; + virtual int rowCount(const QModelIndex &) const override; virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; std::vector> values; }; -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_property_map_impl.cpp b/libopenage/renderer/gui/guisys/link/gui_property_map_impl.cpp similarity index 66% rename from libopenage/gui/guisys/link/gui_property_map_impl.cpp rename to libopenage/renderer/gui/guisys/link/gui_property_map_impl.cpp index 885589c38b..d6204ae719 100644 --- a/libopenage/gui/guisys/link/gui_property_map_impl.cpp +++ b/libopenage/renderer/gui/guisys/link/gui_property_map_impl.cpp @@ -1,16 +1,16 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #include "gui_property_map_impl.h" #include #include -#include "qtsdl_checked_static_cast.h" +#include "renderer/gui/guisys/link/qtgui_checked_static_cast.h" -namespace qtsdl { -GuiPropertyMapImpl::GuiPropertyMapImpl() - : +namespace qtgui { + +GuiPropertyMapImpl::GuiPropertyMapImpl() : QObject{} { } @@ -18,7 +18,7 @@ GuiPropertyMapImpl::~GuiPropertyMapImpl() = default; bool GuiPropertyMapImpl::event(QEvent *e) { if (e->type() == QEvent::DynamicPropertyChange) { - auto property_name = checked_static_cast(e)->propertyName(); + auto property_name = checked_static_cast(e)->propertyName(); emit this->property_changed(property_name, this->property(property_name)); return true; } @@ -26,4 +26,4 @@ bool GuiPropertyMapImpl::event(QEvent *e) { return this->QObject::event(e); } -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/link/gui_property_map_impl.h b/libopenage/renderer/gui/guisys/link/gui_property_map_impl.h similarity index 74% rename from libopenage/gui/guisys/link/gui_property_map_impl.h rename to libopenage/renderer/gui/guisys/link/gui_property_map_impl.h index a7054345be..d0118f4c58 100644 --- a/libopenage/gui/guisys/link/gui_property_map_impl.h +++ b/libopenage/renderer/gui/guisys/link/gui_property_map_impl.h @@ -1,10 +1,11 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once #include -namespace qtsdl { + +namespace qtgui { class GuiPropertyMapImpl : public QObject { Q_OBJECT @@ -20,4 +21,4 @@ class GuiPropertyMapImpl : public QObject { virtual bool event(QEvent *e) override; }; -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/renderer/gui/guisys/link/gui_singleton_item.cpp b/libopenage/renderer/gui/guisys/link/gui_singleton_item.cpp new file mode 100644 index 0000000000..dc01d27e4e --- /dev/null +++ b/libopenage/renderer/gui/guisys/link/gui_singleton_item.cpp @@ -0,0 +1,15 @@ +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + +#include "gui_singleton_item.h" + + +namespace qtgui { + +GuiSingletonItem::GuiSingletonItem(QObject *parent) : + QObject{parent}, + GuiItemLink{} { +} + +GuiSingletonItem::~GuiSingletonItem() = default; + +} // namespace qtgui diff --git a/libopenage/renderer/gui/guisys/link/gui_singleton_item.h b/libopenage/renderer/gui/guisys/link/gui_singleton_item.h new file mode 100644 index 0000000000..8024ecf032 --- /dev/null +++ b/libopenage/renderer/gui/guisys/link/gui_singleton_item.h @@ -0,0 +1,21 @@ +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "renderer/gui/guisys/link/gui_item_link.h" + + +namespace qtgui { + +class GuiSingletonItem : public QObject + , public GuiItemLink { + Q_OBJECT + +public: + explicit GuiSingletonItem(QObject *parent = nullptr); + virtual ~GuiSingletonItem(); +}; + +} // namespace qtgui diff --git a/libopenage/renderer/gui/guisys/link/qtgui_checked_static_cast.h b/libopenage/renderer/gui/guisys/link/qtgui_checked_static_cast.h new file mode 100644 index 0000000000..7b51a89e03 --- /dev/null +++ b/libopenage/renderer/gui/guisys/link/qtgui_checked_static_cast.h @@ -0,0 +1,16 @@ +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include + + +namespace qtgui { + +template +T checked_static_cast(U *u) { + assert(dynamic_cast(u)); + return static_cast(u); +} + +} // namespace qtgui diff --git a/libopenage/renderer/gui/guisys/private/gui_application_impl.cpp b/libopenage/renderer/gui/guisys/private/gui_application_impl.cpp index c0ef0dd1b7..fb8674b69e 100644 --- a/libopenage/renderer/gui/guisys/private/gui_application_impl.cpp +++ b/libopenage/renderer/gui/guisys/private/gui_application_impl.cpp @@ -2,12 +2,12 @@ #include "gui_application_impl.h" -#include #include +#include #include -#include #include +#include namespace qtgui { @@ -41,22 +41,20 @@ void GuiApplicationImpl::processEvents() { } namespace { - int argc = 1; - char arg[] = "qtsdl"; - char *argv = &arg[0]; -} +int argc = 1; +char arg[] = "qtgui"; +char *argv = &arg[0]; +} // namespace -GuiApplicationImpl::GuiApplicationImpl() - : +GuiApplicationImpl::GuiApplicationImpl() : #ifndef NDEBUG owner{std::this_thread::get_id()}, #endif - app{argc, &argv} -{ + app{argc, &argv} { // Set locale back to POSIX for the decimal point parsing (see qcoreapplication.html#locale-settings). std::locale::global(std::locale().combine>(std::locale::classic())); qInfo() << "Compiled with Qt" << QT_VERSION_STR << "and run with Qt" << qVersion(); } -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/renderer/gui/guisys/private/gui_application_impl.h b/libopenage/renderer/gui/guisys/private/gui_application_impl.h index 7294cf8827..7af12c0fa4 100644 --- a/libopenage/renderer/gui/guisys/private/gui_application_impl.h +++ b/libopenage/renderer/gui/guisys/private/gui_application_impl.h @@ -1,9 +1,9 @@ -// Copyright 2015-2022 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once -#include #include +#include #include @@ -12,7 +12,7 @@ namespace qtgui { /** * Houses gui logic event queue. * - * To launch it in a dedicated thread, use qtsdl::GuiDedicatedThread instead. + * To launch it in a dedicated thread, use qtgui::GuiDedicatedThread instead. */ class GuiApplicationImpl { public: @@ -25,8 +25,8 @@ class GuiApplicationImpl { private: GuiApplicationImpl(); - GuiApplicationImpl(const GuiApplicationImpl&) = delete; - GuiApplicationImpl& operator=(const GuiApplicationImpl&) = delete; + GuiApplicationImpl(const GuiApplicationImpl &) = delete; + GuiApplicationImpl &operator=(const GuiApplicationImpl &) = delete; #ifndef NDEBUG const std::thread::id owner; diff --git a/libopenage/renderer/gui/guisys/private/gui_ctx_setup.cpp b/libopenage/renderer/gui/guisys/private/gui_ctx_setup.cpp index d5c32b56e4..49b05af242 100644 --- a/libopenage/renderer/gui/guisys/private/gui_ctx_setup.cpp +++ b/libopenage/renderer/gui/guisys/private/gui_ctx_setup.cpp @@ -4,10 +4,11 @@ #include +#include #include #include +#include -#include "gui/guisys/private/platforms/context_extraction.h" #include "renderer/gui/guisys/private/opengl_debug_logger.h" #include "renderer/opengl/context.h" #include "renderer/opengl/window.h" diff --git a/libopenage/gui/guisys/private/livereload/deferred_initial_constant_property_values.cpp b/libopenage/renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.cpp similarity index 84% rename from libopenage/gui/guisys/private/livereload/deferred_initial_constant_property_values.cpp rename to libopenage/renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.cpp index 932ca20791..f17f7f2a0e 100644 --- a/libopenage/gui/guisys/private/livereload/deferred_initial_constant_property_values.cpp +++ b/libopenage/renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.cpp @@ -1,11 +1,10 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #include "deferred_initial_constant_property_values.h" -namespace qtsdl { +namespace qtgui { -DeferredInitialConstantPropertyValues::DeferredInitialConstantPropertyValues() - : +DeferredInitialConstantPropertyValues::DeferredInitialConstantPropertyValues() : init_over{} { } @@ -27,4 +26,4 @@ bool DeferredInitialConstantPropertyValues::is_init_over() const { return this->init_over; } -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/private/livereload/deferred_initial_constant_property_values.h b/libopenage/renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.h similarity index 88% rename from libopenage/gui/guisys/private/livereload/deferred_initial_constant_property_values.h rename to libopenage/renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.h index 699c9ed64c..1add8b41e1 100644 --- a/libopenage/gui/guisys/private/livereload/deferred_initial_constant_property_values.h +++ b/libopenage/renderer/gui/guisys/private/livereload/deferred_initial_constant_property_values.h @@ -1,11 +1,11 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once -#include #include +#include -namespace qtsdl { +namespace qtgui { /** * Stores static properties during initialization to be able to assign them after all 'liveReloadTag' properties are set. @@ -36,4 +36,4 @@ class DeferredInitialConstantPropertyValues { std::vector> static_properties_assignments; }; -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/gui/guisys/private/livereload/gui_live_reloader.cpp b/libopenage/renderer/gui/guisys/private/livereload/gui_live_reloader.cpp similarity index 98% rename from libopenage/gui/guisys/private/livereload/gui_live_reloader.cpp rename to libopenage/renderer/gui/guisys/private/livereload/gui_live_reloader.cpp index 474de95dc9..142ec7892e 100644 --- a/libopenage/gui/guisys/private/livereload/gui_live_reloader.cpp +++ b/libopenage/renderer/gui/guisys/private/livereload/gui_live_reloader.cpp @@ -8,7 +8,7 @@ #include "../../link/gui_item.h" #include "deferred_initial_constant_property_values.h" -namespace qtsdl { +namespace qtgui { namespace { const int registration = qmlRegisterUncreatableType("yay.sfttech.livereload", 1, 0, "LR", "LR is non-instantiable. It provides the 'LR.tag' attached property."); @@ -88,4 +88,4 @@ void GuiLiveReloader::init_persistent_items(const QList -#include #include +#include +#include -#include #include #include +#include #include #include // since qt 5.14, the std::hash of q* types are included in qt #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) namespace std { -template<> +template <> struct hash { - size_t operator()(const QString& val) const noexcept { + size_t operator()(const QString &val) const noexcept { return qHash(val); } }; -} +} // namespace std #endif -namespace qtsdl { +namespace qtgui { class GuiItemBase; @@ -39,7 +39,7 @@ class GuiLiveReloaderAttachedProperty : public QObject { public: explicit GuiLiveReloaderAttachedProperty(QObject *object); - GuiItemBase* get_attachee() const; + GuiItemBase *get_attachee() const; QString get_tag() const; void set_tag(const QString &tag); @@ -60,7 +60,7 @@ class GuiLiveReloaderAttachedPropertyProvider : public QObject { Q_OBJECT public: - static GuiLiveReloaderAttachedProperty* qmlAttachedProperties(QObject*); + static GuiLiveReloaderAttachedProperty *qmlAttachedProperties(QObject *); }; class PersistentCoreHolderBase; @@ -69,15 +69,14 @@ class PersistentCoreHolderBase; * Stores objects that need to be kept alive across GUI reloads. */ class GuiLiveReloader { - public: - void init_persistent_items(const QList &items); + void init_persistent_items(const QList &items); private: using TagToPreservableMap = std::unordered_map>; TagToPreservableMap preservable; }; -} // namespace qtsdl +} // namespace qtgui -QML_DECLARE_TYPEINFO(qtsdl::GuiLiveReloaderAttachedPropertyProvider, QML_HAS_ATTACHED_PROPERTIES) +QML_DECLARE_TYPEINFO(qtgui::GuiLiveReloaderAttachedPropertyProvider, QML_HAS_ATTACHED_PROPERTIES) diff --git a/libopenage/renderer/gui/guisys/private/opengl_debug_logger.h b/libopenage/renderer/gui/guisys/private/opengl_debug_logger.h index f2763c96e7..3c297e197f 100644 --- a/libopenage/renderer/gui/guisys/private/opengl_debug_logger.h +++ b/libopenage/renderer/gui/guisys/private/opengl_debug_logger.h @@ -40,4 +40,4 @@ gl_debug_parameters get_current_opengl_debug_parameters(QOpenGLContext ¤t_ */ void apply_opengl_debug_parameters(gl_debug_parameters params, QOpenGLContext ¤t_dest_context); -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/renderer/gui/guisys/public/gui_application.cpp b/libopenage/renderer/gui/guisys/public/gui_application.cpp index 08a93aa42d..cd07289f87 100644 --- a/libopenage/renderer/gui/guisys/public/gui_application.cpp +++ b/libopenage/renderer/gui/guisys/public/gui_application.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2022 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #include @@ -8,13 +8,11 @@ namespace qtgui { -GuiApplication::GuiApplication() - : +GuiApplication::GuiApplication() : application{GuiApplicationImpl::get()} { } -GuiApplication::GuiApplication(std::shared_ptr application) - : +GuiApplication::GuiApplication(std::shared_ptr application) : application{application} { } @@ -24,4 +22,4 @@ void GuiApplication::process_events() { this->application->processEvents(); } -} // namespace qtsdl +} // namespace qtgui diff --git a/libopenage/renderer/gui/integration/private/CMakeLists.txt b/libopenage/renderer/gui/integration/private/CMakeLists.txt index 1ef1a3946a..3457b62e3a 100644 --- a/libopenage/renderer/gui/integration/private/CMakeLists.txt +++ b/libopenage/renderer/gui/integration/private/CMakeLists.txt @@ -1,3 +1,8 @@ add_sources(libopenage - gui_log.cpp + gui_filled_texture_handles.cpp + gui_log.cpp + gui_make_standalone_subtexture.cpp + gui_standalone_subtexture.cpp + gui_texture.cpp + gui_texture_handle.cpp ) diff --git a/libopenage/gui/integration/private/gui_filled_texture_handles.cpp b/libopenage/renderer/gui/integration/private/gui_filled_texture_handles.cpp similarity index 70% rename from libopenage/gui/integration/private/gui_filled_texture_handles.cpp rename to libopenage/renderer/gui/integration/private/gui_filled_texture_handles.cpp index 20df907316..db664516b4 100644 --- a/libopenage/gui/integration/private/gui_filled_texture_handles.cpp +++ b/libopenage/renderer/gui/integration/private/gui_filled_texture_handles.cpp @@ -1,12 +1,13 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #include "gui_filled_texture_handles.h" #include -#include "gui_texture_handle.h" +#include "renderer/gui/integration/private/gui_texture_handle.h" -namespace openage::gui { + +namespace openage::renderer::gui { GuiFilledTextureHandles::GuiFilledTextureHandles() = default; @@ -19,39 +20,38 @@ void GuiFilledTextureHandles::add_texture_handle(const QString &id, const QSize void GuiFilledTextureHandles::free_texture_handle(SizedTextureHandle *filled_handle) { std::unique_lock lck{this->handles_mutex}; - this->handles.erase(std::remove_if(std::begin(this->handles), std::end(this->handles), [filled_handle] (const std::tuple& handle) { - return std::get(handle) == filled_handle; - }), std::end(this->handles)); + this->handles.erase(std::remove_if(std::begin(this->handles), std::end(this->handles), [filled_handle](const std::tuple &handle) { + return std::get(handle) == filled_handle; + }), + std::end(this->handles)); } void GuiFilledTextureHandles::fill_all_handles_with_texture(const TextureHandle &texture) { std::unique_lock lck{this->handles_mutex}; - std::for_each(std::begin(this->handles), std::end(this->handles), [&texture] (std::tuple& handle) { - auto filled_handle = std::get(handle); + std::for_each(std::begin(this->handles), std::end(this->handles), [&texture](std::tuple &handle) { + auto filled_handle = std::get(handle); *filled_handle = {texture, textureSize(*filled_handle)}; }); } -void GuiFilledTextureHandles::refresh_all_handles_with_texture(const std::function& refresher) { +void GuiFilledTextureHandles::refresh_all_handles_with_texture(const std::function &refresher) { std::unique_lock lck{this->handles_mutex}; std::vector refreshed_handles(this->handles.size()); - std::transform(std::begin(this->handles), std::end(this->handles), std::begin(refreshed_handles), [refresher] (const std::tuple& handle) { + std::transform(std::begin(this->handles), std::end(this->handles), std::begin(refreshed_handles), [refresher](const std::tuple &handle) { SizedTextureHandle refreshed_handles; refresher(std::get(handle), std::get(handle), &refreshed_handles); return refreshed_handles; }); for (std::size_t i = 0, e = refreshed_handles.size(); i != e; ++i) - *std::get(this->handles[i]) = refreshed_handles[i]; + *std::get(this->handles[i]) = refreshed_handles[i]; } -GuiFilledTextureHandleUser::GuiFilledTextureHandleUser(std::shared_ptr texture_handles, const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle) - : +GuiFilledTextureHandleUser::GuiFilledTextureHandleUser(std::shared_ptr texture_handles, const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle) : texture_handles{std::move(texture_handles)}, filled_handle{filled_handle} { - this->texture_handles->add_texture_handle(id, requested_size, filled_handle); } @@ -60,4 +60,4 @@ GuiFilledTextureHandleUser::~GuiFilledTextureHandleUser() { texture_handles->free_texture_handle(filled_handle); } -} // namespace openage::gui +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_filled_texture_handles.h b/libopenage/renderer/gui/integration/private/gui_filled_texture_handles.h similarity index 74% rename from libopenage/gui/integration/private/gui_filled_texture_handles.h rename to libopenage/renderer/gui/integration/private/gui_filled_texture_handles.h index 8d88a7d688..afca15e1c2 100644 --- a/libopenage/gui/integration/private/gui_filled_texture_handles.h +++ b/libopenage/renderer/gui/integration/private/gui_filled_texture_handles.h @@ -1,17 +1,16 @@ -// Copyright 2015-2019 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once -#include -#include -#include #include +#include +#include +#include -#include #include +#include -namespace openage { -namespace gui { +namespace openage::renderer::gui { class TextureHandle; class SizedTextureHandle; @@ -31,7 +30,7 @@ class GuiFilledTextureHandles { void free_texture_handle(SizedTextureHandle *filled_handle); void fill_all_handles_with_texture(const TextureHandle &texture); - void refresh_all_handles_with_texture(const std::function& refresher); + void refresh_all_handles_with_texture(const std::function &refresher); private: /** @@ -40,7 +39,7 @@ class GuiFilledTextureHandles { * It's not a proper Qt usage, so the live reload of the game assets for the gui may break in future Qt releases. * When it breaks, this feature should be implemented via the recreation of the qml engine. */ - std::vector> handles; + std::vector> handles; std::mutex handles_mutex; }; @@ -49,14 +48,14 @@ class GuiFilledTextureHandleUser { GuiFilledTextureHandleUser(std::shared_ptr texture_handles, const QString &id, const QSize &requested_size, SizedTextureHandle *filled_handle); ~GuiFilledTextureHandleUser(); - GuiFilledTextureHandleUser(GuiFilledTextureHandleUser&&) noexcept = default; + GuiFilledTextureHandleUser(GuiFilledTextureHandleUser &&) noexcept = default; private: - GuiFilledTextureHandleUser(const GuiFilledTextureHandleUser&) = delete; - GuiFilledTextureHandleUser& operator=(const GuiFilledTextureHandleUser&) = delete; + GuiFilledTextureHandleUser(const GuiFilledTextureHandleUser &) = delete; + GuiFilledTextureHandleUser &operator=(const GuiFilledTextureHandleUser &) = delete; std::shared_ptr texture_handles; SizedTextureHandle *filled_handle; }; -}} // namespace openage::gui +} // namespace openage::renderer::gui diff --git a/libopenage/renderer/gui/integration/private/gui_make_standalone_subtexture.cpp b/libopenage/renderer/gui/integration/private/gui_make_standalone_subtexture.cpp new file mode 100644 index 0000000000..5151a3934a --- /dev/null +++ b/libopenage/renderer/gui/integration/private/gui_make_standalone_subtexture.cpp @@ -0,0 +1,14 @@ +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + +#include "gui_make_standalone_subtexture.h" + +#include "renderer/gui/integration/private/gui_standalone_subtexture.h" + + +namespace openage::renderer::gui { + +std::unique_ptr make_standalone_subtexture(GLuint id, const QSize &size) { + return std::make_unique(id, size); +} + +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_make_standalone_subtexture.h b/libopenage/renderer/gui/integration/private/gui_make_standalone_subtexture.h similarity index 87% rename from libopenage/gui/integration/private/gui_make_standalone_subtexture.h rename to libopenage/renderer/gui/integration/private/gui_make_standalone_subtexture.h index e971f478c1..1a74659582 100644 --- a/libopenage/gui/integration/private/gui_make_standalone_subtexture.h +++ b/libopenage/renderer/gui/integration/private/gui_make_standalone_subtexture.h @@ -8,8 +8,7 @@ #include -namespace openage { -namespace gui { +namespace openage::renderer::gui { /* * Reason for this is to resolve epoxy header clash that occur @@ -20,5 +19,4 @@ namespace gui { */ std::unique_ptr make_standalone_subtexture(GLuint id, const QSize &size); -} // namespace gui -} // namespace openage +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_standalone_subtexture.cpp b/libopenage/renderer/gui/integration/private/gui_standalone_subtexture.cpp similarity index 91% rename from libopenage/gui/integration/private/gui_standalone_subtexture.cpp rename to libopenage/renderer/gui/integration/private/gui_standalone_subtexture.cpp index 3f55d77bc3..63ca492169 100644 --- a/libopenage/gui/integration/private/gui_standalone_subtexture.cpp +++ b/libopenage/renderer/gui/integration/private/gui_standalone_subtexture.cpp @@ -2,8 +2,7 @@ #include "gui_standalone_subtexture.h" -namespace openage { -namespace gui { +namespace openage::renderer::gui { GuiStandaloneSubtexture::GuiStandaloneSubtexture(GLuint id, const QSize &size) : id(id), @@ -43,5 +42,4 @@ QSize GuiStandaloneSubtexture::textureSize() const { return this->size; } -} // namespace gui -} // namespace openage +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_standalone_subtexture.h b/libopenage/renderer/gui/integration/private/gui_standalone_subtexture.h similarity index 89% rename from libopenage/gui/integration/private/gui_standalone_subtexture.h rename to libopenage/renderer/gui/integration/private/gui_standalone_subtexture.h index 3512d2d066..462e82f370 100644 --- a/libopenage/gui/integration/private/gui_standalone_subtexture.h +++ b/libopenage/renderer/gui/integration/private/gui_standalone_subtexture.h @@ -5,8 +5,7 @@ #include #include -namespace openage { -namespace gui { +namespace openage::renderer::gui { class GuiStandaloneSubtexture : public QSGTexture { Q_OBJECT @@ -30,5 +29,4 @@ class GuiStandaloneSubtexture : public QSGTexture { const QSize size; }; -} // namespace gui -} // namespace openage +} // namespace openage::renderer::gui diff --git a/libopenage/renderer/gui/integration/private/gui_texture.cpp b/libopenage/renderer/gui/integration/private/gui_texture.cpp new file mode 100644 index 0000000000..daa6f4020a --- /dev/null +++ b/libopenage/renderer/gui/integration/private/gui_texture.cpp @@ -0,0 +1,62 @@ +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + +#include + +#include + +#include "renderer/gui/integration/private/gui_make_standalone_subtexture.h" +#include "renderer/gui/integration/private/gui_texture.h" + + +namespace openage::renderer::gui { + +GuiTexture::GuiTexture(const SizedTextureHandle &texture_handle) : + QSGTexture{}, + texture_handle(texture_handle) { +} + +GuiTexture::~GuiTexture() = default; + +void GuiTexture::bind() { + glBindTexture(GL_TEXTURE_2D, this->textureId()); +} + +qint64 GuiTexture::comparisonKey() const { + // TODO: Qt5 What does this do?????? + return 0; +} + +bool GuiTexture::hasAlphaChannel() const { + // assume 32bit textures + return true; +} + +bool GuiTexture::hasMipmaps() const { + return false; +} + +bool GuiTexture::isAtlasTexture() const { + return openage::renderer::gui::isAtlasTexture(this->texture_handle); +} + +QSGTexture *GuiTexture::removedFromAtlas(QRhiResourceUpdateBatch * /* resourceUpdates */ /* = nullptr */) const { + if (this->isAtlasTexture()) { + return this->standalone.get(); + } + + return nullptr; +} + +QRectF GuiTexture::normalizedTextureSubRect() const { + return QSGTexture::normalizedTextureSubRect(); +} + +int GuiTexture::textureId() const { + return 0; +} + +QSize GuiTexture::textureSize() const { + return openage::renderer::gui::textureSize(this->texture_handle); +} + +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_texture.h b/libopenage/renderer/gui/integration/private/gui_texture.h similarity index 91% rename from libopenage/gui/integration/private/gui_texture.h rename to libopenage/renderer/gui/integration/private/gui_texture.h index aa84a0c10e..1972822763 100644 --- a/libopenage/gui/integration/private/gui_texture.h +++ b/libopenage/renderer/gui/integration/private/gui_texture.h @@ -8,8 +8,7 @@ #include "gui_texture_handle.h" -namespace openage { -namespace gui { +namespace openage::renderer::gui { class GuiTexture : public QSGTexture { Q_OBJECT @@ -35,5 +34,4 @@ class GuiTexture : public QSGTexture { mutable std::unique_ptr standalone; }; -} // namespace gui -} // namespace openage +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_texture_handle.cpp b/libopenage/renderer/gui/integration/private/gui_texture_handle.cpp similarity index 62% rename from libopenage/gui/integration/private/gui_texture_handle.cpp rename to libopenage/renderer/gui/integration/private/gui_texture_handle.cpp index da9c974c80..1174d933b3 100644 --- a/libopenage/gui/integration/private/gui_texture_handle.cpp +++ b/libopenage/renderer/gui/integration/private/gui_texture_handle.cpp @@ -1,43 +1,32 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #include "gui_texture_handle.h" #include -#include "../../../texture.h" -namespace openage { -namespace gui { +namespace openage::renderer::gui { -SizedTextureHandle::SizedTextureHandle() - : - TextureHandle{nullptr, 0}, +SizedTextureHandle::SizedTextureHandle() : + TextureHandle{0}, size{} { } -SizedTextureHandle::SizedTextureHandle(const TextureHandle &handle, const QSize &size) - : +SizedTextureHandle::SizedTextureHandle(const TextureHandle &handle, const QSize &size) : TextureHandle(handle), size{size} { } bool isAtlasTexture(const TextureHandle &texture_handle) { - return texture_handle.subid >= 0 && texture_handle.texture->get_subtexture_count() > 1; + return texture_handle.subid >= 0; } QSize textureSize(const SizedTextureHandle &texture_handle) { return texture_handle.size; } -QSize native_size(const TextureHandle &texture_handle) { - auto tex = texture_handle.texture; - - if (isAtlasTexture(texture_handle)) { - auto sub = tex->get_subtexture(texture_handle.subid); - return QSize(sub->w, sub->h); - } else { - return QSize(tex->w, tex->h); - } +QSize native_size(const TextureHandle & /* texture_handle */) { + return QSize(0, 0); } QSize aspect_fit_size(const TextureHandle &texture_handle, const QSize &requested_size) { @@ -48,9 +37,10 @@ QSize aspect_fit_size(const TextureHandle &texture_handle, const QSize &requeste // If requested_size.isEmpty() then the caller don't care how big one or two dimensions can grow. return size.scaled(bounding_size, requested_size.isEmpty() && (requested_size.width() > size.width() || requested_size.height() > size.height()) ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio); - } else { + } + else { return size; } } -}} // namespace openage::gui +} // namespace openage::renderer::gui diff --git a/libopenage/gui/integration/private/gui_texture_handle.h b/libopenage/renderer/gui/integration/private/gui_texture_handle.h similarity index 83% rename from libopenage/gui/integration/private/gui_texture_handle.h rename to libopenage/renderer/gui/integration/private/gui_texture_handle.h index 58b86ee1bb..f9cdf59686 100644 --- a/libopenage/gui/integration/private/gui_texture_handle.h +++ b/libopenage/renderer/gui/integration/private/gui_texture_handle.h @@ -1,18 +1,13 @@ -// Copyright 2015-2017 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. #pragma once #include -namespace openage { - -class Texture; - -namespace gui { +namespace openage::renderer::gui { class TextureHandle { public: - openage::Texture *texture; int subid; }; @@ -36,4 +31,4 @@ QSize native_size(const TextureHandle &texture_handle); */ QSize aspect_fit_size(const TextureHandle &texture_handle, const QSize &requested_size); -}} // namespace openage::gui +} // namespace openage::renderer::gui diff --git a/libopenage/renderer/gui/qml_info.cpp b/libopenage/renderer/gui/qml_info.cpp deleted file mode 100644 index 16e03f333b..0000000000 --- a/libopenage/renderer/gui/qml_info.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#include "qml_info.h" - -namespace openage { -namespace renderer { -namespace gui { - -QMLInfo::QMLInfo(gamestate::GameSimulation *engine, const util::Path &asset_dir) : - engine{engine}, - asset_dir{asset_dir} {} - -} // namespace gui -} // namespace renderer -} // namespace openage diff --git a/libopenage/renderer/gui/qml_info.h b/libopenage/renderer/gui/qml_info.h deleted file mode 100644 index a5a668a086..0000000000 --- a/libopenage/renderer/gui/qml_info.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include "gui/guisys/public/gui_singleton_items_info.h" -#include "util/path.h" - -namespace openage { - -namespace gamestate { -class GameSimulation; -} - -namespace presenter { -class Presenter; -} - -namespace renderer { -namespace gui { - -class QMLInfo : public qtsdl::GuiSingletonItemsInfo { -public: - QMLInfo(gamestate::GameSimulation *engine, const util::Path &asset_dir); - - /** - * The openage engine, so it can be "used" in QML as a "QML Singleton". - * With this pointer, all of QML can find back to the engine. - */ - gamestate::GameSimulation *engine; - - /** - * The openage display. - */ - presenter::Presenter *display; - - /** - * Search path for finding assets n stuff. - */ - util::Path asset_dir; -}; - - -} // namespace gui -} // namespace renderer -} // namespace openage diff --git a/libopenage/renderer/opengl/CMakeLists.txt b/libopenage/renderer/opengl/CMakeLists.txt index eb93f1df56..300dac811f 100644 --- a/libopenage/renderer/opengl/CMakeLists.txt +++ b/libopenage/renderer/opengl/CMakeLists.txt @@ -2,6 +2,7 @@ add_sources(libopenage buffer.cpp context.cpp debug.cpp + error.cpp framebuffer.cpp geometry.cpp render_pass.cpp diff --git a/libopenage/util/opengl.cpp b/libopenage/renderer/opengl/error.cpp similarity index 79% rename from libopenage/util/opengl.cpp rename to libopenage/renderer/opengl/error.cpp index 1cc8b31ee3..c47bf5a85d 100644 --- a/libopenage/util/opengl.cpp +++ b/libopenage/renderer/opengl/error.cpp @@ -1,20 +1,18 @@ -// Copyright 2014-2016 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. -#include "opengl.h" +#include "error.h" #include -#include "../error/error.h" +#include "error/error.h" -namespace openage { -namespace util { +namespace openage::renderer::opengl { void gl_check_error() { int glerrorstate = 0; glerrorstate = glGetError(); if (glerrorstate != GL_NO_ERROR) { - const char *errormsg; //generate error message @@ -63,11 +61,12 @@ void gl_check_error() { // unknown error state errormsg = "unknown error"; } - throw Error(MSG(err) << - "OpenGL error state after running draw method: " << glerrorstate << "\n" - "\t" << errormsg << "\n" - << "Run the game with --gl-debug to get more information: './run game --gl-debug'."); + throw Error(MSG(err) << "OpenGL error state after running draw method: " + << glerrorstate << "\n" + "\t" + << errormsg << "\n" + << "Run the engine with --gl-debug to get more information."); } } -}} // openage::util +} // namespace openage::renderer::opengl diff --git a/libopenage/util/opengl.h b/libopenage/renderer/opengl/error.h similarity index 51% rename from libopenage/util/opengl.h rename to libopenage/renderer/opengl/error.h index d1c3a2e300..5fe692fd2d 100644 --- a/libopenage/util/opengl.h +++ b/libopenage/renderer/opengl/error.h @@ -1,9 +1,8 @@ -// Copyright 2014-2016 the openage authors. See copying.md for legal info. +// Copyright 2014-2023 the openage authors. See copying.md for legal info. #pragma once -namespace openage { -namespace util { +namespace openage::renderer::opengl { /** * query the current opengl context for any errors. @@ -12,5 +11,4 @@ namespace util { */ void gl_check_error(); -} -} +} // namespace openage::renderer::opengl diff --git a/libopenage/renderer/opengl/render_target.cpp b/libopenage/renderer/opengl/render_target.cpp index c0da3a22a8..ba0505adba 100644 --- a/libopenage/renderer/opengl/render_target.cpp +++ b/libopenage/renderer/opengl/render_target.cpp @@ -22,6 +22,19 @@ GlRenderTarget::GlRenderTarget(const std::shared_ptr &context, this->size = this->textures.value().at(0)->get_info().get_size(); } +resources::Texture2dData GlRenderTarget::into_data() { + // make sure the framebuffer is bound + this->bind_read(); + + std::vector pxdata(this->size.first * this->size.second * 4); + glReadPixels(0, 0, this->size.first, this->size.second, GL_RGBA, GL_UNSIGNED_BYTE, pxdata.data()); + + resources::Texture2dInfo info{this->size.first, + this->size.second, + resources::pixel_format::rgba8}; + return resources::Texture2dData{info, std::move(pxdata)}; +} + std::vector> GlRenderTarget::get_texture_targets() { std::vector> textures{}; if (this->framebuffer->get_type() == gl_framebuffer_t::display) { diff --git a/libopenage/renderer/opengl/render_target.h b/libopenage/renderer/opengl/render_target.h index 5246b03cb7..acf0c0af00 100644 --- a/libopenage/renderer/opengl/render_target.h +++ b/libopenage/renderer/opengl/render_target.h @@ -56,6 +56,13 @@ class GlRenderTarget final : public RenderTarget { GlRenderTarget(const std::shared_ptr &context, std::vector> const &textures); + /** + * Get the pixels stored in the render target's buffer. + * + * @return Texture data with the image contents of the buffer. + */ + resources::Texture2dData into_data() override; + /** * Get the targeted textures. * diff --git a/libopenage/renderer/opengl/shader_data.cpp b/libopenage/renderer/opengl/shader_data.cpp index d4f7e040e2..1bfd912518 100644 --- a/libopenage/renderer/opengl/shader_data.cpp +++ b/libopenage/renderer/opengl/shader_data.cpp @@ -1,3 +1,10 @@ // Copyright 2023-2023 the openage authors. See copying.md for legal info. #include "shader_data.h" + + +namespace openage::renderer::opengl { + +// this file is intentionally empty + +} // namespace openage::renderer::opengl diff --git a/libopenage/renderer/opengl/shader_program.cpp b/libopenage/renderer/opengl/shader_program.cpp index 67127ecc1f..3ccd49ce80 100644 --- a/libopenage/renderer/opengl/shader_program.cpp +++ b/libopenage/renderer/opengl/shader_program.cpp @@ -9,9 +9,9 @@ #include "datastructure/constexpr_map.h" #include "error/error.h" #include "log/log.h" -#include "util/opengl.h" #include "renderer/opengl/context.h" +#include "renderer/opengl/error.h" #include "renderer/opengl/geometry.h" #include "renderer/opengl/lookup.h" #include "renderer/opengl/shader.h" diff --git a/libopenage/renderer/opengl/window.cpp b/libopenage/renderer/opengl/window.cpp index daedbf7537..d169bff00b 100644 --- a/libopenage/renderer/opengl/window.cpp +++ b/libopenage/renderer/opengl/window.cpp @@ -2,18 +2,18 @@ #include "window.h" +#include +#include +#include +#include + #include "error/error.h" -#include "gui/guisys/public/gui_application.h" #include "log/log.h" + #include "renderer/opengl/context.h" #include "renderer/opengl/renderer.h" #include "renderer/window_event_handler.h" -#include -#include -#include -#include - namespace openage::renderer::opengl { @@ -146,7 +146,7 @@ std::shared_ptr GlWindow::make_renderer() { auto renderer = std::make_shared(this->get_context(), this->size * this->scale_dpr); - this->add_resize_callback([this, renderer](size_t w, size_t h, double scale) { + this->add_resize_callback([renderer](size_t w, size_t h, double scale) { // this up-scales all the default framebuffer to the "bigger" highdpi window. renderer->resize_display_target(w * scale, h * scale); }); diff --git a/libopenage/renderer/render_factory.cpp b/libopenage/renderer/render_factory.cpp index 463cb09d4a..c40cc46508 100644 --- a/libopenage/renderer/render_factory.cpp +++ b/libopenage/renderer/render_factory.cpp @@ -2,6 +2,7 @@ #include "render_factory.h" +#include "coord/phys.h" #include "renderer/stages/terrain/terrain_render_entity.h" #include "renderer/stages/terrain/terrain_renderer.h" #include "renderer/stages/world/world_render_entity.h" @@ -14,9 +15,10 @@ RenderFactory::RenderFactory(const std::shared_ptr ter world_renderer{world_renderer} { } -std::shared_ptr RenderFactory::add_terrain_render_entity() { +std::shared_ptr RenderFactory::add_terrain_render_entity(const util::Vector2s chunk_size, + const coord::tile_delta chunk_offset) { auto entity = std::make_shared(); - this->terrain_renderer->set_render_entity(entity); + this->terrain_renderer->add_render_entity(entity, chunk_size, chunk_offset.to_phys2().to_scene2()); return entity; } diff --git a/libopenage/renderer/render_factory.h b/libopenage/renderer/render_factory.h index 84f2b6eb39..5a2a36de59 100644 --- a/libopenage/renderer/render_factory.h +++ b/libopenage/renderer/render_factory.h @@ -4,6 +4,10 @@ #include +#include "coord/tile.h" +#include "util/vector.h" + + namespace openage::renderer { namespace terrain { class TerrainRenderer; @@ -35,9 +39,16 @@ class RenderFactory { /** * Create a new terrain render entity and register it at the terrain renderer. * + * Render entities for terrain are associated with chunks, so a new render entity + * will result in the creation of a new chunk in the renderer. + * + * Size/offset of the chunk in the game simulation should match size/offset + * in the renderer. + * * @return Render entity for pushing terrain updates. */ - std::shared_ptr add_terrain_render_entity(); + std::shared_ptr add_terrain_render_entity(const util::Vector2s chunk_size, + const coord::tile_delta chunk_offset); /** * Create a new world render entity and register it at the world renderer. diff --git a/libopenage/renderer/renderer.h b/libopenage/renderer/renderer.h index 8dec3dec2f..8f6e4ed3b9 100644 --- a/libopenage/renderer/renderer.h +++ b/libopenage/renderer/renderer.h @@ -34,6 +34,15 @@ class RenderTarget : public std::enable_shared_from_this { public: virtual ~RenderTarget() = default; + /** + * Get an image from the pixels in the render target's framebuffer. + * + * This should only be called _after_ rendering to the framebuffer has finished. + * + * @return RGBA texture data. + */ + virtual resources::Texture2dData into_data() = 0; + virtual std::vector> get_texture_targets() = 0; }; diff --git a/libopenage/renderer/resources/mesh_data.cpp b/libopenage/renderer/resources/mesh_data.cpp index 74fb72b629..98c5d7dbdb 100644 --- a/libopenage/renderer/resources/mesh_data.cpp +++ b/libopenage/renderer/resources/mesh_data.cpp @@ -123,7 +123,7 @@ MeshData create_float_mesh(const std::array &src) { auto const data_size = size * sizeof(float); std::vector verts(data_size); - std::memcpy(verts.data(), reinterpret_cast(src.data()), data_size); + std::memcpy(verts.data(), src.data(), data_size); VertexInputInfo info{ {vertex_input_t::V2F32, vertex_input_t::V2F32}, diff --git a/libopenage/renderer/resources/texture_data.cpp b/libopenage/renderer/resources/texture_data.cpp index 0e765b61d7..fe11c19ce5 100644 --- a/libopenage/renderer/resources/texture_data.cpp +++ b/libopenage/renderer/resources/texture_data.cpp @@ -177,7 +177,7 @@ void Texture2dData::store(const util::Path &file) const { QImage image{this->data.data(), size.first, size.second, pix_fmt}; - // Call sdl_image for saving the screenshot to PNG + // Call QImage for saving the screenshot to PNG std::string path = file.resolve_native_path_w(); image.save(path.c_str()); } diff --git a/libopenage/renderer/resources/texture_data.h b/libopenage/renderer/resources/texture_data.h index 0107959d36..004a2bda1e 100644 --- a/libopenage/renderer/resources/texture_data.h +++ b/libopenage/renderer/resources/texture_data.h @@ -31,8 +31,8 @@ class Texture2dData { /// Create a texture from info. /// - /// Uses SDL Image internally. For supported image file types, - /// see the SDL_Image initialization in the engine. + /// Uses QImage internally. For supported image file types, + /// see the QImage initialization in the engine. Texture2dData(Texture2dInfo const &info); /// Construct by moving the information and raw texture data from somewhere else. diff --git a/libopenage/renderer/stages/screen/CMakeLists.txt b/libopenage/renderer/stages/screen/CMakeLists.txt index b964aae19b..59529a556b 100644 --- a/libopenage/renderer/stages/screen/CMakeLists.txt +++ b/libopenage/renderer/stages/screen/CMakeLists.txt @@ -1,3 +1,4 @@ add_sources(libopenage screen_renderer.cpp + screenshot.cpp ) diff --git a/libopenage/renderer/stages/screen/screenshot.cpp b/libopenage/renderer/stages/screen/screenshot.cpp new file mode 100644 index 0000000000..e73c875a11 --- /dev/null +++ b/libopenage/renderer/stages/screen/screenshot.cpp @@ -0,0 +1,67 @@ +// Copyright 2014-2023 the openage authors. See copying.md for legal info. + +#include "screenshot.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "job/job_manager.h" +#include "log/log.h" +#include "renderer/renderer.h" +#include "renderer/resources/texture_data.h" +#include "renderer/stages/screen/screen_renderer.h" +#include "util/strings.h" + + +namespace openage::renderer::screen { + + +ScreenshotManager::ScreenshotManager(std::shared_ptr &renderer, + util::Path &outdir, + std::shared_ptr &job_mgr) : + outdir{outdir}, + count{0}, + last_time{0}, + renderer{renderer}, + job_manager{job_mgr} { +} + +std::string ScreenshotManager::gen_next_filename() { + std::time_t t = std::time(NULL); + + if (t == this->last_time) { + this->count++; + } + else { + this->count = 0; + this->last_time = t; + } + + // these two values (32) *must* be the same for safety reasons + char timestamp[32]; + std::strftime(timestamp, 32, "%Y-%m-%d_%H-%M-%S", std::localtime(&t)); + + return util::sformat("openage_%s_%02d.png", timestamp, this->count); +} + + +void ScreenshotManager::save_screenshot() { + // get screenshot image from scren renderer + auto pass = this->renderer->get_render_pass(); + auto target = pass->get_target(); + auto image = target->into_data(); + + auto store_function = [this, image]() { + image.store(this->outdir / this->gen_next_filename()); + return true; + }; + this->job_manager->enqueue(store_function); +} + +} // namespace openage::renderer::screen diff --git a/libopenage/renderer/stages/screen/screenshot.h b/libopenage/renderer/stages/screen/screenshot.h new file mode 100644 index 0000000000..df4ebcee48 --- /dev/null +++ b/libopenage/renderer/stages/screen/screenshot.h @@ -0,0 +1,80 @@ +// Copyright 2014-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include +#include + +#include "util/path.h" + + +namespace openage { + +namespace job { +class JobManager; +} + +namespace renderer::screen { +class ScreenRenderer; + +/** + * Takes screenshots, duh. + */ +class ScreenshotManager { +public: + /** + * Create a new screenshot manager. + * + * @param renderer Screen render stage to take the screenshot from. + * @param outdir Directory where the screenshots are saved. + * @param job_mgr Job manager to use for writing the screenshot to disk. + */ + ScreenshotManager(std::shared_ptr &renderer, + util::Path &outdir, + std::shared_ptr &job_mgr); + + ~ScreenshotManager() = default; + + /** + * Generate and save a screenshot of the last frame. + */ + void save_screenshot(); + +private: + /** + * Generates a filename for the screenshot. + * + * @return Filename for the screenshot. + */ + std::string gen_next_filename(); + + /** + * Directory where the screenshots are saved. + */ + util::Path outdir; + + /** + * Counter for the screenshot filename. Used if multiple screenshots + * are taken in the same second. + */ + unsigned count; + + /** + * Last time when a screenshot was taken. + */ + std::time_t last_time; + + /** + * Screen render stage to take the screenshot from. + */ + std::shared_ptr renderer; + + /** + * Job manager to use for writing the screenshot to disk. + */ + std::shared_ptr job_manager; +}; + +} // namespace renderer::screen +} // namespace openage diff --git a/libopenage/renderer/stages/terrain/CMakeLists.txt b/libopenage/renderer/stages/terrain/CMakeLists.txt index 6da55d3490..f3d10e1354 100644 --- a/libopenage/renderer/stages/terrain/CMakeLists.txt +++ b/libopenage/renderer/stages/terrain/CMakeLists.txt @@ -1,4 +1,5 @@ add_sources(libopenage + terrain_chunk.cpp terrain_mesh.cpp terrain_model.cpp terrain_render_entity.cpp diff --git a/libopenage/renderer/stages/terrain/terrain_chunk.cpp b/libopenage/renderer/stages/terrain/terrain_chunk.cpp new file mode 100644 index 0000000000..dcea61585e --- /dev/null +++ b/libopenage/renderer/stages/terrain/terrain_chunk.cpp @@ -0,0 +1,131 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#include "terrain_chunk.h" + +#include "renderer/resources/assets/asset_manager.h" +#include "renderer/resources/mesh_data.h" +#include "renderer/stages/terrain/terrain_mesh.h" +#include "renderer/stages/terrain/terrain_render_entity.h" + + +namespace openage::renderer::terrain { + +TerrainChunk::TerrainChunk(const std::shared_ptr &asset_manager, + const util::Vector2s size, + const coord::scene2_delta offset) : + size{size}, + offset{offset}, + asset_manager{asset_manager} {} + +void TerrainChunk::set_render_entity(const std::shared_ptr &entity) { + this->render_entity = entity; +} + +void TerrainChunk::fetch_updates(const time::time_t & /* time */) { + // TODO: Don't create model if render entity is not set + if (not this->render_entity) { + return; + } + + // Check render entity for updates + if (not this->render_entity->is_changed()) { + return; + } + // TODO: Change mesh instead of recreating it + // TODO: Multiple meshes + auto new_mesh = this->create_mesh(); + new_mesh->create_model_matrix(this->offset); + this->meshes.clear(); + this->meshes.push_back(new_mesh); + + // Indicate to the render entity that its updates have been processed. + this->render_entity->clear_changed_flag(); +} + +void TerrainChunk::update_uniforms(const time::time_t &time) { + for (auto &mesh : this->meshes) { + mesh->update_uniforms(time); + } +} + +const std::vector> &TerrainChunk::get_meshes() const { + return this->meshes; +} + +std::shared_ptr TerrainChunk::create_mesh() { + // Update mesh + auto size = this->render_entity->get_size(); + auto src_verts = this->render_entity->get_vertices(); + + // dst_verts places vertices in order + // (left to right, bottom to top) + std::vector dst_verts{}; + dst_verts.reserve(src_verts.size() * 5); + for (auto v : src_verts) { + // Transform to scene coords + auto v_vec = v.to_world_space(); + dst_verts.push_back(v_vec[0]); + dst_verts.push_back(v_vec[1]); + dst_verts.push_back(v_vec[2]); + // TODO: Texture scaling + dst_verts.push_back((v.ne / 10).to_float()); + dst_verts.push_back((v.se / 10).to_float()); + } + + // split the grid into triangles using an index array + std::vector idxs; + idxs.reserve((size[0] - 1) * (size[1] - 1) * 6); + // iterate over all tiles in the grid by columns, i.e. starting + // from the left corner to the bottom corner if you imagine it from + // the camera's point of view + for (size_t i = 0; i < size[0] - 1; ++i) { + for (size_t j = 0; j < size[1] - 1; ++j) { + // since we are working on tiles, we split each tile into two triangles + // with counter-clockwise vertex order + idxs.push_back(j + i * size[1]); // bottom left + idxs.push_back(j + 1 + i * size[1]); // bottom right + idxs.push_back(j + size[1] + i * size[1]); // top left + idxs.push_back(j + 1 + i * size[1]); // bottom right + idxs.push_back(j + size[1] + 1 + i * size[1]); // top right + idxs.push_back(j + size[1] + i * size[1]); // top left + } + } + + resources::VertexInputInfo info{ + {resources::vertex_input_t::V3F32, resources::vertex_input_t::V2F32}, + resources::vertex_layout_t::AOS, + resources::vertex_primitive_t::TRIANGLES, + resources::index_t::U16}; + + auto const vert_data_size = dst_verts.size() * sizeof(float); + std::vector vert_data(vert_data_size); + std::memcpy(vert_data.data(), dst_verts.data(), vert_data_size); + + auto const idx_data_size = idxs.size() * sizeof(uint16_t); + std::vector idx_data(idx_data_size); + std::memcpy(idx_data.data(), idxs.data(), idx_data_size); + + resources::MeshData meshdata{std::move(vert_data), std::move(idx_data), info}; + + // Update textures + auto tex_manager = this->asset_manager->get_texture_manager(); + + // TODO: Support multiple textures per chunk + + auto terrain_mesh = std::make_shared( + this->asset_manager, + this->render_entity->get_terrain_path(), + std::move(meshdata)); + + return terrain_mesh; +} + +util::Vector2s &TerrainChunk::get_size() { + return this->size; +} + +coord::scene2_delta &TerrainChunk::get_offset() { + return this->offset; +} + +} // namespace openage::renderer::terrain diff --git a/libopenage/renderer/stages/terrain/terrain_chunk.h b/libopenage/renderer/stages/terrain/terrain_chunk.h new file mode 100644 index 0000000000..4e96619865 --- /dev/null +++ b/libopenage/renderer/stages/terrain/terrain_chunk.h @@ -0,0 +1,119 @@ +// Copyright 2023-2023 the openage authors. See copying.md for legal info. + +#pragma once + +#include +#include +#include + +#include "coord/scene.h" +#include "time/time.h" +#include "util/vector.h" + + +namespace openage::renderer { + +namespace resources { +class AssetManager; +} + +namespace terrain { +class TerrainRenderMesh; +class TerrainRenderEntity; + +class TerrainChunk { +public: + /** + * Create a new terrain chunk. + * + * @param asset_manager Asset manager for loading textures. + */ + TerrainChunk(const std::shared_ptr &asset_manager, + const util::Vector2s size, + const coord::scene2_delta offset); + + ~TerrainChunk() = default; + + /** + * Set the terrain render entity for vertex updates of this mesh. + * + * @param entity New terrain render entity. + * @param size Size of the chunk in tiles. + * @param offset Offset of the chunk from origin in tiles. + */ + void set_render_entity(const std::shared_ptr &entity); + + /** + * Fetch updates from the render entity. + * + * @param time Current simulation time. + */ + void fetch_updates(const time::time_t &time = 0.0); + + /** + * Update the uniforms of the meshes. + * + * @param time Current simulation time. + */ + void update_uniforms(const time::time_t &time = 0.0); + + /** + * Get the meshes composing the terrain. + * + * @return Vector of terrain meshes. + */ + const std::vector> &get_meshes() const; + + /** + * Get the size of the chunk in tiles. + * + * @return Size of the chunk (in tiles). + */ + util::Vector2s &get_size(); + + /** + * Get the offset of the chunk from origin in tiles. + * + * @return Offset of the chunk (in tiles). + */ + coord::scene2_delta &get_offset(); + +private: + /** + * Create a terrain mesh from the data provided by the render entity. + * + * @return New terrain mesh. + */ + std::shared_ptr create_mesh(); + + /** + * Size of the chunk in tiles (width x height). + */ + util::Vector2s size; + + /** + * Offset of the chunk from origin in tiles (x, y). + */ + coord::scene2_delta offset; + + /** + * Meshes composing the terrain. Each mesh represents a drawable vertex surface + * and a texture. + */ + std::vector> meshes; + + /** + * Asset manager for central accessing and loading textures. + */ + std::shared_ptr asset_manager; + + /** + * Source for ingame terrain coordinates. These coordinates are translated into + * our render vertex mesh when \p update() is called. + */ + std::shared_ptr render_entity; +}; + + +} // namespace terrain +} // namespace openage::renderer diff --git a/libopenage/renderer/stages/terrain/terrain_mesh.cpp b/libopenage/renderer/stages/terrain/terrain_mesh.cpp index 1085e315d4..b02f867050 100644 --- a/libopenage/renderer/stages/terrain/terrain_mesh.cpp +++ b/libopenage/renderer/stages/terrain/terrain_mesh.cpp @@ -70,7 +70,7 @@ void TerrainRenderMesh::update_uniforms(const time::time_t &time) { } // local space -> world space - this->uniforms->update("model", this->get_model_matrix()); + this->uniforms->update("model", this->model_matrix); auto tex_info = this->terrain_info.get(time)->get_texture(0); auto tex_manager = this->asset_manager->get_texture_manager(); @@ -97,10 +97,11 @@ const std::shared_ptr &TerrainRenderMesh::get_uniforms() return this->uniforms; } -Eigen::Matrix4f TerrainRenderMesh::get_model_matrix() { +void TerrainRenderMesh::create_model_matrix(const coord::scene2_delta &offset) { // TODO: Needs input from engine - auto transform = Eigen::Affine3f::Identity(); - return transform.matrix(); + auto model = Eigen::Affine3f::Identity(); + model.translate(offset.to_world_space()); + this->model_matrix = model.matrix(); } bool TerrainRenderMesh::is_changed() { diff --git a/libopenage/renderer/stages/terrain/terrain_mesh.h b/libopenage/renderer/stages/terrain/terrain_mesh.h index a571007204..e2c7545ff8 100644 --- a/libopenage/renderer/stages/terrain/terrain_mesh.h +++ b/libopenage/renderer/stages/terrain/terrain_mesh.h @@ -7,9 +7,11 @@ #include +#include "coord/scene.h" #include "curve/discrete.h" #include "renderer/resources/mesh_data.h" #include "time/time.h" +#include "util/vector.h" namespace openage::renderer { @@ -110,11 +112,11 @@ class TerrainRenderMesh { void clear_requires_renderable(); /** - * Get the model transformation matrix for rendering. - * - * @return Model matrix. + * Create the model transformation matrix for rendering. + * + * @param offset Offset of the terrain mesh to the scene origin. */ - Eigen::Matrix4f get_model_matrix(); + void create_model_matrix(const coord::scene2_delta &offset); /** * Check whether the mesh or texture were changed. @@ -159,6 +161,11 @@ class TerrainRenderMesh { * Pre-transformation vertices for the terrain model. */ renderer::resources::MeshData mesh; + + /** + * Transformation matrix for the terrain model. + */ + Eigen::Matrix4f model_matrix; }; } // namespace terrain } // namespace openage::renderer diff --git a/libopenage/renderer/stages/terrain/terrain_model.cpp b/libopenage/renderer/stages/terrain/terrain_model.cpp index 4b73b556c9..329968f858 100644 --- a/libopenage/renderer/stages/terrain/terrain_model.cpp +++ b/libopenage/renderer/stages/terrain/terrain_model.cpp @@ -12,7 +12,7 @@ #include "coord/scene.h" #include "renderer/resources/assets/asset_manager.h" #include "renderer/resources/mesh_data.h" -#include "renderer/stages/terrain/terrain_mesh.h" +#include "renderer/stages/terrain/terrain_chunk.h" #include "renderer/stages/terrain/terrain_render_entity.h" #include "util/fixed_point.h" #include "util/vector.h" @@ -21,117 +21,39 @@ namespace openage::renderer::terrain { TerrainRenderModel::TerrainRenderModel(const std::shared_ptr &asset_manager) : - meshes{}, + chunks{}, camera{nullptr}, - asset_manager{asset_manager}, - render_entity{nullptr} { + asset_manager{asset_manager} { } -void TerrainRenderModel::set_render_entity(const std::shared_ptr &entity) { - this->render_entity = entity; - this->fetch_updates(); +void TerrainRenderModel::add_chunk(const std::shared_ptr &entity, + const util::Vector2s size, + const coord::scene2_delta offset) { + auto chunk = std::make_shared(this->asset_manager, size, offset); + chunk->set_render_entity(entity); + chunk->fetch_updates(); + + this->chunks.push_back(chunk); } void TerrainRenderModel::set_camera(const std::shared_ptr &camera) { this->camera = camera; } -void TerrainRenderModel::fetch_updates() { - // TODO: Don't create model if render entity is not set - if (not this->render_entity) { - return; - } - - // Check render entity for updates - if (not this->render_entity->is_changed()) { - return; +void TerrainRenderModel::fetch_updates(const time::time_t &time) { + for (auto &chunk : this->chunks) { + chunk->fetch_updates(time); } - // TODO: Change mesh instead of recreating it - // TODO: Multiple meshes - auto new_mesh = this->create_mesh(); - this->meshes.clear(); - this->meshes.push_back(new_mesh); - - // Indicate to the render entity that its updates have been processed. - this->render_entity->clear_changed_flag(); } void TerrainRenderModel::update_uniforms(const time::time_t &time) { - for (auto &mesh : this->meshes) { - mesh->update_uniforms(time); + for (auto &chunk : this->chunks) { + chunk->update_uniforms(time); } } -const std::vector> &TerrainRenderModel::get_meshes() const { - return this->meshes; -} - -std::shared_ptr TerrainRenderModel::create_mesh() { - // Update mesh - auto size = this->render_entity->get_size(); - auto src_verts = this->render_entity->get_vertices(); - - // dst_verts places vertices in order - // (left to right, bottom to top) - std::vector dst_verts{}; - dst_verts.reserve(src_verts.size() * 5); - for (auto v : src_verts) { - // Transform to scene coords - auto v_vec = v.to_world_space(); - dst_verts.push_back(v_vec[0]); - dst_verts.push_back(v_vec[1]); - dst_verts.push_back(v_vec[2]); - // TODO: Texture scaling - dst_verts.push_back((v.ne / 10).to_float()); - dst_verts.push_back((v.se / 10).to_float()); - } - - // split the grid into triangles using an index array - std::vector idxs; - idxs.reserve((size[0] - 1) * (size[1] - 1) * 6); - // iterate over all tiles in the grid by columns, i.e. starting - // from the left corner to the bottom corner if you imagine it from - // the camera's point of view - for (size_t i = 0; i < size[0] - 1; ++i) { - for (size_t j = 0; j < size[1] - 1; ++j) { - // since we are working on tiles, we split each tile into two triangles - // with counter-clockwise vertex order - idxs.push_back(j + i * size[1]); // bottom left - idxs.push_back(j + 1 + i * size[1]); // bottom right - idxs.push_back(j + size[1] + i * size[1]); // top left - idxs.push_back(j + 1 + i * size[1]); // bottom right - idxs.push_back(j + size[1] + 1 + i * size[1]); // top right - idxs.push_back(j + size[1] + i * size[1]); // top left - } - } - - resources::VertexInputInfo info{ - {resources::vertex_input_t::V3F32, resources::vertex_input_t::V2F32}, - resources::vertex_layout_t::AOS, - resources::vertex_primitive_t::TRIANGLES, - resources::index_t::U16}; - - auto const vert_data_size = dst_verts.size() * sizeof(float); - std::vector vert_data(vert_data_size); - std::memcpy(vert_data.data(), reinterpret_cast(dst_verts.data()), vert_data_size); - - auto const idx_data_size = idxs.size() * sizeof(uint16_t); - std::vector idx_data(idx_data_size); - std::memcpy(idx_data.data(), reinterpret_cast(idxs.data()), idx_data_size); - - resources::MeshData meshdata{std::move(vert_data), std::move(idx_data), info}; - - // Update textures - auto tex_manager = this->asset_manager->get_texture_manager(); - - // TODO: Support multiple textures per terrain - - auto terrain_mesh = std::make_shared( - this->asset_manager, - this->render_entity->get_terrain_path(), - std::move(meshdata)); - - return terrain_mesh; +const std::vector> &TerrainRenderModel::get_chunks() const { + return this->chunks; } } // namespace openage::renderer::terrain diff --git a/libopenage/renderer/stages/terrain/terrain_model.h b/libopenage/renderer/stages/terrain/terrain_model.h index 4a1ec15aed..6677f3c4c5 100644 --- a/libopenage/renderer/stages/terrain/terrain_model.h +++ b/libopenage/renderer/stages/terrain/terrain_model.h @@ -5,7 +5,9 @@ #include #include +#include "coord/scene.h" #include "time/time.h" +#include "util/vector.h" namespace openage::renderer { @@ -21,6 +23,7 @@ class AssetManager; namespace terrain { class TerrainRenderEntity; class TerrainRenderMesh; +class TerrainChunk; /** * 3D model of the whole terrain. Combines the individual meshes @@ -32,11 +35,15 @@ class TerrainRenderModel { ~TerrainRenderModel() = default; /** - * Set the terrain render entity for vertex updates of this mesh. + * Add a new chunk to the terrain model. * - * @param entity New terrain render entity. + * @param entity Render entity of the chunk. + * @param chunk_size Size of the chunk in tiles. + * @param chunk_offset Offset of the chunk from origin in tiles. */ - void set_render_entity(const std::shared_ptr &entity); + void add_chunk(const std::shared_ptr &entity, + const util::Vector2s chunk_size, + const coord::scene2_delta chunk_offset); /** * Set the current camera of the scene. @@ -47,8 +54,10 @@ class TerrainRenderModel { /** * Fetch updates from the render entity. + * + * @param time Current simulation time. */ - void fetch_updates(); + void fetch_updates(const time::time_t &time = 0.0); /** * Update the uniforms of the renderable associated with this object. @@ -58,25 +67,17 @@ class TerrainRenderModel { void update_uniforms(const time::time_t &time = 0.0); /** - * Get the meshes composing the terrain. + * Get the chunks composing the terrain. * - * @return Vector of terrain meshes. + * @return Chunks of the terrain. */ - const std::vector> &get_meshes() const; + const std::vector> &get_chunks() const; private: /** - * Create a terrain mesh from the data provided by the render entity. - * - * @return New terrain mesh. - */ - std::shared_ptr create_mesh(); - - /** - * Meshes composing the terrain. Each mesh represents a drawable vertex surface - * and a texture. + * Chunks composing the terrain. */ - std::vector> meshes; + std::vector> chunks; /** * Camera for view and projection uniforms. @@ -87,12 +88,6 @@ class TerrainRenderModel { * Asset manager for central accessing and loading textures. */ std::shared_ptr asset_manager; - - /** - * Source for ingame terrain coordinates. These coordinates are translated into - * our render vertex mesh when \p update() is called. - */ - std::shared_ptr render_entity; }; } // namespace terrain diff --git a/libopenage/renderer/stages/terrain/terrain_render_entity.cpp b/libopenage/renderer/stages/terrain/terrain_render_entity.cpp index a142461cb0..2d83b018f7 100644 --- a/libopenage/renderer/stages/terrain/terrain_render_entity.cpp +++ b/libopenage/renderer/stages/terrain/terrain_render_entity.cpp @@ -16,13 +16,38 @@ TerrainRenderEntity::TerrainRenderEntity() : terrain_path{nullptr, 0} { } -void TerrainRenderEntity::update(util::Vector2s size, - std::vector height_map, - const std::string terrain_path, +void TerrainRenderEntity::update_tile(const util::Vector2s size, + const coord::tile &pos, + const terrain_elevation_t elevation, + const std::string terrain_path, + const time::time_t time) { + std::unique_lock lock{this->mutex}; + + if (this->vertices.empty()) { + throw Error(MSG(err) << "Cannot update tile: Vertices have not been initialized yet."); + } + + // find the postion of the tile in the vertex array + auto left_corner = pos.ne * size[0] + pos.se; + + // update the 4 vertices of the tile + this->vertices[left_corner].up = elevation.to_float(); + this->vertices[left_corner + 1].up = elevation.to_float(); // bottom corner + this->vertices[left_corner + (size[0] + 1)].up = elevation.to_float(); // top corner + this->vertices[left_corner + (size[0] + 2)].up = elevation.to_float(); // right corner + + // set texture path + this->terrain_path.set_last(time, terrain_path); + + this->changed = true; +} + +void TerrainRenderEntity::update(const util::Vector2s size, + const tiles_t tiles, const time::time_t time) { std::unique_lock lock{this->mutex}; - // increase by 1 in every dimension because height_map + // increase by 1 in every dimension because tiles // size is number of tiles, but we want number of vertices util::Vector2i tile_size{size[0], size[1]}; this->size = util::Vector2s{size[0] + 1, size[1] + 1}; @@ -36,16 +61,16 @@ void TerrainRenderEntity::update(util::Vector2s size, // for each vertex, compare the surrounding tiles std::vector surround{}; if (j - 1 >= 0 and i - 1 >= 0) { - surround.push_back(height_map[(i - 1) * size[1] + j - 1]); + surround.push_back(tiles[(i - 1) * size[1] + j - 1].first.to_float()); } if (j < tile_size[1] and i - 1 >= 0) { - surround.push_back(height_map[(i - 1) * size[1] + j]); + surround.push_back(tiles[(i - 1) * size[1] + j].first.to_float()); } if (j < tile_size[1] and i < tile_size[0]) { - surround.push_back(height_map[i * size[1] + j]); + surround.push_back(tiles[i * size[1] + j].first.to_float()); } if (j - 1 >= 0 and i < tile_size[0]) { - surround.push_back(height_map[i * size[1] + j - 1]); + surround.push_back(tiles[i * size[1] + j - 1].first.to_float()); } // select the height of the highest surrounding tile auto max_height = *std::max_element(surround.begin(), surround.end()); @@ -59,7 +84,7 @@ void TerrainRenderEntity::update(util::Vector2s size, } // set texture path - this->terrain_path.set_last(time, terrain_path); + this->terrain_path.set_last(time, tiles[0].second); this->changed = true; } diff --git a/libopenage/renderer/stages/terrain/terrain_render_entity.h b/libopenage/renderer/stages/terrain/terrain_render_entity.h index 2d074e2590..a7b044b874 100644 --- a/libopenage/renderer/stages/terrain/terrain_render_entity.h +++ b/libopenage/renderer/stages/terrain/terrain_render_entity.h @@ -8,32 +8,49 @@ #include #include "coord/scene.h" +#include "coord/tile.h" #include "curve/discrete.h" #include "time/time.h" #include "util/vector.h" -namespace openage::renderer { +namespace openage::renderer::terrain { -namespace terrain { class TerrainRenderEntity { public: TerrainRenderEntity(); ~TerrainRenderEntity() = default; + using terrain_elevation_t = util::FixedPoint; + using tiles_t = std::vector>; + /** - * Update the render entity with information from the + * Update a single tile of the displayed terrain (chunk) with information from the * gamestate. * * @param size Size of the terrain in tiles (width x length) - * @param height_map Height of terrain tiles. + * @param pos Position of the tile in the chunk. + * @param elevation Height of terrain tile. * @param terrain_path Path to the terrain definition. * @param time Simulation time of the update. */ - void update(util::Vector2s size, - std::vector height_map, - const std::string terrain_path, + void update_tile(const util::Vector2s size, + const coord::tile &pos, + const terrain_elevation_t elevation, + const std::string terrain_path, + const time::time_t time = 0.0); + + /** + * Update the full grid of the displayed terrain (chunk) with information from the + * gamestate. + * + * @param size Size of the terrain in tiles (width x length) + * @param tiles Animation data for each tile (elevation, terrain path). + * @param time Simulation time of the update. + */ + void update(const util::Vector2s size, + const tiles_t tiles, const time::time_t time = 0.0); /** @@ -81,7 +98,7 @@ class TerrainRenderEntity { bool changed; /** - * Terrain dimensions (width x height). + * Chunk dimensions (width x height). */ util::Vector2s size; @@ -102,5 +119,4 @@ class TerrainRenderEntity { */ std::shared_mutex mutex; }; -} // namespace terrain -} // namespace openage::renderer +} // namespace openage::renderer::terrain diff --git a/libopenage/renderer/stages/terrain/terrain_renderer.cpp b/libopenage/renderer/stages/terrain/terrain_renderer.cpp index 62b7de8207..92b5933d4f 100644 --- a/libopenage/renderer/stages/terrain/terrain_renderer.cpp +++ b/libopenage/renderer/stages/terrain/terrain_renderer.cpp @@ -8,6 +8,7 @@ #include "renderer/resources/shader_source.h" #include "renderer/resources/texture_info.h" #include "renderer/shader_program.h" +#include "renderer/stages/terrain/terrain_chunk.h" #include "renderer/stages/terrain/terrain_mesh.h" #include "renderer/stages/terrain/terrain_model.h" #include "renderer/window.h" @@ -45,37 +46,40 @@ std::shared_ptr TerrainRenderer::get_render_pass() { return this->render_pass; } -void TerrainRenderer::set_render_entity(const std::shared_ptr entity) { +void TerrainRenderer::add_render_entity(const std::shared_ptr entity, + const util::Vector2s chunk_size, + const coord::scene2_delta chunk_offset) { std::unique_lock lock{this->mutex}; this->render_entity = entity; - this->model->set_render_entity(this->render_entity); + this->model->add_chunk(this->render_entity, chunk_size, chunk_offset); this->update(); } void TerrainRenderer::update() { this->model->fetch_updates(); auto current_time = this->clock->get_real_time(); - for (auto &mesh : this->model->get_meshes()) { - if (mesh->requires_renderable()) [[unlikely]] { /*probably doesn't happen that often?*/ - // TODO: Update uniforms and geometry individually, depending on what changed - // TODO: Update existing renderable instead of recreating it - auto geometry = this->renderer->add_mesh_geometry(mesh->get_mesh()); - auto transform_unifs = this->display_shader->create_empty_input(); - - Renderable display_obj{ - transform_unifs, - geometry, - true, - true, // it's a 3D object, so we need depth testing - }; - - // TODO: Remove old renderable instead of clearing everything - this->render_pass->clear_renderables(); - this->render_pass->add_renderables(display_obj); - mesh->clear_requires_renderable(); - - mesh->set_uniforms(transform_unifs); + for (auto &chunk : this->model->get_chunks()) { + for (auto &mesh : chunk->get_meshes()) { + if (mesh->requires_renderable()) [[unlikely]] { /*probably doesn't happen that often?*/ + // TODO: Update uniforms and geometry individually, depending on what changed + // TODO: Update existing renderable instead of recreating it + auto geometry = this->renderer->add_mesh_geometry(mesh->get_mesh()); + auto transform_unifs = this->display_shader->create_empty_input(); + + Renderable display_obj{ + transform_unifs, + geometry, + true, + true, // it's a 3D object, so we need depth testing + }; + + // TODO: Remove old renderable instead of clearing everything + this->render_pass->add_renderables(display_obj); + mesh->clear_requires_renderable(); + + mesh->set_uniforms(transform_unifs); + } } } this->model->update_uniforms(current_time); diff --git a/libopenage/renderer/stages/terrain/terrain_renderer.h b/libopenage/renderer/stages/terrain/terrain_renderer.h index 286567c34a..4986509c95 100644 --- a/libopenage/renderer/stages/terrain/terrain_renderer.h +++ b/libopenage/renderer/stages/terrain/terrain_renderer.h @@ -5,7 +5,10 @@ #include #include +#include "coord/scene.h" #include "util/path.h" +#include "util/vector.h" + namespace openage { @@ -54,11 +57,15 @@ class TerrainRenderer { std::shared_ptr get_render_pass(); /** - * Set the current render entity of the terrain renderer. + * Add a new render entity to the terrain renderer. + * + * This creates a new terrain chunk and add it to the model. * * @param render_entity New render entity. */ - void set_render_entity(const std::shared_ptr entity); + void add_render_entity(const std::shared_ptr entity, + const util::Vector2s chunk_size, + const coord::scene2_delta chunk_offset); /** * Update the terrain mesh and texture information. diff --git a/libopenage/renderer/text.cpp b/libopenage/renderer/text.cpp deleted file mode 100644 index 9bb108cc33..0000000000 --- a/libopenage/renderer/text.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2015-2018 the openage authors. See copying.md for legal info. - -#include "text.h" - -#include - -#include - -#include "../util/strings.h" -#include "font/font.h" - -namespace openage { - -namespace texturefont_shader { -shader::Program *program; -GLint texture, color, tex_coord; -} // namespace texture_shader - -namespace renderer { - -struct text_render_vertex { - float x; - float y; - float u; - float v; - - text_render_vertex() - : - text_render_vertex{0.0f, 0.0f, 0.0f, 0.0f} { - } - - text_render_vertex(float x, float y, float u, float v) - : - x{x}, - y{y}, - u{u}, - v{v} { - } -}; - -struct text_render_task { - GLenum mode; - Color color; - unsigned int num_elements; - unsigned int offset; -}; - -TextRenderer::TextRenderer() - : - current_font{nullptr}, - current_color{255, 255, 255, 255}, - is_dirty{true}, - vbo{0}, - ibo{0} { - - glGenBuffers(1, &this->vbo); - glGenBuffers(1, &this->ibo); -} - -TextRenderer::~TextRenderer() { - if (this->vbo != 0u) { - glDeleteBuffers(1, &this->vbo); - } - if (this->ibo != 0u) { - glDeleteBuffers(1, &this->ibo); - } -} - -void TextRenderer::set_font(Font *font) { - if (this->current_font == font) { - return; - } - - this->current_font = font; - this->is_dirty = true; -} - -void TextRenderer::set_color(const Color &color) { - if (this->current_color == color) { - return; - } - - this->current_color = color; - this->is_dirty = true; -} - -void TextRenderer::draw(coord::viewport position, const char *format, ...) { - std::string text; - va_list vl; - va_start(vl, format); - util::vsformat(format, vl, text); - va_end(vl); - - this->draw(position.x, position.y, text); -} - -void TextRenderer::draw(coord::viewport position, const std::string &text) { - this->draw(position.x, position.y, text); -} - -void TextRenderer::draw(int x, int y, const std::string &text) { - if (this->is_dirty || this->render_batches.empty()) { - this->render_batches.emplace_back(this->current_font, this->current_color); - this->is_dirty = false; - } - - this->render_batches.back().passes.emplace_back(x, y, text); -} - -void TextRenderer::render() { - // Sort the batches by font - std::sort(std::begin(this->render_batches), std::end(this->render_batches), - [](const text_render_batch &a, const text_render_batch &b) -> bool { - return a.font < b.font; - }); - - // Merge consecutive batches if font and color values are same - for (auto current_batch = std::begin(this->render_batches); current_batch != std::end(this->render_batches); ) { - auto next_batch = current_batch; - next_batch++; - if (next_batch != std::end(this->render_batches) && - current_batch->font == next_batch->font && - current_batch->color == next_batch->color) { - // Merge the render passes of current and next batches and remove the next batch - std::move(std::begin(next_batch->passes), - std::end(next_batch->passes), - std::back_inserter(current_batch->passes)); - this->render_batches.erase(next_batch); - } else { - current_batch++; - } - } - - size_t index = 0; - std::vector vertices; - std::vector indices; - std::vector render_tasks; - render_tasks.reserve(this->render_batches.size()); - unsigned int offset = 0; - - // Compute vertices and indices - for (auto &batch : this->render_batches) { - Font *font = batch.font; - - unsigned int num_elements = 0; - - for (auto &pass : batch.passes) { - auto x = static_cast(pass.x); - auto y = static_cast(pass.y); - - std::vector glyphs = font->get_glyphs(pass.text); - - // We will create 4 vertices & 6 indices for each glyph (GL_TRIANGLES) - vertices.resize(vertices.size() + glyphs.size() * 4); - indices.resize(indices.size() + glyphs.size() * 6); - - codepoint_t previous_glyph = 0; - for (codepoint_t glyph : glyphs) { - GlyphAtlas::Entry entry = this->glyph_atlas.get(font, glyph); - - float x0 = x + entry.glyph.x_offset; - float y0 = y + entry.glyph.y_offset - entry.glyph.height; - float x1 = x0 + entry.glyph.width; - float y1 = y0 + entry.glyph.height; - - vertices[index*4 + 0] = {x0, y0, entry.u0, entry.v0}; - vertices[index*4 + 1] = {x0, y1, entry.u0, entry.v1}; - vertices[index*4 + 2] = {x1, y1, entry.u1, entry.v1}; - vertices[index*4 + 3] = {x1, y0, entry.u1, entry.v0}; - - indices[index*6 + 0] = index*4 + 0; - indices[index*6 + 1] = index*4 + 1; - indices[index*6 + 2] = index*4 + 2; - indices[index*6 + 3] = index*4 + 2; - indices[index*6 + 4] = index*4 + 3; - indices[index*6 + 5] = index*4 + 0; - - // Advance the pen position - x += entry.glyph.x_advance; - y += entry.glyph.y_advance; - - // Handle font kerning - if (previous_glyph != 0) { - x += font->get_horizontal_kerning(previous_glyph, glyph); - } - - index++; - num_elements += 6; - previous_glyph = glyph; - } - } - - text_render_task render_task{GL_TRIANGLES, batch.color, num_elements, offset}; - render_tasks.push_back(render_task); - - offset += num_elements; - } - - // Upload vertices and indices - glBindBuffer(GL_ARRAY_BUFFER, this->vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ibo); - - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(text_render_vertex), &vertices[0], GL_STATIC_DRAW); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); - - texturefont_shader::program->use(); - - this->glyph_atlas.bind(0); - - glEnableVertexAttribArray(texturefont_shader::program->pos_id); - glEnableVertexAttribArray(texturefont_shader::tex_coord); - - glVertexAttribPointer(texturefont_shader::program->pos_id, 2, GL_FLOAT, GL_FALSE, - sizeof(text_render_vertex), (GLvoid *) offsetof(text_render_vertex, x)); - glVertexAttribPointer(texturefont_shader::tex_coord, 2, GL_FLOAT, GL_FALSE, - sizeof(text_render_vertex), (GLvoid *) offsetof(text_render_vertex, u)); - - for (auto &task : render_tasks) { - glUniform4f(texturefont_shader::color, - task.color.r/255.f, task.color.g/255.f, task.color.b/255.f, task.color.a/255.f); - glDrawElements(task.mode, task.num_elements, GL_UNSIGNED_INT, (GLvoid *) (task.offset * sizeof(unsigned int))); - } - - glDisableVertexAttribArray(texturefont_shader::program->pos_id); - glDisableVertexAttribArray(texturefont_shader::tex_coord); - - texturefont_shader::program->stopusing(); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // Clear the render batches for next frame - this->render_batches.clear(); -} - -}} // openage::renderer diff --git a/libopenage/renderer/text.h b/libopenage/renderer/text.h deleted file mode 100644 index 116cbe647a..0000000000 --- a/libopenage/renderer/text.h +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "../coord/pixel.h" -#include "../shader/program.h" -#include "color.h" -#include "font/glyph_atlas.h" - -namespace openage { - -namespace texturefont_shader { -extern shader::Program *program; -extern GLint texture, color, tex_coord; -} // openage::texturefont_shader - -namespace renderer { - -/** - * Can render text with OpenGL. - * - * TODO: move to the main renderer! - */ -class TextRenderer { - -public: - /** - * Requires a working OpenGL context to create buffer objects. - */ - TextRenderer(); - - virtual ~TextRenderer(); - - /** - * Set the font to be used for the future text draw calls. - * - * @param font: the font to be used. - */ - void set_font(Font *font); - - /** - * Set the color to be used for the future text draw calls. - * - * @param color: the color to be used. - */ - void set_color(const Color &color); - - /** - * Draw a formatted string at the specified position. - * - * @param position: where the text should be displayed. - * @param format: the text format - */ - void draw(coord::viewport position, const char *format, ...); - - /** - * Draw text at the specified position. - * - * @param position: where the text should be displayed. - * @param text: the text to be displayed. - */ - void draw(coord::viewport position, const std::string &text); - - /** - * Draw text at the specified position. - * - * @param x: the position in x-direction. - * @param y: the position in y-direction. - * @param text: the text to be displayed. - */ - void draw(int x, int y, const std::string &text); - - /** - * Render all the text draw requests made during the frame. - */ - void render(); - -private: - /** - * A single text draw request containing the text and position. - */ - struct text_render_batch_pass { - int x; - int y; - std::string text; - - text_render_batch_pass(int x, int y, const std::string &text) - : - x{x}, - y{y}, - text{text} { - } - }; - - /** - * The set of text draw requests with the same font and color. - */ - struct text_render_batch { - Font *font; - Color color; - std::vector passes; - - text_render_batch(Font *font, const Color &color) - : - font{font}, - color{color} { - } - }; - - Font *current_font; - Color current_color; - bool is_dirty; - std::vector render_batches; - - GlyphAtlas glyph_atlas; - - GLuint vbo; - GLuint ibo; -}; - -}} // openage::renderer diff --git a/libopenage/renderer/vulkan/render_target.h b/libopenage/renderer/vulkan/render_target.h index 49db9e5ef1..c7c3ab2bed 100644 --- a/libopenage/renderer/vulkan/render_target.h +++ b/libopenage/renderer/vulkan/render_target.h @@ -3,10 +3,14 @@ #pragma once #include +#include -#include "../renderer.h" +#include -#include "graphics_device.h" +#include "log/log.h" + +#include "renderer/renderer.h" +#include "renderer/vulkan/graphics_device.h" namespace openage { diff --git a/libopenage/renderer/vulkan/shader_program.h b/libopenage/renderer/vulkan/shader_program.h index e46030dd13..e1b2b7c0b2 100644 --- a/libopenage/renderer/vulkan/shader_program.h +++ b/libopenage/renderer/vulkan/shader_program.h @@ -1,12 +1,14 @@ -// Copyright 2017-2018 the openage authors. See copying.md for legal info. +// Copyright 2017-2023 the openage authors. See copying.md for legal info. #pragma once -#include "../../error/error.h" -#include "../../log/log.h" +#include "error/error.h" +#include "log/log.h" -#include "../resources/shader_source.h" -#include "../shader_program.h" +#include + +#include "renderer/resources/shader_source.h" +#include "renderer/shader_program.h" namespace openage { @@ -15,12 +17,18 @@ namespace vulkan { static VkShaderStageFlagBits vk_shader_stage(resources::shader_stage_t stage) { switch (stage) { - case resources::shader_stage_t::vertex: return VK_SHADER_STAGE_VERTEX_BIT; - case resources::shader_stage_t::geometry: return VK_SHADER_STAGE_GEOMETRY_BIT; - case resources::shader_stage_t::tesselation_control: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - case resources::shader_stage_t::tesselation_evaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - case resources::shader_stage_t::fragment: return VK_SHADER_STAGE_FRAGMENT_BIT; - default: throw Error(MSG(err) << "Unknown shader stage."); + case resources::shader_stage_t::vertex: + return VK_SHADER_STAGE_VERTEX_BIT; + case resources::shader_stage_t::geometry: + return VK_SHADER_STAGE_GEOMETRY_BIT; + case resources::shader_stage_t::tesselation_control: + return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + case resources::shader_stage_t::tesselation_evaluation: + return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + case resources::shader_stage_t::fragment: + return VK_SHADER_STAGE_FRAGMENT_BIT; + default: + throw Error(MSG(err) << "Unknown shader stage."); } } @@ -29,11 +37,11 @@ class VlkShaderProgram /* final : public ShaderProgram */ { std::vector modules; std::vector pipeline_stage_infos; - explicit VlkShaderProgram(VkDevice dev, std::vector const& srcs) { + explicit VlkShaderProgram(VkDevice dev, std::vector const &srcs) { // TODO reflect with spirv-cross // TODO if glsl, compile to spirv with libshaderc - for (auto const& src : srcs) { + for (auto const &src : srcs) { if (src.get_lang() != resources::shader_lang_t::spirv) { throw Error(MSG(err) << "Unsupported shader language in Vulkan shader."); } @@ -41,7 +49,7 @@ class VlkShaderProgram /* final : public ShaderProgram */ { VkShaderModuleCreateInfo cr_shdr = {}; cr_shdr.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; cr_shdr.codeSize = src.get_source().size(); - cr_shdr.pCode = reinterpret_cast(src.get_source().data()); + cr_shdr.pCode = reinterpret_cast(src.get_source().data()); VkShaderModule mod; VK_CALL_CHECKED(vkCreateShaderModule, dev, &cr_shdr, nullptr, &mod); @@ -61,4 +69,6 @@ class VlkShaderProgram /* final : public ShaderProgram */ { } }; -}}} // openage::renderer::vulkan +} // namespace vulkan +} // namespace renderer +} // namespace openage diff --git a/libopenage/rng/global_rng.h b/libopenage/rng/global_rng.h index 8ed475ae22..9fbe0f3f47 100644 --- a/libopenage/rng/global_rng.h +++ b/libopenage/rng/global_rng.h @@ -1,6 +1,10 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. +// Copyright 2015-2023 the openage authors. See copying.md for legal info. + #pragma once +#include + + /** @file * This file contains functions for the global random number generator. * diff --git a/libopenage/screenshot.cpp b/libopenage/screenshot.cpp deleted file mode 100644 index dfb3d2d5e1..0000000000 --- a/libopenage/screenshot.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. - -#include "screenshot.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "coord/pixel.h" -#include "job/job_manager.h" -#include "log/log.h" -#include "util/strings.h" - -namespace openage { - - -ScreenshotManager::ScreenshotManager(job::JobManager *job_mgr) - : - count{0}, - job_manager{job_mgr} { -} - - -ScreenshotManager::~ScreenshotManager() {} - - -std::string ScreenshotManager::gen_next_filename() { - - std::time_t t = std::time(NULL); - - if (t == this->last_time) { - this->count++; - } else { - this->count = 0; - this->last_time = t; - } - - // these two values (32) *must* be the same for safety reasons - char timestamp[32]; - std::strftime(timestamp, 32, "%Y-%m-%d_%H-%M-%S", std::localtime(&t)); - - return util::sformat("/tmp/openage_%s_%02d.png", timestamp, this->count); -} - - -void ScreenshotManager::save_screenshot(coord::viewport_delta size) { - coord::pixel_t width = size.x, - height = size.y; - - std::shared_ptr pxdata(new uint8_t[4*width*height], std::default_delete()); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pxdata.get()); - - auto encode_function = [this, pxdata, size] () { - return this->encode_png(pxdata, size); - }; - this->job_manager->enqueue(encode_function); -} - - -bool ScreenshotManager::encode_png(std::shared_ptr pxdata, - coord::viewport_delta size) { - std::FILE *fout = NULL; - coord::pixel_t width = size.x, - height = size.y; - auto warn_fn = [] (png_structp /*png_ptr*/, png_const_charp message) { - log::log(MSG(err) << "Creating screenshot failed: libpng error: " << message); - }; - auto err_fn = [] (png_structp png_ptr, png_const_charp message) { - log::log(MSG(err) << "Creating screenshot failed: libpng error: " << message); - longjmp(png_jmpbuf(png_ptr), 1); - }; - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - (png_voidp) NULL, - err_fn, warn_fn); - if (!png_ptr) - return false; - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - return false; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - std::fclose(fout); - png_destroy_write_struct(&png_ptr, &info_ptr); - return false; - } - - std::string filename = this->gen_next_filename(); - fout = std::fopen(filename.c_str(), "wb"); - if (fout == NULL) { - png_destroy_write_struct(&png_ptr, &info_ptr); - log::log(MSG(err) << "Could not open '"<< filename << "': " - << std::string(strerror(errno))); - return false; - } - - png_init_io(png_ptr, fout); - - png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - // Put image row pointer into info_ptr so that we can use the high-level - // write interface. - std::vector row_ptrs; - - // Invert rows. - row_ptrs.reserve(height); - for (int i = 1; i <= height; i++) { - row_ptrs.push_back(pxdata.get() + (height - i) * 4 * width); - } - png_set_rows(png_ptr, info_ptr, &row_ptrs[0]); - - //TODO: print ingame message. - log::log(MSG(info) << "Saving screenshot to '" << filename << "'."); - - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_FILLER_AFTER, NULL); - - std::fclose(fout); - png_destroy_write_struct(&png_ptr, &info_ptr); - return true; -} - -} // openage diff --git a/libopenage/screenshot.h b/libopenage/screenshot.h deleted file mode 100644 index 221f0b43ab..0000000000 --- a/libopenage/screenshot.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "coord/pixel.h" - -namespace openage { - -namespace job { -class JobManager; -} - -/** - * Takes screenshots, duh. - * - * TODO: move into renderer! - */ -class ScreenshotManager { -public: - /** - * Initializes the screenshot manager with the given job manager. - */ - ScreenshotManager(job::JobManager* job_mgr); - - ~ScreenshotManager(); - - /** To be called to save a screenshot. */ - void save_screenshot(coord::viewport_delta size); - - /** To be called by the job manager. Returns true on success, false otherwise. */ - bool encode_png(std::shared_ptr pxdata, - coord::viewport_delta size); - - /** size of the game window, in coord_sdl */ - coord::viewport_delta window_size; - -private: - - /** to be called to get the next screenshot filename into the array */ - std::string gen_next_filename(); - - /** contains the number to be in the next screenshot filename */ - unsigned count; - - /** contains the last time when a screenshot was taken */ - std::time_t last_time; - - /** the job manager this screenshot manager uses */ - job::JobManager *job_manager; -}; - -} // openage diff --git a/libopenage/shader/CMakeLists.txt b/libopenage/shader/CMakeLists.txt deleted file mode 100644 index 6477fa9fc7..0000000000 --- a/libopenage/shader/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_sources(libopenage - program.cpp - shader.cpp -) diff --git a/libopenage/shader/program.cpp b/libopenage/shader/program.cpp deleted file mode 100644 index 479d91a6ae..0000000000 --- a/libopenage/shader/program.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#include "program.h" - -#include -#include -#include - -#include "../error/error.h" -#include "../log/log.h" -#include "../util/compiler.h" -#include "../util/file.h" -#include "../util/strings.h" - -#include "shader.h" - -namespace openage::shader { - -Program::Program() : is_linked(false), vert(nullptr), frag(nullptr), geom(nullptr) { - this->id = glCreateProgram(); -} - -Program::Program(Shader *s0, Shader *s1) : Program{} { - this->attach_shader(s0); - this->attach_shader(s1); -} - -Program::~Program() { - glDeleteProgram(this->id); -} - -void Program::attach_shader(Shader *s) { - switch (s->type) { - case GL_VERTEX_SHADER: - this->vert = s; - break; - case GL_FRAGMENT_SHADER: - this->frag = s; - break; - case GL_GEOMETRY_SHADER: - this->geom = s; - break; - } - glAttachShader(this->id, s->id); -} - -void Program::link() { - glLinkProgram(this->id); - this->check(GL_LINK_STATUS); - glValidateProgram(this->id); - this->check(GL_VALIDATE_STATUS); - this->is_linked = true; - this->post_link_hook(); - - if (this->vert != nullptr) { - glDetachShader(this->id, this->vert->id); - } - if (this->frag != nullptr) { - glDetachShader(this->id, this->frag->id); - } - if (this->geom != nullptr) { - glDetachShader(this->id, this->geom->id); - } -} - -/** - * checks a given status for this program. - * - * @param what_to_check GL_LINK_STATUS GL_VALIDATE_STATUS GL_COMPILE_STATUS - */ -void Program::check(GLenum what_to_check) { - GLint status; - glGetProgramiv(this->id, what_to_check, &status); - - if (status != GL_TRUE) { - GLint loglen; - glGetProgramiv(this->id, GL_INFO_LOG_LENGTH, &loglen); - char *infolog = new char[loglen]; - glGetProgramInfoLog(this->id, loglen, nullptr, infolog); - - const char *what_str; - switch(what_to_check) { - case GL_LINK_STATUS: - what_str = "linking"; - break; - case GL_VALIDATE_STATUS: - what_str = "validation"; - break; - case GL_COMPILE_STATUS: - what_str = "compiliation"; - break; - default: - what_str = ""; - break; - } - - auto errormsg = MSG(err); - errormsg << "Program " << what_str << " failed\n" << infolog; - delete[] infolog; - - throw Error(errormsg); - } -} - -void Program::use() { - glUseProgram(this->id); -} - -void Program::stopusing() { - glUseProgram(static_cast(0)); -} - -GLint Program::get_uniform_id(const char *name) { - return glGetUniformLocation(this->id, name); -} - -GLint Program::get_attribute_id(const char *name) { - if (!this->is_linked) [[unlikely]] { - throw Error(MSG(err) << - "Attribute " << name << - " was queried before program was linked!"); - } - - GLint aid = glGetAttribLocation(this->id, name); - - if (aid == -1) [[unlikely]] { - this->dump_active_attributes(); - throw Error(MSG(err) << - "Attribute " << name << " queried but not found or active" - " (pwnt by the compiler)."); - } - - return aid; -} - -void Program::set_attribute_id(const char *name, GLuint id) { - if (!this->is_linked) { - glBindAttribLocation(this->id, id, name); - } - else { - //TODO: maybe enable overwriting, but after that relink the program - throw Error(MSG(err) << "assigned attribute " << name << " = " << id - << " after program was linked!"); - } -} - -void Program::dump_active_attributes() { - auto msg = MSG(warn); - msg << "Dumping shader program active attribute list:"; - - GLint num_attribs; - glGetProgramiv(this->id, GL_ACTIVE_ATTRIBUTES, &num_attribs); - - GLint attrib_max_length; - glGetProgramiv(this->id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length); - - for (int i = 0; i < num_attribs; i++) { - GLsizei attrib_length; - GLint attrib_size; - GLenum attrib_type; - char *attrib_name = new char[attrib_max_length]; - glGetActiveAttrib(this->id, i, attrib_max_length, &attrib_length, - &attrib_size, &attrib_type, attrib_name); - - msg << "\n" << - "-> attribute " << attrib_name << ": " - " : type=" << attrib_type << ", size=" << attrib_size; - delete[] attrib_name; - } -} - - -void Program::post_link_hook() { - this->pos_id = this->get_attribute_id("vertex_position"); - this->mvpm_id = this->get_uniform_id("mvp_matrix"); -} - -} // openage::shader diff --git a/libopenage/shader/program.h b/libopenage/shader/program.h deleted file mode 100644 index c6848d68be..0000000000 --- a/libopenage/shader/program.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -namespace openage { -namespace shader { - -class Shader; - -class Program { -public: - GLuint id; - GLint pos_id, mvpm_id; - - Program(); - Program(Shader *s0, Shader *s1); - ~Program(); - - void attach_shader(Shader *s); - - void link(); - - void use(); - void stopusing(); - - GLint get_uniform_id(const char *name); - GLint get_attribute_id(const char *name); - - void set_attribute_id(const char *name, GLuint id); - - void dump_active_attributes(); - -private: - bool is_linked; - Shader *vert, *frag, *geom; - - void check(GLenum what_to_check); - GLint get_info(GLenum pname); - char *get_log(); - void post_link_hook(); -}; - - -}} // openage::shader diff --git a/libopenage/shader/shader.cpp b/libopenage/shader/shader.cpp deleted file mode 100644 index f9a7c555db..0000000000 --- a/libopenage/shader/shader.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2013-2019 the openage authors. See copying.md for legal info. - -#include "shader.h" - -#include -#include - -#include "../error/error.h" -#include "../log/log.h" -#include "../util/file.h" -#include "../util/strings.h" - -namespace openage::shader { - -const char *type_to_string(GLenum type) { - switch (type) { - case GL_VERTEX_SHADER: - return "vertex"; - case GL_FRAGMENT_SHADER: - return "fragment"; - case GL_GEOMETRY_SHADER: - return "geometry"; - default: - return "unknown"; - } -} - -Shader::Shader(GLenum type, std::initializer_list sources) { - //create shader - this->id = glCreateShader(type); - - //store type - this->type = type; - - //load shader source - std::vector x = std::vector(sources); - glShaderSource(this->id, x.size(), x.data(), nullptr); - - //compile shader source - glCompileShader(this->id); - - //check compiliation result - GLint status; - glGetShaderiv(this->id, GL_COMPILE_STATUS, &status); - - if (status != GL_TRUE) { - GLint loglen; - glGetShaderiv(this->id, GL_INFO_LOG_LENGTH, &loglen); - - auto infolog = std::make_unique(loglen); - glGetShaderInfoLog(this->id, loglen, nullptr, infolog.get()); - - auto errmsg = MSG(err); - errmsg << "Failed to compile " << type_to_string(type) << " shader\n" << infolog; - - glDeleteShader(this->id); - - throw Error(errmsg); - } -} - -Shader::~Shader() { - glDeleteShader(this->id); -} - -} // openage::shader diff --git a/libopenage/shader/shader.h b/libopenage/shader/shader.h deleted file mode 100644 index a8a263e6b9..0000000000 --- a/libopenage/shader/shader.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include - -namespace openage { -namespace shader { - -const char *type_to_string(GLenum type); - -class Shader { -public: - Shader(GLenum type, std::initializer_list sources); - ~Shader(); - - GLuint id; - GLenum type; -}; - -}} // openage::shader diff --git a/libopenage/terrain/CMakeLists.txt b/libopenage/terrain/CMakeLists.txt deleted file mode 100644 index 2dbe9a39cc..0000000000 --- a/libopenage/terrain/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_sources(libopenage - terrain.cpp - terrain_chunk.cpp - terrain_object.cpp - terrain_outline.cpp - terrain_search.cpp -) diff --git a/libopenage/terrain/terrain.cpp b/libopenage/terrain/terrain.cpp deleted file mode 100644 index a360878984..0000000000 --- a/libopenage/terrain/terrain.cpp +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#include "terrain.h" - -#include -#include -#include -#include - -#include "../coord/chunk.h" -#include "../coord/pixel.h" -#include "../coord/tile.h" -#include "../error/error.h" -#include "../legacy_engine.h" -#include "../log/log.h" -#include "../util/misc.h" -#include "../util/strings.h" - -#include "terrain_chunk.h" -#include "terrain_object.h" - -namespace openage { - -TileContent::TileContent() : - terrain_id{0} { -} - -TileContent::~TileContent() = default; - -Terrain::Terrain(terrain_meta *meta, bool is_infinite) : - infinite{is_infinite}, - meta{meta} { - // TODO: - //this->limit_positive = - //this->limit_negative = - - // maps chunk position to chunks - this->chunks = std::unordered_map{}; -} - -Terrain::~Terrain() { - log::log(MSG(dbg) << "Cleanup terrain"); - - for (auto &chunk : this->chunks) { - // this chunk was autogenerated, so clean it up - if (chunk.second->manually_created == false) { - delete chunk.second; - } - } -} - -std::vector Terrain::used_chunks() const { - std::vector result; - for (auto &c : chunks) { - result.push_back(c.first); - } - return result; -} - -bool Terrain::fill(const int *data, const coord::tile_delta &size) { - bool was_cut = false; - - coord::tile pos = {0, 0}; - for (; pos.ne < size.ne; pos.ne++) { - for (pos.se = 0; pos.se < size.se; pos.se++) { - if (this->check_tile(pos) == tile_state::invalid) { - was_cut = true; - continue; - } - int terrain_id = data[pos.ne * size.ne + pos.se]; - TerrainChunk *chunk = this->get_create_chunk(pos); - chunk->get_data(pos)->terrain_id = terrain_id; - } - } - return was_cut; -} - -void Terrain::attach_chunk(TerrainChunk *new_chunk, - const coord::chunk &position, - bool manually_created) { - new_chunk->set_terrain(this); - new_chunk->manually_created = manually_created; - log::log(MSG(dbg) << "Inserting new chunk at (" << position.ne << "," << position.se << ")"); - this->chunks[position] = new_chunk; - - struct chunk_neighbors neigh = this->get_chunk_neighbors(position); - for (int i = 0; i < 8; i++) { - TerrainChunk *neighbor = neigh.neighbor[i]; - if (neighbor != nullptr) { - //set the new chunks neighbor to the neighbor chunk - new_chunk->neighbors.neighbor[i] = neighbor; - - //set the neighbors neighbor on the opposite direction - //to the new chunk - neighbor->neighbors.neighbor[(i + 4) % 8] = new_chunk; - - log::log(MSG(dbg) << "Neighbor " << i << " gets notified of new neighbor."); - } - else { - log::log(MSG(dbg) << "Neighbor " << i << " not found."); - } - } -} - -TerrainChunk *Terrain::get_chunk(const coord::chunk &position) { - auto iter = this->chunks.find(position); - - if (iter == this->chunks.end()) { - return nullptr; - } - else { - return iter->second; - } -} - -TerrainChunk *Terrain::get_chunk(const coord::tile &position) { - return this->get_chunk(position.to_chunk()); -} - -TerrainChunk *Terrain::get_create_chunk(const coord::chunk &position) { - TerrainChunk *res = this->get_chunk(position); - if (res == nullptr) { - res = new TerrainChunk(); - this->attach_chunk(res, position, false); - } - return res; -} - -TerrainChunk *Terrain::get_create_chunk(const coord::tile &position) { - return this->get_create_chunk(position.to_chunk()); -} - -TileContent *Terrain::get_data(const coord::tile &position) { - TerrainChunk *c = this->get_chunk(position.to_chunk()); - if (c == nullptr) { - return nullptr; - } - else { - return c->get_data(position.get_pos_on_chunk()); - } -} - -TerrainObject *Terrain::obj_at_point(const coord::phys3 &point) { - coord::tile t = point.to_tile(); - TileContent *tc = this->get_data(t); - if (!tc) { - return nullptr; - } - - // prioritise selecting the smallest object - TerrainObject *smallest = nullptr; - for (auto obj_ptr : tc->obj) { - if (obj_ptr->contains(point) && (!smallest || obj_ptr->min_axis() < smallest->min_axis())) { - smallest = obj_ptr; - } - } - return smallest; -} - -bool Terrain::validate_terrain(terrain_t terrain_id) { - if (terrain_id >= static_cast(this->meta->terrain_id_count)) { - throw Error(MSG(err) << "Requested terrain_id is out of range: " << terrain_id); - } - else { - return true; - } -} - -bool Terrain::validate_mask(ssize_t mask_id) { - if (mask_id >= static_cast(this->meta->blendmode_count)) { - throw Error(MSG(err) << "Requested mask_id is out of range: " << mask_id); - } - else { - return true; - } -} - -int Terrain::priority(terrain_t terrain_id) { - this->validate_terrain(terrain_id); - return this->meta->terrain_id_priority_map[terrain_id]; -} - -int Terrain::blendmode(terrain_t terrain_id) { - this->validate_terrain(terrain_id); - return this->meta->terrain_id_blendmode_map[terrain_id]; -} - -Texture *Terrain::texture(terrain_t terrain_id) { - this->validate_terrain(terrain_id); - return this->meta->textures[terrain_id]; -} - -Texture *Terrain::blending_mask(ssize_t mask_id) { - this->validate_mask(mask_id); - return this->meta->blending_masks[mask_id]; -} - -unsigned Terrain::get_subtexture_id(const coord::tile &pos, unsigned atlas_size) { - unsigned result = 0; - - result += util::mod(pos.se, atlas_size); - result *= atlas_size; - result += util::mod(pos.ne, atlas_size); - - return result; -} - -struct chunk_neighbors Terrain::get_chunk_neighbors(const coord::chunk &position) { - struct chunk_neighbors ret; - - for (int i = 0; i < 8; i++) { - coord::chunk tmp{ - position.ne + (coord::chunk_t)neigh_offsets[i].ne, - position.se + (coord::chunk_t)neigh_offsets[i].se}; - ret.neighbor[i] = this->get_chunk(tmp); - } - - return ret; -} - -int Terrain::get_blending_mode(terrain_t base_id, terrain_t neighbor_id) { - /* - * this function may require much more code, but this simple - * magnitude comparison seems to do the job. - * feel free to confirm or fix the behavior. - * - * my guess is that the blending mode encodes another information - * not publicly noticed yet: the overlay priority. - * the higher the blendmode id, the higher the mode priority. - * this may also be the reason why there are mask duplicates - * in blendomatic.dat - * - * funny enough, just using the modes in the dat file lead - * to a totally wrong render. the convert script reassigns the - * blending modes with a simple key=>val mapping, - * and after that, it looks perfect. - */ - - int base_mode = this->blendmode(base_id); - int neighbor_mode = this->blendmode(neighbor_id); - - if (neighbor_mode > base_mode) { - return neighbor_mode; - } - else { - return base_mode; - } -} - -tile_state Terrain::check_tile(const coord::tile &position) { - if (!this->check_tile_position(position)) { - return tile_state::invalid; - } - else { - TerrainChunk *chunk = this->get_chunk(position); - if (chunk == nullptr) { - return tile_state::creatable; - } - else { - return tile_state::existing; - } - } -} - -bool Terrain::check_tile_position(const coord::tile & /*pos*/) { - if (this->infinite) { - return true; - } - else { - throw Error(ERR << "non-infinite terrains are not supported yet"); - } -} - -void Terrain::draw(presenter::LegacyDisplay *display, RenderOptions *settings) { - // TODO: move this draw invokation to a render manager. - // it can reorder the draw instructions and minimize texture switching. - - // query the window coordinates from the display first - coord::viewport wbl = coord::viewport{0, 0}; - coord::viewport wbr = coord::viewport{display->coord.viewport_size.x, 0}; - coord::viewport wtl = coord::viewport{0, display->coord.viewport_size.y}; - coord::viewport wtr = coord::viewport{display->coord.viewport_size.x, display->coord.viewport_size.y}; - - // top left, bottom right tile coordinates - // that are currently visible in the window - // then convert them to tile coordinates. - coord::tile tl = wtl.to_tile(display->coord); - coord::tile tr = wtr.to_tile(display->coord); - coord::tile bl = wbl.to_tile(display->coord); - coord::tile br = wbr.to_tile(display->coord); - - // main terrain calculation call: get the `terrain_render_data` - auto draw_data = this->create_draw_advice(tl, tr, br, bl, true); - - // TODO: the following loop is totally inefficient and shit. - // it reloads the drawing texture to the gpu FOR EACH TILE! - // nevertheless, currently it works. - - // draw the terrain ground - for (auto &tile : draw_data.tiles) { - // iterate over all layers to be drawn - for (int i = 0; i < tile.count; i++) { - struct tile_data *layer = &tile.data[i]; - - // position, where the tile is drawn - coord::tile tile_pos = layer->pos; - - int mask_id = layer->mask_id; - Texture *texture = layer->tex; - int subtexture_id = layer->subtexture_id; - Texture *mask_texture = layer->mask_tex; - - texture->draw(display->coord, *this, tile_pos, ALPHAMASKED, subtexture_id, mask_texture, mask_id); - } - } - - // TODO: drawing buildings can't be the job of the terrain.. - // draw the buildings - for (auto &object : draw_data.objects) { - // object->draw(*display); - } -} - -struct terrain_render_data Terrain::create_draw_advice(const coord::tile &ab, - const coord::tile &cd, - const coord::tile &ef, - const coord::tile &gh, - bool blending_enabled) { - /* - * The passed parameters define the screen corners. - * - * ne, se coordinates - * o = screen corner, where the tile coordinates can be queried. - * x = corner of the rhombus that will be drawn, calculated by all o. - * - * cb - * x - * . . - * . . - * ab o===========o cd - * . = visible = . - * gb x = screen = x cf - * . = = . - * gh o===========o ef - * . . - * . . - * x - * gf - * - * The rendering area may be optimized further in the future, - * to exactly fit the visible screen. - * For now, we are drawing the big rhombus. - */ - - // procedure: find all the tiles to be drawn - // and store them to a tile drawing instruction structure - struct terrain_render_data data; - - // vector of tiles to be drawn - std::vector *tiles = &data.tiles; - - // ordered set of objects on the terrain (buildings.) - // it's ordered by the visibility layers. - auto objects = &data.objects; - - coord::tile gb = {gh.ne, ab.se}; - coord::tile cf = {cd.ne, ef.se}; - - // hint the vector about the number of tiles it will contain - size_t tiles_count = std::abs(cf.ne - gb.ne) * std::abs(cf.se - gb.se); - tiles->reserve(tiles_count); - - // sweep the whole rhombus area - for (coord::tile tilepos = gb; tilepos.ne <= cf.ne; tilepos.ne++) { - for (tilepos.se = gb.se; tilepos.se <= cf.se; tilepos.se++) { - // get the terrain tile drawing data - auto tile = this->create_tile_advice(tilepos, blending_enabled); - tiles->push_back(tile); - - // get the object standing on the tile - // TODO: make the terrain independent of objects standing on it. - TileContent *tile_content = this->get_data(tilepos); - if (tile_content != nullptr) { - for (auto obj_item : tile_content->obj) { - objects->insert(obj_item); - } - } - } - } - - return data; -} - - -struct tile_draw_data Terrain::create_tile_advice(coord::tile position, bool blending_enabled) { - // this struct will be filled with all tiles and overlays to draw. - struct tile_draw_data tile; - tile.count = 0; - - TileContent *base_tile_content = this->get_data(position); - - // chunk of this tile does not exist - if (base_tile_content == nullptr) { - return tile; - } - - struct tile_data base_tile_data; - - // the base terrain id of the tile - base_tile_data.terrain_id = base_tile_content->terrain_id; - - // the base terrain is not existant. - if (base_tile_data.terrain_id < 0) { - return tile; - } - - this->validate_terrain(base_tile_data.terrain_id); - - Texture *tex = this->texture(base_tile_data.terrain_id); - - base_tile_data.state = tile_state::existing; - base_tile_data.pos = position; - base_tile_data.priority = this->priority(base_tile_data.terrain_id); - base_tile_data.tex = tex; - base_tile_data.subtexture_id = this->get_subtexture_id( - position, - std::sqrt(tex->get_subtexture_count())); - base_tile_data.blend_mode = -1; - base_tile_data.mask_tex = nullptr; - base_tile_data.mask_id = -1; - - tile.data[tile.count] = base_tile_data; - tile.count += 1; - - // blendomatic!!111 - // see doc/media/blendomatic for the idea behind this. - if (blending_enabled) { - // the neighbors of the base tile - struct neighbor_tile neigh_data[8]; - - // get all neighbor tiles around position, reset the influence directions. - this->get_neighbors(position, neigh_data, this->meta->influences_buf.get()); - - // create influence list (direction, priority) - // strip and order influences, get the final influence data structure - struct influence_group influence_group = this->calculate_influences( - &base_tile_data, - neigh_data, - this->meta->influences_buf.get()); - - // create the draw_masks from the calculated influences - this->calculate_masks(position, &tile, &influence_group); - } - - return tile; -} - -void Terrain::get_neighbors(coord::tile basepos, - neighbor_tile *neigh_data, - influence *influences_by_terrain_id) { - // walk over all given neighbor tiles and store them to the influence list, - // group them by terrain id. - - for (int neigh_id = 0; neigh_id < 8; neigh_id++) { - // the current neighbor - auto neighbor = &neigh_data[neigh_id]; - - // calculate the pos of the neighbor tile - coord::tile neigh_pos = basepos + neigh_offsets[neigh_id]; - - // get the neighbor data - TileContent *neigh_content = this->get_data(neigh_pos); - - // chunk for neighbor or single tile is not existant - if (neigh_content == nullptr || neigh_content->terrain_id < 0) { - neighbor->state = tile_state::missing; - } - else { - neighbor->terrain_id = neigh_content->terrain_id; - neighbor->state = tile_state::existing; - neighbor->priority = this->priority(neighbor->terrain_id); - - // reset influence directions for this tile - influences_by_terrain_id[neighbor->terrain_id].direction = 0; - } - } -} - -struct influence_group Terrain::calculate_influences(struct tile_data *base_tile, - struct neighbor_tile *neigh_data, - struct influence *influences_by_terrain_id) { - // influences to actually draw (-> maximum 8) - struct influence_group influences {}; - influences.count = 0; - - // process adjacent neighbors first, - // then add diagonal influences, if no adjacent influence was found - constexpr int neigh_id_lookup[] = {1, 3, 5, 7, 0, 2, 4, 6}; - - for (int i = 0; i < 8; i++) { - // diagonal neighbors: (neigh_id % 2) == 0 - // adjacent neighbors: (neigh_id % 2) == 1 - - int neigh_id = neigh_id_lookup[i]; - bool is_adjacent_neighbor = neigh_id % 2 == 1; - bool is_diagonal_neighbor = not is_adjacent_neighbor; - - // the current neighbor_tile. - auto neighbor = &neigh_data[neigh_id]; - - // neighbor is nonexistant - if (neighbor->state == tile_state::missing) { - continue; - } - - // neighbor only interesting if it's a different terrain than the base. - // if it is the same id, the priorities are equal. - // neighbor draws over the base if it's priority is greater. - if (neighbor->priority > base_tile->priority) { - // get influence storage for the neighbor terrain id - // to group influences by id - auto influence = &influences_by_terrain_id[neighbor->terrain_id]; - - // check if diagonal influence is valid - if (is_diagonal_neighbor) { - // get the adjacent neighbors to the current diagonal - // influence - // (a & 0x07) == (a % 8) - uint8_t adj_neigh_0 = (neigh_id - 1) & 0x07; - uint8_t adj_neigh_1 = (neigh_id + 1) & 0x07; - - uint8_t neigh_mask = (1 << adj_neigh_0) | (1 << adj_neigh_1); - - // the adjacent neigbors are already influencing - // the current tile, therefore don't apply the diagonal mask - if ((influence->direction & neigh_mask) != 0) { - continue; - } - } - - // this terrain id hasn't had influence so far: - // add it to the list of influences. - if (influence->direction == 0) { - influences.terrain_ids[influences.count] = neighbor->terrain_id; - influences.count += 1; - } - - // as tile i has influence for this priority - // => bit i is set to 1 by 2^i - influence->direction |= 1 << neigh_id; - influence->priority = neighbor->priority; - influence->terrain_id = neighbor->terrain_id; - } - } - - // influences_by_terrain_id will be merged in the following, - // unused terrain ids will be dropped now. - - // shrink the big influence buffer that had entries for all terrains - // by copying the possible (max 8) influences to a separate buffer. - for (int k = 0; k < influences.count; k++) { - int relevant_id = influences.terrain_ids[k]; - influences.data[k] = influences_by_terrain_id[relevant_id]; - } - - // order the influences by their priority - for (int k = 1; k < influences.count; k++) { - struct influence tmp_influence = influences.data[k]; - - int l = k - 1; - while (l >= 0 && influences.data[l].priority > tmp_influence.priority) { - influences.data[l + 1] = influences.data[l]; - l -= 1; - } - - influences.data[l + 1] = tmp_influence; - } - - return influences; -} - - -void Terrain::calculate_masks(coord::tile position, - struct tile_draw_data *tile_data, - struct influence_group *influences) { - // influences are grouped by terrain id. - // the direction member has each bit set to 1 that is an influence from that direction. - // create a mask for this direction combination. - - // the base tile is stored at position 0 of the draw_mask - terrain_t base_terrain_id = tile_data->data[0].terrain_id; - - // iterate over all neighbors (with different terrain_ids) that have influence - for (ssize_t i = 0; i < influences->count; i++) { - // neighbor id of the current influence - char direction_bits = influences->data[i].direction; - - // all bits are 0 -> no influence directions stored. - // => no influence can be ignored. - if (direction_bits == 0) { - continue; - } - - terrain_t neighbor_terrain_id = influences->data[i].terrain_id; - int adjacent_mask_id = -1; - - /* neighbor ids: - 0 - 7 1 => 8 neighbors that can have influence on - 6 @ 2 the mask id selection. - 5 3 - 4 - */ - - // filter adjacent and diagonal influences neighbor_id: 76543210 - uint8_t direction_bits_adjacent = direction_bits & 0xAA; //0b10101010 - uint8_t direction_bits_diagonal = direction_bits & 0x55; //0b01010101 - - switch (direction_bits_adjacent) { - case 0x08: //0b00001000 - adjacent_mask_id = 0; //0..3 - break; - case 0x02: //0b00000010 - adjacent_mask_id = 4; //4..7 - break; - case 0x20: //0b00100000 - adjacent_mask_id = 8; //8..11 - break; - case 0x80: //0b10000000 - adjacent_mask_id = 12; //12..15 - break; - case 0x22: //0b00100010 - adjacent_mask_id = 20; - break; - case 0x88: //0b10001000 - adjacent_mask_id = 21; - break; - case 0xA0: //0b10100000 - adjacent_mask_id = 22; - break; - case 0x82: //0b10000010 - adjacent_mask_id = 23; - break; - case 0x28: //0b00101000 - adjacent_mask_id = 24; - break; - case 0x0A: //0b00001010 - adjacent_mask_id = 25; - break; - case 0x2A: //0b00101010 - adjacent_mask_id = 26; - break; - case 0xA8: //0b10101000 - adjacent_mask_id = 27; - break; - case 0xA2: //0b10100010 - adjacent_mask_id = 28; - break; - case 0x8A: //0b10001010 - adjacent_mask_id = 29; - break; - case 0xAA: //0b10101010 - adjacent_mask_id = 30; - break; - } - - // if it's the linear adjacent mask, cycle the 4 possible masks. - // e.g. long shorelines don't look the same then. - // maskid == 0x08 0x02 0x80 0x20 for that. - if (adjacent_mask_id <= 12 && adjacent_mask_id % 4 == 0) { - //we have 4 = 2^2 anti redundancy masks, so keep the last 2 bits - uint8_t anti_redundancy_offset = (position.ne + position.se) & 0x03; - adjacent_mask_id += anti_redundancy_offset; - } - - // get the blending mode (the mask selection) for this transition - // the mode is dependent on the two meeting terrain types - int blend_mode = this->get_blending_mode(base_terrain_id, neighbor_terrain_id); - - // append the mask for the adjacent blending - if (adjacent_mask_id >= 0) { - struct tile_data *overlay = &tile_data->data[tile_data->count]; - overlay->pos = position; - overlay->mask_id = adjacent_mask_id; - overlay->blend_mode = blend_mode; - overlay->terrain_id = neighbor_terrain_id; - overlay->tex = this->texture(neighbor_terrain_id); - overlay->subtexture_id = this->get_subtexture_id( - position, - std::sqrt(overlay->tex->get_subtexture_count())); - overlay->mask_tex = this->blending_mask(blend_mode); - overlay->state = tile_state::existing; - - tile_data->count += 1; - } - - // append the mask for the diagonal blending - if (direction_bits_diagonal > 0) { - for (int l = 0; l < 4; l++) { - // generate one mask for each influencing diagonal neighbor id. - // even if they all have the same terrain_id, - // because we don't have combined diagonal influence masks. - - // l == 0: pos = 0b000000001, mask = 18 - // l == 1: pos = 0b000000100, mask = 16 - // l == 2: pos = 0b000010000, mask = 17 - // l == 3: pos = 0b001000000, mask = 19 - - int current_direction_bit = 1 << (l * 2); - constexpr int diag_mask_id_map[4] = {18, 16, 17, 19}; - - if (direction_bits_diagonal & current_direction_bit) { - struct tile_data *overlay = &tile_data->data[tile_data->count]; - overlay->pos = position; - overlay->mask_id = diag_mask_id_map[l]; - overlay->blend_mode = blend_mode; - overlay->terrain_id = neighbor_terrain_id; - overlay->tex = this->texture(neighbor_terrain_id); - overlay->subtexture_id = this->get_subtexture_id( - position, - std::sqrt(overlay->tex->get_subtexture_count())); - overlay->mask_tex = this->blending_mask(blend_mode); - overlay->state = tile_state::existing; - - tile_data->count += 1; - } - } - } - } -} - -} // namespace openage diff --git a/libopenage/terrain/terrain.h b/libopenage/terrain/terrain.h deleted file mode 100644 index bb1d876843..0000000000 --- a/libopenage/terrain/terrain.h +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "../coord/chunk.h" -#include "../coord/phys.h" -#include "../coord/pixel.h" -#include "../coord/tile.h" -#include "../texture.h" -#include "../util/misc.h" -#include "assets/legacy_assetmanager.h" - -namespace openage { - -class LegacyEngine; -class RenderOptions; -class TerrainChunk; -class TerrainObject; - -/** - * type that for terrain ids. - * it's signed so that -1 can indicate a missing tile. - * TODO: get rid of the signedness. - */ -using terrain_t = int; - -/** - * hashing for chunk coordinates. - * - * this allows storage of chunk coords as keys in an unordered map. - */ -struct coord_chunk_hash { - size_t operator()(const coord::chunk &input) const { - constexpr int half_size_t_bits = sizeof(size_t) * 4; - - return ((size_t)input.ne << half_size_t_bits) | input.se; - } -}; - - -/** - * describes the properties of one terrain tile. - * - * this includes the terrain_id (ice, water, grass, ...) - * and the list of objects which have a bounding box overlapping the tile - */ -class TileContent { -public: - TileContent(); - ~TileContent(); - terrain_t terrain_id; - std::vector obj; -}; - - -/** - * coordinate offsets for getting tile neighbors by their id. - */ -constexpr coord::tile_delta const neigh_offsets[] = { - {1, -1}, - {1, 0}, - {1, 1}, - {0, 1}, - {-1, 1}, - {-1, 0}, - {-1, -1}, - {0, -1}}; - - -/** - * describes the state of a terrain tile. - */ -enum class tile_state { - missing, //!< tile is not created yet - existing, //!< tile is already existing - creatable, //!< tile does not exist but can be created - invalid, //!< tile does not exist and can not be created -}; - - -/** - * storage for influences by neighbor tiles. - */ -struct influence { - uint8_t direction; //!< bitmask for influence directions, bit 0 = neighbor 0, etc. - int priority; //!< the blending priority for this influence - terrain_t terrain_id; //!< the terrain id of the influence -}; - -/** - * influences for one tile. - * as a tile has 8 adjacent and diagonal neighbors, - * the maximum number of influences is 8. - */ -struct influence_group { - int count; - terrain_t terrain_ids[8]; - struct influence data[8]; -}; - -/** - * one influence on another tile. - */ -struct neighbor_tile { - terrain_t terrain_id; - tile_state state; - int priority; -}; - -/** - * storage data for a single terrain tile. - */ -struct tile_data { - terrain_t terrain_id; - coord::tile pos{0, 0}; - int subtexture_id; - Texture *tex; - int priority; - int mask_id; - int blend_mode; - Texture *mask_tex; - tile_state state; -}; - -/** - * collection of drawing data for a single tile. - * because of influences, a maximum of 8+1 draws - * could be requested. - */ -struct tile_draw_data { - ssize_t count; - struct tile_data data[9]; -}; - -/** - * the complete render instruction collection for the terrain. - * this is passed to the renderer and will be drawn on screen. - */ -struct terrain_render_data { - std::vector tiles; - std::set> objects; -}; - -/** - * specification for all available - * tile types and blending data - */ -struct terrain_meta { - size_t terrain_id_count; - size_t blendmode_count; - - std::vector textures; - std::vector blending_masks; - - std::unique_ptr terrain_id_priority_map; - std::unique_ptr terrain_id_blendmode_map; - - std::unique_ptr influences_buf; -}; - -/** - * the terrain class is the main top-management interface - * for dealing with cost-benefit analysis to maximize company profits. - * - * actually this is just the entrypoint and container for the terrain chunks. - */ -class Terrain { -public: - Terrain(terrain_meta *meta, bool is_infinite); - ~Terrain(); - - bool infinite; //!< chunks are automagically created as soon as they are referenced - - // TODO: finite terrain limits - // TODO: non-square shaped terrain bounds - - /** - * returns a list of all referenced chunks - */ - std::vector used_chunks() const; - - /** - * fill the terrain with given terrain_id values. - * @returns whether the data filled on the terrain was cut because of - * the terrains size limit. - */ - bool fill(const int *data, const coord::tile_delta &size); - - /** - * Attach a chunk to the terrain, to a given position. - * - * @param new_chunk The chunk to be attached - * @param position The chunk position where the chunk will be placed - * @param manually_created Was this chunk created manually? If true, it will not be free'd automatically - */ - void attach_chunk(TerrainChunk *new_chunk, const coord::chunk &position, bool manual = true); - - /** - * get a terrain chunk by a given chunk position. - * - * @return the chunk if exists, nullptr else - */ - TerrainChunk *get_chunk(const coord::chunk &position); - - /** - * get a terrain chunk by a given tile position. - * - * @return the chunk it exists, nullptr else - */ - TerrainChunk *get_chunk(const coord::tile &position); - - /** - * get or create a terrain chunk for a given chunk position. - * - * @return the (maybe newly created) chunk - */ - TerrainChunk *get_create_chunk(const coord::chunk &position); - - /** - * get or create a terrain chunk for a given tile position. - * - * @return the (maybe newly created) chunk - */ - TerrainChunk *get_create_chunk(const coord::tile &position); - - /** - * return tile data for the given position. - * - * the only reason the chunks exist, is because of this data. - */ - TileContent *get_data(const coord::tile &position); - - /** - * an object which contains the given point, null otherwise - */ - TerrainObject *obj_at_point(const coord::phys3 &point); - - /** - * get the neighbor chunks of a given chunk. - * - * - * chunk neighbor ids: - * 0 / <- ne - * 7 1 - * 6 @ 2 - * 5 3 - * 4 \ <- se - * - * ne se - * 0: 1 -1 - * 1: 1 0 - * 2: 1 1 - * 3: 0 1 - * 4: -1 1 - * 5: -1 0 - * 6: -1 -1 - * 7: 0 -1 - * - * @param position: the position of the center chunk. - */ - struct chunk_neighbors get_chunk_neighbors(const coord::chunk &position); - - /** - * return the subtexture offset id for a given tile position. - * the maximum offset is determined by the atlas size. - * - * this function returns always the right value, so that neighbor tiles - * of the same terrain (like grass-grass) are matching (without blendomatic). - * -> e.g. grass only map. - */ - unsigned get_subtexture_id(const coord::tile &pos, unsigned atlas_size); - - /** - * checks the creation state and premissions of a given tile position. - */ - tile_state check_tile(const coord::tile &position); - - /** - * checks whether the given tile position is allowed to exist on this terrain. - */ - // TODO: rename to is_tile_position_valid - bool check_tile_position(const coord::tile &position); - - /** - * validate whether the given terrain id is available. - */ - bool validate_terrain(terrain_t terrain_id); - - /** - * validate whether the given mask id is available. - */ - bool validate_mask(ssize_t mask_id); - - /** - * return the blending priority for a given terrain id. - */ - int priority(terrain_t terrain_id); - - /** - * return the blending mode/blendomatic mask set for a given terrain id. - */ - int blendmode(terrain_t terrain_id); - - /** - * get the terrain texture for a given terrain id. - */ - Texture *texture(terrain_t terrain_id); - - /** - * get the blendomatic mask with the given mask id. - */ - Texture *blending_mask(ssize_t mask_id); - - /** - * return the blending mode id for two given neighbor ids. - */ - int get_blending_mode(terrain_t base_id, terrain_t neighbor_id); - - /** - * draw the currently visible terrain area on screen. - * @param display: the display where the terrain should be drawn to. - */ - void draw(presenter::LegacyDisplay *display, RenderOptions *settings); - - /** - * create the drawing instruction data. - * - * created draw data according to the given tile boundaries. - * - * - * @param ab: upper left tile - * @param cd: upper right tile - * @param ef: lower right tile - * @param gh: lower left tile - * - * @returns a drawing instruction struct that contains all information for rendering - */ - struct terrain_render_data create_draw_advice(const coord::tile &ab, - const coord::tile &cd, - const coord::tile &ef, - const coord::tile &gh, - bool blending_enabled); - - /** - * create rendering and blending information for a single tile on the terrain. - */ - struct tile_draw_data create_tile_advice(coord::tile position, bool blending_enabled); - - /** - * gather neighbors of a given base tile. - * - * @param basepos: the base position, around which the neighbors will be fetched - * @param neigh_tiles: the destination buffer where the neighbors will be stored - * @param influences_by_terrain_id: influence buffer that is reset in the same step - */ - void get_neighbors(coord::tile basepos, - struct neighbor_tile *neigh_tiles, - struct influence *influences_by_terrain_id); - - /** - * look at neighbor tiles around the base_tile, and store the influence bits. - * - * @param base_tile: the base tile for which influences are calculated - * @param neigh_tiles: the neigbors of base_tile - * @param influences_by_terrain_id: influences will be stored to this buffer, as bitmasks - * @returns an influence group that describes the maximum 8 possible influences on the base_tile - */ - struct influence_group calculate_influences(struct tile_data *base_tile, - struct neighbor_tile *neigh_tiles, - struct influence *influences_by_terrain_id); - - /** - * calculate blending masks for a given tile position. - * - * @param position: the base tile position, for which the masks are calculated - * @param tile_data: the buffer where the created drawing layers will be stored in - * @param influences: the buffer where calculated influences were stored to - * - * @see calculate_influences - */ - void calculate_masks(coord::tile position, - struct tile_draw_data *tile_data, - struct influence_group *influences); - -private: - /** - * terrain meta data - */ - terrain_meta *meta; - - /** - * maps chunk coordinates to chunks. - */ - std::unordered_map chunks; -}; - -} // namespace openage diff --git a/libopenage/terrain/terrain_chunk.cpp b/libopenage/terrain/terrain_chunk.cpp deleted file mode 100644 index 46d877175e..0000000000 --- a/libopenage/terrain/terrain_chunk.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#include "terrain_chunk.h" - -#include - -#include "../coord/phys.h" -#include "../coord/pixel.h" -#include "../coord/tile.h" -#include "../error/error.h" -#include "../legacy_engine.h" -#include "../log/log.h" -#include "../texture.h" -#include "../util/misc.h" - -#include "terrain.h" -#include "terrain_object.h" - -namespace openage { - - -TerrainChunk::TerrainChunk() : - manually_created{true} { - this->tile_count = std::pow(chunk_size, 2); - - // the data array for this chunk. - // each element describes the tile data. - this->data = new TileContent[this->tile_count]; - - // initialize all neighbors as nonexistant - for (int i = 0; i < 8; i++) { - this->neighbors.neighbor[i] = nullptr; - } - - log::log(MSG(dbg) << "Terrain chunk created: " - << "size=" << chunk_size << ", " - << "tiles=" << this->tile_count); -} - - -TerrainChunk::~TerrainChunk() { - delete[] this->data; -} - -TileContent *TerrainChunk::get_data(coord::tile abspos) { - return this->get_data(abspos.get_pos_on_chunk()); -} - -TileContent *TerrainChunk::get_data(coord::tile_delta pos) { - return this->get_data(this->tile_position(pos)); -} - -TileContent *TerrainChunk::get_data(size_t pos) { - return &this->data[pos]; -} - -TileContent *TerrainChunk::get_data_neigh(coord::tile_delta pos) { - // determine the neighbor id by the given position - int neighbor_id = this->neighbor_id_by_pos(pos); - - // if the location is not on the current chunk, the neighbor id is != -1 - if (neighbor_id != -1) { - // get the chunk where the requested neighbor tile lies on. - TerrainChunk *neigh_chunk = this->neighbors.neighbor[neighbor_id]; - - // this neighbor does not exist, so the tile does not exist. - if (neigh_chunk == nullptr) { - return nullptr; - } - - // get position of tile on neighbor - size_t pos_on_neighbor = this->tile_position_neigh(pos); - - return neigh_chunk->get_data(pos_on_neighbor); - } - // the position lies on the current chunk. - else { - return this->get_data(pos); - } -} - -/* - * get the chunk neighbor id by a given position not lying on this chunk. - * - * neighbor ids: - * - * ne - * -- - * /| - * 0 - * 7 1 - * 6 @ 2 - * 5 3 - * 4 - * \| - * -- - * se - */ -int TerrainChunk::neighbor_id_by_pos(coord::tile_delta pos) { - int neigh_id = -1; - - if (pos.ne < 0) { - if (pos.se < 0) { - neigh_id = 6; - } - else if (pos.se >= (ssize_t)chunk_size) { - neigh_id = 4; - } - else { - neigh_id = 5; - } - } - else if (pos.ne >= (ssize_t)chunk_size) { - if (pos.se < 0) { - neigh_id = 0; - } - else if (pos.se >= (ssize_t)chunk_size) { - neigh_id = 2; - } - else { - neigh_id = 1; - } - } - else { - if (pos.se < 0) { - neigh_id = 7; - } - else if (pos.se >= (ssize_t)chunk_size) { - neigh_id = 3; - } - else { - neigh_id = -1; - } - } - return neigh_id; -} - -/* - * calculates the memory position of a given tile location. - * - * give this function isometric coordinates, it returns the tile index. - * - * # is a single terrain tile: - * - * 3 - * 2 # - * 1 # # - * ne= 0 # * # - * # # # # - * se= 0 # # # - * 1 # # - * 2 # - * 3 - * - * for example, * is at position (2, 1) - * the returned index would be 6 (count for each ne row, starting at se=0) - */ -size_t TerrainChunk::tile_position(coord::tile_delta pos) { - if (this->neighbor_id_by_pos(pos) != -1) { - throw Error(MSG(err) << "Tile " - "(" - << pos.ne << ", " << pos.se << ") " - "has been requested, but is not part of this chunk."); - } - - return pos.se * chunk_size + pos.ne; -} - -size_t TerrainChunk::tile_position_neigh(coord::tile_delta pos) { - // get position of tile on neighbor - pos.ne = util::mod(pos.ne); - pos.se = util::mod(pos.se); - - return pos.se * chunk_size + pos.ne; -} - -size_t TerrainChunk::get_tile_count() { - return this->tile_count; -} - -size_t TerrainChunk::get_size() { - return chunk_size; -} - -void TerrainChunk::set_terrain(Terrain *parent) { - this->terrain = parent; -} - -} // namespace openage diff --git a/libopenage/terrain/terrain_chunk.h b/libopenage/terrain/terrain_chunk.h deleted file mode 100644 index 0fd5cceecd..0000000000 --- a/libopenage/terrain/terrain_chunk.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2013-2018 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "../coord/pixel.h" -#include "../coord/tile.h" -#include "../texture.h" -#include "../util/file.h" - -namespace openage { - -class Terrain; -class TerrainChunk; -class TileContent; -class TerrainObject; - - -/** -the number of tiles per direction on a chunk -*/ -constexpr size_t chunk_size = 16; - -/** -adjacent neighbors of a chunk. - -neighbor ids: - 0 - 7 1 - 6 @ 2 - 5 3 - 4 -*/ -struct chunk_neighbors { - TerrainChunk *neighbor[8]; -}; - -/** -terrain chunk class represents one chunk of the the drawn terrain. -*/ -class TerrainChunk { -public: - TerrainChunk(); - ~TerrainChunk(); - - /** - * stores the length for one chunk side. - */ - size_t size; - - /** - * number of tiles on that chunk (this->size^2) - */ - size_t tile_count; - - /** - * stores the chunk data, one tile_content struct for each tile. - */ - TileContent *data; - - /** - * the terrain to which this chunk belongs to. - */ - Terrain *terrain; - - /** - * the 8 neighbors this chunk has. - */ - chunk_neighbors neighbors; - - /** - * draws the terrain chunk on screen. - * - * @param chunk_pos the chunk position where it will be drawn - */ - void draw(coord::chunk chunk_pos); - - /** - * get tile data by absolute coordinates. - */ - TileContent *get_data(coord::tile abspos); - - /** - * get tile data by coordinates that are releative to this chunk. - */ - TileContent *get_data(coord::tile_delta pos); - - /** - * get tile data by memory position. - */ - TileContent *get_data(size_t pos); - - /** - * get the tile data a given tile position relative to this chunk. - * - * also queries neighbors if the position is not on this chunk. - */ - TileContent *get_data_neigh(coord::tile_delta pos); - - int neighbor_id_by_pos(coord::tile_delta pos); - - size_t tile_position(coord::tile_delta pos); - size_t tile_position_neigh(coord::tile_delta pos); - size_t get_tile_count(); - - size_t tiles_in_row(unsigned int row); - size_t get_size(); - - void set_terrain(Terrain *parent); - - bool manually_created; -}; - -} // namespace openage diff --git a/libopenage/terrain/terrain_object.cpp b/libopenage/terrain/terrain_object.cpp deleted file mode 100644 index fdcf611ae3..0000000000 --- a/libopenage/terrain/terrain_object.cpp +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#include "terrain_object.h" - -#include -#include - -#include "../coord/phys.h" -#include "../coord/pixel.h" -#include "../coord/tile.h" -#include "../error/error.h" -#include "../legacy_engine.h" -#include "../texture.h" -#include "../unit/unit.h" - -#include "terrain.h" -#include "terrain_chunk.h" -#include "terrain_outline.h" - -namespace openage { - -TerrainObject::TerrainObject(Unit &u) : - unit(u), - passable{[](const coord::phys3 &) -> bool { return true; }}, - draw{[](const LegacyEngine & /*e*/) {}}, - state{object_state::removed}, - occupied_chunk_count{0}, - parent{nullptr} { -} - -TerrainObject::~TerrainObject() { - // remove all connections from terrain - this->unit.log(MSG(dbg) << "Cleanup terrain object"); - this->remove(); -} - -bool TerrainObject::is_floating() const { - // if parent is floating then all children also are - if (this->parent && this->parent->is_floating()) { - return true; - } - return this->state == object_state::floating; -} - -bool TerrainObject::is_placed() const { - // if object has a parent it must be placed - if (this->parent && !this->parent->is_placed()) { - return false; - } - return this->state == object_state::placed || this->state == object_state::placed_no_collision; -} - - -bool TerrainObject::check_collisions() const { - // if object has a parent it must be placed - if (this->parent && !this->parent->is_placed()) { - return false; - } - return this->state == object_state::placed; -} - -void TerrainObject::draw_outline(const coord::CoordManager &coord) const { - this->outline_texture->draw(coord, this->pos.draw); -} - -bool TerrainObject::place(object_state init_state) { - if (this->state == object_state::removed) { - throw Error(MSG(err) << "Building cannot change state with no position"); - } - - // remove any other floating objects - // which intersect with the new placement - // if non-floating objects are on the foundation - // then this placement will fail - for (coord::tile temp_pos : tile_list(this->pos)) { - std::vector to_remove; - TerrainChunk *chunk = this->get_terrain()->get_chunk(temp_pos); - - if (chunk == nullptr) { - continue; - } - - for (auto obj : chunk->get_data(temp_pos)->obj) { - // ignore self and annexes of self - if (obj != this && obj->get_parent() != this) { - if (obj->is_floating()) { - // floating objects get removed - to_remove.push_back(obj); - } - else if (obj->check_collisions()) { - // solid objects obstruct placement - return false; - } - } - } - - // all obstructing objects get deleted - for (auto remove_obj : to_remove) { - remove_obj->unit.location = nullptr; - } - } - - // set new state - this->state = init_state; - return true; -} - -bool TerrainObject::place(const std::shared_ptr &t, coord::phys3 &position, object_state init_state) { - if (this->state != object_state::removed) { - throw Error(MSG(err) << "This object has already been placed."); - } - else if (init_state == object_state::removed) { - throw Error(MSG(err) << "Cannot place an object with removed state."); - } - - // use passiblity test - if (not this->passable(position)) { - return false; - } - - // place on terrain - this->place_unchecked(t, position); - - // set state - this->state = init_state; - return true; -} - -bool TerrainObject::move(coord::phys3 &position) { - if (this->state == object_state::removed) { - return false; - } - auto old_state = this->state; - - // TODO should do outside of this function - bool can_move = this->passable(position); - if (can_move) { - this->remove(); - this->place_unchecked(this->get_terrain(), position); - this->state = old_state; - } - return can_move; -} - -void TerrainObject::remove() { - // remove all children first - for (auto &c : this->children) { - c->remove(); - } - this->children.clear(); - - if (this->occupied_chunk_count == 0 || this->state == object_state::removed) { - return; - } - - for (coord::tile temp_pos : tile_list(this->pos)) { - TerrainChunk *chunk = this->get_terrain()->get_chunk(temp_pos); - - if (chunk == nullptr) { - continue; - } - - auto &v = chunk->get_data(temp_pos.get_pos_on_chunk())->obj; - auto position_it = std::remove_if( - std::begin(v), - std::end(v), - [this](TerrainObject *obj) { - return this == obj; - }); - v.erase(position_it, std::end(v)); - } - - this->occupied_chunk_count = 0; - this->state = object_state::removed; -} - -void TerrainObject::set_ground(int id, int additional) { - if (not this->is_placed()) { - throw Error(MSG(err) << "Setting ground for object that is not placed yet."); - } - - coord::tile temp_pos = this->pos.start; - temp_pos.ne -= additional; - temp_pos.se -= additional; - while (temp_pos.ne < this->pos.end.ne + additional) { - while (temp_pos.se < this->pos.end.se + additional) { - TerrainChunk *chunk = this->get_terrain()->get_chunk(temp_pos); - - if (chunk == nullptr) { - continue; - } - - chunk->get_data(temp_pos.get_pos_on_chunk())->terrain_id = id; - temp_pos.se++; - } - temp_pos.se = this->pos.start.se - additional; - temp_pos.ne++; - } -} - -const TerrainObject *TerrainObject::get_parent() const { - return this->parent; -} - -std::vector TerrainObject::get_children() const { - // TODO: a better performing way of doing this - // for example accept a lambda to use for each element - // or maintain a duplicate class field for raw pointers - - std::vector result; - for (auto &obj : this->children) { - result.push_back(obj.get()); - } - return result; -} - -bool TerrainObject::operator<(const TerrainObject &other) { - if (this == &other) { - return false; - } - - auto this_ne = this->pos.draw.ne; - auto this_se = this->pos.draw.se; - auto other_ne = other.pos.draw.ne; - auto other_se = other.pos.draw.se; - - auto this_ypos = this_ne - this_se; - auto other_ypos = other_ne - other_se; - - if (this_ypos < other_ypos) { - return false; - } - else if (this_ypos == other_ypos) { - if (this_ne > other_ne) { - return false; - } - else if (this_ne == other_ne) { - return this_se > other_se; - } - } - - return true; -} - -void TerrainObject::place_unchecked(const std::shared_ptr &t, coord::phys3 &position) { - // storing the position: - this->pos = this->get_range(position, *t); - this->terrain = t; - this->occupied_chunk_count = 0; - - bool chunk_known = false; - - - // set pointers to this object on each terrain tile - // where the building will stand and block the ground - for (coord::tile temp_pos : tile_list(this->pos)) { - TerrainChunk *chunk = this->get_terrain()->get_chunk(temp_pos); - - if (chunk == nullptr) { - continue; - } - - for (int c = 0; c < this->occupied_chunk_count; c++) { - if (this->occupied_chunk[c] == chunk) { - chunk_known = true; - } - } - - if (not chunk_known) { - this->occupied_chunk[this->occupied_chunk_count] = chunk; - this->occupied_chunk_count += 1; - } - else { - chunk_known = false; - } - - chunk->get_data(temp_pos.get_pos_on_chunk())->obj.push_back(this); - } -} - -SquareObject::SquareObject(Unit &u, coord::tile_delta foundation_size) : - SquareObject(u, foundation_size, square_outline(foundation_size)) { -} - -SquareObject::SquareObject(Unit &u, coord::tile_delta foundation_size, std::shared_ptr out_tex) : - TerrainObject(u), - size(foundation_size) { - this->outline_texture = out_tex; -} - -SquareObject::~SquareObject() = default; - -tile_range SquareObject::get_range(const coord::phys3 &pos, const Terrain &terrain) const { - return building_center(pos, this->size, terrain); -} - -coord::phys_t SquareObject::from_edge(const coord::phys3 &point) const { - // clamp between start and end - coord::phys2 start_phys = this->pos.start.to_phys2(); - coord::phys2 end_phys = this->pos.end.to_phys2(); - - coord::phys_t cx = std::max(start_phys.ne, std::min(end_phys.ne, point.ne)); - coord::phys_t cy = std::max(start_phys.se, std::min(end_phys.se, point.se)); - - // distance to clamped point - coord::phys_t dx = point.ne - cx; - coord::phys_t dy = point.se - cy; - return std::hypot(dx, dy); -} - -coord::phys3 SquareObject::on_edge(const coord::phys3 &angle, coord::phys_t /* extra */) const { - // clamp between start and end - // TODO extra is unused - coord::phys2 start_phys = this->pos.start.to_phys2(); - coord::phys2 end_phys = this->pos.end.to_phys2(); - coord::phys_t cx = std::max(start_phys.ne, std::min(end_phys.ne, angle.ne)); - coord::phys_t cy = std::max(start_phys.se, std::min(end_phys.se, angle.se)); - - // todo use extra distance - return coord::phys3{cx, cy, 0}; -} - -bool SquareObject::contains(const coord::phys3 &other) const { - coord::tile other_tile = other.to_tile3().to_tile(); - - for (coord::tile check_pos : tile_list(this->pos)) { - if (check_pos == other_tile) { - return true; - } - } - return false; -} - -bool SquareObject::intersects(const TerrainObject &other, const coord::phys3 &position) const { - if (const auto *sq = dynamic_cast(&other)) { - auto terrain_ptr = this->terrain.lock(); - if (not terrain_ptr) { - throw Error{ERR << "object is not associated to a valid terrain"}; - } - - tile_range rng = this->get_range(position, *terrain_ptr); - return this->pos.end.ne < rng.start.ne - || rng.end.ne < sq->pos.start.ne - || rng.end.se < sq->pos.start.se - || rng.end.se < sq->pos.start.se; - } - else if (const auto *rad = dynamic_cast(&other)) { - auto terrain_ptr = this->terrain.lock(); - if (not terrain_ptr) { - throw Error{ERR << "object is not associated to a valid terrain"}; - } - // clamp between start and end - tile_range rng = this->get_range(position, *terrain_ptr); - coord::phys2 start_phys = rng.start.to_phys2(); - coord::phys2 end_phys = rng.end.to_phys2(); - coord::phys_t cx = std::max(start_phys.ne, std::min(end_phys.ne, rad->pos.draw.ne)); - coord::phys_t cy = std::max(start_phys.se, std::min(end_phys.se, rad->pos.draw.se)); - - // distance to square object base - coord::phys_t dx = rad->pos.draw.ne - cx; - coord::phys_t dy = rad->pos.draw.se - cy; - return std::hypot(dx, dy) < rad->phys_radius.to_double(); - } - return false; -} - -coord::phys_t SquareObject::min_axis() const { - return std::min(this->size.ne, this->size.se); -} - -RadialObject::RadialObject(Unit &u, float rad) : - RadialObject(u, rad, radial_outline(rad)) { -} - -RadialObject::RadialObject(Unit &u, float rad, std::shared_ptr out_tex) : - TerrainObject(u), - phys_radius(rad) { - this->outline_texture = out_tex; -} - -RadialObject::~RadialObject() = default; - -tile_range RadialObject::get_range(const coord::phys3 &pos, const Terrain & /*terrain*/) const { - tile_range result; - - // create bounds - coord::phys3 p_start = pos, p_end = pos; - p_start.ne -= this->phys_radius; - p_start.se -= this->phys_radius; - p_end.ne += this->phys_radius; - p_end.se += this->phys_radius; - - // set result - result.start = p_start.to_tile3().to_tile(); - result.end = p_end.to_tile3().to_tile() + coord::tile_delta{1, 1}; - result.draw = pos; - return result; -} - -coord::phys_t RadialObject::from_edge(const coord::phys3 &point) const { - return std::max( - coord::phys_t(point.to_phys2().distance(this->pos.draw.to_phys2())) - this->phys_radius, - static_cast(0)); -} - -coord::phys3 RadialObject::on_edge(const coord::phys3 &angle, coord::phys_t extra) const { - return this->pos.draw + (angle - this->pos.draw).to_phys2().normalize((this->phys_radius + extra).to_double()).to_phys3(); -} - -bool RadialObject::contains(const coord::phys3 &other) const { - return this->pos.draw.to_phys2().distance(other.to_phys2()) < this->phys_radius.to_double(); -} - -bool RadialObject::intersects(const TerrainObject &other, const coord::phys3 &position) const { - if (const auto *sq = dynamic_cast(&other)) { - return sq->from_edge(position) < this->phys_radius; - } - else if (const auto *rad = dynamic_cast(&other)) { - return position.to_phys2().distance(rad->pos.draw.to_phys2()) < (this->phys_radius + rad->phys_radius).to_double(); - } - return false; -} - -coord::phys_t RadialObject::min_axis() const { - return this->phys_radius * 2; -} - -std::vector tile_list(const tile_range &rng) { - std::vector tiles; - - coord::tile check_pos = rng.start; - while (check_pos.ne < rng.end.ne) { - while (check_pos.se < rng.end.se) { - tiles.push_back(check_pos); - check_pos.se += 1; - } - check_pos.se = rng.start.se; - check_pos.ne += 1; - } - - // a case when the objects radius is zero - if (tiles.empty()) { - tiles.push_back(rng.start); - } - return tiles; -} - -tile_range building_center(coord::phys3 west, coord::tile_delta size, const Terrain &terrain) { - tile_range result; - - // TODO it should be possible that the building is placed on any position, - // not just tile positions. - result.start = west.to_tile(); - result.end = result.start + size; - - coord::phys2 draw_pos = result.start.to_phys2(); - - draw_pos.ne += coord::phys_t(size.ne / 2.0f); - draw_pos.se += coord::phys_t(size.se / 2.0f); - - result.draw = draw_pos.to_phys3(terrain); - return result; -} - -bool complete_building(Unit &u) { - if (u.has_attribute(attr_type::building)) { - auto &build = u.get_attribute(); - build.completed = 1.0f; - - // set ground under a completed building - auto target_location = u.location.get(); - bool placed_ok = target_location->place(build.completion_state); - if (placed_ok) { - target_location->set_ground(build.foundation_terrain, 0); - } - return placed_ok; - } - return false; -} - -} // namespace openage diff --git a/libopenage/terrain/terrain_object.h b/libopenage/terrain/terrain_object.h deleted file mode 100644 index 4b6f76097b..0000000000 --- a/libopenage/terrain/terrain_object.h +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "../coord/phys.h" -#include "../coord/tile.h" - -namespace openage { - -class LegacyEngine; -class Terrain; -class TerrainChunk; -class Texture; -class Unit; - -/** - * only placed will enable collision checks - */ -enum class object_state { - removed, - floating, - placed, - placed_no_collision -}; - -/** - * A rectangle or square of tiles which is the minimim - * space to fit the units foundation or radius - * the end tile will have ne and se values greater or equal to - * the start tile - */ -struct tile_range { - coord::tile start{0, 0}; - coord::tile end{0, 0}; // start <= end - coord::phys3 draw{0, 0, 0}; // gets used as center point of radial objects -}; - -/** - * get all tiles in the tile range -- useful for iterating - * returns a flat list of tiles between the rectangle enclosed - * by the tile_range start and end tiles - */ -std::vector tile_list(const tile_range &rng); - -/** - * given the west most point of a building foundation and the tile_delta - * size of the foundation, this will return the tile range covered by the base, - * which includes start and end tiles, and phys3 center point (used for drawing) - */ -tile_range building_center(coord::phys3 west, coord::tile_delta size, const Terrain &terrain); - -/** - * sets a building to a fully completed state - */ -bool complete_building(Unit &); - -/** - * Base class for map location types which include square tile aligned - * positions and radial positions This enables two inheriting classes - * SquareObject and RadialObject to specify different areas of the map - * - * All TerrainObjects are owned by a Unit, to construct TerrainObjects, - * use the make_location function on any Unit - * - * This class allows intersection testing between two TerrainObjects to - * cover all cases of intersection (water, land or flying objects) the units - * lambda function is used which takes a tile and returns a bool value of - * whether that tile can be passed by this - * - * The name of this class is likely to change to TerrainBase or TerrainSpace - */ -class TerrainObject : public std::enable_shared_from_this { -public: - TerrainObject(Unit &u); - TerrainObject(const TerrainObject &) = delete; // disable copy constructor - TerrainObject(TerrainObject &&) = delete; // disable move constructor - virtual ~TerrainObject(); - - /** - * the range of tiles which are covered by this object - */ - tile_range pos; - - /* - * unit which is inside this base - * used to find the unit from user actions - * - * every terrain object should contain a single unit - */ - Unit &unit; - - /** - * is the object a floating outline -- it is only an indicator - * of where a building will be built, but not yet started building - * and does not affect any collisions - */ - bool is_floating() const; - - /** - * returns true if this object has been placed. this indicates that the object has a position and exists - * on the map, floating buildings are not considered placed as they are only an indicator - * for where something can begin construction - */ - bool is_placed() const; - - /** - * should this object be tested for collisions, which decides whether another object is allowed - * to overlap the location of this object. arrows and decaying objects will return false - */ - bool check_collisions() const; - - /** - * decide which terrains this object can be on - * this function should be true if given a valid position for the object - */ - std::function passable; - - /** - * specifies content to be drawn - */ - std::function draw; - - /** - * draws outline of this terrain space in current position - */ - void draw_outline(const coord::CoordManager &coord) const; - - /** - * changes the placement state of this object keeping the existing - * position. this is useful for upgrading a floating building to a placed state - */ - bool place(object_state init_state); - - /** - * binds the TerrainObject to a certain TerrainChunk. - * - * @param terrain: the terrain where the object will be placed onto. - * @param pos: (tile) position of the (nw,sw) corner - * @param init_state should be floating, placed or placed_no_collision - * @returns true when the object was placed, false when it did not fit at pos. - */ - bool place(const std::shared_ptr &t, coord::phys3 &pos, object_state init_state); - - /** - * moves the object -- returns false if object cannot be moved here - */ - bool move(coord::phys3 &pos); - - /** - * remove this TerrainObject from the terrain chunks. - */ - void remove(); - - /** - * sets all the ground below the object to a terrain id. - * - * @param id: the terrain id to which the ground is set - * @param additional: amount of additional space arround the building - */ - void set_ground(int id, int additional = 0); - - - /** - * appends new annex location for this object - * - * this does not replace any existing annex - */ - template - TerrainObject *make_annex(Arg... args) { - this->children.emplace_back(std::unique_ptr(new T(this->unit, args...))); - auto &annex_ptr = this->children.back(); - annex_ptr->parent = this; - return annex_ptr.get(); - } - - /** - * Returns the parent terrain object, - * if null the object has no parent which is - * the case for most objects - * - * objects with a parent are owned by that object - * and to be placed on the map the parent must also be placed - */ - const TerrainObject *get_parent() const; - - /** - * Returns a list of child objects, this is the inverse of the - * get_parent() function - * - * TODO: this does not perform optimally and is likely to change - */ - std::vector get_children() const; - - /* - * terrain this object was placed on - */ - std::shared_ptr get_terrain() const { - return terrain.lock(); - } - - /** - * comparison for TerrainObjects. - * - * sorting for vertical placement. - * by using this order algorithm, the overlapping order - * is optimal so the objects can be drawn in correct order. - */ - bool operator<(const TerrainObject &other); - - /** - * returns the range of tiles covered if the object was in the given pos - * @param pos the position to find a range for - */ - virtual tile_range get_range(const coord::phys3 &pos, const Terrain &terrain) const = 0; - - /** - * how far is a point from the edge of this object - */ - virtual coord::phys_t from_edge(const coord::phys3 &point) const = 0; - - /** - * get a position on the edge of this object - */ - virtual coord::phys3 on_edge(const coord::phys3 &angle, coord::phys_t extra = 0) const = 0; - - /** - * does this space contain a given point - */ - virtual bool contains(const coord::phys3 &other) const = 0; - - /** - * would this intersect with another object if it were positioned at the given point - */ - virtual bool intersects(const TerrainObject &other, const coord::phys3 &position) const = 0; - - /** - * the shortest line that can be placed across the objects center - */ - virtual coord::phys_t min_axis() const = 0; - -protected: - object_state state; - - std::weak_ptr terrain; - int occupied_chunk_count; - TerrainChunk *occupied_chunk[4]; - - /** - * annexes and grouped units - */ - TerrainObject *parent; - std::vector> children; - - /** - * texture for drawing outline - */ - std::shared_ptr outline_texture; - - /** - * placement function which does not check passibility - * used only when passibilty is already checked - * otherwise the place function should be used - * this does not modify the units placement state - */ - void place_unchecked(const std::shared_ptr &t, coord::phys3 &position); -}; - -/** - * terrain object class represents one immobile object on the map (building, trees, fish, ...). - * can only be constructed by unit->make_location(...) - */ -class SquareObject : public TerrainObject { -public: - virtual ~SquareObject(); - - - /** - * tile size of this objects base - */ - const coord::tile_delta size; - - /** - * calculate object start and end positions. - * - * @param pos: the center position of the building - * - * set the center position to "middle", - * start_pos is % and end_pos = & - * - * for a building, the # tile will be "the clicked one": - * @ @ @ - * @ @ @ @ %# & - * @ @ @ % # & @ - * % # @ & @ @ - * @ @ @ @ - * @ @ - * @ - */ - tile_range get_range(const coord::phys3 &pos, const Terrain &terrain) const override; - - coord::phys_t from_edge(const coord::phys3 &point) const override; - coord::phys3 on_edge(const coord::phys3 &angle, coord::phys_t extra = 0) const override; - bool contains(const coord::phys3 &other) const override; - bool intersects(const TerrainObject &other, const coord::phys3 &position) const override; - coord::phys_t min_axis() const override; - -private: - SquareObject(Unit &u, coord::tile_delta foundation_size); - SquareObject(Unit &u, coord::tile_delta foundation_size, std::shared_ptr out_tex); - - - friend class TerrainObject; - friend class Unit; -}; - -/** - * Represents circular shaped objects (movable game units) - * can only be constructed by unit->make_location(...) - */ -class RadialObject : public TerrainObject { -public: - virtual ~RadialObject(); - - /** - * radius of this cirular space - */ - const coord::phys_t phys_radius; - - /** - * finds the range covered if the object was in a position - */ - tile_range get_range(const coord::phys3 &pos, const Terrain &terrain) const override; - - coord::phys_t from_edge(const coord::phys3 &point) const override; - coord::phys3 on_edge(const coord::phys3 &angle, coord::phys_t extra = 0) const override; - bool contains(const coord::phys3 &other) const override; - bool intersects(const TerrainObject &other, const coord::phys3 &position) const override; - coord::phys_t min_axis() const override; - -private: - RadialObject(Unit &u, float rad); - RadialObject(Unit &u, float rad, std::shared_ptr out_tex); - - friend class TerrainObject; - friend class Unit; -}; - -} // namespace openage diff --git a/libopenage/terrain/terrain_outline.cpp b/libopenage/terrain/terrain_outline.cpp deleted file mode 100644 index 6c20fd5983..0000000000 --- a/libopenage/terrain/terrain_outline.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. - -#include -#include - -#include "../texture.h" -#include "terrain_outline.h" - -namespace openage { - -std::shared_ptr square_outline(coord::tile_delta foundation_size) { - int width = (foundation_size.ne + foundation_size.se) * 48; - int height = (foundation_size.ne + foundation_size.se) * 24; - - auto image_data = std::make_unique(width * height); - for (int i = 0; i < width; ++i) { - for (int j = 0; j < height; ++j) { - float w_percent = (float) abs(i - (width / 2)) / (float) (width / 2); - float h_percent = (float) abs(j - (height / 2)) / (float) (height / 2); - - // draw line where (w_percent + h_percent) == 1 - // line variable is in range 0.0 to 1.0 - float line = 1.0f - fabs(1.0f - fabs(h_percent + w_percent)); - unsigned char inten = 255 * pow(line, 16 * width/96); - image_data[i + j * width] = (inten << 24) | (inten << 16) | (inten << 8) | inten; - } - } - - return std::make_shared(width, height, std::move(image_data)); -} - -std::shared_ptr radial_outline(float radius) { - // additional pixels around the edge - int border = 4; - - // image size - int width = border + radius * 96 * 2; - int height = border + radius * 48 * 2; - int half_width = width / 2; - int half_height = height / 2; - - auto image_data = std::make_unique(width * height); - - for (int i = 0; i < width; ++i) { - for (int j = 0; j < height; ++j) { - float w_percent = (float) (border+i-half_width) / (float) (half_width-border); - float h_percent = (float) (border/2+j-half_height) / (float) (half_height-border/2); - - // line drawn where distance to image center == 1 - // line variable is in range 0.0 to 1.0 - float line = 1.0f - fabs(1.0f - std::hypot(w_percent, h_percent)); - unsigned char inten = 255 * pow(line, 32 * width/96); - image_data[i + j * width] = (inten << 24) | (inten << 16) | (inten << 8) | inten; - } - } - - return std::make_shared(width, height, std::move(image_data)); -} - -} // namespace openage diff --git a/libopenage/terrain/terrain_outline.h b/libopenage/terrain/terrain_outline.h deleted file mode 100644 index 8e66fadb6d..0000000000 --- a/libopenage/terrain/terrain_outline.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../coord/tile.h" - -namespace openage { - -class Texture; - -/** - * Generate a isometric square outline texture - */ -std::shared_ptr square_outline(coord::tile_delta foundation_size); - -/** - * Generate a isometric circle outline texture - */ -std::shared_ptr radial_outline(float radius); - -} // namespace openage diff --git a/libopenage/terrain/terrain_search.cpp b/libopenage/terrain/terrain_search.cpp deleted file mode 100644 index 7e3d0db22f..0000000000 --- a/libopenage/terrain/terrain_search.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include - -#include "terrain.h" -#include "terrain_object.h" -#include "terrain_search.h" - -namespace openage { - -TerrainObject *find_near(const TerrainObject &start, - std::function found, - unsigned int search_limit) { - - auto terrain = start.get_terrain(); - auto tile = start.pos.draw.to_tile3().to_tile(); - TerrainSearch search(terrain, tile); - - for (unsigned int i = 0; i < search_limit; ++i) { - for (auto o : terrain->get_data(tile)->obj) { - - // invalid pointers are removed when the object is deleted - if (found(*o)) { - return o; - } - } - tile = search.next_tile(); - } - - return nullptr; -} - -TerrainObject *find_in_radius(const TerrainObject &start, - std::function found, - float radius) { - auto terrain = start.get_terrain(); - coord::tile start_tile = start.pos.draw.to_tile3().to_tile(); - TerrainSearch search(terrain, start_tile, radius); - - // next_tile will first return the starting tile, so we need to run it once. We also - // shouldn't discard this tile - if it isn't useful, ignore it in found - coord::tile tile = search.next_tile(); - do { - for (auto o : terrain->get_data(tile)->obj) { - if (found(*o)) { - return o; - } - } - tile = search.next_tile(); - // coord::tile doesn't have a != operator, so we need to use !(a==b) - } while (!(tile == start_tile)); - - return nullptr; -} - -TerrainSearch::TerrainSearch(std::shared_ptr t, coord::tile s) - : - TerrainSearch(t, s, .0f) { -} - -TerrainSearch::TerrainSearch(std::shared_ptr t, coord::tile s, float radius) - : - terrain{t}, - start(s), - previous_radius{.0f}, - max_radius{radius} { -} - -coord::tile TerrainSearch::start_tile() const { - return this->start; -} - -void TerrainSearch::reset() { - std::queue empty; - std::swap(this->tiles, empty); - this->visited.clear(); - this->tiles.push(this->start); - this->visited.insert(this->start); -} - -coord::tile TerrainSearch::next_tile() { - // conditions for returning to the initial tile - if (this->tiles.empty() || - (this->max_radius && this->previous_radius > this->max_radius)) { - this->reset(); - } - coord::tile result = this->tiles.front(); - this->tiles.pop(); - - for (auto i = 0; i < 4; ++i) { - auto to_add = result + neigh_tile[i]; - - // check not visited and tile is within map - if (this->visited.count(to_add) == 0 && terrain->get_data(to_add)) { - this->visited.insert(to_add); - this->tiles.push(to_add); - } - } - - this->previous_radius = std::hypot(result.ne - start.ne, result.se - start.se); - return result; -} - -} // namespace openage diff --git a/libopenage/terrain/terrain_search.h b/libopenage/terrain/terrain_search.h deleted file mode 100644 index 3221db31d2..0000000000 --- a/libopenage/terrain/terrain_search.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include - -#include "../coord/tile.h" - -namespace openage { - -class Terrain; -class TerrainObject; - -TerrainObject *find_near(const TerrainObject &start, - std::function found, - unsigned int search_limit=500); -TerrainObject *find_in_radius(const TerrainObject &start, - std::function found, - float radius); - -constexpr coord::tile_delta const neigh_tile[] = { - {0, 1}, - {0, -1}, - {1, 0}, - {-1, 0} -}; - -/** - * searches outward from a point and returns nearby objects - * The state of the search is kept within the class, which allows - * a user to look at a limited number of tiles per update cycle - */ -class TerrainSearch { -public: - /** - * next_tile will cover all tiles on the map - */ - TerrainSearch(std::shared_ptr t, coord::tile s); - - /** - * next_tile will iterate over a range of tiles within a radius - */ - TerrainSearch(std::shared_ptr t, coord::tile s, float radius); - ~TerrainSearch() = default; - - /** - * the tile the search began on - */ - coord::tile start_tile() const; - - /** - * restarts the search from the start tile - */ - void reset(); - - /** - * returns all objects on the next tile - */ - coord::tile next_tile(); - -private: - const std::shared_ptr terrain; - const coord::tile start; - std::queue tiles; - std::unordered_set visited; - float previous_radius, max_radius; - -}; - -} // namespace openage diff --git a/libopenage/texture.cpp b/libopenage/texture.cpp deleted file mode 100644 index ec5ebf2202..0000000000 --- a/libopenage/texture.cpp +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright 2013-2019 the openage authors. See copying.md for legal info. - -#include "texture.h" - -#include -#include - -#include -#include - -#include "log/log.h" -#include "error/error.h" -#include "util/csv.h" -#include "coord/phys.h" - -namespace openage { - -// TODO: remove these global variables!!! -// definition of the shaders, -// they are "external" in the header. -namespace texture_shader { -shader::Program *program; -GLint texture, tex_coord; -} - -namespace teamcolor_shader { -shader::Program *program; -GLint texture, tex_coord; -GLint player_id_var, alpha_marker_var, player_color_var; -} - -namespace alphamask_shader { -shader::Program *program; -GLint base_texture, mask_texture, base_coord, mask_coord, show_mask; -} - -Texture::Texture(int width, int height, std::unique_ptr data) - : - use_metafile{false} { - ENSURE(glGenBuffers != nullptr, "gl not initialized properly"); - - this->w = width; - this->h = height; - this->buffer = std::make_unique(); - this->buffer->transferred = false; - this->buffer->texture_format_in = GL_RGBA8; - this->buffer->texture_format_out = GL_RGBA; - this->buffer->data = std::move(data); - this->subtextures.push_back({0, 0, this->w, this->h, this->w/2, this->h/2}); -} - -Texture::Texture(const util::Path &filename, bool use_metafile) - : - use_metafile{use_metafile}, - filename{filename} { - - // load the texture upon creation - this->load(); -} - -void Texture::load() { - // TODO: use libpng directly. - SDL_Surface *surface; - - // TODO: this will break if there is no native path. - // but then we need to load the image - // from the buffer provided by this->filename.open_r().read(). - - std::string native_path = this->filename.resolve_native_path(); - surface = IMG_Load(native_path.c_str()); - - if (!surface) { - throw Error( - MSG(err) << - "SDL_Image could not load texture from " - << this->filename << " (= " << native_path << "): " - << IMG_GetError() - ); - } else { - log::log(MSG(dbg) << "Texture has been loaded from " << native_path); - } - - this->buffer = std::make_unique(); - - // glTexImage2D format determination - switch (surface->format->BytesPerPixel) { - case 3: // RGB 24 bit - this->buffer->texture_format_in = GL_RGB8; - this->buffer->texture_format_out - = surface->format->Rmask == 0x000000ff - ? GL_RGB - : GL_BGR; - break; - case 4: // RGBA 32 bit - this->buffer->texture_format_in = GL_RGBA8; - this->buffer->texture_format_out - = surface->format->Rmask == 0x000000ff - ? GL_RGBA - : GL_BGRA; - break; - default: - throw Error(MSG(err) << - "Unknown texture bit depth for " << this->filename << ": " << - surface->format->BytesPerPixel << " bytes per pixel"); - - } - - this->w = surface->w; - this->h = surface->h; - - // temporary buffer for pixel data - this->buffer->transferred = false; - this->buffer->data = std::make_unique(this->w * this->h); - std::memcpy( - this->buffer->data.get(), - surface->pixels, - this->w * this->h * surface->format->BytesPerPixel - ); - SDL_FreeSurface(surface); - - if (use_metafile) { - // get subtexture information from the exported metainfo file - this->subtextures = util::read_csv_file( - filename.with_suffix(".docx") - ); - } - else { - // we don't have a subtexture description file. - // use the whole image as one texture then. - gamedata::subtexture s{0, 0, this->w, this->h, this->w/2, this->h/2}; - - this->subtextures.push_back(s); - } -} - -GLuint Texture::make_gl_texture(int iformat, int oformat, int w, int h, void *data) const { - // generate 1 texture handle - GLuint textureid; - glGenTextures(1, &textureid); - glBindTexture(GL_TEXTURE_2D, textureid); - - // sdl surface -> opengl texture - glTexImage2D( - GL_TEXTURE_2D, 0, - iformat, w, h, 0, - oformat, GL_UNSIGNED_BYTE, data - ); - - // settings for later drawing - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - return textureid; -} - -void Texture::load_in_glthread() const { - if (not this->buffer->transferred) { - this->buffer->id = this->make_gl_texture( - this->buffer->texture_format_in, - this->buffer->texture_format_out, - this->w, - this->h, - this->buffer->data.get() - ); - this->buffer->data = nullptr; - glGenBuffers(1, &this->buffer->vertbuf); - this->buffer->transferred = true; - } -} - - -void Texture::unload() { - glDeleteTextures(1, &this->buffer->id); - glDeleteBuffers(1, &this->buffer->vertbuf); -} - - -void Texture::reload() { - this->unload(); - this->load(); -} - - -Texture::~Texture() { - this->unload(); -} - - -void Texture::fix_hotspots(unsigned x, unsigned y) { - for (auto &subtexture : this->subtextures) { - subtexture.cx = x; - subtexture.cy = y; - } -} - - -void Texture::draw(const coord::CoordManager &mgr, const coord::camhud pos, - unsigned int mode, bool mirrored, - int subid, unsigned player) const { - this->draw(pos.to_viewport(mgr), mode, mirrored, subid, player, nullptr, -1); -} - - -void Texture::draw(const coord::CoordManager &mgr, coord::camgame pos, - unsigned int mode, bool mirrored, - int subid, unsigned player) const { - this->draw(pos.to_viewport(mgr), mode, mirrored, subid, player, nullptr, -1); -} - - -void Texture::draw(const coord::CoordManager &mgr, coord::phys3 pos, - unsigned int mode, bool mirrored, - int subid, unsigned player) const { - this->draw(pos.to_viewport(mgr), mode, mirrored, subid, player, nullptr, -1); -} - - -void Texture::draw(const coord::CoordManager &mgr, const Terrain &terrain, - coord::tile pos, unsigned int mode, int subid, - Texture *alpha_texture, int alpha_subid) const { - - // currently used for drawing terrain tiles. - this->draw(pos.to_viewport(mgr, terrain), mode, false, - subid, 0, alpha_texture, alpha_subid); -} - - -void Texture::draw(coord::viewport pos, - unsigned int mode, bool mirrored, - int subid, unsigned player, - Texture *alpha_texture, int alpha_subid) const { - - this->load_in_glthread(); - - glColor4f(1, 1, 1, 1); - - bool use_playercolors = false; - bool use_alphashader = false; - const gamedata::subtexture *mtx; - - int *pos_id, *texcoord_id, *masktexcoord_id; - - // is this texture drawn with an alpha mask? - if ((mode & ALPHAMASKED) && alpha_subid >= 0 && alpha_texture != nullptr) { - alphamask_shader::program->use(); - - // bind the alpha mask texture to slot 1 - glActiveTexture(GL_TEXTURE1); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, alpha_texture->get_texture_id()); - - // get the alphamask subtexture (the blend mask!) - mtx = alpha_texture->get_subtexture(alpha_subid); - pos_id = &alphamask_shader::program->pos_id; - texcoord_id = &alphamask_shader::base_coord; - masktexcoord_id = &alphamask_shader::mask_coord; - use_alphashader = true; - } - // is this texure drawn with replaced pixels for team coloring? - else if (mode & PLAYERCOLORED) { - teamcolor_shader::program->use(); - - //set the desired player id in the shader - glUniform1i(teamcolor_shader::player_id_var, player); - pos_id = &teamcolor_shader::program->pos_id; - texcoord_id = &teamcolor_shader::tex_coord; - use_playercolors = true; - } - // mkay, we just draw the plain texture otherwise. - else { - texture_shader::program->use(); - pos_id = &texture_shader::program->pos_id; - texcoord_id = &texture_shader::tex_coord; - } - - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, this->buffer->id); - - const gamedata::subtexture *tx = this->get_subtexture(subid); - - int left, right, top, bottom; - - // coordinates where the texture will be drawn on screen. - bottom = pos.y - (tx->h - tx->cy); - top = bottom + tx->h; - - if (not mirrored) { - left = pos.x - tx->cx; - right = left + tx->w; - } else { - left = pos.x + tx->cx; - right = left - tx->w; - } - - // convert the texture boundaries to float - // these will be the vertex coordinates. - float leftf, rightf, topf, bottomf; - leftf = (float) left; - rightf = (float) right; - topf = (float) top; - bottomf = (float) bottom; - - // subtexture coordinates - // left, right, top and bottom bounds as coordinates - // these pick the requested area out of the big texture. - float txl, txr, txt, txb; - this->get_subtexture_coordinates(tx, &txl, &txr, &txt, &txb); - - float mtxl=0, mtxr=0, mtxt=0, mtxb=0; - if (use_alphashader) { - alpha_texture->get_subtexture_coordinates(mtx, &mtxl, &mtxr, &mtxt, &mtxb); - } - - // this array will be uploaded to the GPU. - // it contains all dynamic vertex data (position, tex coordinates, mask coordinates) - float vdata[] { - leftf, topf, - leftf, bottomf, - rightf, bottomf, - rightf, topf, - txl, txt, - txl, txb, - txr, txb, - txr, txt, - mtxl, mtxt, - mtxl, mtxb, - mtxr, mtxb, - mtxr, mtxt - }; - - - // store vertex buffer data, TODO: prepare this sometime earlier. - glBindBuffer(GL_ARRAY_BUFFER, this->buffer->vertbuf); - glBufferData(GL_ARRAY_BUFFER, sizeof(vdata), vdata, GL_STREAM_DRAW); - - // enable vertex buffer and bind it to the vertex attribute - glEnableVertexAttribArray(*pos_id); - glEnableVertexAttribArray(*texcoord_id); - if (use_alphashader) { - glEnableVertexAttribArray(*masktexcoord_id); - } - - // set data types, offsets in the vdata array - glVertexAttribPointer(*pos_id, 2, GL_FLOAT, GL_FALSE, 0, (void *)(0)); - glVertexAttribPointer(*texcoord_id, 2, GL_FLOAT, GL_FALSE, 0, (void *)(sizeof(float) * 8)); - if (use_alphashader) { - glVertexAttribPointer(*masktexcoord_id, 2, GL_FLOAT, GL_FALSE, 0, (void *)(sizeof(float) * 8 * 2)); - } - - // draw the vertex array - glDrawArrays(GL_QUADS, 0, 4); - - - // unbind the current buffer - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDisableVertexAttribArray(*pos_id); - glDisableVertexAttribArray(*texcoord_id); - if (use_alphashader) { - glDisableVertexAttribArray(*masktexcoord_id); - } - - // disable the shaders. - if (use_playercolors) { - teamcolor_shader::program->stopusing(); - } else if (use_alphashader) { - alphamask_shader::program->stopusing(); - glActiveTexture(GL_TEXTURE1); - glDisable(GL_TEXTURE_2D); - } else { - texture_shader::program->stopusing(); - } - - glActiveTexture(GL_TEXTURE0); - glDisable(GL_TEXTURE_2D); - - //////////////////////////////////////// - /* - int size = 2; - float r = 1.0f, g = 1.0f, b = 0.0f; - glPushMatrix(); - glTranslatef(leftf, bottomf, 0); - glColor3f(r, g, b); - glBegin(GL_TRIANGLES); - glVertex3f(-size, -size, 0); - glVertex3f(-size, size, 0); - glVertex3f(size, size, 0); - glVertex3f(size, size, 0); - glVertex3f(-size, -size, 0); - glVertex3f(size, -size, 0); - glEnd(); - glPopMatrix(); - */ - //////////////////////////////////////// -} - - -const gamedata::subtexture *Texture::get_subtexture(uint64_t subid) const { - if (subid < this->subtextures.size()) { - return &this->subtextures[subid]; - } - else { - throw Error{ - ERR << "Unknown subtexture requested for texture " - << this->filename << ": " << subid - }; - } -} - - -void Texture::get_subtexture_coordinates(uint64_t subid, - float *txl, float *txr, - float *txt, float *txb) const { - const gamedata::subtexture *tx = this->get_subtexture(subid); - this->get_subtexture_coordinates(tx, txl, txr, txt, txb); -} - - -void Texture::get_subtexture_coordinates(const gamedata::subtexture *tx, - float *txl, float *txr, - float *txt, float *txb) const { - *txl = ((float)tx->x) /this->w; - *txr = ((float)(tx->x + tx->w)) /this->w; - *txt = ((float)tx->y) /this->h; - *txb = ((float)(tx->y + tx->h)) /this->h; -} - - -size_t Texture::get_subtexture_count() const { - return this->subtextures.size(); -} - - -void Texture::get_subtexture_size(uint64_t subid, int *w, int *h) const { - const gamedata::subtexture *subtex = this->get_subtexture(subid); - *w = subtex->w; - *h = subtex->h; -} - - -GLuint Texture::get_texture_id() const { - this->load_in_glthread(); - return this->buffer->id; -} - -} // openage diff --git a/libopenage/texture.h b/libopenage/texture.h deleted file mode 100644 index 5469fe11e3..0000000000 --- a/libopenage/texture.h +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "gamedata/texture_dummy.h" -#include "coord/pixel.h" -#include "coord/tile.h" -#include "shader/program.h" -#include "shader/shader.h" -#include "util/path.h" - - -namespace openage { -class Terrain; - -namespace util { -class Path; -} - -namespace coord { -class CoordManager; -} - -namespace texture_shader { -extern shader::Program *program; -extern GLint texture, tex_coord; -} // namespace texture_shader - -namespace teamcolor_shader { -extern shader::Program *program; -extern GLint texture, tex_coord; -extern GLint player_id_var, alpha_marker_var, player_color_var; -} // namespace teamcolor_shader - -namespace alphamask_shader { -extern shader::Program *program; -extern GLint base_texture, mask_texture, base_coord, mask_coord, show_mask; -} // namespace alphamask_shader - -// bitmasks for shader modes -constexpr int PLAYERCOLORED = 1 << 0; -constexpr int ALPHAMASKED = 1 << 1; - -/** - * enables transfer of data to opengl - */ -struct gl_texture_buffer { - GLuint id, vertbuf; - - // this requires loading on the main thread - bool transferred; - int texture_format_in; - int texture_format_out; - std::unique_ptr data; -}; - - -/** - * A texture for rendering graphically. - * - * You may believe it or not, but this class represents a single texture, - * which can be drawn on the screen. - * - * The class supports subtextures, so that one big texture can contain - * several small images. These are the ones actually to be rendered. - */ -class Texture { -public: - int w; - int h; - - /** - * Create a texture from a rgba8 array. - * It will have w * h * 32bit storage. - */ - Texture(int width, int height, std::unique_ptr data); - - /** - * Create a texture from a existing image file. - * For supported image file types, see the SDL_Image initialization in the engine. - */ - Texture(const util::Path &filename, bool use_metafile=false); - ~Texture(); - - /** - * Draws the texture at hud coordinates. - */ - void draw(const coord::CoordManager &mgr, coord::camhud pos, unsigned int mode=0, bool mirrored=false, int subid=0, unsigned player=0) const; - - /** - * Draws the texture at game coordinates. - */ - void draw(const coord::CoordManager &mgr, coord::camgame pos, unsigned int mode=0, bool mirrored=false, int subid=0, unsigned player=0) const; - - /** - * Draws the texture at phys coordinates. - */ - void draw(const coord::CoordManager &mgr, coord::phys3 pos, unsigned int mode=0, bool mirrored=false, int subid=0, unsigned player=0) const; - - /** - * Draws the texture at tile coordinates. - */ - void draw(const coord::CoordManager &mgr, const Terrain &terrain, coord::tile pos, unsigned int mode, int subid, Texture *alpha_texture, int alpha_subid) const; - - /** - * Draws the texture at window coordinates. - */ - void draw(coord::viewport pos, unsigned int mode, bool mirrored, int subid, unsigned player, Texture *alpha_texture, int alpha_subid) const; - - /** - * Reload the image file. Used for inotify refreshing. - */ - void reload(); - - /** - * Get the subtexture coordinates by its id. - */ - const gamedata::subtexture *get_subtexture(uint64_t subid) const; - - /** - * @return the number of available subtextures - */ - size_t get_subtexture_count() const; - - /** - * Fetch the size of the given subtexture. - * @param subid: index of the requested subtexture - * @param w: the subtexture width - * @param h: the subtexture height - */ - void get_subtexture_size(uint64_t subid, int *w, int *h) const; - - /** - * get atlas subtexture coordinates. - * - * left, right, top and bottom bounds as coordinates - * these pick the requested area out of the big texture. - * returned as floats in range 0.0 to 1.0 - */ - void get_subtexture_coordinates(uint64_t subid, float *txl, float *txr, float *txt, float *txb) const; - void get_subtexture_coordinates(const gamedata::subtexture *subtex, float *txl, float *txr, float *txt, float *txb) const; - - /** - * fixes the hotspots of all subtextures to (x,y). - * this is a temporary workaround; such fixes should actually be done in the - * convert script. - */ - void fix_hotspots(unsigned x, unsigned y); - - /** - * activates the influence of a given alpha mask to this texture. - */ - void activate_alphamask(Texture *mask, uint64_t subid); - - /** - * disable a previously activated alpha mask. - */ - void disable_alphamask(); - - /** - * returns the opengl texture id of this texture. - */ - GLuint get_texture_id() const; - -private: - std::unique_ptr buffer; - std::vector subtextures; - bool use_metafile; - - util::Path filename; - - void load(); - - /** - * The texture loadin must occur on the thread that manages the gl context. - */ - void load_in_glthread() const; - GLuint make_gl_texture(int iformat, int oformat, int w, int h, void *) const; - void unload(); - -}; - -} // namespace openage diff --git a/libopenage/unit/CMakeLists.txt b/libopenage/unit/CMakeLists.txt deleted file mode 100644 index 3c7a6e27cc..0000000000 --- a/libopenage/unit/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -add_sources(libopenage - ability.cpp - action.cpp - attribute.cpp - attributes.cpp - command.cpp - producer.cpp - research.cpp - selection.cpp - unit.cpp - unit_container.cpp - unit_texture.cpp - unit_type.cpp -) diff --git a/libopenage/unit/ability.cpp b/libopenage/unit/ability.cpp deleted file mode 100644 index 0ab1eef175..0000000000 --- a/libopenage/unit/ability.cpp +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright 2014-2021 the openage authors. See copying.md for legal info. - -#include - -#include "../terrain/terrain_object.h" -#include "../gamestate/old/cost.h" -#include "../gamestate/old/player.h" -#include "ability.h" -#include "action.h" -#include "command.h" -#include "research.h" -#include "unit.h" - -namespace openage { - -bool UnitAbility::has_hitpoints(Unit &target) { - return target.has_attribute(attr_type::damaged) && - target.get_attribute().hp > 0; -} - -bool UnitAbility::is_damaged(Unit &target) { - return target.has_attribute(attr_type::damaged) && target.has_attribute(attr_type::hitpoints) && - target.get_attribute().hp < target.get_attribute().hp; -} - -bool UnitAbility::has_resource(Unit &target) { - return target.has_attribute(attr_type::resource) && !target.has_attribute(attr_type::worker) && - target.get_attribute().amount > 0; -} - -bool UnitAbility::is_same_player(Unit &to_modify, Unit &target) { - if (to_modify.has_attribute(attr_type::owner) && - target.has_attribute(attr_type::owner)) { - auto &mod_player = to_modify.get_attribute().player; - auto &tar_player = target.get_attribute().player; - return mod_player.color == tar_player.color; - } - return false; - -} - -bool UnitAbility::is_ally(Unit &to_modify, Unit &target) { - if (to_modify.has_attribute(attr_type::owner) && - target.has_attribute(attr_type::owner)) { - auto &mod_player = to_modify.get_attribute().player; - auto &tar_player = target.get_attribute().player; - return mod_player.is_ally(tar_player); - } - return false; -} - -bool UnitAbility::is_enemy(Unit &to_modify, Unit &target) { - if (to_modify.has_attribute(attr_type::owner) && - target.has_attribute(attr_type::owner)) { - auto &mod_player = to_modify.get_attribute().player; - auto &tar_player = target.get_attribute().player; - return mod_player.is_enemy(tar_player); - } - return false; -} - -MoveAbility::MoveAbility(const Sound *s) - : - sound{s} { -} - -bool MoveAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_position()) { - return bool(to_modify.location); - } - else if (cmd.has_unit()) { - return to_modify.location && - cmd.unit()->location && - &to_modify != cmd.unit(); // cannot target self - } - return false; -} - -void MoveAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke move action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - if (cmd.has_position()) { - auto target = cmd.position(); - to_modify.push_action(std::make_unique(&to_modify, target)); - } - else if (cmd.has_unit()) { - auto target = cmd.unit(); - - // distance from the targets edge that is required to stop moving - coord::phys_t radius = path::path_grid_size + (to_modify.location->min_axis() / 2L); - - // add the range of the unit if cmd indicator is set - if (cmd.has_flag(command_flag::use_range) && to_modify.has_attribute(attr_type::attack)) { - auto &att = to_modify.get_attribute(); - radius += att.max_range; - } - to_modify.push_action(std::make_unique(&to_modify, target->get_ref(), radius)); - } -} - -SetPointAbility::SetPointAbility() = default; - -bool SetPointAbility::can_invoke(Unit &to_modify, const Command &cmd) { - return cmd.has_position() && - to_modify.has_attribute(attr_type::building); -} - -void SetPointAbility::invoke(Unit &to_modify, const Command &cmd, bool) { - auto &build_attr = to_modify.get_attribute(); - build_attr.gather_point = cmd.position(); -} - - -GarrisonAbility::GarrisonAbility(const Sound *s) - : - sound{s} { -} - -bool GarrisonAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (!cmd.has_unit()) { - return false; - } - Unit &target = *cmd.unit(); - - // make sure buildings are completed - if (target.has_attribute(attr_type::building)) { - auto &build_attr = target.get_attribute(); - if (build_attr.completed < 1.0f) { - return false; - } - } - return to_modify.location && - target.has_attribute(attr_type::garrison) && - is_ally(to_modify, target); -} - -void GarrisonAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke garrison action"); - if (play_sound && this->sound) { - this->sound->play(); - } - to_modify.push_action(std::make_unique(&to_modify, cmd.unit()->get_ref())); -} - -UngarrisonAbility::UngarrisonAbility(const Sound *s) - : - sound{s} { -} - -bool UngarrisonAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (to_modify.has_attribute(attr_type::garrison)) { - auto &garrison_attr = to_modify.get_attribute(); - return cmd.has_position() && !garrison_attr.content.empty(); - } - return false; -} - -void UngarrisonAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke ungarrison action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - // add as secondary, so primary action is not disrupted - to_modify.secondary_action(std::make_unique(&to_modify, cmd.position())); -} - -TrainAbility::TrainAbility(const Sound *s) - : - sound{s} { -} - -bool TrainAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (to_modify.has_attribute(attr_type::building)) { - auto &build_attr = to_modify.get_attribute(); - return cmd.has_type() && 1.0f <= build_attr.completed; - } - return false; -} - -void TrainAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke train action"); - if (play_sound && this->sound) { - this->sound->play(); - } - to_modify.push_action(std::make_unique(&to_modify, cmd.type())); -} - -ResearchAbility::ResearchAbility(const Sound *s) - : - sound{s} { -} - -bool ResearchAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (to_modify.has_attribute(attr_type::owner) && cmd.has_research()) { - auto &player = to_modify.get_attribute().player; - auto research = cmd.research(); - return research->can_start() && - player.can_deduct(research->type->get_research_cost().get(player)); - } - return false; -} - -void ResearchAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - if (play_sound && this->sound) { - this->sound->play(); - } - to_modify.push_action(std::make_unique(&to_modify, cmd.research())); -} - -BuildAbility::BuildAbility(const Sound *s) - : - sound{s} { -} - -bool BuildAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_unit()) { - Unit *target = cmd.unit(); - return to_modify.location && - is_same_player(to_modify, *target) && - target->has_attribute(attr_type::building) && - target->get_attribute().completed < 1.0f; - } - return false; -} - -void BuildAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke build action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - if (cmd.has_unit()) { - to_modify.push_action(std::make_unique(&to_modify, cmd.unit()->get_ref())); - } -} - -GatherAbility::GatherAbility(const Sound *s) - : - sound{s} { -} - -bool GatherAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_unit()) { - Unit &target = *cmd.unit(); - return &to_modify != &target && - to_modify.location && - to_modify.has_attribute(attr_type::worker) && - has_resource(target); - } - return false; -} - -void GatherAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke gather action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - Unit *target = cmd.unit(); - try { - to_modify.push_action(std::make_unique(&to_modify, target->get_ref())); - } catch (const std::invalid_argument &e) { - to_modify.log(MSG(dbg) << "invoke gather action cancelled due to an exception. Reason: " << e.what()); - } -} - -AttackAbility::AttackAbility(const Sound *s) - : - sound{s} { -} - -bool AttackAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_unit()) { - Unit &target = *cmd.unit(); - bool target_is_resource = has_resource(target); - return &to_modify != &target && - to_modify.location && - target.location && - target.location->is_placed() && - to_modify.has_attribute(attr_type::attack) && - has_hitpoints(target) && - (is_enemy(to_modify, target) || target_is_resource) && - (cmd.has_flag(command_flag::attack_res) == target_is_resource); - } - return false; -} - -void AttackAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke attack action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - Unit *target = cmd.unit(); - to_modify.push_action(std::make_unique(&to_modify, target->get_ref())); -} - -RepairAbility::RepairAbility(const Sound *s) - : - sound{s} { -} - -bool RepairAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_unit()) { - Unit &target = *cmd.unit(); - return &to_modify != &target && - to_modify.location && - target.location && - target.location->is_placed() && - is_damaged(target) && - is_ally(to_modify, target); - } - return false; -} - -void RepairAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke repair action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - Unit *target = cmd.unit(); - to_modify.push_action(std::make_unique(&to_modify, target->get_ref())); -} - -HealAbility::HealAbility(const Sound *s) - : - sound{s} { -} - -bool HealAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_unit()) { - Unit &target = *cmd.unit(); - return &to_modify != &target && - to_modify.location && - target.location && - target.location->is_placed() && - is_damaged(target) && - is_ally(to_modify, target); - } - return false; -} - -void HealAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke heal action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - Unit *target = cmd.unit(); - to_modify.push_action(std::make_unique(&to_modify, target->get_ref())); -} - -PatrolAbility::PatrolAbility(const Sound *s) - : - sound{s} { -} - -bool PatrolAbility::can_invoke(Unit &/*to_modify*/, const Command &/*cmd*/) { - // TODO implement - return false; -} - -void PatrolAbility::invoke(Unit &to_modify, const Command &/*cmd*/, bool play_sound) { - to_modify.log(MSG(dbg) << "not implemented"); - if (play_sound && this->sound) { - this->sound->play(); - } - // TODO implement -} - -ConvertAbility::ConvertAbility(const Sound *s) - : - sound{s} { -} - -bool ConvertAbility::can_invoke(Unit &to_modify, const Command &cmd) { - if (cmd.has_unit()) { - Unit &target = *cmd.unit(); - return &to_modify != &target && - to_modify.location && - target.location && - target.location->is_placed() && - is_enemy(to_modify, target); - } - return false; -} - -void ConvertAbility::invoke(Unit &to_modify, const Command &cmd, bool play_sound) { - to_modify.log(MSG(dbg) << "invoke convert action"); - if (play_sound && this->sound) { - this->sound->play(); - } - - Unit *target = cmd.unit(); - to_modify.push_action(std::make_unique(&to_modify, target->get_ref())); -} - -ability_set UnitAbility::set_from_list(const std::vector &items) { - ability_set result; - for (auto i : items) { - result[static_cast(i)] = 1; - } - return result; -} - -} // namespace openage - -namespace std { - -string to_string(const openage::ability_type &at) { - switch (at) { - case openage::ability_type::move: - return "move"; - case openage::ability_type::garrison: - return "garrison"; - case openage::ability_type::ungarrison: - return "ungarrison"; - case openage::ability_type::patrol: - return "patrol"; - case openage::ability_type::train: - return "train"; - case openage::ability_type::build: - return "build"; - case openage::ability_type::research: - return "research"; - case openage::ability_type::gather: - return "gather"; - case openage::ability_type::attack: - return "attack"; - case openage::ability_type::convert: - return "convert"; - case openage::ability_type::repair: - return "repair"; - case openage::ability_type::heal: - return "heal"; - default: - return "unknown"; - } -} - -} // namespace std diff --git a/libopenage/unit/ability.h b/libopenage/unit/ability.h deleted file mode 100644 index 71985ebe8c..0000000000 --- a/libopenage/unit/ability.h +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2014-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include - -#include "../coord/phys.h" - -namespace openage { - -class Command; -class Sound; -class Unit; -class UnitAction; -class UnitTexture; -class UnitType; - -/** - * roughly the same as command_ability in game data - */ -enum class ability_type { - move, - patrol, - set_point, - garrison, - ungarrison, - train, - build, - research, - gather, - attack, - convert, - repair, - heal, - MAX -}; - -/** - * a container where each ability uses 1 bit - */ -constexpr int ability_type_size = static_cast(ability_type::MAX); -using ability_set = std::bitset; -using ability_id_t = unsigned int; - -/** - * all bits set to 1 - */ -const ability_set ability_all = ability_set().set(); - -/** - * the order abilities should be used when available - */ -static std::vector ability_priority { - ability_type::gather, // targeting - ability_type::convert, - ability_type::repair, - ability_type::heal, - ability_type::attack, - ability_type::build, - ability_type::move, // positional - ability_type::patrol, - ability_type::garrison, - ability_type::ungarrison, // inside buildings - ability_type::train, - ability_type::research, - ability_type::set_point, -}; - - -/** - * Abilities create an action when given a target - * some abilities target positions such as moving or patrolling - * others target other game objects, such as attacking or - * collecting relics - * - * Abilities are constructed with a default unit texture, but allow the texture - * to be specified with the invoke function - */ -class UnitAbility { -public: - virtual ~UnitAbility() {} - - virtual ability_type type() = 0; - - /** - * true if the paramaters allow an action to be performed - */ - virtual bool can_invoke(Unit &to_modify, const Command &cmd) = 0; - - /** - * applies command to a given unit - */ - virtual void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) = 0; - - /** - * some common functions - */ - bool has_hitpoints(Unit &target); - bool is_damaged(Unit &target); - bool has_resource(Unit &target); - bool is_same_player(Unit &to_modify, Unit &target); - bool is_ally(Unit &to_modify, Unit &target); - bool is_enemy(Unit &to_modify, Unit &target); - - /** - * set bits corresponding to abilities, useful for initialising an ability_set - * using a brace enclosed list - */ - static ability_set set_from_list(const std::vector &items); - -}; - -/** - * initiates a move action when given a valid target - */ -class MoveAbility: public UnitAbility { -public: - MoveAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::move; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * sets the gather point on buildings - */ -class SetPointAbility: public UnitAbility { -public: - SetPointAbility(); - - ability_type type() override { - return ability_type::set_point; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; -}; - - -/** - * ability to garrision inside a building - */ -class GarrisonAbility: public UnitAbility { -public: - GarrisonAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::garrison; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * ability to ungarrision a building - */ -class UngarrisonAbility: public UnitAbility { -public: - UngarrisonAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::ungarrison; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * buildings train new objects - */ -class TrainAbility: public UnitAbility { -public: - TrainAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::train; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates a research - */ -class ResearchAbility: public UnitAbility { -public: - ResearchAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::research; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * villagers build new buildings - */ -class BuildAbility: public UnitAbility { -public: - BuildAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::build; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates an gather resource action when given a valid target - */ -class GatherAbility: public UnitAbility { -public: - GatherAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::gather; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates an attack action when given a valid target - */ -class AttackAbility: public UnitAbility { -public: - AttackAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::attack; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates a repair action when given a valid target - */ -class RepairAbility: public UnitAbility { -public: - RepairAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::repair; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates a heal action when given a valid target - */ -class HealAbility: public UnitAbility { -public: - HealAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::heal; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates a patrol action when given a valid target - * TODO implement - */ -class PatrolAbility: public UnitAbility { -public: - PatrolAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::patrol; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -/** - * initiates a convert action when given a valid target - */ -class ConvertAbility: public UnitAbility { -public: - ConvertAbility(const Sound *s=nullptr); - - ability_type type() override { - return ability_type::convert; - } - - bool can_invoke(Unit &to_modify, const Command &cmd) override; - - void invoke(Unit &to_modify, const Command &cmd, bool play_sound=false) override; - -private: - const Sound *sound; -}; - -} // namespace openage - -namespace std { - -std::string to_string(const openage::ability_type &at); - -/** - * hasher for ability type enum - */ -template<> -struct hash { - typedef underlying_type::type underlying_type; - - size_t operator()(const openage::ability_type &arg) const { - hash hasher; - return hasher(static_cast(arg)); - } -}; - -} // namespace std diff --git a/libopenage/unit/action.cpp b/libopenage/unit/action.cpp deleted file mode 100644 index 50a03e2155..0000000000 --- a/libopenage/unit/action.cpp +++ /dev/null @@ -1,1297 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#include -#include - -#include "../legacy_engine.h" -#include "../pathfinding/a_star.h" -#include "../pathfinding/heuristics.h" -#include "../terrain/terrain.h" -#include "../terrain/terrain_search.h" -#include "action.h" -#include "command.h" -#include "producer.h" -#include "research.h" -#include "unit_texture.h" - -namespace openage { - -IntervalTimer::IntervalTimer(unsigned int interval) : - IntervalTimer{interval, -1} { -} - -IntervalTimer::IntervalTimer(unsigned int interval, int max_triggers) : - interval{interval}, - max_triggers{max_triggers}, - time_left{interval}, - triggers{0} { -} - -void IntervalTimer::skip_to_trigger() { - this->time_left = 0; -} - -bool IntervalTimer::update(unsigned int time) { - if (this->triggers == this->max_triggers) { - return false; - } - else if (this->time_left > time) { - this->time_left -= time; - return false; - } - else { - this->time_left += this->interval - time; - this->triggers += 1; - return true; - } -} - -unsigned int IntervalTimer::get_time_left() const { - return this->time_left; -} - -float IntervalTimer::get_progress() const { - return 1.0f - (this->time_left * 1.0f / this->interval); -} - -bool IntervalTimer::has_triggers() const { - return this->triggers > 0; -} - -bool IntervalTimer::finished() const { - return this->triggers == this->max_triggers; -} - -bool UnitAction::show_debug = false; - -coord::phys_t UnitAction::adjacent_range(Unit *u) { - return path::path_grid_size * 3 + (u->location->min_axis() / 2L); -} - -coord::phys_t UnitAction::get_attack_range(Unit *u) { - coord::phys_t range = adjacent_range(u); - if (u->has_attribute(attr_type::attack)) { - auto &attack = u->get_attribute(); - range += attack.max_range; - } - return range; -} - -coord::phys_t UnitAction::get_heal_range(Unit *u) { - coord::phys_t range = adjacent_range(u); - if (u->has_attribute(attr_type::heal)) { - auto &heal = u->get_attribute(); - range += heal.range; - } - return range; -} - -UnitAction::UnitAction(Unit *u, graphic_type initial_gt) : - entity{u}, - graphic{initial_gt}, - frame{.0f}, - frame_rate{.0f} { - auto &g_set = this->current_graphics(); - if (g_set.count(initial_gt) > 0) { - auto utex = g_set.at(initial_gt); - if (utex) { - this->frame_rate = utex->frame_rate; - } - else { - this->entity->log(MSG(dbg) << "Broken graphic (null)"); - } - } - else { - this->entity->log(MSG(dbg) << "Broken graphic (not available)"); - } - - if (this->frame_rate == 0) { - // a random starting point for static graphics - // this creates variations in trees / houses etc - // this value is also deterministic to match across clients - this->frame = (u->id * u->id * 19249) & 0xff; - } -} - -graphic_type UnitAction::type() const { - return this->graphic; -} - -float UnitAction::current_frame() const { - return this->frame; -} - -const graphic_set &UnitAction::current_graphics() const { - // return the default graphic - return this->entity->unit_type->graphics; -} - -void UnitAction::draw_debug(const LegacyEngine &engine) { - // draw debug content if available - if (show_debug && this->debug_draw_action) { - this->debug_draw_action(engine); - } -} - -void UnitAction::face_towards(const coord::phys3 pos) { - if (this->entity->has_attribute(attr_type::direction)) { - auto &d_attr = this->entity->get_attribute(); - d_attr.unit_dir = pos - this->entity->location->pos.draw; - } -} - -bool UnitAction::damage_unit(Unit &target) { - bool killed = false; - - if (target.has_attribute(attr_type::damaged)) { - auto &dm = target.get_attribute(); - - // this is the damage calculation system - - if (dm.hp == 0) { - // already killed, do nothing - } - else if (target.has_attribute(attr_type::armor) && this->entity->has_attribute(attr_type::attack)) { - auto &armor = target.get_attribute().armor; - auto &damage = this->entity->get_attribute().damage; - - unsigned int actual_damage = 0; - for (const auto &pair : armor) { - auto search = damage.find(pair.first); - if (search != damage.end()) { - if (pair.second < search->second) { - actual_damage += search->second - pair.second; - } - } - } - // TODO add elevation modifier here - if (actual_damage < 1) { - actual_damage = 1; - } - - if (dm.hp > actual_damage) { - dm.hp -= actual_damage; - } - else { - dm.hp = 0; - killed = true; - } - } - else { - // TODO remove (keep for testing) - unsigned int dmg = 1; - if (dm.hp > dmg) { - dm.hp -= dmg; - } - else { - dm.hp = 0; - killed = true; - } - } - } - - if (killed) { - // if killed, give credit to a player - if (this->entity->has_attribute(attr_type::owner)) { - auto &owner = this->entity->get_attribute().player; - owner.killed_unit(target); - } - } - - return killed; -} - -void UnitAction::move_to(Unit &target, bool use_range) { - auto &player = this->entity->get_attribute().player; - Command cmd(player, &target); - cmd.set_ability(ability_type::move); - if (use_range) { - cmd.add_flag(command_flag::use_range); - } - this->entity->queue_cmd(cmd); -} - -TargetAction::TargetAction(Unit *u, graphic_type gt, UnitReference r, coord::phys_t rad) : - UnitAction(u, gt), - target{r}, - target_type_id{0}, - repath_attempts{10}, - end_action{false}, - radius{rad} { - // update type - if (this->target.is_valid()) { - auto target_ptr = this->target.get(); - this->target_type_id = target_ptr->unit_type->id(); - } - - // initial value for distance - this->update_distance(); -} - -TargetAction::TargetAction(Unit *u, graphic_type gt, UnitReference r) : - TargetAction(u, gt, r, adjacent_range(u)) { -} - -void TargetAction::update(unsigned int time) { - auto target_ptr = this->update_distance(); - if (!target_ptr) { - return; // target has become invalid - } - - // this update moves a unit within radius of the target - // once within the radius the update gets passed to the class - // derived from TargetAction - - // set direction unit should face - this->face_towards(target_ptr->location->pos.draw); - - // move to within the set radius - if (this->dist_to_target <= this->radius) { - // the derived class controls what to - // do when in range of the target - this->update_in_range(time, target_ptr); - this->repath_attempts = 10; - } - else if (this->repath_attempts) { - // out of range so try move towards - // if this unit has a move ability - this->move_to(*target_ptr); - this->repath_attempts -= 1; - } - else { - // unit is stuck - this->end_action = true; - } -} - -void TargetAction::on_completion() { - // do not retask if action is forced to end - if (this->end_action || !this->entity->location) { - return; - } - - // retask units on nearby objects - // such as gathers targeting a new resource - // when the current target expires - this->on_completion_in_range(this->target_type_id); -} - -bool TargetAction::completed() const { - if (this->end_action || !this->target.is_valid() || !this->target.get()->location) { - return true; - } - return this->completed_in_range(this->target.get()); -} - -coord::phys_t TargetAction::distance_to_target() { - return this->dist_to_target; -} - -Unit *TargetAction::update_distance() { - if (!this->target.is_valid()) { - return nullptr; - } - - // make sure object is not garrisoned - auto target_ptr = this->target.get(); - if (!target_ptr->location) { - return nullptr; - } - - // update distance - this->dist_to_target = target_ptr->location->from_edge(this->entity->location->pos.draw); - - // return the targeted unit - return target_ptr; -} - -UnitReference TargetAction::get_target() const { - return this->target; -} - -int TargetAction::get_target_type_id() const { - return this->target_type_id; -} - -void TargetAction::set_target(UnitReference new_target) { - if (new_target.is_valid()) { - this->target = new_target; - this->update_distance(); - } - else { - this->end_action = true; - } -} - -DecayAction::DecayAction(Unit *e) : - UnitAction(e, graphic_type::standing), - end_frame{.0f} { - auto &g_set = this->current_graphics(); - if (g_set.count(this->graphic) > 0) { - this->end_frame = g_set.at(this->graphic)->frame_count - 1; - } -} - -void DecayAction::update(unsigned int time) { - this->frame += time * this->frame_rate / 10000.0f; -} - -void DecayAction::on_completion() {} - -bool DecayAction::completed() const { - return this->frame > this->end_frame; -} - -DeadAction::DeadAction(Unit *e, std::function on_complete) : - UnitAction(e, graphic_type::dying), - end_frame{.0f}, - on_complete_func{on_complete} { - auto &g_set = this->current_graphics(); - if (g_set.count(graphic) > 0) { - this->end_frame = g_set.at(graphic)->frame_count - 1; - } -} - -void DeadAction::update(unsigned int time) { - if (this->entity->has_attribute(attr_type::damaged)) { - auto &dm = this->entity->get_attribute(); - dm.hp = 0; - } - - // decay resources - if (this->entity->has_attribute(attr_type::resource)) { - auto &resource = this->entity->get_attribute(); - if (resource.decay > 0) { - resource.amount -= resource.decay; - } - } - - // inc frame but do not pass the end frame - // the end frame will remain if the object carries resources - if (this->frame < this->end_frame) { - this->frame += 0.001 + time * this->frame_rate / 3.0f; - } - else { - this->frame = this->end_frame; - } -} - -void DeadAction::on_completion() { - if (this->entity->has_attribute(attr_type::owner)) { - auto &owner = this->entity->get_attribute().player; - owner.active_unit_removed(this->entity); // TODO move before the start of dead action? - } - - this->on_complete_func(); -} - -bool DeadAction::completed() const { - // check resource, trees/huntables with resource are not removed but not workers - if (this->entity->has_attribute(attr_type::resource) && !this->entity->has_attribute(attr_type::worker)) { - auto &res_attr = this->entity->get_attribute(); - return res_attr.amount <= 0; // cannot complete when resource remains - } - return this->frame > this->end_frame; -} - -FoundationAction::FoundationAction(Unit *e, bool add_destruction) : - UnitAction(e, graphic_type::construct), - add_destruct_effect{add_destruction}, - cancel{false} { -} - -void FoundationAction::update(unsigned int) { - if (!this->entity->location) { - this->cancel = true; - } -} - -void FoundationAction::on_completion() { - // do nothing if construction is cancelled - if (this->cancel) { - return; - } - - if (this->entity->has_attribute(attr_type::owner)) { - auto &owner = this->entity->get_attribute().player; - owner.active_unit_added(this->entity, true); - } - - // add destruction effect when available - if (this->add_destruct_effect) { - this->entity->push_action(std::make_unique(this->entity), true); - } - this->entity->push_action(std::make_unique(this->entity), true); -} - -bool FoundationAction::completed() const { - return this->cancel || (this->entity->has_attribute(attr_type::building) && (this->entity->get_attribute().completed >= 1.0f)); -} - -IdleAction::IdleAction(Unit *e) : - UnitAction(e, graphic_type::standing) { - auto terrain = this->entity->location->get_terrain(); - auto current_tile = this->entity->location->pos.draw.to_tile3().to_tile(); - this->search = std::make_shared(terrain, current_tile, 5.0f); - - // currently allow attack and heal automatically - this->auto_abilities = UnitAbility::set_from_list({ability_type::attack, ability_type::heal}); -} - -void IdleAction::update(unsigned int time) { - // auto task searching - if (this->entity->location && this->entity->has_attribute(attr_type::owner) && this->entity->has_attribute(attr_type::attack) && this->entity->has_attribute(attr_type::formation) && this->entity->get_attribute().stance != attack_stance::do_nothing) { - // restart search from new tile when moved - auto terrain = this->entity->location->get_terrain(); - auto current_tile = this->entity->location->pos.draw.to_tile3().to_tile(); - if (!(current_tile == this->search->start_tile())) { - this->search = std::make_shared(terrain, current_tile, 5.0f); - } - - // search one tile per update - // next tile will always be valid - coord::tile tile = this->search->next_tile(); - auto tile_data = terrain->get_data(tile); - auto &player = this->entity->get_attribute().player; - - // find and actions which can be invoked - for (auto object_location : tile_data->obj) { - Command to_object(player, &object_location->unit); - - // only allow abilities in the set of auto ability types - to_object.set_ability_set(auto_abilities); - if (this->entity->queue_cmd(to_object)) { - break; - } - } - } - - // generate resources - // TODO move elsewhere - if (this->entity->has_attribute(attr_type::resource_generator) && this->entity->has_attribute(attr_type::owner)) { - auto &player = this->entity->get_attribute().player; - auto &resource_generator = this->entity->get_attribute(); - - ResourceBundle resources = resource_generator.resources.clone(); - if (resource_generator.rate == 0) { - resources *= time; - } - else { - // TODO add in intervals and not continuously - resources *= time * resource_generator.rate; - } - - player.receive(resources); - } - - // unit carrying resources take the carrying sprite when idle - // we're not updating frames because the carrying sprite is walking - if (entity->has_attribute(attr_type::worker)) { - auto &worker_resource = this->entity->get_attribute(); - if (worker_resource.amount > 0) { - this->graphic = graphic_type::carrying; - } - else { - this->graphic = graphic_type::standing; - this->frame += time * this->frame_rate / 20.0f; - } - } - else { - // inc frame - this->frame += time * this->frame_rate / 20.0f; - } -} - -void IdleAction::on_completion() {} - -bool IdleAction::completed() const { - if (this->entity->has_attribute(attr_type::damaged)) { - auto &dm = this->entity->get_attribute(); - return dm.hp == 0; - } - else if (this->entity->has_attribute(attr_type::resource)) { - auto &res_attr = this->entity->get_attribute(); - return res_attr.amount <= 0.0; - } - return false; -} - -MoveAction::MoveAction(Unit *e, coord::phys3 tar, bool repath) : - UnitAction{e, graphic_type::walking}, - unit_target{}, - target(tar), - radius{path::path_grid_size}, - allow_repath{repath}, - end_action{false} { - this->initialise(); -} - -MoveAction::MoveAction(Unit *e, UnitReference tar, coord::phys_t within_range) : - UnitAction{e, graphic_type::walking}, - unit_target{tar}, - target(tar.get()->location->pos.draw), - radius{within_range}, - allow_repath{false}, - end_action{false} { - this->initialise(); -} - -void MoveAction::initialise() { - // switch workers to the carrying graphic - if (this->entity->has_attribute(attr_type::worker)) { - auto &worker_resource = this->entity->get_attribute(); - if (worker_resource.amount > 0) { - this->graphic = graphic_type::carrying; - } - } - - // set initial distance - this->set_distance(); - - // set an initial path - this->set_path(); - // this->debug_draw_action = [&](const Engine &engine) { - // this->path.draw_path(engine.coord); - // }; -} - -MoveAction::~MoveAction() = default; - -void MoveAction::update(unsigned int time) { - if (this->unit_target.is_valid()) { - // a unit is targeted, which may move - auto &target_object = this->unit_target.get()->location; - - // check for garrisoning objects - if (!target_object) { - this->end_action = true; - return; - } - coord::phys3 &target_pos = target_object->pos.draw; - coord::phys3 &unit_pos = this->entity->location->pos.draw; - - // repath if target changes tiles by a threshold - // this repathing is more frequent when the unit is - // close to its target - coord::phys_t tdx = target_pos.ne - this->target.ne; - coord::phys_t tdy = target_pos.se - this->target.se; - coord::phys_t udx = unit_pos.ne - this->target.ne; - coord::phys_t udy = unit_pos.se - this->target.se; - if (this->path.waypoints.empty() || std::hypot(tdx, tdy) > std::hypot(udx, udy)) { - this->target = target_pos; - this->set_path(); - } - } - - // path not found - if (this->path.waypoints.empty()) { - if (!this->allow_repath) { - this->entity->log(MSG(dbg) << "Path not found -- drop action"); - this->end_action = true; - } - return; - } - - // find distance to move in this update - auto &sp_attr = this->entity->get_attribute(); - double distance_to_move = sp_attr.unit_speed.to_double() * time; - - // current position and direction - coord::phys3 new_position = this->entity->location->pos.draw; - auto &d_attr = this->entity->get_attribute(); - coord::phys3_delta new_direction = d_attr.unit_dir; - - while (distance_to_move > 0) { - if (this->path.waypoints.empty()) { - break; - } - - // find a point to move directly towards - coord::phys3 waypoint = this->next_waypoint(); - coord::phys3_delta move_dir = waypoint - new_position; - - // normalise dir - double distance_to_waypoint = std::hypot(move_dir.ne, move_dir.se); - - if (distance_to_waypoint <= distance_to_move) { - distance_to_move -= distance_to_waypoint; - - // change entity position and direction - new_position = waypoint; - new_direction = move_dir; - - // remove the waypoint - this->path.waypoints.pop_back(); - } - else { - // change entity position and direction - new_position += move_dir * (distance_to_move / distance_to_waypoint); - new_direction = move_dir; - break; - } - } - - // check move collisions - bool move_completed = this->entity->location->move(new_position); - if (move_completed) { - d_attr.unit_dir = new_direction; - this->set_distance(); - } - else { - // cases for modifying path when blocked - if (this->allow_repath) { - this->entity->log(MSG(dbg) << "Path blocked -- finding new path"); - this->set_path(); - } - else { - this->entity->log(MSG(dbg) << "Path blocked -- drop action"); - this->end_action = true; - } - } - - // inc frame - this->frame += time * this->frame_rate / 5.0f; -} - -void MoveAction::on_completion() {} - -bool MoveAction::completed() const { - // no more waypoints to a static location - if (this->end_action || (!this->unit_target.is_valid() && this->path.waypoints.empty())) { - return true; - } - - //close enough to end action - if (this->distance_to_target < this->radius) { - return true; - } - return false; -} - - -coord::phys3 MoveAction::next_waypoint() const { - if (this->path.waypoints.size() > 0) { - return this->path.waypoints.back().position; - } - else { - throw Error{MSG(err) << "No next waypoint available!"}; - } -} - - -void MoveAction::set_path() { - if (this->unit_target.is_valid()) { - this->path = path::to_object(this->entity->location.get(), this->unit_target.get()->location.get(), this->radius); - } - else { - coord::phys3 start = this->entity->location->pos.draw; - coord::phys3 end = this->target; - this->path = path::to_point(start, end, this->entity->location->passable); - } -} - -void MoveAction::set_distance() { - if (this->unit_target.is_valid()) { - auto &target_object = this->unit_target.get()->location; - coord::phys3 &unit_pos = this->entity->location->pos.draw; - this->distance_to_target = target_object->from_edge(unit_pos); - } - else { - coord::phys3_delta move_dir = this->target - this->entity->location->pos.draw; - this->distance_to_target = static_cast(std::hypot(move_dir.ne, move_dir.se)); - } -} - -GarrisonAction::GarrisonAction(Unit *e, UnitReference build) : - TargetAction{e, graphic_type::standing, build}, - complete{false} { -} - -void GarrisonAction::update_in_range(unsigned int, Unit *target_unit) { - auto &garrison_attr = target_unit->get_attribute(); - garrison_attr.content.push_back(this->entity->get_ref()); - - if (this->entity->location) { - this->entity->location->remove(); - this->entity->location = nullptr; - } - this->complete = true; -} - -UngarrisonAction::UngarrisonAction(Unit *e, const coord::phys3 &pos) : - UnitAction{e, graphic_type::standing}, - position(pos), - complete{false} { -} - -void UngarrisonAction::update(unsigned int) { - auto &garrison_attr = this->entity->get_attribute(); - - // try unload all objects currently garrisoned - auto position_it = std::remove_if( - std::begin(garrison_attr.content), - std::end(garrison_attr.content), - [this](UnitReference &u) { - if (u.is_valid()) { - // ptr to unit being ungarrisoned - Unit *unit_ptr = u.get(); - - // make sure it was placed outside - if (unit_ptr->unit_type->place_beside(unit_ptr, this->entity->location.get())) { - // task unit to move to position - auto &player = this->entity->get_attribute().player; - Command cmd(player, this->position); - cmd.set_ability(ability_type::move); - unit_ptr->queue_cmd(cmd); - return true; - } - } - return false; - }); - - // remove elements which were ungarrisoned - garrison_attr.content.erase(position_it, std::end(garrison_attr.content)); - - // completed when no units are remaining - this->complete = garrison_attr.content.empty(); -} - -void UngarrisonAction::on_completion() {} - -TrainAction::TrainAction(Unit *e, UnitType *pp) : - UnitAction{e, graphic_type::standing}, - trained{pp}, - timer{10000, 1}, // TODO get the training time from unit type - started{false}, - complete{false} { - // TODO deduct resources -} - -void TrainAction::update(unsigned int time) { - if (!this->started) { - // check if there is enough population capacity - if (!this->trained->default_attributes.has(attr_type::population)) { - this->started = true; - } - else { - auto &player = this->entity->get_attribute().player; - auto &population_demand = this->trained->default_attributes.get().demand; - bool can_start = population_demand == 0 || population_demand <= player.population.get_space(); - // TODO trigger not enough population capacity message - this->started = can_start; - } - } - - if (this->started) { - // place unit when ready - if (this->timer.finished() || this->timer.update(time)) { - // create using the producer - UnitContainer *container = this->entity->get_container(); - auto &player = this->entity->get_attribute().player; - auto uref = container->new_unit(*this->trained, player, this->entity->location.get()); - - // make sure unit got placed - // try again next update if cannot place - if (uref.is_valid()) { - if (this->entity->has_attribute(attr_type::building)) { - // use a move command to the gather point - auto &build_attr = this->entity->get_attribute(); - Command cmd(player, build_attr.gather_point); - cmd.set_ability(ability_type::move); - uref.get()->queue_cmd(cmd); - } - this->complete = true; - } - } - } -} - -void TrainAction::on_completion() { - if (!this->complete) { - // TODO give back the resources - } -} - -ResearchAction::ResearchAction(Unit *e, Research *research) : - UnitAction{e, graphic_type::standing}, - research{research}, - timer{research->type->get_research_time(), 1}, - complete{false} { - this->research->started(); -} - -void ResearchAction::update(unsigned int time) { - if (timer.update(time)) { - this->complete = true; - this->research->apply(); - this->research->completed(); - } -} - -void ResearchAction::on_completion() { - if (!this->complete) { - this->research->stopped(); - } -} - -BuildAction::BuildAction(Unit *e, UnitReference foundation) : - TargetAction{e, graphic_type::work, foundation}, - complete{.0f}, - build_rate{.0001f} { - // update the units type - if (this->entity->has_attribute(attr_type::multitype)) { - this->entity->get_attribute().switchType(gamedata::unit_classes::BUILDING, this->entity); - } -} - -void BuildAction::update_in_range(unsigned int time, Unit *target_unit) { - if (target_unit->has_attribute(attr_type::building)) { - auto &build = target_unit->get_attribute(); - - // upgrade floating outlines - auto target_location = target_unit->location.get(); - if (target_location->is_floating()) { - // try to place the object - if (target_location->place(object_state::placed)) { - // modify ground terrain - if (build.foundation_terrain > 0) { - target_location->set_ground(build.foundation_terrain, 0); - } - } - else { - // failed to start construction - this->complete = 1.0f; - return; - } - } - - // increment building completion - build.completed += build_rate * time; - this->complete = build.completed; - - if (this->complete >= 1.0f) { - this->complete = build.completed = 1.0f; - target_location->place(build.completion_state); - } - } - else { - this->complete = 1.0f; - } - - // inc frame - this->frame += time * this->frame_rate / 2.5f; -} - -void BuildAction::on_completion() { - if (this->get_target().is_valid() && this->get_target().get()->get_attribute().completed < 1.0f) { - // The BuildAction was just aborted and we shouldn't look for new buildings - return; - } - this->entity->log(MSG(dbg) << "Done building, searching for new building"); - auto valid = [this](const TerrainObject &obj) { - if (!this->entity->get_attribute().player.owns(obj.unit) || !obj.unit.has_attribute(attr_type::building) || obj.unit.get_attribute().completed >= 1.0f) { - return false; - } - this->entity->log(MSG(dbg) << "Found unit " << obj.unit.logsource_name()); - return true; - }; - - TerrainObject *new_target = find_in_radius(*this->entity->location, valid, BuildAction::search_tile_distance); - if (new_target != nullptr) { - this->entity->log(MSG(dbg) << "Found new building, queueing command"); - Command cmd(this->entity->get_attribute().player, &new_target->unit); - this->entity->queue_cmd(cmd); - } - else { - this->entity->log(MSG(dbg) << "Didn't find new building"); - } -} - -RepairAction::RepairAction(Unit *e, UnitReference tar) : - TargetAction{e, graphic_type::work, tar}, - timer{80}, - complete{false} { - if (!tar.is_valid()) { - // the target no longer exists - complete = true; - } - else { - Unit *target = tar.get(); - - if (!target->has_attribute(attr_type::building)) { - this->timer.set_interval(this->timer.get_interval() * 4); - } - - // cost formula: 0.5 * (target cost) / (target max hp) - auto &hp = target->get_attribute(); - auto &owner = this->entity->get_attribute(); - - // get the target unit's cost - this->cost += target->unit_type->cost.get(owner.player); - this->cost *= 0.5 / hp.hp; - - if (!owner.player.deduct(this->cost)) { - // no resources to start - this->complete = true; - } - } -} - -void RepairAction::update_in_range(unsigned int time, Unit *target_unit) { - auto &hp = target_unit->get_attribute(); - auto &dm = target_unit->get_attribute(); - - if (dm.hp >= hp.hp) { - // repaired by something else - this->complete = true; - } - else if (this->timer.update(time)) { - dm.hp += 1; - - if (dm.hp >= hp.hp) { - this->complete = true; - } - - if (!this->complete) { - auto &owner = this->entity->get_attribute(); - if (!owner.player.deduct(this->cost)) { - // no resources to continue - this->complete = true; - } - } - } - - // inc frame - this->frame += time * this->frame_rate / 2.5f; -} - -GatherAction::GatherAction(Unit *e, UnitReference tar) : - TargetAction{e, graphic_type::work, tar}, - complete{false}, - target_resource{true}, - target{tar} { - Unit *target = this->target.get(); - this->resource_class = target->unit_type->unit_class; - - // handle unit type changes based on resource class - if (this->entity->has_attribute(attr_type::multitype)) { - this->entity->get_attribute().switchType(this->resource_class, this->entity); - } - - // set the type of gatherer - auto &worker_resource = this->entity->get_attribute(); - if (target->has_attribute(attr_type::resource)) { - auto &resource_attr = target->get_attribute(); - if (worker_resource.resource_type != resource_attr.resource_type) { - worker_resource.amount = 0; - } - worker_resource.resource_type = resource_attr.resource_type; - } - else { - throw std::invalid_argument("Unit reference has no resource attribute"); - } -} - -GatherAction::~GatherAction() = default; - -void GatherAction::update_in_range(unsigned int time, Unit *targeted_resource) { - auto &worker = this->entity->get_attribute(); - auto &worker_resource = this->entity->get_attribute(); - if (this->target_resource) { - // the targets attributes - if (!targeted_resource->has_attribute(attr_type::resource)) { - complete = true; - return; - } - - // attack objects which have hitpoints (trees, hunt, sheep) - if (this->entity->has_attribute(attr_type::owner) && targeted_resource->has_attribute(attr_type::damaged)) { - auto &pl = this->entity->get_attribute(); - auto &dm = targeted_resource->get_attribute(); - - // only attack if hitpoints remain - if (dm.hp > 0) { - Command cmd(pl.player, targeted_resource); - cmd.set_ability(ability_type::attack); - cmd.add_flag(command_flag::attack_res); - this->entity->queue_cmd(cmd); - return; - } - } - - // need to return to dropsite - if (worker_resource.amount > worker.capacity) { - // move to dropsite location - this->target_resource = false; - this->set_target(this->nearest_dropsite(worker_resource.resource_type)); - } - else { - auto &resource_attr = targeted_resource->get_attribute(); - if (resource_attr.amount <= 0.0) { - // when the resource runs out - if (worker_resource.amount > 0.0) { - this->target_resource = false; - this->set_target(this->nearest_dropsite(worker_resource.resource_type)); - } - else { - this->complete = true; - } - } - else { - // transfer using gather rate - double amount = worker.gather_rate[worker_resource.resource_type] - * resource_attr.gather_rate * time; - worker_resource.amount += amount; - resource_attr.amount -= amount; - } - } - } - else { - // dropsite has been reached - // add value to player stockpile - auto &player = this->entity->get_attribute().player; - player.receive(worker_resource.resource_type, worker_resource.amount); - worker_resource.amount = 0.0; - - // make sure the resource still exists - if (this->target.is_valid() && this->target.get()->get_attribute().amount > 0.0) { - // return to resource collection - this->target_resource = true; - this->set_target(this->target); - } - else { - // resource depleted - this->complete = true; - } - } - - // inc frame - this->frame += time * this->frame_rate / 3.0f; -} - -void GatherAction::on_completion_in_range(int target_type) { - // find a different target with same type - TerrainObject *new_target = nullptr; - new_target = find_near(*this->entity->location, - [target_type](const TerrainObject &obj) { - return obj.unit.unit_type->id() == target_type && !obj.unit.has_attribute(attr_type::worker) && obj.unit.has_attribute(attr_type::resource) && obj.unit.get_attribute().amount > 0.0; - }); - - if (new_target) { - this->entity->log(MSG(dbg) << "auto retasking"); - auto &pl_attr = this->entity->get_attribute(); - Command cmd(pl_attr.player, &new_target->unit); - this->entity->queue_cmd(cmd); - } -} - -UnitReference GatherAction::nearest_dropsite(game_resource res_type) { - // find nearest dropsite from the targeted resource - auto ds = find_near(*this->target.get()->location, - [=, this](const TerrainObject &obj) { - if (not obj.unit.has_attribute(attr_type::building) or &obj.unit == this->entity or &obj.unit == this->target.get()) { - return false; - } - - return obj.unit.get_attribute().completed >= 1.0f && obj.unit.has_attribute(attr_type::owner) && obj.unit.get_attribute().player.owns(*this->entity) && obj.unit.has_attribute(attr_type::dropsite) && obj.unit.get_attribute().accepting_resource(res_type); - }); - - if (ds) { - return ds->unit.get_ref(); - } - else { - this->entity->log(MSG(dbg) << "no dropsite found"); - return UnitReference(); - } -} - -AttackAction::AttackAction(Unit *e, UnitReference tar) : - TargetAction{e, graphic_type::attack, tar, get_attack_range(e)}, - timer{500} { // TODO get fire rate from unit type - - // check if attacking a non resource unit - if (this->entity->has_attribute(attr_type::worker) && (!tar.get()->has_attribute(attr_type::resource) || tar.get()->has_attribute(attr_type::worker))) { - // switch to default villager graphics - if (this->entity->has_attribute(attr_type::multitype)) { - this->entity->get_attribute().switchType(gamedata::unit_classes::CIVILIAN, this->entity); - } - } - - // TODO rivit logic, a start inside the animation should be provided - this->timer.skip_to_trigger(); -} - -AttackAction::~AttackAction() = default; - -void AttackAction::update_in_range(unsigned int time, Unit *target_ptr) { - if (this->timer.update(time)) { - this->attack(*target_ptr); - } - - // inc frame - this->frame += time * this->current_graphics().at(graphic)->frame_count * 1.0f / this->timer.get_interval(); -} - -bool AttackAction::completed_in_range(Unit *target_ptr) const { - auto &dm = target_ptr->get_attribute(); - return dm.hp < 1; // is unit still alive? -} - -void AttackAction::attack(Unit &target) { - auto &attack = this->entity->get_attribute(); - if (attack.ptype) { - // add projectile to the game - this->fire_projectile(attack, target.location->pos.draw); - } - else { - this->damage_unit(target); - } -} - -void AttackAction::fire_projectile(const Attribute &att, const coord::phys3 &target) { - // container terrain and initial position - UnitContainer *container = this->entity->get_container(); - coord::phys3 current_pos = this->entity->location->pos.draw; - current_pos.up = att.init_height; - - // create using the producer - auto &player = this->entity->get_attribute().player; - auto projectile_ref = container->new_unit(*att.ptype, player, current_pos); - - // send towards target using a projectile ability (creates projectile motion action) - if (projectile_ref.is_valid()) { - auto projectile = projectile_ref.get(); - auto &projectile_attr = projectile->get_attribute(); - projectile_attr.launcher = this->entity->get_ref(); - projectile_attr.launched = true; - projectile->push_action(std::make_unique(projectile, target), true); - } - else { - this->entity->log(MSG(dbg) << "projectile launch failed"); - } -} - - -HealAction::HealAction(Unit *e, UnitReference tar) : - TargetAction{e, graphic_type::heal, tar, get_attack_range(e)}, - timer{this->entity->get_attribute().rate} { -} - -HealAction::~HealAction() = default; - -void HealAction::update_in_range(unsigned int time, Unit *target_ptr) { - if (this->timer.update(time)) { - this->heal(*target_ptr); - } - - // inc frame - this->frame += time * this->current_graphics().at(graphic)->frame_count * 1.0f / this->timer.get_interval(); -} - -bool HealAction::completed_in_range(Unit *target_ptr) const { - auto &hp = target_ptr->get_attribute(); - auto &dm = target_ptr->get_attribute(); - return dm.hp >= hp.hp; // is unit at full hitpoints? -} - -void HealAction::heal(Unit &target) { - auto &heal = this->entity->get_attribute(); - - // TODO move to separate function heal_unit (like damage_unit)? - // heal object - if (target.has_attribute(attr_type::hitpoints) && target.has_attribute(attr_type::damaged)) { - auto &hp = target.get_attribute(); - auto &dm = target.get_attribute(); - if ((dm.hp + heal.life) < hp.hp) { - dm.hp += heal.life; - } - else { - dm.hp = hp.hp; - } - } -} - - -ConvertAction::ConvertAction(Unit *e, UnitReference tar) : - TargetAction{e, graphic_type::attack, tar}, - complete{.0f} { -} - -void ConvertAction::update_in_range(unsigned int, Unit *) {} - -ProjectileAction::ProjectileAction(Unit *e, coord::phys3 target) : - UnitAction{e, graphic_type::standing}, - has_hit{false} { - // find speed to move - auto &sp_attr = this->entity->get_attribute(); - double projectile_speed = sp_attr.unit_speed.to_double(); - - // arc of projectile - auto &pr_attr = this->entity->get_attribute(); - float projectile_arc = pr_attr.projectile_arc; - - // distance and time to target - coord::phys3_delta d = target - this->entity->location->pos.draw; - double distance_to_target = d.length(); - double flight_time = distance_to_target / projectile_speed; - - - if (projectile_arc < 0) { - // TODO negative values probably indicate something - projectile_arc += 0.2; - } - - // now figure gravity from arc parameter - // TODO projectile arc is the ratio between horizontal and - // vertical components of the initial direction - this->grav = 0.01f * (exp(pow(projectile_arc, 0.5f)) - 1) * projectile_speed; - - // inital launch direction - auto &d_attr = this->entity->get_attribute(); - d_attr.unit_dir = d * (projectile_speed / distance_to_target); - - // account for initial height - coord::phys_t initial_height = this->entity->location->pos.draw.up; - d_attr.unit_dir.up = coord::phys_t((grav * flight_time) / 2) - (initial_height * (1 / flight_time)); -} - -ProjectileAction::~ProjectileAction() = default; - -void ProjectileAction::update(unsigned int time) { - auto &d_attr = this->entity->get_attribute(); - - // apply gravity - d_attr.unit_dir.up -= this->grav * time; - - coord::phys3 new_position = this->entity->location->pos.draw + d_attr.unit_dir * time; - if (!this->entity->location->move(new_position)) { - // TODO implement friendly_fire (now friendly_fire is always on), attack_attribute.friendly_fire - - // find object which was hit - auto terrain = this->entity->location->get_terrain(); - TileContent *tc = terrain->get_data(new_position.to_tile3().to_tile()); - if (tc && !tc->obj.empty()) { - for (auto obj_location : tc->obj) { - if (this->entity->location.get() != obj_location && obj_location->check_collisions()) { - this->damage_unit(obj_location->unit); - break; - } - } - } - - // TODO implement area of effect, attack_attribute.area_of_effect - - has_hit = true; - } - - // inc frame - this->frame += time * this->frame_rate; -} - -void ProjectileAction::on_completion() {} - -bool ProjectileAction::completed() const { - return (has_hit || this->entity->location->pos.draw.up <= 0); -} - -} // namespace openage diff --git a/libopenage/unit/action.h b/libopenage/unit/action.h deleted file mode 100644 index 60299dc577..0000000000 --- a/libopenage/unit/action.h +++ /dev/null @@ -1,736 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "../gamestate/old/resource.h" -#include "../pathfinding/path.h" -#include "attribute.h" -#include "research.h" -#include "unit.h" -#include "unit_container.h" - -namespace openage { - -class TerrainSearch; - -// TODO use a type instead of unsigned int for time - -/** - * A interval triggering timer used in actions. - * TODO find a better name for triggers - */ -class IntervalTimer { -public: - /** - * Constructs a timer with a given interval - */ - IntervalTimer(unsigned int interval); - - /** - * Constructs a timer with a given interval which will - * stop after a given number of triggers. - */ - IntervalTimer(unsigned int interval, int max_triggers); - - void skip_to_trigger(); - - bool update(unsigned int time); - - /** - * Returns the time until the next trigger - */ - unsigned int get_time_left() const; - - float get_progress() const; - - /** - * Returns true if at least one interval has passed. - */ - bool has_triggers() const; - - /** - * Returns true if the interval passed have reached the max. - */ - bool finished() const; - - /** - * Returns the number of intervals passed. - */ - int get_triggers() const { - return this->triggers; - } - - unsigned int get_interval() const { - return this->interval; - } - - void set_interval(unsigned int interval) { - this->interval = interval; - } - -private: - unsigned int interval; - - int max_triggers; - - unsigned int time_left; - - int triggers; -}; - - -/** - * Actions can be pushed onto any units action stack - * - * Each update cycle will perform the update function of the - * action on top of this stack - */ -class UnitAction { -public: - /** - * Require unit to be updated and an initial graphic type - */ - UnitAction(Unit *u, graphic_type initial_gt); - - virtual ~UnitAction() {} - - /** - * type of graphic this action should use - */ - graphic_type type() const; - - /** - * frame number to use on the current graphic - */ - float current_frame() const; - - /** - * each action has its own update functionality which gets called when this - * is the active action - */ - virtual void update(unsigned int time) = 0; - - /** - * action to perform when popped from a units action stack - */ - virtual void on_completion() = 0; - - /** - * gets called for all actions on stack each update cycle - * @return true when action is completed so it and everything above it can be popped - */ - virtual bool completed() const = 0; - - /** - * checks if the action can be interrupted, allowing it to be popped if the user - * specifies a new action, if false the action must reach a completed state - * before removal - * eg dead action must be completed and cannot be discarded - */ - virtual bool allow_interrupt() const = 0; - - /** - * control whether stack can discard the action automatically and - * should the stack be modifiable when this action is on top - * - * if true this action must complete and will not allow new actions - * to be pushed while it is active and also does not update the secondary actions - */ - virtual bool allow_control() const = 0; - - /** - * debug string to identify action types - */ - virtual std::string name() const = 0; - - /** - * determines which graphic should be used for drawing this unit - * finds the default graphic using the units type, used by most actions - * - * this virtual function is overriden for special cases such as - * villager task graphics - */ - virtual const graphic_set ¤t_graphics() const; - - void draw_debug(const LegacyEngine &engine); - - /** - * common functions for actions - */ - void face_towards(const coord::phys3 pos); - - /** - * Damage a unit, returns true if the unit was killed in the process - */ - bool damage_unit(Unit &target); - - void move_to(Unit &target, bool use_range = true); - - /** - * produce debug info such as visualising paths - */ - static bool show_debug; - - /** - * a small distance to which units are considered touching - * when within this distance - */ - static coord::phys_t adjacent_range(Unit *u); - - /** - * looks at an ranged attributes on the unit - * otherwise returns same as adjacent_range() - */ - static coord::phys_t get_attack_range(Unit *u); - - /** - * looks at heal attribute on the unit - * otherwise returns same as adjacent_range() - */ - static coord::phys_t get_heal_range(Unit *u); - -protected: - /** - * the entity being updated - */ - Unit *entity; - - /** - * common graphic controls - */ - graphic_type graphic; - float frame; - float frame_rate; - - /** - * additional drawing for debug purposes - */ - std::function debug_draw_action; -}; - -/** - * Base class for actions which target another unit such as - * gather, attack, heal and convert - * TODO implement min range - */ -class TargetAction : public UnitAction { -public: - /** - * action_rad is how close a unit must come to another - * unit to be considered to touch the other, for example in - * gathering resource and melee attack - */ - TargetAction(Unit *e, graphic_type gt, UnitReference r, coord::phys_t action_rad); - - /** - * this constructor uses the default action radius formula which will - * bring the object as near to the target as the pathing grid will allow. - */ - TargetAction(Unit *e, graphic_type gt, UnitReference r); - virtual ~TargetAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return true; - } - bool allow_control() const override { - return true; - } - virtual std::string name() const override = 0; - - /** - * Control units action when in range of the target - */ - virtual void update_in_range(unsigned int, Unit *) = 0; - virtual void on_completion_in_range(int target_type) = 0; - virtual bool completed_in_range(Unit *) const = 0; - - coord::phys_t distance_to_target(); - Unit *update_distance(); - - UnitReference get_target() const; - int get_target_type_id() const; - - /** - * changes target, ending action when new target is invalid - */ - void set_target(UnitReference new_target); - -private: - UnitReference target; - int target_type_id; - int repath_attempts; - bool end_action; - - /** - * tracks distance to target from last update - */ - coord::phys_t dist_to_target, radius; -}; - -/** - * plays a fixed number of frames for the units dying animation - */ -class DecayAction : public UnitAction { -public: - DecayAction(Unit *e); - virtual ~DecayAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return false; - } - bool allow_control() const override { - return false; - } - std::string name() const override { - return "decay"; - } - -private: - float end_frame; -}; - -/** - * plays a fixed number of frames for the units dying animation - */ -class DeadAction : public UnitAction { -public: - DeadAction( - Unit *e, - std::function on_complete = []() {}); - virtual ~DeadAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return false; - } - bool allow_control() const override { - return false; - } - std::string name() const override { - return "dead"; - } - -private: - float end_frame; - std::function on_complete_func; -}; - -/** - * places an idle action on the stack once building is complete - */ -class FoundationAction : public UnitAction { -public: - FoundationAction(Unit *e, bool add_destuction = false); - virtual ~FoundationAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return true; - } - bool allow_control() const override { - return false; - } - std::string name() const override { - return "foundation"; - } - -private: - bool add_destruct_effect, cancel; -}; - -/** - * keeps an entity in a fixed position - */ -class IdleAction : public UnitAction { -public: - IdleAction(Unit *e); - virtual ~IdleAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return false; - } - bool allow_control() const override { - return true; - } - std::string name() const override { - return "idle"; - } - -private: - // look for auto task actions - std::shared_ptr search; - ability_set auto_abilities; -}; - -/** - * moves an entity to another location - */ -class MoveAction : public UnitAction { -public: - /** - * moves unit to a given fixed location - */ - MoveAction(Unit *e, coord::phys3 tar, bool repath = true); - - /** - * moves a unit to within a distance to another unit - */ - MoveAction(Unit *e, UnitReference tar, coord::phys_t within_range); - virtual ~MoveAction(); - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return true; - } - bool allow_control() const override { - return true; - } - std::string name() const override { - return "move"; - } - - coord::phys3 next_waypoint() const; - -private: - UnitReference unit_target; - coord::phys3 target; - - // how near the units should come to target - coord::phys_t distance_to_target, radius; - - path::Path path; - - // should a new path be found if unit gets blocked - bool allow_repath, end_action; - - void initialise(); - - /** - * use a star to find a path to target - */ - void set_path(); - - /** - * updates the distance_to_target value - */ - void set_distance(); -}; - -/** - * garrison inside a building - */ -class GarrisonAction : public TargetAction { -public: - GarrisonAction(Unit *e, UnitReference build); - virtual ~GarrisonAction() {} - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int) override {} - bool completed_in_range(Unit *) const override { - return this->complete; - } - std::string name() const override { - return "garrison"; - } - -private: - bool complete; -}; - -/** - * garrison inside a building - */ -class UngarrisonAction : public UnitAction { -public: - UngarrisonAction(Unit *e, const coord::phys3 &pos); - virtual ~UngarrisonAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override { - return this->complete; - } - bool allow_interrupt() const override { - return true; - } - bool allow_control() const override { - return true; - } - std::string name() const override { - return "ungarrison"; - } - -private: - coord::phys3 position; - bool complete; -}; - -/** - * trains a new unit - */ -class TrainAction : public UnitAction { -public: - TrainAction(Unit *e, UnitType *pp); - virtual ~TrainAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override { - return this->complete; - } - bool allow_interrupt() const override { - return false; - } - bool allow_control() const override { - return true; - } - std::string name() const override { - return "train"; - } - - float get_progress() const { - return this->timer.get_progress(); - } - -private: - UnitType *trained; - - IntervalTimer timer; - bool started; - bool complete; -}; - -/** - * trains a new unit - */ -class ResearchAction : public UnitAction { -public: - ResearchAction(Unit *e, Research *research); - virtual ~ResearchAction() {} - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override { - return this->complete; - } - bool allow_interrupt() const override { - return false; - } - bool allow_control() const override { - return true; - } - std::string name() const override { - return "train"; - } - - float get_progress() const { - return this->timer.get_progress(); - } - const ResearchType *get_research_type() const { - return this->research->type; - } - -private: - Research *research; - - IntervalTimer timer; - bool complete; -}; - -/** - * builds a building - */ -class BuildAction : public TargetAction { -public: - BuildAction(Unit *e, UnitReference foundation); - virtual ~BuildAction() {} - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int) override {} - bool completed_in_range(Unit *) const override { - return this->complete >= 1.0f; - } - void on_completion() override; - std::string name() const override { - return "build"; - } - - float get_progress() const { - return this->complete; - } - -private: - float complete, build_rate; - static constexpr float search_tile_distance = 9.0f; -}; - -/** - * repairs a unit - */ -class RepairAction : public TargetAction { -public: - RepairAction(Unit *e, UnitReference tar); - virtual ~RepairAction() {} - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int) override {} - bool completed_in_range(Unit *) const override { - return this->complete; - } - std::string name() const override { - return "repair"; - } - -private: - /** - * stores the cost of the repair for 1hp - */ - ResourceBundle cost; - - IntervalTimer timer; - bool complete; -}; - -/** - * gathers resource from another object - */ -class GatherAction : public TargetAction { -public: - GatherAction(Unit *e, UnitReference tar); - virtual ~GatherAction(); - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int target_type) override; - bool completed_in_range(Unit *) const override { - return this->complete; - } - std::string name() const override { - return "gather"; - } - -private: - bool complete, target_resource; - UnitReference target; - gamedata::unit_classes resource_class; - UnitReference nearest_dropsite(game_resource res_type); -}; - -/** - * attacks another unit - */ -class AttackAction : public TargetAction { -public: - AttackAction(Unit *e, UnitReference tar); - virtual ~AttackAction(); - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int) override {} - bool completed_in_range(Unit *) const override; - std::string name() const override { - return "attack"; - } - -private: - IntervalTimer timer; - - /** - * use attack action - */ - void attack(Unit &target); - - /** - * add a projectile game object which moves towards the target - */ - void fire_projectile(const Attribute &att, const coord::phys3 &target); -}; - -/** - * heals another unit - */ -class HealAction : public TargetAction { -public: - HealAction(Unit *e, UnitReference tar); - virtual ~HealAction(); - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int) override {} - bool completed_in_range(Unit *) const override; - std::string name() const override { - return "heal"; - } - -private: - IntervalTimer timer; - - /** - * use heal action - */ - void heal(Unit &target); -}; - -/** - * convert an object - */ -class ConvertAction : public TargetAction { -public: - ConvertAction(Unit *e, UnitReference tar); - virtual ~ConvertAction() {} - - void update_in_range(unsigned int time, Unit *target_unit) override; - void on_completion_in_range(int) override {} - bool completed_in_range(Unit *) const override { - return this->complete >= 1.0f; - } - std::string name() const override { - return "convert"; - } - -private: - float complete; -}; - -/** - * moves object to fly in a parabolic shape - */ -class ProjectileAction : public UnitAction { -public: - ProjectileAction(Unit *e, coord::phys3 target); - virtual ~ProjectileAction(); - - void update(unsigned int time) override; - void on_completion() override; - bool completed() const override; - bool allow_interrupt() const override { - return false; - } - bool allow_control() const override { - return false; - } - std::string name() const override { - return "projectile"; - } - -private: - double grav; - bool has_hit; -}; - -} // namespace openage diff --git a/libopenage/unit/attribute.cpp b/libopenage/unit/attribute.cpp deleted file mode 100644 index 6826bded35..0000000000 --- a/libopenage/unit/attribute.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016-2017 the openage authors. See copying.md for legal info. - -#include "attribute.h" -#include "unit.h" -#include "unit_type.h" - -namespace openage { - -bool Attribute::accepting_resource(game_resource res) const { - return std::find(resource_types.begin(), resource_types.end(), res) != resource_types.end(); -} - -void Attribute::switchType(const gamedata::unit_classes cls, Unit *unit) const { - auto search = this->types.find(cls); - if (search != this->types.end()) { - auto &player = unit->get_attribute(); - search->second->reinitialise(unit, player.player); - } -} - -} // namespace openage diff --git a/libopenage/unit/attribute.h b/libopenage/unit/attribute.h deleted file mode 100644 index 2390c1dacc..0000000000 --- a/libopenage/unit/attribute.h +++ /dev/null @@ -1,650 +0,0 @@ -// Copyright 2014-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "../coord/tile.h" -#include "../gamedata/unit_dummy.h" -#include "../terrain/terrain_object.h" -#include "../gamestate/old/resource.h" -#include "unit_container.h" - -namespace std { - -/** - * hasher for unit classes enum type - */ -template<> struct hash { - typedef underlying_type::type underlying_type; - - size_t operator()(const openage::gamedata::unit_classes &arg) const { - hash hasher; - return hasher(static_cast(arg)); - } -}; - -} // namespace std - -namespace openage { - -/** - * Types of action graphics - */ -enum class graphic_type { - construct, - shadow, - decay, - dying, - standing, - walking, - carrying, - attack, - heal, - work -}; - -class UnitTexture; - -/** - * Collection of graphics attached to each unit. - */ -using graphic_set = std::map>; - -/** - * List of unit's attribute types. - */ -enum class attr_type { - owner, - population, - damaged, - hitpoints, - armor, - attack, - formation, - heal, - speed, - direction, - projectile, - building, - dropsite, - resource, - resource_generator, - worker, - storage, - multitype, - garrison -}; - -/** - * List of unit's attack stance. - * Can be used for buildings also. - */ -enum class attack_stance { - aggressive, - defensive, - stand_ground, - do_nothing -}; - -/** - * List of unit's formation. - * Effect applys on a group of units. - */ -enum class attack_formation { - line, - staggered, - box, - flank -}; - - -/** - * this type gets specialized for each attribute - */ -template class Attribute; - -/** - * Wraps a templated attribute - */ -class AttributeContainer { -public: - AttributeContainer() {} - - AttributeContainer(attr_type t) - : - type{t} {} - - virtual ~AttributeContainer() = default; - - attr_type type; - - /** - * shared attributes are common across all units of - * one type, such as max hp, and gather rates - * - * non shared attributes include a units current hp, - * and the amount a villager is carrying - */ - virtual bool shared() const = 0; - - /** - * Produces an copy of the attribute. - */ - virtual std::shared_ptr copy() const = 0; -}; - -/** - * An unordered_map with a int key used as a type id - * and a unsigned int value used as the amount - */ -using typeamount_map = std::unordered_map; - -/** - * Wraps a templated shared attribute - * - * Shared attributes are common across all units of - * one type - */ -class SharedAttributeContainer: public AttributeContainer { -public: - - SharedAttributeContainer(attr_type t) - : - AttributeContainer{t} {} - - bool shared() const override { - return true; - } -}; - -/** - * Wraps a templated unshared attribute - * - * Shared attributes are copied for each unit of - * one type - */ -class UnsharedAttributeContainer: public AttributeContainer { -public: - - UnsharedAttributeContainer(attr_type t) - : - AttributeContainer{t} {} - - bool shared() const override { - return false; - } -}; - -// ----------------------------- -// attribute definitions go here -// ----------------------------- - -class Player; - -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(Player &p) - : - SharedAttributeContainer{attr_type::owner}, - player(p) {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - Player &player; -}; - -/** - * The max hitpoints and health bar information. - * TODO change bar information stucture - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(unsigned int i) - : - SharedAttributeContainer{attr_type::hitpoints}, - hp{i} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The max hitpoints - */ - unsigned int hp; - float hp_bar_height; -}; - -/** - * The population capacity and the population demand. - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(int demand, int capacity) - : - SharedAttributeContainer{attr_type::population}, - demand{demand}, - capacity{capacity} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - int demand; - int capacity; -}; - -/** - * The current hitpoints. - * TODO add last damage taken timestamp - */ -template<> class Attribute: public UnsharedAttributeContainer { -public: - Attribute(unsigned int i) - : - UnsharedAttributeContainer{attr_type::damaged}, - hp{i} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The current hitpoint - */ - unsigned int hp; -}; - -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(typeamount_map a) - : - SharedAttributeContainer{attr_type::armor}, - armor{a} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - typeamount_map armor; -}; - -/** - * TODO can a unit have multiple attacks such as villagers hunting map target classes onto attacks - * TODO remove the first constructor and the default values after (keep for now for compatibility) - */ -template<> class Attribute: public SharedAttributeContainer { -public: - // TODO remove (keep for testing) - // 4 = gamedata::hit_class::UNITS_MELEE (not exported at the moment) - Attribute(UnitType *type, coord::phys_t r, coord::phys_t h, unsigned int d) - : - Attribute{type, r, h, {{4, d}}} {} - - Attribute(UnitType *type, coord::phys_t r, coord::phys_t h, typeamount_map d, - coord::phys_t min_range=0, bool friendly_fire=false, - coord::phys_t area_of_effect=0) - : - SharedAttributeContainer{attr_type::attack}, - ptype{type}, - min_range{min_range}, - max_range{r}, - init_height{h}, - damage{d}, - friendly_fire{friendly_fire}, - area_of_effect{area_of_effect} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The projectile's unit type - */ - UnitType *ptype; - - /** - * The min range of the attack - * TODO not used - */ - coord::phys_t min_range; - - /** - * The max range of the attack - */ - coord::phys_t max_range; - - /** - * The height from which the projectile starts - */ - coord::phys_t init_height; - - typeamount_map damage; - - /** - * If the attack can damage allied (friendly) units. - * TODO not used - */ - bool friendly_fire; - - /** - * The radius of the area of effect of the attack or 0 if there is no area_of_effect. - * TODO not used - */ - coord::phys_t area_of_effect; -}; - -/** - * The attack stance and formation - * TODO store patrol and follow command information - */ -template<> class Attribute: public UnsharedAttributeContainer { -public: - - Attribute() - : - Attribute{attack_stance::do_nothing} {} - - Attribute(attack_stance stance) - : - UnsharedAttributeContainer{attr_type::formation}, - stance{stance}, - formation{attack_formation::line} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - attack_stance stance; - attack_formation formation; -}; - -/** - * Healing capabilities. - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(coord::phys_t r, unsigned int l, unsigned int ra) - : - SharedAttributeContainer{attr_type::heal}, - range{r}, - life{l}, - rate{ra} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The max range of the healing. - */ - coord::phys_t range; - - /** - * Life healed in each cycle - */ - unsigned int life; - - /** - * The period of each heal cycle - */ - unsigned int rate; -}; - -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(coord::phys_t sp) - : - SharedAttributeContainer{attr_type::speed}, - unit_speed{sp} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - // TODO rename to default or normal - coord::phys_t unit_speed; -}; - -template<> class Attribute: public UnsharedAttributeContainer { -public: - Attribute(coord::phys3_delta dir) - : - UnsharedAttributeContainer{attr_type::direction}, - unit_dir(dir) {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - coord::phys3_delta unit_dir; -}; - -template<> class Attribute: public UnsharedAttributeContainer { -public: - Attribute(float arc) - : - UnsharedAttributeContainer{attr_type::projectile}, - projectile_arc{arc}, - launched{false} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - float projectile_arc; - UnitReference launcher; - bool launched; -}; - -/** - * TODO revisit after unit training is improved - */ -template<> class Attribute: public UnsharedAttributeContainer { -public: - Attribute(int foundation_terrain, UnitType *pp, coord::phys3 gather_point) - : - UnsharedAttributeContainer{attr_type::building}, - completed{.0f}, - foundation_terrain{foundation_terrain}, - pp{pp}, - gather_point{gather_point} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - float completed; - int foundation_terrain; - - // set the TerrainObject to this state - // once building has been completed - object_state completion_state; - - // TODO: list allowed trainable producers - UnitType *pp; - - /** - * The go to point after a unit is created. - */ - coord::phys3 gather_point; -}; - -/** - * The resources that are accepted to be dropped. - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute(std::vector types) - : - SharedAttributeContainer{attr_type::dropsite}, - resource_types{types} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - bool accepting_resource(game_resource res) const; - - std::vector resource_types; -}; - -/** - * Resource capacity of a trees, mines, animal, worker etc. - */ -template<> class Attribute: public UnsharedAttributeContainer { -public: - Attribute() - : - Attribute{game_resource::food, 0} {} - - Attribute(game_resource type, double init_amount, double decay=0.0, double gather_rate=1.0) - : - UnsharedAttributeContainer{attr_type::resource}, - resource_type{type}, - amount{init_amount}, - decay{decay}, - gather_rate{gather_rate} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - game_resource resource_type; - - double amount; - - /** - * The rate of decay - */ - double decay; - - /** - * The gather rate multiplier (1.0 is the identity) - */ - double gather_rate; - -}; - -/** - * Resource generator eg. relic. - * While a unit is idle and contains this attribute, it will generate resources for its owner. - * - * A rate of zero means that the generation is continuously and not in intervals. - */ -template<> class Attribute: public SharedAttributeContainer { -public: - - Attribute(ResourceBundle resources, double rate=0) - : - SharedAttributeContainer{attr_type::resource_generator}, - resources{resources}, - rate{rate} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - ResourceBundle resources; - - double rate; - -}; - -/** - * The worker's capacity and gather rates. - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute() - : - SharedAttributeContainer{attr_type::worker} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The max number of resources that can be carried. - */ - double capacity; - - /** - * The gather rate for each resource. - * The ResourceBundle class is used but instead of amounts it stores gather rates. - */ - ResourceBundle gather_rate; -}; - -/** - * The worker's capacity and gather rates. - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute() - : - SharedAttributeContainer{attr_type::storage} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The capacity for each resource. - */ - ResourceBundle capacity; -}; - -class Unit; - -/** - * Stores the collection of unit types based on a unit class. - * It is used mostly for units with multiple graphics (villagers, trebuchets). - */ -template<> class Attribute: public SharedAttributeContainer { -public: - Attribute() - : - SharedAttributeContainer{attr_type::multitype} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * Switch the type of a unit based on a given unit class - */ - void switchType(const gamedata::unit_classes cls, Unit *unit) const; - - /** - * The collection of unit class to unit type pairs - */ - std::unordered_map types; -}; - -/** - * Units put inside a building. - * TODO add capacity per type of unit - */ -template<> class Attribute: public UnsharedAttributeContainer { -public: - Attribute() - : - UnsharedAttributeContainer{attr_type::garrison} {} - - std::shared_ptr copy() const override { - return std::make_shared>(*this); - } - - /** - * The units that are garrisoned. - */ - std::vector content; -}; - -} // namespace openage diff --git a/libopenage/unit/attributes.cpp b/libopenage/unit/attributes.cpp deleted file mode 100644 index faa4fa0df5..0000000000 --- a/libopenage/unit/attributes.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#include "attributes.h" - -namespace openage { - -void Attributes::add(const std::shared_ptr attr) { - this->attrs[attr->type] = attr; -} - -void Attributes::add_copies(const Attributes &other) { - this->add_copies(other, true, true); -} - -void Attributes::add_copies(const Attributes &other, bool shared, bool unshared) { - for (auto &i : other.attrs) { - auto &attr = *i.second.get(); - - if (attr.shared()) { - if (shared) { - // pass self - this->add(i.second); - } - } - else if (unshared) { - // create copy - this->add(attr.copy()); - } - } -} - -bool Attributes::remove(const attr_type type) { - return this->attrs.erase(type) > 0; -} - -bool Attributes::has(const attr_type type) const { - return this->attrs.find(type) != this->attrs.end(); -} - -std::shared_ptr Attributes::get(const attr_type type) const { - return this->attrs.at(type); -} - -} // namespace openage diff --git a/libopenage/unit/attributes.h b/libopenage/unit/attributes.h deleted file mode 100644 index cc02ac1193..0000000000 --- a/libopenage/unit/attributes.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "attribute.h" - -namespace openage { - -/** - * Contains a group of attributes. - * Can contain only one attribute of each type. - */ -class Attributes { -public: - Attributes() {} - - /** - * Add an attribute or replace any attribute of the same type. - */ - void add(const std::shared_ptr attr); - - /** - * Add copies of all the attributes from the given Attributes. - */ - void add_copies(const Attributes &attrs); - - /** - * Add copies of all the attributes from the given Attributes. - * If shared is false, shared attributes are ignored. - * If unshared is false, unshared attributes are ignored. - */ - void add_copies(const Attributes &attrs, bool shared, bool unshared); - - /** - * Remove an attribute based on the type. - */ - bool remove(const attr_type type); - - /** - * Check if the attribute of the given type exists. - */ - bool has(const attr_type type) const; - - /** - * Get the attribute based on the type. - */ - std::shared_ptr get(const attr_type type) const; - - /** - * Get the attribute - */ - template - Attribute &get() const { - return *reinterpret_cast *>(this->attrs.at(T).get()); - } - -private: - - std::map> attrs; -}; - -} // namespace openage diff --git a/libopenage/unit/command.cpp b/libopenage/unit/command.cpp deleted file mode 100644 index ec83664394..0000000000 --- a/libopenage/unit/command.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014-2017 the openage authors. See copying.md for legal info. - -#include "command.h" - -namespace openage { - -Command::Command(const Player &p, Unit *unit, bool haspos, UnitType *t, Research *res) - : - player(p), - has_pos{haspos}, - u{unit}, - unit_type{t}, - res{res} { - this->modifiers.set(); -} - -Command::Command(const Player &p, Unit *unit) - : - Command{p, unit, false, nullptr, nullptr} { -} - -Command::Command(const Player &p, coord::phys3 position) - : - Command{p, nullptr, true, nullptr, nullptr} { - this->pos = position; -} - -Command::Command(const Player &p, Unit *unit, coord::phys3 position) - : - Command{p, unit, true, nullptr, nullptr} { - this->pos = position; -} - -Command::Command(const Player &p, UnitType *t) - : - Command{p, nullptr, false, t, nullptr} { -} - -Command::Command(const Player &p, Research *res) - : - Command{p, nullptr, false, nullptr, res} { -} - -Command::Command(const Player &p, UnitType *t, coord::phys3 position) - : - Command{p, nullptr, true, t, nullptr} { - this->pos = position; -} - -bool Command::has_unit() const { - return this->u; -} - -bool Command::has_position() const { - return this->has_pos; -} - -bool Command::has_type() const { - return this->unit_type; -} - -bool Command::has_research() const { - return this->res; -} - -Unit *Command::unit() const { - return this->u; -} - -coord::phys3 Command::position() const { - return this->pos; -} - -UnitType *Command::type() const { - return this->unit_type; -} - -Research *Command::research() const { - return this->res; -} - -void Command::set_ability(ability_type t) { - this->modifiers = 0; - this->modifiers[static_cast(t)] = true; -} - -void Command::set_ability_set(ability_set set) { - this->modifiers = set; -} - -const ability_set &Command::ability() const { - return this->modifiers; -} - -void Command::add_flag(command_flag flag) { - this->flags.insert(flag); -} - -bool Command::has_flag(command_flag flag) const { - return 0 < this->flags.count(flag); -} - -} // namespace openage diff --git a/libopenage/unit/command.h b/libopenage/unit/command.h deleted file mode 100644 index 4719e09e0b..0000000000 --- a/libopenage/unit/command.h +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2014-2018 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../coord/phys.h" -#include "ability.h" - -namespace openage { - -/** - * additional flags which may affect some abilities - */ -enum class command_flag { - interrupt, // the user directly issued this command, stopping other actions - use_range, // move command account for units range - attack_res // allow attack on a resource object -}; - -} // namespace openage - -namespace std { - -/** - * hasher for game command flags - */ -template<> -struct hash { - typedef underlying_type::type underlying_type; - - size_t operator()(const openage::command_flag &arg) const { - hash hasher; - return hasher(static_cast(arg)); - } -}; - -} // namespace std - -namespace openage { - -class Player; -class Research; -class Unit; -class UnitType; - -/* - * Game command from the ui - * TODO reorganize the names of the optional variables and their getters - */ -class Command { -public: - - /** - * target another unit - */ - Command(const Player &, Unit *unit); - - /** - * target a position - */ - Command(const Player &, coord::phys3 position); - - /** - * target another unit or a position - */ - Command(const Player &, Unit *unit, coord::phys3 position); - - /** - * select a type - */ - Command(const Player &, UnitType *t); - - /** - * select a research - */ - Command(const Player &, Research *res); - - /** - * place building foundation - */ - Command(const Player &, UnitType *, coord::phys3); - - bool has_unit() const; - bool has_position() const; - bool has_type() const; - bool has_research() const; - - Unit *unit() const; - coord::phys3 position() const; - UnitType *type() const; - Research *research() const; - - /** - * sets invoked ability type, no other type may be used if - * this gets set - * - * @param type allows a specific ability type to be used - * for example to set a unit to patrol rather than the default move - */ - void set_ability(ability_type t); - - /** - * restricts action to a set of possible ability types - */ - void set_ability_set(ability_set set); - - /** - * the ability types allowed to use this command - */ - const ability_set &ability() const; - - /** - * add addition option to this command - */ - void add_flag(command_flag flag); - - /** - * read the range setting - */ - bool has_flag(command_flag flag) const; - - /** - * player who created the command - */ - const Player &player; - -private: - - /** - * basic constructor, which shouldnt be used directly - */ - Command(const Player &, Unit *unit, bool haspos, UnitType *t, Research *res); - - bool has_pos; - Unit *u; - coord::phys3 pos = {0, 0, 0}; // TODO: make pos a c++17 optional - UnitType *unit_type; - Research *res; - - /** - * additional options - */ - std::unordered_set flags; - - /** - * select actions to use when targeting - */ - ability_set modifiers; - -}; - -} // namespace openage diff --git a/libopenage/unit/producer.cpp b/libopenage/unit/producer.cpp deleted file mode 100644 index 2e6ed907e6..0000000000 --- a/libopenage/unit/producer.cpp +++ /dev/null @@ -1,861 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#include - -#include "../legacy_engine.h" -#include "../gamedata/unit_dummy.h" -#include "../log/log.h" -#include "../terrain/terrain.h" -#include "../terrain/terrain_object.h" -#include "../terrain/terrain_outline.h" -#include "../util/strings.h" -#include "ability.h" -#include "action.h" -#include "producer.h" -#include "unit.h" -#include "unit_texture.h" - -/** @file - * Many values in this file are hardcoded, due to limited understanding of how the original - * game files work -- as more becomes known these will be removed. - * - * It is likely the conversion from gamedata to openage units will be done by the nyan - * system in future - */ - -namespace openage { - -std::unordered_set allowed_terrains(const gamedata::ground_type &restriction) { - // returns a terrain whitelist for a given restriction - // you can also define a blacklist for brevity, it will be converted and returned - std::unordered_set whitelist; - std::unordered_set blacklist; - - // 1, 14, and 15 are water, 2 is shore - if (restriction == gamedata::ground_type::WATER || restriction == gamedata::ground_type::WATER_0x0D || restriction == gamedata::ground_type::WATER_SHIP_0x03 || restriction == gamedata::ground_type::WATER_SHIP_0x0F) { - whitelist.insert(1); // water - whitelist.insert(2); // shore - whitelist.insert(4); // shallows - whitelist.insert(14); // medium water - whitelist.insert(15); // deep water - } - else if (restriction == gamedata::ground_type::SOLID) { - blacklist.insert(1); // water - blacklist.insert(4); // shallows - blacklist.insert(14); // medium water - blacklist.insert(15); // deep water - } - else if (restriction == gamedata::ground_type::FOUNDATION || restriction == gamedata::ground_type::NO_ICE_0x08 || restriction == gamedata::ground_type::FOREST) { - blacklist.insert(1); // water - blacklist.insert(4); // shallows - blacklist.insert(14); // medium water - blacklist.insert(15); // deep water - blacklist.insert(18); // ice - } - else { - log::log(MSG(warn) << "undefined terrain restriction, assuming solid"); - blacklist.insert(1); // water - blacklist.insert(4); // shallows - blacklist.insert(14); // medium water - blacklist.insert(15); // deep water - } - - // if we're using a blacklist, fill out a whitelist with everything not on it - if (blacklist.size() > 0) { - // Allow all terrains that are not on blacklist - for (int i = 0; i < 32; ++i) { - if (blacklist.count(i) == 0) { - whitelist.insert(i); - } - } - } - - return whitelist; -} - -ResourceBundle create_resource_cost(game_resource resource, int amount) { - ResourceBundle resources = ResourceBundle(); - resources[resource] = amount; - return resources; -} - -ObjectProducer::ObjectProducer(const Player &owner, const GameSpec &spec, const gamedata::unit_object *ud) : - UnitType(owner), - dataspec(spec), - unit_data(*ud), - terrain_outline{nullptr}, - default_tex{spec.get_unit_texture(ud->idle_graphic0)}, - dead_unit_id{ud->dead_unit_id} { - // copy the class type - this->unit_class = this->unit_data.unit_class; - this->icon = this->unit_data.icon_id; - - // for now just look for type names ending with "_D" - this->decay = unit_data.name.substr(unit_data.name.length() - 2) == "_D"; - - // find suitable sounds - int creation_sound = this->unit_data.train_sound_id; - int dying_sound = this->unit_data.dying_sound_id; - if (creation_sound == -1) { - creation_sound = this->unit_data.damage_sound_id; - } - if (creation_sound == -1) { - creation_sound = this->unit_data.selection_sound_id; - } - if (dying_sound == -1) { - dying_sound = 323; //generic explosion sound - } - on_create = spec.get_sound(creation_sound); - on_destroy = spec.get_sound(dying_sound); - - // convert the float to the discrete foundation size... - this->foundation_size = { - static_cast(this->unit_data.radius_x * 2), - static_cast(this->unit_data.radius_y * 2), - }; - - // shape of the outline - if (this->unit_data.obstruction_class > 1) { - this->terrain_outline = radial_outline(this->unit_data.radius_x); - } - else { - this->terrain_outline = square_outline(this->foundation_size); - } - - // graphic set - auto standing = spec.get_unit_texture(this->unit_data.idle_graphic0); - if (!standing) { - // indicates problems with data converion - throw Error(MSG(err) << "Unit id " << this->unit_data.id0 - << " has invalid graphic data, try reconverting the data"); - } - this->graphics[graphic_type::standing] = standing; - auto dying_tex = spec.get_unit_texture(this->unit_data.dying_graphic); - if (dying_tex) { - this->graphics[graphic_type::dying] = dying_tex; - } - - // default extra graphics - this->graphics[graphic_type::attack] = this->graphics[graphic_type::standing]; - this->graphics[graphic_type::work] = this->graphics[graphic_type::standing]; - - // pull extra graphics from unit commands - auto cmds = spec.get_command_data(this->unit_data.id0); - for (auto cmd : cmds) { - // same attack / work graphic - if (cmd->work_sprite_id == -1 && cmd->proceed_sprite_id > 0) { - auto task = spec.get_unit_texture(cmd->proceed_sprite_id); - if (task) { - this->graphics[graphic_type::work] = task; - this->graphics[graphic_type::attack] = task; - } - } - - // separate work and attack graphics - if (cmd->work_sprite_id > 0 && cmd->proceed_sprite_id > 0) { - auto attack = spec.get_unit_texture(cmd->proceed_sprite_id); - auto work = spec.get_unit_texture(cmd->work_sprite_id); - if (attack) { - this->graphics[graphic_type::attack] = attack; - } - if (work) { - this->graphics[graphic_type::work] = work; - } - } - - // villager carrying resources graphics - if (cmd->carry_sprite_id > 0) { - auto carry = spec.get_unit_texture(cmd->carry_sprite_id); - this->graphics[graphic_type::carrying] = carry; - } - } - - // TODO get cost, temp fixed cost of 50 food - this->cost.set(cost_type::constant, create_resource_cost(game_resource::food, 50)); -} - -ObjectProducer::~ObjectProducer() = default; - -int ObjectProducer::id() const { - return this->unit_data.id0; -} - -int ObjectProducer::parent_id() const { - int uid = this->unit_data.id0; - - // male types - if (uid == 156 || uid == 120 || uid == 592 || uid == 123 || uid == 579 || uid == 124) { - return 83; - } - - // female types - else if (uid == 222 || uid == 354 || uid == 590 || uid == 218 || uid == 581 || uid == 220) { - return 293; - } - return uid; -} - -std::string ObjectProducer::name() const { - return this->unit_data.name; -} - -void ObjectProducer::initialise(Unit *unit, Player &player) { - ENSURE(this->owner == player, "unit init from a UnitType of a wrong player which breaks tech levels"); - - // log attributes - unit->log(MSG(dbg) << "setting unit type " << this->unit_data.id0 << " " << this->unit_data.name); - - // reset existing attributes - unit->reset(); - - // initialise unit - unit->unit_type = this; - - // colour - unit->add_attribute(std::make_shared>(player)); - - // hitpoints if available - if (this->unit_data.hit_points > 0) { - unit->add_attribute(std::make_shared>(this->unit_data.hit_points)); - unit->add_attribute(std::make_shared>(this->unit_data.hit_points)); - } - - // collectable resources - if (this->unit_data.unit_class == gamedata::unit_classes::TREES) { - unit->add_attribute(std::make_shared>(game_resource::wood, 125)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::BERRY_BUSH) { - unit->add_attribute(std::make_shared>(game_resource::food, 100)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::SEA_FISH) { - unit->add_attribute(std::make_shared>(game_resource::food, 200)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::PREY_ANIMAL) { - unit->add_attribute(std::make_shared>(game_resource::food, 140)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::HERDABLE) { - unit->add_attribute(std::make_shared>(game_resource::food, 100, 0.1)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::GOLD_MINE) { - unit->add_attribute(std::make_shared>(game_resource::gold, 800)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::STONE_MINE) { - unit->add_attribute(std::make_shared>(game_resource::stone, 350)); - } - - // decaying units have a timed lifespan - if (decay) { - unit->push_action(std::make_unique(unit), true); - } - else { - // if destruction graphic is available - if (this->dead_unit_id) { - unit->push_action( - std::make_unique( - unit, - [this, unit, &player]() { - // modify unit to have dead type - UnitType *t = player.get_type(this->dead_unit_id); - if (t) { - t->initialise(unit, player); - } - }), - true); - } - else if (this->graphics.count(graphic_type::dying) > 0) { - unit->push_action(std::make_unique(unit), true); - } - - // the default action - unit->push_action(std::make_unique(unit), true); - } - - // give required abilitys - for (auto &a : this->type_abilities) { - unit->give_ability(a); - } -} - -TerrainObject *ObjectProducer::place(Unit *u, std::shared_ptr terrain, coord::phys3 init_pos) const { - // create new object with correct base shape - if (this->unit_data.obstruction_class > 1) { - u->make_location(this->unit_data.radius_x, this->terrain_outline); - } - else { - u->make_location(this->foundation_size, this->terrain_outline); - } - - // find set of allowed terrains - std::unordered_set terrains = allowed_terrains(this->unit_data.terrain_restriction); - - /* - * decide what terrain is passable using this lambda - * currently unit avoids water and tiles with another unit - * this function should be true if pos is a valid position of the object - */ - TerrainObject *obj_ptr = u->location.get(); - std::weak_ptr terrain_ptr = terrain; - u->location->passable = [obj_ptr, terrain_ptr, terrains](const coord::phys3 &pos) -> bool { - // if location is deleted, then so is this lambda (deleting terrain implies location is deleted) - // so locking objects here will not return null - auto terrain = terrain_ptr.lock(); - - // look at all tiles in the bases range - for (coord::tile check_pos : tile_list(obj_ptr->get_range(pos, *terrain))) { - TileContent *tc = terrain->get_data(check_pos); - - // invalid tile types - if (!tc || terrains.count(tc->terrain_id) == 0) { - return false; - } - - // compare with objects intersecting the units tile - // ensure no intersections with other objects - for (auto obj_cmp : tc->obj) { - if (obj_ptr != obj_cmp && obj_cmp->check_collisions() && obj_ptr->intersects(*obj_cmp, pos)) { - return false; - } - } - } - return true; - }; - - // u->location->draw = [u, obj_ptr](const Engine &e) { - // if (u->selected) { - // obj_ptr->draw_outline(e.coord); - // } - // u->draw(e); - // }; - - // try to place the obj, it knows best whether it will fit. - auto state = this->decay ? object_state::placed_no_collision : object_state::placed; - if (u->location->place(terrain, init_pos, state)) { - if (this->on_create) { - this->on_create->play(); - } - return u->location.get(); - } - - // placing at the given position failed - u->log(MSG(dbg) << "failed to place object"); - return nullptr; -} - -MovableProducer::MovableProducer(const Player &owner, const GameSpec &spec, const gamedata::projectile_unit *um) : - ObjectProducer(owner, spec, um), - unit_data(*um), - on_move{spec.get_sound(this->unit_data.command_sound_id)}, - on_attack{spec.get_sound(this->unit_data.command_sound_id)}, - projectile{this->unit_data.attack_projectile_primary_unit_id} { - // extra graphics if available - // villagers have invalid attack and walk graphics - // it seems these come from the command data instead - auto walk = spec.get_unit_texture(this->unit_data.move_graphics); - if (!walk) { - // use standing instead - walk = this->graphics[graphic_type::standing]; - } - this->graphics[graphic_type::walking] = walk; - - // reuse as carry graphic if not already set - if (this->graphics.count(graphic_type::carrying) == 0) { - this->graphics[graphic_type::carrying] = walk; - } - - auto attack = spec.get_unit_texture(this->unit_data.attack_sprite_id); - if (attack && attack->is_valid()) { - this->graphics[graphic_type::attack] = attack; - } - - // extra abilities - this->type_abilities.emplace_back(std::make_shared(this->on_move)); - this->type_abilities.emplace_back(std::make_shared(this->on_attack)); -} - -MovableProducer::~MovableProducer() = default; - -void MovableProducer::initialise(Unit *unit, Player &player) { - /* - * call base function - */ - ObjectProducer::initialise(unit, player); - - /* - * basic attributes - */ - if (!unit->has_attribute(attr_type::direction)) { - unit->add_attribute(std::make_shared>(coord::phys3_delta{1, 0, 0})); - } - - /* - * distance per millisecond -- consider original game speed - * where 1.5 in game seconds pass in 1 real second - */ - coord::phys_t sp = this->unit_data.speed / 666; - unit->add_attribute(std::make_shared>(sp)); - - // projectile of melee attacks - UnitType *proj_type = this->owner.get_type(this->projectile); - if (this->unit_data.attack_projectile_primary_unit_id > 0 && proj_type) { - // calculate requirements for ranged attacks - coord::phys_t range_phys = this->unit_data.weapon_range_max; - unit->add_attribute(std::make_shared>(proj_type, range_phys, 48000, 1)); - } - else { - unit->add_attribute(std::make_shared>(nullptr, 0, 0, 1)); - } - unit->add_attribute(std::make_shared>()); -} - -TerrainObject *MovableProducer::place(Unit *unit, std::shared_ptr terrain, coord::phys3 init_pos) const { - return ObjectProducer::place(unit, terrain, init_pos); -} - -LivingProducer::LivingProducer(const Player &owner, const GameSpec &spec, const gamedata::living_unit *ud) : - MovableProducer(owner, spec, ud), - unit_data(*ud) { - // extra abilities - this->type_abilities.emplace_back(std::make_shared(this->on_move)); -} - -LivingProducer::~LivingProducer() = default; - -void LivingProducer::initialise(Unit *unit, Player &player) { - /* - * call base function - */ - MovableProducer::initialise(unit, player); - - // population of 1 for all movable units - if (this->unit_data.unit_class != gamedata::unit_classes::HERDABLE) { - unit->add_attribute(std::make_shared>(1, 0)); - } - - // add worker attributes - if (this->unit_data.unit_class == gamedata::unit_classes::CIVILIAN) { - unit->add_attribute(std::make_shared>()); - unit->add_attribute(std::make_shared>()); - unit->add_attribute(std::make_shared>()); - - // add graphic ids for resource actions - auto &worker_attr = unit->get_attribute(); - worker_attr.capacity = 10.0; - worker_attr.gather_rate[game_resource::wood] = 0.002; - worker_attr.gather_rate[game_resource::food] = 0.002; - worker_attr.gather_rate[game_resource::gold] = 0.002; - worker_attr.gather_rate[game_resource::stone] = 0.002; - - auto &multitype_attr = unit->get_attribute(); - // currently not sure where the game data keeps these values - // todo PREY_ANIMAL SEA_FISH - if (this->parent_id() == 83) { - // male graphics - multitype_attr.types[gamedata::unit_classes::CIVILIAN] = this->parent_type(); // get default villager - multitype_attr.types[gamedata::unit_classes::BUILDING] = this->owner.get_type(156); // builder 118 - multitype_attr.types[gamedata::unit_classes::BERRY_BUSH] = this->owner.get_type(120); // forager - multitype_attr.types[gamedata::unit_classes::HERDABLE] = this->owner.get_type(592); // sheperd - multitype_attr.types[gamedata::unit_classes::TREES] = this->owner.get_type(123); // woodcutter - multitype_attr.types[gamedata::unit_classes::GOLD_MINE] = this->owner.get_type(579); // gold miner - multitype_attr.types[gamedata::unit_classes::STONE_MINE] = this->owner.get_type(124); // stone miner - } - else { - // female graphics - multitype_attr.types[gamedata::unit_classes::CIVILIAN] = this->parent_type(); // get default villager - multitype_attr.types[gamedata::unit_classes::BUILDING] = this->owner.get_type(222); // builder 212 - multitype_attr.types[gamedata::unit_classes::BERRY_BUSH] = this->owner.get_type(354); // forager - multitype_attr.types[gamedata::unit_classes::HERDABLE] = this->owner.get_type(590); // sheperd - multitype_attr.types[gamedata::unit_classes::TREES] = this->owner.get_type(218); // woodcutter - multitype_attr.types[gamedata::unit_classes::GOLD_MINE] = this->owner.get_type(581); // gold miner - multitype_attr.types[gamedata::unit_classes::STONE_MINE] = this->owner.get_type(220); // stone miner - } - unit->give_ability(std::make_shared(this->on_attack)); - unit->give_ability(std::make_shared(this->on_attack)); - unit->give_ability(std::make_shared(this->on_attack)); - } - else if (this->unit_data.unit_class == gamedata::unit_classes::FISHING_BOAT) { - unit->add_attribute(std::make_shared>()); - unit->add_attribute(std::make_shared>()); - - // add fishing abilites - auto &worker_attr = unit->get_attribute(); - worker_attr.capacity = 15.0; - worker_attr.gather_rate[game_resource::food] = 0.002; - - unit->give_ability(std::make_shared(this->on_attack)); - } -} - -TerrainObject *LivingProducer::place(Unit *unit, std::shared_ptr terrain, coord::phys3 init_pos) const { - return MovableProducer::place(unit, terrain, init_pos); -} - -BuildingProducer::BuildingProducer(const Player &owner, const GameSpec &spec, const gamedata::building_unit *ud) : - UnitType(owner), - unit_data{*ud}, - texture{spec.get_unit_texture(ud->idle_graphic0)}, - destroyed{spec.get_unit_texture(ud->dying_graphic)}, - projectile{this->unit_data.attack_projectile_primary_unit_id}, - foundation_terrain{ud->foundation_terrain_id}, - enable_collisions{this->unit_data.id0 != 109} { // 109 = town center - - // copy the class type - this->unit_class = this->unit_data.unit_class; - this->icon = this->unit_data.icon_id; - - // find suitable sounds - int creation_sound = this->unit_data.train_sound_id; - int dying_sound = this->unit_data.dying_sound_id; - if (creation_sound == -1) { - creation_sound = this->unit_data.damage_sound_id; - } - if (creation_sound == -1) { - creation_sound = this->unit_data.selection_sound_id; - } - if (dying_sound == -1) { - dying_sound = 323; //generic explosion sound - } - on_create = spec.get_sound(creation_sound); - on_destroy = spec.get_sound(dying_sound); - - // convert the float to the discrete foundation size... - this->foundation_size = { - static_cast(this->unit_data.radius_x * 2), - static_cast(this->unit_data.radius_y * 2), - }; - - // graphic set - this->graphics[graphic_type::construct] = spec.get_unit_texture(ud->construction_graphic_id); - this->graphics[graphic_type::standing] = spec.get_unit_texture(ud->idle_graphic0); - this->graphics[graphic_type::attack] = spec.get_unit_texture(ud->idle_graphic0); - auto dying_tex = spec.get_unit_texture(ud->dying_graphic); - if (dying_tex) { - this->graphics[graphic_type::dying] = dying_tex; - } - - this->terrain_outline = square_outline(this->foundation_size); - - // TODO get cost, temp fixed cost of 100 wood - this->cost.set(cost_type::constant, create_resource_cost(game_resource::wood, 100)); -} - -BuildingProducer::~BuildingProducer() = default; - -int BuildingProducer::id() const { - return this->unit_data.id0; -} - -int BuildingProducer::parent_id() const { - return this->unit_data.id0; -} - -std::string BuildingProducer::name() const { - return this->unit_data.name; -} - -void BuildingProducer::initialise(Unit *unit, Player &player) { - ENSURE(this->owner == player, "unit init from a UnitType of a wrong player which breaks tech levels"); - - // log type - unit->log(MSG(dbg) << "setting unit type " << this->unit_data.id0 << " " << this->unit_data.name); - - // initialize graphic set - unit->unit_type = this; - - auto player_attr = std::make_shared>(player); - unit->add_attribute(player_attr); - - // building specific attribute - auto build_attr = std::make_shared>( - this->foundation_terrain, - this->owner.get_type(293), // fem_villager, male is 83 - unit->location->pos.draw); - build_attr->completion_state = this->enable_collisions ? object_state::placed : object_state::placed_no_collision; - unit->add_attribute(build_attr); - - // garrison and hp for all buildings - unit->add_attribute(std::make_shared>()); - unit->add_attribute(std::make_shared>(this->unit_data.hit_points)); - unit->add_attribute(std::make_shared>(this->unit_data.hit_points)); - - // population - if (this->id() == 109 || this->id() == 70) { // Town center, House - unit->add_attribute(std::make_shared>(0, 5)); - } - else if (this->id() == 82) { // Castle - unit->add_attribute(std::make_shared>(0, 20)); - } - - // limits - if (this->id() == 109 || this->id() == 276) { // Town center, Wonder - this->have_limit = 2; // TODO change to 1, 2 is for testing - } - - bool has_destruct_graphic = this->destroyed != nullptr; - unit->push_action(std::make_unique(unit, has_destruct_graphic), true); - - UnitType *proj_type = this->owner.get_type(this->projectile); - if (this->unit_data.attack_projectile_primary_unit_id > 0 && proj_type) { - coord::phys_t range_phys = this->unit_data.weapon_range_max; - unit->add_attribute(std::make_shared>(proj_type, range_phys, 350000, 1)); - // formation is used only for the attack_stance - unit->add_attribute(std::make_shared>(attack_stance::aggressive)); - unit->give_ability(std::make_shared()); - } - - // dropsite attribute - std::vector accepted_resources = this->get_accepted_resources(); - if (accepted_resources.size() != 0) { - unit->add_attribute(std::make_shared>(accepted_resources)); - } - - // building can train new units and ungarrison - unit->give_ability(std::make_shared()); - unit->give_ability(std::make_shared()); - unit->give_ability(std::make_shared()); -} - -std::vector BuildingProducer::get_accepted_resources() { - //TODO use a more general approach instead of hard coded ids - - auto id_in = [=, this](std::initializer_list ids) { - return std::any_of(ids.begin(), ids.end(), [=, this](int n) { return n == this->id(); }); - }; - - if (this->id() == 109) { // Town center - return std::vector{ - game_resource::wood, - game_resource::food, - game_resource::gold, - game_resource::stone}; - } - else if (id_in({584, 585, 586, 587})) { // Mine - return std::vector{ - game_resource::gold, - game_resource::stone}; - } - else if (id_in({68, 129, 130, 131})) { // Mill - return std::vector{ - game_resource::food}; - } - else if (id_in({562, 563, 564, 565})) { // Lumberjack camp - return std::vector{ - game_resource::wood}; - } - - return std::vector(); -} - -TerrainObject *BuildingProducer::place(Unit *u, std::shared_ptr terrain, coord::phys3 init_pos) const { - // buildings have a square base - u->make_location(this->foundation_size, this->terrain_outline); - - /* - * decide what terrain is passable using this lambda - * currently unit avoids water and tiles with another unit - * this function should be true if pos is a valid position of the object - */ - TerrainObject *obj_ptr = u->location.get(); - std::weak_ptr terrain_ptr = terrain; - - // find set of allowed terrains - std::unordered_set terrains = allowed_terrains(this->unit_data.terrain_restriction); - - u->location->passable = [obj_ptr, terrain_ptr, terrains](const coord::phys3 &pos) -> bool { - auto terrain = terrain_ptr.lock(); - - // look at all tiles in the bases range - for (coord::tile check_pos : tile_list(obj_ptr->get_range(pos, *terrain))) { - TileContent *tc = terrain->get_data(check_pos); - - // check if terrains are suitable and free of content - if (!tc || !terrains.count(tc->terrain_id) || tc->obj.size()) { - return false; - } - } - - return true; - }; - - // drawing function - // bool draw_outline = this->enable_collisions; - // u->location->draw = [u, obj_ptr, draw_outline](const Engine &e) { - // if (u->selected && draw_outline) { - // obj_ptr->draw_outline(e.coord); - // } - // u->draw(e); - // }; - - // try to place the obj, it knows best whether it will fit. - auto state = object_state::floating; - if (!u->location->place(terrain, init_pos, state)) { - return nullptr; - } - - // annex objects - for (unsigned i = 0; i < 4; ++i) { - const gamedata::building_annex &annex = this->unit_data.building_annex.data[i]; - if (annex.unit_id > 0) { - // make objects for annex - coord::phys3 a_pos = u->location->pos.draw; - a_pos.ne += annex.misplaced0; - a_pos.se += annex.misplaced1; - this->make_annex(*u, terrain, annex.unit_id, a_pos, i == 0); - } - } - - // TODO: play sound once built - if (this->on_create) { - this->on_create->play(); - } - return u->location.get(); -} - -TerrainObject *BuildingProducer::make_annex(Unit &u, std::shared_ptr t, int annex_id, coord::phys3 annex_pos, bool c) const { - // for use in lambda drawing functions - auto annex_type = this->owner.get_type(annex_id); - if (!annex_type) { - u.log(MSG(warn) << "Invalid annex type id " << annex_id); - return nullptr; - } - - // foundation size - coord::tile_delta annex_foundation = annex_type->foundation_size; - - // producers place by the nw tile - coord::phys3 start_tile = annex_pos; - start_tile.ne -= annex_foundation.ne / 2.0; - start_tile.se -= annex_foundation.se / 2.0; - - // create and place on terrain - TerrainObject *annex_loc = u.location->make_annex(annex_foundation); - object_state state = c ? object_state::placed : object_state::placed_no_collision; - annex_loc->place(t, start_tile, state); - - // create special drawing functions for annexes, - annex_loc->draw = [annex_loc, annex_type, &u, c](const LegacyEngine &e) { - // hack which draws the outline in the right order - // removable once rendering system is improved - if (c && u.selected) { - // annex_loc->get_parent()->draw_outline(e.coord); - } - - // only draw if building is completed - if (u.has_attribute(attr_type::building) && u.get_attribute().completed >= 1.0f) { - u.draw(annex_loc, annex_type->graphics, e); - } - }; - return annex_loc; -} - -ProjectileProducer::ProjectileProducer(const Player &owner, const GameSpec &spec, const gamedata::missile_unit *pd) : - UnitType(owner), - unit_data{*pd}, - tex{spec.get_unit_texture(this->unit_data.idle_graphic0)}, - sh{spec.get_unit_texture(3379)}, // 3379 = general arrow shadow - destroyed{spec.get_unit_texture(this->unit_data.dying_graphic)} { - // copy the class type - this->unit_class = this->unit_data.unit_class; - - // graphic set - this->graphics[graphic_type::standing] = this->tex; - this->graphics[graphic_type::shadow] = this->sh; - if (destroyed) { - this->graphics[graphic_type::dying] = destroyed; - } - - // outline - terrain_outline = radial_outline(pd->radius_y); -} - -ProjectileProducer::~ProjectileProducer() = default; - -int ProjectileProducer::id() const { - return this->unit_data.id0; -} - -int ProjectileProducer::parent_id() const { - return this->unit_data.id0; -} - -std::string ProjectileProducer::name() const { - return this->unit_data.name; -} - -void ProjectileProducer::initialise(Unit *unit, Player &player) { - ENSURE(this->owner == player, "unit init from a UnitType of a wrong player which breaks tech levels"); - - // initialize graphic set - unit->unit_type = this; - - auto player_attr = std::make_shared>(player); - unit->add_attribute(player_attr); - - // projectile speed - coord::phys_t sp = this->unit_data.speed / 666; - unit->add_attribute(std::make_shared>(sp)); - unit->add_attribute(std::make_shared>(this->unit_data.projectile_arc)); - unit->add_attribute(std::make_shared>(coord::phys3_delta{1, 0, 0})); - - // if destruction graphic is available - if (this->destroyed) { - unit->push_action(std::make_unique(unit), true); - } -} - -TerrainObject *ProjectileProducer::place(Unit *u, std::shared_ptr terrain, coord::phys3 init_pos) const { - /* - * radial base shape without collision checking - */ - u->make_location(this->unit_data.radius_y, this->terrain_outline); - - TerrainObject *obj_ptr = u->location.get(); - std::weak_ptr terrain_ptr = terrain; - u->location->passable = [obj_ptr, u, terrain_ptr](const coord::phys3 &pos) -> bool { - if (pos.up > 64000) { - return true; - } - - // avoid intersections with launcher - Unit *launcher = nullptr; - auto terrain = terrain_ptr.lock(); - if (u->has_attribute(attr_type::projectile)) { - auto &pr_attr = u->get_attribute(); - if (pr_attr.launched && pr_attr.launcher.is_valid()) { - launcher = pr_attr.launcher.get(); - } - else { - return true; - } - } - else { - return true; - } - - // look at all tiles in the bases range - for (coord::tile check_pos : tile_list(obj_ptr->get_range(pos, *terrain))) { - TileContent *tc = terrain->get_data(check_pos); - if (!tc) - return false; - - // ensure no intersections with other objects - for (auto obj_cmp : tc->obj) { - if (obj_ptr != obj_cmp && &obj_cmp->unit != launcher && obj_cmp->check_collisions() && obj_ptr->intersects(*obj_cmp, pos)) { - return false; - } - } - } - return true; - }; - - u->location->draw = [u](const LegacyEngine &e) { - u->draw(e); - }; - - // try to place the obj, it knows best whether it will fit. - if (u->location->place(terrain, init_pos, object_state::placed_no_collision)) { - return u->location.get(); - } - return nullptr; -} - -} // namespace openage diff --git a/libopenage/unit/producer.h b/libopenage/unit/producer.h deleted file mode 100644 index 804df598cf..0000000000 --- a/libopenage/unit/producer.h +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2014-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "../coord/tile.h" -#include "../gamedata/gamedata_dummy.h" -#include "../gamedata/graphic_dummy.h" -#include "../gamestate/old/player.h" -#include "unit.h" -#include "unit_type.h" - -namespace openage { - -class GameMain; -class GameSpec; -class Terrain; -class TerrainObject; -class Texture; -class Sound; - -class UnitAbility; -class UnitAction; -class UnitTexture; - - -std::unordered_set allowed_terrains(const gamedata::ground_type &restriction); - -/** - * base game data unit type - */ -class ObjectProducer: public UnitType { -public: - ObjectProducer(const Player &owner, const GameSpec &spec, const gamedata::unit_object *ud); - virtual ~ObjectProducer(); - - int id() const override; - int parent_id() const override; - std::string name() const override; - void initialise(Unit *, Player &) override; - TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const override; - -protected: - const GameSpec &dataspec; - const gamedata::unit_object unit_data; - - /** - * decaying objects have a timed lifespan - */ - bool decay; - - /** - * Sound id played when object is created or destroyed. - */ - const Sound *on_create; - const Sound *on_destroy; - std::shared_ptr terrain_outline; - std::shared_ptr default_tex; - int dead_unit_id; -}; - -/** - * movable unit types - */ -class MovableProducer: public ObjectProducer { -public: - MovableProducer(const Player &owner, const GameSpec &spec, const gamedata::projectile_unit *); - virtual ~MovableProducer(); - - void initialise(Unit *, Player &) override; - TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const override; - -protected: - const gamedata::projectile_unit unit_data; - UnitTexture *moving; - UnitTexture *attacking; - const Sound *on_move; - const Sound *on_attack; - int projectile; - -}; - -/** - * temporary class -- will be replaced with nyan system in future - * Stores graphics and attributes for a single unit type - * in aoe living units are derived from objects - */ -class LivingProducer: public MovableProducer { -public: - LivingProducer(const Player &owner, const GameSpec &spec, const gamedata::living_unit *); - virtual ~LivingProducer(); - - void initialise(Unit *, Player &) override; - TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const override; - -private: - const gamedata::living_unit unit_data; -}; - -/** - * Stores graphics and attributes for a building type - * Will be replaced with nyan system in future - * in aoe buildings are derived from living units - */ -class BuildingProducer: public UnitType { -public: - BuildingProducer(const Player &owner, - const GameSpec &spec, - const gamedata::building_unit *ud); - virtual ~BuildingProducer(); - - int id() const override; - int parent_id() const override; - std::string name() const override; - void initialise(Unit *, Player &) override; - TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const override; - -private: - const gamedata::building_unit unit_data; - - /** - * Sound id played when object is created or destroyed. - */ - const Sound *on_create; - const Sound *on_destroy; - std::shared_ptr terrain_outline; - std::shared_ptr texture; - std::shared_ptr destroyed; - int projectile; - int foundation_terrain; - std::vector get_accepted_resources(); - - /** - * used for objects like town centers or gates - * where the base does not apply collision checks - */ - bool enable_collisions; - - TerrainObject *make_annex(Unit &u, std::shared_ptr t, int annex_id, coord::phys3 annex_pos, bool c) const; -}; - -/** - * creates projectiles - * todo use MovableProducer as base class - */ -class ProjectileProducer: public UnitType { -public: - ProjectileProducer(const Player &owner, const GameSpec &spec, const gamedata::missile_unit *); - virtual ~ProjectileProducer(); - - int id() const override; - int parent_id() const override; - std::string name() const override; - void initialise(Unit *, Player &) override; - TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const override; - -private: - const gamedata::missile_unit unit_data; - std::shared_ptr terrain_outline; - std::shared_ptr tex; - std::shared_ptr sh; // shadow texture - std::shared_ptr destroyed; -}; - -} // namespace openage diff --git a/libopenage/unit/research.cpp b/libopenage/unit/research.cpp deleted file mode 100644 index 7161565583..0000000000 --- a/libopenage/unit/research.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2017-2018 the openage authors. See copying.md for legal info. - -#include "../gamestate/old/player.h" -#include "research.h" - - -namespace openage { - -ResearchType::ResearchType(Player &owner) - : - owner{owner} { -} - -std::shared_ptr ResearchType::initialise() const { - return std::make_shared(this); -} - -Research::Research(const ResearchType *type) - : - type{type}, - active_count{0}, - completed_count{0} { -} - -void Research::started() { - this->active_count += 1; -} - -void Research::stopped() { - this->active_count -= 1; -} - -void Research::completed() { - this->active_count -= 1; - this->completed_count += 1; -} - -bool Research::can_start() const { - return this->active_count + this->completed_count < this->type->get_max_repeats(); -} - -bool Research::is_active() const { - return this->active_count > 0; -} - -bool Research::is_researched() const { - return this->completed_count == this->type->get_max_repeats(); -} - -void Research::apply() { - // apply the patch - this->type->apply(); - - // perform category based actions - if (type->category() == research_category::age_advance) { - type->owner.advance_age(); - - } else if (type->category() == research_category::generic) { - // TODO implement a way to handle this category - } -} - -} // namespace openage diff --git a/libopenage/unit/research.h b/libopenage/unit/research.h deleted file mode 100644 index edd73ee8ed..0000000000 --- a/libopenage/unit/research.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2017-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - - -namespace openage { - -class Player; -class Research; -class ResourceCost; - -enum class research_category : int { - /** - * Research which modify unit type data. - */ - unit_upgrade, - /** - * Research which modify unit type data and also progresses the next age. - * Separate category for simplification. - */ - age_advance, - /** - * Research which modify unit type data and something else. - * (eg. see enemy line of sight) - */ - generic, - RESEARCH_CATEGORY_COUNT -}; - -/** - * Describes a research for a single player - * - * The get_max_repeats (with a default value of 1) can allow for a research to be - * performed multiple types - */ -class ResearchType { -public: - - ResearchType(Player &owner); - - /** - * Gets the unique id of this research type. - */ - virtual int id() const = 0; - - /** - * Gets the name of the research. - */ - virtual std::string name() const = 0; - - /** - * Gets the research category of the research. - */ - virtual research_category category() const = 0; - - /** - * Creates a single Research object. - * Must be called only once. - */ - std::shared_ptr initialise() const; - - /** - * The player who owns this research type - */ - Player &owner; - - /** - * How many times it can be researched. - * All classic researches have a value of 1. - */ - int get_max_repeats() const { return 1; } - - virtual unsigned int get_research_time() const = 0; - - virtual ResourceCost get_research_cost() const = 0; - - /** - * Performs the modifications (eg. apply patch to the unit types) - */ - virtual void apply() const = 0; - -protected: - -private: - -}; - -class NyanResearchType : public ResearchType { - // TODO POST-NYAN Implement - - NyanResearchType(Player &owner); - -}; - -/** - * At most one Research must exist for each ResearchType. - * - * A research represents how many times the research type has been completed (completed count) - * and also how many unit are researching it now (active count). - */ -class Research { -public: - - Research(const ResearchType *type); - - const ResearchType *type; - - /** - * Called when a unit started researching this research. - */ - void started(); - - /** - * Called when a unit stopped researching this research before completing it. - */ - void stopped(); - - /** - * Called when a unit completed researching this research. - */ - void completed(); - - /** - * Returns true if a unit can start researching this research. - */ - bool can_start() const; - - /** - * Returns true if any unit is researching this research. - */ - bool is_active() const; - - /** - * Returns true if it has nothing more to offer (reached max repeats). - */ - bool is_researched() const; - - /** - * Apply the modifications to the owner player. - */ - void apply(); - -protected: - - /** - * The number of units that are researching this research - */ - int active_count; - - /** - * The number of times this research has been completed - */ - int completed_count; - -private: - -}; - -} // namespace openage diff --git a/libopenage/unit/selection.cpp b/libopenage/unit/selection.cpp deleted file mode 100644 index 49ddd78440..0000000000 --- a/libopenage/unit/selection.cpp +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "selection.h" - -#include -#include - -#include "../coord/tile.h" -#include "../legacy_engine.h" -#include "../log/log.h" -#include "../renderer/text.h" -#include "../terrain/terrain.h" -#include "action.h" -#include "command.h" -#include "producer.h" -#include "unit.h" - - -namespace openage { - -UnitSelection::UnitSelection(LegacyEngine *engine) : - selection_type{selection_type_t::nothing}, - drag_active{false}, - engine{engine} { -} - -bool UnitSelection::on_drawhud() { - // // the drag selection box - // if (drag_active) { - // coord::viewport s = this->start.to_viewport(this->engine->coord); - // coord::viewport e = this->end.to_viewport(this->engine->coord); - // glLineWidth(1); - // glColor3f(1.0, 1.0, 1.0); - // glBegin(GL_LINE_LOOP); { - // glVertex3f(s.x, s.y, 0); - // glVertex3f(e.x, s.y, 0); - // glVertex3f(e.x, e.y, 0); - // glVertex3f(s.x, e.y, 0); - // } - // glEnd(); - // } - // - // // draw hp bars for each selected unit - // glLineWidth(3); - // for (auto u : this->units) { - // if (u.second.is_valid()) { - // Unit *unit_ptr = u.second.get(); - // if (unit_ptr->location && - // unit_ptr->has_attribute(attr_type::hitpoints) && - // unit_ptr->has_attribute(attr_type::damaged)) { - // - // auto &hp = unit_ptr->get_attribute(); - // auto &dm = unit_ptr->get_attribute(); - // float percent = static_cast(dm.hp) / static_cast(hp.hp); - // int mid = percent * 28.0f - 14.0f; - // - // coord::phys3 &pos_phys3 = unit_ptr->location->pos.draw; - // auto pos = pos_phys3.to_viewport(this->engine->coord); - // // green part - // glColor3f(0.0, 1.0, 0.0); - // glBegin(GL_LINES); { - // glVertex3f(pos.x - 14, pos.y + 60, 0); - // glVertex3f(pos.x + mid, pos.y + 60, 0); - // } - // glEnd(); - // - // // red part - // glColor3f(1.0, 0.0, 0.0); - // glBegin(GL_LINES); { - // glVertex3f(pos.x + mid, pos.y + 60, 0); - // glVertex3f(pos.x + 14, pos.y + 60, 0); - // } - // glEnd(); - // } - // } - // } - // glColor3f(1.0, 1.0, 1.0); // reset - - // ui graphics 3404 and 3405 - return true; -} - -void UnitSelection::drag_begin(coord::camgame pos) { - this->start = pos; - this->end = pos; - this->drag_active = true; -} - -// called as the entry point for the selection -// from ActionMode. -void UnitSelection::drag_update(coord::camgame pos) { - if (!this->drag_active) { - this->drag_begin(pos); - } - this->end = pos; -} - -void UnitSelection::drag_release(const Player &player, Terrain *terrain, bool append) { - if (this->start == this->end) { - this->select_point(player, terrain, this->start, append); - } - else { - this->select_space(player, terrain, this->start, this->end, append); - } - this->drag_active = false; -} - -void UnitSelection::clear() { - for (auto u : this->units) { - if (u.second.is_valid()) { - u.second.get()->selected = false; - } - } - this->units.clear(); - this->selection_type = selection_type_t::nothing; -} - -void UnitSelection::toggle_unit(const Player &player, Unit *u, bool append) { - if (this->units.count(u->id) == 0) { - this->add_unit(player, u, append); - } - else { - this->remove_unit(u); - } -} - -void UnitSelection::add_unit(const Player &player, Unit *u, bool append) { - // Only select resources and units with hitpoints > 0 - if (u->has_attribute(attr_type::resource) || (u->has_attribute(attr_type::damaged) && u->get_attribute().hp > 0)) { - selection_type_t unit_type = get_unit_selection_type(player, u); - int unit_type_i = static_cast(unit_type); - int selection_type_i = static_cast(this->selection_type); - - if (unit_type_i > selection_type_i) { - // Don't select this unit as it has too low priority - return; - } - - if (unit_type_i < selection_type_i) { - // Upgrade selection to a higher priority selection - this->clear(); - this->selection_type = unit_type; - } - - // Can't select multiple enemies at once - if (not(unit_type == selection_type_t::own_units || (unit_type == selection_type_t::own_buildings && append))) { - this->clear(); - this->selection_type = unit_type; // Clear resets selection_type - } - - // Finally, add the unit to the selection - u->selected = true; - this->units[u->id] = u->get_ref(); - } -} - -void UnitSelection::remove_unit(Unit *u) { - u->selected = false; - this->units.erase(u->id); - - if (this->units.empty()) { - this->selection_type = selection_type_t::nothing; - } -} - -selection_type_t UnitSelection::get_selection_type() { - return this->selection_type; -} - -void UnitSelection::kill_unit(const Player &player) { - if (this->units.empty()) { - return; - } - - UnitReference &ref = this->units.begin()->second; - if (!ref.is_valid()) { - this->units.erase(this->units.begin()); - - if (this->units.empty()) { - this->selection_type = selection_type_t::nothing; - } - } - else { - Unit *u = ref.get(); - - // Check color: you can only kill your own units - if (u->is_own_unit(player)) { - this->remove_unit(u); - u->delete_unit(); - } - } -} - -bool UnitSelection::contains_builders(const Player &player) { - for (auto &it : units) { - if (it.second.is_valid() && it.second.get()->get_ability(ability_type::build) && it.second.get()->is_own_unit(player)) { - return true; - } - } - return false; -} - -bool UnitSelection::contains_military(const Player &player) { - for (auto &it : units) { - if (it.second.is_valid() && !it.second.get()->get_ability(ability_type::build) && it.second.get()->is_own_unit(player)) { - return true; - } - } - return false; -} - -void UnitSelection::select_point(const Player &player, Terrain *terrain, coord::camgame point, bool append) { - //if (!append) { - // this->clear(); - //} - // - //if (!terrain) { - // log::log(MSG(warn) << "selection terrain not specified"); - // return; - //} - // - //// find any object at selected point - //auto obj = terrain->obj_at_point(point.to_phys3(this->engine->coord)); - //if (obj) { - // this->toggle_unit(player, &obj->unit); - //} -} - -void UnitSelection::select_space(const Player &player, Terrain *terrain, coord::camgame point0, coord::camgame point1, bool append) { - if (!append) { - this->clear(); - } - - coord::camgame min{std::min(point0.x, point1.x), std::min(point0.y, point1.y)}; - coord::camgame max{std::max(point0.x, point1.x), std::max(point0.y, point1.y)}; - - // look at each tile in the range and find all units - //for (coord::tile check_pos : tiles_in_range(point0, point1, this->engine->coord)) { - // TileContent *tc = terrain->get_data(check_pos); - // if (tc) { - // // find objects within selection box - // for (auto unit_location : tc->obj) { - // coord::camgame pos = unit_location->pos.draw.to_camgame(this->engine->coord); - // - // if ((pos.x > min.x and pos.x < max.x) and (pos.y > min.y and pos.y < max.y)) { - // this->add_unit(player, &unit_location->unit, append); - // } - // } - // } - //} -} - -void UnitSelection::all_invoke(Command &cmd) { - for (auto u : this->units) { - if (u.second.is_valid() && u.second.get()->is_own_unit(cmd.player)) { - // allow unit to find best use of the command - // TODO: queue_cmd returns ability which allows playing of sound - u.second.get()->queue_cmd(cmd); - } - } -} - -selection_type_t UnitSelection::get_unit_selection_type(const Player &player, Unit *u) { - bool is_building = u->has_attribute(attr_type::building); - - // Check owner - // TODO implement allied units - if (u->is_own_unit(player)) { - return is_building ? selection_type_t::own_buildings : selection_type_t::own_units; - } - else { - return is_building ? selection_type_t::enemy_building : selection_type_t::enemy_unit; - } -} - -std::vector tiles_in_range(coord::camgame p1, coord::camgame p2, const coord::CoordManager &coord) { - // the remaining corners - coord::camgame p3 = coord::camgame{p1.x, p2.y}; - coord::camgame p4 = coord::camgame{p2.x, p1.y}; - coord::camgame pts[4]{p1, p2, p3, p4}; - - // find the range of tiles covered - coord::tile t1 = pts[0].to_tile(coord); - coord::tile min = t1; - coord::tile max = t1; - - for (unsigned i = 1; i < 4; ++i) { - coord::tile t = pts[i].to_tile(coord); - min.ne = std::min(min.ne, t.ne); - min.se = std::min(min.se, t.se); - max.ne = std::max(max.ne, t.ne); - max.se = std::max(max.se, t.se); - } - - // find all units in the boxed region - std::vector tiles; - coord::tile check_pos = min; - while (check_pos.ne <= max.ne) { - while (check_pos.se <= max.se) { - tiles.push_back(check_pos); - check_pos.se += 1; - } - check_pos.se = min.se; - check_pos.ne += 1; - } - return tiles; -} - -} // namespace openage diff --git a/libopenage/unit/selection.h b/libopenage/unit/selection.h deleted file mode 100644 index e946266009..0000000000 --- a/libopenage/unit/selection.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include - -#include "../coord/pixel.h" -#include "../handlers.h" -#include "ability.h" -#include "unit_container.h" - -namespace openage { - -class LegacyEngine; -class Terrain; - -std::vector tiles_in_range(coord::camgame p1, coord::camgame p2, const coord::CoordManager &coord); - -/** - * A selection of units always has a type - * You can't select units from multiple types at once - * Earlier types have precedence over later types - * - * So you can select a group of units, or a building (or multiple if append is on) - * Enemy units, enemy buildings and other objects may only be selected one at a time - */ -enum class selection_type_t { - own_units, - own_buildings, - enemy_unit, - enemy_building, - nothing -}; - -/** - * a user interface component allowing control of a selected group - */ -class UnitSelection : public HudHandler { -public: - UnitSelection(LegacyEngine *engine); - - bool on_drawhud() override; - void drag_begin(coord::camgame pos); - void drag_update(coord::camgame pos); - void drag_release(const Player &player, Terrain *terrain, bool append = false); - - void clear(); - - void toggle_unit(const Player &player, Unit *u, bool append = false); - void add_unit(const Player &player, Unit *u, bool append = false); - void remove_unit(Unit *u); - - selection_type_t get_selection_type(); - - /** - * kill a single unit in the selection - */ - void kill_unit(const Player &player); - - /** - * checks whether there are any builders in the selection - */ - bool contains_builders(const Player &player); - - /** - * checks whether there are any military units (i.e. non-builders) in the selection - */ - bool contains_military(const Player &player); - - /** - * point unit selection - */ - void select_point(const Player &player, Terrain *terrain, coord::camgame p, bool append = false); - - /** - * boxed unit selection - */ - void select_space(const Player &player, Terrain *terrain, coord::camgame p1, coord::camgame p2, bool append = false); - - /** - * uses command on every selected unit - */ - void all_invoke(Command &cmd); - - int get_units_count() const { - return this->units.size(); - } - - const UnitReference &get_first_unit() const { - return this->units.begin()->second; - } - -private: - /** - * Check whether the currently selected units may be selected at the same time - * If not, deselect some units - * This is the order in which the checks occur: - * Own units > own building(s) > enemy unit > enemy building > any object - * - * So you can select a group of units, or a building (or multiple if append is on) - * Enemy units, enemy buildings and other objects may only be selected one at a time - */ - selection_type_t get_unit_selection_type(const Player &player, Unit *); - - std::unordered_map units; - selection_type_t selection_type; - - bool drag_active; - // TODO: turn these into a C++17 optional - coord::camgame start = {0, 0}, end = {0, 0}; - - /** - * Engine where this selection is attached to. - */ - LegacyEngine *engine; -}; - -} // namespace openage diff --git a/libopenage/unit/type_pair.cpp b/libopenage/unit/type_pair.cpp deleted file mode 100644 index 725f63c072..0000000000 --- a/libopenage/unit/type_pair.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#include "type_pair.h" - -namespace openage { - -UnitType::UnitType() {} - -bool UnitType::match(Unit *) { - // TODO: types - return true; -} - -TypePair::TypePair() {} - -} // namespace openage diff --git a/libopenage/unit/type_pair.h b/libopenage/unit/type_pair.h deleted file mode 100644 index 7b96cd45bd..0000000000 --- a/libopenage/unit/type_pair.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015-2016 the openage authors. See copying.md for legal info. - -#pragma once - -namespace openage { - -/** - * units in aoc have a class and a type - */ -class UnitType { -public: - UnitType(); - - /** - * the unit must have either same class or id as this - */ - bool match(class Unit *); - -private: - unsigned int class_id; - unsigned int unit_type_id; -}; - -/** - * many effects in aoc use a pair structure - * such as attack bonuses, armour and selection commands - */ -class TypePair { -public: - TypePair(); - -private: - UnitType a, b; - -}; - -} // namespace openage diff --git a/libopenage/unit/unit.cpp b/libopenage/unit/unit.cpp deleted file mode 100644 index 483d651bd1..0000000000 --- a/libopenage/unit/unit.cpp +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#include -#include -#include - -#include "../legacy_engine.h" -#include "../terrain/terrain.h" - -#include "ability.h" -#include "action.h" -#include "command.h" -#include "producer.h" -#include "unit.h" -#include "unit_texture.h" - -namespace openage { - -Unit::Unit(UnitContainer *c, id_t id) : - id{id}, - unit_type{nullptr}, - selected{false}, - pop_destructables{false}, - container(c) {} - -Unit::~Unit() { - // remove any used location from the map - if (this->location) { - this->location->remove(); - } -} - -void Unit::reset() { - this->ability_available.clear(); - this->action_stack.clear(); - this->pop_destructables = false; -} - -bool Unit::has_action() const { - return !this->action_stack.empty(); -} - -bool Unit::accept_commands() const { - return (this->has_action() && this->top()->allow_control()); -} - -bool Unit::is_own_unit(const Player &player) { - return player.owns(*this); -} - -UnitAction *Unit::top() const { - if (this->action_stack.empty()) { - throw Error{MSG(err) << "Unit stack empty - no top action exists"}; - } - return this->action_stack.back().get(); -} - -UnitAction *Unit::before(const UnitAction *action) const { - auto start = std::find_if( - std::begin(this->action_stack), - std::end(this->action_stack), - [action](const std::unique_ptr &a) { - return action == a.get(); - }); - - if (start != std::begin(this->action_stack) && start != std::end(this->action_stack)) { - return (*(start - 1)).get(); - } - return nullptr; -} - -bool Unit::update(time_nsec_t lastframe_duration) { - // if unit is not on the map then do nothing - if (!this->location) { - return true; - } - - // unit is dead (not player controlled) - if (this->pop_destructables) { - this->erase_after( - [](std::unique_ptr &e) { - return e->allow_interrupt() || e->allow_control(); - }, - false); - } - - /* - * the active action is on top - */ - if (this->has_action()) { - // TODO: change the entire unit action timing - // to a higher resolution like nsecs or usecs. - - // time as float, in milliseconds. - auto time_elapsed = lastframe_duration / 1e6; - - this->top()->update(time_elapsed); - - // the top primary action specifies whether - // secondary actions are updated - if (this->top()->allow_control()) { - this->update_secondary(time_elapsed); - } - - // check completion of all primary actions, - // pop completed actions and anything above - this->erase_after( - [](std::unique_ptr &e) { - return e->completed(); - }); - } - - // apply new queued commands - this->apply_all_cmds(); - - return true; -} - -void Unit::update_secondary(int64_t time_elapsed) { - // update secondary actions and remove when completed - auto position_it = std::remove_if( - std::begin(this->action_secondary), - std::end(this->action_secondary), - [time_elapsed](std::unique_ptr &action) { - action->update(time_elapsed); - return action->completed(); - }); - this->action_secondary.erase(position_it, std::end(this->action_secondary)); -} - -void Unit::apply_all_cmds() { - std::lock_guard lock(this->command_queue_lock); - while (!this->command_queue.empty()) { - auto &action = this->command_queue.front(); - this->apply_cmd(action.first, action.second); - this->command_queue.pop(); - } -} - - -void Unit::apply_cmd(std::shared_ptr ability, const Command &cmd) { - // if the interrupt flag is set, discard ongoing actions - bool is_direct = cmd.has_flag(command_flag::interrupt); - if (is_direct) { - this->stop_actions(); - } - if (ability->can_invoke(*this, cmd)) { - ability->invoke(*this, cmd, is_direct); - } -} - - -void Unit::draw(const LegacyEngine &engine) { - // the top action decides the graphic type and action - this->draw(this->location.get(), this->top()->current_graphics(), engine); -} - - -void Unit::draw(TerrainObject *loc, const graphic_set &grpc, const LegacyEngine &engine) { - ENSURE(loc != nullptr, "there should always be a location for a placed unit"); - - auto top_action = this->top(); - auto draw_graphic = top_action->type(); - if (grpc.count(draw_graphic) == 0) { - this->log(MSG(warn) << "Graphic not available"); - return; - } - - // the texture to draw with - auto draw_texture = grpc.at(draw_graphic); - if (!draw_texture) { - this->log(MSG(warn) << "Graphic null"); - return; - } - - // frame specified by the current action - auto draw_frame = top_action->current_frame(); - this->draw(loc->pos.draw, draw_texture, draw_frame, engine); - - // draw a shadow if the graphic is available - if (grpc.count(graphic_type::shadow) > 0) { - auto draw_shadow = grpc.at(graphic_type::shadow); - if (draw_shadow) { - // position without height component - // TODO: terrain elevation - coord::phys3 shadow_pos = loc->pos.draw; - shadow_pos.up = 0; - this->draw(shadow_pos, draw_shadow, draw_frame, engine); - } - } - - // draw debug details - top_action->draw_debug(engine); -} - - -void Unit::draw(coord::phys3 draw_pos, std::shared_ptr graphic, unsigned int frame, const LegacyEngine &engine) { - // players color if available - unsigned color = 0; - if (this->has_attribute(attr_type::owner)) { - auto &own_attr = this->get_attribute(); - color = own_attr.player.color; - } - - // check if object has a direction - if (this->has_attribute(attr_type::direction)) { - // directional textures - auto &d_attr = this->get_attribute(); - coord::phys3_delta draw_dir = d_attr.unit_dir; - // graphic->draw(engine.coord, draw_pos.to_camgame(engine.coord), draw_dir, frame, color); - } - else { - // graphic->draw(engine.coord, draw_pos.to_camgame(engine.coord), frame, color); - } -} - -void Unit::give_ability(std::shared_ptr ability) { - this->ability_available.emplace(std::make_pair(ability->type(), ability)); -} - -UnitAbility *Unit::get_ability(ability_type type) { - if (this->ability_available.count(type) > 0) { - return this->ability_available[type].get(); - } - return nullptr; -} - -void Unit::push_action(std::unique_ptr action, bool force) { - // unit not being deleted -- can control unit - if (force || this->accept_commands()) { - this->action_stack.push_back(std::move(action)); - } -} - -void Unit::secondary_action(std::unique_ptr action) { - this->action_secondary.push_back(std::move(action)); -} - -void Unit::add_attribute(std::shared_ptr attr) { - this->attributes.add(attr); -} - -void Unit::add_attributes(const Attributes &attr) { - this->attributes.add_copies(attr); -} - -void Unit::add_attributes(const Attributes &attr, bool shared, bool unshared) { - this->attributes.add_copies(attr, shared, unshared); -} - -bool Unit::has_attribute(attr_type type) const { - return this->attributes.has(type); -} - -std::shared_ptr Unit::queue_cmd(const Command &cmd) { - std::lock_guard lock(this->command_queue_lock); - - // following the specified ability priority - // find suitable ability for this target if available - for (auto &ability : ability_priority) { - auto pair = this->ability_available.find(ability); - if (pair != this->ability_available.end() && cmd.ability()[static_cast(pair->first)] && pair->second->can_invoke(*this, cmd)) { - command_queue.push(std::make_pair(pair->second, cmd)); - return pair->second; - } - } - return nullptr; -} - -void Unit::delete_unit() { - this->pop_destructables = true; -} - -void Unit::stop_gather() { - this->erase_after( - [](std::unique_ptr &e) { - return e->name() == "gather"; - }, - false); -} - -void Unit::stop_actions() { - // work around for workers continuing to work after retasking - if (this->has_attribute(attr_type::worker)) { - this->stop_gather(); - } - - // discard all interruptible tasks - this->erase_after( - [](std::unique_ptr &e) { - return e->allow_interrupt(); - }); -} - -UnitReference Unit::get_ref() { - return UnitReference(this->container, id, this); -} - -UnitContainer *Unit::get_container() const { - return this->container; -} - -std::string Unit::logsource_name() { - return "Unit " + std::to_string(this->id); -} - -void Unit::erase_after(std::function &)> func, bool run_completed) { - auto position_it = std::find_if( - std::begin(this->action_stack), - std::end(this->action_stack), - func); - - if (position_it != std::end(this->action_stack)) { - auto completed_action = std::move(*position_it); - - // erase from the stack - this->action_stack.erase(position_it, std::end(this->action_stack)); - - // perform any completion actions - if (run_completed) { - completed_action->on_completion(); - } - } -} - -} // namespace openage diff --git a/libopenage/unit/unit.h b/libopenage/unit/unit.h deleted file mode 100644 index 01416a6ac8..0000000000 --- a/libopenage/unit/unit.h +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2014-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include - -#include "../coord/phys.h" -#include "../handlers.h" -#include "../log/logsource.h" -#include "../terrain/terrain_object.h" -#include "../util/timing.h" -#include "ability.h" -#include "attribute.h" -#include "attributes.h" -#include "command.h" -#include "unit_container.h" - - -namespace openage { - -class UnitAbility; -class UnitAction; - -/** - * A game object with current state represented by a stack of actions - * since this class represents both unit and building objects it may be better to - * name as GameObject - * - * it is possible that abilities are not required here and they could be moved - * to selection controller -- units only need the attributes - */ -class Unit : public log::LogSource { -public: - Unit(UnitContainer *c, id_t id); - - /** - * unit cleanup will delete terrain object - */ - virtual ~Unit(); - - /** - * this units unique id value - */ - const id_t id; - - /** - * type of this object, this is set by the the UnitType which - * was most recently applied to this unit - */ - const UnitType *unit_type; - - /** - * should selection features be drawn - * TODO: should be a pointer to selection to be updated - * when unit is removed, or null if not selected - */ - bool selected; - - /** - * space on the map used by this unit - * null if the object is not yet placed or garrisoned - * TODO: make private field - */ - std::unique_ptr location; - - /** - * constructs a new location for this unit replacing any - * existing locatio - * - * uses same args as the location constructor - * except the first which will filled automatically - */ - template - void make_location(Arg... args) { - // remove any existing location first - if (this->location) { - this->location->remove(); - } - - // since Unit is a friend of the location - // make_shared will not work - this->location = std::unique_ptr(new T(*this, args...)); - } - - /** - * removes all actions and abilities - * current attributes are kept - */ - void reset(); - - /** - * checks the entity has an action, if it has no action it should be removed from the game - * @return true if the entity currently has an action - */ - bool has_action() const; - - /** - * true when the unit is alive and able to add new actions - */ - bool accept_commands() const; - - /** - * checks whether the current player is the owner of this unit - */ - bool is_own_unit(const Player &player); - - /** - * returns the current action on top of the stack - */ - UnitAction *top() const; - - /** - * returns action under the passed action in the stack - * returns null if stack size is less than 2 - */ - UnitAction *before(const UnitAction *action) const; - - /** - * update this object using the action currently on top of the stack - */ - bool update(time_nsec_t lastframe_duration); - - /** - * draws this action by taking the graphic type of the top action - * the graphic is found from the current graphic set - * - * this function should be used for most draw purposes - */ - void draw(const LegacyEngine &engine); - - /** - * an generalized draw function which is useful for drawing annexes - */ - void draw(TerrainObject *loc, const graphic_set &graphics, const LegacyEngine &engine); - - /** - * draws with a specific graphic and frame - */ - void draw(coord::phys3 draw_pos, std::shared_ptr graphic, unsigned int frame, const LegacyEngine &engine); - - /** - * adds an available ability to this unit - * this turns targeted objects into actions which are pushed - * onto the stack, eg. targeting a relic may push a collect relic action - */ - void give_ability(std::shared_ptr); - - /** - * get ability with specified type, null if not available - * - * To invoke commands use the invoke function instead - */ - UnitAbility *get_ability(ability_type type); - - /** - * adds a new action on top of the action stack - * will be performed immediately - */ - void push_action(std::unique_ptr action, bool force = false); - - /** - * adds a secondary action which is always updated - */ - void secondary_action(std::unique_ptr action); - - /** - * give a new attribute this this unit - * this is used to set things like color, hitpoints and speed - */ - void add_attribute(std::shared_ptr attr); - - /** - * Give new attributes to this unit. - * This is used to add the default attributes - */ - void add_attributes(const Attributes &attr); - - /** - * Give new attributes to this unit. - * If shared is false, shared attributes are ignored. - * If unshared is false, unshared attributes are ignored. - */ - void add_attributes(const Attributes &attr, bool shared, bool unshared); - - /** - * returns whether attribute is available - */ - bool has_attribute(attr_type type) const; - - /** - * returns attribute based on templated value - */ - template - Attribute &get_attribute() { - return *reinterpret_cast *>(attributes.get(T).get()); - // TODO change to (templates errors) - //return attributes.get(); - } - - /** - * queues a command to be applied to this unit on the next update - * - * @return the ability which will apply the command if an action was created - * otherwise nullptr is returned when no ability can handle the command - */ - std::shared_ptr queue_cmd(const Command &cmd); - - /** - * removes all gather actions without calling their on_complete actions - * this cancels the gathering action completely - */ - void stop_gather(); - - /** - * removes all actions above and including the first interuptable action - * this will stop any of the units current moving or attacking actions - * a direct command from the user will invoke this function - */ - void stop_actions(); - - /** - * begins unit removal by popping some actions - * - * this is the action that occurs when pressing the delete key - * which plays death sequence and does not remove instantly - */ - void delete_unit(); - - /** - * get a reference which can check against the container - * to ensure this object still exists - */ - UnitReference get_ref(); - - /** - * the container used when constructing this unit - */ - UnitContainer *get_container() const; - - /** - * Returns the unit's name as the LogSource name. - */ - std::string logsource_name() override; - - /** - * Unit attributes include color, hitpoints, speed, objects garrisoned etc - * contains 0 or 1 values for each type - */ - Attributes attributes; - -private: - /** - * ability available -- actions that this entity - * can perform when controlled - */ - std::unordered_map> ability_available; - - - /** - * action stack -- top action determines graphic to be drawn - */ - std::vector> action_stack; - - - /** - * secondary actions are always updated - */ - std::vector> action_secondary; - - - /** - * queue commands to be applied on the next update - */ - std::queue, const Command>> command_queue; - - /** - * mutex controlling updates to the command queue - */ - std::mutex command_queue_lock; - - - /** - * pop any destructable actions on the next update cycle - * and prevent additional actions being added - */ - bool pop_destructables; - - /** - * the container that updates this unit - */ - UnitContainer *container; - - /** - * applies new commands as part of the units update process - */ - void apply_all_cmds(); - - /** - * applies one command using a chosen ability - * locks the command queue mutex while operating - */ - void apply_cmd(std::shared_ptr ability, const Command &cmd); - - /** - * update all secondary actions - */ - void update_secondary(int64_t time_elapsed); - - /** - * erase from action specified by func to the end of the stack - * all actions erased will have the on_complete function called - * - * @param run_completed usually each action has an on_complete() function called when it is removed - * but when run_completed is false this on_complete() function is not called for all popped actions - */ - void erase_after(std::function &)> func, bool run_completed = true); -}; - -} // namespace openage diff --git a/libopenage/unit/unit_container.cpp b/libopenage/unit/unit_container.cpp deleted file mode 100644 index 672fedacd9..0000000000 --- a/libopenage/unit/unit_container.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2014-2019 the openage authors. See copying.md for legal info. - -#include "unit_container.h" - -#include - -#include "../log/log.h" -#include "../terrain/terrain_object.h" -#include "producer.h" -#include "unit.h" - - -namespace openage { - -reference_data::reference_data(const UnitContainer *c, id_t id, Unit *u) - : - container{c}, - unit_id{id}, - unit_ptr{u} { - if (!u) { - throw Error{MSG(err) << "Cannot reference null unit pointer"}; - } -} - - -UnitReference::UnitReference() - : - data{nullptr} {} - - -UnitReference::UnitReference(const UnitContainer *c, id_t id, Unit *u) - : - data{std::make_shared(c, id, u)} {} - - -bool UnitReference::is_valid() const { - return this->data && - this->data->container->valid_id(this->data->unit_id); -} - - -Unit *UnitReference::get() const { - if (!this->is_valid()) { - throw Error{MSG(err) << "Unit reference is no longer valid"}; - } - return this->data->unit_ptr; -} - - -UnitContainer::UnitContainer() - : - next_new_id{1} {} - - -UnitContainer::~UnitContainer() = default; - - -void UnitContainer::reset() { - this->live_units.clear(); -} - -void UnitContainer::set_terrain(std::shared_ptr &t) { - this->terrain = t; -} - -std::shared_ptr UnitContainer::get_terrain() const { - if (this->terrain.expired()) { - throw Error{MSG(err) << "Terrain has expired"}; - } - return this->terrain.lock(); -} - - -bool UnitContainer::valid_id(id_t id) const { - return (this->live_units.count(id) > 0); -} - - -UnitReference UnitContainer::get_unit(id_t id) { - if (this->valid_id(id)) { - return UnitReference(this, id, this->live_units[id].get()); - } - else { - return UnitReference(this, id, nullptr); - } -} - -UnitReference UnitContainer::new_unit() { - auto id = next_new_id; - next_new_id += 1; - - this->live_units.emplace(id, std::make_unique(this, id)); - return this->live_units[id]->get_ref(); -} - -UnitReference UnitContainer::new_unit(UnitType &type, - Player &owner, - coord::phys3 position) { - - auto new_id = next_new_id; - next_new_id += 1; - - auto newobj = std::make_unique(this, new_id); - - // try placing unit at this location - auto terrain_shared = this->get_terrain(); - auto placed = type.place(newobj.get(), terrain_shared, position); - if (placed) { - type.initialise(newobj.get(), owner); - owner.active_unit_added(newobj.get()); // TODO change, move elsewhere - auto id = newobj->id; - this->live_units.emplace(id, std::move(newobj)); - return this->live_units[id]->get_ref(); - } - return UnitReference(); // is not valid -} - -UnitReference UnitContainer::new_unit(UnitType &type, - Player &owner, - TerrainObject *other) { - auto new_id = next_new_id; - next_new_id += 1; - - auto newobj = std::make_unique(this, new_id); - - // try placing unit - TerrainObject *placed = type.place_beside(newobj.get(), other); - if (placed) { - type.initialise(newobj.get(), owner); - owner.active_unit_added(newobj.get()); // TODO change, move elsewhere - auto id = newobj->id; - this->live_units.emplace(id, std::move(newobj)); - return this->live_units[id]->get_ref(); - } - return UnitReference(); // is not valid -} - - -bool dispatch_command(id_t, const Command &) { - return true; -} - -bool UnitContainer::update_all(time_nsec_t lastframe_duration) { - // update everything and find objects with no actions - std::vector to_remove; - - for (auto &obj : this->live_units) { - obj.second->update(lastframe_duration); - - if (not obj.second->has_action()) { - to_remove.push_back(obj.first); - } - } - - // cleanup and removal of objects - for (auto &obj : to_remove) { - - // unique pointer triggers cleanup - this->live_units.erase(obj); - } - return true; -} - -std::vector UnitContainer::all_units() { - std::vector result; - for (auto &u : this->live_units) { - result.push_back(u.second.get()); - } - return result; -} - -} // namespace openage diff --git a/libopenage/unit/unit_container.h b/libopenage/unit/unit_container.h deleted file mode 100644 index 89c6848990..0000000000 --- a/libopenage/unit/unit_container.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2014-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include - -#include "../coord/tile.h" -#include "../handlers.h" -#include "../util/timing.h" - - -namespace openage { - -class Command; -class Player; -class Terrain; -class TerrainObject; -class Unit; -class UnitContainer; -class UnitType; - - -/** - * Type used to identify each single unit in the game. - */ -using id_t = unsigned long int; - - -/** - * immutable reference data - */ -struct reference_data { - reference_data(const UnitContainer *c, id_t id, Unit *); - - const UnitContainer *const container; - const id_t unit_id; - Unit *const unit_ptr; -}; - -/** - * Reference to a single unit, which may have been removed - * from the game, check is_valid() before calling get() - */ -class UnitReference { -public: - - /** - * create an invalid reference - */ - UnitReference(); - - /** - * create referece by unit id - */ - UnitReference(const UnitContainer *c, id_t id, Unit *); - - bool is_valid() const; - Unit *get() const; - -private: - - /** - * The default copy constructor and assignment - * will just copy the shared pointer - */ - std::shared_ptr data; -}; - -/** - * the list of units that are currently in use - * will also give a view of the current game state for networking in later milestones - */ -class UnitContainer { -public: - UnitContainer(); - ~UnitContainer(); - - void reset(); - - /** - * sets terrain to initialise units on - */ - void set_terrain(std::shared_ptr &t); - - /** - * returns the terrain which units are placed on - */ - std::shared_ptr get_terrain() const; - - /** - * checks the id is valid - */ - bool valid_id(id_t id) const; - - /** - * returns a reference to a unit - */ - UnitReference get_unit(id_t id); - - /** - * creates a new unit without initialising - */ - UnitReference new_unit(); - - /** - * adds a new unit to the container and initialises using a unit type - */ - UnitReference new_unit(UnitType &type, Player &owner, coord::phys3 position); - - /** - * adds a new unit to the container and initialises using a unit type - * places outside an existing object using the player of that object - */ - UnitReference new_unit(UnitType &type, Player &owner, TerrainObject *other); - - /** - * give a command to a unit -- unit creation and deletion should be done as commands - */ - bool dispatch_command(id_t to_id, const Command &cmd); - - /** - * update dispatched by the game engine on each physics tick. - * this will update all game objects. - */ - bool update_all(time_nsec_t lastframe_duration); - - /** - * gets a list of all units in the container - */ - std::vector all_units(); - -private: - id_t next_new_id; - - /** - * mapping unit ids to unit objects - */ - std::unordered_map> live_units; - - /** - * Terrain for initialising new units - */ - std::weak_ptr terrain; -}; - -} // namespace openage diff --git a/libopenage/unit/unit_texture.cpp b/libopenage/unit/unit_texture.cpp deleted file mode 100644 index a146f471b2..0000000000 --- a/libopenage/unit/unit_texture.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "unit_texture.h" - -#include -#include - -#include "../coord/phys.h" -#include "../coord/pixel.h" -#include "../gamestate/old/game_spec.h" -#include "../log/log.h" -#include "../texture.h" -#include "../util/math.h" -#include "../util/math_constants.h" - - -namespace openage { - -UnitTexture::UnitTexture(GameSpec &spec, uint16_t graphic_id, bool delta) - : - UnitTexture{spec, spec.get_graphic_data(graphic_id), delta} {} - -UnitTexture::UnitTexture(GameSpec &spec, const gamedata::graphic *graphic, bool delta) - : - id{graphic->graphic_id}, - sound_id{graphic->sound_id}, - frame_count{graphic->frame_count}, - angle_count{graphic->angle_count}, - mirroring_mode{graphic->mirroring_mode}, - frame_rate{graphic->frame_rate}, - use_up_angles{graphic->mirroring_mode == 24}, - use_deltas{delta}, - texture{nullptr}, - draw_this{true}, - sound{nullptr}, - delta_id{graphic->graphic_deltas.data} { - this->initialise(spec); -} - -bool UnitTexture::is_valid() const { - return texture; -} - -coord::viewport UnitTexture::size() const { - return coord::viewport{this->texture->w, this->texture->h}; -} - -void UnitTexture::sample(const coord::CoordManager &coord, const coord::camhud &draw_pos, unsigned color) const { - - // draw delta list first - for (auto &d : this->deltas) { - coord::camhud_delta dlt = coord::camhud_delta{d.second.x, d.second.y}; - d.first->sample(coord, draw_pos + dlt, color); - } - - // draw texture - if (this->draw_this) { - this->texture->draw(coord, draw_pos, PLAYERCOLORED, false, 0, color); - } -} - -void UnitTexture::draw(const coord::CoordManager &coord, const coord::camgame &draw_pos, unsigned int frame, unsigned color) const { - - // draw delta list first - for (auto &d : this->deltas) { - d.first->draw(coord, draw_pos + d.second, frame, color); - } - - // draw texture - if (this->draw_this) { - unsigned int to_draw = frame % this->texture->get_subtexture_count(); - this->texture->draw(coord, draw_pos, PLAYERCOLORED, false, to_draw, color); - } -} - -void UnitTexture::draw(const coord::CoordManager &coord, const coord::camgame &draw_pos, coord::phys3_delta &dir, unsigned int frame, unsigned color) const { - unsigned int frame_to_use = frame; - if (this->use_up_angles) { - // up 1 => tilt 0 - // up -1 => tilt 1 - // up has a scale 5 times smaller - double len = math::hypot3(dir.ne.to_double(), dir.se.to_double(), dir.up.to_double()/5); - double up = dir.up.to_double()/(5.0 * len); - frame_to_use = (0.5 - (0.5 * up)) * this->frame_count; - } - else if (this->sound && frame == 0.0) { - this->sound->play(); - } - - // the index for the current direction - unsigned int angle = dir_group(dir, this->angle_count); - - // mirroring is used to make additional image sets - bool mirror = false; - if (this->angles_included <= angle) { - // this->angles_included <= angle < this->angle_count - angle = this->top_frame - angle; - mirror = true; - } - - // draw delta list first - for (auto &d : this->deltas) { - d.first->draw(coord, draw_pos + d.second, dir, frame, color); - } - - if (this->draw_this) { - unsigned int to_draw = this->subtexture(this->texture, angle, frame_to_use); - this->texture->draw(coord, draw_pos, PLAYERCOLORED, mirror, to_draw, color); - } -} - -void UnitTexture::initialise(GameSpec &spec) { - this->texture = spec.get_texture(this->id); - this->sound = spec.get_sound(this->sound_id); - if (not is_valid()) { - this->draw_this = false; - } - - // find deltas - if (this->use_deltas) for (auto d : this->delta_id) { - if (spec.get_graphic_data(d.graphic_id)) { - auto ut = std::make_unique(spec, d.graphic_id, false); - if (ut->is_valid()) { - this->deltas.push_back({std::move(ut), coord::camgame_delta{d.offset_x, d.offset_y}}); - } - } - } - - if (this->draw_this) { - - // the graphic frame count includes deltas - unsigned int subtextures = this->texture->get_subtexture_count(); - if (subtextures >= this->frame_count) { - - // angles with graphic data - this->angles_included = subtextures / this->frame_count; - this->angles_mirrored = this->angle_count - this->angles_included; - this->safe_frame_count = this->frame_count; - } - else { - this->angles_included = 1; - this->angles_mirrored = 0; - this->safe_frame_count = subtextures; - } - - // find the top direction for mirroring over - this->top_frame = this->angle_count - (1 - (this->angles_included - this->angles_mirrored) / 2); - } -} - -unsigned int UnitTexture::subtexture(const Texture *t, unsigned int angle, unsigned int frame) const { - unsigned int tex_frames = t->get_subtexture_count(); - unsigned int count = tex_frames / this->angles_included; - unsigned int to_draw = angle * count + (frame % count); - if (tex_frames <= to_draw) { - log::log(MSG(err) << "Subtexture out of range (" << angle << ", " << frame << ")"); - return 0; - } - return to_draw; -} - -unsigned int dir_group(coord::phys3_delta dir, unsigned int angles) { - unsigned int first_angle = 5 * angles / 8; - - // normalise direction vector - double len = std::hypot(dir.ne, dir.se); - double dir_ne = static_cast(dir.ne) / len; - double dir_se = static_cast(dir.se) / len; - - // formula to find the correct angle - return static_cast( - round(angles * atan2(dir_se, dir_ne) * (math::INV_PI / 2)) - + first_angle - ) % angles; -} - - -} // namespace openage diff --git a/libopenage/unit/unit_texture.h b/libopenage/unit/unit_texture.h deleted file mode 100644 index 20efe9eede..0000000000 --- a/libopenage/unit/unit_texture.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include - -#include "../coord/phys.h" -#include "../gamedata/graphic_dummy.h" - -namespace openage { - -class GameSpec; -class Texture; -class Sound; - -/** - * Handling animated and directional textures based on the game - * graphics data. - * - * These objects handle the drawing of regular textures to use a - * unit's direction and include delta graphics. - * - * This type can also deal with playing position based game sounds. - */ -class UnitTexture { -public: - /** - * Delta option specifies whether the delta graphics are included. - * - * Note that the game data contains loops in delta links - * which mean recursive loading should be avoided - */ - UnitTexture(GameSpec &spec, uint16_t graphic_id, bool delta=true); - UnitTexture(GameSpec &spec, const gamedata::graphic *graphic, bool delta=true); - - /** - * const attributes of the graphic - */ - const int16_t id; - const int16_t sound_id; - const unsigned int frame_count; - const unsigned int angle_count; - const int16_t mirroring_mode; - const float frame_rate; - - /** - * draw object with vertical orientation (arrows) - * adding an addtion degree of orientation - */ - const bool use_up_angles; - - /** - * use delta information - */ - const bool use_deltas; - - /** - * invalid unit textures will cause errors if drawn - */ - bool is_valid() const; - - /** - * pixel size of this texture - */ - coord::viewport size() const; - - /** - * a sample drawing for hud - */ - void sample(const coord::CoordManager &coord, const coord::camhud &draw_pos, unsigned color=1) const; - - /** - * draw object with no direction - */ - void draw(const coord::CoordManager &coord, const coord::camgame &draw_pos, unsigned int frame, unsigned color) const; - - /** - * draw object with direction - */ - void draw(const coord::CoordManager &coord, const coord::camgame &draw_pos, coord::phys3_delta &dir, unsigned int frame, unsigned color) const; - - /** - * initialise graphic data - */ - void initialise(GameSpec &spec); - -private: - /** - * use a regular texture for drawing - */ - const Texture *texture; - - /** - * the above frame count covers the entire graphic (with deltas) - * the actual number in the base texture may be different - */ - unsigned int safe_frame_count; - unsigned int angles_included; - unsigned int angles_mirrored; - unsigned int top_frame; - - // avoid drawing missing graphics - bool draw_this; - const Sound *sound; - - // delta graphic ids - std::vector delta_id; - - // delta graphics - std::vector, coord::camgame_delta>> deltas; - - /** - * find which subtexture should be used for drawing this texture - */ - unsigned int subtexture(const Texture *t, unsigned int angle, unsigned int frame) const; -}; - -/** - * the set of images to used based on unit direction, - * usually 8 directions to draw for each unit (3 are mirrored) - * - * @param dir a world space direction, - * @param angles number of angles, usually 8 - * @param first_angle offset added to angle, modulo number of angles - * @return image set index - */ -unsigned int dir_group(coord::phys3_delta dir, unsigned int angles=8); - -} // namespace openage diff --git a/libopenage/unit/unit_type.cpp b/libopenage/unit/unit_type.cpp deleted file mode 100644 index bc760bd955..0000000000 --- a/libopenage/unit/unit_type.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#include "../gamestate/old/player.h" -#include "../terrain/terrain_object.h" -#include "../util/math_constants.h" -#include "action.h" -#include "unit.h" -#include "unit_container.h" -#include "unit_type.h" - -#include - -namespace openage { - -UnitTypeMeta::UnitTypeMeta(std::string name, int id, init_func f) - : - init{f}, - type_name{std::move(name)}, - type_id{id} { -} - -std::string UnitTypeMeta::name() const { - return this->type_name; -} - -int UnitTypeMeta::id() const { - return this->type_id; -} - -UnitType::UnitType(const Player &owner) - : - owner{owner}, - have_limit{math::INT_INF}, - had_limit{math::INT_INF} { -} - -void UnitType::reinitialise(Unit *unit, Player &player) { - // In case reinitialise is not implemented separately - - Attributes tmp; - // copy only unshared - tmp.add_copies(unit->attributes, false, true); - // initialise the new unit - this->initialise(unit, player); - // replace new unshared attributes with the old - unit->attributes.add_copies(tmp); -} - -bool UnitType::operator==(const UnitType &other) const { - return this->type_abilities == other.type_abilities; -} - -bool UnitType::operator!=(const UnitType &other) const { - return !(*this == other); -} - -UnitTexture *UnitType::default_texture() { - return this->graphics[graphic_type::standing].get(); -} - -TerrainObject *UnitType::place_beside(Unit *u, TerrainObject const *other) const { - if (!u || !other) { - return nullptr; - } - - // find the range of possible tiles - tile_range outline{other->pos.start - coord::tile_delta{1, 1}, - other->pos.end + coord::tile_delta{1, 1}, - other->pos.draw}; - - // find a free position adjacent to the object - auto terrain = other->get_terrain(); - for (coord::tile temp_pos : tile_list(outline)) { - TerrainChunk *chunk = terrain->get_chunk(temp_pos); - - if (chunk == nullptr) { - continue; - } - - auto placed = this->place(u, terrain, temp_pos.to_phys3(*terrain)); - if (placed) { - return placed; - } - } - return nullptr; -} - -void UnitType::copy_attributes(Unit *unit) const { - unit->add_attributes(this->default_attributes); -} - -void UnitType::upgrade(const std::shared_ptr &attr) { - this->default_attributes.add(attr); -} - -UnitType *UnitType::parent_type() const { - return this->owner.get_type(this->parent_id()); -} - -NyanType::NyanType(const Player &owner) - : - UnitType(owner) { - // TODO: the type should be given attributes and abilities -} - -NyanType::~NyanType() = default; - -int NyanType::id() const { - return 1; -} - -int NyanType::parent_id() const { - return -1; -} - -std::string NyanType::name() const { - return "Nyan"; -} - -void NyanType::initialise(Unit *unit, Player &) { - // removes all actions and abilities - unit->reset(); - - // initialise unit - unit->unit_type = this; - - // the parsed nyan data gives the list of attributes - // and abilities which are given to the unit - for (auto &ability : this->type_abilities) { - unit->give_ability(ability); - } - - // copy all attributes - this->copy_attributes(unit); - - // give idle action - unit->push_action(std::make_unique(unit), true); -} - -TerrainObject *NyanType::place(Unit *unit, std::shared_ptr terrain, coord::phys3 init_pos) const { - // the parsed nyan data gives the rules for terrain placement - // which includes valid terrains, base radius and shape - - unit->make_location(coord::tile_delta{1, 1}); - - // allow unit to go anywhere - unit->location->passable = [](const coord::phys3 &) { - return true; - }; - - // try to place the obj, it knows best whether it will fit. - if (unit->location->place(terrain, init_pos, object_state::placed)) { - return unit->location.get(); - } - - // placing at the given position failed - unit->log(MSG(dbg) << "failed to place object"); - return nullptr; -} - -} // namespace openage diff --git a/libopenage/unit/unit_type.h b/libopenage/unit/unit_type.h deleted file mode 100644 index 5e960915a3..0000000000 --- a/libopenage/unit/unit_type.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2015-2021 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include - -#include "../coord/phys.h" -#include "../gamestate/old/cost.h" -#include "attributes.h" - -namespace openage { - -class Player; -class Terrain; -class TerrainObject; -class Unit; -class UnitAbility; -class UnitContainer; -class UnitTexture; - - -/** - * an abstract unit type which is not yet owned by any player - */ -class UnitTypeMeta { -public: - using type_ptr = std::shared_ptr; - using init_func = std::function; - UnitTypeMeta(std::string name, int id, init_func f); - - std::string name() const; - - int id() const; - - /** - * creates the base unit type for a player - */ - const init_func init; - -private: - const std::string type_name; - const int type_id; - -}; - -/** - * UnitType has to main roles: - * - * initialise(unit, player) should be called on a unit to give it a type and the required attributes, abilities and initial actions - * of that type - * - * place(unit, terrain, initial position) is called to customise how the unit gets added to the world -- used to setup the TerrainObject location - * - * UnitType is connected to a player to allow independent tech levels - */ -class UnitType { -public: - UnitType(const Player &owner); - virtual ~UnitType() {} - - /** - * gets the unique id of this unit type - */ - virtual int id() const = 0; - - /** - * gets the parent id of this unit type - * which is used for village base and gather types - */ - virtual int parent_id() const = 0; - - /** - * gets the name of the unit type being produced - */ - virtual std::string name() const = 0; - - /** - * Initialize units attributes to this type spec - * - * This can be called using existing units to modify type - * Ensure that the unit has been placed before seting the units type - * - * TODO: make const - */ - virtual void initialise(Unit *, Player &) = 0; - - /** - * Initialize units shared attributes only to this type spec - * - * This can be called using existing units to modify type if the type - * Ensure that the unit has been placed before seting the units type - * - * TODO define if pure vitrual or not / should be in nyan? - */ - virtual void reinitialise(Unit *, Player &); - - /** - * set unit in place -- return if placement was successful - * - * This should be used when initially creating a unit or - * when a unit is ungarrsioned from a building or object - * TODO: make const - */ - virtual TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const = 0; - - /** - * compare if two types are the same - */ - bool operator==(const UnitType &other) const; - bool operator!=(const UnitType &other) const; - - /** - * Get a default texture for HUD drawing - */ - UnitTexture *default_texture(); - - /** - * similar to place but places adjacent to an existing object - */ - TerrainObject *place_beside(Unit *, TerrainObject const *) const; - - /** - * copy attributes of this unit type to a new unit instance - */ - void copy_attributes(Unit *unit) const; - - /** - * upgrades one attribute of this unit type - */ - void upgrade(const std::shared_ptr &attr); - - /** - * returns type matching parent_id() - */ - UnitType *parent_type() const; - - /** - * the player who owns this unit type - */ - const Player &owner; - - /** - * all instances of units made from this unit type - * this could allow all units of a type to be upgraded - */ - std::vector instances; - - /** - * abilities given to all instances - */ - std::vector> type_abilities; - - /** - * default attributes which get copied to new units - */ - Attributes default_attributes; - - /** - * The cost of the unit. - */ - ResourceCost cost; - - /** - * The max number of units of this type that a player can have at an instance. - * Use negative values for special cases. - */ - int have_limit; - - /** - * The max number of units of this type that a player can create. - * Use negative values for special cases. - */ - int had_limit; - - /** - * The set of graphics used for this type - */ - graphic_set graphics; - - /** - * The index of the icon representing this unit - */ - int icon; - - /** - * the square dimensions of the placement - */ - coord::tile_delta foundation_size; - - /** - * raw game data class of this unit instance - */ - gamedata::unit_classes unit_class; -}; - -/** - * An example of how nyan can work with the type system - */ -class NyanType: public UnitType { -public: - /** - * TODO: give the parsed nyan attributes - * to the constructor - */ - NyanType(const Player &owner); - virtual ~NyanType(); - - int id() const override; - int parent_id() const override; - std::string name() const override; - void initialise(Unit *, Player &) override; - TerrainObject *place(Unit *, std::shared_ptr, coord::phys3) const override; - -}; - -} // namespace openage diff --git a/libopenage/util/CMakeLists.txt b/libopenage/util/CMakeLists.txt index ac5b585f06..d278f4b427 100644 --- a/libopenage/util/CMakeLists.txt +++ b/libopenage/util/CMakeLists.txt @@ -2,7 +2,6 @@ add_sources(libopenage color.cpp compiler.cpp constinit_vector.cpp - csv.cpp enum.cpp enum_test.cpp externalprofiler.cpp @@ -20,10 +19,8 @@ add_sources(libopenage matrix_test.cpp misc.cpp misc_test.cpp - opengl.cpp os.cpp path.cpp - profiler.cpp quaternion.cpp quaternion_test.cpp repr.cpp diff --git a/libopenage/util/color.cpp b/libopenage/util/color.cpp index 5254606f74..fed90a54a4 100644 --- a/libopenage/util/color.cpp +++ b/libopenage/util/color.cpp @@ -1,4 +1,4 @@ -// Copyright 2013-2019 the openage authors. See copying.md for legal info. +// Copyright 2013-2023 the openage authors. See copying.md for legal info. #include "color.h" @@ -6,13 +6,6 @@ namespace openage::util { -col::col(gamedata::palette_color c) { - this->r = c.r; - this->g = c.g; - this->b = c.b; - this->a = c.a; -} - void col::use() { //TODO use glColor4b glColor4f(r / 255.f, g / 255.f, b / 255.f, a / 255.f); @@ -22,4 +15,4 @@ void col::use(float alpha) { glColor4f(r / 255.f, g / 255.f, b / 255.f, alpha); } -} // openage::util +} // namespace openage::util diff --git a/libopenage/util/color.h b/libopenage/util/color.h index 326b1a1e2d..ee7199a8b7 100644 --- a/libopenage/util/color.h +++ b/libopenage/util/color.h @@ -1,15 +1,14 @@ -// Copyright 2013-2021 the openage authors. See copying.md for legal info. +// Copyright 2013-2023 the openage authors. See copying.md for legal info. #pragma once -#include "../gamedata/color_dummy.h" namespace openage { namespace util { struct col { - col(unsigned r, unsigned g, unsigned b, unsigned a) : r{r}, g{g}, b{b}, a{a} {} - col(gamedata::palette_color c); + col(unsigned r, unsigned g, unsigned b, unsigned a) : + r{r}, g{g}, b{b}, a{a} {} unsigned r, g, b, a; @@ -17,4 +16,5 @@ struct col { void use(float alpha); }; -}} // openage::util +} // namespace util +} // namespace openage diff --git a/libopenage/util/csv.cpp b/libopenage/util/csv.cpp deleted file mode 100644 index e0bf825c3b..0000000000 --- a/libopenage/util/csv.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013-2023 the openage authors. See copying.md for legal info. - -#include "csv.h" - -#include - -#include "file.h" -#include "../error/error.h" -#include "../log/log.h" - - -namespace openage { -namespace util { - - -CSVCollection::CSVCollection(const Path &entryfile_path) { - - auto file = entryfile_path.open(); - log::log(DBG << "Loading csv collection: " << file); - - // The file format is defined in: - // openage/convert/dataformat/data_definition.py - // example: - // - // ### some/folder/and/filename.docx - // # irrelevant - // # comments - // data,stuff,moar,bla - - // store the currently read file name - std::string current_file; - - for (auto &line : file.get_lines()) { - // a new file starts: - if (line[0] == '#' and - line[1] == '#' and - line[2] == '#' and - line[3] == ' ') { - - // remove the "### " - current_file = (line.erase(0, 4)); - - // create a vector to put lines in - this->data.emplace(current_file, std::vector{}); - } - else { - if (line.empty() or line[0] == '#') { - continue; - } - - if (current_file.size() > 0) [[likely]] { - // add line to the current file linelist - this->data.at(current_file).push_back(line); - } - else { - throw Error{ - ERR << "csv collection content encountered " - << "without known target in " << entryfile_path - << ", linedata: " << line - }; - } - } - } - - log::log(INFO << "Loaded multi-csv file: " - << this->data.size() << " sub-files"); -} - -}} // openage::util diff --git a/libopenage/util/csv.h b/libopenage/util/csv.h deleted file mode 100644 index 88d5ea0322..0000000000 --- a/libopenage/util/csv.h +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2013-2017 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "../error/error.h" -#include "compiler.h" -#include "fslike/native.h" -#include "path.h" - - -namespace openage { -namespace util { - - -/** - * Collection of multiple csv files. - * Read from a packed csv that contains all the data. - * - * Then, data can be read recursively. - */ -class CSVCollection { -public: - - /** - * Type for storing csv data: - * {filename: [line, ...]}. - */ - using csv_file_map_t = std::unordered_map>; - - /** - * Initialize the collection by reading the given file. - * This file must contain the data that this collection is made up of. - */ - explicit CSVCollection(const Path &entryfile); - virtual ~CSVCollection() = default; - - - /** - * This function is the entry point to load the whole file tree recursively. - * - * Should be called again from the .recurse() method of the struct. - * - * The internal flow is as follows: - * * read entries of the given files - * (call to the generated field parsers (the fill function)) - * * then, recurse into referenced subdata entries - * (this implementation is generated) - * * from there, reach this function again to read each subdata entry. - * - */ - template - std::vector read(const std::string &filename) const { - - // first read the content from the data - auto result = this->get_data(filename); - - std::string dir = dirname(filename); - - size_t line_count = 0; - - // then recurse into each subdata entry. - for (auto &entry : result) { - line_count += 1; - - if (not entry.recurse(*this, dir)) { - throw Error{ - MSG(err) - << "Failed to read follow-up files for " - << filename << ":" << line_count - }; - } - } - - return result; - } - - - /** - * Parse the data from one file in the map. - */ - template - std::vector get_data(const std::string &filename) const { - - size_t line_count = 0; - - std::vector ret; - - // locate the data in the collection - auto it = this->data.find(filename); - - if (it != std::end(this->data)) { - const std::vector &lines = it->second; - - for (auto &line : lines) { - line_count += 1; - lineformat current_line_data; - - // use the line copy to fill the current line struct. - int error_column = current_line_data.fill(line); - if (error_column != -1) { - throw Error{ - ERR - << "Failed to read CSV file: " - << filename << ":" << line_count << ":" << error_column - << ": error parsing " << line - }; - } - - ret.push_back(current_line_data); - } - } - else { - throw Error{ - ERR << "File was not found in csv cache: '" - << filename << "'" - }; - } - - return ret; - } - -protected: - csv_file_map_t data; -}; - - -/** - * Referenced file tree structure. - * - * Used for storing information for subtype members - * that need to be recursed. - */ -template -struct csv_subdata { - /** - * File where to read subdata from. - * This name is relative to the file that defined the subdata! - */ - std::string filename; - - /** - * Data that was read from the file with this->filename. - */ - std::vector data; - - /** - * Read the data of the lineformat from the collection. - * Can descend recursively into dependencies. - */ - bool read(const CSVCollection &collection, const std::string &basedir) { - std::string next_file = basedir; - if (basedir.size() > 0) { - next_file += fslike::PATHSEP; - } - next_file += this->filename; - - this->data = collection.read(next_file); - return true; - } - - /** - * Convenience operator to access data - */ - const lineformat &operator [](size_t idx) const { - return this->data[idx]; - } -}; - - -/** - * read a single csv file. - * call the destination struct .fill() method for actually storing line data - */ -template -std::vector read_csv_file(const Path &path) { - - File csv = path.open(); - - std::vector ret; - size_t line_count = 0; - - for (auto &line : csv.get_lines()) { - line_count += 1; - - // ignore comments and empty lines - if (line.empty() || line[0] == '#') { - continue; - } - - lineformat current_line_data; - - // use the line copy to fill the current line struct. - int error_column = current_line_data.fill(line); - if (error_column != -1) { - throw Error{ - ERR - << "Failed to read CSV file: " - << csv << ":" << line_count << ":" << error_column - << ": error parsing " << line - }; - } - - ret.push_back(current_line_data); - } - - return ret; -} - -}} // openage::util diff --git a/libopenage/util/profiler.cpp b/libopenage/util/profiler.cpp deleted file mode 100644 index 9b0917edd4..0000000000 --- a/libopenage/util/profiler.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#include "profiler.h" -#include "../legacy_engine.h" -#include "../renderer/color.h" -#include "misc.h" - -#include -#include -#include -#include - -namespace openage::util { - -Profiler::Profiler(LegacyEngine *engine) : - engine{engine} {} - - -Profiler::~Profiler() { - this->unregister_all(); -} - -void Profiler::register_component(const std::string &com, color component_color) { - if (this->registered(com)) { - return; - } - - component_time_data cdt; - cdt.display_name = com; - cdt.drawing_color = component_color; - - for (auto &val : cdt.history) { - val = 0; - } - - this->components[com] = cdt; -} - -void Profiler::unregister_component(const std::string &com) { - if (not this->registered(com)) { - return; - } - - this->components.erase(com); -} - -void Profiler::unregister_all() { - std::vector registered_components = this->registered_components(); - - for (auto com : registered_components) { - this->unregister_component(com); - } -} - -std::vector Profiler::registered_components() { - std::vector registered_components; - for (auto &pair : this->components) { - registered_components.push_back(pair.first); - } - - return registered_components; -} - -void Profiler::start_measure(const std::string &com, color component_color) { - if (not this->engine_in_debug_mode()) { - return; - } - - if (not this->registered(com)) { - this->register_component(com, component_color); - } - - this->components[com].start = std::chrono::high_resolution_clock::now(); -} - -void Profiler::end_measure(const std::string &com) { - if (not this->engine_in_debug_mode()) { - return; - } - - if (this->registered(com)) { - std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); - this->components[com].duration = end - this->components[com].start; - } -} - -void Profiler::draw_component_performance(const std::string &com) { - color rgb = this->components[com].drawing_color; - glColor4f(rgb.r, rgb.g, rgb.b, 1.0); - - glLineWidth(1.0); - glBegin(GL_LINE_STRIP); - float x_offset = 0.0; - float offset_factor = static_cast(PROFILER_CANVAS_WIDTH) / static_cast(MAX_DURATION_HISTORY); - float percentage_factor = static_cast(PROFILER_CANVAS_HEIGHT) / 100.0; - - for (auto i = this->insert_pos; mod(i, MAX_DURATION_HISTORY) != mod(this->insert_pos - 1, MAX_DURATION_HISTORY); ++i) { - i = mod(i, MAX_DURATION_HISTORY); - - auto percentage = this->components[com].history.at(i); - glVertex3f(PROFILER_CANVAS_POSITION_X + x_offset, PROFILER_CANVAS_POSITION_Y + percentage * percentage_factor, 0.0); - x_offset += offset_factor; - } - glEnd(); - - // reset color - glColor4f(1.0, 1.0, 1.0, 1.0); -} - -void Profiler::show(bool debug_mode) { - if (debug_mode) { - this->show(); - } -} - -void Profiler::show() { - this->draw_canvas(); - this->draw_legend(); - - for (auto com : this->components) { - this->draw_component_performance(com.first); - } -} - -bool Profiler::registered(const std::string &com) const { - return this->components.find(com) != this->components.end(); -} - -unsigned Profiler::size() const { - return this->components.size(); -} - -void Profiler::start_frame_measure() { - if (this->engine_in_debug_mode()) { - this->frame_start = std::chrono::high_resolution_clock::now(); - } -} - -void Profiler::end_frame_measure() { - if (not this->engine_in_debug_mode()) { - return; - } - - auto frame_end = std::chrono::high_resolution_clock::now(); - this->frame_duration = frame_end - this->frame_start; - - for (auto com : this->registered_components()) { - double percentage = this->duration_to_percentage(this->components[com].duration); - this->append_to_history(com, percentage); - } - - this->insert_pos++; -} - -void Profiler::draw_canvas() { - glColor4f(0.2, 0.2, 0.2, PROFILER_CANVAS_ALPHA); - glRecti(PROFILER_CANVAS_POSITION_X, - PROFILER_CANVAS_POSITION_Y, - PROFILER_CANVAS_POSITION_X + PROFILER_CANVAS_WIDTH, - PROFILER_CANVAS_POSITION_Y + PROFILER_CANVAS_HEIGHT); -} - -void Profiler::draw_legend() { - int offset = 0; - for (auto com : this->components) { - glColor4f(com.second.drawing_color.r, com.second.drawing_color.g, com.second.drawing_color.b, 1.0); - int box_x = PROFILER_CANVAS_POSITION_X + 2; - int box_y = PROFILER_CANVAS_POSITION_Y - PROFILER_COM_BOX_HEIGHT - 2 - offset; - glRecti(box_x, box_y, box_x + PROFILER_COM_BOX_WIDTH, box_y + PROFILER_COM_BOX_HEIGHT); - - glColor4f(0.2, 0.2, 0.2, 1); - coord::viewport position = coord::viewport{box_x + PROFILER_COM_BOX_WIDTH + 2, box_y + 2}; - // this->display->render_text(position, 12, renderer::Colors::WHITE, "%s", com.second.display_name.c_str()); - - offset += PROFILER_COM_BOX_HEIGHT + 2; - } -} - -double Profiler::duration_to_percentage(std::chrono::high_resolution_clock::duration duration) { - double dur = std::chrono::duration_cast(duration).count(); - double ref = std::chrono::duration_cast(this->frame_duration).count(); - double percentage = dur / ref * 100; - return percentage; -} - -void Profiler::append_to_history(const std::string &com, double percentage) { - if (this->insert_pos == MAX_DURATION_HISTORY) { - this->insert_pos = 0; - } - this->components[com].history[this->insert_pos] = percentage; -} - -bool Profiler::engine_in_debug_mode() { - // if (this->display->drawing_debug_overlay.value) { - // return true; - // } - // else { - // return false; - // } - return true; -} - -} // namespace openage::util diff --git a/libopenage/util/profiler.h b/libopenage/util/profiler.h deleted file mode 100644 index 24d3946394..0000000000 --- a/libopenage/util/profiler.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2015-2023 the openage authors. See copying.md for legal info. - -#pragma once - -#include -#include -#include -#include -#include - -constexpr int MAX_DURATION_HISTORY = 100; -constexpr int PROFILER_CANVAS_WIDTH = 250; -constexpr int PROFILER_CANVAS_HEIGHT = 120; -constexpr int PROFILER_CANVAS_POSITION_X = 0; -constexpr int PROFILER_CANVAS_POSITION_Y = 300; -constexpr float PROFILER_CANVAS_ALPHA = 0.6f; -constexpr int PROFILER_COM_BOX_WIDTH = 30; -constexpr int PROFILER_COM_BOX_HEIGHT = 15; - -namespace openage { - -class LegacyEngine; - - -namespace util { - -struct color { - float r, g, b; -}; - -struct component_time_data { - std::string display_name; - color drawing_color; - std::chrono::high_resolution_clock::time_point start; - std::chrono::high_resolution_clock::duration duration; - std::array history; -}; - -class Profiler { -public: - Profiler(LegacyEngine *engine); - ~Profiler(); - - /** - * registers a component - * @param com the identifier to distinguish the components - * @param component_color color of the plotted line - */ - void register_component(const std::string &com, color component_color); - - /** - * unregisters an individual component - * @param com component name which should be unregistered - */ - void unregister_component(const std::string &com); - - /** - * unregisters all remaining components - */ - void unregister_all(); - - /** - *returns a vector of registered component names - */ - std::vector registered_components(); - - /* - * starts a measurement for the component com. If com is not yet - * registered, its getting registered and the profiler uses the color - * information given by component_color. The default value is white. - */ - void start_measure(const std::string &com, color component_color = {1.0, 1.0, 1.0}); - - /* - * stops the measurement for the component com. If com is not yet - * registered it does nothing. - */ - void end_measure(const std::string &com); - - /* - * draws the profiler gui if debug_mode is set - */ - void show(bool debug_mode); - - /* - * draws the profiler gui - */ - void show(); - - /* - * true if the component com is already registered, otherwise false - */ - bool registered(const std::string &com) const; - - /* - * returns the number of registered components - */ - unsigned size() const; - - /** - * sets the start point for the actual frame which is used as a reference - * value for the registered components - */ - void start_frame_measure(); - - /** - * sets the end point for the reference time used to compute the portions - * of the components. Each recorded measurement for the registered components - * get appended to their history complete the measurement. - */ - void end_frame_measure(); - -private: - void draw_canvas(); - void draw_legend(); - void draw_component_performance(const std::string &com); - double duration_to_percentage(std::chrono::high_resolution_clock::duration duration); - void append_to_history(const std::string &com, double percentage); - bool engine_in_debug_mode(); - - std::chrono::high_resolution_clock::time_point frame_start; - std::chrono::high_resolution_clock::duration frame_duration; - std::unordered_map components; - int insert_pos = 0; - - LegacyEngine *engine; -}; - -} // namespace util -} // namespace openage diff --git a/libopenage/versions/versions.cpp b/libopenage/versions/versions.cpp index c94d898f33..d2e1fd251a 100644 --- a/libopenage/versions/versions.cpp +++ b/libopenage/versions/versions.cpp @@ -1,4 +1,4 @@ -// Copyright 2020-2020 the openage authors. See copying.md for legal info. +// Copyright 2020-2023 the openage authors. See copying.md for legal info. #include "versions.h" @@ -11,37 +11,21 @@ #include #include #include -#include #include -#include "versions/compiletime.h" #include "../util/strings.h" +#include "versions/compiletime.h" namespace openage::versions { std::map get_version_numbers() { - std::map version_numbers; - // SDL runtime version number - SDL_version sdl_runtime_version; - SDL_GetVersion(&sdl_runtime_version); - version_numbers.emplace("SDL-runtime", util::sformat("%d.%d.%d", - sdl_runtime_version.major, - sdl_runtime_version.minor, - sdl_runtime_version.patch)); - // Eigen compiletime version number - version_numbers.emplace("Eigen", util::sformat("%d.%d.%d", - EIGEN_WORLD_VERSION, - EIGEN_MAJOR_VERSION, - EIGEN_MINOR_VERSION)); + version_numbers.emplace("Eigen", util::sformat("%d.%d.%d", EIGEN_WORLD_VERSION, EIGEN_MAJOR_VERSION, EIGEN_MINOR_VERSION)); // Harfbuzz compiletime version number - version_numbers.emplace("Harfbuzz", util::sformat("%d.%d.%d", - HB_VERSION_MAJOR, - HB_VERSION_MINOR, - HB_VERSION_MICRO)); + version_numbers.emplace("Harfbuzz", util::sformat("%d.%d.%d", HB_VERSION_MAJOR, HB_VERSION_MINOR, HB_VERSION_MICRO)); // Add Qt version number version_numbers.emplace("Qt", QT_VERSION_STR); @@ -49,38 +33,17 @@ std::map get_version_numbers() { // Add nyan version number version_numbers.emplace("nyan", nyan_version); - // Add OpenGL version number - // TODO: set the same SDL_GL_CONTEXT_MAJOR_VERSION as the real renderer - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - version_numbers.emplace("OpenGL", SDL_GetError()); - } - else { - SDL_Window *window = SDL_CreateWindow("Query OpenGL version", - 0, 0, 640, 480, - SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN); - if (window != nullptr) { - SDL_GLContext glcontext = SDL_GL_CreateContext(window); - if (glcontext != nullptr) { - version_numbers.emplace("OpenGL", - reinterpret_cast(glGetString(GL_VERSION))); - SDL_GL_DeleteContext(glcontext); - } - SDL_DestroyWindow(window); - } - SDL_Quit(); - } - // Add Opus version number std::string opus_version = opus_get_version_string(); version_numbers.emplace("Opus", opus_version.substr(opus_version.find(' ') + 1)); + // TODO: Add OpenGL version number + #ifdef __linux__ // Add libc version number if not MacOSX version_numbers.emplace("libc-runtime", gnu_get_libc_version()); - version_numbers.emplace("libc-compile", util::sformat("%d.%d", - __GLIBC__, - __GLIBC_MINOR__)); + version_numbers.emplace("libc-compile", util::sformat("%d.%d", __GLIBC__, __GLIBC_MINOR__)); #endif #ifdef __APPLE__ diff --git a/openage/convert/entity_object/export/formats/terrain_metadata.py b/openage/convert/entity_object/export/formats/terrain_metadata.py index 956b44d11e..46ba96b259 100644 --- a/openage/convert/entity_object/export/formats/terrain_metadata.py +++ b/openage/convert/entity_object/export/formats/terrain_metadata.py @@ -158,7 +158,9 @@ def dump(self) -> str: output_str += "\n" # blendtable reference - output_str += f"blendtable {self.blendtable['table_id']} {self.blendtable['filename']}\n\n" + if self.blendtable: + output_str += (f"blendtable {self.blendtable['table_id']} " + "{self.blendtable['filename']}\n\n") # scale factor output_str += f"scalefactor {self.scalefactor}\n\n" @@ -185,7 +187,16 @@ def dump(self) -> str: # frame definitions for frame in self.frames: - output_str += f'frame {" ".join(str(param) for param in frame.values())}\n' + frame_attributes = list(frame.values()) + output_str += f'frame {" ".join(str(param) for param in frame_attributes[:4])}' + + if frame["priority"]: + output_str += f" priority={frame['priority']}" + + if frame["blend_mode"]: + output_str += f" blend_mode={frame['blend_mode']}" + + output_str += "\n" return output_str diff --git a/openage/convert/entity_object/export/metadata_export.py b/openage/convert/entity_object/export/metadata_export.py index a4d2fd35ed..d01e1d53f5 100644 --- a/openage/convert/entity_object/export/metadata_export.py +++ b/openage/convert/entity_object/export/metadata_export.py @@ -11,10 +11,14 @@ from ....util.observer import Observer from .formats.sprite_metadata import SpriteMetadata from .formats.texture_metadata import TextureMetadata +from .formats.terrain_metadata import TerrainMetadata if typing.TYPE_CHECKING: from openage.util.observer import Observable - from openage.convert.entity_object.export.formats.sprite_metadata import LayerMode + from openage.convert.entity_object.export.formats.sprite_metadata import LayerMode\ + as SpriteLayerMode + from openage.convert.entity_object.export.formats.terrain_metadata import LayerMode\ + as TerrainLayerMode class MetadataExport(Observer): @@ -50,7 +54,7 @@ def add_graphics_metadata( self, img_filename: str, tex_filename: str, - layer_mode: LayerMode, + layer_mode: SpriteLayerMode, layer_pos: int, frame_rate: float, replay_delay: float, @@ -62,12 +66,28 @@ def add_graphics_metadata( """ Add metadata from the GenieGraphic object. + :param img_filename: Filename of the exported PNG file. :param tex_filename: Filename of the .texture file. + :param layer_mode: Animation mode (off, once, loop). + :param layer_pos: Layer position. + :param frame_rate: Time spent on each frame. + :param replay_delay: Time delay before replaying the animation. + :param frame_count: Number of frames per angle in the animation. + :param angle_count: Number of angles in the animation. + :param mirror_mode: Mirroring mode (0, 1). If 1, angles above 180 degrees are mirrored. :param start_angle: Angle used for the first frame in the .texture file. """ - self.graphics_metadata[img_filename] = (tex_filename, layer_mode, layer_pos, frame_rate, - replay_delay, frame_count, angle_count, mirror_mode, - start_angle) + self.graphics_metadata[img_filename] = ( + tex_filename, + layer_mode, + layer_pos, + frame_rate, + replay_delay, + frame_count, + angle_count, + mirror_mode, + start_angle + ) def dump(self) -> str: """ @@ -191,3 +211,72 @@ def update(self, observable: Observable, message: dict = None): texture_metadata = message[self.imagefile] self.size = texture_metadata["size"] self.subtex_metadata = texture_metadata["subtex_metadata"] + + +class TerrainMetadataExport(MetadataExport): + """ + Export requests for texture definition files. + """ + + def __init__(self, targetdir, target_filename): + super().__init__(targetdir, target_filename) + + self.graphics_metadata: dict[int, tuple] = {} + self.subtex_count: dict[str, int] = {} + + def add_graphics_metadata( + self, + img_filename: str, + tex_filename: str, + layer_mode: TerrainLayerMode, + layer_pos: int, + frame_rate: float, + replay_delay: float, + frame_count: int, + ): + """ + Add metadata from the GenieGraphic object. + + :param img_filename: Filename of the exported PNG file. + :param tex_filename: Filename of the .texture file. + :param layer_mode: Animation mode (off, loop). + :param layer_pos: Layer position. + :param frame_rate: Time spent on each frame. + :param replay_delay: Time delay before replaying the animation. + :param frame_count: Number of frames in the animation. + """ + self.graphics_metadata[img_filename] = ( + tex_filename, + layer_mode, + layer_pos, + frame_rate, + replay_delay, + frame_count + ) + + def dump(self) -> str: + """ + Creates a human-readable string that can be written to a file. + """ + terrain_file = TerrainMetadata(self.targetdir, self.filename) + + tex_index = 0 + for _, metadata in self.graphics_metadata.items(): + tex_filename = metadata[0] + terrain_file.add_texture(tex_index, tex_filename) + terrain_file.add_layer(tex_index, *metadata[1:5]) + + frame_count = metadata[5] + + for frame_idx in range(frame_count): + subtex_index = frame_idx + terrain_file.add_frame( + frame_idx, + tex_index, + tex_index, + subtex_index + ) + + tex_index += 1 + + return terrain_file.dump() diff --git a/openage/convert/processor/conversion/aoc/media_subprocessor.py b/openage/convert/processor/conversion/aoc/media_subprocessor.py index 360a13b4f7..90af7ad297 100644 --- a/openage/convert/processor/conversion/aoc/media_subprocessor.py +++ b/openage/convert/processor/conversion/aoc/media_subprocessor.py @@ -1,6 +1,6 @@ # Copyright 2019-2023 the openage authors. See copying.md for legal info. # -# pylint: disable=too-many-locals,too-few-public-methods +# pylint: disable=too-many-locals,too-few-public-methods,too-many-statements """ Convert media information to metadata definitions and export requests. Subroutine of the main AoC processor. @@ -10,10 +10,12 @@ from openage.convert.value_object.read.media_types import MediaType -from ....entity_object.export.formats.sprite_metadata import LayerMode +from ....entity_object.export.formats.sprite_metadata import LayerMode as SpriteLayerMode +from ....entity_object.export.formats.terrain_metadata import LayerMode as TerrainLayerMode from ....entity_object.export.media_export_request import MediaExportRequest from ....entity_object.export.metadata_export import SpriteMetadataExport from ....entity_object.export.metadata_export import TextureMetadataExport +from ....entity_object.export.metadata_export import TerrainMetadataExport from ....value_object.read.media_types import MediaType if typing.TYPE_CHECKING: @@ -82,13 +84,13 @@ def create_graphics_requests(full_data_set: GenieObjectContainer) -> None: # Add metadata from graphics to animation metadata sequence_type = graphic["sequence_type"].value if sequence_type == 0x00: - layer_mode = LayerMode.OFF + layer_mode = SpriteLayerMode.OFF elif sequence_type & 0x08: - layer_mode = LayerMode.ONCE + layer_mode = SpriteLayerMode.ONCE else: - layer_mode = LayerMode.LOOP + layer_mode = SpriteLayerMode.LOOP layer_pos = graphic["layer"].value frame_rate = round(graphic["frame_rate"].value, ndigits=6) @@ -132,6 +134,44 @@ def create_graphics_requests(full_data_set: GenieObjectContainer) -> None: target_filename) full_data_set.graphics_exports.update({slp_id: export_request}) + texture_meta_filename = f"{texture.get_filename()}.texture" + texture_meta_export = TextureMetadataExport(targetdir, + texture_meta_filename) + full_data_set.metadata_exports.append(texture_meta_export) + + # Add texture image filename to texture metadata + texture_meta_export.add_imagefile(target_filename) + texture_meta_export.update( + None, + { + f"{target_filename}": { + "size": (481, 481), # TODO: Get actual size = sqrt(slp_frame_count) + "subtex_metadata": [ + { + "x": 0, + "y": 0, + "w": 481, + "h": 481, + "cx": 0, + "cy": 0, + } + ] + }} + ) + + terrain_meta_filename = f"{texture.get_filename()}.terrain" + terrain_meta_export = TerrainMetadataExport(targetdir, + terrain_meta_filename) + full_data_set.metadata_exports.append(terrain_meta_export) + + terrain_meta_export.add_graphics_metadata(target_filename, + texture_meta_filename, + TerrainLayerMode.OFF, + 0, + 0.0, + 0.0, + 1) + @staticmethod def create_blend_requests(full_data_set: GenieObjectContainer) -> None: """ diff --git a/openage/convert/processor/conversion/hd/media_subprocessor.py b/openage/convert/processor/conversion/hd/media_subprocessor.py index 935643efa0..62dc1dd719 100644 --- a/openage/convert/processor/conversion/hd/media_subprocessor.py +++ b/openage/convert/processor/conversion/hd/media_subprocessor.py @@ -1,6 +1,6 @@ # Copyright 2021-2023 the openage authors. See copying.md for legal info. # -# pylint: disable=too-many-locals +# pylint: disable=too-many-locals,too-many-statements """ Convert media information to metadata definitions and export @@ -9,9 +9,12 @@ from __future__ import annotations import typing -from ....entity_object.export.formats.sprite_metadata import LayerMode +from ....entity_object.export.formats.sprite_metadata import LayerMode as SpriteLayerMode +from ....entity_object.export.formats.terrain_metadata import LayerMode as TerrainLayerMode from ....entity_object.export.media_export_request import MediaExportRequest -from ....entity_object.export.metadata_export import SpriteMetadataExport, TextureMetadataExport +from ....entity_object.export.metadata_export import SpriteMetadataExport +from ....entity_object.export.metadata_export import TextureMetadataExport +from ....entity_object.export.metadata_export import TerrainMetadataExport from ....value_object.read.media_types import MediaType if typing.TYPE_CHECKING: @@ -77,13 +80,13 @@ def create_graphics_requests(full_data_set: GenieObjectContainer) -> None: # Add metadata from graphics to animation metadata sequence_type = graphic["sequence_type"].value if sequence_type == 0x00: - layer_mode = LayerMode.OFF + layer_mode = SpriteLayerMode.OFF elif sequence_type & 0x08: - layer_mode = LayerMode.ONCE + layer_mode = SpriteLayerMode.ONCE else: - layer_mode = LayerMode.LOOP + layer_mode = SpriteLayerMode.LOOP layer_pos = graphic["layer"].value frame_rate = round(graphic["frame_rate"].value, ndigits=6) @@ -128,6 +131,44 @@ def create_graphics_requests(full_data_set: GenieObjectContainer) -> None: target_filename) full_data_set.graphics_exports.update({slp_id: export_request}) + texture_meta_filename = f"{texture.get_filename()}.texture" + texture_meta_export = TextureMetadataExport(targetdir, + texture_meta_filename) + full_data_set.metadata_exports.append(texture_meta_export) + + # Add texture image filename to texture metadata + texture_meta_export.add_imagefile(target_filename) + texture_meta_export.update( + None, + { + f"{target_filename}": { + "size": (512, 512), + "subtex_metadata": [ + { + "x": 0, + "y": 0, + "w": 512, + "h": 512, + "cx": 0, + "cy": 0, + } + ] + }} + ) + + terrain_meta_filename = f"{texture.get_filename()}.terrain" + terrain_meta_export = TerrainMetadataExport(targetdir, + terrain_meta_filename) + full_data_set.metadata_exports.append(terrain_meta_export) + + terrain_meta_export.add_graphics_metadata(target_filename, + texture_meta_filename, + TerrainLayerMode.OFF, + 0, + 0.0, + 0.0, + 1) + @staticmethod def create_sound_requests(full_data_set: GenieObjectContainer) -> None: """ diff --git a/openage/testing/testlist.py b/openage/testing/testlist.py index 939732bd0d..75a684e85e 100644 --- a/openage/testing/testlist.py +++ b/openage/testing/testlist.py @@ -99,7 +99,6 @@ def tests_cpp(): yield "openage::util::tests::vector" yield "openage::util::tests::siphash" yield "openage::util::tests::array_conversion" - yield "openage::input::legacy::tests::parse_event_string", "keybinds parsing" yield "openage::curve::tests::container" yield "openage::curve::tests::curve_types" yield "openage::event::tests::eventtrigger" diff --git a/openage/util/fslike/path.py b/openage/util/fslike/path.py index 422b9f176b..ccdf8cc2b8 100644 --- a/openage/util/fslike/path.py +++ b/openage/util/fslike/path.py @@ -4,7 +4,7 @@ Provides Path, which is analogous to pathlib.Path, and the type of FSLikeObject.root. """ -from typing import NoReturn +from typing import NoReturn, Union from io import UnsupportedOperation, TextIOWrapper import os @@ -35,7 +35,7 @@ class Path: # lower. # pylint: disable=too-many-public-methods - def __init__(self, fsobj, parts: str | bytes | bytearray | list | tuple = None): + def __init__(self, fsobj, parts: Union[str, bytes, bytearray, list, tuple] = None): if isinstance(parts, str): parts = parts.encode() diff --git a/packaging/docker/devenv/Dockerfile.ubuntu.2204 b/packaging/docker/devenv/Dockerfile.ubuntu.2204 index 40b1dd3abc..4976e0c693 100644 --- a/packaging/docker/devenv/Dockerfile.ubuntu.2204 +++ b/packaging/docker/devenv/Dockerfile.ubuntu.2204 @@ -20,8 +20,6 @@ RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y sudo \ libopus-dev \ libopusfile-dev \ libpng-dev \ - libsdl2-dev \ - libsdl2-image-dev \ libtoml11-dev \ make \ ninja-build \ @@ -35,5 +33,7 @@ RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y sudo \ python3-toml \ qml6-module-qtquick-controls \ qt6-declarative-dev \ + qt6-multimedia-dev \ + qml6-module-qtquick3d-spatialaudio \ && sudo apt-get clean \ && truncate -s 0 ~/.bash_history diff --git a/shell.nix b/shell.nix index 5b466174ef..5d80e0669f 100644 --- a/shell.nix +++ b/shell.nix @@ -9,7 +9,7 @@ pkgs.mkShell { #pkgs.gdb pkgs.cmake pkgs.gnumake - pkgs.qt5.full + pkgs.qt6.full #pkgs.qtcreator pkgs.eigen @@ -27,13 +27,12 @@ pkgs.mkShell { pkgs.ftgl pkgs.fontconfig pkgs.harfbuzz - pkgs.SDL2 - pkgs.SDL2_image pkgs.opusfile pkgs.libopus pkgs.python39Packages.pylint pkgs.python39Packages.toml pkgs.libsForQt6.qt6.qtdeclarative pkgs.libsForQt6.qt6.qtquickcontrols + pkgs.libsForQt6.qt6.qtmultimedia ]; }