Move clipping and drawing to base class and fix int<->float warnings.

This commit is contained in:
King_DuckZ 2016-10-30 23:30:32 +01:00
parent c8920ea997
commit 5da4cef4a5
8 changed files with 159 additions and 22 deletions

View file

@ -6,7 +6,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/include")
include(TargetArch) include(TargetArch)
include(FindPkgConfig) include(FindPkgConfig)
set(common_gcc_flags "-Wall -Wextra -pedantic") set(common_gcc_flags "-Wall -Wextra -pedantic -Wconversion")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${common_gcc_flags}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${common_gcc_flags}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${common_gcc_flags}")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${common_gcc_flags}")

View file

@ -1,8 +1,13 @@
#include "gamescenebase.hpp" #include "gamescenebase.hpp"
#include "inputbag.hpp" #include "inputbag.hpp"
#include "sdlmain.hpp" #include "sdlmain.hpp"
#include "rect_to_sdl.hpp"
#include "rect.hpp"
#include "texture.hpp"
#include <cassert> #include <cassert>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <algorithm>
#include <ciso646>
namespace curry { namespace curry {
namespace { namespace {
@ -38,12 +43,56 @@ namespace curry {
} }
return false; return false;
} }
///----------------------------------------------------------------------
///Adjustes parSrc and parDest so that parDest will fit into parClip and
///parSrc to be the relevant part of the source texture to be drawn.
///Returns true if such operation was possible and parSrc and parDest
///got set to a valid value, otherwise false.
///----------------------------------------------------------------------
bool clip_rect (Rect<float>& parSrc, Rect<float>& parDest, const Rect<float>& parClip) {
typedef Rect<float> RectFloat;
assert(parSrc.is_valid());
assert(parDest.is_valid());
//If the dest rect is completely out of the clipping region, there
//is nothing to do at all.
if (parDest.to <= parClip.from or parDest.from >= parClip.to)
return false;
{
const RectFloat clip(vec2f(0.0f), vec2f(1.0f));
const vec2f srcWidthHeight(parSrc.width_height());
const vec2f scaledOffs((parDest.from - parClip.from) / parClip.width_height());
parSrc.from -= vec2f(std::min(0.0f, scaledOffs.x() * srcWidthHeight.x()), std::min(0.0f, scaledOffs.y() * srcWidthHeight.y()));
const vec2f scaledCrop((parClip.to - parDest.to) / parClip.width_height());
parSrc.to += vec2f(std::min(0.0f, scaledCrop.x() * srcWidthHeight.x()), std::min(0.0f, scaledCrop.y() * srcWidthHeight.y()));
assert(parSrc.is_valid());
}
RectFloat dst(parDest.from - parClip.from, parDest.to - parClip.from);
dst.from.x() = std::max(dst.from.x(), parClip.from.x());
dst.from.y() = std::max(dst.from.y(), parClip.from.y());
dst.to.x() = std::min(dst.to.x(), parClip.to.x());
dst.to.y() = std::min(dst.to.y(), parClip.to.y());
if (not dst.is_valid())
return false;
parDest.from += parClip.from;
parDest.to += parClip.from;
assert(parDest.is_valid());
return true;
}
} //unnamed namespace } //unnamed namespace
GameSceneBase::GameSceneBase (cloonel::SDLMain* parSdlMain) : GameSceneBase::GameSceneBase (cloonel::SDLMain* parSdlMain) :
m_time0(std::chrono::steady_clock::now()), m_time0(std::chrono::steady_clock::now()),
m_input(std::make_unique<cloonel::InputBag>()), m_input(std::make_unique<cloonel::InputBag>()),
m_sdlmain(parSdlMain), m_sdlmain(parSdlMain),
m_screen_width(static_cast<float>(m_sdlmain->WidthHeight().x())),
m_screen_height(static_cast<float>(m_sdlmain->WidthHeight().y())),
m_wants_to_quit(false) m_wants_to_quit(false)
{ {
assert(m_sdlmain); assert(m_sdlmain);
@ -82,6 +131,7 @@ namespace curry {
const float delta = std::chrono::duration<float>(time1 - m_time0).count(); const float delta = std::chrono::duration<float>(time1 - m_time0).count();
m_time0 = time1; m_time0 = time1;
this->on_update(delta); this->on_update(delta);
SDL_RenderPresent(this->sdl_main()->GetRenderer());
} }
cloonel::SDLMain* GameSceneBase::sdl_main() { cloonel::SDLMain* GameSceneBase::sdl_main() {
@ -91,4 +141,14 @@ namespace curry {
cloonel::InputBag& GameSceneBase::input_bag() { cloonel::InputBag& GameSceneBase::input_bag() {
return *m_input; return *m_input;
} }
void GameSceneBase::draw_clipped (Texture& parTexture, Rect<float> parSrc, Rect<float> parDest) {
const vec2f lefttop(0.0f);
const vec2f rightbottom(m_screen_width, m_screen_height);
clip_rect(parSrc, parDest, Rect<float>(lefttop, rightbottom));
auto src = make_sdlrect(parSrc);
auto dst = make_sdlrect(parDest);
SDL_RenderCopy(m_sdlmain->GetRenderer(), parTexture.texture(), &src, &dst);
}
} //namespace curry } //namespace curry

View file

@ -9,6 +9,9 @@ namespace cloonel {
} //namespace cloonel } //namespace cloonel
namespace curry { namespace curry {
class Texture;
template <typename T> class Rect;
class GameSceneBase { class GameSceneBase {
public: public:
explicit GameSceneBase (cloonel::SDLMain* parSdlMain); explicit GameSceneBase (cloonel::SDLMain* parSdlMain);
@ -28,11 +31,14 @@ namespace curry {
virtual void on_update (float parDeltaT) = 0; virtual void on_update (float parDeltaT) = 0;
cloonel::SDLMain* sdl_main(); cloonel::SDLMain* sdl_main();
cloonel::InputBag& input_bag(); cloonel::InputBag& input_bag();
void draw_clipped (Texture& parTexture, Rect<float> parSrc, Rect<float> parDest);
private: private:
std::chrono::time_point<std::chrono::steady_clock> m_time0; std::chrono::time_point<std::chrono::steady_clock> m_time0;
std::unique_ptr<cloonel::InputBag> m_input; std::unique_ptr<cloonel::InputBag> m_input;
cloonel::SDLMain* m_sdlmain; cloonel::SDLMain* m_sdlmain;
float m_screen_width;
float m_screen_height;
bool m_wants_to_quit; bool m_wants_to_quit;
}; };
} //namespace curry } //namespace curry

View file

@ -7,6 +7,7 @@
#include "worldgrid.hpp" #include "worldgrid.hpp"
#include "worldviewport.hpp" #include "worldviewport.hpp"
#include "texture.hpp" #include "texture.hpp"
#include "rect.hpp"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <algorithm> #include <algorithm>
@ -18,22 +19,12 @@ namespace curry {
ActionRight, ActionRight,
ActionDown ActionDown
}; };
void clip (SDL_Rect& parSource, SDL_Rect& parDest, const vec2i& parTopLeft, const vec2i& parBotRight) {
if (parDest.x < parTopLeft.x()) {
const auto diff = parTopLeft.x() - parDest.x;
parDest.x = parTopLeft.x();
parDest.w -= diff;
parSource.x += diff;
parSource.w -= diff;
}
}
} //unnamed namespace } //unnamed namespace
struct IngameScene::LocalData { struct IngameScene::LocalData {
LocalData (const vec2us& parTileSize, const vec2us& parTileCount, cloonel::SDLMain* parSDLMain) : LocalData (const vec2us& parTileSize, const vec2us& parTileCount, cloonel::SDLMain* parSDLMain) :
world(parTileSize, parTileCount), world(parTileSize, parTileCount),
viewport(&world, vec2i(parSDLMain->WidthHeight())), viewport(&world, vec2f(parSDLMain->WidthHeight())),
player(parTileSize) player(parTileSize)
{ {
} }
@ -82,18 +73,17 @@ namespace curry {
if (cloonel::IsPressed(input_bag(), ActionDown)) if (cloonel::IsPressed(input_bag(), ActionDown))
viewport.set_position(viewport.position() + vec2f(0, speed)); viewport.set_position(viewport.position() + vec2f(0, speed));
const auto tilesize(world.tile_size()); const auto tilesize(static_cast<vec2f>(world.tile_size()));
for (auto tile : viewport) { for (auto tile : viewport) {
vec2us idx(tile.index & 1, (tile.index >> 1) & 1); vec2f idx(static_cast<float>(tile.index & 1), static_cast<float>((tile.index >> 1) & 1));
vec2us src_rect_xy = idx * tilesize; vec2f src_rect_xy = idx * tilesize;
vec2f pixel_pos = vector_cast<vec2f>(tile.pixel_pos);
//std::cout << "Drawing src " << src_rect_xy << " dst " << tile.pixel_pos << '\n'; //std::cout << "Drawing src " << src_rect_xy << " dst " << tile.pixel_pos << '\n';
SDL_Rect src{src_rect_xy.x(), src_rect_xy.y(), tilesize.x(), tilesize.y()}; Rect<float> src_rect(src_rect_xy, src_rect_xy + tilesize);
SDL_Rect dst{tile.pixel_pos.x(), tile.pixel_pos.y(), tilesize.x(), tilesize.y()}; Rect<float> dst_rect(pixel_pos, pixel_pos + tilesize);
clip(src, dst, vec2i(0), sdl_main()->WidthHeight()); this->draw_clipped(m_local_data->worldtiles, src_rect, dst_rect);
SDL_RenderCopy(this->sdl_main()->GetRenderer(), m_local_data->worldtiles.texture(), &src, &dst);
} }
SDL_RenderPresent(this->sdl_main()->GetRenderer());
} }
void IngameScene::on_destroy() noexcept { void IngameScene::on_destroy() noexcept {

62
src/rect.hpp Normal file
View file

@ -0,0 +1,62 @@
#pragma once
#include "vector.hpp"
#if !defined(NDEBUG)
# include <iostream>
#endif
namespace curry {
template <typename T>
class Rect {
public:
typedef vwr::Vec<std::array<T, 2>> VecType;
Rect (T parLeft, T parTop, T parRight, T parBottom);
template <typename V1, typename V2>
Rect (const vwr::Vec<V1>& parLeftTop, const vwr::Vec<V2>& parBottomRight);
T left() const { return from.x(); }
T top() const { return from.y(); }
T right() const { return to.x(); }
T bottom() const { return to.y(); }
T& left() { return from.x(); }
T& top() { return from.y(); }
T& right() { return to.x(); }
T& bottom() { return to.y(); }
T width() const { return right() - left(); }
T height() const { return bottom() - top(); }
VecType width_height() const { return VecType(width(), height()); }
bool is_valid() const;
VecType from;
VecType to;
};
template <typename T>
Rect<T>::Rect (T parLeft, T parTop, T parRight, T parBottom) :
from(parLeft, parTop),
to(parRight, parBottom)
{
}
template <typename T>
template <typename V1, typename V2>
Rect<T>::Rect (const vwr::Vec<V1>& parLeftTop, const vwr::Vec<V2>& parBottomRight) :
Rect(parLeftTop.x(), parLeftTop.y(), parBottomRight.x(), parBottomRight.y())
{
}
template <typename T>
bool Rect<T>::is_valid() const {
return from <= to;
}
#if !defined(NDEBUG)
template <typename T>
std::ostream& operator<< (std::ostream& parStream, const Rect<T>& parRect) {
parStream << '{' << parRect.from << '-' << parRect.to << '}';
return parStream;
}
#endif
} //namespace curry

19
src/rect_to_sdl.hpp Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "rect.hpp"
#include <SDL2/SDL.h>
#include <utility>
namespace curry {
template <typename T>
inline SDL_Rect make_sdlrect (const Rect<T>& parOther) {
typedef decltype(std::declval<SDL_Rect>().w) ValueType;
return SDL_Rect{
static_cast<ValueType>(parOther.left()),
static_cast<ValueType>(parOther.top()),
static_cast<ValueType>(parOther.width()),
static_cast<ValueType>(parOther.height())
};
}
} //namespace curry

View file

@ -3,7 +3,7 @@
#include <cassert> #include <cassert>
namespace curry { namespace curry {
WorldViewport::WorldViewport (WorldGrid* parWorld, vec2i parSize) : WorldViewport::WorldViewport (WorldGrid* parWorld, vec2f parSize) :
m_position(0), m_position(0),
m_size(parSize), m_size(parSize),
m_world(parWorld) m_world(parWorld)

View file

@ -10,7 +10,7 @@ namespace curry {
public: public:
typedef TileIterator iterator; typedef TileIterator iterator;
WorldViewport (WorldGrid* parWorld, vec2i parSize); WorldViewport (WorldGrid* parWorld, vec2f parSize);
const WorldGrid* world() const; const WorldGrid* world() const;
const vec2f& position() const; const vec2f& position() const;
const vec2f& size() const; const vec2f& size() const;