From aa2fd8d7b2ba5d7fd0b0385a16021de200a30c14 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Tue, 20 May 2025 17:22:28 +0200 Subject: [PATCH] Add SFML3 example Copy the existing SFML example to a new directory "SFML3Example" and make it build and run with SFML 3. No real functional changes, just small tweaks to make the SFML example build with SFML 3.0 --- SFML3Example/CMakeLists.txt | 50 ++ SFML3Example/SFMLExample.vcxproj | 156 +++++ SFML3Example/SFMLExample.vcxproj.filters | 27 + SFML3Example/SFMLExample/CMakeLists.txt | 50 ++ SFML3Example/SFMLExample/SFMLExample.vcxproj | 156 +++++ .../SFMLExample/SFMLExample.vcxproj.filters | 27 + SFML3Example/SFMLExample/assets/demo.tmx | 34 + .../assets/images/tilemap/platform.tsx | 18 + .../assets/images/tilemap/tileset.png | Bin 0 -> 29737 bytes .../assets/images/tilemap/tileset.txt | 2 + .../assets/images/tilemap/tileset02.png | Bin 0 -> 6478 bytes SFML3Example/SFMLExample/assets/platform.tmx | 94 +++ .../SFMLExample/cmake/modules/FindSFML.cmake | 366 ++++++++++ .../cmake/modules/FindTMXLITE.cmake | 10 + SFML3Example/SFMLExample/meson.build | 17 + SFML3Example/SFMLExample/readme.md | 10 + .../SFMLExample/src/SFMLOrthogonalLayer.hpp | 651 ++++++++++++++++++ SFML3Example/SFMLExample/src/main.cpp | 95 +++ SFML3Example/assets/demo.tmx | 34 + .../assets/images/tilemap/platform.tsx | 18 + .../assets/images/tilemap/tileset.png | Bin 0 -> 29737 bytes .../assets/images/tilemap/tileset.txt | 2 + .../assets/images/tilemap/tileset02.png | Bin 0 -> 6478 bytes SFML3Example/assets/platform.tmx | 94 +++ SFML3Example/cmake/modules/FindSFML.cmake | 366 ++++++++++ SFML3Example/cmake/modules/FindTMXLITE.cmake | 10 + SFML3Example/meson.build | 17 + SFML3Example/readme.md | 10 + SFML3Example/src/SFMLOrthogonalLayer.hpp | 648 +++++++++++++++++ SFML3Example/src/main.cpp | 95 +++ 30 files changed, 3057 insertions(+) create mode 100644 SFML3Example/CMakeLists.txt create mode 100644 SFML3Example/SFMLExample.vcxproj create mode 100644 SFML3Example/SFMLExample.vcxproj.filters create mode 100644 SFML3Example/SFMLExample/CMakeLists.txt create mode 100644 SFML3Example/SFMLExample/SFMLExample.vcxproj create mode 100644 SFML3Example/SFMLExample/SFMLExample.vcxproj.filters create mode 100644 SFML3Example/SFMLExample/assets/demo.tmx create mode 100644 SFML3Example/SFMLExample/assets/images/tilemap/platform.tsx create mode 100644 SFML3Example/SFMLExample/assets/images/tilemap/tileset.png create mode 100644 SFML3Example/SFMLExample/assets/images/tilemap/tileset.txt create mode 100644 SFML3Example/SFMLExample/assets/images/tilemap/tileset02.png create mode 100644 SFML3Example/SFMLExample/assets/platform.tmx create mode 100644 SFML3Example/SFMLExample/cmake/modules/FindSFML.cmake create mode 100644 SFML3Example/SFMLExample/cmake/modules/FindTMXLITE.cmake create mode 100644 SFML3Example/SFMLExample/meson.build create mode 100644 SFML3Example/SFMLExample/readme.md create mode 100644 SFML3Example/SFMLExample/src/SFMLOrthogonalLayer.hpp create mode 100644 SFML3Example/SFMLExample/src/main.cpp create mode 100644 SFML3Example/assets/demo.tmx create mode 100644 SFML3Example/assets/images/tilemap/platform.tsx create mode 100644 SFML3Example/assets/images/tilemap/tileset.png create mode 100644 SFML3Example/assets/images/tilemap/tileset.txt create mode 100644 SFML3Example/assets/images/tilemap/tileset02.png create mode 100644 SFML3Example/assets/platform.tmx create mode 100644 SFML3Example/cmake/modules/FindSFML.cmake create mode 100644 SFML3Example/cmake/modules/FindTMXLITE.cmake create mode 100644 SFML3Example/meson.build create mode 100644 SFML3Example/readme.md create mode 100644 SFML3Example/src/SFMLOrthogonalLayer.hpp create mode 100644 SFML3Example/src/main.cpp diff --git a/SFML3Example/CMakeLists.txt b/SFML3Example/CMakeLists.txt new file mode 100644 index 0000000..e180972 --- /dev/null +++ b/SFML3Example/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.5) + +project(SFML3_example) +SET(PROJECT_NAME SFML3_example) + +if(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build (Debug or Release)" FORCE) +endif() + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") +SET(PROJECT_STATIC_RUNTIME FALSE CACHE BOOL "Use statically linked standard/runtime libraries?") +#SET(PROJECT_STATIC_TMX FALSE CACHE BOOL "Use statically linked tmxlite library?") + +if(CMAKE_COMPILER_IS_GNUCXX OR APPLE) + if(PROJECT_STATIC_RUNTIME) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14 -static") + else() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14") + endif() +endif() + +SET (CMAKE_CXX_FLAGS_DEBUG "-g -D_DEBUG_") +SET (CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") + +find_package(TMXLITE REQUIRED) +find_package(SFML 2 REQUIRED graphics window system) + +include_directories( + ${TMXLITE_INCLUDE_DIR} + ${SFML_INCLUDE_DIR}) + +set(PROJECT_SRC src/main.cpp) + +if(WIN32) + add_executable(${PROJECT_NAME} WIN32 ${PROJECT_SRC}) +else() + add_executable(${PROJECT_NAME} ${PROJECT_SRC}) +endif() + +target_link_libraries(${PROJECT_NAME} + ${TMXLITE_LIBRARIES} + ${SFML_LIBRARIES}) + +#install executable +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION .) + +#install game data +install(DIRECTORY assets + DESTINATION .) diff --git a/SFML3Example/SFMLExample.vcxproj b/SFML3Example/SFMLExample.vcxproj new file mode 100644 index 0000000..7a5c32d --- /dev/null +++ b/SFML3Example/SFMLExample.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {2298a657-d09a-438e-b976-5ee827966124} + SFMLExample + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ../tmxlite/include;../extlibs/sfml/include + + + Console + true + ../extlibs/sfml/lib;../tmxlite/x64/bin/DebugStatic + libtmxlite-s-d.lib;sfml-system-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ../tmxlite/include;../extlibs/sfml/include + + + Console + true + true + true + ../extlibs/sfml/lib;../tmxlite/x64/bin/ReleaseStatic + libtmxlite-s.lib;sfml-system.lib;sfml-window.lib;sfml-graphics.lib;%(AdditionalDependencies) + + + + + + + + + + + + \ No newline at end of file diff --git a/SFML3Example/SFMLExample.vcxproj.filters b/SFML3Example/SFMLExample.vcxproj.filters new file mode 100644 index 0000000..ac62e2a --- /dev/null +++ b/SFML3Example/SFMLExample.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/SFML3Example/SFMLExample/CMakeLists.txt b/SFML3Example/SFMLExample/CMakeLists.txt new file mode 100644 index 0000000..77a0577 --- /dev/null +++ b/SFML3Example/SFMLExample/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.5) + +project(SFML_example) +SET(PROJECT_NAME SFML_example) + +if(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build (Debug or Release)" FORCE) +endif() + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") +SET(PROJECT_STATIC_RUNTIME FALSE CACHE BOOL "Use statically linked standard/runtime libraries?") +#SET(PROJECT_STATIC_TMX FALSE CACHE BOOL "Use statically linked tmxlite library?") + +if(CMAKE_COMPILER_IS_GNUCXX OR APPLE) + if(PROJECT_STATIC_RUNTIME) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14 -static") + else() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++14") + endif() +endif() + +SET (CMAKE_CXX_FLAGS_DEBUG "-g -D_DEBUG_") +SET (CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG") + +find_package(TMXLITE REQUIRED) +find_package(SFML 2 REQUIRED graphics window system) + +include_directories( + ${TMXLITE_INCLUDE_DIR} + ${SFML_INCLUDE_DIR}) + +set(PROJECT_SRC src/main.cpp) + +if(WIN32) + add_executable(${PROJECT_NAME} WIN32 ${PROJECT_SRC}) +else() + add_executable(${PROJECT_NAME} ${PROJECT_SRC}) +endif() + +target_link_libraries(${PROJECT_NAME} + ${TMXLITE_LIBRARIES} + ${SFML_LIBRARIES}) + +#install executable +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION .) + +#install game data +install(DIRECTORY assets + DESTINATION .) diff --git a/SFML3Example/SFMLExample/SFMLExample.vcxproj b/SFML3Example/SFMLExample/SFMLExample.vcxproj new file mode 100644 index 0000000..7a5c32d --- /dev/null +++ b/SFML3Example/SFMLExample/SFMLExample.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {2298a657-d09a-438e-b976-5ee827966124} + SFMLExample + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ../tmxlite/include;../extlibs/sfml/include + + + Console + true + ../extlibs/sfml/lib;../tmxlite/x64/bin/DebugStatic + libtmxlite-s-d.lib;sfml-system-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ../tmxlite/include;../extlibs/sfml/include + + + Console + true + true + true + ../extlibs/sfml/lib;../tmxlite/x64/bin/ReleaseStatic + libtmxlite-s.lib;sfml-system.lib;sfml-window.lib;sfml-graphics.lib;%(AdditionalDependencies) + + + + + + + + + + + + \ No newline at end of file diff --git a/SFML3Example/SFMLExample/SFMLExample.vcxproj.filters b/SFML3Example/SFMLExample/SFMLExample.vcxproj.filters new file mode 100644 index 0000000..ac62e2a --- /dev/null +++ b/SFML3Example/SFMLExample/SFMLExample.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/SFML3Example/SFMLExample/assets/demo.tmx b/SFML3Example/SFMLExample/assets/demo.tmx new file mode 100644 index 0000000..6691792 --- /dev/null +++ b/SFML3Example/SFMLExample/assets/demo.tmx @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + eJxjYBg8QAOIGcnQxwvEPEiYj0h9nECsggVzkeGGwQoAJB8BMA== + + + + + eJxjYBg+gBmJzT9grhhcAAAUlAAT + + + + + eJxjYBjaQBCIBaCYG4k9CiAAAGXcAF0= + + + diff --git a/SFML3Example/SFMLExample/assets/images/tilemap/platform.tsx b/SFML3Example/SFMLExample/assets/images/tilemap/platform.tsx new file mode 100644 index 0000000..6a48b12 --- /dev/null +++ b/SFML3Example/SFMLExample/assets/images/tilemap/platform.tsx @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/SFML3Example/SFMLExample/assets/images/tilemap/tileset.png b/SFML3Example/SFMLExample/assets/images/tilemap/tileset.png new file mode 100644 index 0000000000000000000000000000000000000000..f13825d15b99d26cb03e987f038c2fb3c6ab61a4 GIT binary patch literal 29737 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 + + + + + + + + + + + eJzt2VsKwyAQBdCsoo8VNN3/BvvbQC1Em9iZOQeE/AQcyFXjLAuc69YxIKuePMgLVckCtNkz4LvrjgGVXHYMqGZPPuSFSuQCPrt3Dshudt/jOfAuZLfOngD8MfmANvkY43ya22P2BIKzvkCbfECbfECb8ykAAABnqNb/qlYvY6rdX0avV77PVe3+Mnq90fMNv/a+Z8gHbK2NZ2B7Jox+PqQO/8rQZi0HAAAAiCf7nWf2+jhW9v5u9vo41sj3E2Ftlg9GjPTMIvTbIswRYKYXswgSvA== + + + + + + + + eJztm9tOw0AMBc0DPAEfAKIY6P9/I6kgqA25NInXa3dnpCOeqJxmZ+89CgCMcfwNAPwHPwCmwQ+AafDDlrvaBYAp+GHLZ5fDIF9VK4I94AfU4qXL60LeqlX3A34ATIMfvrA+yQV++MC6JCf4AdkpOSbjB2RmbFy2HJvxw5bh+2IOlRv8iA9rehueujwO8rzwP/gRk6l5A+PSNua+z7nvEj/KsqXPuhW2jHvRxkr8KMfWPmsN0dqTdnkvlA+/x/ijZT/G+vYM/XuksxSVyzZ8LBxvT1r1g/n9PlR8fJiKlyOt+gHbUKnrhbcj+AFLqPjNn6LNt/AjLyXniCpxnfAcS/ADelRyOeHhCH7ACZX67dvSkdO+99T+5FzO9y7vzz63BaKdFURBpX67tozVecv5Z94Kpzl5/3yHkb/s3V6iUr89Zwi0h0r9dpclUI+18+S58/1r5pAqedfg+NEOKuXuKl07ryb4sYZr+nKL+1kq9d85wY81LJ23WZy9qdCHZ0x2ou/dquBF5mRGJeZvB3pU6r9f0p4fKuv6ZG9H1tZH4iYTKtvbnYcje+ojMZMFlf3PWtIRi/pIvERHxbZPLuGIGtZHYiUiKmXPtKzW7X2dtd8hKZcH2XYf2CrDMzd1fPY9jnjWSeqmxl2HKHcgstRJ/PMNRu5JzA== + + + + + eJzt2+FqwjAUBtDihO2fbnPv/6rbYGUxNOuqbW9izoEgIsqF+jVpczsMAAAAAACkPqILgIq9RxdA1U7RBQSTDyiTjz4dowtoxJr5eP0a52T0PjfX7PDzuuUxajmDY+3mD7byFF3AHcba5YN7nSfGt0PxG/WLzke6FnsLqgFKovNBXVwrXhvnvsswPT9ODed5lvC/YU/5+t45HwCgX+la0HUJsIaWexBga3M9CM+7VAH1SNedf/Ug9JCNUm8G9Mxzm1CmrwfKWsrHXN/RlP/s7S/9TfqR58N9PPiV5+PWZ4n0YPGI1soHPKJL9r7lZ+0AAAAgZQ+Bnr3MfO4eKb3LM5Lujy29Rzq3t3ZLX8VeTkPd9QHU4hO/Kwa1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SFML3Example/SFMLExample/cmake/modules/FindSFML.cmake b/SFML3Example/SFMLExample/cmake/modules/FindSFML.cmake new file mode 100644 index 0000000..48873ef --- /dev/null +++ b/SFML3Example/SFMLExample/cmake/modules/FindSFML.cmake @@ -0,0 +1,366 @@ +# This script locates the SFML library +# ------------------------------------ +# +# Usage +# ----- +# +# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main). +# If none is given, the SFML_LIBRARIES variable will be empty and you'll end up linking to nothing. +# example: +# find_package(SFML COMPONENTS graphics window system) // find the graphics, window and system modules +# +# You can enforce a specific version, either MAJOR.MINOR or only MAJOR. +# If nothing is specified, the version won't be checked (i.e. any version will be accepted). +# example: +# find_package(SFML COMPONENTS ...) // no specific version required +# find_package(SFML 2 COMPONENTS ...) // any 2.x version +# find_package(SFML 2.4 COMPONENTS ...) // version 2.4 or greater +# +# By default, the dynamic libraries of SFML will be found. To find the static ones instead, +# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...). +# Since you have to link yourself all the SFML dependencies when you link it statically, the following +# additional variables are defined: SFML_XXX_DEPENDENCIES and SFML_DEPENDENCIES (see their detailed +# description below). +# In case of static linking, the SFML_STATIC macro will also be defined by this script. +# example: +# set(SFML_STATIC_LIBRARIES TRUE) +# find_package(SFML 2 COMPONENTS network system) +# +# On Mac OS X if SFML_STATIC_LIBRARIES is not set to TRUE then by default CMake will search for frameworks unless +# CMAKE_FIND_FRAMEWORK is set to "NEVER" for example. Please refer to CMake documentation for more details. +# Moreover, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which +# are available for both release and debug modes. +# +# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable +# to tell CMake where SFML is. +# +# Output +# ------ +# +# This script defines the following variables: +# - For each specified module XXX (system, window, graphics, network, audio, main): +# - SFML_XXX_LIBRARY_DEBUG: the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found) +# - SFML_XXX_LIBRARY_RELEASE: the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found) +# - SFML_XXX_LIBRARY: the name of the library to link to for the xxx module (includes both debug and optimized names if necessary) +# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found +# - SFML_XXX_DEPENDENCIES: the list of libraries the module depends on, in case of static linking +# - SFML_LIBRARIES: the list of all libraries corresponding to the required modules +# - SFML_FOUND: true if all the required modules are found +# - SFML_INCLUDE_DIR: the path where SFML headers are located (the directory containing the SFML/Config.hpp file) +# - SFML_DEPENDENCIES: the list of libraries SFML depends on, in case of static linking +# +# example: +# find_package(SFML 2 COMPONENTS system window graphics audio REQUIRED) +# include_directories(${SFML_INCLUDE_DIR}) +# add_executable(myapp ...) +# target_link_libraries(myapp ${SFML_LIBRARIES}) + +# define the SFML_STATIC macro if static build was chosen +if(SFML_STATIC_LIBRARIES) + add_definitions(-DSFML_STATIC) +endif() + +# define the list of search paths for headers and libraries +set(FIND_SFML_PATHS + ${SFML_ROOT} + $ENV{SFML_ROOT} + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw + /opt/local + /opt/csw + /opt) + +# find the SFML include directory +find_path(SFML_INCLUDE_DIR SFML/Config.hpp + PATH_SUFFIXES include + PATHS ${FIND_SFML_PATHS}) + +# check the version number +set(SFML_VERSION_OK TRUE) +if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR) + # extract the major and minor version numbers from SFML/Config.hpp + # we have to handle framework a little bit differently: + if("${SFML_INCLUDE_DIR}" MATCHES "SFML.framework") + set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/Headers/Config.hpp") + else() + set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/SFML/Config.hpp") + endif() + FILE(READ "${SFML_CONFIG_HPP_INPUT}" SFML_CONFIG_HPP_CONTENTS) + STRING(REGEX MATCH ".*#define SFML_VERSION_MAJOR ([0-9]+).*#define SFML_VERSION_MINOR ([0-9]+).*#define SFML_VERSION_PATCH ([0-9]+).*" SFML_CONFIG_HPP_CONTENTS "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_MAJOR ([0-9]+).*" "\\1" SFML_VERSION_MAJOR "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_MINOR ([0-9]+).*" "\\1" SFML_VERSION_MINOR "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_PATCH ([0-9]+).*" "\\1" SFML_VERSION_PATCH "${SFML_CONFIG_HPP_CONTENTS}") + math(EXPR SFML_REQUESTED_VERSION "${SFML_FIND_VERSION_MAJOR} * 10000 + ${SFML_FIND_VERSION_MINOR} * 100 + ${SFML_FIND_VERSION_PATCH}") + + # if we could extract them, compare with the requested version number + if (SFML_VERSION_MAJOR) + # transform version numbers to an integer + math(EXPR SFML_VERSION "${SFML_VERSION_MAJOR} * 10000 + ${SFML_VERSION_MINOR} * 100 + ${SFML_VERSION_PATCH}") + + # compare them + if(SFML_VERSION LESS SFML_REQUESTED_VERSION) + set(SFML_VERSION_OK FALSE) + endif() + else() + # SFML version is < 2.0 + if (SFML_REQUESTED_VERSION GREATER 10900) + set(SFML_VERSION_OK FALSE) + set(SFML_VERSION_MAJOR 1) + set(SFML_VERSION_MINOR x) + set(SFML_VERSION_PATCH x) + endif() + endif() +endif() + +# find the requested modules +set(SFML_FOUND TRUE) # will be set to false if one of the required modules is not found +foreach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS}) + string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER) + string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER) + set(FIND_SFML_COMPONENT_NAME sfml-${FIND_SFML_COMPONENT_LOWER}) + + # no suffix for sfml-main, it is always a static library + if(FIND_SFML_COMPONENT_LOWER STREQUAL "main") + # release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME} + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + else() + # static release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME}-s + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # static debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-s-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # dynamic release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME} + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # dynamic debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # choose the entries that fit the requested link type + if(SFML_STATIC_LIBRARIES) + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE}) + endif() + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG}) + endif() + else() + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE}) + endif() + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG}) + endif() + endif() + endif() + + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG OR SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + # library found + set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND TRUE) + + # if both are found, set SFML_XXX_LIBRARY to contain both + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY debug ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG} + optimized ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + endif() + + # if only one debug/release variant is found, set the other to be equal to the found one + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + # debug and not release + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}) + endif() + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG) + # release and not debug + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + endif() + else() + # library not found + set(SFML_FOUND FALSE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND FALSE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY "") + set(FIND_SFML_MISSING "${FIND_SFML_MISSING} SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY") + endif() + + # mark as advanced + MARK_AS_ADVANCED(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG) + + # add to the global list of libraries + set(SFML_LIBRARIES ${SFML_LIBRARIES} "${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY}") +endforeach() + +# in case of static linking, we must also define the list of all the dependencies of SFML libraries +if(SFML_STATIC_LIBRARIES) + + # detect the OS + if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(FIND_SFML_OS_WINDOWS 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(FIND_SFML_OS_LINUX 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + set(FIND_SFML_OS_FREEBSD 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(FIND_SFML_OS_MACOSX 1) + endif() + + # start with an empty list + set(SFML_DEPENDENCIES) + set(FIND_SFML_DEPENDENCIES_NOTFOUND) + + # macro that searches for a 3rd-party library + macro(find_sfml_dependency output friendlyname) + # No lookup in environment variables (PATH on Windows), as they may contain wrong library versions + find_library(${output} NAMES ${ARGN} PATHS ${FIND_SFML_PATHS} PATH_SUFFIXES lib NO_SYSTEM_ENVIRONMENT_PATH) + if(${${output}} STREQUAL "${output}-NOTFOUND") + unset(output) + set(FIND_SFML_DEPENDENCIES_NOTFOUND "${FIND_SFML_DEPENDENCIES_NOTFOUND} ${friendlyname}") + endif() + endmacro() + + # sfml-system + list(FIND SFML_FIND_COMPONENTS "system" FIND_SFML_SYSTEM_COMPONENT) + if(NOT ${FIND_SFML_SYSTEM_COMPONENT} EQUAL -1) + + # update the list -- these are only system libraries, no need to find them + if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD OR FIND_SFML_OS_MACOSX) + set(SFML_SYSTEM_DEPENDENCIES "pthread") + endif() + if(FIND_SFML_OS_LINUX) + set(SFML_SYSTEM_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} "rt") + endif() + if(FIND_SFML_OS_WINDOWS) + set(SFML_SYSTEM_DEPENDENCIES "winmm") + endif() + set(SFML_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-network + list(FIND SFML_FIND_COMPONENTS "network" FIND_SFML_NETWORK_COMPONENT) + if(NOT ${FIND_SFML_NETWORK_COMPONENT} EQUAL -1) + + # update the list -- these are only system libraries, no need to find them + if(FIND_SFML_OS_WINDOWS) + set(SFML_NETWORK_DEPENDENCIES "ws2_32") + endif() + set(SFML_DEPENDENCIES ${SFML_NETWORK_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-window + list(FIND SFML_FIND_COMPONENTS "window" FIND_SFML_WINDOW_COMPONENT) + if(NOT ${FIND_SFML_WINDOW_COMPONENT} EQUAL -1) + + # find libraries + if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) + find_sfml_dependency(X11_LIBRARY "X11" X11) + find_sfml_dependency(LIBXCB_LIBRARIES "XCB" xcb libxcb) + find_sfml_dependency(X11_XCB_LIBRARY "X11-xcb" X11-xcb libX11-xcb) + find_sfml_dependency(XCB_RANDR_LIBRARY "xcb-randr" xcb-randr libxcb-randr) + find_sfml_dependency(XCB_IMAGE_LIBRARY "xcb-image" xcb-image libxcb-image) + endif() + + if(FIND_SFML_OS_LINUX) + find_sfml_dependency(UDEV_LIBRARIES "UDev" udev libudev) + endif() + + # update the list + if(FIND_SFML_OS_WINDOWS) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32") + elseif(FIND_SFML_OS_LINUX) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} ${UDEV_LIBRARIES}) + elseif(FIND_SFML_OS_FREEBSD) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} "usbhid") + elseif(FIND_SFML_OS_MACOSX) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon") + endif() + set(SFML_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-graphics + list(FIND SFML_FIND_COMPONENTS "graphics" FIND_SFML_GRAPHICS_COMPONENT) + if(NOT ${FIND_SFML_GRAPHICS_COMPONENT} EQUAL -1) + + # find libraries + find_sfml_dependency(FREETYPE_LIBRARY "FreeType" freetype) + find_sfml_dependency(JPEG_LIBRARY "libjpeg" jpeg) + + # update the list + set(SFML_GRAPHICS_DEPENDENCIES ${FREETYPE_LIBRARY} ${JPEG_LIBRARY}) + set(SFML_DEPENDENCIES ${SFML_GRAPHICS_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-audio + list(FIND SFML_FIND_COMPONENTS "audio" FIND_SFML_AUDIO_COMPONENT) + if(NOT ${FIND_SFML_AUDIO_COMPONENT} EQUAL -1) + + # find libraries + find_sfml_dependency(OPENAL_LIBRARY "OpenAL" openal openal32) + find_sfml_dependency(OGG_LIBRARY "Ogg" ogg) + find_sfml_dependency(VORBIS_LIBRARY "Vorbis" vorbis) + find_sfml_dependency(VORBISFILE_LIBRARY "VorbisFile" vorbisfile) + find_sfml_dependency(VORBISENC_LIBRARY "VorbisEnc" vorbisenc) + find_sfml_dependency(FLAC_LIBRARY "FLAC" flac) + + # update the list + set(SFML_AUDIO_DEPENDENCIES ${OPENAL_LIBRARY} ${FLAC_LIBRARY} ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY}) + set(SFML_DEPENDENCIES ${SFML_DEPENDENCIES} ${SFML_AUDIO_DEPENDENCIES}) + endif() + +endif() + +# handle errors +if(NOT SFML_VERSION_OK) + # SFML version not ok + set(FIND_SFML_ERROR "SFML found but version too low (requested: ${SFML_FIND_VERSION}, found: ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH})") + set(SFML_FOUND FALSE) +elseif(SFML_STATIC_LIBRARIES AND FIND_SFML_DEPENDENCIES_NOTFOUND) + set(FIND_SFML_ERROR "SFML found but some of its dependencies are missing (${FIND_SFML_DEPENDENCIES_NOTFOUND})") + set(SFML_FOUND FALSE) +elseif(NOT SFML_FOUND) + # include directory or library not found + set(FIND_SFML_ERROR "Could NOT find SFML (missing: ${FIND_SFML_MISSING})") +endif() +if (NOT SFML_FOUND) + if(SFML_FIND_REQUIRED) + # fatal error + message(FATAL_ERROR ${FIND_SFML_ERROR}) + elseif(NOT SFML_FIND_QUIETLY) + # error but continue + message("${FIND_SFML_ERROR}") + endif() +endif() + +# handle success +if(SFML_FOUND AND NOT SFML_FIND_QUIETLY) + message(STATUS "Found SFML ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH} in ${SFML_INCLUDE_DIR}") +endif() diff --git a/SFML3Example/SFMLExample/cmake/modules/FindTMXLITE.cmake b/SFML3Example/SFMLExample/cmake/modules/FindTMXLITE.cmake new file mode 100644 index 0000000..6ca7154 --- /dev/null +++ b/SFML3Example/SFMLExample/cmake/modules/FindTMXLITE.cmake @@ -0,0 +1,10 @@ +find_path(TMXLITE_INCLUDE_DIR NAMES tmxlite/Config.hpp PATH_SUFFIXES include) + +find_library(TMXLITE_LIBRARY_DEBUG NAMES tmxlite-d) +find_library(TMXLITE_LIBRARY_RELEASE NAMES tmxlite) + +include(SelectLibraryConfigurations) +select_library_configurations(TMXLITE) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TMXLITE DEFAULT_MSG TMXLITE_LIBRARY TMXLITE_INCLUDE_DIR) \ No newline at end of file diff --git a/SFML3Example/SFMLExample/meson.build b/SFML3Example/SFMLExample/meson.build new file mode 100644 index 0000000..7b3dd5d --- /dev/null +++ b/SFML3Example/SFMLExample/meson.build @@ -0,0 +1,17 @@ +sfml_graphics_dep = dependency('sfml-graphics') +sfml_window_dep = dependency('sfml-window') +sfml_system_dep = dependency('sfml-system') + +pvt_incdir = include_directories('src') + +executable('SFML_example', + 'src/main.cpp', + install: false, + include_directories: pvt_incdir, + dependencies: [ + tmxlite_dep, + sfml_graphics_dep, + sfml_window_dep, + sfml_system_dep, + ], +) diff --git a/SFML3Example/SFMLExample/readme.md b/SFML3Example/SFMLExample/readme.md new file mode 100644 index 0000000..2069582 --- /dev/null +++ b/SFML3Example/SFMLExample/readme.md @@ -0,0 +1,10 @@ +SFML Example +------------ + +Test program demonstrating how one may possibly implement +an orthogonal map renderer using SFML. + +Note that this example provides very basic rendering, and +does not support all the features supported by tmxlite, +such as tile flipping/rotation or tilesets which are created +as a collection of images \ No newline at end of file diff --git a/SFML3Example/SFMLExample/src/SFMLOrthogonalLayer.hpp b/SFML3Example/SFMLExample/src/SFMLOrthogonalLayer.hpp new file mode 100644 index 0000000..450064b --- /dev/null +++ b/SFML3Example/SFMLExample/src/SFMLOrthogonalLayer.hpp @@ -0,0 +1,651 @@ +/********************************************************************* +(c) Matt Marchant & contributors 2016 - 2024 +http://trederia.blogspot.com + +tmxlite - Zlib license. + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but +is not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any +source distribution. +*********************************************************************/ + +/* +Creates an SFML drawable from an Orthogonal tmx map layer. +This is an example of drawing with SFML - not all features +are implemented. +*/ + +#ifndef SFML_ORTHO_HPP_ +#define SFML_ORTHO_HPP_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +class MapLayer final : public sf::Drawable +{ +public: + + MapLayer(const tmx::Map& map, std::size_t idx) + { + const auto& layers = map.getLayers(); + if (map.getOrientation() != tmx::Orientation::Orthogonal) + { + std::cout << "Map is not orthogonal - nothing will be drawn" << std::endl; + } + else if (idx >= layers.size()) + { + std::cout << "Layer index " << idx << " is out of range, layer count is " << layers.size() << std::endl; + } + else if (layers[idx]->getType() != tmx::Layer::Type::Tile) + { + std::cout << "layer " << idx << " is not a Tile layer..." << std::endl; + } + + else + { + //round the chunk size to the nearest tile + const auto tileSize = map.getTileSize(); + m_chunkSize.x = std::floor(m_chunkSize.x / tileSize.x) * tileSize.x; + m_chunkSize.y = std::floor(m_chunkSize.y / tileSize.y) * tileSize.y; + m_mapTileSize.x = map.getTileSize().x; + m_mapTileSize.y = map.getTileSize().y; + const auto& layer = layers[idx]->getLayerAs(); + createChunks(map, layer); + + auto mapSize = map.getBounds(); + m_globalBounds.size = {mapSize.width, mapSize.height}; + } + } + + ~MapLayer() = default; + MapLayer(const MapLayer&) = delete; + MapLayer& operator = (const MapLayer&) = delete; + + const sf::FloatRect& getGlobalBounds() const { return m_globalBounds; } + + void setTile(std::int32_t tileX, std::int32_t tileY, tmx::TileLayer::Tile tile, bool refresh = true) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + selectedChunk->setTile(chunkLocale.x, chunkLocale.y, tile, refresh); + } + + tmx::TileLayer::Tile getTile(std::int32_t tileX, std::int32_t tileY) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + return selectedChunk->getTile(chunkLocale.x, chunkLocale.y); + } + void setColor(std::int32_t tileX, std::int32_t tileY, sf::Color color, bool refresh = true) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + selectedChunk->setColor(chunkLocale.x, chunkLocale.y, color, refresh); + } + + sf::Color getColor(std::int32_t tileX, std::int32_t tileY) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + return selectedChunk->getColor(chunkLocale.x, chunkLocale.y); + } + + void setOffset(sf::Vector2f offset) { m_offset = offset; } + sf::Vector2f getOffset() const { return m_offset; } + + void update(sf::Time elapsed) + { + for (auto& c : m_visibleChunks) + { + for (AnimationState& as : c->getActiveAnimations()) + { + as.currentTime += elapsed; + + tmx::TileLayer::Tile tile; + std::int32_t animTime = 0; + auto x = as.animTile.animation.frames.begin(); + while (animTime < as.currentTime.asMilliseconds()) + { + if (x == as.animTile.animation.frames.end()) + { + x = as.animTile.animation.frames.begin(); + as.currentTime -= sf::milliseconds(animTime); + animTime = 0; + } + + tile.ID = x->tileID; + animTime += x->duration; + x++; + } + + setTile(as.tileCords.x, as.tileCords.y, tile); + } + } + } + +private: + //increasing m_chunkSize by 4; fixes render problems when mapsize != chunksize + //sf::Vector2f m_chunkSize = sf::Vector2f(1024.f, 1024.f); + sf::Vector2f m_chunkSize = sf::Vector2f(512.f, 512.f); + sf::Vector2u m_chunkCount; + sf::Vector2u m_mapTileSize; // general Tilesize of Map + sf::FloatRect m_globalBounds; + sf::Vector2f m_offset; + + using TextureResource = std::map>; + TextureResource m_textureResource; + + struct AnimationState + { + sf::Vector2u tileCords; + sf::Time startTime; + sf::Time currentTime; + tmx::Tileset::Tile animTile; + std::uint8_t flipFlags; + }; + + class Chunk final : public sf::Transformable, public sf::Drawable + { + public: + using Ptr = std::unique_ptr; + using Tile = std::array; + + Chunk(const tmx::TileLayer& layer, std::vector tilesets, + const sf::Vector2f& position, const sf::Vector2f& tileCount, + const sf::Vector2u& tileSize, std::size_t rowSize, + TextureResource& tr, const std::map& animTiles) + : m_animTiles(animTiles) + { + setPosition(position); + layerOpacity = static_cast(layer.getOpacity() / 1.f * 255.f); + + sf::Color vertColour = sf::Color(200 ,200, 200, layerOpacity); + auto offset = layer.getOffset(); + layerOffset = { static_cast(offset.x), static_cast(offset.y) }; + chunkTileCount = { tileCount.x, tileCount.y }; + mapTileSize = tileSize; + + const auto& tileIDs = layer.getTiles(); + + //go through the tiles and create all arrays (for latter manipulation) + for (const auto& ts : tilesets) + { + if(ts->getImagePath().empty()) + { + tmx::Logger::log("This example does not support Collection of Images tilesets", tmx::Logger::Type::Info); + tmx::Logger::log("Chunks using " + ts->getName() + " will not be created", tmx::Logger::Type::Info); + continue; + } + m_chunkArrays.emplace_back(std::make_unique(*tr.find(ts->getImagePath())->second, *ts)); + } + std::size_t xPos = static_cast(position.x / tileSize.x); + std::size_t yPos = static_cast(position.y / tileSize.y); + for (auto y = yPos; y < yPos + tileCount.y; ++y) + { + for (auto x = xPos; x < xPos + tileCount.x; ++x) + { + auto idx = (y * rowSize + x); + m_chunkTileIDs.emplace_back(tileIDs[idx]); + m_chunkColors.emplace_back(vertColour); + } + } + generateTiles(true); + } + + void generateTiles(bool registerAnimation = false) + { + if (registerAnimation) + { + m_activeAnimations.clear(); + } + for (const auto& ca : m_chunkArrays) + { + std::uint32_t idx = 0; + std::uint32_t xPos = static_cast(getPosition().x / mapTileSize.x); + std::uint32_t yPos = static_cast(getPosition().y / mapTileSize.y); + for (auto y = yPos; y < yPos + chunkTileCount.y; ++y) + { + for (auto x = xPos; x < xPos + chunkTileCount.x; ++x) + { + if (idx < m_chunkTileIDs.size() && m_chunkTileIDs[idx].ID >= ca->m_firstGID + && m_chunkTileIDs[idx].ID <= ca->m_lastGID) + { + if (registerAnimation && m_animTiles.find(m_chunkTileIDs[idx].ID) != m_animTiles.end()) + { + AnimationState as; + as.animTile = m_animTiles[m_chunkTileIDs[idx].ID]; + as.startTime = sf::milliseconds(0); + as.tileCords = sf::Vector2u(x,y); + m_activeAnimations.push_back(as); + } + + sf::Vector2f tileOffset(static_cast(x) * mapTileSize.x, static_cast(y) * mapTileSize.y + mapTileSize.y - ca->tileSetSize.y); + + auto idIndex = m_chunkTileIDs[idx].ID - ca->m_firstGID; + sf::Vector2f tileIndex(sf::Vector2i(idIndex % ca->tsTileCount.x, idIndex / ca->tsTileCount.x)); + tileIndex.x *= ca->tileSetSize.x; + tileIndex.y *= ca->tileSetSize.y; + Tile tile = + { + sf::Vertex(tileOffset - getPosition(), m_chunkColors[idx], tileIndex), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(static_cast(ca->tileSetSize.x), 0.f), m_chunkColors[idx], tileIndex + sf::Vector2f(static_cast(ca->tileSetSize.x), 0.f)), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y))), + sf::Vertex(tileOffset - getPosition(), m_chunkColors[idx], tileIndex), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y))), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(0.f,static_cast(ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(0.f, static_cast(ca->tileSetSize.y))) + }; + doFlips(m_chunkTileIDs[idx].flipFlags,&tile[0].texCoords,&tile[1].texCoords,&tile[2].texCoords,&tile[3].texCoords,&tile[4].texCoords,&tile[5].texCoords); + ca->addTile(tile); + } + idx++; + } + } + } + } + ~Chunk() = default; + Chunk(const Chunk&) = delete; + Chunk& operator = (const Chunk&) = delete; + + std::vector& getActiveAnimations() + { + return m_activeAnimations; + } + + tmx::TileLayer::Tile getTile(std::int32_t x, std::int32_t y) const + { + return m_chunkTileIDs[calcIndexFrom(x,y)]; + } + + void setTile(std::int32_t x, std::int32_t y, tmx::TileLayer::Tile tile, bool refresh) + { + m_chunkTileIDs[calcIndexFrom(x,y)] = tile; + maybeRegenerate(refresh); + } + + sf::Color getColor(std::int32_t x, std::int32_t y) const + { + return m_chunkColors[calcIndexFrom(x,y)]; + } + + void setColor(std::int32_t x, std::int32_t y, sf::Color color, bool refresh) + { + m_chunkColors[calcIndexFrom(x,y)] = color; + maybeRegenerate(refresh); + } + + void maybeRegenerate(bool refresh) + { + if (refresh) + { + for (const auto& ca : m_chunkArrays) + { + ca->reset(); + } + generateTiles(); + } + } + + std::int32_t calcIndexFrom(std::int32_t x, std::int32_t y) const + { + return x + y * static_cast(chunkTileCount.x); + } + + bool empty() const + { + return m_chunkArrays.empty(); + } + + void flipY(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //Flip Y + sf::Vector2f tmp0 = *v0; + v0->y = v5->y; + v3->y = v5->y; + v5->y = tmp0.y; + sf::Vector2f tmp2 = *v2; + v2->y = v1->y; + v4->y = v1->y; + v1->y = tmp2.y; + } + + void flipX(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //Flip X + sf::Vector2f tmp0 = *v0; + v0->x = v1->x; + v3->x = v1->x; + v1->x = tmp0.x; + sf::Vector2f tmp2 = *v2; + v2->x = v5->x; + v4->x = v5->x; + v5->x = tmp2.x; + } + + void flipD(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //Diagonal flip + sf::Vector2f tmp2 = *v2; + *v2 = *v4; + *v4 = tmp2; + sf::Vector2f tmp0 = *v0; + *v0 = *v3; + *v3 = tmp0; + sf::Vector2f tmp1 = *v1; + *v1 = *v5; + *v5 = tmp1; + } + + void doFlips(std::uint8_t bits, sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //0000 = no change + //0100 = vertical = swap y axis + //1000 = horizontal = swap x axis + //1100 = horiz + vert = swap both axes = horiz+vert = rotate 180 degrees + //0010 = diag = rotate 90 degrees right and swap x axis + //0110 = diag+vert = rotate 270 degrees right + //1010 = horiz+diag = rotate 90 degrees right + //1110 = horiz+vert+diag = rotate 90 degrees right and swap y axis + if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //Shortcircuit tests for nothing to do + return; + } + else if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //0100 + flipY(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1000 + flipX(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1100 + flipY(v0,v1,v2,v3,v4,v5); + flipX(v0,v1,v2,v3,v4,v5); + } + else if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //0010 + flipD(v0,v1,v2,v3,v4,v5); + } + else if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //0110 + flipX(v0,v1,v2,v3,v4,v5); + flipD(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1010 + flipY(v0,v1,v2,v3,v4,v5); + flipD(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1110 + flipY(v0,v1,v2,v3,v4,v5); + flipX(v0,v1,v2,v3,v4,v5); + flipD(v0,v1,v2,v3,v4,v5); + } + } + + private: + class ChunkArray final : public sf::Drawable + { + public: + using Ptr = std::unique_ptr; + + tmx::Vector2u tileSetSize; + sf::Vector2u tsTileCount; + std::uint32_t m_firstGID, m_lastGID; + + explicit ChunkArray(const sf::Texture& t, const tmx::Tileset& ts) + : m_texture(t) + { + auto texSize = getTextureSize(); + tileSetSize = ts.getTileSize(); + tsTileCount.x = texSize.x / tileSetSize.x; + tsTileCount.y = texSize.y / tileSetSize.y; + m_firstGID = ts.getFirstGID(); + m_lastGID = ts.getLastGID(); + } + + ~ChunkArray() = default; + ChunkArray(const ChunkArray&) = delete; + ChunkArray& operator = (const ChunkArray&) = delete; + + void reset() + { + m_vertices.clear(); + } + + void addTile(const Chunk::Tile& tile) + { + for (const auto& v : tile) + { + m_vertices.push_back(v); + } + } + + sf::Vector2u getTextureSize() const + { + return m_texture.getSize(); + } + + private: + const sf::Texture& m_texture; + std::vector m_vertices; + void draw(sf::RenderTarget& rt, sf::RenderStates states) const override + { + states.texture = &m_texture; + rt.draw(m_vertices.data(), m_vertices.size(), sf::PrimitiveType::Triangles, states); + } + }; + + std::uint8_t layerOpacity; // opacity of the layer + sf::Vector2f layerOffset; // Layer offset + sf::Vector2u mapTileSize; // general Tilesize of Map + sf::Vector2f chunkTileCount; // chunk tilecount + std::vector m_chunkTileIDs; // stores all tiles in this chunk for later manipulation + std::vector m_chunkColors; // stores colors for extended color effects + std::map m_animTiles; // animation catalogue + std::vector m_activeAnimations; // Animations to be done in this chunk + std::vector m_chunkArrays; + + void draw(sf::RenderTarget& rt, sf::RenderStates states) const override + { + states.transform *= getTransform(); + for (const auto& a : m_chunkArrays) + { + rt.draw(*a, states); + } + } + }; + + std::vector m_chunks; + mutable std::vector m_visibleChunks; + + Chunk::Ptr& getChunkAndTransform(std::int32_t x, std::int32_t y, sf::Vector2u& chunkRelative) + { + std::uint32_t chunkX = (x * m_mapTileSize.x) / static_cast(m_chunkSize.x); + std::uint32_t chunkY = (y * m_mapTileSize.y) / static_cast(m_chunkSize.y); + chunkRelative.x = ((x * m_mapTileSize.x) - chunkX * static_cast(m_chunkSize.x)) / m_mapTileSize.x ; + chunkRelative.y = ((y * m_mapTileSize.y) - chunkY * static_cast(m_chunkSize.y)) / m_mapTileSize.y ; + return m_chunks[chunkX + chunkY * m_chunkCount.x]; + } + + void createChunks(const tmx::Map& map, const tmx::TileLayer& layer) + { + //look up all the tile sets and load the textures + const auto& tileSets = map.getTilesets(); + const auto& layerIDs = layer.getTiles(); + std::uint32_t maxID = std::numeric_limits::max(); + std::vector usedTileSets; + + for (auto i = tileSets.rbegin(); i != tileSets.rend(); ++i) + { + for (const auto& tile : layerIDs) + { + if (tile.ID >= i->getFirstGID() && tile.ID < maxID) + { + usedTileSets.push_back(&(*i)); + break; + } + } + maxID = i->getFirstGID(); + } + + sf::Image fallback({2, 2}, sf::Color::Magenta); + for (const auto& ts : usedTileSets) + { + const auto& path = ts->getImagePath(); + + std::unique_ptr newTexture = std::make_unique(); + sf::Image img; + if (!img.loadFromFile(path)) + { + if (!newTexture->loadFromImage(fallback)) { + throw std::runtime_error("Unable to load fallback image"); + } + } else { + if (ts->hasTransparency()) + { + auto transparency = ts->getTransparencyColour(); + img.createMaskFromColor({ transparency.r, transparency.g, transparency.b, transparency.a }); + } + if (!newTexture->loadFromImage(img)) { + throw std::runtime_error("Unable to load image: " + path); + } + } + m_textureResource.insert(std::make_pair(path, std::move(newTexture))); + } + + //calculate the number of chunks in the layer + //and create each one + const auto bounds = map.getBounds(); + m_chunkCount.x = static_cast(std::ceil(bounds.width / m_chunkSize.x)); + m_chunkCount.y = static_cast(std::ceil(bounds.height / m_chunkSize.y)); + + sf::Vector2u tileSize(map.getTileSize().x, map.getTileSize().y); + + for (auto y = 0u; y < m_chunkCount.y; ++y) + { + sf::Vector2f tileCount(m_chunkSize.x / tileSize.x, m_chunkSize.y / tileSize.y); + for (auto x = 0u; x < m_chunkCount.x; ++x) + { + // calculate size of each Chunk (clip against map) + if ((x + 1) * m_chunkSize.x > bounds.width) + { + tileCount.x = (bounds.width - x * m_chunkSize.x) / map.getTileSize().x; + } + if ((y + 1) * m_chunkSize.y > bounds.height) + { + tileCount.y = (bounds.height - y * m_chunkSize.y) / map.getTileSize().y; + } + //m_chunks.emplace_back(std::make_unique(layer, usedTileSets, + // sf::Vector2f(x * m_chunkSize.x, y * m_chunkSize.y), tileCount, map.getTileCount().x, m_textureResource)); + m_chunks.emplace_back(std::make_unique(layer, usedTileSets, + sf::Vector2f(x * m_chunkSize.x, y * m_chunkSize.y), tileCount, tileSize, map.getTileCount().x, m_textureResource, map.getAnimatedTiles())); + } + } + } + + void updateVisibility(const sf::View& view) const + { + sf::Vector2f viewCorner = view.getCenter(); + viewCorner -= view.getSize() / 2.f; + + std::int32_t posX = static_cast(std::floor(viewCorner.x / m_chunkSize.x)); + std::int32_t posY = static_cast(std::floor(viewCorner.y / m_chunkSize.y)); + std::int32_t posX2 = static_cast(std::ceil((viewCorner.x + view.getSize().x) / m_chunkSize.x)); + std::int32_t posY2 = static_cast(std::ceil((viewCorner.y + view.getSize().x)/ m_chunkSize.y)); + + std::vector visible; + for (auto y = posY; y < posY2; ++y) + { + for (auto x = posX; x < posX2; ++x) + { + std::size_t idx = y * std::int32_t(m_chunkCount.x) + x; + if (idx >= 0u && idx < m_chunks.size() && !m_chunks[idx]->empty()) + { + visible.push_back(m_chunks[idx].get()); + } + } + } + + std::swap(m_visibleChunks, visible); + } + + + void draw(sf::RenderTarget& rt, sf::RenderStates states) const override + { + states.transform.translate(m_offset); + + //calc view coverage and draw nearest chunks + updateVisibility(rt.getView()); + for (const auto& c : m_visibleChunks) + { + rt.draw(*c, states); + } + } +}; + +#endif //SFML_ORTHO_HPP_ diff --git a/SFML3Example/SFMLExample/src/main.cpp b/SFML3Example/SFMLExample/src/main.cpp new file mode 100644 index 0000000..2c66d18 --- /dev/null +++ b/SFML3Example/SFMLExample/src/main.cpp @@ -0,0 +1,95 @@ +/********************************************************************* +(c) Matt Marchant & contributors 2016 - 2024 +http://trederia.blogspot.com + +tmxlite - Zlib license. + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but +is not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any +source distribution. +*********************************************************************/ + + +#include "SFMLOrthogonalLayer.hpp" + +#include +#include +#include + + +int main() +{ + sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); + + tmx::Map map; + map.load("assets/demo.tmx"); + + MapLayer layerZero(map, 0); + MapLayer layerOne(map, 1); + MapLayer layerTwo(map, 2); + + sf::Clock globalClock; + sf::Clock wiggleClock; + + bool doWiggle = false; + + while (window.isOpen()) + { + sf::Event event; + while (window.pollEvent(event)) + { + if (event.type == sf::Event::Closed) + { + window.close(); + } + + else if( event.type == sf::Event::KeyPressed ) + { + switch(event.key.code) + { + case sf::Keyboard::W: + // toggle doWiggle + doWiggle = !doWiggle; + break; + } + } + } + + + sf::Time duration = globalClock.restart(); + layerZero.update(duration); + + sf::Vector2f newOffset = sf::Vector2f(0.f, 0.f); + if (doWiggle) + { + newOffset = sf::Vector2f(std::cos(wiggleClock.getElapsedTime().asSeconds()) * 100.f, 0.f); + } + layerZero.setOffset(newOffset); + layerOne.setOffset(newOffset); + layerTwo.setOffset(newOffset); + + window.clear(sf::Color::Black); + window.draw(layerZero); + window.draw(layerOne); + window.draw(layerTwo); + window.display(); + } + + return 0; +} diff --git a/SFML3Example/assets/demo.tmx b/SFML3Example/assets/demo.tmx new file mode 100644 index 0000000..6691792 --- /dev/null +++ b/SFML3Example/assets/demo.tmx @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + eJxjYBg8QAOIGcnQxwvEPEiYj0h9nECsggVzkeGGwQoAJB8BMA== + + + + + eJxjYBg+gBmJzT9grhhcAAAUlAAT + + + + + eJxjYBjaQBCIBaCYG4k9CiAAAGXcAF0= + + + diff --git a/SFML3Example/assets/images/tilemap/platform.tsx b/SFML3Example/assets/images/tilemap/platform.tsx new file mode 100644 index 0000000..6a48b12 --- /dev/null +++ b/SFML3Example/assets/images/tilemap/platform.tsx @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/SFML3Example/assets/images/tilemap/tileset.png b/SFML3Example/assets/images/tilemap/tileset.png new file mode 100644 index 0000000000000000000000000000000000000000..f13825d15b99d26cb03e987f038c2fb3c6ab61a4 GIT binary patch literal 29737 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 + + + + + + + + + + + eJzt2VsKwyAQBdCsoo8VNN3/BvvbQC1Em9iZOQeE/AQcyFXjLAuc69YxIKuePMgLVckCtNkz4LvrjgGVXHYMqGZPPuSFSuQCPrt3Dshudt/jOfAuZLfOngD8MfmANvkY43ya22P2BIKzvkCbfECbfECb8ykAAABnqNb/qlYvY6rdX0avV77PVe3+Mnq90fMNv/a+Z8gHbK2NZ2B7Jox+PqQO/8rQZi0HAAAAiCf7nWf2+jhW9v5u9vo41sj3E2Ftlg9GjPTMIvTbIswRYKYXswgSvA== + + + + + + + + eJztm9tOw0AMBc0DPAEfAKIY6P9/I6kgqA25NInXa3dnpCOeqJxmZ+89CgCMcfwNAPwHPwCmwQ+AafDDlrvaBYAp+GHLZ5fDIF9VK4I94AfU4qXL60LeqlX3A34ATIMfvrA+yQV++MC6JCf4AdkpOSbjB2RmbFy2HJvxw5bh+2IOlRv8iA9rehueujwO8rzwP/gRk6l5A+PSNua+z7nvEj/KsqXPuhW2jHvRxkr8KMfWPmsN0dqTdnkvlA+/x/ijZT/G+vYM/XuksxSVyzZ8LBxvT1r1g/n9PlR8fJiKlyOt+gHbUKnrhbcj+AFLqPjNn6LNt/AjLyXniCpxnfAcS/ADelRyOeHhCH7ACZX67dvSkdO+99T+5FzO9y7vzz63BaKdFURBpX67tozVecv5Z94Kpzl5/3yHkb/s3V6iUr89Zwi0h0r9dpclUI+18+S58/1r5pAqedfg+NEOKuXuKl07ryb4sYZr+nKL+1kq9d85wY81LJ23WZy9qdCHZ0x2ou/dquBF5mRGJeZvB3pU6r9f0p4fKuv6ZG9H1tZH4iYTKtvbnYcje+ojMZMFlf3PWtIRi/pIvERHxbZPLuGIGtZHYiUiKmXPtKzW7X2dtd8hKZcH2XYf2CrDMzd1fPY9jnjWSeqmxl2HKHcgstRJ/PMNRu5JzA== + + + + + eJzt2+FqwjAUBtDihO2fbnPv/6rbYGUxNOuqbW9izoEgIsqF+jVpczsMAAAAAACkPqILgIq9RxdA1U7RBQSTDyiTjz4dowtoxJr5eP0a52T0PjfX7PDzuuUxajmDY+3mD7byFF3AHcba5YN7nSfGt0PxG/WLzke6FnsLqgFKovNBXVwrXhvnvsswPT9ODed5lvC/YU/5+t45HwCgX+la0HUJsIaWexBga3M9CM+7VAH1SNedf/Ug9JCNUm8G9Mxzm1CmrwfKWsrHXN/RlP/s7S/9TfqR58N9PPiV5+PWZ4n0YPGI1soHPKJL9r7lZ+0AAAAgZQ+Bnr3MfO4eKb3LM5Lujy29Rzq3t3ZLX8VeTkPd9QHU4hO/Kwa1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SFML3Example/cmake/modules/FindSFML.cmake b/SFML3Example/cmake/modules/FindSFML.cmake new file mode 100644 index 0000000..48873ef --- /dev/null +++ b/SFML3Example/cmake/modules/FindSFML.cmake @@ -0,0 +1,366 @@ +# This script locates the SFML library +# ------------------------------------ +# +# Usage +# ----- +# +# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main). +# If none is given, the SFML_LIBRARIES variable will be empty and you'll end up linking to nothing. +# example: +# find_package(SFML COMPONENTS graphics window system) // find the graphics, window and system modules +# +# You can enforce a specific version, either MAJOR.MINOR or only MAJOR. +# If nothing is specified, the version won't be checked (i.e. any version will be accepted). +# example: +# find_package(SFML COMPONENTS ...) // no specific version required +# find_package(SFML 2 COMPONENTS ...) // any 2.x version +# find_package(SFML 2.4 COMPONENTS ...) // version 2.4 or greater +# +# By default, the dynamic libraries of SFML will be found. To find the static ones instead, +# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...). +# Since you have to link yourself all the SFML dependencies when you link it statically, the following +# additional variables are defined: SFML_XXX_DEPENDENCIES and SFML_DEPENDENCIES (see their detailed +# description below). +# In case of static linking, the SFML_STATIC macro will also be defined by this script. +# example: +# set(SFML_STATIC_LIBRARIES TRUE) +# find_package(SFML 2 COMPONENTS network system) +# +# On Mac OS X if SFML_STATIC_LIBRARIES is not set to TRUE then by default CMake will search for frameworks unless +# CMAKE_FIND_FRAMEWORK is set to "NEVER" for example. Please refer to CMake documentation for more details. +# Moreover, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which +# are available for both release and debug modes. +# +# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable +# to tell CMake where SFML is. +# +# Output +# ------ +# +# This script defines the following variables: +# - For each specified module XXX (system, window, graphics, network, audio, main): +# - SFML_XXX_LIBRARY_DEBUG: the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found) +# - SFML_XXX_LIBRARY_RELEASE: the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found) +# - SFML_XXX_LIBRARY: the name of the library to link to for the xxx module (includes both debug and optimized names if necessary) +# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found +# - SFML_XXX_DEPENDENCIES: the list of libraries the module depends on, in case of static linking +# - SFML_LIBRARIES: the list of all libraries corresponding to the required modules +# - SFML_FOUND: true if all the required modules are found +# - SFML_INCLUDE_DIR: the path where SFML headers are located (the directory containing the SFML/Config.hpp file) +# - SFML_DEPENDENCIES: the list of libraries SFML depends on, in case of static linking +# +# example: +# find_package(SFML 2 COMPONENTS system window graphics audio REQUIRED) +# include_directories(${SFML_INCLUDE_DIR}) +# add_executable(myapp ...) +# target_link_libraries(myapp ${SFML_LIBRARIES}) + +# define the SFML_STATIC macro if static build was chosen +if(SFML_STATIC_LIBRARIES) + add_definitions(-DSFML_STATIC) +endif() + +# define the list of search paths for headers and libraries +set(FIND_SFML_PATHS + ${SFML_ROOT} + $ENV{SFML_ROOT} + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw + /opt/local + /opt/csw + /opt) + +# find the SFML include directory +find_path(SFML_INCLUDE_DIR SFML/Config.hpp + PATH_SUFFIXES include + PATHS ${FIND_SFML_PATHS}) + +# check the version number +set(SFML_VERSION_OK TRUE) +if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR) + # extract the major and minor version numbers from SFML/Config.hpp + # we have to handle framework a little bit differently: + if("${SFML_INCLUDE_DIR}" MATCHES "SFML.framework") + set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/Headers/Config.hpp") + else() + set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/SFML/Config.hpp") + endif() + FILE(READ "${SFML_CONFIG_HPP_INPUT}" SFML_CONFIG_HPP_CONTENTS) + STRING(REGEX MATCH ".*#define SFML_VERSION_MAJOR ([0-9]+).*#define SFML_VERSION_MINOR ([0-9]+).*#define SFML_VERSION_PATCH ([0-9]+).*" SFML_CONFIG_HPP_CONTENTS "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_MAJOR ([0-9]+).*" "\\1" SFML_VERSION_MAJOR "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_MINOR ([0-9]+).*" "\\1" SFML_VERSION_MINOR "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_PATCH ([0-9]+).*" "\\1" SFML_VERSION_PATCH "${SFML_CONFIG_HPP_CONTENTS}") + math(EXPR SFML_REQUESTED_VERSION "${SFML_FIND_VERSION_MAJOR} * 10000 + ${SFML_FIND_VERSION_MINOR} * 100 + ${SFML_FIND_VERSION_PATCH}") + + # if we could extract them, compare with the requested version number + if (SFML_VERSION_MAJOR) + # transform version numbers to an integer + math(EXPR SFML_VERSION "${SFML_VERSION_MAJOR} * 10000 + ${SFML_VERSION_MINOR} * 100 + ${SFML_VERSION_PATCH}") + + # compare them + if(SFML_VERSION LESS SFML_REQUESTED_VERSION) + set(SFML_VERSION_OK FALSE) + endif() + else() + # SFML version is < 2.0 + if (SFML_REQUESTED_VERSION GREATER 10900) + set(SFML_VERSION_OK FALSE) + set(SFML_VERSION_MAJOR 1) + set(SFML_VERSION_MINOR x) + set(SFML_VERSION_PATCH x) + endif() + endif() +endif() + +# find the requested modules +set(SFML_FOUND TRUE) # will be set to false if one of the required modules is not found +foreach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS}) + string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER) + string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER) + set(FIND_SFML_COMPONENT_NAME sfml-${FIND_SFML_COMPONENT_LOWER}) + + # no suffix for sfml-main, it is always a static library + if(FIND_SFML_COMPONENT_LOWER STREQUAL "main") + # release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME} + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + else() + # static release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME}-s + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # static debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-s-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # dynamic release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME} + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # dynamic debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_PATHS}) + + # choose the entries that fit the requested link type + if(SFML_STATIC_LIBRARIES) + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE}) + endif() + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG}) + endif() + else() + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE}) + endif() + if(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG}) + endif() + endif() + endif() + + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG OR SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + # library found + set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND TRUE) + + # if both are found, set SFML_XXX_LIBRARY to contain both + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY debug ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG} + optimized ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + endif() + + # if only one debug/release variant is found, set the other to be equal to the found one + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + # debug and not release + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}) + endif() + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG) + # release and not debug + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + endif() + else() + # library not found + set(SFML_FOUND FALSE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND FALSE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY "") + set(FIND_SFML_MISSING "${FIND_SFML_MISSING} SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY") + endif() + + # mark as advanced + MARK_AS_ADVANCED(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_STATIC_DEBUG + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DYNAMIC_DEBUG) + + # add to the global list of libraries + set(SFML_LIBRARIES ${SFML_LIBRARIES} "${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY}") +endforeach() + +# in case of static linking, we must also define the list of all the dependencies of SFML libraries +if(SFML_STATIC_LIBRARIES) + + # detect the OS + if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(FIND_SFML_OS_WINDOWS 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(FIND_SFML_OS_LINUX 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + set(FIND_SFML_OS_FREEBSD 1) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(FIND_SFML_OS_MACOSX 1) + endif() + + # start with an empty list + set(SFML_DEPENDENCIES) + set(FIND_SFML_DEPENDENCIES_NOTFOUND) + + # macro that searches for a 3rd-party library + macro(find_sfml_dependency output friendlyname) + # No lookup in environment variables (PATH on Windows), as they may contain wrong library versions + find_library(${output} NAMES ${ARGN} PATHS ${FIND_SFML_PATHS} PATH_SUFFIXES lib NO_SYSTEM_ENVIRONMENT_PATH) + if(${${output}} STREQUAL "${output}-NOTFOUND") + unset(output) + set(FIND_SFML_DEPENDENCIES_NOTFOUND "${FIND_SFML_DEPENDENCIES_NOTFOUND} ${friendlyname}") + endif() + endmacro() + + # sfml-system + list(FIND SFML_FIND_COMPONENTS "system" FIND_SFML_SYSTEM_COMPONENT) + if(NOT ${FIND_SFML_SYSTEM_COMPONENT} EQUAL -1) + + # update the list -- these are only system libraries, no need to find them + if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD OR FIND_SFML_OS_MACOSX) + set(SFML_SYSTEM_DEPENDENCIES "pthread") + endif() + if(FIND_SFML_OS_LINUX) + set(SFML_SYSTEM_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} "rt") + endif() + if(FIND_SFML_OS_WINDOWS) + set(SFML_SYSTEM_DEPENDENCIES "winmm") + endif() + set(SFML_DEPENDENCIES ${SFML_SYSTEM_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-network + list(FIND SFML_FIND_COMPONENTS "network" FIND_SFML_NETWORK_COMPONENT) + if(NOT ${FIND_SFML_NETWORK_COMPONENT} EQUAL -1) + + # update the list -- these are only system libraries, no need to find them + if(FIND_SFML_OS_WINDOWS) + set(SFML_NETWORK_DEPENDENCIES "ws2_32") + endif() + set(SFML_DEPENDENCIES ${SFML_NETWORK_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-window + list(FIND SFML_FIND_COMPONENTS "window" FIND_SFML_WINDOW_COMPONENT) + if(NOT ${FIND_SFML_WINDOW_COMPONENT} EQUAL -1) + + # find libraries + if(FIND_SFML_OS_LINUX OR FIND_SFML_OS_FREEBSD) + find_sfml_dependency(X11_LIBRARY "X11" X11) + find_sfml_dependency(LIBXCB_LIBRARIES "XCB" xcb libxcb) + find_sfml_dependency(X11_XCB_LIBRARY "X11-xcb" X11-xcb libX11-xcb) + find_sfml_dependency(XCB_RANDR_LIBRARY "xcb-randr" xcb-randr libxcb-randr) + find_sfml_dependency(XCB_IMAGE_LIBRARY "xcb-image" xcb-image libxcb-image) + endif() + + if(FIND_SFML_OS_LINUX) + find_sfml_dependency(UDEV_LIBRARIES "UDev" udev libudev) + endif() + + # update the list + if(FIND_SFML_OS_WINDOWS) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "opengl32" "winmm" "gdi32") + elseif(FIND_SFML_OS_LINUX) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} ${UDEV_LIBRARIES}) + elseif(FIND_SFML_OS_FREEBSD) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "GL" ${X11_LIBRARY} ${LIBXCB_LIBRARIES} ${X11_XCB_LIBRARY} ${XCB_RANDR_LIBRARY} ${XCB_IMAGE_LIBRARY} "usbhid") + elseif(FIND_SFML_OS_MACOSX) + set(SFML_WINDOW_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} "-framework OpenGL -framework Foundation -framework AppKit -framework IOKit -framework Carbon") + endif() + set(SFML_DEPENDENCIES ${SFML_WINDOW_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-graphics + list(FIND SFML_FIND_COMPONENTS "graphics" FIND_SFML_GRAPHICS_COMPONENT) + if(NOT ${FIND_SFML_GRAPHICS_COMPONENT} EQUAL -1) + + # find libraries + find_sfml_dependency(FREETYPE_LIBRARY "FreeType" freetype) + find_sfml_dependency(JPEG_LIBRARY "libjpeg" jpeg) + + # update the list + set(SFML_GRAPHICS_DEPENDENCIES ${FREETYPE_LIBRARY} ${JPEG_LIBRARY}) + set(SFML_DEPENDENCIES ${SFML_GRAPHICS_DEPENDENCIES} ${SFML_DEPENDENCIES}) + endif() + + # sfml-audio + list(FIND SFML_FIND_COMPONENTS "audio" FIND_SFML_AUDIO_COMPONENT) + if(NOT ${FIND_SFML_AUDIO_COMPONENT} EQUAL -1) + + # find libraries + find_sfml_dependency(OPENAL_LIBRARY "OpenAL" openal openal32) + find_sfml_dependency(OGG_LIBRARY "Ogg" ogg) + find_sfml_dependency(VORBIS_LIBRARY "Vorbis" vorbis) + find_sfml_dependency(VORBISFILE_LIBRARY "VorbisFile" vorbisfile) + find_sfml_dependency(VORBISENC_LIBRARY "VorbisEnc" vorbisenc) + find_sfml_dependency(FLAC_LIBRARY "FLAC" flac) + + # update the list + set(SFML_AUDIO_DEPENDENCIES ${OPENAL_LIBRARY} ${FLAC_LIBRARY} ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY}) + set(SFML_DEPENDENCIES ${SFML_DEPENDENCIES} ${SFML_AUDIO_DEPENDENCIES}) + endif() + +endif() + +# handle errors +if(NOT SFML_VERSION_OK) + # SFML version not ok + set(FIND_SFML_ERROR "SFML found but version too low (requested: ${SFML_FIND_VERSION}, found: ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH})") + set(SFML_FOUND FALSE) +elseif(SFML_STATIC_LIBRARIES AND FIND_SFML_DEPENDENCIES_NOTFOUND) + set(FIND_SFML_ERROR "SFML found but some of its dependencies are missing (${FIND_SFML_DEPENDENCIES_NOTFOUND})") + set(SFML_FOUND FALSE) +elseif(NOT SFML_FOUND) + # include directory or library not found + set(FIND_SFML_ERROR "Could NOT find SFML (missing: ${FIND_SFML_MISSING})") +endif() +if (NOT SFML_FOUND) + if(SFML_FIND_REQUIRED) + # fatal error + message(FATAL_ERROR ${FIND_SFML_ERROR}) + elseif(NOT SFML_FIND_QUIETLY) + # error but continue + message("${FIND_SFML_ERROR}") + endif() +endif() + +# handle success +if(SFML_FOUND AND NOT SFML_FIND_QUIETLY) + message(STATUS "Found SFML ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR}.${SFML_VERSION_PATCH} in ${SFML_INCLUDE_DIR}") +endif() diff --git a/SFML3Example/cmake/modules/FindTMXLITE.cmake b/SFML3Example/cmake/modules/FindTMXLITE.cmake new file mode 100644 index 0000000..6ca7154 --- /dev/null +++ b/SFML3Example/cmake/modules/FindTMXLITE.cmake @@ -0,0 +1,10 @@ +find_path(TMXLITE_INCLUDE_DIR NAMES tmxlite/Config.hpp PATH_SUFFIXES include) + +find_library(TMXLITE_LIBRARY_DEBUG NAMES tmxlite-d) +find_library(TMXLITE_LIBRARY_RELEASE NAMES tmxlite) + +include(SelectLibraryConfigurations) +select_library_configurations(TMXLITE) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(TMXLITE DEFAULT_MSG TMXLITE_LIBRARY TMXLITE_INCLUDE_DIR) \ No newline at end of file diff --git a/SFML3Example/meson.build b/SFML3Example/meson.build new file mode 100644 index 0000000..7b3dd5d --- /dev/null +++ b/SFML3Example/meson.build @@ -0,0 +1,17 @@ +sfml_graphics_dep = dependency('sfml-graphics') +sfml_window_dep = dependency('sfml-window') +sfml_system_dep = dependency('sfml-system') + +pvt_incdir = include_directories('src') + +executable('SFML_example', + 'src/main.cpp', + install: false, + include_directories: pvt_incdir, + dependencies: [ + tmxlite_dep, + sfml_graphics_dep, + sfml_window_dep, + sfml_system_dep, + ], +) diff --git a/SFML3Example/readme.md b/SFML3Example/readme.md new file mode 100644 index 0000000..2069582 --- /dev/null +++ b/SFML3Example/readme.md @@ -0,0 +1,10 @@ +SFML Example +------------ + +Test program demonstrating how one may possibly implement +an orthogonal map renderer using SFML. + +Note that this example provides very basic rendering, and +does not support all the features supported by tmxlite, +such as tile flipping/rotation or tilesets which are created +as a collection of images \ No newline at end of file diff --git a/SFML3Example/src/SFMLOrthogonalLayer.hpp b/SFML3Example/src/SFMLOrthogonalLayer.hpp new file mode 100644 index 0000000..10b5687 --- /dev/null +++ b/SFML3Example/src/SFMLOrthogonalLayer.hpp @@ -0,0 +1,648 @@ +/********************************************************************* +(c) Matt Marchant & contributors 2016 - 2024 +http://trederia.blogspot.com + +tmxlite - Zlib license. + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but +is not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any +source distribution. +*********************************************************************/ + +/* +Creates an SFML drawable from an Orthogonal tmx map layer. +This is an example of drawing with SFML - not all features +are implemented. +*/ + +#ifndef SFML_ORTHO_HPP_ +#define SFML_ORTHO_HPP_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +class MapLayer final : public sf::Drawable +{ +public: + + MapLayer(const tmx::Map& map, std::size_t idx) + { + const auto& layers = map.getLayers(); + if (map.getOrientation() != tmx::Orientation::Orthogonal) + { + std::cout << "Map is not orthogonal - nothing will be drawn" << std::endl; + } + else if (idx >= layers.size()) + { + std::cout << "Layer index " << idx << " is out of range, layer count is " << layers.size() << std::endl; + } + else if (layers[idx]->getType() != tmx::Layer::Type::Tile) + { + std::cout << "layer " << idx << " is not a Tile layer..." << std::endl; + } + + else + { + //round the chunk size to the nearest tile + const auto tileSize = map.getTileSize(); + m_chunkSize.x = std::floor(m_chunkSize.x / tileSize.x) * tileSize.x; + m_chunkSize.y = std::floor(m_chunkSize.y / tileSize.y) * tileSize.y; + m_mapTileSize.x = map.getTileSize().x; + m_mapTileSize.y = map.getTileSize().y; + const auto& layer = layers[idx]->getLayerAs(); + createChunks(map, layer); + + auto mapSize = map.getBounds(); + m_globalBounds.width = mapSize.width; + m_globalBounds.height = mapSize.height; + } + } + + ~MapLayer() = default; + MapLayer(const MapLayer&) = delete; + MapLayer& operator = (const MapLayer&) = delete; + + const sf::FloatRect& getGlobalBounds() const { return m_globalBounds; } + + void setTile(std::int32_t tileX, std::int32_t tileY, tmx::TileLayer::Tile tile, bool refresh = true) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + selectedChunk->setTile(chunkLocale.x, chunkLocale.y, tile, refresh); + } + + tmx::TileLayer::Tile getTile(std::int32_t tileX, std::int32_t tileY) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + return selectedChunk->getTile(chunkLocale.x, chunkLocale.y); + } + void setColor(std::int32_t tileX, std::int32_t tileY, sf::Color color, bool refresh = true) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + selectedChunk->setColor(chunkLocale.x, chunkLocale.y, color, refresh); + } + + sf::Color getColor(std::int32_t tileX, std::int32_t tileY) + { + sf::Vector2u chunkLocale; + const auto& selectedChunk = getChunkAndTransform(tileX, tileY, chunkLocale); + return selectedChunk->getColor(chunkLocale.x, chunkLocale.y); + } + + void setOffset(sf::Vector2f offset) { m_offset = offset; } + sf::Vector2f getOffset() const { return m_offset; } + + void update(sf::Time elapsed) + { + for (auto& c : m_visibleChunks) + { + for (AnimationState& as : c->getActiveAnimations()) + { + as.currentTime += elapsed; + + tmx::TileLayer::Tile tile; + std::int32_t animTime = 0; + auto x = as.animTile.animation.frames.begin(); + while (animTime < as.currentTime.asMilliseconds()) + { + if (x == as.animTile.animation.frames.end()) + { + x = as.animTile.animation.frames.begin(); + as.currentTime -= sf::milliseconds(animTime); + animTime = 0; + } + + tile.ID = x->tileID; + animTime += x->duration; + x++; + } + + setTile(as.tileCords.x, as.tileCords.y, tile); + } + } + } + +private: + //increasing m_chunkSize by 4; fixes render problems when mapsize != chunksize + //sf::Vector2f m_chunkSize = sf::Vector2f(1024.f, 1024.f); + sf::Vector2f m_chunkSize = sf::Vector2f(512.f, 512.f); + sf::Vector2u m_chunkCount; + sf::Vector2u m_mapTileSize; // general Tilesize of Map + sf::FloatRect m_globalBounds; + sf::Vector2f m_offset; + + using TextureResource = std::map>; + TextureResource m_textureResource; + + struct AnimationState + { + sf::Vector2u tileCords; + sf::Time startTime; + sf::Time currentTime; + tmx::Tileset::Tile animTile; + std::uint8_t flipFlags; + }; + + class Chunk final : public sf::Transformable, public sf::Drawable + { + public: + using Ptr = std::unique_ptr; + using Tile = std::array; + + Chunk(const tmx::TileLayer& layer, std::vector tilesets, + const sf::Vector2f& position, const sf::Vector2f& tileCount, + const sf::Vector2u& tileSize, std::size_t rowSize, + TextureResource& tr, const std::map& animTiles) + : m_animTiles(animTiles) + { + setPosition(position); + layerOpacity = static_cast(layer.getOpacity() / 1.f * 255.f); + + sf::Color vertColour = sf::Color(200 ,200, 200, layerOpacity); + auto offset = layer.getOffset(); + layerOffset = { static_cast(offset.x), static_cast(offset.y) }; + chunkTileCount = { tileCount.x, tileCount.y }; + mapTileSize = tileSize; + + const auto& tileIDs = layer.getTiles(); + + //go through the tiles and create all arrays (for latter manipulation) + for (const auto& ts : tilesets) + { + if(ts->getImagePath().empty()) + { + tmx::Logger::log("This example does not support Collection of Images tilesets", tmx::Logger::Type::Info); + tmx::Logger::log("Chunks using " + ts->getName() + " will not be created", tmx::Logger::Type::Info); + continue; + } + m_chunkArrays.emplace_back(std::make_unique(*tr.find(ts->getImagePath())->second, *ts)); + } + std::size_t xPos = static_cast(position.x / tileSize.x); + std::size_t yPos = static_cast(position.y / tileSize.y); + for (auto y = yPos; y < yPos + tileCount.y; ++y) + { + for (auto x = xPos; x < xPos + tileCount.x; ++x) + { + auto idx = (y * rowSize + x); + m_chunkTileIDs.emplace_back(tileIDs[idx]); + m_chunkColors.emplace_back(vertColour); + } + } + generateTiles(true); + } + + void generateTiles(bool registerAnimation = false) + { + if (registerAnimation) + { + m_activeAnimations.clear(); + } + for (const auto& ca : m_chunkArrays) + { + std::uint32_t idx = 0; + std::uint32_t xPos = static_cast(getPosition().x / mapTileSize.x); + std::uint32_t yPos = static_cast(getPosition().y / mapTileSize.y); + for (auto y = yPos; y < yPos + chunkTileCount.y; ++y) + { + for (auto x = xPos; x < xPos + chunkTileCount.x; ++x) + { + if (idx < m_chunkTileIDs.size() && m_chunkTileIDs[idx].ID >= ca->m_firstGID + && m_chunkTileIDs[idx].ID <= ca->m_lastGID) + { + if (registerAnimation && m_animTiles.find(m_chunkTileIDs[idx].ID) != m_animTiles.end()) + { + AnimationState as; + as.animTile = m_animTiles[m_chunkTileIDs[idx].ID]; + as.startTime = sf::milliseconds(0); + as.tileCords = sf::Vector2u(x,y); + m_activeAnimations.push_back(as); + } + + sf::Vector2f tileOffset(static_cast(x) * mapTileSize.x, static_cast(y) * mapTileSize.y + mapTileSize.y - ca->tileSetSize.y); + + auto idIndex = m_chunkTileIDs[idx].ID - ca->m_firstGID; + sf::Vector2f tileIndex(sf::Vector2i(idIndex % ca->tsTileCount.x, idIndex / ca->tsTileCount.x)); + tileIndex.x *= ca->tileSetSize.x; + tileIndex.y *= ca->tileSetSize.y; + Tile tile = + { + sf::Vertex(tileOffset - getPosition(), m_chunkColors[idx], tileIndex), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(static_cast(ca->tileSetSize.x), 0.f), m_chunkColors[idx], tileIndex + sf::Vector2f(static_cast(ca->tileSetSize.x), 0.f)), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y))), + sf::Vertex(tileOffset - getPosition(), m_chunkColors[idx], tileIndex), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(sf::Vector2u(ca->tileSetSize.x, ca->tileSetSize.y))), + sf::Vertex(tileOffset - getPosition() + sf::Vector2f(0.f,static_cast(ca->tileSetSize.y)), m_chunkColors[idx], tileIndex + sf::Vector2f(0.f, static_cast(ca->tileSetSize.y))) + }; + doFlips(m_chunkTileIDs[idx].flipFlags,&tile[0].texCoords,&tile[1].texCoords,&tile[2].texCoords,&tile[3].texCoords,&tile[4].texCoords,&tile[5].texCoords); + ca->addTile(tile); + } + idx++; + } + } + } + } + ~Chunk() = default; + Chunk(const Chunk&) = delete; + Chunk& operator = (const Chunk&) = delete; + + std::vector& getActiveAnimations() + { + return m_activeAnimations; + } + + tmx::TileLayer::Tile getTile(std::int32_t x, std::int32_t y) const + { + return m_chunkTileIDs[calcIndexFrom(x,y)]; + } + + void setTile(std::int32_t x, std::int32_t y, tmx::TileLayer::Tile tile, bool refresh) + { + m_chunkTileIDs[calcIndexFrom(x,y)] = tile; + maybeRegenerate(refresh); + } + + sf::Color getColor(std::int32_t x, std::int32_t y) const + { + return m_chunkColors[calcIndexFrom(x,y)]; + } + + void setColor(std::int32_t x, std::int32_t y, sf::Color color, bool refresh) + { + m_chunkColors[calcIndexFrom(x,y)] = color; + maybeRegenerate(refresh); + } + + void maybeRegenerate(bool refresh) + { + if (refresh) + { + for (const auto& ca : m_chunkArrays) + { + ca->reset(); + } + generateTiles(); + } + } + + std::int32_t calcIndexFrom(std::int32_t x, std::int32_t y) const + { + return x + y * static_cast(chunkTileCount.x); + } + + bool empty() const + { + return m_chunkArrays.empty(); + } + + void flipY(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //Flip Y + sf::Vector2f tmp0 = *v0; + v0->y = v5->y; + v3->y = v5->y; + v5->y = tmp0.y; + sf::Vector2f tmp2 = *v2; + v2->y = v1->y; + v4->y = v1->y; + v1->y = tmp2.y; + } + + void flipX(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //Flip X + sf::Vector2f tmp0 = *v0; + v0->x = v1->x; + v3->x = v1->x; + v1->x = tmp0.x; + sf::Vector2f tmp2 = *v2; + v2->x = v5->x; + v4->x = v5->x; + v5->x = tmp2.x; + } + + void flipD(sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //Diagonal flip + sf::Vector2f tmp2 = *v2; + *v2 = *v4; + *v4 = tmp2; + sf::Vector2f tmp0 = *v0; + *v0 = *v3; + *v3 = tmp0; + sf::Vector2f tmp1 = *v1; + *v1 = *v5; + *v5 = tmp1; + } + + void doFlips(std::uint8_t bits, sf::Vector2f* v0, sf::Vector2f* v1, sf::Vector2f* v2, sf::Vector2f* v3, sf::Vector2f* v4, sf::Vector2f* v5) + { + //0000 = no change + //0100 = vertical = swap y axis + //1000 = horizontal = swap x axis + //1100 = horiz + vert = swap both axes = horiz+vert = rotate 180 degrees + //0010 = diag = rotate 90 degrees right and swap x axis + //0110 = diag+vert = rotate 270 degrees right + //1010 = horiz+diag = rotate 90 degrees right + //1110 = horiz+vert+diag = rotate 90 degrees right and swap y axis + if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //Shortcircuit tests for nothing to do + return; + } + else if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //0100 + flipY(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1000 + flipX(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + !(bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1100 + flipY(v0,v1,v2,v3,v4,v5); + flipX(v0,v1,v2,v3,v4,v5); + } + else if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //0010 + flipD(v0,v1,v2,v3,v4,v5); + } + else if(!(bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //0110 + flipX(v0,v1,v2,v3,v4,v5); + flipD(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + !(bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1010 + flipY(v0,v1,v2,v3,v4,v5); + flipD(v0,v1,v2,v3,v4,v5); + } + else if((bits & tmx::TileLayer::FlipFlag::Horizontal) && + (bits & tmx::TileLayer::FlipFlag::Vertical) && + (bits & tmx::TileLayer::FlipFlag::Diagonal) ) + { + //1110 + flipY(v0,v1,v2,v3,v4,v5); + flipX(v0,v1,v2,v3,v4,v5); + flipD(v0,v1,v2,v3,v4,v5); + } + } + + private: + class ChunkArray final : public sf::Drawable + { + public: + using Ptr = std::unique_ptr; + + tmx::Vector2u tileSetSize; + sf::Vector2u tsTileCount; + std::uint32_t m_firstGID, m_lastGID; + + explicit ChunkArray(const sf::Texture& t, const tmx::Tileset& ts) + : m_texture(t) + { + auto texSize = getTextureSize(); + tileSetSize = ts.getTileSize(); + tsTileCount.x = texSize.x / tileSetSize.x; + tsTileCount.y = texSize.y / tileSetSize.y; + m_firstGID = ts.getFirstGID(); + m_lastGID = ts.getLastGID(); + } + + ~ChunkArray() = default; + ChunkArray(const ChunkArray&) = delete; + ChunkArray& operator = (const ChunkArray&) = delete; + + void reset() + { + m_vertices.clear(); + } + + void addTile(const Chunk::Tile& tile) + { + for (const auto& v : tile) + { + m_vertices.push_back(v); + } + } + + sf::Vector2u getTextureSize() const + { + return m_texture.getSize(); + } + + private: + const sf::Texture& m_texture; + std::vector m_vertices; + void draw(sf::RenderTarget& rt, sf::RenderStates states) const override + { + states.texture = &m_texture; + rt.draw(m_vertices.data(), m_vertices.size(), sf::Triangles, states); + } + }; + + sf::Uint8 layerOpacity; // opacity of the layer + sf::Vector2f layerOffset; // Layer offset + sf::Vector2u mapTileSize; // general Tilesize of Map + sf::Vector2f chunkTileCount; // chunk tilecount + std::vector m_chunkTileIDs; // stores all tiles in this chunk for later manipulation + std::vector m_chunkColors; // stores colors for extended color effects + std::map m_animTiles; // animation catalogue + std::vector m_activeAnimations; // Animations to be done in this chunk + std::vector m_chunkArrays; + + void draw(sf::RenderTarget& rt, sf::RenderStates states) const override + { + states.transform *= getTransform(); + for (const auto& a : m_chunkArrays) + { + rt.draw(*a, states); + } + } + }; + + std::vector m_chunks; + mutable std::vector m_visibleChunks; + + Chunk::Ptr& getChunkAndTransform(std::int32_t x, std::int32_t y, sf::Vector2u& chunkRelative) + { + std::uint32_t chunkX = (x * m_mapTileSize.x) / static_cast(m_chunkSize.x); + std::uint32_t chunkY = (y * m_mapTileSize.y) / static_cast(m_chunkSize.y); + chunkRelative.x = ((x * m_mapTileSize.x) - chunkX * static_cast(m_chunkSize.x)) / m_mapTileSize.x ; + chunkRelative.y = ((y * m_mapTileSize.y) - chunkY * static_cast(m_chunkSize.y)) / m_mapTileSize.y ; + return m_chunks[chunkX + chunkY * m_chunkCount.x]; + } + + void createChunks(const tmx::Map& map, const tmx::TileLayer& layer) + { + //look up all the tile sets and load the textures + const auto& tileSets = map.getTilesets(); + const auto& layerIDs = layer.getTiles(); + std::uint32_t maxID = std::numeric_limits::max(); + std::vector usedTileSets; + + for (auto i = tileSets.rbegin(); i != tileSets.rend(); ++i) + { + for (const auto& tile : layerIDs) + { + if (tile.ID >= i->getFirstGID() && tile.ID < maxID) + { + usedTileSets.push_back(&(*i)); + break; + } + } + maxID = i->getFirstGID(); + } + + sf::Image fallback; + fallback.create(2, 2, sf::Color::Magenta); + for (const auto& ts : usedTileSets) + { + const auto& path = ts->getImagePath(); + + std::unique_ptr newTexture = std::make_unique(); + sf::Image img; + if (!img.loadFromFile(path)) + { + newTexture->loadFromImage(fallback); + } + else + { + if (ts->hasTransparency()) + { + auto transparency = ts->getTransparencyColour(); + img.createMaskFromColor({ transparency.r, transparency.g, transparency.b, transparency.a }); + } + newTexture->loadFromImage(img); + } + m_textureResource.insert(std::make_pair(path, std::move(newTexture))); + } + + //calculate the number of chunks in the layer + //and create each one + const auto bounds = map.getBounds(); + m_chunkCount.x = static_cast(std::ceil(bounds.width / m_chunkSize.x)); + m_chunkCount.y = static_cast(std::ceil(bounds.height / m_chunkSize.y)); + + sf::Vector2u tileSize(map.getTileSize().x, map.getTileSize().y); + + for (auto y = 0u; y < m_chunkCount.y; ++y) + { + sf::Vector2f tileCount(m_chunkSize.x / tileSize.x, m_chunkSize.y / tileSize.y); + for (auto x = 0u; x < m_chunkCount.x; ++x) + { + // calculate size of each Chunk (clip against map) + if ((x + 1) * m_chunkSize.x > bounds.width) + { + tileCount.x = (bounds.width - x * m_chunkSize.x) / map.getTileSize().x; + } + if ((y + 1) * m_chunkSize.y > bounds.height) + { + tileCount.y = (bounds.height - y * m_chunkSize.y) / map.getTileSize().y; + } + //m_chunks.emplace_back(std::make_unique(layer, usedTileSets, + // sf::Vector2f(x * m_chunkSize.x, y * m_chunkSize.y), tileCount, map.getTileCount().x, m_textureResource)); + m_chunks.emplace_back(std::make_unique(layer, usedTileSets, + sf::Vector2f(x * m_chunkSize.x, y * m_chunkSize.y), tileCount, tileSize, map.getTileCount().x, m_textureResource, map.getAnimatedTiles())); + } + } + } + + void updateVisibility(const sf::View& view) const + { + sf::Vector2f viewCorner = view.getCenter(); + viewCorner -= view.getSize() / 2.f; + + std::int32_t posX = static_cast(std::floor(viewCorner.x / m_chunkSize.x)); + std::int32_t posY = static_cast(std::floor(viewCorner.y / m_chunkSize.y)); + std::int32_t posX2 = static_cast(std::ceil((viewCorner.x + view.getSize().x) / m_chunkSize.x)); + std::int32_t posY2 = static_cast(std::ceil((viewCorner.y + view.getSize().x)/ m_chunkSize.y)); + + std::vector visible; + for (auto y = posY; y < posY2; ++y) + { + for (auto x = posX; x < posX2; ++x) + { + std::size_t idx = y * std::int32_t(m_chunkCount.x) + x; + if (idx >= 0u && idx < m_chunks.size() && !m_chunks[idx]->empty()) + { + visible.push_back(m_chunks[idx].get()); + } + } + } + + std::swap(m_visibleChunks, visible); + } + + + void draw(sf::RenderTarget& rt, sf::RenderStates states) const override + { + states.transform.translate(m_offset); + + //calc view coverage and draw nearest chunks + updateVisibility(rt.getView()); + for (const auto& c : m_visibleChunks) + { + rt.draw(*c, states); + } + } +}; + +#endif //SFML_ORTHO_HPP_ diff --git a/SFML3Example/src/main.cpp b/SFML3Example/src/main.cpp new file mode 100644 index 0000000..2c66d18 --- /dev/null +++ b/SFML3Example/src/main.cpp @@ -0,0 +1,95 @@ +/********************************************************************* +(c) Matt Marchant & contributors 2016 - 2024 +http://trederia.blogspot.com + +tmxlite - Zlib license. + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute +it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; +you must not claim that you wrote the original software. +If you use this software in a product, an acknowledgment +in the product documentation would be appreciated but +is not required. + +2. Altered source versions must be plainly marked as such, +and must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any +source distribution. +*********************************************************************/ + + +#include "SFMLOrthogonalLayer.hpp" + +#include +#include +#include + + +int main() +{ + sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window"); + + tmx::Map map; + map.load("assets/demo.tmx"); + + MapLayer layerZero(map, 0); + MapLayer layerOne(map, 1); + MapLayer layerTwo(map, 2); + + sf::Clock globalClock; + sf::Clock wiggleClock; + + bool doWiggle = false; + + while (window.isOpen()) + { + sf::Event event; + while (window.pollEvent(event)) + { + if (event.type == sf::Event::Closed) + { + window.close(); + } + + else if( event.type == sf::Event::KeyPressed ) + { + switch(event.key.code) + { + case sf::Keyboard::W: + // toggle doWiggle + doWiggle = !doWiggle; + break; + } + } + } + + + sf::Time duration = globalClock.restart(); + layerZero.update(duration); + + sf::Vector2f newOffset = sf::Vector2f(0.f, 0.f); + if (doWiggle) + { + newOffset = sf::Vector2f(std::cos(wiggleClock.getElapsedTime().asSeconds()) * 100.f, 0.f); + } + layerZero.setOffset(newOffset); + layerOne.setOffset(newOffset); + layerTwo.setOffset(newOffset); + + window.clear(sf::Color::Black); + window.draw(layerZero); + window.draw(layerOne); + window.draw(layerTwo); + window.display(); + } + + return 0; +}