From cbd19df7395977e0547323ec6261624a5989c60d Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Wed, 7 Jul 2021 11:33:22 +0200 Subject: [PATCH] Implement scaling. We render pack man at twice the size that we want on screen, which is the native resolution of the asset file. The maze is upscaled. We then project everything onto a view which is applies the scale factor. This patches also dectect the appropriate scale on OSX. This required a bit of objective C (scaling.mm), but students should not look at this file and there is a comment in that direction. Scalling.cpp provides the default implementation for other platforms. --- lib/CMakeLists.txt | 6 ++++ lib/Canvas.cpp | 69 ++++++++++++++++++++++++++---------------- lib/Scaling.cpp | 5 +++ lib/Scaling.mm | 14 +++++++++ lib/include/Canvas.hpp | 25 +++++++-------- 5 files changed, 79 insertions(+), 40 deletions(-) create mode 100644 lib/Scaling.cpp create mode 100644 lib/Scaling.mm diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 05f2d28..9af7be0 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -15,3 +15,9 @@ target_link_libraries(libpacman PUBLIC fmt::fmt sfml-graphics) if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") target_link_libraries(libpacman PUBLIC OpenGL::OpenGL OpenGL::GLX) endif () + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + target_sources(libpacman PRIVATE Scaling.mm) +else() + target_sources(libpacman PRIVATE Scaling.cpp) +endif () diff --git a/lib/Canvas.cpp b/lib/Canvas.cpp index 20d0346..2de16fc 100644 --- a/lib/Canvas.cpp +++ b/lib/Canvas.cpp @@ -4,14 +4,30 @@ #include #include +double scaling_factor_for_window(sf::WindowHandle); + namespace pacman { Canvas::Canvas() - : window(sf::VideoMode(windowDimensions().width, windowDimensions().height), + : window(sf::VideoMode((viewDimensions().width/2.0), (viewDimensions().height/2.0)), "Pacman", - sf::Style::Titlebar | sf::Style::Close) { + sf::Style::Titlebar | sf::Style::Close) + , view(sf::FloatRect(0, 0, viewDimensions().width, viewDimensions().height)) +{ + + window.setView(view); window.setFramerateLimit(60); window.setVerticalSyncEnabled(true); + + // We render the game in view at twice the native resolution, + // Then project it on a scaled window - on some mac we get the + // scaling factor of the window to adjust the resolution + const auto scale = scaling_factor_for_window(window.getSystemHandle()); + const auto width = viewDimensions().width/2.0 * scale; + const auto height = viewDimensions().height/2.0 * scale; + window.setSize(sf::Vector2u(width, height)); + + maze_texture = loadTexture("maze.png"); sprites_texture = loadTexture("sprites32.png"); game_font = loadFont("retro_font.ttf"); @@ -55,10 +71,10 @@ void Canvas::renderMaze() { maze.setTextureRect(sf::IntRect{ 0, 0, - DEFAULT_MAZE_WIDTH, - DEFAULT_MAZE_HEIGHT }); - maze.setScale(scale(DEFAULT_MAZE_SCALE_UP), scale(DEFAULT_MAZE_SCALE_UP)); - maze.setPosition(scale(LEFT_MARGIN), scale(TOP_MARGIN)); + MAZE_WIDTH, + MAZE_HEIGHT }); + maze.setScale(MAZE_SCALE_UP, MAZE_SCALE_UP); + maze.setPosition(LEFT_MARGIN, TOP_MARGIN); window.draw(maze); } @@ -91,47 +107,52 @@ void Canvas::renderGhost(const Ghost & ghost) { } void Canvas::renderScore(int score) { + const int x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN); + const int y = (TOP_MARGIN * 2) ; + sf::Text text; - text.setPosition(scale(RIGHT_PANEL_X), scale(TOP_MARGIN * 2)); + text.setPosition(x, y); text.setFont(game_font); text.setString(fmt::format("SCORE\n{}", score)); - text.setCharacterSize(int(scale(40))); + text.setCharacterSize(40); text.setFillColor(sf::Color::White); window.draw(text); } void Canvas::renderLives(int lives) { constexpr GridPosition liveSprite = Atlas::pacman_left_narrow; - const auto x = scale(RIGHT_PANEL_X); - const auto y = scale(DEFAULT_TARGET_MAZE_HEIGHT); + const size_t x = (LEFT_MARGIN + TARGET_MAZE_WIDTH + LEFT_MARGIN); + const size_t y = TARGET_MAZE_HEIGHT; Sprite pacmanSprite = getSprite(liveSprite); for (int i = 0; i < lives - 1; i++) { - auto life_position = scale(i * DEFAULT_SPRITE_WIDTH); - pacmanSprite.setPosition(x + life_position, y); + size_t life_position = i * SPRITE_WIDTH * 1.5; + GridPosition pos{ x + life_position, y }; + pacmanSprite.setPosition(pos.x, pos.y); window.draw(pacmanSprite); } } -Rect Canvas::windowDimensions() { - return { 0, 0, int(scale(WINDOW_WIDTH)), int(scale(WINDOW_HEIGHT)) }; +Rect Canvas::viewDimensions() { + const double width = (LEFT_MARGIN + TARGET_MAZE_WIDTH + SCORE_WIDTH); + const double height = (TOP_MARGIN + TARGET_MAZE_HEIGHT + BOTTOM_MARGIN); + return { 0, 0, int(width), int(height) }; } Sprite Canvas::getSprite(GridPosition coordinate) const { sf::Sprite sprite; sprite.setTexture(sprites_texture); - sprite.setTextureRect(sf::IntRect{ int(coordinate.x * DEFAULT_SPRITE_WIDTH), - int(coordinate.y * DEFAULT_SPRITE_HEIGHT), - DEFAULT_SPRITE_WIDTH, - DEFAULT_SPRITE_HEIGHT }); - sprite.scale(SCALE_FACTOR, SCALE_FACTOR); + sprite.setTextureRect(sf::IntRect{ int(coordinate.x * SPRITE_WIDTH), + int(coordinate.y * SPRITE_HEIGHT), + SPRITE_WIDTH, + SPRITE_HEIGHT }); return sprite; } void Canvas::renderSprite(Sprite sprite, Position pos) { - const auto x = scale(LEFT_MARGIN + int(pos.x * DEFAULT_SPRITE_WIDTH)); - const auto y = scale(TOP_MARGIN + int(pos.y * DEFAULT_SPRITE_HEIGHT)); - sprite.setPosition(x, y); + pos.x = LEFT_MARGIN + (pos.x * SPRITE_WIDTH); + pos.y = TOP_MARGIN + (pos.y * SPRITE_HEIGHT); + sprite.setPosition(pos.x, pos.y); window.draw(sprite); } @@ -156,8 +177,4 @@ sf::Font Canvas::loadFont(std::string_view path) { return font; } -float_t Canvas::scale(int value) { - return float_t(value) * SCALE_FACTOR; -} - } // namespace pacman diff --git a/lib/Scaling.cpp b/lib/Scaling.cpp new file mode 100644 index 0000000..5d9bade --- /dev/null +++ b/lib/Scaling.cpp @@ -0,0 +1,5 @@ +#include + +double scaling_factor_for_window(sf::WindowHandle) { + return 1.0; +} diff --git a/lib/Scaling.mm b/lib/Scaling.mm new file mode 100644 index 0000000..b9c02f0 --- /dev/null +++ b/lib/Scaling.mm @@ -0,0 +1,14 @@ +/* +This is an Objective C file to detect the window's +resolution scale on Apple platforms. +It is not a C++ file and is not part of this course! +*/ +#import "AppKit/NSWindow.h" +#include + +double scaling_factor_for_window(void* ptr) { + NSWindow* window = static_cast(ptr); + assert(window); + double d = [window backingScaleFactor]; + return d; +} \ No newline at end of file diff --git a/lib/include/Canvas.hpp b/lib/include/Canvas.hpp index 329cead..91c1eff 100644 --- a/lib/include/Canvas.hpp +++ b/lib/include/Canvas.hpp @@ -19,21 +19,17 @@ public: std::optional pollEvent(); private: - static constexpr float_t SCALE_FACTOR = 0.5; static constexpr uint16_t LEFT_MARGIN = 40 * 2; - static constexpr uint16_t TOP_MARGIN = 40 * 2; + static constexpr uint16_t TOP_MARGIN = 40 * 2; static constexpr uint16_t BOTTOM_MARGIN = 40 * 2; - static constexpr uint16_t DEFAULT_MAZE_WIDTH = 448; - static constexpr uint16_t DEFAULT_MAZE_HEIGHT = 496; - static constexpr uint16_t DEFAULT_MAZE_SCALE_UP = 2; - static constexpr uint16_t DEFAULT_TARGET_MAZE_WIDTH = DEFAULT_MAZE_WIDTH * DEFAULT_MAZE_SCALE_UP; - static constexpr uint16_t DEFAULT_TARGET_MAZE_HEIGHT = DEFAULT_MAZE_HEIGHT * DEFAULT_MAZE_SCALE_UP; + static constexpr uint16_t MAZE_WIDTH = 448; + static constexpr uint16_t MAZE_HEIGHT = 496; + static constexpr uint16_t MAZE_SCALE_UP = 2; + static constexpr uint16_t TARGET_MAZE_WIDTH = 448 * MAZE_SCALE_UP; + static constexpr uint16_t TARGET_MAZE_HEIGHT = 496 * MAZE_SCALE_UP; static constexpr uint16_t SCORE_WIDTH = 200 * 2; - static constexpr uint16_t DEFAULT_SPRITE_WIDTH = 32; - static constexpr uint16_t DEFAULT_SPRITE_HEIGHT = 32; - static constexpr uint16_t RIGHT_PANEL_X = LEFT_MARGIN + DEFAULT_TARGET_MAZE_WIDTH + LEFT_MARGIN; - static constexpr uint16_t WINDOW_WIDTH = LEFT_MARGIN + DEFAULT_TARGET_MAZE_WIDTH + SCORE_WIDTH; - static constexpr uint16_t WINDOW_HEIGHT = TOP_MARGIN + DEFAULT_TARGET_MAZE_HEIGHT + BOTTOM_MARGIN; + static constexpr uint16_t SPRITE_WIDTH = 32; + static constexpr uint16_t SPRITE_HEIGHT = 32; void clear(); void render(); @@ -47,17 +43,18 @@ private: void renderScore(int score); void renderLives(int lives); - static Rect windowDimensions(); + static Rect viewDimensions(); static sf::Texture loadTexture(std::string_view path); static sf::Font loadFont(std::string_view path); - static float_t scale(int value); Sprite getSprite(GridPosition rect) const; sf::RenderWindow window; + sf::View view; sf::Texture maze_texture; sf::Texture sprites_texture; sf::Font game_font; + }; } // namespace pacman