├── .appveyor.yml ├── .gitignore ├── .gitmodules ├── Android.mk ├── CMakeLists.txt ├── CMakeSettings.json ├── Doxyfile ├── LICENSE.md ├── README.md ├── cmake ├── CMakeLists_SDL2_devel.txt ├── Copyright.txt ├── FindSDL2.cmake └── LibFindMacros.cmake ├── default.nix ├── demo ├── res │ ├── backgrounds │ │ ├── city-bg0-with-planets.png │ │ ├── city-bg0.png │ │ ├── city-bg1.png │ │ └── city-bg2.png │ ├── maps │ │ ├── city.json │ │ └── city.tmx │ ├── sprites │ │ ├── player.png │ │ ├── vehicle-misc1.png │ │ ├── vehicle-misc2.png │ │ ├── vehicle-police.png │ │ └── vehicle-truck.png │ └── tilesets │ │ ├── city.png │ │ └── city.tsx ├── src │ └── main.c └── work │ ├── .gitignore │ ├── city.pyxel │ ├── demo.tiled-project │ ├── objecttypes.xml │ ├── player.pyxel │ ├── vehicle-misc1.pyxel │ ├── vehicle-misc2.pyxel │ ├── vehicle-police.pyxel │ └── vehicle-truck.pyxel ├── doc ├── .gitignore ├── customdoxygen.css ├── doxy-boot.js ├── footer.html ├── header.html └── logo.png ├── examples └── minimal_application.c ├── external ├── .gitignore └── Android.mk ├── media ├── demo-01-tn.png ├── demo-01.png ├── demo-02-tn.png └── demo-02.png └── src ├── Android.mk ├── esz.c ├── esz.h ├── esz_compat.c ├── esz_compat.h ├── esz_hash.c ├── esz_hash.h ├── esz_init.c ├── esz_init.h ├── esz_macros.h ├── esz_render.c ├── esz_render.h ├── esz_types.h ├── esz_utils.c └── esz_utils.h /.appveyor.yml: -------------------------------------------------------------------------------- 1 | image: ubuntu 2 | 3 | before_build: 4 | - sudo apt-get update 5 | - sudo apt-get install -y libsdl2-dev libxml2-dev 6 | - git submodule update --init --recursive 7 | 8 | build_script: 9 | - mkdir -p build 10 | - cd build 11 | - cmake -DUSE_LIBTMX=ON .. 12 | - make 13 | - cmake -DUSE_LIBTMX=OFF .. 14 | - make 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | eszFW-cppcheck-build-dir 3 | out 4 | project 5 | .vs 6 | *.a 7 | *.cppcheck 8 | *.dll 9 | *.exe 10 | *.ilk 11 | *.lib 12 | *.o 13 | *.pdb 14 | *.so 15 | *.zip 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/tmx"] 2 | path = external/tmx 3 | url = https://github.com/baylej/tmx.git 4 | [submodule "external/cwalk"] 5 | path = external/cwalk 6 | url = https://github.com/likle/cwalk.git 7 | [submodule "external/stb"] 8 | path = external/stb 9 | url = https://github.com/nothings/stb.git 10 | [submodule "external/cute_headers"] 11 | path = external/cute_headers 12 | url = https://github.com/RandyGaul/cute_headers.git 13 | [submodule "external/lua"] 14 | path = external/lua 15 | url = https://github.com/lua/lua.git 16 | [submodule "external/log.c"] 17 | path = external/log.c 18 | url = https://github.com/rxi/log.c.git 19 | [submodule "external/picolog"] 20 | path = external/picolog 21 | url = https://github.com/picojs/picolog.git 22 | [submodule "external/buffer"] 23 | path = external/buffer 24 | url = https://github.com/clibs/buffer.git 25 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | include $(call all-subdir-makefiles) 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(eszFW C) 3 | 4 | set(CMAKE_C_STANDARD 11) 5 | 6 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/) 7 | 8 | if(WIN32) 9 | set(SDL2_PLATFORM "x64") 10 | set(SDL2_VERSION "2.0.12") 11 | set(SDL2_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/SDL2-${SDL2_VERSION}) 12 | set(SDL2_DEVEL_PKG SDL2-devel-${SDL2_VERSION}-VC.zip) 13 | 14 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 15 | set(SDL2_PLATFORM "x86") 16 | endif() 17 | 18 | include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) 19 | 20 | ExternalProject_Add(SDL2_devel 21 | URL https://www.libsdl.org/release/${SDL2_DEVEL_PKG} 22 | URL_HASH SHA1=6839b6ec345ef754a6585ab24f04e125e88c3392 23 | DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external 24 | DOWNLOAD_NO_PROGRESS true 25 | TLS_VERIFY true 26 | SOURCE_DIR ${SDL2_PATH}/ 27 | BUILD_BYPRODUCTS ${SDL2_PATH}/lib/${SDL2_PLATFORM}/SDL2.lib 28 | 29 | BUILD_COMMAND cmake -E echo "Skipping build step." 30 | 31 | INSTALL_COMMAND cmake -E copy 32 | ${SDL2_PATH}/lib/${SDL2_PLATFORM}/SDL2.dll ${CMAKE_CURRENT_SOURCE_DIR}/demo 33 | 34 | PATCH_COMMAND ${CMAKE_COMMAND} -E copy 35 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeLists_SDL2_devel.txt" ${SDL2_PATH}/CMakeLists.txt) 36 | 37 | set(SDL2_INCLUDE_DIR ${SDL2_PATH}/include) 38 | set(SDL2_LIBRARY ${SDL2_PATH}/lib/${SDL2_PLATFORM}/SDL2.lib) 39 | 40 | endif(WIN32) 41 | 42 | find_package(SDL2 REQUIRED) 43 | if(USE_LIBTMX) 44 | find_package(LibXml2 REQUIRED) 45 | endif(USE_LIBTMX) 46 | 47 | set(CUTE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/cute_headers) 48 | set(CWALK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/cwalk/include) 49 | set(LIBTMX_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/tmx/src) 50 | set(LUA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/lua) 51 | set(PICOLOG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/picolog) 52 | set(STB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/stb) 53 | 54 | include_directories( 55 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src 56 | SYSTEM ${CWALK_INCLUDE_DIR} 57 | SYSTEM ${LUA_INCLUDE_DIR} 58 | SYSTEM ${PICOLOG_INCLUDE_DIR} 59 | SYSTEM ${SDL2_INCLUDE_DIRS} 60 | SYSTEM ${STB_INCLUDE_DIR}) 61 | 62 | set(eszFW_sources 63 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz.c 64 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz.h 65 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_compat.c 66 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_compat.h 67 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_hash.c 68 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_hash.h 69 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_init.c 70 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_init.h 71 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_render.c 72 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_render.h 73 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_types.h 74 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_utils.c 75 | ${CMAKE_CURRENT_SOURCE_DIR}/src/esz_utils.h) 76 | 77 | set(demo_sources 78 | ${CMAKE_CURRENT_SOURCE_DIR}/demo/src/main.c) 79 | 80 | add_library( 81 | ${PROJECT_NAME} 82 | STATIC 83 | ${eszFW_sources}) 84 | 85 | target_include_directories( 86 | ${PROJECT_NAME} 87 | PUBLIC 88 | ${CMAKE_CURRENT_SOURCE_DIR}/src 89 | ${CUTE_INCLUDE_DIR} 90 | ${LIBTMX_INCLUDE_DIR} 91 | ${PICOLOG_INCLUDE_DIR}) 92 | 93 | add_executable( 94 | demo 95 | ${demo_sources}) 96 | 97 | set_target_properties( 98 | demo 99 | PROPERTIES 100 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/demo 101 | RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/demo 102 | RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/demo) 103 | 104 | if(WIN32) 105 | set_target_properties( 106 | demo 107 | PROPERTIES 108 | ADDITIONAL_CLEAN_FILES 109 | ${CMAKE_CURRENT_SOURCE_DIR}/demo/SDL2.dll) 110 | endif(WIN32) 111 | 112 | add_library( 113 | cwalk 114 | STATIC 115 | ${CMAKE_CURRENT_SOURCE_DIR}/external/cwalk/src/cwalk.c) 116 | 117 | add_library( 118 | picolog 119 | STATIC 120 | ${CMAKE_CURRENT_SOURCE_DIR}/external/picolog/picolog.c) 121 | 122 | add_library( 123 | lua 124 | STATIC 125 | ${LUA_INCLUDE_DIR}/onelua.c) 126 | 127 | option(ENABLE_DIAGNOSTICS "Enable all diagnostics" OFF) 128 | option(USE_LIBTMX "Use libTMX instead of cute_tiled" OFF) 129 | 130 | target_link_libraries( 131 | ${PROJECT_NAME} 132 | ${SDL2_LIBRARIES} 133 | cwalk 134 | picolog) 135 | 136 | target_link_libraries( 137 | demo 138 | ${SDL2_LIBRARIES} 139 | ${PROJECT_NAME}) 140 | 141 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 142 | 143 | if(USE_LIBTMX) 144 | add_definitions(-DUSE_LIBTMX) 145 | add_subdirectory(external/tmx) 146 | set_property(TARGET tmx PROPERTY POSITION_INDEPENDENT_CODE ON) 147 | target_link_libraries( 148 | ${PROJECT_NAME} 149 | ${LIBXML2_LIBRARIES} 150 | tmx) 151 | endif(USE_LIBTMX) 152 | 153 | if(UNIX) 154 | target_link_libraries(${PROJECT_NAME} m) 155 | endif(UNIX) 156 | 157 | if (CMAKE_C_COMPILER_ID STREQUAL "Clang") 158 | set(COMPILE_OPTIONS 159 | -Wall 160 | -Wextra 161 | -Wpedantic) 162 | 163 | elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU") 164 | set(COMPILE_OPTIONS 165 | -Wall 166 | -Wextra 167 | -Wpedantic) 168 | 169 | elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC") 170 | set(COMPILE_OPTIONS 171 | /W4) 172 | endif() 173 | 174 | if (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND ENABLE_DIAGNOSTICS) 175 | message("Enabling all diagnostics") 176 | set(COMPILE_OPTIONS 177 | -Weverything) 178 | add_compile_options(-Weverything) 179 | endif() 180 | -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Visual Studio 16 2019 Win64", 6 | "configurationType": "Debug", 7 | "buildRoot": "${projectDir}\\out\\build\\${name}", 8 | "installRoot": "${projectDir}\\out\\install\\${name}", 9 | "cmakeCommandArgs": "-DUSE_LIBTMX=OFF", 10 | "buildCommandArgs": "", 11 | "ctestCommandArgs": "", 12 | "inheritEnvironments": [ "msvc_x64_x64" ], 13 | "variables": [ 14 | { 15 | "name": "SDL2_INCLUDE_DIR", 16 | "value": "${projectDir}\\external\\SDL2-2.0.12\\include", 17 | "type": "PATH" 18 | }, 19 | { 20 | "name": "SDL2_LIBRARY", 21 | "value": "${projectDir}\\external\\SDL2-2.0.12\\lib\\x64\\SDL2.lib", 22 | "type": "FILEPATH" 23 | } 24 | ] 25 | }, 26 | { 27 | "name": "x64-Release", 28 | "generator": "Visual Studio 16 2019 Win64", 29 | "configurationType": "Release", 30 | "buildRoot": "${projectDir}\\out\\build\\${name}", 31 | "installRoot": "${projectDir}\\out\\install\\${name}", 32 | "cmakeCommandArgs": "-DUSE_LIBTMX=OFF", 33 | "buildCommandArgs": "", 34 | "ctestCommandArgs": "", 35 | "inheritEnvironments": [ "msvc_x64_x64" ], 36 | "variables": [ 37 | { 38 | "name": "SDL2_INCLUDE_DIR", 39 | "value": "${projectDir}\\external\\SDL2-2.0.12\\include", 40 | "type": "PATH" 41 | }, 42 | { 43 | "name": "SDL2_LIBRARY", 44 | "value": "${projectDir}\\external\\SDL2-2.0.12\\lib\\x64\\SDL2.lib", 45 | "type": "FILEPATH" 46 | } 47 | ] 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2020 Michael Fitzmayer 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eszFW 2 | 3 |

4 | 5 | GitHub project 6 | 7 | 8 | Licence 9 | 10 | 11 | Build status 12 | 13 | 14 | Codacy Badge 15 | 16 | 17 | Open Source Helpers 18 | 19 |

20 | 21 | ## About 22 | 23 | eszFW is a cross-platform game engine written in C. It's aimed at 24 | platformer games. This project is the logical continuation of my older 25 | projects [Rainbow Joe](https://github.com/mupfelofen-de/rainbow-joe) and 26 | [Boondock Sam](https://github.com/mupfelofen-de/boondock-sam). 27 | 28 | ## Features 29 | 30 | - It runs on all platforms [supported by 31 | SDL2](https://wiki.libsdl.org/Installation#Supported_platforms). 32 | 33 | - Fully reentrant engine core. 34 | 35 | - The dependencies can be limited to SDL2. 36 | 37 | - It uses the [Tiled Map Editor](https://www.mapeditor.org/) as its main 38 | tool to develop games. 39 | 40 | ## Documentation 41 | 42 | The documentation can be generated using Doxygen: 43 | ```bash 44 | doxygen 45 | ``` 46 | 47 | A automatically generated version of the documentation can be found 48 | here: [eszfw.de](https://eszfw.de) 49 | 50 | ## Code style 51 | 52 | You are invited to contribute to this project. But to ensure a uniform 53 | formatting of the source code, you will find some rules here: 54 | 55 | - Follow the C11 standard. 56 | - Do not use tabs and use a consistent 4 space indentation style. 57 | - Use lower snake_case for both function and variable names. 58 | - Try to use a consistent style. Use the existing code as a guideline. 59 | 60 | ### Status 61 | 62 | This project currently undergoes a complete overhaul. 63 | 64 | If you wanna see a previous version in action, take a look at the [demo 65 | application](demo/). 66 | 67 | [![demo](https://raw.githubusercontent.com/mupfelofen-de/eszFW/master/media/demo-01-tn.png)](https://raw.githubusercontent.com/mupfelofen-de/eszFW/master/media/demo-01.png?raw=true "demo 1") 68 | [![demo](https://raw.githubusercontent.com/mupfelofen-de/eszFW/master/media/demo-02-tn.png)](https://raw.githubusercontent.com/mupfelofen-de/eszFW/master/media/demo-02.png?raw=true "demo 2") 69 | 70 | An Android version is available on Google Play: 71 | 72 | [![Get it on Google Play](https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=de.mupfelofen.TauCeti) 73 | 74 | ## C is dead, long live C 75 | 76 | Even though hardly any games are written in C nowadays, there are a few 77 | noteworthy titles that meet this criterion e.g. Doom, Quake, Quake II, 78 | and Neverwinter Nights. 79 | 80 | This project should show that it is still possible and that C (and 81 | procedural programming in general) is often underestimated. 82 | 83 | With that in mind: C is dead, long live C! 84 | 85 | ### Trivia 86 | 87 | The abbreviation esz is a tribute to my best friend [Ertugrul 88 | Söylemez](https://github.com/esoeylemez), who suddenly passed away on 89 | May 12th, 2018. We all miss you deeply. 90 | 91 | ## Dependencies 92 | 93 | The program has been successfully compiled and tested with the following libraries: 94 | ```text 95 | SDL2 2.0.12 96 | libxml2 2.9.10 (optional) 97 | zlib 1.2.11 (optional) 98 | ``` 99 | 100 | ## Compiling 101 | 102 | First clone the repository including the submodules: 103 | ```bash 104 | git clone --recurse-submodules -j2 https://github.com/mupfelofen-de/eszFW.git 105 | ``` 106 | 107 | ### Windows 108 | 109 | The easiest way to get eszFW up and running is Visual Studio 2019 with 110 | [C++ CMake tools for 111 | Windows](https://docs.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=vs-2019#installation) 112 | installed. Just open the project inside the IDE and everything else is 113 | set up automatically. 114 | 115 | Alternatively just use [MSYS2](https://www.msys2.org/) with CMake and a 116 | compiler of your choice. 117 | 118 | ### Linux 119 | 120 | To compile _eszFW_ and the included demo application, simply use CMake e.g.: 121 | ```bash 122 | mkdir build 123 | cd build 124 | cmake .. 125 | make 126 | ``` 127 | 128 | If you wanna compile eszFW with _libTMX_ instead of _cute_tiled_, just enable the 129 | respective CMake option: 130 | ```bash 131 | cmake -DUSE_LIBTMX=ON .. 132 | ``` 133 | 134 | ## Licence and Credits 135 | 136 | ### Engine 137 | 138 | [cute_tiled](https://github.com/RandyGaul/cute_headers) by Randy Gaul is 139 | licensed under the zlib licence. 140 | 141 | [TMX C Loader](https://github.com/baylej/tmx/) by Bayle Jonathan is 142 | licensed under a BSD 2-Clause "Simplified" Licence. 143 | 144 | This project and all further listed libraries are licensed under the 145 | "The MIT License". See the file [LICENSE.md](LICENSE.md) for details. 146 | 147 | [cwalk](https://github.com/likle/cwalk) by Leonard Iklé. 148 | 149 | [picolog](https://github.com/picojs/picolog) by James McLean. 150 | 151 | ### Demo application 152 | 153 | [Warped City](https://ansimuz.itch.io/warped-city) by Luis Zuno. 154 | Dedicated to [public 155 | domain](https://creativecommons.org/publicdomain/zero/1.0/). 156 | 157 | Every other work that is not explicitly mentioned here is also under 158 | [public domain](https://creativecommons.org/publicdomain/zero/1.0/). 159 | -------------------------------------------------------------------------------- /cmake/CMakeLists_SDL2_devel.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(SDL2_devel C) 3 | -------------------------------------------------------------------------------- /cmake/Copyright.txt: -------------------------------------------------------------------------------- 1 | CMake - Cross Platform Makefile Generator 2 | Copyright 2000-2020 Kitware, Inc. and Contributors 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Kitware, Inc. nor the names of Contributors 17 | may be used to endorse or promote products derived from this 18 | software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ------------------------------------------------------------------------------ 33 | 34 | The following individuals and institutions are among the Contributors: 35 | 36 | * Aaron C. Meadows 37 | * Adriaan de Groot 38 | * Aleksey Avdeev 39 | * Alexander Neundorf 40 | * Alexander Smorkalov 41 | * Alexey Sokolov 42 | * Alex Merry 43 | * Alex Turbov 44 | * Andreas Pakulat 45 | * Andreas Schneider 46 | * André Rigland Brodtkorb 47 | * Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf 48 | * Benjamin Eikel 49 | * Bjoern Ricks 50 | * Brad Hards 51 | * Christopher Harvey 52 | * Christoph Grüninger 53 | * Clement Creusot 54 | * Daniel Blezek 55 | * Daniel Pfeifer 56 | * Enrico Scholz 57 | * Eran Ifrah 58 | * Esben Mose Hansen, Ange Optimization ApS 59 | * Geoffrey Viola 60 | * Google Inc 61 | * Gregor Jasny 62 | * Helio Chissini de Castro 63 | * Ilya Lavrenov 64 | * Insight Software Consortium 65 | * Jan Woetzel 66 | * Julien Schueller 67 | * Kelly Thompson 68 | * Laurent Montel 69 | * Konstantin Podsvirov 70 | * Mario Bensi 71 | * Martin Gräßlin 72 | * Mathieu Malaterre 73 | * Matthaeus G. Chajdas 74 | * Matthias Kretz 75 | * Matthias Maennich 76 | * Michael Hirsch, Ph.D. 77 | * Michael Stürmer 78 | * Miguel A. Figueroa-Villanueva 79 | * Mike Jackson 80 | * Mike McQuaid 81 | * Nicolas Bock 82 | * Nicolas Despres 83 | * Nikita Krupen'ko 84 | * NVIDIA Corporation 85 | * OpenGamma Ltd. 86 | * Patrick Stotko 87 | * Per Øyvind Karlsen 88 | * Peter Collingbourne 89 | * Petr Gotthard 90 | * Philip Lowman 91 | * Philippe Proulx 92 | * Raffi Enficiaud, Max Planck Society 93 | * Raumfeld 94 | * Roger Leigh 95 | * Rolf Eike Beer 96 | * Roman Donchenko 97 | * Roman Kharitonov 98 | * Ruslan Baratov 99 | * Sebastian Holtermann 100 | * Stephen Kelly 101 | * Sylvain Joubert 102 | * The Qt Company Ltd. 103 | * Thomas Sondergaard 104 | * Tobias Hunger 105 | * Todd Gamblin 106 | * Tristan Carel 107 | * University of Dundee 108 | * Vadim Zhukov 109 | * Will Dicharry 110 | 111 | See version control history for details of individual contributions. 112 | 113 | The above copyright and license notice applies to distributions of 114 | CMake in source and binary form. Third-party software packages supplied 115 | with CMake under compatible licenses provide their own copyright notices 116 | documented in corresponding subdirectories or source files. 117 | 118 | ------------------------------------------------------------------------------ 119 | 120 | CMake was initially developed by Kitware with the following sponsorship: 121 | 122 | * National Library of Medicine at the National Institutes of Health 123 | as part of the Insight Segmentation and Registration Toolkit (ITK). 124 | 125 | * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel 126 | Visualization Initiative. 127 | 128 | * National Alliance for Medical Image Computing (NAMIC) is funded by the 129 | National Institutes of Health through the NIH Roadmap for Medical Research, 130 | Grant U54 EB005149. 131 | 132 | * Kitware, Inc. 133 | -------------------------------------------------------------------------------- /cmake/FindSDL2.cmake: -------------------------------------------------------------------------------- 1 | # Locate SDL2 library 2 | # This module defines 3 | # SDL2_LIBRARY, the SDL2 library, with no other libraries 4 | # SDL2_LIBRARIES, the SDL library and required components with compiler flags 5 | # SDL2_FOUND, if false, do not try to link to SDL2 6 | # SDL2_INCLUDE_DIR, where to find SDL.h 7 | # SDL2_VERSION, the version of the found library 8 | # 9 | # This module accepts the following env variables 10 | # SDL2DIR - Can be set to ./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02 11 | # This module responds to the the flag: 12 | # SDL2_BUILDING_LIBRARY 13 | # If this is defined, then no SDL2_main will be linked in because 14 | # only applications need main(). 15 | # Otherwise, it is assumed you are building an application and this 16 | # module will attempt to locate and set the the proper link flags 17 | # as part of the returned SDL2_LIBRARIES variable. 18 | # 19 | # Don't forget to include SDL2main.h and SDL2main.m your project for the 20 | # OS X framework based version. (Other versions link to -lSDL2main which 21 | # this module will try to find on your behalf.) Also for OS X, this 22 | # module will automatically add the -framework Cocoa on your behalf. 23 | # 24 | # 25 | # Modified by Eric Wing. 26 | # Added code to assist with automated building by using environmental variables 27 | # and providing a more controlled/consistent search behavior. 28 | # Added new modifications to recognize OS X frameworks and 29 | # additional Unix paths (FreeBSD, etc). 30 | # Also corrected the header search path to follow "proper" SDL2 guidelines. 31 | # Added a search for SDL2main which is needed by some platforms. 32 | # Added a search for threads which is needed by some platforms. 33 | # Added needed compile switches for MinGW. 34 | # 35 | # On OSX, this will prefer the Framework version (if found) over others. 36 | # People will have to manually change the cache values of 37 | # SDL2_LIBRARY to override this selection or set the CMake environment 38 | # CMAKE_INCLUDE_PATH to modify the search paths. 39 | # 40 | # Note that the header path has changed from SDL2/SDL.h to just SDL.h 41 | # This needed to change because "proper" SDL2 convention 42 | # is #include "SDL.h", not . This is done for portability 43 | # reasons because not all systems place things in SDL2/ (see FreeBSD). 44 | # 45 | # Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake 46 | # module with the minor edit of changing "SDL" to "SDL2" where necessary. This 47 | # was not created for redistribution, and exists temporarily pending official 48 | # SDL2 CMake modules. 49 | 50 | #============================================================================= 51 | # Copyright 2003-2009 Kitware, Inc. 52 | # 53 | # Distributed under the OSI-approved BSD License (the "License"); 54 | # see accompanying file Copyright.txt for details. 55 | # 56 | # This software is distributed WITHOUT ANY WARRANTY; without even the 57 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 58 | # See the License for more information. 59 | #============================================================================= 60 | # (To distribute this file outside of CMake, substitute the full 61 | # License text for the above reference.) 62 | 63 | 64 | if (CMAKE_SIZEOF_VOID_P EQUAL 8) 65 | set(_sdl_lib_suffix lib/x64) 66 | else() 67 | set(_sdl_lib_suffix lib/x86) 68 | endif() 69 | 70 | include(LibFindMacros) 71 | 72 | libfind_pkg_detect(SDL2 sdl2 73 | FIND_PATH SDL.h 74 | HINTS $ENV{SDL2DIR} 75 | PATH_SUFFIXES include SDL2 76 | FIND_LIBRARY SDL2 77 | HINTS $ENV{SDL2DIR} 78 | PATH_SUFFIXES ${_sdl_lib_suffix} 79 | ) 80 | libfind_version_n_header(SDL2 NAMES SDL_version.h DEFINES SDL_MAJOR_VERSION SDL_MINOR_VERSION SDL_PATCHLEVEL) 81 | 82 | IF(NOT SDL2_BUILDING_LIBRARY AND NOT APPLE) 83 | # Non-OS X framework versions expect you to also dynamically link to 84 | # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms 85 | # seem to provide SDL2main for compatibility even though they don't 86 | # necessarily need it. 87 | libfind_pkg_detect(SDL2MAIN sdl2 88 | FIND_LIBRARY SDL2main 89 | HINTS $ENV{SDL2DIR} 90 | PATH_SUFFIXES ${_sdl_lib_suffix} 91 | ) 92 | set(SDL2MAIN_FIND_QUIETLY TRUE) 93 | libfind_process(SDL2MAIN) 94 | list(APPEND SDL2_PROCESS_LIBS SDL2MAIN_LIBRARY) 95 | ENDIF() 96 | 97 | 98 | set(SDL2_TARGET_SPECIFIC) 99 | 100 | if (APPLE) 101 | # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. 102 | list(APPEND SDL2_TARGET_SPECIFIC "-framework Cocoa") 103 | else() 104 | # SDL2 may require threads on your system. 105 | # The Apple build may not need an explicit flag because one of the 106 | # frameworks may already provide it. 107 | # But for non-OSX systems, I will use the CMake Threads package. 108 | libfind_package(SDL2 Threads) 109 | list(APPEND SDL2_TARGET_SPECIFIC ${CMAKE_THREAD_LIBS_INIT}) 110 | endif() 111 | 112 | # MinGW needs an additional library, mwindows 113 | # It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows 114 | # (Actually on second look, I think it only needs one of the m* libraries.) 115 | if(MINGW) 116 | list(APPEND SDL2_TARGET_SPECIFIC mingw32) 117 | endif() 118 | 119 | if(WIN32) 120 | list(APPEND SDL2_TARGET_SPECIFIC winmm imm32 version msimg32) 121 | endif() 122 | 123 | set(SDL2_PROCESS_LIBS SDL2_TARGET_SPECIFIC) 124 | 125 | libfind_process(SDL2) 126 | 127 | if (SDL2_STATIC AND UNIX AND NOT APPLE) 128 | execute_process(COMMAND sdl2-config --static-libs OUTPUT_VARIABLE SDL2_STATIC_FLAGS) 129 | string(REGEX REPLACE "(\r?\n)+$" "" SDL2_STATIC_FLAGS "${SDL2_STATIC_FLAGS}") 130 | set(SDL2_LIBRARIES ${SDL2_STATIC_FLAGS}) 131 | endif() 132 | -------------------------------------------------------------------------------- /cmake/LibFindMacros.cmake: -------------------------------------------------------------------------------- 1 | # Version 2.2 2 | # Public Domain, originally written by Lasse Kärkkäinen 3 | # Maintained at https://github.com/Tronic/cmake-modules 4 | # Please send your improvements as pull requests on Github. 5 | 6 | include(CMakeParseArguments) 7 | 8 | # Find another package and make it a dependency of the current package. 9 | # This also automatically forwards the "REQUIRED" argument. 10 | # Usage: libfind_package( [extra args to find_package]) 11 | macro (libfind_package PREFIX PKG) 12 | set(${PREFIX}_args ${PKG} ${ARGN}) 13 | if (${PREFIX}_FIND_REQUIRED) 14 | set(${PREFIX}_args ${${PREFIX}_args} REQUIRED) 15 | endif() 16 | find_package(${${PREFIX}_args}) 17 | set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG}) 18 | unset(${PREFIX}_args) 19 | endmacro() 20 | 21 | # A simple wrapper to make pkg-config searches a bit easier. 22 | # Works the same as CMake's internal pkg_check_modules but is always quiet. 23 | macro (libfind_pkg_check_modules) 24 | find_package(PkgConfig QUIET) 25 | if (PKG_CONFIG_FOUND) 26 | pkg_check_modules(${ARGN} QUIET) 27 | endif() 28 | endmacro() 29 | 30 | # Avoid useless copy&pasta by doing what most simple libraries do anyway: 31 | # pkg-config, find headers, find library. 32 | # Usage: libfind_pkg_detect( FIND_PATH [other args] FIND_LIBRARY [other args]) 33 | # E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2) 34 | function (libfind_pkg_detect PREFIX) 35 | # Parse arguments 36 | set(argname pkgargs) 37 | foreach (i ${ARGN}) 38 | if ("${i}" STREQUAL "FIND_PATH") 39 | set(argname pathargs) 40 | elseif ("${i}" STREQUAL "FIND_LIBRARY") 41 | set(argname libraryargs) 42 | else() 43 | set(${argname} ${${argname}} ${i}) 44 | endif() 45 | endforeach() 46 | if (NOT pkgargs) 47 | message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.") 48 | endif() 49 | # Find library 50 | libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs}) 51 | if (pathargs) 52 | find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS}) 53 | endif() 54 | if (libraryargs) 55 | find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}) 56 | endif() 57 | endfunction() 58 | 59 | # libfind_header_path( [PATHS [ ...]] NAMES [name ...] VAR [QUIET]) 60 | # Get fullpath of the first found header looking inside _INCLUDE_DIR or in the given PATHS 61 | # Usage: libfind_header_path(Foobar NAMES foobar/version.h VAR filepath) 62 | function (libfind_header_path PREFIX) 63 | set(options QUIET) 64 | set(one_value_keywords VAR PATH) 65 | set(multi_value_keywords NAMES PATHS) 66 | CMAKE_PARSE_ARGUMENTS(OPT "${options}" "${one_value_keywords}" "${multi_value_keywords}" ${ARGN}) 67 | if (NOT OPT_VAR OR NOT OPT_NAMES) 68 | message(FATAL_ERROR "Arguments VAR, NAMES are required!") 69 | endif() 70 | if (OPT_UNPARSED_ARGUMENTS) 71 | message(FATAL_ERROR "Calling function with unused arguments '${OPT_UNPARSED_ARGUMENTS}'!") 72 | endif() 73 | if (OPT_QUIET OR ${PREFIX}_FIND_QUIETLY) 74 | set(quiet TRUE) 75 | endif() 76 | set(paths ${OPT_PATHS} ${PREFIX}_INCLUDE_DIR) 77 | 78 | foreach(name ${OPT_NAMES}) 79 | foreach(path ${paths}) 80 | set(filepath "${${path}}/${name}") 81 | # check for existance 82 | if (EXISTS ${filepath}) 83 | set(${OPT_VAR} ${filepath} PARENT_SCOPE) # export path 84 | return() 85 | endif() 86 | endforeach() 87 | endforeach() 88 | 89 | # report error if not found 90 | set(${OPT_VAR} NOTFOUND PARENT_SCOPE) 91 | if (NOT quiet) 92 | message(AUTHOR_WARNING "Unable to find '${OPT_NAMES}'") 93 | endif() 94 | endfunction() 95 | 96 | # libfind_version_n_header( 97 | # NAMES [ ...] 98 | # DEFINES [ ...] | CONSTANTS [ ...] 99 | # [PATHS [ ...]] 100 | # [QUIET] 101 | # ) 102 | # Collect all defines|constants from a header inside _INCLUDE_DIR or in the given PATHS 103 | # output stored to _VERSION. 104 | # This function does nothing if the version variable is already defined. 105 | # Usage: libfind_version_n_header(Foobar NAMES foobar/version.h DEFINES FOOBAR_VERSION_MAJOR FOOBAR_VERSION_MINOR) 106 | function (libfind_version_n_header PREFIX) 107 | # Skip processing if we already have a version 108 | if (${PREFIX}_VERSION) 109 | return() 110 | endif() 111 | 112 | set(options QUIET) 113 | set(one_value_keywords ) 114 | set(multi_value_keywords NAMES PATHS DEFINES CONSTANTS) 115 | CMAKE_PARSE_ARGUMENTS(OPT "${options}" "${one_value_keywords}" "${multi_value_keywords}" ${ARGN}) 116 | if (NOT OPT_NAMES OR (NOT OPT_DEFINES AND NOT OPT_CONSTANTS)) 117 | message(FATAL_ERROR "Arguments NAMES, DEFINES|CONSTANTS are required!") 118 | endif() 119 | if (OPT_DEFINES AND OPT_CONSTANTS) 120 | message(FATAL_ERROR "Either DEFINES or CONSTANTS must be set!") 121 | endif() 122 | if (OPT_UNPARSED_ARGUMENTS) 123 | message(FATAL_ERROR "Calling function with unused arguments '${OPT_UNPARSED_ARGUMENTS}'!") 124 | endif() 125 | if (OPT_QUIET OR ${PREFIX}_FIND_QUIETLY) 126 | set(quiet TRUE) 127 | set(force_quiet "QUIET") # to propagate argument QUIET 128 | endif() 129 | 130 | # Read the header 131 | libfind_header_path(${PREFIX} NAMES ${OPT_NAMES} PATHS ${OPT_PATHS} VAR filename ${force_quiet}) 132 | if (NOT filename) 133 | return() 134 | endif() 135 | file(READ "${filename}" header) 136 | # Parse for version number 137 | unset(version_parts) 138 | foreach(define_name ${OPT_DEFINES}) 139 | string(REGEX MATCH "# *define +${define_name} +((\"([^\n]*)\")|([^ \n]*))" match "${header}") 140 | # No regex match? 141 | if (NOT match OR match STREQUAL header) 142 | if (NOT quiet) 143 | message(AUTHOR_WARNING "Unable to find \#define ${define_name} \"\" from ${filename}") 144 | endif() 145 | return() 146 | else() 147 | list(APPEND version_parts "${CMAKE_MATCH_3}${CMAKE_MATCH_4}") 148 | endif() 149 | endforeach() 150 | foreach(constant_name ${OPT_CONSTANTS}) 151 | string(REGEX MATCH "${constant_name} *= *((\"([^\;]*)\")|([^ \;]*))" match "${header}") 152 | # No regex match? 153 | if (NOT match OR match STREQUAL header) 154 | if (NOT quiet) 155 | message(AUTHOR_WARNING "Unable to find ${constant_name} = \"\" from ${filename}") 156 | endif() 157 | return() 158 | else() 159 | list(APPEND version_parts "${CMAKE_MATCH_3}${CMAKE_MATCH_4}") 160 | endif() 161 | endforeach() 162 | 163 | # Export the version string 164 | string(REPLACE ";" "." version "${version_parts}") 165 | set(${PREFIX}_VERSION "${version}" PARENT_SCOPE) 166 | endfunction() 167 | 168 | # libfind_version_header(
[PATHS [ ...]] [QUIET]) 169 | # Extracts a version #define from a version.h file, output stored to _VERSION. 170 | # This function does nothing if the version variable is already defined. 171 | # Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR) 172 | function (libfind_version_header PREFIX VERSION_H DEFINE_NAME) 173 | # Skip processing if we already have a version 174 | if (${PREFIX}_VERSION) 175 | return() 176 | endif() 177 | 178 | set(options QUIET) 179 | set(one_value_keywords ) 180 | set(multi_value_keywords PATHS) 181 | CMAKE_PARSE_ARGUMENTS(OPT "${options}" "${one_value_keywords}" "${multi_value_keywords}" ${ARGN}) 182 | if (OPT_UNPARSED_ARGUMENTS) 183 | message(FATAL_ERROR "Calling function with unused arguments '${OPT_UNPARSED_ARGUMENTS}'!") 184 | endif() 185 | if (OPT_QUIET OR ${PREFIX}_FIND_QUIETLY) 186 | set(force_quiet "QUIET") # to propagate argument QUIET 187 | endif() 188 | 189 | libfind_version_n_header(${PREFIX} NAMES ${VERSION_H} PATHS ${OPT_PATHS} DEFINES ${DEFINE_NAME} ${force_quiet}) 190 | set(${PREFIX}_VERSION "${${PREFIX}_VERSION}" PARENT_SCOPE) 191 | endfunction() 192 | 193 | # Do the final processing once the paths have been detected. 194 | # If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain 195 | # all the variables, each of which contain one include directory. 196 | # Ditto for ${PREFIX}_PROCESS_LIBS and library files. 197 | # Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. 198 | # Also handles errors in case library detection was required, etc. 199 | function (libfind_process PREFIX) 200 | # Skip processing if already processed during this configuration run 201 | if (${PREFIX}_FOUND) 202 | return() 203 | endif() 204 | 205 | set(found TRUE) # Start with the assumption that the package was found 206 | 207 | # Did we find any files? Did we miss includes? These are for formatting better error messages. 208 | set(some_files FALSE) 209 | set(missing_headers FALSE) 210 | 211 | # Shorthands for some variables that we need often 212 | set(quiet ${${PREFIX}_FIND_QUIETLY}) 213 | set(required ${${PREFIX}_FIND_REQUIRED}) 214 | set(exactver ${${PREFIX}_FIND_VERSION_EXACT}) 215 | set(findver "${${PREFIX}_FIND_VERSION}") 216 | set(version "${${PREFIX}_VERSION}") 217 | 218 | # Lists of config option names (all, includes, libs) 219 | unset(configopts) 220 | set(includeopts ${${PREFIX}_PROCESS_INCLUDES}) 221 | set(libraryopts ${${PREFIX}_PROCESS_LIBS}) 222 | 223 | # Process deps to add to 224 | foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES}) 225 | if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS) 226 | # The package seems to export option lists that we can use, woohoo! 227 | list(APPEND includeopts ${${i}_INCLUDE_OPTS}) 228 | list(APPEND libraryopts ${${i}_LIBRARY_OPTS}) 229 | else() 230 | # If plural forms don't exist or they equal singular forms 231 | if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR 232 | ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES)) 233 | # Singular forms can be used 234 | if (DEFINED ${i}_INCLUDE_DIR) 235 | list(APPEND includeopts ${i}_INCLUDE_DIR) 236 | endif() 237 | if (DEFINED ${i}_LIBRARY) 238 | list(APPEND libraryopts ${i}_LIBRARY) 239 | endif() 240 | else() 241 | # Oh no, we don't know the option names 242 | message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!") 243 | endif() 244 | endif() 245 | endforeach() 246 | 247 | if (includeopts) 248 | list(REMOVE_DUPLICATES includeopts) 249 | endif() 250 | 251 | if (libraryopts) 252 | list(REMOVE_DUPLICATES libraryopts) 253 | endif() 254 | 255 | string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}") 256 | if (NOT tmp STREQUAL "${includeopts} ${libraryopts}") 257 | message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).") 258 | endif() 259 | 260 | # Include/library names separated by spaces (notice: not CMake lists) 261 | unset(includes) 262 | unset(libs) 263 | 264 | # Process all includes and set found false if any are missing 265 | foreach (i ${includeopts}) 266 | list(APPEND configopts ${i}) 267 | if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") 268 | list(APPEND includes "${${i}}") 269 | else() 270 | set(found FALSE) 271 | set(missing_headers TRUE) 272 | endif() 273 | endforeach() 274 | 275 | # Process all libraries and set found false if any are missing 276 | foreach (i ${libraryopts}) 277 | list(APPEND configopts ${i}) 278 | if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") 279 | list(APPEND libs "${${i}}") 280 | else() 281 | set (found FALSE) 282 | endif() 283 | endforeach() 284 | 285 | # Version checks 286 | if (found AND findver) 287 | if (NOT version) 288 | message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.") 289 | elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver)) 290 | set(found FALSE) 291 | set(version_unsuitable TRUE) 292 | endif() 293 | endif() 294 | 295 | # If all-OK, hide all config options, export variables, print status and exit 296 | if (found) 297 | foreach (i ${configopts}) 298 | mark_as_advanced(${i}) 299 | endforeach() 300 | set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE) 301 | set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE) 302 | set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE) 303 | set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE) 304 | set (${PREFIX}_FOUND TRUE PARENT_SCOPE) 305 | if (NOT quiet) 306 | message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") 307 | if (LIBFIND_DEBUG) 308 | message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}") 309 | message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}") 310 | message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}") 311 | message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}") 312 | message(STATUS " ${PREFIX}_LIBRARIES=${libs}") 313 | endif() 314 | endif() 315 | return() 316 | endif() 317 | 318 | # Format messages for debug info and the type of error 319 | set(vars "Relevant CMake configuration variables:\n") 320 | foreach (i ${configopts}) 321 | mark_as_advanced(CLEAR ${i}) 322 | set(val ${${i}}) 323 | if ("${val}" STREQUAL "${i}-NOTFOUND") 324 | set (val "") 325 | elseif (val AND NOT EXISTS "${val}") 326 | set (val "${val} (does not exist)") 327 | else() 328 | set(some_files TRUE) 329 | endif() 330 | set(vars "${vars} ${i}=${val}\n") 331 | endforeach() 332 | set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n") 333 | if (version_unsuitable) 334 | set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but") 335 | if (exactver) 336 | set(msg "${msg} only version ${findver} is acceptable.") 337 | else() 338 | set(msg "${msg} version ${findver} is the minimum requirement.") 339 | endif() 340 | else() 341 | if (missing_headers) 342 | set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?") 343 | elseif (some_files) 344 | set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?") 345 | if(findver) 346 | set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).") 347 | endif() 348 | else() 349 | set(msg "We were unable to find package ${PREFIX}.") 350 | endif() 351 | endif() 352 | 353 | # Fatal error out if REQUIRED 354 | if (required) 355 | set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.") 356 | message(FATAL_ERROR "${msg}\n${vars}") 357 | endif() 358 | # Otherwise just print a nasty warning 359 | if (NOT quiet) 360 | message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}") 361 | endif() 362 | endfunction() 363 | 364 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixpkgs ? , 3 | pkgs ? import nixpkgs {} 4 | }: 5 | 6 | with pkgs; 7 | 8 | let 9 | extraIncludes = ps: builtins.concatStringsSep " " ( 10 | builtins.map (p: "-I${stdenv.lib.getDev p}/include/SDL2") ps 11 | ); 12 | in stdenv.mkDerivation { 13 | name = "eszfw"; 14 | src = ./.; 15 | 16 | nativeBuildInputs = [ cmake pkgconfig ]; 17 | buildInputs = [ libxml2 SDL2 SDL2_image SDL2_mixer SDL2_ttf ]; 18 | 19 | NIX_CFLAGS_COMPILE = extraIncludes [ SDL2_ttf SDL2_mixer ]; 20 | 21 | installPhase = '' 22 | mkdir -p $out/bin 23 | cp libeszFW.so $out/lib/libeszFW.so 24 | ''; 25 | } 26 | -------------------------------------------------------------------------------- /demo/res/backgrounds/city-bg0-with-planets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/backgrounds/city-bg0-with-planets.png -------------------------------------------------------------------------------- /demo/res/backgrounds/city-bg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/backgrounds/city-bg0.png -------------------------------------------------------------------------------- /demo/res/backgrounds/city-bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/backgrounds/city-bg1.png -------------------------------------------------------------------------------- /demo/res/backgrounds/city-bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/backgrounds/city-bg2.png -------------------------------------------------------------------------------- /demo/res/maps/city.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | eJztmM+OTFEQxus+gIUV1hNEyAQxgrUgQjqI8QQTREinu5HgAbQFmTCJBC9hjRewECZYyPACFsIECxHfSXclpe75253bTbq+5Evn9L0z59zqqt+pc4lMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJNGl1KqLu0D3hrvq+G3BP/e3VatpP1Kx2wrvg3fAeeC88nzG+gbjchG/B+zBemMLaJ63L8BX4FHwaPgO3E+MW/Agxegw/ga9hfH0Ka5+0TsAn4Q7chXs0iI0ctzzjZ4jRc/gFfJZmI1acV/fhB/AKDWIlxy3P9TXE6CP8aUbySrM9xfnQ9Vlj+1v4HfyeZoftc/C2iHeo+5lX3+Ef8E8qZ7vj1WKzj5VUJ1Af+lPm/mGKx+q4moN5tQn/YzO8pfKz/H9ge2meLCXuv6Tu57w6gGc+CB+q6mz3sV6zfdp55eTLk63Dz+1Uz5OS2Mq89XFcszvW1/8LbPflyRH4KHyM6nlSWoMhtqdYL6+Xsv1Vwb0lcnnyGn4Dr9Lgec/DF+CLlFeDa/AH8tcg80qyfVmNXc1p1svrpbz6UnBviVyefIW/wes0eN7bcB++Q3k1+Bv+RfF9ULJ9nuKsb6vrpbHa2ECthnrF3H2wP3SrGji2D2q2x1jfUtdLe4bSvOp4nt3HR5cnkuWa7bEalLFqV/Ua7CR+g9j3vt49l+2j5BVz1eV8iI8uTyTLNdtzatDFqU/+GuQ1yD481aeH+vanDcaKWeFyOpTHLk8kyzXbc/ZBzq+XVI8tr0H24T6W6+u+vn21wVgxK9xaQmd1lyeS5ZrtOfsgx+ozhfdB2Yen+nQ95rWvixj4WDvOWZt/0+VIrFyelJxxfDXIsdpQhfdB2Yen+nQ9DtWEZq3j5gK837OOlPg3dfUfq0E5H8/F43F6UX3ejPXnsfwIsV2z1nFzET5X1VmQEv+m7Uis5tR8PBePxz0P5r6T0WzP6ds1a2VPrdeRkmR7rAblfFxPPB7nPOjk69s12zXLdV8f6kU1a2VPPWoNxvJqSc3XF3bjcc+DvncyvvftkuW6r/etPdZHj3LW5nWGeoac91ddNWdpDd6F79HffbjLm9j7dd3Xu7U/9DyfW4s+y4bWkRurUM/wB8mWbrI= 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | eJztl8EuxFAUhm87TzBeAI9gZosXILGY2eIFEKHdDi/Aji1eACu22FnNWIqNYWc1YykWfkkTTXBT47adtt+X/EnbNKfnfj3pTY0BAAAAAAAAAAAAAAAAAIA0WfCMWfTy7qIYrMnTOq4SsSdP+7hKxKk8neEqEV156uEqEQN5GuIKYCyo+8ZM+Hl3UQwa8tTEVSJa8tSuuKut2D63ZNnzAnkKK+yqq7X3YuvftLg60H2HFXY10NqHsfXb5upC911W2FW9pr2t9nVum6uq05CnZsyVba5+YlJzNqVM+/+7niXnI85DS57af3S1UfDZuxux/0CewsjVrGrMKfNRrQc3rY0F77HjVwfvelk1VpRV73v9LHlU+inUvXVYqyNHO8quMhMlDzw910/h2S5dHam/Y+Wk4N+j33Dp6kqOrpWbErq6N25d9eXoSXkuoas35SXvJgrA5//uthIoYQnnICs+AM+LL3o= 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | eJzt2EsKwjAUheHEuaAz1yEouApnCq5CrK7MZQiKjwXoXFB8zL2DFoJYml4obcz/wYFCU7icQiAxBgAAAAAAAAAAAAAAAAD0FtaYJM3y69nNytY9Kdb8A2+nBnR1llxKrN9LDpJjJdPkezegKysztNI5eh7rH5Kn5FXhTCEYFbx39/Ik8v18VmLtQPoZRtiRxkR6mtIVCmwlu7qHCMRNcld+G1vHHdl7usr9R9txyPrKrrQdx0jbcWw2hq58XSVjuvLStnSVx71nyM45dPWbe8+QnXPmf97VB+C4Iyo= 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | eJzt1skNgkAYhmGmBAtwK8EpQNFG3FpyqUSxC2+gXXBzOfkd0ERIBDVxMvg+yXtgwmH4k5kQBAAAAAAAAAAAAAAAwBd71xvwSOp6Ax5pGNc7+J2maqm26qhuyfs985w1xbW66quBCtVQjbL1g775WOPv/sRYTdRUzdQ8W79oTldmBUc4q9VxVv8X/9bl7jNKc88osrn/Rcu9ArxtoXOzVCu15gy9tNF8tipSO2YFAA+x7sSEe7GSk+Z0Zlb4wg38ERvX 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /demo/res/sprites/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/sprites/player.png -------------------------------------------------------------------------------- /demo/res/sprites/vehicle-misc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/sprites/vehicle-misc1.png -------------------------------------------------------------------------------- /demo/res/sprites/vehicle-misc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/sprites/vehicle-misc2.png -------------------------------------------------------------------------------- /demo/res/sprites/vehicle-police.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/sprites/vehicle-police.png -------------------------------------------------------------------------------- /demo/res/sprites/vehicle-truck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/sprites/vehicle-truck.png -------------------------------------------------------------------------------- /demo/res/tilesets/city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/res/tilesets/city.png -------------------------------------------------------------------------------- /demo/res/tilesets/city.tsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | -------------------------------------------------------------------------------- /demo/src/main.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Beerware 2 | /** 3 | * @file main.c 4 | * @author Michael Fitzmayer 5 | * @copyright "THE BEER-WARE LICENCE" (Revision 42) 6 | */ 7 | 8 | #define SDL_MAIN_HANDLED 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static void key_down_callback(esz_window_t* window, esz_core_t* core); 17 | 18 | #ifdef USE_LIBTMX 19 | #define MAP_FILE "res/maps/city.tmx" 20 | #else // (cute_tiled.h) 21 | #define MAP_FILE "res/maps/city.json" 22 | #endif 23 | 24 | int main() 25 | { 26 | const uint8_t* keystate = esz_get_keyboard_state(); 27 | esz_status status; 28 | esz_window_t* window = NULL; 29 | esz_window_config_t config = { 640, 360, 384, 216, false, false }; 30 | esz_core_t* core = NULL; 31 | 32 | status = esz_create_window("Tau Ceti", &config, &window); 33 | if (ESZ_OK != status) 34 | { 35 | goto quit; 36 | } 37 | 38 | status = esz_init_core(&core); 39 | if (ESZ_OK != status) 40 | { 41 | goto quit; 42 | } 43 | 44 | esz_load_map(MAP_FILE, window, core); 45 | esz_register_event_callback(EVENT_KEYDOWN, &key_down_callback, core); 46 | 47 | while (esz_is_core_active(core)) 48 | { 49 | esz_update_core(window, core); 50 | 51 | status = esz_show_scene(window, core); 52 | if (ESZ_ERROR_CRITICAL == status) 53 | { 54 | break; 55 | } 56 | } 57 | 58 | quit: 59 | esz_unload_map(window, core); 60 | esz_destroy_core(core); 61 | esz_destroy_window(window); 62 | 63 | if (ESZ_OK != status) 64 | { 65 | return EXIT_FAILURE; 66 | } 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | 71 | static void key_down_callback(esz_window_t* window, esz_core_t* core) 72 | { 73 | switch (esz_get_keycode(core)) 74 | { 75 | case SDLK_F5: 76 | { 77 | if (esz_is_map_loaded(core)) 78 | { 79 | esz_unload_map(window, core); 80 | } 81 | else 82 | { 83 | esz_load_map(MAP_FILE, window, core); 84 | } 85 | break; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /demo/work/.gitignore: -------------------------------------------------------------------------------- 1 | *.tiled-session 2 | -------------------------------------------------------------------------------- /demo/work/city.pyxel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/work/city.pyxel -------------------------------------------------------------------------------- /demo/work/demo.tiled-project: -------------------------------------------------------------------------------- 1 | { 2 | "automappingRulesFile": "", 3 | "commands": [ 4 | ], 5 | "extensionsPath": "extensions", 6 | "folders": [ 7 | "../../../TauCeti-dev/res" 8 | ], 9 | "objectTypesFile": "objecttypes.xml" 10 | } 11 | -------------------------------------------------------------------------------- /demo/work/objecttypes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/work/player.pyxel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/work/player.pyxel -------------------------------------------------------------------------------- /demo/work/vehicle-misc1.pyxel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/work/vehicle-misc1.pyxel -------------------------------------------------------------------------------- /demo/work/vehicle-misc2.pyxel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/work/vehicle-misc2.pyxel -------------------------------------------------------------------------------- /demo/work/vehicle-police.pyxel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/work/vehicle-police.pyxel -------------------------------------------------------------------------------- /demo/work/vehicle-truck.pyxel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/demo/work/vehicle-truck.pyxel -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | html 2 | !Doxyfile 3 | !.style.css 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /doc/customdoxygen.css: -------------------------------------------------------------------------------- 1 | h1, .h1, h2, .h2, h3, .h3{ 2 | font-weight: 200 !important; 3 | } 4 | 5 | #navrow1, #navrow2, #navrow3, #navrow4, #navrow5{ 6 | border-bottom: 1px solid #EEEEEE; 7 | } 8 | 9 | .adjust-right { 10 | margin-left: 30px !important; 11 | font-size: 1.15em !important; 12 | } 13 | .navbar { 14 | border: 0px solid #222 !important; 15 | } 16 | .navbar-header { 17 | margin: 2em 1em; 18 | padding-left: 2em; 19 | } 20 | table { 21 | white-space:pre-wrap !important; 22 | } 23 | /* 24 | =========================== 25 | */ 26 | 27 | 28 | /* Sticky footer styles 29 | -------------------------------------------------- */ 30 | html, 31 | body { 32 | height: 100%; 33 | /* The html and body elements cannot have any padding or margin. */ 34 | } 35 | 36 | /* Wrapper for page content to push down footer */ 37 | #wrap { 38 | min-height: 100%; 39 | height: auto; 40 | /* Negative indent footer by its height */ 41 | margin: 0 auto -60px; 42 | /* Pad bottom by footer height */ 43 | padding: 0 0 60px; 44 | } 45 | 46 | /* Set the fixed height of the footer here */ 47 | #footer { 48 | font-size: 0.9em; 49 | padding: 8px 0px; 50 | background-color: #f5f5f5; 51 | } 52 | 53 | .footer-row { 54 | line-height: 44px; 55 | } 56 | 57 | #footer > .container { 58 | padding-left: 15px; 59 | padding-right: 15px; 60 | } 61 | 62 | .footer-follow-icon { 63 | margin-left: 3px; 64 | text-decoration: none !important; 65 | } 66 | 67 | .footer-follow-icon img { 68 | width: 20px; 69 | } 70 | 71 | .footer-link { 72 | padding-top: 5px; 73 | display: inline-block; 74 | color: #999999; 75 | text-decoration: none; 76 | } 77 | 78 | .footer-copyright { 79 | text-align: center; 80 | } 81 | 82 | 83 | @media (min-width: 992px) { 84 | .footer-row { 85 | text-align: left; 86 | } 87 | 88 | .footer-icons { 89 | text-align: right; 90 | } 91 | } 92 | @media (max-width: 991px) { 93 | .footer-row { 94 | text-align: center; 95 | } 96 | 97 | .footer-icons { 98 | text-align: center; 99 | } 100 | } 101 | 102 | /* DOXYGEN Code Styles 103 | ----------------------------------- */ 104 | 105 | 106 | a.qindex { 107 | font-weight: bold; 108 | } 109 | 110 | a.qindexHL { 111 | font-weight: bold; 112 | background-color: #9CAFD4; 113 | color: #ffffff; 114 | border: 1px double #869DCA; 115 | } 116 | 117 | .contents a.qindexHL:visited { 118 | color: #ffffff; 119 | } 120 | 121 | a.code, a.code:visited, a.line, a.line:visited { 122 | color: #4665A2; 123 | } 124 | 125 | a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { 126 | color: #4665A2; 127 | } 128 | 129 | /* @end */ 130 | 131 | dl.el { 132 | margin-left: -1cm; 133 | } 134 | 135 | pre.fragment { 136 | border: 1px solid #C4CFE5; 137 | background-color: #FBFCFD; 138 | padding: 4px 6px; 139 | margin: 4px 8px 4px 2px; 140 | overflow: auto; 141 | word-wrap: break-word; 142 | font-size: 9pt; 143 | line-height: 125%; 144 | font-family: monospace, fixed; 145 | font-size: 105%; 146 | } 147 | 148 | div.fragment { 149 | padding: 4px 6px; 150 | margin: 4px 8px 4px 2px; 151 | border: 1px solid #C4CFE5; 152 | } 153 | 154 | div.line { 155 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 156 | font-size: 12px; 157 | min-height: 13px; 158 | line-height: 1.0; 159 | text-wrap: unrestricted; 160 | white-space: -moz-pre-wrap; /* Moz */ 161 | white-space: -pre-wrap; /* Opera 4-6 */ 162 | white-space: -o-pre-wrap; /* Opera 7 */ 163 | white-space: pre-wrap; /* CSS3 */ 164 | word-wrap: normal; /* IE 5.5+ */ 165 | text-indent: -53px; 166 | padding-left: 53px; 167 | padding-bottom: 0px; 168 | margin: 0px; 169 | -webkit-transition-property: background-color, box-shadow; 170 | -webkit-transition-duration: 0.5s; 171 | -moz-transition-property: background-color, box-shadow; 172 | -moz-transition-duration: 0.5s; 173 | -ms-transition-property: background-color, box-shadow; 174 | -ms-transition-duration: 0.5s; 175 | -o-transition-property: background-color, box-shadow; 176 | -o-transition-duration: 0.5s; 177 | transition-property: background-color, box-shadow; 178 | transition-duration: 0.5s; 179 | } 180 | div.line:hover{ 181 | background-color: #FBFF00; 182 | } 183 | 184 | div.line.glow { 185 | background-color: cyan; 186 | box-shadow: 0 0 10px cyan; 187 | } 188 | 189 | 190 | span.lineno { 191 | padding-right: 4px; 192 | text-align: right; 193 | color:rgba(0,0,0,0.3); 194 | border-right: 1px solid #EEE; 195 | border-left: 1px solid #EEE; 196 | background-color: #FFF; 197 | white-space: pre; 198 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace ; 199 | } 200 | span.lineno a { 201 | background-color: #FAFAFA; 202 | cursor:pointer; 203 | } 204 | 205 | span.lineno a:hover { 206 | background-color: #EFE200; 207 | color: #1e1e1e; 208 | } 209 | 210 | div.groupHeader { 211 | margin-left: 16px; 212 | margin-top: 12px; 213 | font-weight: bold; 214 | } 215 | 216 | div.groupText { 217 | margin-left: 16px; 218 | font-style: italic; 219 | } 220 | 221 | /* @group Code Colorization */ 222 | 223 | span.keyword { 224 | color: #008000 225 | } 226 | 227 | span.keywordtype { 228 | color: #604020 229 | } 230 | 231 | span.keywordflow { 232 | color: #e08000 233 | } 234 | 235 | span.comment { 236 | color: #800000 237 | } 238 | 239 | span.preprocessor { 240 | color: #806020 241 | } 242 | 243 | span.stringliteral { 244 | color: #002080 245 | } 246 | 247 | span.charliteral { 248 | color: #008080 249 | } 250 | 251 | span.vhdldigit { 252 | color: #ff00ff 253 | } 254 | 255 | span.vhdlchar { 256 | color: #000000 257 | } 258 | 259 | span.vhdlkeyword { 260 | color: #700070 261 | } 262 | 263 | span.vhdllogic { 264 | color: #ff0000 265 | } 266 | 267 | blockquote { 268 | background-color: #F7F8FB; 269 | border-left: 2px solid #9CAFD4; 270 | margin: 0 24px 0 4px; 271 | padding: 0 12px 0 16px; 272 | } 273 | 274 | /*---------------- Search Box */ 275 | 276 | #search-box { 277 | margin: 10px 0px; 278 | } 279 | #search-box .close { 280 | display: none; 281 | position: absolute; 282 | right: 0px; 283 | padding: 6px 12px; 284 | z-index: 5; 285 | } 286 | 287 | /*---------------- Search results window */ 288 | 289 | #search-results-window { 290 | display: none; 291 | } 292 | 293 | iframe#MSearchResults { 294 | width: 100%; 295 | height: 15em; 296 | } 297 | 298 | .SRChildren { 299 | padding-left: 3ex; padding-bottom: .5em 300 | } 301 | .SRPage .SRChildren { 302 | display: none; 303 | } 304 | a.SRScope { 305 | display: block; 306 | } 307 | a.SRSymbol:focus, a.SRSymbol:active, 308 | a.SRScope:focus, a.SRScope:active { 309 | text-decoration: underline; 310 | } 311 | span.SRScope { 312 | padding-left: 4px; 313 | } 314 | .SRResult { 315 | display: none; 316 | } 317 | 318 | /* class and file list */ 319 | .directory .icona, 320 | .directory .arrow { 321 | height: auto; 322 | } 323 | .directory .icona .icon { 324 | height: 16px; 325 | } 326 | .directory .icondoc { 327 | background-position: 0px 0px; 328 | height: 20px; 329 | } 330 | .directory .iconfopen { 331 | background-position: 0px 0px; 332 | } 333 | .directory td.entry { 334 | padding: 7px 8px 6px 8px; 335 | } 336 | 337 | .table > tbody > tr > td.memSeparator { 338 | line-height: 0; 339 | .table-hover; 340 | 341 | } 342 | 343 | .memItemLeft, .memTemplItemLeft { 344 | white-space: normal; 345 | } 346 | 347 | /* enumerations */ 348 | .panel-body thead > tr { 349 | background-color: #e0e0e0; 350 | } 351 | 352 | /* todo lists */ 353 | .todoname, 354 | .todoname a { 355 | font-weight: bold; 356 | } 357 | 358 | /* Class title */ 359 | .summary { 360 | margin-top: 25px; 361 | } 362 | .page-header { 363 | margin: 20px 0px !important; 364 | } 365 | .page-header .title { 366 | display: inline-block; 367 | } 368 | .page-header .pull-right { 369 | margin-top: 0.3em; 370 | margin-left: 0.5em; 371 | } 372 | .page-header .label { 373 | font-size: 50%; 374 | } 375 | 376 | img.inline { 377 | max-width: 75%; 378 | } 379 | -------------------------------------------------------------------------------- /doc/doxy-boot.js: -------------------------------------------------------------------------------- 1 | $( document ).ready(function() { 2 | 3 | $("div.headertitle").addClass("page-header"); 4 | $("div.title").addClass("h1"); 5 | 6 | $('li > a[href="index.html"] > span').before(" "); 7 | $('li > a[href="modules.html"] > span').before(" "); 8 | $('li > a[href="namespaces.html"] > span').before(" "); 9 | $('li > a[href="annotated.html"] > span').before(" "); 10 | $('li > a[href="classes.html"] > span').before(" "); 11 | $('li > a[href="inherits.html"] > span').before(" "); 12 | $('li > a[href="functions.html"] > span').before(" "); 13 | $('li > a[href="functions_func.html"] > span').before(" "); 14 | $('li > a[href="functions_vars.html"] > span').before(" "); 15 | $('li > a[href="functions_enum.html"] > span').before(" "); 16 | $('li > a[href="functions_eval.html"] > span').before(" "); 17 | $('img[src="ftv2ns.png"]').replaceWith('N '); 18 | $('img[src="ftv2cl.png"]').replaceWith('C '); 19 | 20 | $("ul.tablist").addClass("nav nav-pills nav-justified"); 21 | $("ul.tablist").css("margin-top", "0.5em"); 22 | $("ul.tablist").css("margin-bottom", "0.5em"); 23 | $("li.current").addClass("active"); 24 | $("iframe").attr("scrolling", "yes"); 25 | 26 | $("#nav-path > ul").addClass("breadcrumb"); 27 | 28 | $("table.params").addClass("table"); 29 | $("div.ingroups").wrapInner(""); 30 | $("div.levels").css("margin", "0.5em"); 31 | $("div.levels > span").addClass("btn btn-default btn-xs"); 32 | $("div.levels > span").css("margin-right", "0.25em"); 33 | 34 | $("table.directory").addClass("table table-striped"); 35 | $("div.summary > a").addClass("btn btn-default btn-xs"); 36 | $("table.fieldtable").addClass("table"); 37 | $(".fragment").addClass("well"); 38 | $(".memitem").addClass("panel panel-default"); 39 | $(".memproto").addClass("panel-heading"); 40 | $(".memdoc").addClass("panel-body"); 41 | $("span.mlabel").addClass("label label-info"); 42 | 43 | $("table.memberdecls").addClass("table"); 44 | $("[class^=memitem]").addClass("active"); 45 | 46 | $("div.ah").addClass("btn btn-default"); 47 | $("span.mlabels").addClass("pull-right"); 48 | $("table.mlabels").css("width", "100%") 49 | $("td.mlabels-right").addClass("pull-right"); 50 | 51 | $("div.ttc").addClass("panel panel-primary"); 52 | $("div.ttname").addClass("panel-heading"); 53 | $("div.ttname a").css("color", 'white'); 54 | $("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body"); 55 | 56 | $('div.fragment.well div.line:first').css('margin-top', '2px'); 57 | $('div.fragment.well div.line:last').css('margin-bottom', '2px'); 58 | 59 | $('table.doxtable').removeClass('doxtable').addClass('table table-striped table-bordered').each(function(){ 60 | $(this).prepend(''); 61 | $(this).find('tbody > tr:first').prependTo($(this).find('thead')); 62 | 63 | $(this).find('td > span.success').parent().addClass('success'); 64 | $(this).find('td > span.warning').parent().addClass('warning'); 65 | $(this).find('td > span.danger').parent().addClass('danger'); 66 | }); 67 | 68 | 69 | 70 | if($('div.fragment.well div.ttc').length > 0) 71 | { 72 | $('div.fragment.well div.line:first').parent().removeClass('fragment well'); 73 | } 74 | 75 | $('table.memberdecls').find('.memItemRight').each(function(){ 76 | $(this).contents().appendTo($(this).siblings('.memItemLeft')); 77 | $(this).siblings('.memItemLeft').attr('align', 'left'); 78 | }); 79 | 80 | $('table.memberdecls').find('.memTemplItemRight').each(function(){ 81 | $(this).contents().appendTo($(this).siblings('.memTemplItemLeft')); 82 | $(this).siblings('.memTemplItemLeft').attr('align', 'left'); 83 | }); 84 | 85 | function getOriginalWidthOfImg(img_element) { 86 | var t = new Image(); 87 | t.src = (img_element.getAttribute ? img_element.getAttribute("src") : false) || img_element.src; 88 | return t.width; 89 | } 90 | 91 | $('div.dyncontent').find('img').each(function(){ 92 | if(getOriginalWidthOfImg($(this)[0]) > $('#content>div.container').width()) 93 | $(this).css('width', '100%'); 94 | }); 95 | 96 | 97 | /* responsive search box */ 98 | $('#MSearchBox').parent().remove(); 99 | 100 | var nav_container = $('
'); 101 | $('#navrow1').parent().prepend(nav_container); 102 | 103 | var left_nav = $('
'); 104 | for (i = 0; i < 6; i++) { 105 | var navrow = $('#navrow' + i + ' > ul.tablist').detach(); 106 | left_nav.append(navrow); 107 | $('#navrow' + i).remove(); 108 | } 109 | var right_nav = $('
').append('\ 110 | '); 121 | $(nav_container).append(left_nav); 122 | $(nav_container).append(right_nav); 123 | 124 | $('#MSearchSelectWindow .SelectionMark').remove(); 125 | var search_selectors = $('#MSearchSelectWindow .SelectItem'); 126 | for (var i = 0; i < search_selectors.length; i += 1) { 127 | var element_a = $('').text($(search_selectors[i]).text()); 128 | 129 | element_a.click(function(){ 130 | $('#search-box .dropdown-menu li').removeClass('active'); 131 | $(this).parent().addClass('active'); 132 | searchBox.OnSelectItem($('#search-box li a').index(this)); 133 | searchBox.Search(); 134 | return false; 135 | }); 136 | 137 | var element = $('
  • ').append(element_a); 138 | $('#search-box .dropdown-menu').append(element); 139 | } 140 | $('#MSearchSelectWindow').remove(); 141 | 142 | $('#search-box .close').click(function (){ 143 | searchBox.CloseResultsWindow(); 144 | }); 145 | 146 | $('body').append('
    '); 147 | $('body').append('
    '); 148 | $('body').append('
    '); 149 | 150 | searchBox.searchLabel = ''; 151 | searchBox.DOMSearchField = function() { 152 | return document.getElementById("search-field"); 153 | } 154 | searchBox.DOMSearchClose = function(){ 155 | return document.getElementById("search-close"); 156 | } 157 | 158 | 159 | /* search results */ 160 | var results_iframe = $('#MSearchResults').detach(); 161 | $('#MSearchResultsWindow') 162 | .attr('id', 'search-results-window') 163 | .addClass('panel panel-default') 164 | .append( 165 | '
    \ 166 |

    Search Results

    \ 167 |
    \ 168 |
    ' 169 | ); 170 | $('#search-results-window .panel-body').append(results_iframe); 171 | 172 | searchBox.DOMPopupSearchResultsWindow = function() { 173 | return document.getElementById("search-results-window"); 174 | } 175 | 176 | function update_search_results_window() { 177 | $('#search-results-window').removeClass('panel-default panel-success panel-warning panel-danger') 178 | var status = $('#MSearchResults').contents().find('.SRStatus:visible'); 179 | if (status.length > 0) { 180 | switch(status.attr('id')) { 181 | case 'Loading': 182 | case 'Searching': 183 | $('#search-results-window').addClass('panel-warning'); 184 | break; 185 | case 'NoMatches': 186 | $('#search-results-window').addClass('panel-danger'); 187 | break; 188 | default: 189 | $('#search-results-window').addClass('panel-default'); 190 | } 191 | } else { 192 | $('#search-results-window').addClass('panel-success'); 193 | } 194 | } 195 | $('#MSearchResults').load(function() { 196 | $('#MSearchResults').contents().find('link[href="search.css"]').attr('href','../doxygen.css'); 197 | $('#MSearchResults').contents().find('head').append( 198 | ''); 199 | 200 | update_search_results_window(); 201 | 202 | // detect status changes (only for search with external search backend) 203 | var observer = new MutationObserver(function(mutations) { 204 | update_search_results_window(); 205 | }); 206 | var config = { attributes: true}; 207 | 208 | var targets = $('#MSearchResults').contents().find('.SRStatus'); 209 | for (i = 0; i < targets.length; i++) { 210 | observer.observe(targets[i], config); 211 | } 212 | }); 213 | 214 | 215 | /* enumerations */ 216 | $('table.fieldtable').removeClass('fieldtable').addClass('table table-striped table-bordered').each(function(){ 217 | $(this).prepend(''); 218 | $(this).find('tbody > tr:first').prependTo($(this).find('thead')); 219 | 220 | $(this).find('td > span.success').parent().addClass('success'); 221 | $(this).find('td > span.warning').parent().addClass('warning'); 222 | $(this).find('td > span.danger').parent().addClass('danger'); 223 | }); 224 | 225 | /* todo list */ 226 | var todoelements = $('.contents > .textblock > dl.reflist > dt, .contents > .textblock > dl.reflist > dd'); 227 | for (var i = 0; i < todoelements.length; i += 2) { 228 | $('.contents > .textblock').append( 229 | '
    ' 230 | + "
    " + $(todoelements[i]).html() + "
    " 231 | + "
    " + $(todoelements[i+1]).html() + "
    " 232 | + '
    '); 233 | } 234 | $('.contents > .textblock > dl').remove(); 235 | 236 | 237 | $(".memitem").removeClass('memitem'); 238 | $(".memproto").removeClass('memproto'); 239 | $(".memdoc").removeClass('memdoc'); 240 | $("span.mlabel").removeClass('mlabel'); 241 | $("table.memberdecls").removeClass('memberdecls'); 242 | $("[class^=memitem]").removeClass('memitem'); 243 | $("span.mlabels").removeClass('mlabels'); 244 | $("table.mlabels").removeClass('mlabels'); 245 | $("td.mlabels-right").removeClass('mlabels-right'); 246 | $(".navpath").removeClass('navpath'); 247 | $("li.navelem").removeClass('navelem'); 248 | $("a.el").removeClass('el'); 249 | $("div.ah").removeClass('ah'); 250 | $("div.header").removeClass("header"); 251 | 252 | $('.mdescLeft').each(function(){ 253 | if($(this).html()==" ") { 254 | $(this).siblings('.mdescRight').attr('colspan', 2); 255 | $(this).remove(); 256 | } 257 | }); 258 | $('td.memItemLeft').each(function(){ 259 | if($(this).siblings('.memItemRight').html()=="") { 260 | $(this).attr('colspan', 2); 261 | $(this).siblings('.memItemRight').remove(); 262 | } 263 | }); 264 | $('td.memTemplItemLeft').each(function(){ 265 | if($(this).siblings('.memTemplItemRight').html()=="") { 266 | $(this).attr('colspan', 2); 267 | $(this).siblings('.memTemplItemRight').remove(); 268 | } 269 | }); 270 | searchBox.CloseResultsWindow(); 271 | }); 272 | -------------------------------------------------------------------------------- /doc/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /doc/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | $projectname: $title 15 | $title 16 | 17 | 18 | $treeview 19 | $search 20 | $mathjax 21 | 22 | $extrastylesheet 23 | 24 | 25 | 26 | 27 | 28 | 29 | 37 |
    38 |
    39 |
    40 |
    41 |
    42 |
    43 | 44 | -------------------------------------------------------------------------------- /doc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/doc/logo.png -------------------------------------------------------------------------------- /examples/minimal_application.c: -------------------------------------------------------------------------------- 1 | #define SDL_MAIN_HANDLED 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void key_down_callback(esz_window_t* window, esz_core_t* core); 9 | 10 | int main() 11 | { 12 | esz_status status; 13 | esz_window_t* window = NULL; 14 | esz_window_config_t config = { 640, 360, 384, 216, false, false }; 15 | esz_core_t* core = NULL; 16 | 17 | status = esz_create_window("eszFW", &config, &window); 18 | if (ESZ_OK != status) 19 | { 20 | goto quit; 21 | } 22 | 23 | status = esz_init_core(&core); 24 | if (ESZ_OK != status) 25 | { 26 | goto quit; 27 | } 28 | 29 | if (ESZ_OK == esz_load_map("res/maps/example.tmx", window, core)) 30 | { 31 | esz_register_event_callback(EVENT_KEYDOWN, &key_down_callback, core); 32 | } 33 | else 34 | { 35 | esz_deactivate_core(core); 36 | } 37 | 38 | while (esz_is_core_active(core)) 39 | { 40 | esz_update_core(window, core); 41 | 42 | status = esz_show_scene(window, core); 43 | if (ESZ_ERROR_CRITICAL == status) 44 | { 45 | break; 46 | } 47 | } 48 | 49 | quit: 50 | if (esz_is_map_loaded(core)) 51 | { 52 | esz_unload_map(window, core); 53 | } 54 | if (core) 55 | { 56 | esz_destroy_core(core); 57 | } 58 | if (window) 59 | { 60 | esz_destroy_window(window); 61 | } 62 | 63 | if (ESZ_OK != status) 64 | { 65 | return EXIT_FAILURE; 66 | } 67 | 68 | return EXIT_SUCCESS; 69 | } 70 | 71 | static void key_down_callback(esz_window_t* window, esz_core_t* core) 72 | { 73 | switch (esz_get_keycode(core)) 74 | { 75 | case SDLK_q: 76 | esz_deactivate_core(core); 77 | break; 78 | case SDLK_F11: 79 | esz_toggle_fullscreen(window); 80 | break; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /external/.gitignore: -------------------------------------------------------------------------------- 1 | SDL2-* 2 | -------------------------------------------------------------------------------- /external/Android.mk: -------------------------------------------------------------------------------- 1 | include $(call all-subdir-makefiles) 2 | -------------------------------------------------------------------------------- /media/demo-01-tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/media/demo-01-tn.png -------------------------------------------------------------------------------- /media/demo-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/media/demo-01.png -------------------------------------------------------------------------------- /media/demo-02-tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/media/demo-02-tn.png -------------------------------------------------------------------------------- /media/demo-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mupfdev/eszFW/31c04ccf1c109c39cbed761f1af0618187966878/media/demo-02.png -------------------------------------------------------------------------------- /src/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_C_INCLUDES := $(LOCAL_PATH) 6 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) 7 | 8 | LOCAL_MODULE := eszFW 9 | 10 | LOCAL_SRC_FILES := $(LOCAL_PATH)/esz.c 11 | 12 | LOCAL_CFLAGS := -D_REENTRANT -DWANT_ZLIB 13 | 14 | LOCAL_LDLIBS := -lz 15 | 16 | LOCAL_STATIC_LIBRARIES := 17 | LOCAL_SHARED_LIBRARIES := tmx SDL2 SDL2_image 18 | 19 | include $(BUILD_SHARED_LIBRARY) 20 | -------------------------------------------------------------------------------- /src/esz.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz.h 4 | * @brief eszFW main include header 5 | * @example minimal_application.c 6 | */ 7 | #ifndef ESZ_H 8 | #define ESZ_H 9 | 10 | #include 11 | #include 12 | #include "esz_types.h" 13 | 14 | /** 15 | * @brief Check if two axis-aligned bounding boxes intersect 16 | * @param bb_a Box A 17 | * @param bb_b Box B 18 | * @return Boolean condition 19 | * @retval true The boxes intersect 20 | * @retval false The boxes do not intersect 21 | */ 22 | bool esz_bounding_boxes_do_intersect(const esz_aabb_t bb_a, const esz_aabb_t bb_b); 23 | 24 | /** 25 | * @brief Clears state of player actor 26 | * @param state Actor state ID 27 | * @param core Engine core 28 | */ 29 | void esz_clear_player_state(esz_state state, esz_core_t* core); 30 | 31 | /** 32 | * @brief Create window and rendering context 33 | * @details It tries to use the opengl rendering driver. If the driver 34 | * is not found, the system's default driver is used instead. 35 | * @param window_title The window title 36 | * @param config Initial window configuration 37 | * @param window Pointer to window handle 38 | * @return Status code 39 | * @retval ESZ_OK OK 40 | * @retval ESZ_ERROR_CRITICAL 41 | * Critical error; the application should be terminated 42 | */ 43 | esz_status esz_create_window(const char* window_title, esz_window_config_t* config, esz_window_t** window); 44 | 45 | /** 46 | * @brief Deactivate engine core 47 | * @details Can be used to signal the application that the program 48 | * should be terminated. 49 | * @param core Engine core 50 | */ 51 | void esz_deactivate_core(esz_core_t* core); 52 | 53 | /** 54 | * @brief Destroy engine core 55 | * @attention Before calling this function, make sure that no map is 56 | * loaded for this core! 57 | * @param core Engine core 58 | */ 59 | void esz_destroy_core(esz_core_t* core); 60 | 61 | /** 62 | * @brief Destroy window and rendering context 63 | * @details This function should be called when exiting the application. 64 | * @param window Window handle 65 | */ 66 | void esz_destroy_window(esz_window_t* window); 67 | 68 | /** 69 | * @brief Get boolean map property 70 | * @param name_hash Hash of the property name. 71 | * @param core Engine core 72 | * @return Boolean value, or 0.0 if not property does not exist 73 | */ 74 | bool esz_get_boolean_map_property(const uint64_t name_hash, esz_core_t* core); 75 | 76 | /** 77 | * @brief Get decimal map property 78 | * @param name_hash Hash of the property name. 79 | * @param core Engine core 80 | * @return Boolean value, or false if property does not exist 81 | */ 82 | double esz_get_decimal_map_property(const uint64_t name_hash, esz_core_t* core); 83 | 84 | /** 85 | * @brief Get integer map property 86 | * @param name_hash Hash of the property name. 87 | * @param core Engine core 88 | * @return Integer value, or 0 if property does not exist 89 | */ 90 | int32_t esz_get_integer_map_property(const uint64_t name_hash, esz_core_t* core); 91 | 92 | /** 93 | * @brief Get string or file type map property 94 | * @param name_hash Hash of the property name. 95 | * @param core Engine core 96 | * @return The string, or NULL if property does not exist 97 | */ 98 | const char* esz_get_string_map_property(const uint64_t name_hash, esz_core_t* core); 99 | 100 | /** 101 | * @brief Get the current state of the keyboard 102 | * @return Returns a pointer to am array of key states. Indexes into 103 | * this array are obtained by using SDL_Scancode values: See 104 | * https://wiki.libsdl.org/SDL_Scancode 105 | */ 106 | const uint8_t* esz_get_keyboard_state(void); 107 | 108 | /** 109 | * @brief Get the current keycode 110 | * @param core Engine core 111 | 112 | * @return SDL_Keycode value. See https://wiki.libsdl.org/SDL_Keycode 113 | * for details 114 | */ 115 | int32_t esz_get_keycode(esz_core_t* core); 116 | 117 | /** 118 | * @brief Get the time since the last frame in seconds 119 | * @param window Window handle 120 | * @return Time since last frame in seconds 121 | */ 122 | double esz_get_time_since_last_frame(esz_window_t* window); 123 | 124 | /** 125 | * @brief Hide render layer for debugging purposes 126 | * @param layer Layer to hide 127 | * @param core Engine core 128 | */ 129 | void esz_hide_render_layer(esz_render_layer layer, esz_core_t* core); 130 | 131 | /** 132 | * @brief Initialise engine core 133 | * @param core Engine core 134 | * @return Status code 135 | * @retval ESZ_OK OK 136 | * @retval ESZ_ERROR_CRITICAL 137 | * Critical error; the application should be terminated 138 | */ 139 | esz_status esz_init_core(esz_core_t** core); 140 | 141 | /** 142 | * @brief Check if the camera is currently locked 143 | * @param core Engine core 144 | * @return Boolean condition 145 | */ 146 | bool esz_is_camera_locked(esz_core_t* core); 147 | 148 | /** 149 | * @brief Check if engine core is currently active 150 | * @param core Engine core 151 | * @return Boolean condition 152 | * @retval true Engine core is active 153 | * @retval false Engine core is not active 154 | */ 155 | bool esz_is_core_active(esz_core_t* core); 156 | 157 | /** 158 | * @brief Check if a map is currently loaded 159 | * @param core Engine core 160 | * @return Boolean condition 161 | * @retval true Map is loaded 162 | * @retval false Map is not loaded 163 | */ 164 | bool esz_is_map_loaded(esz_core_t* core); 165 | 166 | /** 167 | * @brief Check if the active player actor is currently moving 168 | * @param core Engine core 169 | * @return Boolean condition 170 | */ 171 | bool esz_is_player_moving(esz_core_t* core); 172 | 173 | /** 174 | * @brief Load map file 175 | * @attention Before calling this function, make sure that the engine 176 | * core has been initialised! 177 | * @param map_file_name Path and file name to the map file 178 | * @param window Window handle 179 | * @param core Engine core 180 | * @return Status code 181 | * @retval ESZ_OK OK 182 | * @retval ESZ_WARNING Map could not be loaded 183 | */ 184 | esz_status esz_load_map(const char* map_file_name, esz_window_t* window, esz_core_t* core); 185 | 186 | /** 187 | * @brief Lock camera for engine core 188 | * @details If the camera is locked, it automatically follows the main 189 | * player actor. 190 | * @param core Engine core 191 | */ 192 | void esz_lock_camera(esz_core_t* core); 193 | 194 | /** 195 | * @brief Register callback function which is called when the event 196 | * occurs 197 | * @param event_type Event type 198 | * @param event_callback Callback function 199 | * @param core Engine core 200 | */ 201 | void esz_register_event_callback(const esz_event_type event_type, esz_event_callback event_callback, esz_core_t* core); 202 | 203 | /** 204 | * @brief Set active player actor 205 | * @param id Actor ID 206 | * @param core Engine core 207 | */ 208 | void esz_set_active_player_actor(int32_t id, esz_core_t* core); 209 | 210 | /** 211 | * @brief Set the position of the camera 212 | * @remark The camera has to be unlocked. 213 | * @param pos_x Position along the x-axis 214 | * @param pos_y Position along the y-axis 215 | * @param pos_is_relative Use relative instead of absolute position 216 | * @param window Window handle 217 | * @param core Engine core 218 | */ 219 | void esz_set_camera_position(const double pos_x, const double pos_y, bool pos_is_relative, esz_window_t* window, esz_core_t* core); 220 | 221 | /** 222 | * @brief Set the position of the camera 223 | * @remark The camera has to be locked. 224 | * @param id Actor ID 225 | * @param core Engine core 226 | */ 227 | void esz_set_camera_target(const int32_t id, esz_core_t* core); 228 | 229 | /** 230 | * @brief Select and set the next animation of active player actor 231 | * @details If the last animation is skipped, it selects the first one 232 | * again. 233 | * @remark This function is mainly intended for debugging purposes. 234 | * @param core Engine core 235 | */ 236 | void esz_set_next_player_animation(esz_core_t* core); 237 | 238 | /** 239 | * @brief Set animation of active player actor 240 | * @param id Animation ID 241 | * @param core Engine core 242 | */ 243 | void esz_set_player_animation(int32_t id, esz_core_t* core); 244 | 245 | /** 246 | * @brief Set state of player actor 247 | * @param state Actor state ID 248 | * @param core Engine core 249 | */ 250 | void esz_set_player_state(esz_state state, esz_core_t* core); 251 | 252 | /** 253 | * @brief Set the window's zoom level 254 | * @param factor Zoom factor 255 | * @param window Window handle 256 | * @return Status code 257 | * @retval ESZ_OK OK 258 | * @retval ESZ_WARNING 259 | * The zoom-level could not be set 260 | */ 261 | esz_status esz_set_zoom_level(const double factor, esz_window_t* window); 262 | 263 | /** 264 | * @brief Show previously hidden render layer for debugging purposes 265 | * @param layer Layer to show 266 | * @param core Engine core 267 | */ 268 | void esz_show_render_layer(esz_render_layer layer, esz_core_t* core); 269 | 270 | /** 271 | * @brief Render and draw the current scene 272 | * @param window Window handle 273 | * @param core Engine core 274 | * @return Status code 275 | * @retval ESZ_OK OK 276 | * @retval ESZ_ERROR_CRITICAL 277 | * Critical error; the application should be terminated 278 | */ 279 | esz_status esz_show_scene(esz_window_t* window, esz_core_t* core); 280 | 281 | /** 282 | * @brief Toggle between fullscreen and windowed mode 283 | * @param window Window handle 284 | * @return Status code 285 | * @retval ESZ_OK OK 286 | * @retval ESZ_WARNING 287 | * Fullscreen could not be toggled 288 | */ 289 | esz_status esz_toggle_fullscreen(esz_window_t* window); 290 | 291 | /** 292 | * @brief Trigger action for player enttiy 293 | * @param action Enity action ID 294 | * @param core Engine core 295 | */ 296 | void esz_trigger_player_action(esz_action action, esz_core_t* core); 297 | 298 | /** 299 | * @brief Unload current map 300 | * @remark It's always safe to call this function; if no map is 301 | * currently loaded, the function does nothing. 302 | * @param window Window handle 303 | * @param core Engine core 304 | */ 305 | void esz_unload_map(esz_window_t* window, esz_core_t* core); 306 | 307 | /** 308 | * @brief Unlock camera for engine core 309 | * @details If the camera is unlocked, it can be moved freely around the map. 310 | * @param core Engine core 311 | */ 312 | void esz_unlock_camera(esz_core_t* core); 313 | 314 | /** 315 | * @brief Update engine core 316 | * @details This function should be called cyclically in the main loop 317 | * of the application. 318 | * @param window Window handle 319 | * @param core Engine core 320 | */ 321 | void esz_update_core(esz_window_t* window, esz_core_t* core); 322 | 323 | #endif // ESZ_H 324 | -------------------------------------------------------------------------------- /src/esz_compat.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_compat.c 4 | * @brief eszFW compatibility layer 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "esz_compat.h" 14 | #include "esz_hash.h" 15 | #include "esz_macros.h" 16 | #include "esz_types.h" 17 | 18 | DISABLE_WARNING_PUSH 19 | DISABLE_WARNING_PADDING 20 | DISABLE_WARNING_SPECTRE_MITIGATION 21 | 22 | #include 23 | 24 | #ifdef USE_LIBTMX 25 | #include 26 | #else // (cute_tiled.h) 27 | #define CUTE_TILED_IMPLEMENTATION 28 | #include 29 | #endif 30 | 31 | DISABLE_WARNING_SYMBOL_NOT_DEFINED 32 | 33 | #include 34 | #include 35 | 36 | DISABLE_WARNING_POP 37 | 38 | #ifdef USE_LIBTMX 39 | static void tmxlib_store_property(esz_tiled_property_t* property, void* core); 40 | #endif 41 | 42 | int32_t get_first_gid(esz_tiled_map_t* tiled_map) 43 | { 44 | #ifdef USE_LIBTMX 45 | return (int32_t)tiled_map->ts_head->firstgid; 46 | 47 | #else // (cute_tiled.h) 48 | return tiled_map->tilesets->firstgid; 49 | 50 | #endif 51 | } 52 | 53 | esz_tiled_layer_t* get_head_layer(esz_tiled_map_t* tiled_map) 54 | { 55 | #ifdef USE_LIBTMX 56 | return tiled_map->ly_head; 57 | 58 | #else // (cute_tiled.h) 59 | return tiled_map->layers; 60 | 61 | #endif 62 | } 63 | 64 | esz_tiled_object_t* get_head_object(esz_tiled_layer_t* tiled_layer, esz_core_t* core) 65 | { 66 | if (is_tiled_layer_of_type(ESZ_OBJECT_GROUP, tiled_layer, core)) 67 | { 68 | #ifdef USE_LIBTMX 69 | return tiled_layer->content.objgr->head; 70 | 71 | #else // (cute_tiled.h) 72 | return tiled_layer->objects; 73 | 74 | #endif 75 | } 76 | 77 | return NULL; 78 | } 79 | 80 | esz_tiled_tileset_t* get_head_tileset(esz_tiled_map_t* tiled_map) 81 | { 82 | #ifdef USE_LIBTMX 83 | int32_t first_gid = get_first_gid(tiled_map); 84 | return tiled_map->tiles[first_gid]->tileset; 85 | 86 | #else // (cute_tiled.h) 87 | return tiled_map->tilesets; 88 | 89 | #endif 90 | } 91 | 92 | int32_t* get_layer_content(esz_tiled_layer_t* tiled_layer) 93 | { 94 | #ifdef USE_LIBTMX 95 | return (int32_t*)tiled_layer->content.gids; 96 | 97 | #else // (cute_tiled.h) 98 | return tiled_layer->data; 99 | 100 | #endif 101 | } 102 | 103 | const char* get_layer_name(esz_tiled_layer_t* tiled_layer) 104 | { 105 | #ifdef USE_LIBTMX 106 | return tiled_layer->name; 107 | 108 | #else // (cute_tiled.h) 109 | return tiled_layer->name.ptr; 110 | 111 | #endif 112 | } 113 | 114 | int32_t get_layer_property_count(esz_tiled_layer_t* tiled_layer) 115 | { 116 | #ifdef USE_LIBTMX 117 | (void)tiled_layer; 118 | return 0; 119 | 120 | #else // (cute_tiled.h) 121 | return tiled_layer->property_count; 122 | 123 | #endif 124 | } 125 | 126 | int32_t get_local_id(int32_t gid, esz_tiled_map_t* tiled_map) 127 | { 128 | #ifdef USE_LIBTMX 129 | (void)tiled_map; 130 | return gid; 131 | 132 | #else // (cute_tiled.h) 133 | int32_t local_id = gid - get_first_gid(tiled_map); 134 | 135 | return local_id >= 0 ? local_id : 0; 136 | 137 | #endif 138 | } 139 | 140 | int32_t get_map_property_count(esz_tiled_map_t* tiled_map) 141 | { 142 | #ifdef USE_LIBTMX 143 | (void)tiled_map; 144 | return 0; 145 | 146 | #else // (cute_tiled.h) 147 | return tiled_map->property_count; 148 | 149 | #endif 150 | } 151 | 152 | int32_t get_next_animated_tile_id(int32_t gid, int32_t current_frame, esz_tiled_map_t* tiled_map) 153 | { 154 | #ifdef USE_LIBTMX 155 | return (int32_t)tiled_map->tiles[gid]->animation[current_frame].tile_id; 156 | 157 | #else // (cute_tiled.h) 158 | esz_tiled_tileset_t* tileset = get_head_tileset(tiled_map); 159 | cute_tiled_tile_descriptor_t* tile = tileset->tiles; 160 | while (tile) 161 | { 162 | if (tile->tile_index == gid) 163 | { 164 | return tile->animation[current_frame].tileid; 165 | } 166 | tile = tile->next; 167 | } 168 | 169 | #endif 170 | 171 | return 0; 172 | } 173 | 174 | const char* get_object_name(esz_tiled_object_t* tiled_object) 175 | { 176 | #ifdef USE_LIBTMX 177 | return tiled_object->name; 178 | 179 | #else // (cute_tiled.h) 180 | return tiled_object->name.ptr; 181 | 182 | #endif 183 | } 184 | 185 | int32_t get_object_property_count(esz_tiled_object_t* tiled_object) 186 | { 187 | #ifdef USE_LIBTMX 188 | (void)tiled_object; 189 | return 0; 190 | 191 | #else // (cute_tiled.h) 192 | return tiled_object->property_count; 193 | 194 | #endif 195 | } 196 | 197 | const char* get_object_type_name(esz_tiled_object_t* tiled_object) 198 | { 199 | #ifdef USE_LIBTMX 200 | return tiled_object->type; 201 | 202 | #else // (cute_tiled.h) 203 | return tiled_object->type.ptr; 204 | 205 | #endif 206 | } 207 | 208 | int32_t get_tile_height(esz_tiled_map_t* tiled_map) 209 | { 210 | #ifdef USE_LIBTMX 211 | int32_t first_gid = get_first_gid(tiled_map); 212 | return (int32_t)tiled_map->tiles[first_gid]->tileset->tile_height; 213 | 214 | #else // (cute_tiled.h) 215 | return tiled_map->tilesets->tileheight; 216 | 217 | #endif 218 | } 219 | 220 | void get_tile_position(int32_t gid, int32_t* pos_x, int32_t* pos_y, esz_tiled_map_t* tiled_map) 221 | { 222 | #ifdef USE_LIBTMX 223 | *pos_x = (int32_t)tiled_map->tiles[gid]->ul_x; 224 | *pos_y = (int32_t)tiled_map->tiles[gid]->ul_y; 225 | 226 | #else // (cute_tiled.h) 227 | esz_tiled_tileset_t* tileset = tiled_map->tilesets; 228 | int32_t local_id = get_local_id(gid, tiled_map); 229 | 230 | *pos_x = (local_id % tileset->columns) * get_tile_width(tiled_map); 231 | *pos_y = (local_id / tileset->columns) * get_tile_height(tiled_map); 232 | 233 | #endif 234 | } 235 | 236 | int32_t get_tile_property_count(esz_tiled_tile_t* tiled_tile) 237 | { 238 | #ifdef USE_LIBTMX 239 | (void)tiled_tile; 240 | return 0; 241 | 242 | #else // (cute_tiled.h) 243 | return tiled_tile->property_count; 244 | 245 | #endif 246 | } 247 | 248 | int32_t get_tile_width(esz_tiled_map_t* tiled_map) 249 | { 250 | #ifdef USE_LIBTMX 251 | int32_t first_gid = get_first_gid(tiled_map); 252 | return (int32_t)tiled_map->tiles[first_gid]->tileset->tile_width; 253 | 254 | #else // (cute_tiled.h) 255 | return tiled_map->tilesets->tilewidth; 256 | 257 | #endif 258 | } 259 | 260 | void set_tileset_path(char* path_name, int32_t path_length, esz_core_t* core) 261 | { 262 | #ifdef USE_LIBTMX 263 | int32_t first_gid = get_first_gid(core->map->handle); 264 | char ts_path[64] = { 0 }; 265 | size_t ts_path_length = 0; 266 | 267 | cwk_path_get_dirname(core->map->handle->ts_head->source, &ts_path_length); 268 | 269 | if (63 <= ts_path_length) 270 | { 271 | ts_path_length = 63; 272 | } 273 | 274 | /* The tileset image source is stored relatively to the tileset 275 | * file but because we only know the location of the tileset 276 | * file relatively to the map file, we need to adjust the path 277 | * accordingly. It's a hack, but it works. 278 | */ 279 | 280 | SDL_strlcpy(ts_path, core->map->handle->ts_head->source, ts_path_length + 1); 281 | stbsp_snprintf(path_name, (int32_t)path_length, "%s%s%s", 282 | core->map->path, 283 | ts_path, 284 | core->map->handle->tiles[first_gid]->tileset->image->source); 285 | 286 | #else // (cute_tiled.h) 287 | stbsp_snprintf(path_name, (int32_t)path_length, "%s%s", 288 | core->map->path, 289 | core->map->handle->tilesets->image.ptr); 290 | 291 | #endif 292 | } 293 | 294 | int32_t get_tileset_path_length(esz_core_t* core) 295 | { 296 | int32_t path_length = 0; 297 | 298 | #ifdef USE_LIBTMX 299 | int32_t first_gid = get_first_gid(core->map->handle); 300 | size_t ts_path_length = 0; 301 | 302 | cwk_path_get_dirname(core->map->handle->ts_head->source, &ts_path_length); 303 | 304 | path_length += (int32_t)strnlen(core->map->path, 64); 305 | path_length += strnlen(core->map->handle->tiles[first_gid]->tileset->image->source, 64); 306 | path_length += (int32_t)ts_path_length + 1; 307 | 308 | #else // (cute_tiled.h) 309 | if (! core->map->handle->tilesets) 310 | { 311 | plog_error("%s: no embedded tileset found.", __func__); 312 | return 0; 313 | } 314 | 315 | path_length += (int32_t)strnlen(core->map->path, 64); 316 | path_length += (int32_t)strnlen(core->map->handle->tilesets->image.ptr, 64); 317 | path_length += 1; 318 | 319 | #endif 320 | 321 | return path_length; 322 | } 323 | 324 | bool is_gid_valid(int32_t gid, esz_tiled_map_t* tiled_map) 325 | { 326 | #ifdef USE_LIBTMX 327 | if (tiled_map->tiles[gid]) 328 | { 329 | return true; 330 | } 331 | #else // (cute_tiled.h) 332 | (void)tiled_map; 333 | 334 | if (gid) 335 | { 336 | return true; 337 | } 338 | 339 | #endif 340 | return false; 341 | } 342 | 343 | bool is_tile_animated(int32_t gid, int32_t* animation_length, int32_t* id, esz_tiled_map_t* tiled_map) 344 | { 345 | int32_t local_id = get_local_id(gid, tiled_map); 346 | 347 | #ifdef USE_LIBTMX 348 | if (tiled_map->tiles[local_id]) 349 | { 350 | if (tiled_map->tiles[local_id]->animation) 351 | { 352 | if (animation_length) 353 | { 354 | *animation_length = (int32_t)tiled_map->tiles[local_id]->animation_len; 355 | } 356 | if (id) 357 | { 358 | *id = (int32_t)tiled_map->tiles[local_id]->animation[0].tile_id; 359 | } 360 | return true; 361 | } 362 | } 363 | 364 | #else // (cute_tiled.h) 365 | esz_tiled_tileset_t* tileset = tiled_map->tilesets; 366 | esz_tiled_tile_t* tile = tileset->tiles; 367 | 368 | while (tile) 369 | { 370 | if (tile->tile_index == local_id) 371 | { 372 | if (tile->animation) 373 | { 374 | if (animation_length) 375 | { 376 | *animation_length = tile->frame_count; 377 | } 378 | if (id) 379 | { 380 | *id = tile->animation->tileid; 381 | } 382 | return true; 383 | } 384 | } 385 | tile = tile->next; 386 | } 387 | 388 | #endif 389 | 390 | return false; 391 | } 392 | 393 | bool is_tiled_layer_of_type(const esz_tiled_layer_type tiled_type, esz_tiled_layer_t* tiled_layer, esz_core_t* core) 394 | { 395 | switch (tiled_type) 396 | { 397 | case ESZ_TILE_LAYER: 398 | #ifdef USE_LIBTMX 399 | (void)core; 400 | 401 | if (L_LAYER == tiled_layer->type) 402 | { 403 | return true; 404 | } 405 | 406 | #else // (cute_tiled.h) 407 | if (core->map->hash_id_tilelayer == tiled_layer->type.hash_id) 408 | { 409 | return true; 410 | } 411 | 412 | #endif 413 | break; 414 | case ESZ_OBJECT_GROUP: 415 | #ifdef USE_LIBTMX 416 | if (L_OBJGR == tiled_layer->type) 417 | { 418 | return true; 419 | } 420 | 421 | #else // (cute_tiled.h) 422 | if (core->map->hash_id_objectgroup == tiled_layer->type.hash_id) 423 | { 424 | return true; 425 | } 426 | 427 | #endif 428 | break; 429 | } 430 | 431 | return false; 432 | } 433 | 434 | void load_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core) 435 | { 436 | #ifdef USE_LIBTMX 437 | (void)property_count; 438 | core->map->hash_query = name_hash; 439 | tmx_property_foreach(properties, tmxlib_store_property, (void*)core); 440 | 441 | #else // (cute_tiled.h) 442 | int index = 0; 443 | 444 | for (index = 0; index < property_count; index += 1) 445 | { 446 | if (name_hash == generate_hash((const unsigned char*)properties[index].name.ptr)) 447 | { 448 | break; 449 | } 450 | } 451 | 452 | if (properties[index].name.ptr) 453 | { 454 | switch (properties[index].type) 455 | { 456 | case CUTE_TILED_PROPERTY_COLOR: 457 | case CUTE_TILED_PROPERTY_FILE: 458 | case CUTE_TILED_PROPERTY_NONE: 459 | break; 460 | case CUTE_TILED_PROPERTY_INT: 461 | plog_debug("Loading integer property '%s': %d", properties[index].name.ptr, properties[index].data.integer); 462 | 463 | core->map->integer_property = properties[index].data.integer; 464 | break; 465 | case CUTE_TILED_PROPERTY_BOOL: 466 | plog_debug("Loading boolean property '%s': %u", properties[index].name.ptr, properties[index].data.boolean); 467 | 468 | core->map->boolean_property = (bool)properties[index].data.boolean; 469 | break; 470 | case CUTE_TILED_PROPERTY_FLOAT: 471 | plog_debug("Loading decimal property '%s': %f", properties[index].name.ptr, (double)properties[index].data.floating); 472 | 473 | core->map->decimal_property = (double)properties[index].data.floating; 474 | break; 475 | case CUTE_TILED_PROPERTY_STRING: 476 | plog_debug("Loading string property '%s': %s", properties[index].name.ptr, properties[index].data.string.ptr); 477 | 478 | core->map->string_property = properties[index].data.string.ptr; 479 | break; 480 | } 481 | } 482 | #endif 483 | } 484 | 485 | esz_status load_tiled_map(const char* map_file_name, esz_core_t* core) 486 | { 487 | FILE* fp = fopen(map_file_name, "r"); 488 | 489 | if (fp) 490 | { 491 | fclose(fp); 492 | } 493 | else 494 | { 495 | plog_error("%s: %s not found.", __func__, map_file_name); 496 | return ESZ_WARNING; 497 | } 498 | 499 | #ifdef USE_LIBTMX 500 | core->map->handle = (esz_tiled_map_t*)tmx_load(map_file_name); 501 | if (! core->map->handle) 502 | { 503 | plog_error("%s: %s.", __func__, tmx_strerr()); 504 | return ESZ_WARNING; 505 | } 506 | 507 | #else // (cute_tiled.h) 508 | esz_tiled_layer_t* layer; 509 | 510 | core->map->handle = (esz_tiled_map_t*)cute_tiled_load_map_from_file(map_file_name, NULL); 511 | if (! core->map->handle) 512 | { 513 | plog_error("%s: %s.", __func__, cute_tiled_error_reason); 514 | return ESZ_WARNING; 515 | } 516 | 517 | layer = get_head_layer(core->map->handle); 518 | while (layer) 519 | { 520 | if (H_tilelayer == generate_hash((const unsigned char*)layer->type.ptr) && !core->map->hash_id_tilelayer) 521 | { 522 | core->map->hash_id_tilelayer = layer->type.hash_id; 523 | plog_info("Set hash ID for tile layer: %llu", core->map->hash_id_tilelayer); 524 | } 525 | else if (H_objectgroup == generate_hash((const unsigned char*)layer->type.ptr) && !core->map->hash_id_objectgroup) 526 | { 527 | core->map->hash_id_objectgroup = layer->type.hash_id; 528 | plog_info("Set hash ID for object group: %llu", core->map->hash_id_objectgroup); 529 | } 530 | layer = layer->next; 531 | } 532 | 533 | #endif 534 | 535 | return ESZ_OK; 536 | } 537 | 538 | int32_t remove_gid_flip_bits(int32_t gid) 539 | { 540 | #ifdef USE_LIBTMX 541 | return gid & TMX_FLIP_BITS_REMOVAL; 542 | 543 | #else // (cute_tiled.h) 544 | return cute_tiled_unset_flags(gid); 545 | 546 | #endif 547 | } 548 | 549 | bool tile_has_properties(int32_t gid, esz_tiled_tile_t** tile, esz_tiled_map_t* tiled_map) 550 | { 551 | int32_t local_id; 552 | 553 | #ifdef USE_LIBTMX 554 | return true; 555 | 556 | #else // (cute_tiled.h) 557 | local_id = gid - get_first_gid(tiled_map); 558 | 559 | while ((*tile)) 560 | { 561 | if ((*tile)->tile_index == local_id) 562 | { 563 | if (0 < (*tile)->property_count) 564 | { 565 | return true; 566 | } 567 | } 568 | (*tile) = (*tile)->next; 569 | } 570 | 571 | #endif 572 | 573 | return false; 574 | } 575 | 576 | void unload_tiled_map(esz_core_t* core) 577 | { 578 | #ifdef USE_LIBTMX 579 | if (core->map->handle) 580 | { 581 | tmx_map_free(core->map->handle); 582 | } 583 | 584 | #else // (cute_tiled.h) 585 | core->map->hash_id_objectgroup = 0; 586 | core->map->hash_id_tilelayer = 0; 587 | 588 | if (core->map->handle) 589 | { 590 | cute_tiled_free_map(core->map->handle); 591 | } 592 | #endif 593 | } 594 | 595 | #ifdef USE_LIBTMX 596 | static void tmxlib_store_property(esz_tiled_property_t* property, void* core) 597 | { 598 | esz_core_t* core_ptr = core; 599 | 600 | if (core_ptr->map->hash_query == generate_hash((const unsigned char*)property->name)) 601 | { 602 | switch (property->type) 603 | { 604 | case PT_COLOR: 605 | case PT_NONE: 606 | break; 607 | case PT_BOOL: 608 | plog_debug("Loading boolean property '%s': %u", property->name, property->value.boolean); 609 | 610 | core_ptr->map->boolean_property = (bool)property->value.boolean; 611 | break; 612 | case PT_FILE: 613 | plog_debug("Loading string property '%s': %s", property->name, property->value.file); 614 | 615 | core_ptr->map->string_property = property->value.file; 616 | break; 617 | case PT_FLOAT: 618 | plog_debug("Loading decimal property '%s': %f", property->name, (double)property->value.decimal); 619 | 620 | core_ptr->map->decimal_property = (double)property->value.decimal; 621 | break; 622 | case PT_INT: 623 | plog_debug("Loading integer property '%s': %d", property->name, property->value.integer); 624 | 625 | core_ptr->map->integer_property = property->value.integer; 626 | break; 627 | case PT_STRING: 628 | plog_debug("Loading string property '%s': %s", property->name, property->value.string); 629 | 630 | core_ptr->map->string_property = property->value.string; 631 | break; 632 | } 633 | } 634 | } 635 | #endif 636 | -------------------------------------------------------------------------------- /src/esz_compat.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_compat.h 4 | * @brief eszFW compatibility layer 5 | * @details Functions used to maintain compatibility between libTMX and 6 | * cute_tiled. 7 | */ 8 | 9 | #ifndef ESZ_COMPAT_H 10 | #define ESZ_COMPAT_H 11 | 12 | #include 13 | #include 14 | 15 | #include "esz_types.h" 16 | 17 | int32_t get_first_gid(esz_tiled_map_t* tiled_map); 18 | esz_tiled_layer_t* get_head_layer(esz_tiled_map_t* tiled_map); 19 | esz_tiled_object_t* get_head_object(esz_tiled_layer_t* tiled_layer, esz_core_t* core); 20 | esz_tiled_tileset_t* get_head_tileset(esz_tiled_map_t* tiled_map); 21 | int32_t* get_layer_content(esz_tiled_layer_t* tiled_layer); 22 | const char* get_layer_name(esz_tiled_layer_t* tiled_layer); 23 | int32_t get_layer_property_count(esz_tiled_layer_t* tiled_layer); 24 | int32_t get_local_id(int32_t gid, esz_tiled_map_t* tiled_map); 25 | int32_t get_map_property_count(esz_tiled_map_t* tiled_map); 26 | int32_t get_next_animated_tile_id(int32_t gid, int32_t current_frame, esz_tiled_map_t* tiled_map); 27 | const char* get_object_name(esz_tiled_object_t* tiled_object); 28 | int32_t get_object_property_count(esz_tiled_object_t* tiled_object); 29 | const char* get_object_type_name(esz_tiled_object_t* tiled_object); 30 | int32_t get_tile_height(esz_tiled_map_t* tiled_map); 31 | void get_tile_position(int32_t gid, int32_t* pos_x, int32_t* pos_y, esz_tiled_map_t* tiled_map); 32 | int32_t get_tile_property_count(esz_tiled_tile_t* tiled_tile); 33 | int32_t get_tile_width(esz_tiled_map_t* tiled_map); 34 | void set_tileset_path(char* path_name, int32_t path_length, esz_core_t* core); 35 | int32_t get_tileset_path_length(esz_core_t* core); 36 | bool is_gid_valid(int32_t gid, esz_tiled_map_t* tiled_map); 37 | bool is_tile_animated(int32_t gid, int32_t* animation_length, int32_t* id, esz_tiled_map_t* tiled_map); 38 | bool is_tiled_layer_of_type(const esz_tiled_layer_type tiled_type, esz_tiled_layer_t* tiled_layer, esz_core_t* core); 39 | void load_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core); 40 | esz_status load_tiled_map(const char* map_file_name, esz_core_t* core); 41 | int32_t remove_gid_flip_bits(int32_t gid); 42 | bool tile_has_properties(int32_t gid, esz_tiled_tile_t** tile, esz_tiled_map_t* tiled_map); 43 | void unload_tiled_map(esz_core_t* core); 44 | 45 | #endif // ESZ_COMPAT_H 46 | -------------------------------------------------------------------------------- /src/esz_hash.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_hash.c 4 | * @brief eszFW hash table and hash generator 5 | */ 6 | 7 | #include 8 | 9 | /* djb2 by Dan Bernstein 10 | * http://www.cse.yorku.ca/~oz/hash.html 11 | */ 12 | uint64_t generate_hash(const unsigned char* name) 13 | { 14 | uint64_t hash = 5381; 15 | uint32_t c; 16 | 17 | while ((c = *name++)) 18 | { 19 | hash = ((hash << 5) + hash) + c; 20 | } 21 | 22 | return hash; 23 | } 24 | -------------------------------------------------------------------------------- /src/esz_hash.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_hash.h 4 | * @brief eszFW hash table and hash generator 5 | */ 6 | 7 | #ifndef ESZ_HASHES_H 8 | #define ESZ_HASHES_H 9 | 10 | #include 11 | 12 | #define H_acceleration 0xce26e518186a848f 13 | #define H_anim_id_idle 0xce63c6afa347d913 14 | #define H_anim_id_jump 0xce63c6afa348adf1 15 | #define H_anim_id_run 0xc06fa12c1c38a36a 16 | #define H_anim_id_walk 0xce63c6afa34f79a4 17 | #define H_animated_tile_fps 0xf16ba347de2debdd 18 | #define H_background_constant_velocity 0x1cb19bb15ad8b7fc 19 | #define H_background_is_top_aligned 0xe10d87b900773f85 20 | #define H_background_layer_shift 0xf42f15f4c255007e 21 | #define H_climbable 0x0377c455420b8600 22 | #define H_connect_horizontal_map_ends 0xb2d77d5c88cb679e 23 | #define H_connect_vertical_map_ends 0x8fd9bf6992bca50e 24 | #define H_actor 0x000000310f128ebe 25 | #define H_gravitation 0xc090e5ec12404d2d 26 | #define H_height 0x0000065301d688de 27 | #define H_is_affected_by_gravity 0xd7df2608f228f6d1 28 | #define H_is_animated 0xc09beeb13eae4983 29 | #define H_is_in_background 0xdba806855b4839b6 30 | #define H_is_in_foreground 0xdba8c1d8d43eb8f1 31 | #define H_is_in_midground 0x7b0525da0f6ff45f 32 | #define H_is_left_oriented 0x1af19f00c7d179a4 33 | #define H_is_moving 0x0377cc4471f37f30 34 | #define H_is_player 0x0377cc4478b16e8d 35 | #define H_jumping_power 0x702da8a7606d92ab 36 | #define H_max_velocity_x 0xa1d4b1b096163590 37 | #define H_meter_in_pixel 0xfbbc8a6d4a407cf9 38 | #define H_opengl 0x0000065312ef9eea 39 | #define H_scancode_down 0x339db31fc86859fc 40 | #define H_scancode_jump 0x339db31fc86bbc80 41 | #define H_scancode_left 0x339db31fc86c904f 42 | #define H_scancode_right 0xa7541718d66d61e2 43 | #define H_scancode_up 0xc0cfb7feda9252a9 44 | #define H_scancode_quit 0x339db31fc86f92a7 45 | #define H_scancode_run 0xdac6b7da2cdc9c19 46 | #define H_scancode_toggle_fullscreen 0xebb406be8e806258 47 | #define H_scancode_unlock_camera 0x657e367e0c361b38 48 | #define H_solid_above 0xc0d1c0679690db0c 49 | #define H_solid_below 0xc0d1c06796a48b18 50 | #define H_solid_left 0x7272f650b702b58a 51 | #define H_solid_right 0xc0d1c06797c82e7d 52 | #define H_sprite_sheet_id 0xe2141daae50cd180 53 | #define H_width 0x0000003110a3b0a5 54 | 55 | #ifndef USE_LIBTMX // (cute_tiled.h) 56 | #define H_objectgroup 0xc0b9d518970be349 57 | #define H_tilelayer 0x0377d9f70e844fb0 58 | #endif 59 | 60 | uint64_t generate_hash(const unsigned char* name); 61 | 62 | #endif // ESZ_HASHES_H 63 | -------------------------------------------------------------------------------- /src/esz_init.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_init.h 4 | * @brief eszFW initialisation functions 5 | */ 6 | 7 | #ifndef ESZ_INIT_H 8 | #define ESZ_INIT_H 9 | 10 | #include 11 | #include 12 | 13 | #include "esz_types.h" 14 | 15 | esz_status load_animated_tiles(esz_core_t* core); 16 | esz_status load_background(esz_window_t* window, esz_core_t* core); 17 | esz_status load_entities(esz_core_t* core); 18 | esz_status load_map_path(const char* map_file_name, esz_core_t* core); 19 | esz_status load_sprites(esz_window_t* window, esz_core_t* core); 20 | esz_status load_tile_properties(esz_core_t* core); 21 | esz_status load_tileset(esz_window_t* window, esz_core_t*); 22 | esz_status load_texture_from_file(const char* file_name, SDL_Texture** texture, esz_window_t* window); 23 | esz_status load_texture_from_memory(const unsigned char* buffer, const int length, SDL_Texture** texture, esz_window_t* window); 24 | 25 | #endif // ESZ_INIT_H 26 | -------------------------------------------------------------------------------- /src/esz_macros.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_macros.h 4 | * @brief eszFW macros 5 | */ 6 | 7 | #ifndef ESZ_MACROS_H 8 | #define ESZ_MACROS_H 9 | 10 | #define CLR_STATE(number, bit) number &= ~(1UL << bit) 11 | #define SET_STATE(number, bit) number |= 1UL << bit 12 | #define IS_STATE_SET(number, bit) ((0U == (number & (1 << bit))) ? 0U : 1U) 13 | 14 | /* Based on 15 | * https://www.fluentcpp.com/2019/08/30/how-to-disable-a-warning-in-cpp/ 16 | */ 17 | #if defined(_MSC_VER) 18 | #define DISABLE_WARNING_PUSH __pragma(warning( push )) 19 | #define DISABLE_WARNING_POP __pragma(warning( pop )) 20 | #define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber )) 21 | 22 | #define DISABLE_WARNING_PADDING DISABLE_WARNING(4820) 23 | #define DISABLE_WARNING_SPECTRE_MITIGATION DISABLE_WARNING(5045) 24 | #define DISABLE_WARNING_SYMBOL_NOT_DEFINED DISABLE_WARNING(4668) 25 | 26 | #elif defined(__GNUC__) || defined(__clang__) 27 | #define DO_PRAGMA(X) _Pragma(#X) 28 | #define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push) 29 | #define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop) 30 | #define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName) 31 | 32 | #define DISABLE_WARNING_PADDING DISABLE_WARNING(-Wpadded) 33 | #define DISABLE_WARNING_SPECTRE_MITIGATION 34 | #define DISABLE_WARNING_SYMBOL_NOT_DEFINED 35 | 36 | #else 37 | #define DISABLE_WARNING_PUSH 38 | #define DISABLE_WARNING_POP 39 | #define DISABLE_WARNING_PADDING 40 | #define DISABLE_WARNING_SPECTRE_MITIGATION 41 | #define DISABLE_WARNING_SYMBOL_NOT_DEFINED 42 | 43 | #endif 44 | 45 | #endif // ESZ_MACROS_H 46 | -------------------------------------------------------------------------------- /src/esz_render.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_render.c 4 | * @brief eszFW rendering and scene drawing 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "esz_compat.h" 12 | #include "esz_hash.h" 13 | #include "esz_macros.h" 14 | #include "esz_types.h" 15 | #include "esz_utils.h" 16 | 17 | static esz_status render_background_layer(int32_t index, esz_window_t* window, esz_core_t* core); 18 | 19 | esz_status create_and_set_render_target(SDL_Texture** target, esz_window_t* window) 20 | { 21 | if (! (*target)) 22 | { 23 | (*target) = SDL_CreateTexture( 24 | window->renderer, 25 | SDL_PIXELFORMAT_ARGB8888, 26 | SDL_TEXTUREACCESS_TARGET, 27 | window->width, 28 | window->height); 29 | } 30 | 31 | if (! (*target)) 32 | { 33 | plog_error("%s: %s.", __func__, SDL_GetError()); 34 | return ESZ_ERROR_CRITICAL; 35 | } 36 | else 37 | { 38 | if (0 > SDL_SetTextureBlendMode((*target), SDL_BLENDMODE_BLEND)) 39 | { 40 | plog_error("%s: %s.", __func__, SDL_GetError()); 41 | SDL_DestroyTexture((*target)); 42 | return ESZ_ERROR_CRITICAL; 43 | } 44 | } 45 | 46 | if (0 > SDL_SetRenderTarget(window->renderer, (*target))) 47 | { 48 | plog_error("%s: %s.", __func__, SDL_GetError()); 49 | SDL_DestroyTexture((*target)); 50 | return ESZ_ERROR_CRITICAL; 51 | } 52 | 53 | SDL_RenderClear(window->renderer); 54 | 55 | return ESZ_OK; 56 | } 57 | 58 | esz_status draw_scene(esz_window_t* window, esz_core_t* core) 59 | { 60 | SDL_Rect dst; 61 | 62 | if (0 > SDL_SetRenderTarget(window->renderer, NULL)) 63 | { 64 | plog_error("%s: %s.", __func__, SDL_GetError()); 65 | } 66 | 67 | if (! core->is_map_loaded) 68 | { 69 | // Display logo in the lower-right corder. 70 | dst.x = (window->logical_width) - 53; 71 | dst.y = (window->logical_height) - 19; 72 | dst.w = 48; 73 | dst.h = 14; 74 | 75 | SDL_SetRenderDrawColor(window->renderer, 0xa9, 0x20, 0x3e, SDL_ALPHA_OPAQUE); 76 | 77 | if (0 > SDL_RenderCopy(window->renderer, window->esz_logo, NULL, &dst)) 78 | { 79 | plog_error("%s: %s.", __func__, SDL_GetError()); 80 | return ESZ_ERROR_CRITICAL; 81 | } 82 | 83 | SDL_RenderPresent(window->renderer); 84 | SDL_RenderClear(window->renderer); 85 | 86 | return ESZ_OK; 87 | } 88 | 89 | dst.x = 0; 90 | dst.y = 0; 91 | dst.w = window->width; 92 | dst.h = window->height; 93 | 94 | for (int32_t index = 0; index < ESZ_RENDER_LAYER_MAX; index += 1) 95 | { 96 | if (IS_STATE_SET(core->debug, index)) 97 | { 98 | continue; 99 | } 100 | 101 | if (0 > SDL_RenderCopy(window->renderer, core->map->render_target[index], NULL, &dst)) 102 | { 103 | plog_error("%s: %s.", __func__, SDL_GetError()); 104 | return ESZ_ERROR_CRITICAL; 105 | } 106 | } 107 | 108 | SDL_RenderPresent(window->renderer); 109 | 110 | SDL_RenderClear(window->renderer); 111 | return ESZ_OK; 112 | } 113 | 114 | esz_status render_actors(int32_t level, esz_window_t* window, esz_core_t* core) 115 | { 116 | esz_tiled_layer_t* layer; 117 | esz_render_layer render_layer = ESZ_ACTOR_FG; 118 | int32_t index = 0; 119 | 120 | if (! core->is_map_loaded) 121 | { 122 | return ESZ_OK; 123 | } 124 | 125 | layer = get_head_layer(core->map->handle); 126 | 127 | if (level >= ESZ_ACTOR_LAYER_LEVEL_MAX) 128 | { 129 | plog_error("%s: invalid layer level selected.", __func__); 130 | return ESZ_ERROR_CRITICAL; 131 | } 132 | 133 | if (ESZ_ACTOR_LAYER_BG == level) 134 | { 135 | render_layer = ESZ_ACTOR_BG; 136 | } 137 | else if (ESZ_ACTOR_LAYER_MG == level) 138 | { 139 | render_layer = ESZ_ACTOR_MG; 140 | } 141 | 142 | if (ESZ_OK != create_and_set_render_target(&core->map->render_target[render_layer], window)) 143 | { 144 | return ESZ_ERROR_CRITICAL; 145 | } 146 | 147 | while (layer) 148 | { 149 | if (is_tiled_layer_of_type(ESZ_OBJECT_GROUP, layer, core)) 150 | { 151 | esz_tiled_object_t* tiled_object = get_head_object(layer, core); 152 | while (tiled_object) 153 | { 154 | uint64_t type_hash = generate_hash((const unsigned char*)get_object_type_name(tiled_object)); 155 | esz_entity_t* object = &core->map->entity[index]; 156 | 157 | switch (type_hash) 158 | { 159 | case H_actor: 160 | { 161 | esz_actor_t** actor = &object->actor; 162 | double pos_x = object->pos_x - core->camera.pos_x; 163 | double pos_y = object->pos_y - core->camera.pos_y; 164 | SDL_RendererFlip flip = SDL_FLIP_NONE; 165 | SDL_Rect dst = { 0 }; 166 | SDL_Rect src = { 0 }; 167 | 168 | if (ESZ_ACTOR_LAYER_BG == level && ! IS_STATE_SET((*actor)->state, STATE_IN_BACKGROUND)) 169 | { 170 | break; 171 | } 172 | 173 | if (ESZ_ACTOR_LAYER_MG == level && ! IS_STATE_SET((*actor)->state, STATE_IN_MIDGROUND)) 174 | { 175 | break; 176 | } 177 | 178 | if (ESZ_ACTOR_LAYER_FG == level && ! IS_STATE_SET((*actor)->state, STATE_IN_FOREGROUND)) 179 | { 180 | break; 181 | } 182 | 183 | if (IS_STATE_SET((*actor)->state, STATE_LOOKING_LEFT)) 184 | { 185 | flip = SDL_FLIP_HORIZONTAL; 186 | } 187 | 188 | // Update animation frame 189 | // ----------------------------------------------------- 190 | 191 | if (IS_STATE_SET((*actor)->state, STATE_ANIMATED) && (*actor)->animation) 192 | { 193 | int32_t current_animation = (*actor)->current_animation; 194 | 195 | (*actor)->time_since_last_anim_frame += window->time_since_last_frame; 196 | 197 | if ((*actor)->time_since_last_anim_frame >= 1.0 / (double)((*actor)->animation[current_animation - 1].fps)) 198 | { 199 | (*actor)->time_since_last_anim_frame = 0.0; 200 | 201 | (*actor)->current_frame += 1; 202 | 203 | if ((*actor)->current_frame >= (*actor)->animation[current_animation - 1].length) 204 | { 205 | (*actor)->current_frame = 0; 206 | } 207 | } 208 | 209 | src.x = ((*actor)->animation[current_animation - 1].first_frame - 1) * object->width; 210 | src.x += (*actor)->current_frame * object->width; 211 | src.y = (*actor)->animation[current_animation - 1].offset_y * object->height; 212 | } 213 | 214 | src.w = object->width; 215 | src.h = object->height; 216 | dst.x = (int32_t)pos_x - (object->width / 2); 217 | dst.y = (int32_t)pos_y - (object->height / 2); 218 | dst.w = object->width; 219 | dst.h = object->height; 220 | 221 | if (0 > SDL_RenderCopyEx(window->renderer, core->map->sprite[(*actor)->sprite_sheet_id - 1].texture, &src, &dst, 0, NULL, flip)) 222 | { 223 | plog_error("%s: %s.", __func__, SDL_GetError()); 224 | return ESZ_ERROR_CRITICAL; 225 | } 226 | break; 227 | } 228 | } 229 | index += 1; 230 | tiled_object = tiled_object->next; 231 | } 232 | } 233 | layer = layer->next; 234 | } 235 | 236 | return ESZ_OK; 237 | } 238 | 239 | esz_status render_background(esz_window_t* window, esz_core_t* core) 240 | { 241 | esz_status status = ESZ_OK; 242 | esz_render_layer render_layer = ESZ_BACKGROUND; 243 | double factor; 244 | 245 | if (! core->is_map_loaded) 246 | { 247 | return ESZ_OK; 248 | } 249 | 250 | factor = (double)core->map->background.layer_count + 1.0; 251 | 252 | if (! core->map->render_target[render_layer]) 253 | { 254 | core->map->render_target[render_layer] = SDL_CreateTexture( 255 | window->renderer, 256 | SDL_PIXELFORMAT_ARGB8888, 257 | SDL_TEXTUREACCESS_TARGET, 258 | window->width, 259 | window->height); 260 | } 261 | 262 | if (! core->map->render_target[render_layer]) 263 | { 264 | plog_error("%s: %s.", __func__, SDL_GetError()); 265 | return ESZ_ERROR_CRITICAL; 266 | } 267 | 268 | if (is_camera_at_horizontal_boundary(core)) 269 | { 270 | if (! core->map->background.velocity_is_constant) 271 | { 272 | core->map->background.velocity = 0.0; 273 | } 274 | } 275 | else 276 | { 277 | if (core->map->entity) 278 | { 279 | if (core->map->entity[core->camera.target_actor_id].actor) 280 | { 281 | core->map->background.velocity = core->map->entity[core->camera.target_actor_id].actor->velocity_x; 282 | } 283 | } 284 | else 285 | { 286 | core->map->background.velocity = 0.0; 287 | } 288 | } 289 | 290 | if (! core->camera.is_locked) 291 | { 292 | core->map->background.velocity = 0.0; 293 | } 294 | 295 | for (int32_t index = 0; index < core->map->background.layer_count; index += 1) 296 | { 297 | core->map->background.layer[index].velocity = core->map->background.velocity / factor; 298 | factor -= core->map->background.layer_shift; 299 | 300 | status = render_background_layer(index, window, core); 301 | 302 | if (ESZ_OK != status) 303 | { 304 | break; 305 | } 306 | } 307 | 308 | return status; 309 | } 310 | 311 | esz_status render_map(int32_t level, esz_window_t* window, esz_core_t* core) 312 | { 313 | esz_tiled_layer_t* layer; 314 | bool render_animated_tiles = false; 315 | esz_render_layer render_layer = ESZ_MAP_FG; 316 | 317 | if (! core->is_map_loaded) 318 | { 319 | return ESZ_OK; 320 | } 321 | 322 | layer = get_head_layer(core->map->handle); 323 | 324 | if (level >= ESZ_MAP_LAYER_LEVEL_MAX) 325 | { 326 | plog_error("%s: invalid layer level selected.", __func__); 327 | return ESZ_ERROR_CRITICAL; 328 | } 329 | 330 | if (ESZ_MAP_LAYER_BG == level) 331 | { 332 | render_layer = ESZ_MAP_BG; 333 | 334 | if (0 < core->map->animated_tile_fps) 335 | { 336 | render_animated_tiles = true; 337 | } 338 | } 339 | 340 | if (ESZ_OK != create_and_set_render_target(&core->map->render_target[render_layer], window)) 341 | { 342 | return ESZ_ERROR_CRITICAL; 343 | } 344 | 345 | // Update and render animated tiles. 346 | core->map->time_since_last_anim_frame += window->time_since_last_frame; 347 | 348 | if (0 < core->map->animated_tile_index && 349 | core->map->time_since_last_anim_frame >= 1.0 / (double)(core->map->animated_tile_fps) && render_animated_tiles) 350 | { 351 | core->map->time_since_last_anim_frame = 0.0; 352 | 353 | /* Remark: animated tiles are always rendered in the background 354 | * layer. 355 | */ 356 | if (! core->map->animated_tile_texture) 357 | { 358 | core->map->animated_tile_texture = SDL_CreateTexture( 359 | window->renderer, 360 | SDL_PIXELFORMAT_ARGB8888, 361 | SDL_TEXTUREACCESS_TARGET, 362 | (int32_t)(core->map->width), 363 | (int32_t)(core->map->height)); 364 | } 365 | 366 | if (! core->map->animated_tile_texture) 367 | { 368 | plog_error("%s: %s.", __func__, SDL_GetError()); 369 | return ESZ_ERROR_CRITICAL; 370 | } 371 | 372 | if (0 > SDL_SetRenderTarget(window->renderer, core->map->animated_tile_texture)) 373 | { 374 | plog_error("%s: %s.", __func__, SDL_GetError()); 375 | return ESZ_ERROR_CRITICAL; 376 | } 377 | SDL_RenderClear(window->renderer); 378 | 379 | for (int32_t index = 0; core->map->animated_tile_index > index; index += 1) 380 | { 381 | esz_tiled_tileset_t* tileset; 382 | int32_t gid = core->map->animated_tile[index].gid; 383 | int32_t next_tile_id = 0; 384 | int32_t local_id; 385 | SDL_Rect dst; 386 | SDL_Rect src; 387 | 388 | local_id = core->map->animated_tile[index].id + 1; 389 | tileset = get_head_tileset(core->map->handle); 390 | src.w = dst.w = get_tile_width(core->map->handle); 391 | src.h = dst.h = get_tile_height(core->map->handle); 392 | dst.x = (int32_t)core->map->animated_tile[index].dst_x; 393 | dst.y = (int32_t)core->map->animated_tile[index].dst_y; 394 | 395 | get_tile_position(local_id, &src.x, &src.y, core->map->handle); 396 | 397 | if (0 > SDL_RenderCopy(window->renderer, core->map->tileset_texture, &src, &dst)) 398 | { 399 | plog_error("%s: %s.", __func__, SDL_GetError()); 400 | return ESZ_ERROR_CRITICAL; 401 | } 402 | 403 | core->map->animated_tile[index].current_frame += 1; 404 | 405 | if (core->map->animated_tile[index].current_frame >= core->map->animated_tile[index].animation_length) 406 | { 407 | core->map->animated_tile[index].current_frame = 0; 408 | } 409 | 410 | next_tile_id = get_next_animated_tile_id(gid, core->map->animated_tile[index].current_frame, core->map->handle); 411 | 412 | core->map->animated_tile[index].id = next_tile_id; 413 | } 414 | 415 | if (0 > SDL_SetRenderTarget(window->renderer, core->map->render_target[render_layer])) 416 | { 417 | plog_error("%s: %s.", __func__, SDL_GetError()); 418 | return ESZ_ERROR_CRITICAL; 419 | } 420 | SDL_RenderClear(window->renderer); 421 | 422 | if (0 > SDL_SetTextureBlendMode(core->map->animated_tile_texture, SDL_BLENDMODE_BLEND)) 423 | { 424 | plog_error("%s: %s.", __func__, SDL_GetError()); 425 | return ESZ_ERROR_CRITICAL; 426 | } 427 | } 428 | 429 | // Texture has already been rendered. 430 | if (core->map->layer_texture[level]) 431 | { 432 | double render_pos_x = core->map->pos_x - core->camera.pos_x; 433 | double render_pos_y = core->map->pos_y - core->camera.pos_y; 434 | SDL_Rect dst = { 435 | (int32_t)render_pos_x, 436 | (int32_t)render_pos_y, 437 | (int32_t)core->map->width, 438 | (int32_t)core->map->height 439 | }; 440 | 441 | if (0 > SDL_RenderCopyEx(window->renderer, core->map->layer_texture[level], NULL, &dst, 0, NULL, SDL_FLIP_NONE)) 442 | { 443 | plog_error("%s: %s.", __func__, SDL_GetError()); 444 | return ESZ_ERROR_CRITICAL; 445 | } 446 | 447 | if (render_animated_tiles) 448 | { 449 | if (core->map->animated_tile_texture) 450 | { 451 | if (0 > SDL_RenderCopyEx(window->renderer, core->map->animated_tile_texture, NULL, &dst, 0, NULL, SDL_FLIP_NONE)) 452 | { 453 | plog_error("%s: %s.", __func__, SDL_GetError()); 454 | return ESZ_ERROR_CRITICAL; 455 | } 456 | } 457 | } 458 | 459 | return ESZ_OK; 460 | } 461 | 462 | // Texture does not yet exist. Render it! 463 | core->map->layer_texture[level] = SDL_CreateTexture( 464 | window->renderer, 465 | SDL_PIXELFORMAT_ARGB8888, 466 | SDL_TEXTUREACCESS_TARGET, 467 | (int32_t)core->map->width, 468 | (int32_t)core->map->height); 469 | 470 | if (! core->map->layer_texture[level]) 471 | { 472 | plog_error("%s: %s.", __func__, SDL_GetError()); 473 | return ESZ_ERROR_CRITICAL; 474 | } 475 | 476 | if (0 > SDL_SetRenderTarget(window->renderer, core->map->layer_texture[level])) 477 | { 478 | plog_error("%s: %s.", __func__, SDL_GetError()); 479 | return ESZ_ERROR_CRITICAL; 480 | } 481 | SDL_RenderClear(window->renderer); 482 | 483 | while (layer) 484 | { 485 | SDL_Rect dst; 486 | SDL_Rect src; 487 | 488 | if (is_tiled_layer_of_type(ESZ_TILE_LAYER, layer, core)) 489 | { 490 | bool is_in_foreground = false; 491 | bool is_layer_rendered = false; 492 | int32_t prop_cnt = get_layer_property_count(layer); 493 | 494 | is_in_foreground = get_boolean_property(H_is_in_foreground, layer->properties, prop_cnt, core); 495 | 496 | if (ESZ_MAP_LAYER_BG == level && false == is_in_foreground) 497 | { 498 | is_layer_rendered = true; 499 | } 500 | else if (ESZ_MAP_LAYER_FG == level && is_in_foreground) 501 | { 502 | is_layer_rendered = true; 503 | } 504 | 505 | if (layer->visible && is_layer_rendered) 506 | { 507 | for (int32_t index_height = 0; index_height < (int32_t)core->map->handle->height; index_height += 1) 508 | { 509 | for (int32_t index_width = 0; index_width < (int32_t)core->map->handle->width; index_width += 1) 510 | { 511 | int32_t* layer_content = get_layer_content(layer); 512 | int32_t gid = remove_gid_flip_bits((int32_t)layer_content[(index_height * (int32_t)core->map->handle->width) + index_width]); 513 | int32_t local_id = gid - get_first_gid(core->map->handle); 514 | 515 | if (is_gid_valid(gid, core->map->handle)) 516 | { 517 | esz_tiled_tileset_t* tileset = get_head_tileset(core->map->handle); 518 | 519 | src.w = dst.w = get_tile_width(core->map->handle); 520 | src.h = dst.h = get_tile_height(core->map->handle); 521 | dst.x = (int32_t)(index_width * get_tile_width(core->map->handle)); 522 | dst.y = (int32_t)(index_height * get_tile_height(core->map->handle)); 523 | 524 | get_tile_position(gid, &src.x, &src.y, core->map->handle); 525 | SDL_RenderCopy(window->renderer, core->map->tileset_texture, &src, &dst); 526 | 527 | if (render_animated_tiles) 528 | { 529 | int32_t animation_length = 0; 530 | int32_t id = 0; 531 | 532 | if (is_tile_animated(gid, &animation_length, &id, core->map->handle)) 533 | { 534 | core->map->animated_tile[core->map->animated_tile_index].gid = get_local_id(gid, core->map->handle); 535 | core->map->animated_tile[core->map->animated_tile_index].id = id; 536 | core->map->animated_tile[core->map->animated_tile_index].dst_x = dst.x; 537 | core->map->animated_tile[core->map->animated_tile_index].dst_y = dst.y; 538 | core->map->animated_tile[core->map->animated_tile_index].current_frame = 0; 539 | core->map->animated_tile[core->map->animated_tile_index].animation_length = animation_length; 540 | 541 | core->map->animated_tile_index += 1; 542 | } 543 | } 544 | } 545 | } 546 | } 547 | 548 | { 549 | const char* layer_name = get_layer_name(layer); 550 | plog_info("Render map layer: %s", layer_name); 551 | } 552 | } 553 | } 554 | layer = layer->next; 555 | } 556 | 557 | if (0 > SDL_SetRenderTarget(window->renderer, core->map->render_target[render_layer])) 558 | { 559 | plog_error("%s: %s.", __func__, SDL_GetError()); 560 | return ESZ_ERROR_CRITICAL; 561 | } 562 | 563 | if (0 > SDL_SetTextureBlendMode(core->map->layer_texture[level], SDL_BLENDMODE_BLEND)) 564 | { 565 | plog_error("%s: %s.", __func__, SDL_GetError()); 566 | return ESZ_ERROR_CRITICAL; 567 | } 568 | 569 | return ESZ_OK; 570 | } 571 | 572 | esz_status render_scene(esz_window_t* window, esz_core_t* core) 573 | { 574 | esz_status status = ESZ_OK; 575 | 576 | status = render_background(window, core); 577 | if (ESZ_OK != status) 578 | { 579 | return status; 580 | } 581 | 582 | for (int32_t index = 0; index < ESZ_MAP_LAYER_LEVEL_MAX; index += 1) 583 | { 584 | status = render_map(index, window, core); 585 | if (ESZ_OK != status) 586 | { 587 | return status; 588 | } 589 | } 590 | 591 | for (int32_t index = 0; index < ESZ_ACTOR_LAYER_LEVEL_MAX; index += 1) 592 | { 593 | status = render_actors(index, window, core); 594 | if (ESZ_OK != status) 595 | { 596 | return status; 597 | } 598 | } 599 | 600 | return status; 601 | } 602 | 603 | static esz_status render_background_layer(int32_t index, esz_window_t* window, esz_core_t* core) 604 | { 605 | esz_render_layer render_layer = ESZ_BACKGROUND; 606 | int32_t width = 0; 607 | SDL_Rect dst; 608 | double pos_x_a; 609 | double pos_x_b; 610 | 611 | if (0 > SDL_QueryTexture(core->map->background.layer[index].texture, NULL, NULL, &width, NULL)) 612 | { 613 | plog_error("%s: %s.", __func__, SDL_GetError()); 614 | return ESZ_ERROR_CRITICAL; 615 | } 616 | 617 | if (core->map->background.layer[index].pos_x < -width) 618 | { 619 | core->map->background.layer[index].pos_x = +width; 620 | } 621 | 622 | if (core->map->background.layer[index].pos_x > +width) 623 | { 624 | core->map->background.layer[index].pos_x = -width; 625 | } 626 | 627 | pos_x_a = core->map->background.layer[index].pos_x; 628 | if (0 < pos_x_a) 629 | { 630 | pos_x_b = pos_x_a - width; 631 | } 632 | else 633 | { 634 | pos_x_b = pos_x_a + width; 635 | } 636 | 637 | if (0 < core->map->background.layer[index].velocity) 638 | { 639 | if (ESZ_RIGHT == core->map->background.direction) 640 | { 641 | core->map->background.layer[index].pos_x -= core->map->background.layer[index].velocity; 642 | } 643 | else 644 | { 645 | core->map->background.layer[index].pos_x += core->map->background.layer[index].velocity; 646 | } 647 | } 648 | 649 | if (ESZ_TOP == core->map->background.alignment) 650 | { 651 | dst.y = (int32_t)(core->map->background.layer[index].pos_y - core->camera.pos_y); 652 | } 653 | else 654 | { 655 | dst.y = (int32_t)(core->map->background.layer[index].pos_y + (window->logical_height - core->map->background.layer[index].height)); 656 | } 657 | 658 | if (0 > SDL_SetRenderTarget(window->renderer, core->map->render_target[render_layer])) 659 | { 660 | plog_error("%s: %s.", __func__, SDL_GetError()); 661 | return ESZ_ERROR_CRITICAL; 662 | } 663 | 664 | if (0 == index) 665 | { 666 | SDL_SetRenderDrawColor( 667 | window->renderer, 668 | (core->map->handle->backgroundcolor >> 16) & 0xFF, 669 | (core->map->handle->backgroundcolor >> 8) & 0xFF, 670 | (core->map->handle->backgroundcolor) & 0xFF, 671 | 0); 672 | 673 | SDL_RenderClear(window->renderer); 674 | } 675 | 676 | dst.x = (int32_t)pos_x_a; 677 | dst.w = width; 678 | dst.h = core->map->background.layer[index].height; 679 | 680 | if (0 > SDL_RenderCopyEx(window->renderer, core->map->background.layer[index].texture, NULL, &dst, 0, NULL, SDL_FLIP_NONE)) 681 | { 682 | plog_error("%s: %s.", __func__, SDL_GetError()); 683 | return ESZ_ERROR_CRITICAL; 684 | } 685 | 686 | dst.x = (int32_t)pos_x_b; 687 | if (0 > SDL_RenderCopyEx(window->renderer, core->map->background.layer[index].texture, NULL, &dst, 0, NULL, SDL_FLIP_NONE)) 688 | { 689 | plog_error("%s: %s.", __func__, SDL_GetError()); 690 | return ESZ_ERROR_CRITICAL; 691 | } 692 | 693 | return ESZ_OK; 694 | } 695 | -------------------------------------------------------------------------------- /src/esz_render.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_render.h 4 | * @brief eszFW rendering and scene drawing 5 | */ 6 | 7 | #ifndef ESZ_RENDER_H 8 | #define ESZ_RENDER_H 9 | 10 | #include 11 | 12 | #include "esz_types.h" 13 | 14 | esz_status create_and_set_render_target(SDL_Texture** target, esz_window_t* window); 15 | esz_status draw_scene(esz_window_t* window, esz_core_t* core); 16 | esz_status render_actors(int32_t level, esz_window_t* window, esz_core_t* core); 17 | esz_status render_background(esz_window_t* window, esz_core_t* core); 18 | esz_status render_background_layer(int32_t index, esz_window_t* window, esz_core_t* core); 19 | esz_status render_map(int32_t level, esz_window_t* window, esz_core_t* core); 20 | esz_status render_scene(esz_window_t* window, esz_core_t* core); 21 | 22 | #endif // ESZ_RENDER_H 23 | -------------------------------------------------------------------------------- /src/esz_types.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_types.h 4 | * @brief eszFW types 5 | */ 6 | 7 | #ifndef ESZ_TYPES_H 8 | #define ESZ_TYPES_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef USE_LIBTMX 15 | typedef struct _tmx_layer tmx_layer; 16 | typedef struct _tmx_map tmx_map; 17 | typedef struct _tmx_obj tmx_object; 18 | typedef struct _tmx_prop tmx_property; 19 | typedef struct _tmx_tile tmx_tile; 20 | typedef struct _tmx_ts tmx_tileset; 21 | 22 | typedef tmx_layer esz_tiled_layer_t; 23 | typedef tmx_map esz_tiled_map_t; 24 | typedef tmx_object esz_tiled_object_t; 25 | typedef tmx_property esz_tiled_property_t; 26 | typedef tmx_tile esz_tiled_tile_t; 27 | typedef tmx_tileset esz_tiled_tileset_t; 28 | 29 | #include 30 | 31 | #else // (cute_tiled.h) 32 | struct cute_tiled_layer_t; 33 | struct cute_tiled_map_t; 34 | struct cute_tiled_object_t; 35 | struct cute_tiled_property_t; 36 | struct cute_tiled_tile_descriptor_t; 37 | struct cute_tiled_tileset_t; 38 | 39 | typedef struct cute_tiled_layer_t esz_tiled_layer_t; 40 | typedef struct cute_tiled_map_t esz_tiled_map_t; 41 | typedef struct cute_tiled_object_t esz_tiled_object_t; 42 | typedef struct cute_tiled_property_t esz_tiled_property_t; 43 | typedef struct cute_tiled_tile_descriptor_t esz_tiled_tile_t; 44 | typedef struct cute_tiled_tileset_t esz_tiled_tileset_t; 45 | 46 | #include 47 | 48 | #endif 49 | 50 | typedef struct esz_window esz_window_t; 51 | typedef struct esz_core esz_core_t; 52 | 53 | /** 54 | * @brief Event callback function type 55 | * @attention An event callback function always expects a window handle 56 | * as first and a core handle as second parameter! 57 | */ 58 | typedef void (*esz_event_callback)(esz_window_t* window, esz_core_t* core); 59 | 60 | /** 61 | * @brief An enumeration of actor actions 62 | */ 63 | typedef enum 64 | { 65 | ACTION_JUMP = 0 66 | 67 | } esz_action; 68 | 69 | /** 70 | * @brief An enumeration of alignments. 71 | */ 72 | typedef enum 73 | { 74 | ESZ_BOT = 0, 75 | ESZ_TOP 76 | 77 | } esz_alignment; 78 | 79 | /** 80 | * @brief An enumeration of directional constants. 81 | */ 82 | typedef enum 83 | { 84 | ESZ_LEFT = 0, 85 | ESZ_RIGHT 86 | 87 | } esz_direction; 88 | 89 | /** 90 | * @brief An enumeration of actor layer levels. 91 | */ 92 | typedef enum 93 | { 94 | ESZ_ACTOR_LAYER_BG = 0, 95 | ESZ_ACTOR_LAYER_MG, 96 | ESZ_ACTOR_LAYER_FG, 97 | ESZ_ACTOR_LAYER_LEVEL_MAX 98 | 99 | } esz_actor_layer_level; 100 | 101 | /** 102 | * @brief An enumeration of event types 103 | */ 104 | typedef enum 105 | { 106 | EVENT_FINGERDOWN = 0, 107 | EVENT_FINGERMOTION, 108 | EVENT_FINGERUP, 109 | EVENT_KEYDOWN, 110 | EVENT_KEYUP, 111 | EVENT_MAP_LOADED, 112 | EVENT_MAP_UNLOADED, 113 | EVENT_MULTIGESTURE 114 | 115 | } esz_event_type; 116 | 117 | /** 118 | * @brief An enumeration of map layer levels. 119 | */ 120 | typedef enum 121 | { 122 | ESZ_MAP_LAYER_BG = 0, 123 | ESZ_MAP_LAYER_FG, 124 | ESZ_MAP_LAYER_LEVEL_MAX 125 | 126 | } esz_map_layer_level; 127 | 128 | /** 129 | * @brief An enumeration of render layer levels. 130 | */ 131 | typedef enum 132 | { 133 | ESZ_BACKGROUND = 0, 134 | ESZ_ACTOR_BG, 135 | ESZ_MAP_BG, 136 | ESZ_ACTOR_MG, 137 | ESZ_MAP_FG, 138 | ESZ_ACTOR_FG, 139 | ESZ_RENDER_LAYER_MAX 140 | 141 | } esz_render_layer; 142 | 143 | /** 144 | * @brief An enumeration of actor states 145 | */ 146 | typedef enum 147 | { 148 | STATE_ANIMATED, 149 | STATE_DUCKING, 150 | STATE_FLOATING, 151 | STATE_GRAVITATIONAL, 152 | STATE_GOING_DOWN, 153 | STATE_GOING_LEFT, 154 | STATE_GOING_RIGHT, 155 | STATE_GOING_UP, 156 | STATE_IN_BACKGROUND, 157 | STATE_IN_FOREGROUND, 158 | STATE_IN_MID_AIR, 159 | STATE_IN_MIDGROUND, 160 | STATE_JUMPING, 161 | STATE_LOOKING_LEFT, 162 | STATE_LOOKING_RIGHT, 163 | STATE_MOVING, 164 | STATE_RISING, 165 | STATE_STANDING 166 | 167 | } esz_state; 168 | 169 | /** 170 | * @brief An enumeration of status codes. 171 | */ 172 | typedef enum 173 | { 174 | ESZ_OK = 0, 175 | ESZ_ERROR_CRITICAL = -1, 176 | ESZ_WARNING = -2 177 | 178 | } esz_status; 179 | 180 | /** 181 | * @brief An enumeration of Tiled layer types. 182 | */ 183 | typedef enum 184 | { 185 | ESZ_TILE_LAYER = 0, 186 | ESZ_OBJECT_GROUP 187 | 188 | } esz_tiled_layer_type; 189 | 190 | typedef enum 191 | { 192 | TILE_CLIMBABLE, 193 | TILE_SOLID_ABOVE, 194 | TILE_SOLID_BELOW, 195 | TILE_SOLID_LEFT, 196 | TILE_SOLID_RIGHT 197 | 198 | } esz_tile_property; 199 | 200 | /** 201 | * @brief A structure that contains a axis-aligned bounding box. 202 | */ 203 | typedef struct esz_aabb 204 | { 205 | double bottom; 206 | double left; 207 | double right; 208 | double top; 209 | 210 | } esz_aabb_t; 211 | 212 | /** 213 | * @brief A structure that contains an animated tile. 214 | */ 215 | typedef struct esz_animated_tile 216 | { 217 | int32_t dst_x; 218 | int32_t dst_y; 219 | int32_t animation_length; 220 | int32_t current_frame; 221 | int32_t gid; 222 | int32_t id; 223 | 224 | } esz_animated_tile_t; 225 | 226 | /** 227 | * @brief A structure that contains animation settings. 228 | */ 229 | typedef struct esz_animation 230 | { 231 | int32_t first_frame; 232 | int32_t fps; 233 | int32_t length; 234 | int32_t offset_y; 235 | 236 | } esz_animation_t; 237 | 238 | /** 239 | * @brief A structure that contains a background layer. 240 | */ 241 | typedef struct esz_background_layer 242 | { 243 | double pos_x; 244 | double pos_y; 245 | double velocity; 246 | SDL_Texture* texture; 247 | int32_t width; 248 | int32_t height; 249 | 250 | } esz_background_layer_t; 251 | 252 | /** 253 | * @brief A structure that contains a parallax-scrolling background. 254 | */ 255 | typedef struct esz_background 256 | { 257 | esz_alignment alignment; 258 | esz_direction direction; 259 | esz_background_layer_t* layer; 260 | double velocity; 261 | double layer_shift; 262 | int32_t layer_count; 263 | bool velocity_is_constant; 264 | 265 | } esz_background_t ; 266 | 267 | /** 268 | * @brief A structure that contains a camera. 269 | */ 270 | typedef struct esz_camera 271 | { 272 | double pos_x; 273 | double pos_y; 274 | int32_t max_pos_x; 275 | int32_t max_pos_y; 276 | int32_t target_actor_id; 277 | bool is_at_horizontal_boundary; 278 | bool is_locked; 279 | 280 | } esz_camera_t; 281 | 282 | /** 283 | * @brief A structure that contains the initial window configuration. 284 | */ 285 | typedef struct esz_window_config 286 | { 287 | const int32_t width; 288 | const int32_t height; 289 | const int32_t logical_width; 290 | const int32_t logical_height; 291 | const bool enable_fullscreen; 292 | const bool enable_vsync; 293 | 294 | } esz_window_config_t; 295 | 296 | /** 297 | * @brief A structure that contains the event handler. 298 | */ 299 | typedef struct esz_event 300 | { 301 | SDL_Event handle; 302 | 303 | void (*finger_down_cb)(esz_window_t* window, esz_core_t* core); 304 | void (*finger_motion_cb)(esz_window_t* window, esz_core_t* core); 305 | void (*finger_up_cb)(esz_window_t* window, esz_core_t* core); 306 | void (*key_down_cb)(esz_window_t* window, esz_core_t* core); 307 | void (*key_up_cb)(esz_window_t* window, esz_core_t* core); 308 | void (*map_loaded_cb)(esz_window_t* window, esz_core_t* core); 309 | void (*map_unloaded_cb)(esz_window_t* window, esz_core_t* core); 310 | void (*multi_gesture_cb)(esz_window_t* window, esz_core_t* core); 311 | 312 | } esz_event_t; 313 | 314 | /** 315 | * @brief A structure that contains actor information. 316 | */ 317 | typedef struct esz_actor 318 | { 319 | double acceleration; 320 | double jumping_power; 321 | double max_velocity_x; 322 | double spawn_pos_x; 323 | double spawn_pos_y; 324 | double time_since_last_anim_frame; 325 | double velocity_x; 326 | double velocity_y; 327 | esz_animation_t* animation; 328 | int32_t animation_count; 329 | int32_t current_animation; 330 | int32_t current_frame; 331 | int32_t sprite_sheet_id; 332 | uint32_t action; 333 | uint32_t state; 334 | bool connect_horizontal_map_ends; 335 | bool connect_vertical_map_ends; 336 | 337 | } esz_actor_t; 338 | 339 | /** 340 | * @brief A structure that contains an entity 341 | */ 342 | typedef struct esz_entity 343 | { 344 | struct esz_aabb bounding_box; 345 | double pos_x; 346 | double pos_y; 347 | esz_actor_t* actor; 348 | esz_tiled_object_t* handle; 349 | int32_t height; 350 | int32_t id; 351 | int32_t index; 352 | int32_t width; 353 | 354 | } esz_entity_t; 355 | 356 | /** 357 | * @brief A structure that contains a sprite. 358 | */ 359 | typedef struct esz_sprite 360 | { 361 | SDL_Texture* texture; 362 | int32_t id; 363 | 364 | } esz_sprite_t; 365 | 366 | /** 367 | * @brief A structure that contains a game map. 368 | */ 369 | typedef struct esz_map 370 | { 371 | double decimal_property; 372 | double gravitation; 373 | double pos_x; 374 | double pos_y; 375 | double time_since_last_anim_frame; 376 | 377 | #ifdef USE_LIBTMX 378 | uint64_t hash_query; 379 | #else 380 | long long unsigned hash_id_objectgroup; 381 | long long unsigned hash_id_tilelayer; 382 | #endif 383 | 384 | size_t path_length; 385 | const char* string_property; 386 | char* path; 387 | SDL_Texture* animated_tile_texture; 388 | SDL_Texture* layer_texture[ESZ_MAP_LAYER_LEVEL_MAX]; 389 | SDL_Texture* render_target[ESZ_RENDER_LAYER_MAX]; 390 | SDL_Texture* tileset_texture; 391 | esz_animated_tile_t* animated_tile; 392 | struct esz_background background; 393 | esz_entity_t* entity; 394 | esz_sprite_t* sprite; 395 | esz_tiled_map_t* handle; 396 | uint32_t* tile_properties; 397 | int32_t active_player_actor_id; 398 | int32_t animated_tile_fps; 399 | int32_t animated_tile_index; 400 | int32_t height; 401 | int32_t integer_property; 402 | int32_t meter_in_pixel; 403 | int32_t entity_count; 404 | int32_t sprite_sheet_count; 405 | int32_t width; 406 | bool boolean_property; 407 | 408 | } esz_map_t; 409 | 410 | /** 411 | * @brief A structure that contains an engine core. 412 | */ 413 | typedef struct esz_core 414 | { 415 | struct esz_camera camera; 416 | struct esz_event event; 417 | esz_map_t* map; 418 | uint32_t debug; 419 | bool is_active; 420 | bool is_map_loaded; 421 | bool is_paused; 422 | 423 | } esz_core_t; 424 | 425 | /** 426 | * @brief A structure that contains a window and the rendering context. 427 | */ 428 | typedef struct esz_window 429 | { 430 | double initial_zoom_level; 431 | double time_since_last_frame; 432 | double zoom_level; 433 | SDL_Renderer* renderer; 434 | SDL_Texture* esz_logo; 435 | SDL_Window* window; 436 | uint32_t flags; 437 | uint32_t time_a; 438 | uint32_t time_b; 439 | int32_t height; 440 | int32_t logical_height; 441 | int32_t logical_width; 442 | int32_t pos_x; 443 | int32_t pos_y; 444 | int32_t refresh_rate; 445 | int32_t width; 446 | bool is_fullscreen; 447 | bool vsync_enabled; 448 | 449 | } esz_window_t; 450 | 451 | #endif // ESZ_TYPES_H 452 | -------------------------------------------------------------------------------- /src/esz_utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_utils.c 4 | * @brief eszFW utilities 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "esz.h" 13 | #include "esz_compat.h" 14 | #include "esz_hash.h" 15 | #include "esz_macros.h" 16 | #include "esz_types.h" 17 | #include "esz_utils.h" 18 | 19 | bool get_boolean_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core) 20 | { 21 | core->map->boolean_property = false; 22 | load_property(name_hash, properties, property_count, core); 23 | return core->map->boolean_property; 24 | } 25 | 26 | double get_decimal_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core) 27 | { 28 | core->map->decimal_property = 0.0; 29 | load_property(name_hash, properties, property_count, core); 30 | return core->map->decimal_property; 31 | } 32 | 33 | int32_t get_integer_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core) 34 | { 35 | core->map->integer_property = 0; 36 | load_property(name_hash, properties, property_count, core); 37 | return core->map->integer_property; 38 | } 39 | 40 | const char* get_string_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core) 41 | { 42 | core->map->string_property = NULL; 43 | load_property(name_hash, properties, property_count, core); 44 | return core->map->string_property; 45 | } 46 | 47 | bool is_camera_at_horizontal_boundary(esz_core_t* core) 48 | { 49 | return core->camera.is_at_horizontal_boundary; 50 | } 51 | 52 | void move_camera_to_target(esz_window_t* window, esz_core_t* core) 53 | { 54 | if (core->camera.is_locked) 55 | { 56 | if (core->map->entity) 57 | { 58 | if (core->map->entity[core->camera.target_actor_id].actor) 59 | { 60 | esz_entity_t* target = &core->map->entity[core->camera.target_actor_id]; 61 | 62 | core->camera.pos_x = target->pos_x; 63 | core->camera.pos_x -= (double)window->logical_width / 2.0; 64 | core->camera.pos_y = target->pos_y; 65 | core->camera.pos_y -= (double)window->logical_height / 2.0; 66 | } 67 | 68 | if (0 > core->camera.pos_x) 69 | { 70 | core->camera.pos_x = 0; 71 | } 72 | 73 | set_camera_boundaries_to_map_size(window, core); 74 | } 75 | } 76 | } 77 | 78 | void poll_events(esz_window_t* window, esz_core_t* core) 79 | { 80 | const uint8_t* keystate = esz_get_keyboard_state(); 81 | double time_factor = (window->time_since_last_frame * 1000.0); 82 | int32_t scancode; 83 | 84 | while (0 != SDL_PollEvent(&core->event.handle)) 85 | { 86 | switch (core->event.handle.type) 87 | { 88 | case SDL_QUIT: 89 | core->is_active = false; 90 | return; 91 | case SDL_FINGERDOWN: 92 | if (core->event.finger_down_cb) 93 | { 94 | core->event.finger_down_cb(window, core); 95 | } 96 | break; 97 | case SDL_FINGERUP: 98 | if (core->event.finger_up_cb) 99 | { 100 | core->event.finger_up_cb(window, core); 101 | } 102 | break; 103 | case SDL_FINGERMOTION: 104 | if (core->event.finger_motion_cb) 105 | { 106 | core->event.finger_motion_cb(window, core); 107 | } 108 | break; 109 | case SDL_KEYDOWN: 110 | if (core->event.key_down_cb) 111 | { 112 | core->event.key_down_cb(window, core); 113 | } 114 | 115 | scancode = esz_get_integer_map_property(H_scancode_quit, core); 116 | if (keystate[scancode] && scancode > 0) 117 | { 118 | core->is_active = false; 119 | return; 120 | } 121 | 122 | scancode = esz_get_integer_map_property(H_scancode_toggle_fullscreen, core); 123 | if (keystate[scancode] && scancode > 0) 124 | { 125 | esz_toggle_fullscreen(window); 126 | } 127 | 128 | break; 129 | case SDL_KEYUP: 130 | if (core->event.key_up_cb) 131 | { 132 | core->event.key_up_cb(window, core); 133 | } 134 | break; 135 | case SDL_MULTIGESTURE: 136 | if (core->event.multi_gesture_cb) 137 | { 138 | core->event.multi_gesture_cb(window, core); 139 | } 140 | break; 141 | } 142 | } 143 | 144 | scancode = esz_get_integer_map_property(H_scancode_unlock_camera, core); 145 | if (keystate[scancode] && scancode > 0) 146 | { 147 | esz_unlock_camera(core); 148 | } 149 | else 150 | { 151 | esz_lock_camera(core); 152 | } 153 | 154 | if (! esz_is_camera_locked(core)) 155 | { 156 | scancode = esz_get_integer_map_property(H_scancode_up, core); 157 | if (keystate[scancode] && scancode > 0) 158 | { 159 | core->camera.pos_y -= 0.3f * time_factor; 160 | } 161 | scancode = esz_get_integer_map_property(H_scancode_down, core); 162 | if (keystate[scancode] && scancode > 0) 163 | { 164 | core->camera.pos_y += 0.3f * time_factor; 165 | } 166 | scancode = esz_get_integer_map_property(H_scancode_left, core); 167 | if (keystate[scancode] && scancode > 0) 168 | { 169 | core->camera.pos_x -= 0.3f * time_factor; 170 | } 171 | scancode = esz_get_integer_map_property(H_scancode_right, core); 172 | if (keystate[scancode] && scancode > 0) 173 | { 174 | core->camera.pos_x += 0.3f * time_factor; 175 | } 176 | 177 | set_camera_boundaries_to_map_size(window, core); 178 | } 179 | } 180 | 181 | void set_camera_boundaries_to_map_size(esz_window_t* window, esz_core_t* core) 182 | { 183 | core->camera.is_at_horizontal_boundary = false; 184 | core->camera.max_pos_x = (int32_t)core->map->width - window->logical_width; 185 | core->camera.max_pos_y = (int32_t)core->map->height - window->logical_height; 186 | 187 | if (0 >= core->camera.pos_x) 188 | { 189 | core->camera.pos_x = 0; 190 | core->camera.is_at_horizontal_boundary = true; 191 | } 192 | 193 | if (0 >= core->camera.pos_y) 194 | { 195 | core->camera.pos_y = 0; 196 | } 197 | 198 | if (core->camera.pos_x >= core->camera.max_pos_x) 199 | { 200 | core->camera.pos_x = core->camera.max_pos_x; 201 | core->camera.is_at_horizontal_boundary = true; 202 | } 203 | 204 | if (core->camera.pos_y >= core->camera.max_pos_y) 205 | { 206 | core->camera.pos_y = core->camera.max_pos_y; 207 | } 208 | } 209 | 210 | void update_bounding_box(esz_entity_t* entity) 211 | { 212 | entity->bounding_box.top = entity->pos_y - (double)(entity->height / 2.0); 213 | entity->bounding_box.bottom = entity->pos_y + (double)(entity->height / 2.0); 214 | entity->bounding_box.left = entity->pos_x - (double)(entity->width / 2.0); 215 | entity->bounding_box.right = entity->pos_x + (double)(entity->width / 2.0); 216 | 217 | if (0 >= entity->bounding_box.left) 218 | { 219 | entity->bounding_box.left = 0.0; 220 | } 221 | 222 | if (0 >= entity->bounding_box.top) 223 | { 224 | entity->bounding_box.top = 0.0; 225 | } 226 | } 227 | 228 | void update_entities(esz_window_t* window, esz_core_t* core) 229 | { 230 | esz_tiled_layer_t* layer; 231 | int32_t index = 0; 232 | 233 | if (! core->is_map_loaded) 234 | { 235 | return; 236 | } 237 | 238 | layer = get_head_layer(core->map->handle); 239 | 240 | while (layer) 241 | { 242 | if (is_tiled_layer_of_type(ESZ_OBJECT_GROUP, layer, core)) 243 | { 244 | esz_tiled_object_t* tiled_object = get_head_object(layer, core); 245 | while (tiled_object) 246 | { 247 | uint64_t type_hash = generate_hash((const unsigned char*)get_object_type_name(tiled_object)); 248 | esz_entity_t* entity = &core->map->entity[index]; 249 | 250 | switch (type_hash) 251 | { 252 | case H_actor: 253 | { 254 | esz_actor_t** actor = &entity->actor; 255 | uint32_t* state = &(*actor)->state; 256 | double acceleration_x = (*actor)->acceleration * core->map->meter_in_pixel; 257 | double acceleration_y = core->map->meter_in_pixel * core->map->meter_in_pixel; 258 | double time_since_last_frame = window->time_since_last_frame; 259 | double distance_x = acceleration_x * time_since_last_frame * time_since_last_frame; 260 | double distance_y = acceleration_y * time_since_last_frame * time_since_last_frame; 261 | 262 | // Vertical movement and gravity 263 | // ---------------------------------------------------- 264 | 265 | if (IS_STATE_SET(*state, STATE_GRAVITATIONAL)) 266 | { 267 | CLR_STATE((*actor)->state, STATE_FLOATING); 268 | 269 | if (0 > (*actor)->velocity_y) 270 | { 271 | SET_STATE((*actor)->state, STATE_RISING); 272 | } 273 | else 274 | { 275 | CLR_STATE((*actor)->state, STATE_RISING); 276 | } 277 | 278 | if (IS_STATE_SET((*actor)->state, STATE_RISING)) 279 | { 280 | SET_STATE((*actor)->state, STATE_IN_MID_AIR); 281 | } 282 | 283 | // tbd. check ground collision here 284 | } 285 | else 286 | { 287 | SET_STATE((*actor)->state, STATE_FLOATING); 288 | CLR_STATE((*actor)->state, STATE_IN_MID_AIR); 289 | CLR_STATE((*actor)->state, STATE_JUMPING); 290 | CLR_STATE((*actor)->state, STATE_RISING); 291 | } 292 | 293 | if (0 < core->map->gravitation) 294 | { 295 | if (IS_STATE_SET((*actor)->state, STATE_IN_MID_AIR)) 296 | { 297 | (*actor)->velocity_y += distance_y; 298 | entity->pos_y += (*actor)->velocity_y; 299 | } 300 | else 301 | { 302 | int32_t tile_height = get_tile_height(core->map->handle); 303 | 304 | CLR_STATE((*actor)->action, ACTION_JUMP); 305 | (*actor)->velocity_y = 0.0; 306 | // Correct actor position along the y-axis: 307 | entity->pos_y = ((double)tile_height * round(entity->pos_y / (double)tile_height)); 308 | } 309 | } 310 | else 311 | { 312 | if (IS_STATE_SET((*actor)->state, STATE_MOVING)) 313 | { 314 | (*actor)->velocity_y += distance_y; 315 | } 316 | else 317 | { 318 | (*actor)->velocity_y -= distance_y; 319 | } 320 | 321 | if (0.0 < (*actor)->velocity_y) 322 | { 323 | if (IS_STATE_SET((*actor)->state, STATE_GOING_UP)) 324 | { 325 | entity->pos_y -= (*actor)->velocity_y; 326 | } 327 | else if (IS_STATE_SET((*actor)->state, STATE_GOING_DOWN)) 328 | { 329 | entity->pos_y += (*actor)->velocity_y; 330 | } 331 | } 332 | 333 | /* Since the velocity in free fall is 334 | * normally not limited, the maximum 335 | * horizontal velocity is used in this case. 336 | */ 337 | if ((*actor)->max_velocity_x <= (*actor)->velocity_y) 338 | { 339 | (*actor)->velocity_y = (*actor)->max_velocity_x; 340 | } 341 | else if (0.0 > (*actor)->velocity_x) 342 | { 343 | (*actor)->velocity_y = 0.0; 344 | } 345 | } 346 | 347 | // Horizontal movement 348 | // ---------------------------------------------------- 349 | 350 | if (IS_STATE_SET((*actor)->state, STATE_MOVING)) 351 | { 352 | (*actor)->velocity_x += distance_x; 353 | } 354 | else 355 | { 356 | // tbd. friction 357 | (*actor)->velocity_x -= distance_x * 2.0; 358 | } 359 | 360 | if (0.0 < (*actor)->velocity_x) 361 | { 362 | if (IS_STATE_SET((*actor)->state, STATE_GOING_LEFT)) 363 | { 364 | entity->pos_x -= (*actor)->velocity_x; 365 | } 366 | else if (IS_STATE_SET((*actor)->state, STATE_GOING_RIGHT)) 367 | { 368 | entity->pos_x += (*actor)->velocity_x; 369 | } 370 | } 371 | 372 | if ((*actor)->max_velocity_x <= (*actor)->velocity_x) 373 | { 374 | (*actor)->velocity_x = (*actor)->max_velocity_x; 375 | } 376 | else if (0.0 > (*actor)->velocity_x) 377 | { 378 | (*actor)->velocity_x = 0.0; 379 | } 380 | 381 | // Connect map ends 382 | // ---------------------------------------------------- 383 | 384 | if ((*actor)->connect_horizontal_map_ends) 385 | { 386 | if (0.0 - entity->width > entity->pos_x) 387 | { 388 | entity->pos_x = core->map->width + entity->width; 389 | } 390 | else if (core->map->width + entity->width < entity->pos_x) 391 | { 392 | entity->pos_x = 0.0 - entity->width; 393 | } 394 | } 395 | else 396 | { 397 | if ((double)(entity->width / 4) > entity->pos_x) 398 | { 399 | entity->pos_x = (double)(entity->width / 4); 400 | } 401 | // tbd. 402 | } 403 | 404 | if ((*actor)->connect_vertical_map_ends) 405 | { 406 | if (0.0 - entity->height > entity->pos_y) 407 | { 408 | entity->pos_y = core->map->height + entity->width; 409 | } 410 | else if (core->map->height + entity->height < entity->pos_y) 411 | { 412 | entity->pos_y = 0.0 - entity->height; 413 | } 414 | } 415 | else 416 | { 417 | // tbd. 418 | } 419 | 420 | break; 421 | } 422 | } 423 | 424 | // Update axis-aligned bounding box 425 | // ------------------------------------------------------------ 426 | 427 | update_bounding_box(entity); 428 | 429 | index += 1; 430 | tiled_object = tiled_object->next; 431 | } 432 | } 433 | layer = layer->next; 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /src/esz_utils.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | /** 3 | * @file esz_utils.h 4 | * @brief eszFW utilities 5 | * @details Various helper functions and utilities 6 | */ 7 | 8 | #ifndef ESZ_UTILS_H 9 | #define ESZ_UTILS_H 10 | 11 | #include 12 | #include 13 | 14 | #include "esz_types.h" 15 | 16 | bool get_boolean_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core); 17 | double get_decimal_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core); 18 | int32_t get_integer_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core); 19 | const char* get_string_property(const uint64_t name_hash, esz_tiled_property_t* properties, int32_t property_count, esz_core_t* core); 20 | bool is_camera_at_horizontal_boundary(esz_core_t* core); 21 | void move_camera_to_target(esz_window_t* window, esz_core_t* core); 22 | void poll_events(esz_window_t* window, esz_core_t* core); 23 | void set_camera_boundaries_to_map_size(esz_window_t* window, esz_core_t* core); 24 | void update_bounding_box(esz_entity_t* entity); 25 | void update_entities(esz_window_t* window, esz_core_t* core); 26 | 27 | #endif // ESZ_UTILS_H 28 | --------------------------------------------------------------------------------