From 69aee157b811ab1ba41946baf6ca42fcaaf4f90d Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 20 Jul 2015 13:00:27 +1000 Subject: [PATCH] Implemented zoom in/out with the scroll wheel The focus of the zooming is the top left of the screen, but that is fine for now. --- src/base_scene.cpp | 4 ++++ src/example_scene.cpp | 40 +++++++++++++++++++++++++++++++-------- src/libmap/region.hpp | 2 ++ src/libmap/tile_sheet.cpp | 36 ++++++++++++++++++++++++++--------- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/base_scene.cpp b/src/base_scene.cpp index 128070f..38dab00 100644 --- a/src/base_scene.cpp +++ b/src/base_scene.cpp @@ -86,6 +86,10 @@ void BaseScene::ProcessEvents() { MouseButtonUp(event.button); break; + case SDL_MOUSEWHEEL: + MouseWheel(event.wheel); + break; + case SDL_KEYDOWN: KeyDown(event.key); break; diff --git a/src/example_scene.cpp b/src/example_scene.cpp index 7422ecd..3a52aee 100644 --- a/src/example_scene.cpp +++ b/src/example_scene.cpp @@ -65,6 +65,7 @@ void ExampleScene::FrameEnd() { void ExampleScene::RenderFrame(SDL_Renderer* renderer) { for (std::list::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { + //NOTE: Graphical scaling is done internally tileSheet.DrawRegionTo(renderer, &(*it), camera.x, camera.y, camera.scale, camera.scale); } } @@ -76,8 +77,8 @@ void ExampleScene::RenderFrame(SDL_Renderer* renderer) { void ExampleScene::MouseMotion(SDL_MouseMotionEvent const& event) { //right mouse button moves the camera if (event.state & SDL_BUTTON_RMASK) { - camera.x -= event.xrel; - camera.y -= event.yrel; + camera.x -= event.xrel / camera.scale; + camera.y -= event.yrel / camera.scale; } } @@ -85,14 +86,15 @@ void ExampleScene::MouseButtonDown(SDL_MouseButtonEvent const& event) { switch(event.button) { case SDL_BUTTON_LEFT: { //DOCS: broke this down into several lines for clarity - //these are the "real" click positions, relative to the map (can be scaled) - int fieldX = event.x + camera.x; - int fieldY = event.y + camera.y; + //these are the "real" click positions, relative to the map + //(scaled input is transformed into unscaled tile selection) + int fieldX = event.x / camera.scale + camera.x; + int fieldY = event.y / camera.scale + camera.y; //these are the x & y indexes of the selected tile //NOTE: the terniary operator is used to circumvent an error with integer devision - int tileX = (fieldX >= 0 ? fieldX : fieldX - 32) / 32; - int tileY = (fieldY >= 0 ? fieldY : fieldY - 32) / 32; + int tileX = (fieldX >= 0 ? fieldX : fieldX - tileSheet.GetTileW()) / tileSheet.GetTileW(); + int tileY = (fieldY >= 0 ? fieldY : fieldY - tileSheet.GetTileH()) / tileSheet.GetTileH(); //finally, call the method regionPager.SetTile(tileX, tileY, layer, selection); @@ -106,7 +108,29 @@ void ExampleScene::MouseButtonUp(SDL_MouseButtonEvent const& event) { } void ExampleScene::MouseWheel(SDL_MouseWheelEvent const& event) { - // + constexpr double scaleMod = 1.2; + constexpr double scaleUpperBound = 3.0; + constexpr double scaleLowerBound = 0.5; + + //zoom out + if (event.y < 0) { //downscroll + if (camera.scale / scaleMod <= scaleLowerBound) { + camera.scale = scaleLowerBound; + } + else { + camera.scale /= scaleMod; + } + } + + //zoom in + if (event.y > 0) { //upscroll + if (camera.scale * scaleMod >= scaleUpperBound) { + camera.scale = scaleUpperBound; + } + else { + camera.scale *= scaleMod; + } + } } void ExampleScene::KeyDown(SDL_KeyboardEvent const& event) { diff --git a/src/libmap/region.hpp b/src/libmap/region.hpp index 68511be..da919cb 100644 --- a/src/libmap/region.hpp +++ b/src/libmap/region.hpp @@ -52,6 +52,8 @@ public: std::bitset* GetSolidBitset(); private: + friend class TileSheet; + const int x; const int y; diff --git a/src/libmap/tile_sheet.cpp b/src/libmap/tile_sheet.cpp index 7c2654a..2b458ca 100644 --- a/src/libmap/tile_sheet.cpp +++ b/src/libmap/tile_sheet.cpp @@ -21,6 +21,8 @@ */ #include "tile_sheet.hpp" +#include + TileSheet& TileSheet::operator=(TileSheet const& rhs) { //don't screw yourself if (this == &rhs) { @@ -85,21 +87,37 @@ void TileSheet::DrawLayerTo(SDL_Renderer* const renderer, Region* const region, } void TileSheet::DrawRegionTo(SDL_Renderer* const renderer, Region* const region, int camX, int camY, double scaleX, double scaleY) { - //TODO: (2) make TileSheet a friend class of Region + //NOTE: TileSheet is a friend class of Region + //reimplementing DrawTo() to improve performance (less indirection) + if (!texture) { + throw(std::logic_error("No image texture to draw")); + } + + //the local variables + SDL_Rect sclip = {0, 0, clip.w, clip.h}; + SDL_Rect dclip = {0, 0, Uint16(clip.w * scaleX), Uint16(clip.h * scaleY)}; Region::type_t tile = 0; + + //for each tile for (register int i = 0; i < REGION_WIDTH; ++i) { for (register int j = 0; j < REGION_HEIGHT; ++j) { for (register int k = 0; k < REGION_DEPTH; ++k) { - tile = region->GetTile(i, j, k); + //get the value to skip expensive lookups + tile = region->tiles[i][j][k]; + //0 is invisible if (tile == 0) continue; - clip.x = (tile-1) % countX * clip.h; - clip.y = (tile-1) / countX * clip.w; - //TODO: (2) raw rendering; improve preformance - Image::DrawTo(renderer, - (region->GetX() + i) * clip.w - camX, - (region->GetY() + j) * clip.h - camY, - scaleX, scaleY); + + //set the sclip + sclip.x = (tile-1) % countX * clip.h; + sclip.x = (tile-1) / countX * clip.w; + + //set the dclip + dclip.x = ((region->x + i) * clip.w - camX) * scaleX; + dclip.y = ((region->y + j) * clip.h - camY) * scaleY; + + //draw + SDL_RenderCopy(renderer, texture, &sclip, &dclip); } } }