diff --git a/.appveyor.yml b/.appveyor.yml index d8ad518..b3234c5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -os: Visual Studio 2015 +os: Visual Studio 2017 build: verbosity: detailed @@ -24,23 +24,29 @@ platform: - x64 install: - - set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip" + - set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-win.zip" - set SFML_URL="https://www.sfml-dev.org/files/SFML-2.4.2-windows-vc14-64-bit.zip" + - set DEPS_DIR=C:\projects\deps - - if not exist C:\projects\deps ( - mkdir C:\projects\deps && - cd C:\projects\deps && + - if not exist %DEPS_DIR% ( + mkdir %DEPS_DIR% && + cd %DEPS_DIR% && appveyor DownloadFile %NINJA_URL% -FileName ninja.zip && appveyor DownloadFile %SFML_URL% -FileName sfml.zip && - 7z x ninja.zip -oC:\projects\deps\ninja > nul && - 7z x sfml.zip -oC:\projects\deps\sfml > nul) - - - set PATH=C:\projects\deps\ninja;%PATH% - - set PATH=C:\projects\deps\sfml\SFML-2.4.2\bin;%PATH% - - set PATH="C:\Program Files\LLVM\bin";%PATH% - - set INCLUDE=%INCLUDE%;C:\Libraries\boost_1_63_0 - - set LIB=%LIB%;C:\Libraries\boost_1_63_0 - + 7z x ninja.zip -o%DEPS_DIR%\ninja > nul && + 7z x sfml.zip -o%DEPS_DIR%\sfml > nul) + + - set BOOST_LIB=C:\Libraries\boost_1_65_1 + - set SFML_DIR=%DEPS_DIR%\sfml\SFML-2.4.2 + - set SFML_LIB=%SFML_DIR%\lib + - set SFML_BIN=%SFML_DIR%\bin + - set NINJA_BIN=%DEPS_DIR%\ninja + + - set PATH=%NINJA_BIN%;%PATH% + - set PATH=%SFML_BIN%;%PATH% + - set INCLUDE=%INCLUDE%;%BOOST_LIB% + - set LIB=%LIB%;%BOOST_LIB%;%SFML_LIB% + - ninja --version - clang-cl -v @@ -62,5 +68,3 @@ build_script: test_script: - ps: | & ctest -V -j nproc - - diff --git a/.gitignore b/.gitignore index f0f3480..c81989b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ CMakeScripts cmake_install.cmake install_manifest.txt CTestTestfile.cmake + +TAGS + # Compiled Object files *.slo *.lo diff --git a/.travis.yml b/.travis.yml index 2014a74..b87ee43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,9 @@ matrix: # Build steps script: - mkdir boost-dl; cd boost-dl - - wget https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.bz2 - - tar --bzip2 -xf ./boost_1_62_0.tar.bz2 - - sudo mv ./boost_1_62_0/boost /usr/include + - wget https://dl.bintray.com/boostorg/release/1.65.1/source/boost_1_65_1.tar.bz2 + - tar --bzip2 -xf ./boost_1_65_1.tar.bz2 + - sudo mv ./boost_1_65_1/boost /usr/include - cd .. - mkdir build - cd build @@ -40,4 +40,6 @@ script: - echo "We have" `nproc` "cores here" - make -j `nproc` - ctest -j `nproc` -V + +after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/CMakeLists.txt b/CMakeLists.txt index 17cdbea..3814aad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,44 +1,40 @@ -cmake_minimum_required (VERSION 2.8.11) -project("bomberman") +cmake_minimum_required (VERSION 3.2.2) +project("bomberman" CXX) + +set(CMAKE_CXX_EXTENSIONS OFF) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules" ${CMAKE_MODULE_PATH}) set(EXTERNAL_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external") +set(GLM_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/glm/") +set(RANGEV3_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/range-v3/include/") +set(FAKEIT_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/fakeit/single_header/gtest/") +set(GSL_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/GSL/include") +set(GMOCK_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/googletest/googlemock/include") +set(GTEST_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/googletest/googletest/include") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGSL_THROW_ON_CONTRACT_VIOLATION") + +enable_testing() + +add_subdirectory(external/googletest/) + +if(${WIN32}) + include(${CMAKE_SOURCE_DIR}/cmake/platforms/Windows.cmake) +else() + include(${CMAKE_SOURCE_DIR}/cmake/platforms/Linux.cmake) +endif() -find_package(SFML 2 COMPONENTS system window graphics network audio) - -if(SFML_FOUND) - enable_testing() - - set(GLM_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/glm/") - set(RANGEV3_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/range-v3/include/") - set(FAKEIT_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/fakeit/single_header/gtest/") - set(GSL_INCLUDE_DIR "${EXTERNAL_INCLUDE_DIR}/GSL/include") - set(GMOCK_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/googletest/googlemock/include") - set(GTEST_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/googletest/googletest/include") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGSL_THROW_ON_CONTRACT_VIOLATION") - - add_subdirectory(external/googletest) - - if(${WIN32}) - include(${CMAKE_SOURCE_DIR}/cmake/platforms/Windows.cmake) - else() - include(${CMAKE_SOURCE_DIR}/cmake/platforms/Linux.cmake) - endif() - - if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") - include(${CMAKE_SOURCE_DIR}/cmake/compilators/Clang.cmake) - elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") - include(${CMAKE_SOURCE_DIR}/cmake/compilators/Msvc.cmake) - else() - include(${CMAKE_SOURCE_DIR}/cmake/compilators/Gcc.cmake) - endif() - - include_directories(SYSTEM ${RANGEV3_INCLUDE_DIR}) - include_directories(SYSTEM ${SFML_INCLUDE_DIR}) - include_directories(SYSTEM ${GSL_INCLUDE_DIR}) - include_directories(SYSTEM ${GLM_INCLUDE_DIR}) - - add_subdirectory(src) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + include(${CMAKE_SOURCE_DIR}/cmake/compilators/Clang.cmake) +elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") + include(${CMAKE_SOURCE_DIR}/cmake/compilators/Msvc.cmake) +else() + include(${CMAKE_SOURCE_DIR}/cmake/compilators/Gcc.cmake) endif() + +include_directories(SYSTEM ${RANGEV3_INCLUDE_DIR}) +include_directories(SYSTEM ${GSL_INCLUDE_DIR}) +include_directories(SYSTEM ${GLM_INCLUDE_DIR}) + +add_subdirectory(src) diff --git a/README.md b/README.md index 5be2f4c..2ec9574 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,2 @@ # bomberman -Repo for bomberman - [![Build Status](https://travis-ci.org/NadzwyczajnaGrupaRobocza/bomberman.svg?branch=master)](https://travis-ci.org/NadzwyczajnaGrupaRobocza/bomberman)[![Build status](https://ci.appveyor.com/api/projects/status/60vqqan3qtj4eu35/branch/master?svg=true)](https://ci.appveyor.com/project/Abergard/bomberman/branch/master)[![codecov](https://codecov.io/gh/NadzwyczajnaGrupaRobocza/bomberman/branch/master/graph/badge.svg)](https://codecov.io/gh/NadzwyczajnaGrupaRobocza/bomberman) diff --git a/cmake/platforms/Linux.cmake b/cmake/platforms/Linux.cmake index fa06dfc..cf5ed29 100644 --- a/cmake/platforms/Linux.cmake +++ b/cmake/platforms/Linux.cmake @@ -1,9 +1,10 @@ -message(STATUS "Detected GNU CXX compiler.") +message(STATUS "Detected Linux kind system.") option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" FALSE) if(${ENABLE_COVERAGE}) add_compile_options(--coverage -O0) + link_libraries(--coverage) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") diff --git a/docs/04-ClassDiagram.md b/docs/04-ClassDiagram.md index cd3898a..f0575b3 100644 --- a/docs/04-ClassDiagram.md +++ b/docs/04-ClassDiagram.md @@ -1,4 +1,7 @@ # Class diagram +## All ![ClassDiagramImage](./img/class_diagram.png) +## Graphics +![GraphicsClassDiagramImage](./img/class_diagram_graphics.png) diff --git a/docs/img/Activity_2_1_BombLauncher.png b/docs/img/Activity_2_1_BombLauncher.png index 7ff76d4..ac433ec 100644 Binary files a/docs/img/Activity_2_1_BombLauncher.png and b/docs/img/Activity_2_1_BombLauncher.png differ diff --git a/docs/img/Activity_2_2_Bomb.png b/docs/img/Activity_2_2_Bomb.png index c52a5cc..f2e410b 100644 Binary files a/docs/img/Activity_2_2_Bomb.png and b/docs/img/Activity_2_2_Bomb.png differ diff --git a/docs/img/Activity_2_2_BombLauncher.png b/docs/img/Activity_2_2_BombLauncher.png index cc1ff3e..6a13822 100644 Binary files a/docs/img/Activity_2_2_BombLauncher.png and b/docs/img/Activity_2_2_BombLauncher.png differ diff --git a/docs/img/Activity_2_2_Explosion.png b/docs/img/Activity_2_2_Explosion.png index 1a17e66..1e36cc5 100644 Binary files a/docs/img/Activity_2_2_Explosion.png and b/docs/img/Activity_2_2_Explosion.png differ diff --git a/docs/img/Activity_3_2_PhysicsEngine.png b/docs/img/Activity_3_2_PhysicsEngine.png index 29fd9ac..583a3ee 100644 Binary files a/docs/img/Activity_3_2_PhysicsEngine.png and b/docs/img/Activity_3_2_PhysicsEngine.png differ diff --git a/docs/img/Communication_UC_1_1.png b/docs/img/Communication_UC_1_1.png index 110e9f3..7b10ffb 100644 Binary files a/docs/img/Communication_UC_1_1.png and b/docs/img/Communication_UC_1_1.png differ diff --git a/docs/img/Communication_UC_1_2.png b/docs/img/Communication_UC_1_2.png index 42363f0..caa4b46 100644 Binary files a/docs/img/Communication_UC_1_2.png and b/docs/img/Communication_UC_1_2.png differ diff --git a/docs/img/Communication_UC_2_1.png b/docs/img/Communication_UC_2_1.png index a511e99..6e2c0b7 100644 Binary files a/docs/img/Communication_UC_2_1.png and b/docs/img/Communication_UC_2_1.png differ diff --git a/docs/img/Communication_UC_2_2.png b/docs/img/Communication_UC_2_2.png index 6b60fd7..02af7f4 100644 Binary files a/docs/img/Communication_UC_2_2.png and b/docs/img/Communication_UC_2_2.png differ diff --git a/docs/img/Communication_UC_2_3.png b/docs/img/Communication_UC_2_3.png index d7a04df..41a76d8 100644 Binary files a/docs/img/Communication_UC_2_3.png and b/docs/img/Communication_UC_2_3.png differ diff --git a/docs/img/UC_1_2.png b/docs/img/UC_1_2.png index 7d3b550..44f22c4 100644 Binary files a/docs/img/UC_1_2.png and b/docs/img/UC_1_2.png differ diff --git a/docs/img/UC_1_3.png b/docs/img/UC_1_3.png index 5a6cae9..1bfc3d9 100644 Binary files a/docs/img/UC_1_3.png and b/docs/img/UC_1_3.png differ diff --git a/docs/img/UC_1_4.png b/docs/img/UC_1_4.png index 56c7a45..a70658f 100644 Binary files a/docs/img/UC_1_4.png and b/docs/img/UC_1_4.png differ diff --git a/docs/img/UC_2_1.png b/docs/img/UC_2_1.png index 80a404d..b9d76da 100644 Binary files a/docs/img/UC_2_1.png and b/docs/img/UC_2_1.png differ diff --git a/docs/img/UC_2_2.png b/docs/img/UC_2_2.png index 9ab7655..708f23f 100644 Binary files a/docs/img/UC_2_2.png and b/docs/img/UC_2_2.png differ diff --git a/docs/img/UC_2_3.png b/docs/img/UC_2_3.png index 95d4b1e..b38e2da 100644 Binary files a/docs/img/UC_2_3.png and b/docs/img/UC_2_3.png differ diff --git a/docs/img/class_diagram.png b/docs/img/class_diagram.png index 0e7e9ec..a716bf5 100644 Binary files a/docs/img/class_diagram.png and b/docs/img/class_diagram.png differ diff --git a/docs/img/class_diagram_graphics.png b/docs/img/class_diagram_graphics.png new file mode 100644 index 0000000..209b891 Binary files /dev/null and b/docs/img/class_diagram_graphics.png differ diff --git a/docs/img/domain_model.png b/docs/img/domain_model.png index 3c0fa51..8c49702 100644 Binary files a/docs/img/domain_model.png and b/docs/img/domain_model.png differ diff --git a/docs/img/graphical_layer_domain_model.png b/docs/img/graphical_layer_domain_model.png index 32f10ee..eb964d1 100644 Binary files a/docs/img/graphical_layer_domain_model.png and b/docs/img/graphical_layer_domain_model.png differ diff --git a/docs/img/main_state_changes.png b/docs/img/main_state_changes.png index 536a697..f92ebfa 100644 Binary files a/docs/img/main_state_changes.png and b/docs/img/main_state_changes.png differ diff --git a/docs/img/move_update_loop.png b/docs/img/move_update_loop.png index 39b6dce..47705bb 100644 Binary files a/docs/img/move_update_loop.png and b/docs/img/move_update_loop.png differ diff --git a/docs/img/player_seq.png b/docs/img/player_seq.png index 5e4e902..068a396 100644 Binary files a/docs/img/player_seq.png and b/docs/img/player_seq.png differ diff --git a/docs/uml_src/class_diagram.uml b/docs/uml_src/class_diagram.uml index c6dc500..fd7478f 100644 --- a/docs/uml_src/class_diagram.uml +++ b/docs/uml_src/class_diagram.uml @@ -1,5 +1,21 @@ @startuml +namespace graphics{ + interface RendererPool{ + + RendererId acquire(const math::Size2f&, const math::Position2f&) + + void release(const RendererId&) + + void render_all() + + void set_position(const RendererId&, const math::Position2f&) + + Position get_position(const RendererId&) + } + interface Window{ + + bool is_open() + + void display() + + void update() + } + class RendererId +} + interface Entity { + update(delta_time) + bool areYouDead() @@ -8,23 +24,26 @@ interface Entity { class Bomberman { - phys_id : PhysId - physics_engine : PhysicsEngine& -- render_id : RenderId -- render_engine : RenderEngine& +- renderer_id : graphics::RendererId +- renderer_pool : graphics::RendererPool& - human_player : HumanPlayer - bomb_launcher : BombLauncher } +Bomberman o-- graphics.RendererPool +Bomberman *-- graphics.RendererId class GameWorld { - bomberman : Entity - map : Map - physics_engine : std::unique_ptr -- render_engine : std::unique_ptr +- renderer_pool : std::unique_ptr - bombs : std::vector - explosions : std::vector + bool is_bomb_at_pos(Vector2D position) + create_bomb(Vector2D position, int timeToExplode) + create_explosion(Vector2D povesition) } +GameWorld o-down- graphics.RendererPool class HumanPlayer { + Vector2D get_direction() @@ -40,12 +59,14 @@ class BombLauncher { } class Map { -- background : RenderId +- background : graphics::RendererId - static_element : std::vector -- render_engine : RenderEngine& +- renderer_pool : graphics::RendererPool& - physics_engine : PhysicsEngine& + ExplosionRange : get_explosion_range(const std::pair, int) } +Map o-- graphics.RendererPool +Map *-- graphics.RendererId class PhysicsEngine{ + void set_position(PhysId id, Vector2D position) @@ -54,25 +75,23 @@ class PhysicsEngine{ + PhysicId register_colider(const math::vec2d&, const math::vec2d&) } -class RenderEngine{ -+ void set_position(RenderId id, Vector2D position) -+ void render() -+ RenderId register_rendarable(const math::vec2d&, const math:::vec2d&) -} - class Bomb { - phys_id : PhysId -- render_id : RenderId -- render_engine : RenderEngine& +- renderer_id : graphics::RendererId - physics_engine : PhysicsEngine& +- renderer_pool : RendererPool& } +Bomb o-- graphics.RendererPool +Bomb *-- graphics.RendererId class Explosion { +- renderer_ids : std::vector - phys_ids : std::vector -- render_ids : std::vector -- render_engine : RenderEngine& - physics_engine : PhysicsEngine& +- renderer_pool : graphics::RendererPool& } +Explosion o-- graphics.RendererPool +Explosion *-- graphics.RendererId Bomberman --|> Entity Bomb --|> Entity @@ -87,10 +106,8 @@ HumanPlayer --* Bomberman BombLauncher --> GameWorld BombLauncher --* Bomberman - Map --* GameWorld -RenderEngine --* GameWorld PhysicsEngine --* GameWorld @enduml diff --git a/docs/uml_src/class_diagram_graphics.uml b/docs/uml_src/class_diagram_graphics.uml new file mode 100644 index 0000000..6e38b3b --- /dev/null +++ b/docs/uml_src/class_diagram_graphics.uml @@ -0,0 +1,86 @@ +@startuml + +namespace sf{ + class RectangleShape + class Window + abstract class RenderTarget +} + +namespace graphics { +package public <> { + + interface RendererPool{ + + RendererId acquire(const math::Size2f&, const math::Position2f&) + + void release(const RendererId&) + + void render_all() + + void set_position(const RendererId&, const math::Position2f&) + + Position get_position(const RendererId&) + } + interface Window{ + + bool is_open() + + void display() + + void update() + } + class RendererId + } + package private <> { + + package types{ + math.Position2f <|-- Position2f + math.Size2f <|-- Size2f + math.Size2u <|-- WindowSize + } + + package sfml_adaptors <> { + + interface SfmlWindow{ + + bool is_open() + + void display() + + bool poll_event(sf::Event&) + + void close() + + void create(sf::VideoMode, const sf::String& title) + } + + class SfmlWindowFacade + SfmlWindowFacade --|> SfmlWindow + SfmlWindowFacade *-down- sf.Window + + class SfmlRenderTarget + SfmlRenderTarget -down-|> sf.RenderTarget + + + class SfmlRectangleShape{ + + Position2f getPosition() + + Size2f getSize() + } + SfmlRectangleShape --|> sf.RectangleShape + + } + class WindowSfml + WindowSfml --|> Window + WindowSfml *-- SfmlWindow + + interface ContextRenderer{ + + initialize() + + clear(const sf::Color&) + + draw(const SfmlRectangleShape&) + } + ContextRenderer --> SfmlRectangleShape + ContextRenderer <|-- SfmlRenderTarget + + class RendererPoolSfml{ + } + RendererPoolSfml --|> RendererPool + RendererPoolSfml o-- RendererId + RendererPoolSfml o-- SfmlRectangleShape + RendererPoolSfml *-- RendererIdGenerator + RendererPoolSfml *-- ContextRenderer + + class RendererIdGenerator + RendererIdGenerator --> RendererId + } + + +} + +@enduml diff --git a/external/GSL b/external/GSL index ebab8ca..211e195 160000 --- a/external/GSL +++ b/external/GSL @@ -1 +1 @@ -Subproject commit ebab8cab7f552e0fa2265f940e1dab2fdb6551d2 +Subproject commit 211e195d8f9dd6fa967a5741387fb5eae1ff351b diff --git a/external/glm b/external/glm index 5dcc564..8a8a6c2 160000 --- a/external/glm +++ b/external/glm @@ -1 +1 @@ -Subproject commit 5dcc56489e1b66dfd5bca751fa9b8dc68059e008 +Subproject commit 8a8a6c2b76180a3c65d11467c79270bfcc75bb25 diff --git a/external/range-v3 b/external/range-v3 index d065c64..dd7fd44 160000 --- a/external/range-v3 +++ b/external/range-v3 @@ -1 +1 @@ -Subproject commit d065c649e651e9b0d6eb6d54cd184a1303281fbf +Subproject commit dd7fd449936d1d2f21ea9c52ce765d7ef25cebec diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 326fe07..4d2ee49 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,7 @@ set(UT_INCLUDES ${FAKEIT_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR}) - -add_subdirectory(graphics) set(INTERNAL_LIBS_INCLUDE_PATH ${CMAKE_CURRENT_LIST_DIR}) +add_subdirectory(graphics) add_subdirectory(physics) - +add_subdirectory(math) add_subdirectory(game) diff --git a/src/game/BombPosition.hpp b/src/game/BombPosition.hpp index ea5b874..32c37ff 100644 --- a/src/game/BombPosition.hpp +++ b/src/game/BombPosition.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include "math/Position.hpp" +#include "math/Position2f.hpp" -BOOST_STRONG_TYPEDEF(math::Position2, BombPosition) +BOOST_STRONG_TYPEDEF(math::Position2f, BombPosition) diff --git a/src/game/BombermanGameWorld.hpp b/src/game/BombermanGameWorld.hpp index fc1884e..112cd83 100644 --- a/src/game/BombermanGameWorld.hpp +++ b/src/game/BombermanGameWorld.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include "math/Position.hpp" #include #include "Bomb.hpp" #include diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index cb29f78..cd57eb9 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -1,3 +1,5 @@ +find_package(SFML 2 COMPONENTS graphics REQUIRED) + add_library(game BombermanGameWorld.cpp BoundaryWallsPositionsGenerator.cpp @@ -8,7 +10,15 @@ add_library(game TimeBomb.cpp ) -add_executable(game_test +target_include_directories(game SYSTEM + PRIVATE ${SFML_INCLUDE_DIR}) + +target_link_libraries(game + PUBLIC math + PRIVATE graphics + ) + +add_executable(game-ut BoundaryWallsPositionsGenerator.ut.cpp Entity.ut.cpp LimitedBombLauncher.ut.cpp @@ -17,7 +27,7 @@ add_executable(game_test TimeBomb.ut.cpp ) -target_include_directories(game_test SYSTEM PRIVATE +target_include_directories(game-ut SYSTEM PRIVATE ${UT_INCLUDES} ) @@ -25,7 +35,7 @@ target_include_directories(game PRIVATE ${INTERNAL_LIBS_INCLUDE_PATH} ) -target_include_directories(game_test PRIVATE +target_include_directories(game-ut PRIVATE ${INTERNAL_LIBS_INCLUDE_PATH} ) @@ -33,5 +43,7 @@ target_include_directories(game PRIVATE ${INTERNAL_LIBS_INCLUDE_PATH} ) -target_link_libraries(game_test --coverage gmock gtest_main game) -add_test(game_test ${EXECUTABLE_OUTPUT_PATH}/game_test --gtest_color=yes) +target_link_libraries(game-ut + PRIVATE game graphics gtest_main gmock) + +add_test(game-ut ${EXECUTABLE_OUTPUT_PATH}/game-ut --gtest_color=yes) diff --git a/src/game/ExplosionPosition.hpp b/src/game/ExplosionPosition.hpp index 980e2c5..33a5e9f 100644 --- a/src/game/ExplosionPosition.hpp +++ b/src/game/ExplosionPosition.hpp @@ -1,5 +1,7 @@ #pragma once -#include +#include "math/Position2f.hpp" -BOOST_STRONG_TYPEDEF(math::Position2, ExplosionPosition) +struct ExplosionPosition : math::Position2f +{ +}; diff --git a/src/game/SimpleMap.cpp b/src/game/SimpleMap.cpp index fa85dda..7118a1e 100644 --- a/src/game/SimpleMap.cpp +++ b/src/game/SimpleMap.cpp @@ -4,27 +4,32 @@ SimpleMap::SimpleMap(physics::PhysicsEngine& pEngine, const WallPositionsGenerator& generated_wallss_generator, - graphics::RenderEngine& rEngine) + graphics::RendererPool& rEngine) : physics_engine(pEngine), graphics_engine{rEngine} { for (const auto& generated_walls : generated_wallss_generator.generate_boundary_walls(map_size)) { physics_ids.push_back(physics_engine.register_colider( - {generated_walls.first.first, generated_walls.first.second}, - {generated_walls.second.first, generated_walls.second.second})); - render_ids.push_back(graphics_engine.register_renderable( - {generated_walls.second.first, generated_walls.second.second}, - {generated_walls.first.first, generated_walls.first.second})); + {static_cast(generated_walls.second.first), + static_cast(generated_walls.second.second)}, + {static_cast(generated_walls.first.first), + static_cast(generated_walls.first.second)})); + render_ids.push_back(graphics_engine.acquire( + {static_cast(generated_walls.second.first), + static_cast(generated_walls.second.second)}, + {static_cast(generated_walls.first.first), + static_cast(generated_walls.first.second)})); } - render_ids.push_back( - graphics_engine.register_renderable({map_size, map_size}, {0, 0})); + render_ids.push_back(graphics_engine.acquire( + {static_cast(map_size), static_cast(map_size)}, + {0.0f, 0.0f})); } SimpleMap::~SimpleMap() { boost::for_each(render_ids, - [&](const auto id) { graphics_engine.deregister(id); }); + [&](const auto id) { graphics_engine.release(id); }); boost::for_each(physics_ids, [&](const auto id) { physics_engine.deregister(id); }); } diff --git a/src/game/SimpleMap.hpp b/src/game/SimpleMap.hpp index de8f046..cd3281f 100644 --- a/src/game/SimpleMap.hpp +++ b/src/game/SimpleMap.hpp @@ -7,15 +7,15 @@ #include "glm/glm.hpp" #include "physics/PhysicsEngine.hpp" -#include "graphics/RenderEngine.hpp" -#include "graphics/RenderId.hpp" +#include "graphics/RendererPool.hpp" +#include "graphics/RendererId.hpp" class SimpleMap : public Map { public: SimpleMap(physics::PhysicsEngine& pEngine, const WallPositionsGenerator& wall_positions_generator, - graphics::RenderEngine& rEngine); + graphics::RendererPool& rEngine); ~SimpleMap() override; ExplosionRange get_explosion_range(std::pair start_point, @@ -24,10 +24,10 @@ class SimpleMap : public Map private: physics::PhysicsEngine& physics_engine; std::vector walls; - graphics::RenderEngine& graphics_engine; - const int map_size = 10; + graphics::RendererPool& graphics_engine; + const int map_size{10}; std::vector physics_ids; - std::vector render_ids; + std::vector render_ids; template Distance get_range_in_decreasing_direction(const int start_point, diff --git a/src/game/SimpleMap.ut.cpp b/src/game/SimpleMap.ut.cpp index e5296ae..d47887b 100644 --- a/src/game/SimpleMap.ut.cpp +++ b/src/game/SimpleMap.ut.cpp @@ -1,6 +1,7 @@ #include "gmock/gmock.h" #include "glm/glm.hpp" +#include #include "fakeit.hpp" @@ -14,8 +15,8 @@ class SimpleMapConstructorExpectations : public ::testing::Test SimpleMapConstructorExpectations() { When(Method(physics_engine, register_colider)) - .AlwaysDo([&](const auto& position, const auto& size) { - static unsigned id = 0; + .AlwaysDo([&](const auto& size, const auto& position) { + static uint8_t id = 0; physics_wall_positions.push_back(position); physics_wall_sizes.push_back(size); const auto pid = physics::PhysicsId{id++}; @@ -27,46 +28,49 @@ class SimpleMapConstructorExpectations : public ::testing::Test }); Method(wall_positions_generator, generate_boundary_walls) .Using(edge_size) = generated_walls; - When(Method(render_engine, register_renderable)) + When(Method(render_engine, acquire)) .AlwaysDo([&](const auto& size, const auto& position) { - static unsigned id = 0; + static uint8_t id = 0; render_wall_positions.push_back(position); render_wall_sizes.push_back(size); - const auto rid = graphics::RenderId{id++}; + const auto rid = graphics::RendererId{{id++}}; render_ids.push_back(rid); return rid; }); - When(Method(render_engine, deregister)).AlwaysDo([&](const auto id) { + When(Method(render_engine, release)).AlwaysDo([&](const auto id) { deregistered_render_ids.push_back(id); }); - Method(render_engine, register_renderable) - .Using(boundary_size, top_left_position) = background_id; + Method(render_engine, acquire).Using(boundary_size, top_left_position) = + background_id; render_ids.push_back(background_id); } const int edge_size{10}; - const graphics::RenderEngine::Position top_left_position{0, 0}; - const graphics::RenderEngine::Position boundary_size{edge_size, edge_size}; - const std::vector generateed_walls_sizes{ + const math::Position2f top_left_position{0, 0}; + const math::Size2f boundary_size{static_cast(edge_size), + static_cast(edge_size)}; + const std::vector generated_walls_sizes{ {1, 1}, {1, 2}, {4, 4}, {4, 67}}; - const std::vector - generated_walls_positions{{8, 7}, {2, 1}, {2, 8}, {88, 123}}; + + const std::vector generated_walls_positions{ + {8, 7}, {2, 1}, {2, 8}, {88, 123}}; + const WallPositionsGenerator::Walls generated_walls{{{8, 7}, {1, 1}}, {{2, 1}, {1, 2}}, {{2, 8}, {4, 4}}, {{88, 123}, {4, 67}}}; Mock physics_engine; - Mock render_engine; + Mock render_engine; Mock wall_positions_generator; std::vector physicsIds; std::vector deregistered_physics_ids; - std::vector physics_wall_positions; - std::vector physics_wall_sizes; - std::vector render_ids; - std::vector deregistered_render_ids; - std::vector render_wall_positions; - std::vector render_wall_sizes; - graphics::RenderId background_id{1024}; + std::vector physics_wall_positions; + std::vector physics_wall_sizes; + std::vector render_ids; + std::vector render_wall_positions; + std::vector render_wall_sizes; + std::vector deregistered_render_ids; + graphics::RendererId background_id{{uint8_t(1024)}}; }; class SimpleMapTest : public SimpleMapConstructorExpectations @@ -81,11 +85,11 @@ class SimpleMapTest : public SimpleMapConstructorExpectations physics_wall_positions, ::testing::UnorderedElementsAreArray(generated_walls_positions)); ASSERT_THAT(physics_wall_sizes, ::testing::UnorderedElementsAreArray( - generateed_walls_sizes)); + generated_walls_sizes)); ASSERT_THAT(render_wall_positions, ::testing::UnorderedElementsAreArray( generated_walls_positions)); ASSERT_THAT(render_wall_sizes, ::testing::UnorderedElementsAreArray( - generateed_walls_sizes)); + generated_walls_sizes)); } }; @@ -95,7 +99,7 @@ TEST_F(SimpleMapTest, DuringConstruction_ShouldCreateWalls) .Exactly(static_cast(generated_walls.size())); Verify(Method(wall_positions_generator, generate_boundary_walls)); verifyAllWallsArePlacedCorrectly(); - Verify(Method(render_engine, register_renderable)); + Verify(Method(render_engine, acquire)); } TEST_F(SimpleMapTest, diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 182bb1f..8f781b4 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -1,11 +1,2 @@ -add_executable(graphics_ut - RenderEngine.ut.cpp - ) - -target_include_directories(graphics_ut SYSTEM PRIVATE - ${UT_INCLUDES} - ) - - -target_link_libraries(graphics_ut --coverage gtest_main) -add_test(graphics_ut ${EXECUTABLE_OUTPUT_PATH}/graphics_ut --gtest_color=yes) +add_subdirectory(core) +add_subdirectory(examples) diff --git a/src/graphics/RenderEngine.hpp b/src/graphics/RenderEngine.hpp deleted file mode 100644 index a8e0cdd..0000000 --- a/src/graphics/RenderEngine.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -#include "RenderId.fwd.hpp" - -namespace graphics -{ -class RenderEngine -{ -public: - using Position = glm::vec2; - - virtual ~RenderEngine() = default; - - virtual RenderId register_renderable(const Position& size, - const Position& position) = 0; - virtual void deregister(const RenderId&) = 0; - virtual void set_position(const RenderId&, const glm::vec2& position) = 0; - virtual void render() = 0; -}; -} diff --git a/src/graphics/RenderEngine.ut.cpp b/src/graphics/RenderEngine.ut.cpp deleted file mode 100644 index f07cb49..0000000 --- a/src/graphics/RenderEngine.ut.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "RenderEngine.hpp" - -#include -#include - -#include - -#include "RenderId.hpp" - -namespace graphics -{ -class TestRenderer : public RenderEngine, public ::testing::Test -{ -public: - void set_position(const RenderId&, const glm::vec2&) override - { - ASSERT_TRUE(true); - } - - RenderId register_renderable(const glm::vec2&, - const glm::vec2&) override - { - return RenderId{0}; - } - - void deregister(const RenderId&) override - { - ASSERT_TRUE(true); - } - - void render() override - { - ASSERT_TRUE(true); - } -}; - -TEST_F(TestRenderer, register_deregister_renderable) -{ - const glm::vec2 size{1, 1}; - const glm::vec2 position{0, 0}; - - RenderEngine& r = *this; - const auto ob = r.register_renderable(size, position); - r.deregister(ob); -} - -TEST_F(TestRenderer, set_position) -{ - const RenderId id{546}; - ASSERT_FALSE(id == 56); - ASSERT_TRUE(id == 546); - const glm::vec2 v2{34, 12}; - - RenderEngine& r = *this; - r.set_position(id, v2); -} - -TEST_F(TestRenderer, render) -{ - RenderEngine& r = *this; - r.render(); -} -} diff --git a/src/graphics/RenderId.fwd.hpp b/src/graphics/RenderId.fwd.hpp deleted file mode 100644 index 16f3ab4..0000000 --- a/src/graphics/RenderId.fwd.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace graphics -{ -struct RenderId; -} diff --git a/src/graphics/RenderId.hpp b/src/graphics/RenderId.hpp deleted file mode 100644 index 6522016..0000000 --- a/src/graphics/RenderId.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -namespace graphics -{ -BOOST_STRONG_TYPEDEF(std::uint32_t, RenderId) -} diff --git a/src/graphics/core/CMakeLists.txt b/src/graphics/core/CMakeLists.txt new file mode 100644 index 0000000..693f013 --- /dev/null +++ b/src/graphics/core/CMakeLists.txt @@ -0,0 +1,43 @@ +find_package(SFML 2 COMPONENTS system graphics window REQUIRED) +find_package(Boost 1.6 REQUIRED) + +########################### SRC ########################### +add_library(graphics + Factory.cpp + RendererPoolSfml.cpp + RendererIdGenerator.cpp + SfmlRectangleShape.cpp + WindowSfml.cpp + SfmlWindowFacade.cpp) + +target_include_directories(graphics + PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../includes + PRIVATE ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../types) + +target_include_directories(graphics SYSTEM + PRIVATE ${SFML_INCLUDE_DIR} + Boost::boost) + +target_link_libraries(graphics + PRIVATE ${SFML_LIBRARIES} + PUBLIC math) + +########################### UT ########################### +add_executable(graphics-ut + RendererPoolSfml.ut.cpp + SfmlRenderTarget.ut.cpp + SfmlRectangleShape.ut.cpp + WindowSfml.ut.cpp) + +target_include_directories(graphics-ut SYSTEM BEFORE + PRIVATE ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../types + ${UT_INCLUDES} + ${SFML_INCLUDE_DIR} + Boost::boost) + +target_link_libraries(graphics-ut + PRIVATE graphics gmock_main ${SFML_LIBRARIES}) + +add_test(graphics-ut ${EXECUTABLE_OUTPUT_PATH}/graphics-ut --gtest_color=yes) diff --git a/src/graphics/core/ContextRenderer.hpp b/src/graphics/core/ContextRenderer.hpp new file mode 100644 index 0000000..557d0e5 --- /dev/null +++ b/src/graphics/core/ContextRenderer.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include +#include + +#include "SfmlRectangleShape.hpp" + +namespace graphics +{ +class ContextRenderer +{ +public: + virtual ~ContextRenderer() noexcept = default; + + virtual void initialize() = 0; + virtual void clear(const sf::Color&) = 0; + virtual void draw(const SfmlRectangleShape&) = 0; +}; +} diff --git a/src/graphics/core/Factory.cpp b/src/graphics/core/Factory.cpp new file mode 100644 index 0000000..cf55e33 --- /dev/null +++ b/src/graphics/core/Factory.cpp @@ -0,0 +1,25 @@ +#include "graphics/Factory.hpp" + +#include "RendererPoolSfml.hpp" +#include "SfmlRenderTarget.hpp" +#include "RendererIdGenerator.hpp" +#include "WindowSfml.hpp" +#include "SfmlWindowFacade.hpp" + +namespace graphics +{ +std::unique_ptr +create_renderer_pool(const math::Size2u& rendering_region_size) +{ + return std::make_unique( + std::make_unique(rendering_region_size), + std::make_unique()); +} + +std::unique_ptr create_window(const math::Size2u& size, + const std::string& title) +{ + return std::make_unique( + size, title, std::make_unique(size, title)); +} +} diff --git a/src/graphics/core/RenderTarget.stub.hpp b/src/graphics/core/RenderTarget.stub.hpp new file mode 100644 index 0000000..d6fe17d --- /dev/null +++ b/src/graphics/core/RenderTarget.stub.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include + +#include "SfmlRectangleShape.hpp" + +namespace graphics +{ +namespace +{ +const Position2f pos{0, 0}; +const Size2f size{0, 0}; +} + +class RenderTargetStub +{ +public: + virtual ~RenderTargetStub() + { + EXPECT_EQ(shouldInitialize, initialized); + EXPECT_EQ(shouldClear, cleared); + if (shouldClear) + { + EXPECT_EQ(expectedColor, clearedColor); + } + EXPECT_EQ(shouldDraw, drawn); + if (shouldDraw) + { + EXPECT_EQ(expectedShape, drawnShape); + } + } + void initialize() + { + initialized = true; + } + + void clear(const sf::Color& color) + { + cleared = true; + clearedColor = color; + } + + void draw(const SfmlRectangleShape& shape) + { + drawn = true; + drawnShape = shape; + } + + virtual sf::Vector2u getSize() const = 0; + virtual bool activate(bool) = 0; + + void expectClear(const sf::Color& color) + { + shouldClear = true; + expectedColor = color; + } + + void expectDraw(const SfmlRectangleShape& shape) + { + shouldDraw = true; + expectedShape = shape; + } + + bool initialized{false}; + bool cleared{false}; + sf::Color clearedColor{sf::Color::Transparent}; + bool drawn{false}; + SfmlRectangleShape drawnShape{size, pos}; + + bool shouldInitialize{false}; + bool shouldClear{false}; + bool shouldDraw{false}; + + sf::Color expectedColor{sf::Color::Transparent}; + SfmlRectangleShape expectedShape{size, pos}; +}; +} diff --git a/src/graphics/core/RendererIdGenerator.cpp b/src/graphics/core/RendererIdGenerator.cpp new file mode 100644 index 0000000..669183d --- /dev/null +++ b/src/graphics/core/RendererIdGenerator.cpp @@ -0,0 +1,11 @@ +#include "RendererIdGenerator.hpp" + +#include + +namespace graphics +{ +RendererId RendererIdGenerator::generate() const +{ + return boost::uuids::random_generator()(); +} +} diff --git a/src/graphics/core/RendererIdGenerator.hpp b/src/graphics/core/RendererIdGenerator.hpp new file mode 100644 index 0000000..ca0ae33 --- /dev/null +++ b/src/graphics/core/RendererIdGenerator.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "graphics/RendererId.hpp" + +namespace graphics +{ +class RendererIdGenerator +{ +public: + virtual ~RendererIdGenerator() noexcept = default; + virtual RendererId generate() const; +}; +} diff --git a/src/graphics/core/RendererPoolSfml.cpp b/src/graphics/core/RendererPoolSfml.cpp new file mode 100644 index 0000000..c1fec0d --- /dev/null +++ b/src/graphics/core/RendererPoolSfml.cpp @@ -0,0 +1,61 @@ +#include "RendererPoolSfml.hpp" + +#include +#include +#include + +#include + +namespace graphics +{ + +RendererPoolSfml::RendererPoolSfml( + std::unique_ptr renderer, + std::unique_ptr generator) + : context_renderer{std::move(renderer)}, renderer_id_generator{ + std::move(generator)} +{ + context_renderer->initialize(); +} + +RendererId RendererPoolSfml::acquire(const math::Size2f& size, + const math::Position2f& position) +{ + auto id = renderer_id_generator->generate(); + shapes.emplace(std::piecewise_construct, std::forward_as_tuple(id), + std::forward_as_tuple(size, position)); + return id; +} + +void RendererPoolSfml::release(const RendererId& id) +{ + trash.emplace(id); +} + +void RendererPoolSfml::cleanup_unused() +{ + ranges::for_each(trash, [this](const auto& id) { shapes.erase(id); }); + trash.clear(); +} + +void RendererPoolSfml::render_all() +{ + cleanup_unused(); + context_renderer->clear(sf::Color::Black); + + ranges::for_each(shapes, [&](const auto& shape) { + context_renderer->draw(shape.second); + }); +} + +void RendererPoolSfml::set_position(const RendererId& id, + const math::Position2f& position) +{ + shapes.at(id).setPosition({position.x, position.y}); +} + +math::Position2f RendererPoolSfml::get_position(const RendererId& id) +{ + return shapes.at(id).getPosition(); +} +} diff --git a/src/graphics/core/RendererPoolSfml.hpp b/src/graphics/core/RendererPoolSfml.hpp new file mode 100644 index 0000000..cb658f0 --- /dev/null +++ b/src/graphics/core/RendererPoolSfml.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "graphics/RendererPool.hpp" + +#include +#include +#include +#include +#include + +#include "ContextRenderer.hpp" +#include "RendererIdGenerator.hpp" + +namespace graphics +{ +class RendererPoolSfml : public RendererPool +{ +public: + RendererPoolSfml(std::unique_ptr, + std::unique_ptr); + + RendererId acquire(const math::Size2f&, const math::Position2f&) override; + void release(const RendererId&) override; + void render_all() override; + + void set_position(const RendererId&, + const math::Position2f& position) override; + math::Position2f get_position(const RendererId&) override; + +private: + void cleanup_unused(); + + std::unique_ptr context_renderer; + std::unique_ptr renderer_id_generator; + std::unordered_map> + shapes; + std::unordered_set> trash; +}; +} diff --git a/src/graphics/core/RendererPoolSfml.ut.cpp b/src/graphics/core/RendererPoolSfml.ut.cpp new file mode 100644 index 0000000..bda0baa --- /dev/null +++ b/src/graphics/core/RendererPoolSfml.ut.cpp @@ -0,0 +1,194 @@ +#include "RendererPoolSfml.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include "SfmlRectangleShape.hpp" + +using namespace ::fakeit; + +using ::testing::UnorderedElementsAreArray; + +namespace graphics +{ +namespace +{ +constexpr math::Size2f dummy_size{20, 30}; +constexpr math::Size2f another_dummy_size{100, 100}; +constexpr math::Position2f dummy_position{0, 10}; +} +class RendererPoolSfmlTest : public ::testing::Test +{ +public: + void SetUp() override + { + Fake(Dtor(renderer_id_generator)); + Fake(Dtor(context_renderer)); + Fake(Method(context_renderer, initialize)); + + renderer_pool = std::make_unique( + std::unique_ptr(&context_renderer.get()), + std::unique_ptr(&renderer_id_generator.get())); + + Verify(Method(context_renderer, initialize)); + } + + auto create_dummy_shape(const Size2f& size = dummy_size, + const Position2f& position = dummy_position) + { + return SfmlRectangleShape{size, position}; + } + + void expect_render_all(std::vector expected_shapes) + { + std::vector shapes; + shapes.reserve(expected_shapes.size()); + Fake(Method(context_renderer, clear)); + When(Method(context_renderer, draw)).AlwaysDo([&](const auto& shape) { + shapes.push_back(shape); + }); + + renderer_pool->render_all(); + ASSERT_THAT(shapes, UnorderedElementsAreArray(expected_shapes)); + } + + void expect_acquire_renderable(const math::Size2f& size, + const math::Position2f& position, + const RendererId& id) + { + EXPECT_EQ(id, renderer_pool->acquire(size, position)); + } + + void expect_eq_position(const math::Position2f& position, + const RendererId& id) + { + EXPECT_FLOAT_EQ(position.x, renderer_pool->get_position(id).x); + EXPECT_FLOAT_EQ(position.y, renderer_pool->get_position(id).y); + } + + void expect_move_object(const float x, const float y, const RendererId& id) + { + auto new_position = dummy_position; + new_position.x += x; + new_position.y += y; + renderer_pool->set_position(id, new_position); + + expect_eq_position(new_position, id); + } + + Mock renderer_id_generator; + Mock context_renderer; + std::unique_ptr renderer_pool; + + const RendererId id1{RendererIdGenerator{}.generate()}; + const RendererId id2{RendererIdGenerator{}.generate()}; +}; + +TEST_F(RendererPoolSfmlTest, acquireTwoRenderableObject_positionShouldMatch) +{ + When(Method(renderer_id_generator, generate)).Return(id1).Return(id2); + + expect_acquire_renderable(dummy_size, dummy_position, id1); + expect_acquire_renderable(another_dummy_size, dummy_position, id2); + expect_eq_position(dummy_position, id1); + expect_eq_position(dummy_position, id2); +} + +TEST_F(RendererPoolSfmlTest, renderableObjectShouldBeMovable) +{ + When(Method(renderer_id_generator, generate)).Return(id1); + expect_acquire_renderable(dummy_size, dummy_position, id1); + expect_eq_position(dummy_position, id1); + + expect_move_object(10, 30, id1); + expect_move_object(0, -23, id1); + expect_move_object(-99, 10, id1); + expect_move_object(10, -231, id1); +} + +TEST_F(RendererPoolSfmlTest, getPositionOfInvalidIdShouldThrow) +{ + EXPECT_THROW(renderer_pool->get_position(id1), std::out_of_range); +} + +TEST_F(RendererPoolSfmlTest, setPositiontOfInvalidIdShouldThrow) +{ + EXPECT_THROW(renderer_pool->set_position(id1, dummy_position), + std::out_of_range); +} + +TEST_F(RendererPoolSfmlTest, renderAll) +{ + When(Method(renderer_id_generator, generate)).AlwaysDo([]() { + return RendererIdGenerator{}.generate(); + }); + + auto expected_shapes = { + create_dummy_shape(Size2f{10, 10}), create_dummy_shape(Size2f{710, 30}), + create_dummy_shape(Size2f{80, 8}), create_dummy_shape(Size2f{107, 180}), + create_dummy_shape(Size2f{60, 30})}; + + ranges::for_each(expected_shapes, [this](auto& shape) { + this->renderer_pool->acquire(shape.getSize(), dummy_position); + }); + + expect_render_all({expected_shapes}); + + Verify(Method(context_renderer, clear).Using(sf::Color::Black)); + Verify(Method(context_renderer, draw)) + .Exactly(static_cast(expected_shapes.size())); +} + +TEST_F(RendererPoolSfmlTest, releaseWithoutAcquire_doNothing) +{ + renderer_pool->release(id1); + Fake(Method(context_renderer, clear)); + Fake(Method(context_renderer, draw)); + renderer_pool->render_all(); + Verify(Method(context_renderer, draw)).Exactly(0); +} + +TEST_F(RendererPoolSfmlTest, acquireTwoReleaseOne_shouldRenderOnlyOne) +{ + When(Method(renderer_id_generator, generate)).Return(id1).Return(id2); + + EXPECT_EQ(id1, renderer_pool->acquire(dummy_size, dummy_position)); + EXPECT_EQ(id2, renderer_pool->acquire(another_dummy_size, dummy_position)); + + renderer_pool->release(id2); + + auto expected_shapes = {create_dummy_shape()}; + + expect_render_all(expected_shapes); + + Verify(Method(context_renderer, clear).Using(sf::Color::Black)); + Verify(Method(context_renderer, draw)).Once(); +} + +TEST_F(RendererPoolSfmlTest, reacquirenShouldBeRendered) +{ + When(Method(renderer_id_generator, generate)) + .Return(id1) + .Return(id2) + .Return(id2); + + EXPECT_EQ(id1, renderer_pool->acquire(dummy_size, dummy_position)); + EXPECT_EQ(id2, renderer_pool->acquire(another_dummy_size, dummy_position)); + + std::vector expected_shapes{create_dummy_shape()}; + + renderer_pool->release(id2); + expect_render_all(expected_shapes); + + EXPECT_EQ(id2, renderer_pool->acquire(another_dummy_size, dummy_position)); + expected_shapes.emplace_back(another_dummy_size, dummy_position); + + expect_render_all(expected_shapes); +} +} diff --git a/src/graphics/core/SfmlRectangleShape.cpp b/src/graphics/core/SfmlRectangleShape.cpp new file mode 100644 index 0000000..b72b2e8 --- /dev/null +++ b/src/graphics/core/SfmlRectangleShape.cpp @@ -0,0 +1,24 @@ +#include "SfmlRectangleShape.hpp" + +#include + +namespace graphics +{ + +SfmlRectangleShape::SfmlRectangleShape(const Size2f& size, + const Position2f& position) +{ + setSize(size); + setPosition(position); +} + +Position2f SfmlRectangleShape::getPosition() const +{ + return sf::RectangleShape::getPosition(); +} + +Size2f SfmlRectangleShape::getSize() const +{ + return sf::RectangleShape::getSize(); +} +} diff --git a/src/graphics/core/SfmlRectangleShape.hpp b/src/graphics/core/SfmlRectangleShape.hpp new file mode 100644 index 0000000..bf157be --- /dev/null +++ b/src/graphics/core/SfmlRectangleShape.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include "Position2f.hpp" +#include "Size2f.hpp" + +namespace graphics +{ +class SfmlRectangleShape : public sf::RectangleShape, + public boost::equality_comparable +{ +public: + SfmlRectangleShape(const Size2f&, const Position2f&); + + Position2f getPosition() const; + Size2f getSize() const; +}; + +inline bool operator==(const SfmlRectangleShape& lhs, + const SfmlRectangleShape& rhs) +{ + return lhs.getPosition() == rhs.getPosition() && + lhs.getSize() == rhs.getSize(); +} +} diff --git a/src/graphics/core/SfmlRectangleShape.ut.cpp b/src/graphics/core/SfmlRectangleShape.ut.cpp new file mode 100644 index 0000000..a92ebda --- /dev/null +++ b/src/graphics/core/SfmlRectangleShape.ut.cpp @@ -0,0 +1,45 @@ +#include + +#include "SfmlRectangleShape.hpp" + +namespace graphics +{ + +namespace +{ +const Position2f pos{0.7f, 73.0f}; +const Size2f size{200, 100}; +} + +TEST(SfmlRectangleShapeTest, getPosition) +{ + const SfmlRectangleShape rect(size, pos); + + EXPECT_EQ(pos, rect.getPosition()); +} + +TEST(SfmlRectangleShapeTest, getSize) +{ + const SfmlRectangleShape rect(size, pos); + + EXPECT_EQ(size, rect.getSize()); +} + +TEST(SfmlRectangleShapeTest, equality) +{ + const SfmlRectangleShape rect_1(Size2f{200, 100}, pos); + const SfmlRectangleShape rect_2(Size2f{200, 100}, pos); + const SfmlRectangleShape rect_3(rect_2); + + EXPECT_EQ(rect_1, rect_2); + EXPECT_EQ(rect_1, rect_3); +} + +TEST(SfmlRectangleShapeTest, inequality) +{ + const SfmlRectangleShape rect_1(Size2f{200, 10}, pos); + const SfmlRectangleShape rect_2(Size2f{20, 100}, pos); + + EXPECT_NE(rect_1, rect_2); +} +} diff --git a/src/graphics/core/SfmlRenderTarget.hpp b/src/graphics/core/SfmlRenderTarget.hpp new file mode 100644 index 0000000..e0dc77d --- /dev/null +++ b/src/graphics/core/SfmlRenderTarget.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include + +#include "WindowSize.hpp" +#include "ContextRenderer.hpp" + +namespace graphics +{ +template +class RenderTarget : public ContextRenderer, public BaseRenderTarget +{ +public: + RenderTarget(const WindowSize& size) : window_size{size} + { + } + + void initialize() override + { + BaseRenderTarget::initialize(); + } + + void clear(const sf::Color& color) override + { + BaseRenderTarget::clear(color); + } + + void draw(const SfmlRectangleShape& drawable) override + { + BaseRenderTarget::draw(drawable); + } + + sf::Vector2u getSize() const override + { + return window_size; + } + bool activate([[maybe_unused]] bool active) override + { + return true; + } + +protected: + WindowSize window_size; +}; + +using SfmlRenderTarget = RenderTarget; +} diff --git a/src/graphics/core/SfmlRenderTarget.mock.hpp b/src/graphics/core/SfmlRenderTarget.mock.hpp new file mode 100644 index 0000000..3eaef78 --- /dev/null +++ b/src/graphics/core/SfmlRenderTarget.mock.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "RenderTarget.hpp" + +namespace graphics +{ +class RenderTargetMock : public RenderTarget +{ +public: + MOCK_METHOD0(initialize, void()); + MOCK_METHOD1(clear, void(const sf::Color)); + MOCK_METHOD1(draw, void(const sf::Drawable&)); + MOCK_METHOD1(setSize, void(const sf::Vector2u)); + MOCK_CONST_METHOD0(getSize, sf::Vector2u()); +}; +} diff --git a/src/graphics/core/SfmlRenderTarget.ut.cpp b/src/graphics/core/SfmlRenderTarget.ut.cpp new file mode 100644 index 0000000..783262d --- /dev/null +++ b/src/graphics/core/SfmlRenderTarget.ut.cpp @@ -0,0 +1,60 @@ +#include "SfmlRenderTarget.hpp" + +#include +#include + +#include "RenderTarget.stub.hpp" + +using ::testing::Test; + +namespace graphics +{ +class RenderTargetBaseFunctionsTest : public Test +{ +public: + RenderTarget renderTarget{WindowSize{200, 300}}; +}; + +TEST_F(RenderTargetBaseFunctionsTest, + initializeShouldInvokeInitializeFromBaseClass) +{ + renderTarget.shouldInitialize = true; + renderTarget.initialize(); +} + +TEST_F(RenderTargetBaseFunctionsTest, clearShouldInvokeClearFromBaseClass) +{ + auto red = sf::Color::Red; + renderTarget.expectClear(red); + renderTarget.clear(red); +} + +TEST_F(RenderTargetBaseFunctionsTest, drawShouldInvokeDrawFromBaseClass) +{ + const SfmlRectangleShape shape(Size2f{200, 100}, Position2f(1.f, 2.3f)); + renderTarget.expectDraw(shape); + renderTarget.draw(shape); +} + +TEST(RenderTargetOverridedFuncionsTest, setAndGetSize) +{ + const WindowSize size_200x300{200, 300}; + const WindowSize size_400x300{400, 300}; + SfmlRenderTarget renderTarget200x300{size_200x300}; + SfmlRenderTarget renderTarget400x300{size_400x300}; + EXPECT_EQ(size_200x300, renderTarget200x300.getSize()); + EXPECT_EQ(size_400x300, renderTarget400x300.getSize()); +} + +TEST(RenderTargetOverridedFuncionsTest, + activate_dummyMethodShouldJustReturnTrue) +{ + const WindowSize dummy_size{200, 300}; + SfmlRenderTarget renderTarget{dummy_size}; + EXPECT_TRUE(renderTarget.activate(true)); + EXPECT_TRUE(renderTarget.activate(true)); + EXPECT_TRUE(renderTarget.activate(false)); + EXPECT_TRUE(renderTarget.activate(false)); + EXPECT_TRUE(renderTarget.activate(true)); +} +} diff --git a/src/graphics/core/SfmlWindow.hpp b/src/graphics/core/SfmlWindow.hpp new file mode 100644 index 0000000..fa6b4be --- /dev/null +++ b/src/graphics/core/SfmlWindow.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include + +namespace graphics +{ +class SfmlWindow +{ +public: + virtual ~SfmlWindow() noexcept = default; + + virtual bool is_open() const = 0; + virtual void display() = 0; + virtual bool poll_event(sf::Event&) = 0; + virtual void close() = 0; + virtual void create(sf::VideoMode, const sf::String& title) = 0; +}; +} diff --git a/src/graphics/core/SfmlWindowFacade.cpp b/src/graphics/core/SfmlWindowFacade.cpp new file mode 100644 index 0000000..4b1ee9a --- /dev/null +++ b/src/graphics/core/SfmlWindowFacade.cpp @@ -0,0 +1,34 @@ +#include "SfmlWindowFacade.hpp" + +namespace graphics +{ +SfmlWindowFacade::SfmlWindowFacade(const WindowSize& , + const std::string& ) +{ +} + +bool SfmlWindowFacade::is_open() const +{ + return window.isOpen(); +} + +void SfmlWindowFacade::display() +{ + window.display(); +} + +bool SfmlWindowFacade::poll_event(sf::Event& event) +{ + return window.pollEvent(event); +} + +void SfmlWindowFacade::close() +{ + return window.close(); +} + +void SfmlWindowFacade::create(sf::VideoMode mode, const sf::String& title) +{ + return window.create(mode, title); +} +} diff --git a/src/graphics/core/SfmlWindowFacade.hpp b/src/graphics/core/SfmlWindowFacade.hpp new file mode 100644 index 0000000..5db164b --- /dev/null +++ b/src/graphics/core/SfmlWindowFacade.hpp @@ -0,0 +1,22 @@ +#include "SfmlWindow.hpp" + +#include + +#include "WindowSize.hpp" + +namespace graphics +{ +class SfmlWindowFacade : public SfmlWindow +{ +public: + SfmlWindowFacade(const WindowSize&, const std::string& title); + bool is_open() const override; + void display() override; + bool poll_event(sf::Event&) override; + void close() override; + void create(sf::VideoMode, const sf::String& title) override; + +private: + sf::Window window; +}; +} diff --git a/src/graphics/core/WindowSfml.cpp b/src/graphics/core/WindowSfml.cpp new file mode 100644 index 0000000..73f47b4 --- /dev/null +++ b/src/graphics/core/WindowSfml.cpp @@ -0,0 +1,35 @@ +#include "WindowSfml.hpp" + +#include + +namespace graphics +{ +WindowSfml::WindowSfml(const WindowSize& size, const std::string& title, + std::unique_ptr w) + : window{std::move(w)} +{ + window->create(sf::VideoMode{size.width, size.height}, title); +} + +bool WindowSfml::is_open() const +{ + return window->is_open(); +} + +void WindowSfml::display() +{ + window->display(); +} + +void WindowSfml::update() +{ + sf::Event event; + while (window->poll_event(event)) + { + if (event.type == sf::Event::Closed) + { + window->close(); + } + } +} +} diff --git a/src/graphics/core/WindowSfml.hpp b/src/graphics/core/WindowSfml.hpp new file mode 100644 index 0000000..b045217 --- /dev/null +++ b/src/graphics/core/WindowSfml.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "graphics/Window.hpp" + +#include +#include + +#include "WindowSize.hpp" +#include "SfmlWindow.hpp" + +namespace graphics +{ +class WindowSfml : public Window +{ +public: + WindowSfml(const WindowSize&, const std::string&, + std::unique_ptr); + + bool is_open() const override; + void display() override; + void update() override; + +private: + std::unique_ptr window; +}; +} diff --git a/src/graphics/core/WindowSfml.ut.cpp b/src/graphics/core/WindowSfml.ut.cpp new file mode 100644 index 0000000..54423ef --- /dev/null +++ b/src/graphics/core/WindowSfml.ut.cpp @@ -0,0 +1,103 @@ +#include +#include +#include +#include + +#include "WindowSfml.hpp" + +namespace graphics +{ +class WindowSfmlTest : public ::testing::Test +{ +public: + void SetUp() override + { + fakeit::Fake(Dtor(sfml_window)); + fakeit::Fake(Method(sfml_window, create).Using(mode, window_title)); + fakeit::When(Method(sfml_window, is_open)).Return(true); + fakeit::Fake(Method(sfml_window, display)); + } + + auto create_window() + { + return WindowSfml{size, window_title, + std::unique_ptr(&sfml_window.get())}; + } + + void expectPollEvent() + { + fakeit::When(Method(sfml_window, poll_event)) + .AlwaysDo([&](sf::Event& e) { + e.type = events.back(); + events.pop_back(); + return not events.empty(); + }); + } + + void prepare_events(std::vector&& e) + { + events = std::move(e); + } + + int number_of_expected_events() const + { + return static_cast(events.size()); + } + + const std::string window_title = "My Window"; + const WindowSize size{300, 400}; + const sf::VideoMode mode{size.width, size.height}; + + fakeit::Mock sfml_window; + std::vector events; +}; + +TEST_F(WindowSfmlTest, windowShouldCreated) +{ + auto window = create_window(); + fakeit::Verify(Method(sfml_window, create)).Once(); +} + +TEST_F(WindowSfmlTest, windowShouldBeOpenendImmediatelyAfterCreation) +{ + auto window = create_window(); + + EXPECT_TRUE(window.is_open()); + fakeit::Verify(Method(sfml_window, is_open)).Once(); +} + +TEST_F(WindowSfmlTest, displayWindow) +{ + auto window = create_window(); + + window.display(); + fakeit::Verify(Method(sfml_window, display)).Once(); +} + +TEST_F(WindowSfmlTest, updateWindow) +{ + auto window = create_window(); + prepare_events({sf::Event::MouseLeft, sf::Event::LostFocus, + sf::Event::MouseMoved, sf::Event::MouseEntered}); + const auto no_events = number_of_expected_events(); + + expectPollEvent(); + window.update(); + fakeit::Verify(Method(sfml_window, poll_event)).Exactly(no_events); +} + +TEST_F(WindowSfmlTest, updateAndCloseWindow) +{ + fakeit::Fake(Method(sfml_window, close)); + auto window = create_window(); + prepare_events({sf::Event::MouseLeft, sf::Event::LostFocus, + sf::Event::MouseMoved, sf::Event::MouseEntered, + sf::Event::Closed}); + const auto no_events = number_of_expected_events(); + + expectPollEvent(); + window.update(); + fakeit::Verify(Method(sfml_window, poll_event)).Exactly(no_events); + fakeit::Verify(Method(sfml_window, close)).Once(); +} +} diff --git a/src/graphics/examples/CMakeLists.txt b/src/graphics/examples/CMakeLists.txt new file mode 100644 index 0000000..91bc316 --- /dev/null +++ b/src/graphics/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +find_package(SFML 2 COMPONENTS window REQUIRED) + +include_directories(SYSTEM ${SFML_INCLUDE_DIR}) +link_libraries(graphics ${SFML_LIBRARIES}) + +add_executable(simple-rectangle-draw SimpleRectangleDraw.cpp) +add_executable(simple-moving-rectangle SimpleMovingRectangle.cpp) + +add_custom_target(graphics-examples DEPENDS + simple-rectangle-draw + simple-moving-rectangle) diff --git a/src/graphics/examples/SimpleMovingRectangle.cpp b/src/graphics/examples/SimpleMovingRectangle.cpp new file mode 100644 index 0000000..258476f --- /dev/null +++ b/src/graphics/examples/SimpleMovingRectangle.cpp @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "math/Size2u.hpp" +#include "math/Position2f.hpp" +#include "graphics/Factory.hpp" +#include "graphics/Window.hpp" + +using namespace math; +using Arrow = std::vector>; + +inline auto create_object_at_center(const Size2u& available_region, + graphics::RendererPool& renderer_pool) +{ + using namespace graphics; + return renderer_pool.acquire( + Size2f{15, 15}, + Position2f{static_cast(available_region.width) / 2.0f, + static_cast(available_region.height) / 2.0f}); +} + +inline auto create_arrow_from_point(const Position2f& point, + const std::uint32_t& arrow_length, + const std::uint32_t& arrow_body_density, + graphics::RendererPool& renderer_pool) +{ + using namespace graphics; + const auto point_count = arrow_length / arrow_body_density; + float current_pos = static_cast(arrow_body_density); + + Arrow arrow(point_count); + ranges::generate(arrow, [&] { + const auto distance_from_center = current_pos; + current_pos += static_cast(arrow_body_density); + return std::make_pair(distance_from_center, + renderer_pool.acquire(Size2f{20, 30}, point)); + }); + return arrow; +} + +inline auto calculate_pi() +{ + return std::acos(-1); +} + +inline auto update_alfa(double& alfa, const double& delta_time) +{ + constexpr auto speed = 1.5; + alfa += speed * delta_time; +} + +inline auto update_arrows_after_one_turn(double& alfa, + graphics::RendererPool& renderer_pool, + Arrow& arrow, + const double& alfa_of_one_turn, + const double& double_pi) +{ + if (alfa > alfa_of_one_turn) + { + alfa -= double_pi; + renderer_pool.release(arrow.back().second); + arrow.pop_back(); + } +} + +inline auto update_arrow(const double& alfa, Arrow& arrow, + graphics::RendererPool& renderer_pool, + const Position2f& center_position) +{ + auto sinus = std::sin(alfa); + auto cosinus = std::cos(alfa); + + ranges::for_each(arrow, [&](auto& point) { + auto new_x = gsl::narrow_cast(point.first * cosinus); + auto new_y = gsl::narrow_cast(point.first * sinus); + + renderer_pool.set_position(point.second, + center_position + Position2f{new_x, new_y}); + }); +} + +inline auto +update_time(std::chrono::time_point& last) +{ + const auto now = std::chrono::system_clock::now(); + const auto delta_time = std::chrono::duration(now - last).count(); + last = now; + return delta_time; +} + +int main() +{ + const Size2u available_region{800, 600}; + auto window = graphics::create_window(available_region, "win"); + auto renderer_pool = graphics::create_renderer_pool(available_region); + + const auto center_id = + create_object_at_center(available_region, *renderer_pool); + const auto center_position = renderer_pool->get_position(center_id); + + constexpr auto circle_r = 200; + constexpr auto step = 40; + auto arrow = create_arrow_from_point(center_position, circle_r, step, + *renderer_pool); + + const auto pi = calculate_pi(); + const auto double_pi = pi * 2; + + auto alfa = 3 * pi / 2; + const auto alfa_of_one_turn = alfa + double_pi; + + auto last = std::chrono::system_clock::now(); + while (window->is_open() && arrow.size() > 0) + { + const auto delta_time = update_time(last); + update_arrow(alfa, arrow, *renderer_pool, center_position); + update_alfa(alfa, delta_time); + update_arrows_after_one_turn(alfa, *renderer_pool, arrow, + alfa_of_one_turn, double_pi); + renderer_pool->render_all(); + window->display(); + window->update(); + } +} diff --git a/src/graphics/examples/SimpleRectangleDraw.cpp b/src/graphics/examples/SimpleRectangleDraw.cpp new file mode 100644 index 0000000..0f0e207 --- /dev/null +++ b/src/graphics/examples/SimpleRectangleDraw.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include "graphics/Factory.hpp" + +using namespace math; + +int main() +{ + const Size2u window_size{800, 600}; + auto renderer_pool = graphics::create_renderer_pool(window_size); + auto window = graphics::create_window(window_size, "My Window"); + + renderer_pool->acquire(Size2f{20, 30}, Position2f{100.0f, 200.0f}); + renderer_pool->acquire(Size2f{30, 30}, Position2f{200.0f, 350.0f}); + + while (window->is_open()) + { + renderer_pool->render_all(); + window->display(); + window->update(); + } +} diff --git a/src/graphics/includes/graphics/Factory.hpp b/src/graphics/includes/graphics/Factory.hpp new file mode 100644 index 0000000..3a614db --- /dev/null +++ b/src/graphics/includes/graphics/Factory.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "math/Position2f.hpp" +#include "math/Size2u.hpp" + +#include "RendererPool.hpp" +#include "Window.hpp" + +namespace graphics +{ +std::unique_ptr +create_renderer_pool(const math::Size2u& rendering_region_size); +std::unique_ptr create_window(const math::Size2u&, + const std::string& title); +} diff --git a/src/graphics/includes/graphics/RendererId.hpp b/src/graphics/includes/graphics/RendererId.hpp new file mode 100644 index 0000000..07ca062 --- /dev/null +++ b/src/graphics/includes/graphics/RendererId.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace graphics +{ +using RendererId = boost::uuids::uuid; +} diff --git a/src/graphics/includes/graphics/RendererPool.hpp b/src/graphics/includes/graphics/RendererPool.hpp new file mode 100644 index 0000000..a3f019f --- /dev/null +++ b/src/graphics/includes/graphics/RendererPool.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "RendererId.hpp" +#include "math/Position2f.hpp" +#include "math/Size2f.hpp" + +namespace graphics +{ +class RendererPool +{ +public: + virtual ~RendererPool() noexcept = default; + + virtual RendererId acquire(const math::Size2f&, const math::Position2f&) = 0; + virtual void release(const RendererId&) = 0; + + //TODO: extract functions below to another abstraction + virtual void render_all() = 0; + virtual void set_position(const RendererId&, const math::Position2f&) = 0; + virtual math::Position2f get_position(const RendererId&) = 0; +}; +} diff --git a/src/graphics/includes/graphics/Window.hpp b/src/graphics/includes/graphics/Window.hpp new file mode 100644 index 0000000..5b56247 --- /dev/null +++ b/src/graphics/includes/graphics/Window.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace graphics +{ +class Window +{ +public: + virtual ~Window() noexcept = default; + + virtual bool is_open() const = 0; + virtual void display() = 0; + virtual void update() = 0; +}; +} diff --git a/src/graphics/types/Position2f.hpp b/src/graphics/types/Position2f.hpp new file mode 100644 index 0000000..e4072c8 --- /dev/null +++ b/src/graphics/types/Position2f.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "math/Position2f.hpp" + +namespace graphics +{ +struct Position2f : public ::math::Position2f +{ + Position2f(float x_, float y_) : ::math::Position2f(x_, y_) + { + } + + Position2f(const ::math::Position2f& pos) : Position2f(pos.x, pos.y) + { + } + + Position2f(const ::sf::Vector2f& pos) : Position2f(pos.x, pos.y) + { + } + + operator ::sf::Vector2f() const + { + return {x, y}; + } +}; +} diff --git a/src/graphics/types/Size2f.hpp b/src/graphics/types/Size2f.hpp new file mode 100644 index 0000000..98a46c6 --- /dev/null +++ b/src/graphics/types/Size2f.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "math/Size2f.hpp" + +namespace graphics +{ +struct Size2f : ::math::Size2f +{ + Size2f(const float width_, const float height_) + : ::math::Size2f{width_, height_} + { + } + + Size2f(const ::math::Size2f& size) : Size2f{size.width, size.height} + { + } + + Size2f(const ::sf::Vector2f& size) : Size2f{size.x, size.y} + { + } + + operator ::sf::Vector2f() const + { + return {width, height}; + } +}; +} diff --git a/src/graphics/types/WindowSize.hpp b/src/graphics/types/WindowSize.hpp new file mode 100644 index 0000000..14a07ec --- /dev/null +++ b/src/graphics/types/WindowSize.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "math/Size2u.hpp" + +namespace graphics +{ +struct WindowSize : ::math::Size2u, boost::totally_ordered +{ + WindowSize(const unsigned width_, const unsigned height_) + : ::math::Size2u{width_, height_} + { + } + + WindowSize(const ::math::Size2u& size) : WindowSize{size.width, size.height} + { + } + + WindowSize(const ::sf::Vector2u& size) : WindowSize{size.x, size.y} + { + } + + operator ::sf::Vector2u() const + { + return {width, height}; + } +}; + +inline bool operator==(const WindowSize& lhs, const ::sf::Vector2u& rhs) +{ + return sf::Vector2u(lhs) == rhs; +} +} diff --git a/src/math/CMakeLists.txt b/src/math/CMakeLists.txt new file mode 100644 index 0000000..0049b83 --- /dev/null +++ b/src/math/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(math INTERFACE) + +target_include_directories(math + INTERFACE ${CMAKE_CURRENT_LIST_DIR}/includes) diff --git a/src/math/Position.hpp b/src/math/Position.hpp deleted file mode 100644 index 84894e3..0000000 --- a/src/math/Position.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include - -namespace math -{ -struct Position2 -{ - float x; - float y; -}; - -inline bool operator==(const Position2& a, const Position2& b) -{ - return std::tie(a.x, a.y) == std::tie(b.x, b.y); -} - -inline bool operator<(const Position2& a, const Position2& b) -{ - return std::tie(a.x, a.y) < std::tie(b.x, b.y); -} - -} diff --git a/src/math/Size.hpp b/src/math/Size.hpp deleted file mode 100644 index 44ea6e2..0000000 --- a/src/math/Size.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -namespace math -{ -struct Size -{ - float width; - float height; -}; -} diff --git a/src/math/includes/math/Position2f.hpp b/src/math/includes/math/Position2f.hpp new file mode 100644 index 0000000..eee349c --- /dev/null +++ b/src/math/includes/math/Position2f.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include + +namespace math +{ +struct Position2f : boost::additive, + boost::totally_ordered +{ + constexpr Position2f(const float x_, const float y_) : x{x_}, y{y_} + { + } + + float x; + float y; +}; + +namespace +{ +auto tie(const Position2f& pos) +{ + return std::tie(pos.x, pos.y); +} +} + +inline Position2f& operator+=(Position2f& lhs, const Position2f& rhs) +{ + lhs.x += rhs.x; + lhs.y += rhs.y; + return lhs; +} + +inline bool operator==(const Position2f& lhs, const Position2f& rhs) +{ + return tie(lhs) == tie(rhs); +} + +inline bool operator<(const Position2f& lhs, const Position2f& rhs) +{ + return tie(lhs) < tie(rhs); +} +} diff --git a/src/math/includes/math/Size2.hpp b/src/math/includes/math/Size2.hpp new file mode 100644 index 0000000..56b86b5 --- /dev/null +++ b/src/math/includes/math/Size2.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace math +{ +template +struct Size2 : boost::additive>, boost::equality_comparable> +{ + constexpr Size2(const T width_, const T height_) + : width{width_}, height{height_} + { + } + + T& operator+=(const Size2& size) + { + width += size.width; + height += size.height; + return *this; + } + + T width; + T height; +}; + +template +bool operator==(const Size2& lhs, const Size2& rhs) +{ + const auto tie = [](const Size2& size) { + return std::tie(size.width, size.height); + }; + return tie(lhs) == tie(rhs); +} +} diff --git a/src/math/includes/math/Size2f.hpp b/src/math/includes/math/Size2f.hpp new file mode 100644 index 0000000..cbcc214 --- /dev/null +++ b/src/math/includes/math/Size2f.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "math/Size2.hpp" + +namespace math +{ +using Size2f = Size2; +} diff --git a/src/math/includes/math/Size2u.hpp b/src/math/includes/math/Size2u.hpp new file mode 100644 index 0000000..02610cc --- /dev/null +++ b/src/math/includes/math/Size2u.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "math/Size2.hpp" + +namespace math +{ +using Size2u = Size2; +} diff --git a/src/physics/CMakeLists.txt b/src/physics/CMakeLists.txt index 78db91f..ee7319f 100644 --- a/src/physics/CMakeLists.txt +++ b/src/physics/CMakeLists.txt @@ -1,12 +1,18 @@ -add_executable(physics_ut +# add_library(physics "") + +# target_link_libraries(physics +# PUBLIC math) + +add_executable(physics-ut PhysicsId.ut.cpp PhysicsEngine.ut.cpp ) -target_include_directories(physics_ut SYSTEM PRIVATE - ${UT_INCLUDES} +target_include_directories(physics-ut SYSTEM + PRIVATE ${UT_INCLUDES} ) +target_link_libraries(physics-ut + PRIVATE math gtest_main) -target_link_libraries(physics_ut --coverage gtest_main) -add_test(physics_ut ${EXECUTABLE_OUTPUT_PATH}/physics_ut --gtest_color=yes) +add_test(physics-ut ${EXECUTABLE_OUTPUT_PATH}/physics-ut --gtest_color=yes) diff --git a/src/physics/PhysicsEngine.hpp b/src/physics/PhysicsEngine.hpp index e835e1f..4828913 100644 --- a/src/physics/PhysicsEngine.hpp +++ b/src/physics/PhysicsEngine.hpp @@ -1,8 +1,10 @@ #pragma once -#include "glm/fwd.hpp" +#include "math/Position2f.hpp" +#include "math/Size2f.hpp" #include "PhysicsId.hpp" +#include "math/Position2f.hpp" namespace physics { @@ -10,13 +12,13 @@ namespace physics class PhysicsEngine { public: - using Position = glm::vec2; virtual ~PhysicsEngine() = default; - virtual void set_position(PhysicsId, const Position&) = 0; - virtual Position get_position(PhysicsId) const = 0; + virtual void set_position(PhysicsId, const math::Position2f&) = 0; + virtual math::Position2f get_position(PhysicsId) const = 0; virtual void solve_colisions() = 0; - virtual PhysicsId register_colider(const Position&, const Position&) = 0; + virtual PhysicsId register_colider(const math::Size2f&, + const math::Position2f&) = 0; virtual void deregister(PhysicsId) = 0; }; } diff --git a/src/physics/PhysicsEngine.ut.cpp b/src/physics/PhysicsEngine.ut.cpp index 2c90d13..ca818bc 100644 --- a/src/physics/PhysicsEngine.ut.cpp +++ b/src/physics/PhysicsEngine.ut.cpp @@ -7,21 +7,21 @@ class ConcretePhysicsEngine : public physics::PhysicsEngine { public: - void set_position(physics::PhysicsId, const Position&) override + void set_position(physics::PhysicsId, const math::Position2f&) override { } - Position get_position(physics::PhysicsId) const override + math::Position2f get_position(physics::PhysicsId) const override { - return {}; + return {0, 0}; } void solve_colisions() override { } - physics::PhysicsId register_colider(const Position&, - const Position&) override + physics::PhysicsId register_colider(const math::Size2f&, + const math::Position2f&) override { return {}; } @@ -48,7 +48,7 @@ TEST_F(PhysicsEngineInterfaceTest, ShouldCreateDeriveFromPhysicsEngine) TEST_F(PhysicsEngineInterfaceTest, ShouldHaveSetPositionFunction) { auto testFunction = [](physics::PhysicsEngine& engineTested) { - engineTested.set_position(physics::PhysicsId{}, glm::vec2{}); + engineTested.set_position(physics::PhysicsId{}, math::Position2f{0, 0}); }; testFunction(engine); } @@ -72,8 +72,8 @@ TEST_F(PhysicsEngineInterfaceTest, ShouldHaveSolveColisionsFunction) TEST_F(PhysicsEngineInterfaceTest, ShouldHaveRegisterColiderFunction) { auto testFunction = [](physics::PhysicsEngine& engineTested) { - engineTested.register_colider(physics::PhysicsEngine::Position{}, - physics::PhysicsEngine::Position{}); + engineTested.register_colider(math::Size2f{0, 0}, + math::Position2f{0, 0}); }; testFunction(engine); }