diff --git a/lib/clooneljump b/lib/clooneljump index 77e2bf5..ceb3e18 160000 --- a/lib/clooneljump +++ b/lib/clooneljump @@ -1 +1 @@ -Subproject commit 77e2bf539f21431d5b0b883d5113a2e396a3233e +Subproject commit ceb3e180fee15ba3d6e7b17e8f88261b35d4ae92 diff --git a/lib/kakoune/safe_ptr.hh b/lib/kakoune/safe_ptr.hh index 2b3d2b1..36aa80d 100644 --- a/lib/kakoune/safe_ptr.hh +++ b/lib/kakoune/safe_ptr.hh @@ -29,6 +29,7 @@ class SafeCountable public: #ifdef KAK_DEBUG SafeCountable() : m_count(0) {} + SafeCountable (SafeCountable&&) : m_count(0) {} ~SafeCountable() { kak_assert(m_count == 0); @@ -94,8 +95,8 @@ struct SafeCountablePolicy #endif } #else - static void inc_ref(const SafeCountable*, void* ptr) noexcept {} - static void dec_ref(const SafeCountable*, void* ptr) noexcept {} + static void inc_ref(const SafeCountable*, void*) noexcept {} + static void dec_ref(const SafeCountable*, void*) noexcept {} static void ptr_moved(const SafeCountable*, void*, void*) noexcept {} #endif }; diff --git a/src/gamelib/CMakeLists.txt b/src/gamelib/CMakeLists.txt index 2433b8e..aa5832a 100644 --- a/src/gamelib/CMakeLists.txt +++ b/src/gamelib/CMakeLists.txt @@ -20,6 +20,7 @@ add_library(${PROJECT_NAME} moveable.cpp grid_raytrace.cpp drawable.cpp + drawing_queue.cpp ) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) diff --git a/src/gamelib/character.hpp b/src/gamelib/character.hpp index cb91aa8..63e6ca2 100644 --- a/src/gamelib/character.hpp +++ b/src/gamelib/character.hpp @@ -48,7 +48,7 @@ namespace curry { void set_speed (float parSpeed); private: - virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz); + virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz) override; ConstrainedPosition m_position; cloonel::InputBag* m_input_bag; diff --git a/src/gamelib/drawable.cpp b/src/gamelib/drawable.cpp index b3a60af..7032e3b 100644 --- a/src/gamelib/drawable.cpp +++ b/src/gamelib/drawable.cpp @@ -18,34 +18,74 @@ */ #include "drawable.hpp" +#include "texture.hpp" +#include "safe_stack_object.hpp" +#include +#include +#include +#include namespace curry { + namespace { + vec2f max_size (const vec2f& parA, const vec2f& parB) { + return vec2f( + std::max(parA.x(), parB.x()), + std::max(parA.y(), parB.y()) + ); + } + } //unnamed namespace + Drawable::Drawable() : m_width_height(0.0f) { } - void Drawable::load (const char* parTexturePath, cloonel::SDLMain& parSDLMain) { - const auto old_wh = m_width_height; - m_texture.load(parTexturePath, parSDLMain); - m_width_height = vector_cast(m_texture.width_height()); - const auto& new_wh = m_width_height; - if (new_wh != old_wh) - this->on_texture_size_changed(old_wh, new_wh); + Drawable::~Drawable() noexcept = default; + + size_t Drawable::add_texture (const char* parTexturePath, cloonel::SDLMain& parSDLMain) { + SafeStackObject new_texture; + new_texture->load(parTexturePath, parSDLMain); + const auto retval = store_new_texture(std::move(new_texture)); + return retval; } - void Drawable::unload() { - m_texture.unload(); + size_t Drawable::add_texture (const vec2f& parSize, cloonel::SDLMain& parSDLMain) { + assert(parSize > 0.0f); + SafeStackObject new_texture; + new_texture->load_empty(parSDLMain, static_cast(parSize)); + const auto retval = store_new_texture(std::move(new_texture)); + return retval; + } + + void Drawable::unload_textures() noexcept { + for (auto& tex : m_textures) { + tex->unload(); + } + m_textures.clear(); } const vec2f& Drawable::width_height() const { return m_width_height; } - Texture& Drawable::texture() { - return m_texture; + Kakoune::SafePtr& Drawable::texture() { + assert(not m_textures.empty()); + auto& retval = m_textures[0]; + return retval; } void Drawable::on_texture_size_changed (const vec2f&, const vec2f&) { } + + size_t Drawable::store_new_texture (SafeStackObject&& parNewTexture) { + const auto old_wh = m_width_height; + m_width_height = max_size(vector_cast(parNewTexture->width_height()), old_wh); + const auto& new_wh = m_width_height; + if (new_wh != old_wh) + this->on_texture_size_changed(old_wh, new_wh); + + m_textures.push_back(std::move(parNewTexture)); + assert(m_textures.size() > 0); + return m_textures.size() - 1; + } } //namespace curry diff --git a/src/gamelib/drawable.hpp b/src/gamelib/drawable.hpp index c0d7735..a312b02 100644 --- a/src/gamelib/drawable.hpp +++ b/src/gamelib/drawable.hpp @@ -19,24 +19,38 @@ #pragma once -#include "texture.hpp" +#include "safe_ptr.hh" #include "vector.hpp" +#include + +namespace cloonel { + class SDLMain; +} //namespace cloonel namespace curry { + template class SafeStackObject; + class Texture; + class DrawingQueue; + class WorldViewport; + class Drawable { public: Drawable(); - virtual ~Drawable() noexcept = default; + virtual ~Drawable() noexcept; - void load (const char* parTexturePath, cloonel::SDLMain& parSDLMain); - void unload(); + size_t add_texture (const char* parTexturePath, cloonel::SDLMain& parSDLMain); + size_t add_texture (const vec2f& parSize, cloonel::SDLMain& parSDLMain); + + void unload_textures() noexcept; const vec2f& width_height() const; - Texture& texture(); + Kakoune::SafePtr& texture(); + virtual void draw ( DrawingQueue& parDQ, const WorldViewport& parViewport ) = 0; private: + size_t store_new_texture (SafeStackObject&& parNewTexture); virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz); - Texture m_texture; + std::vector> m_textures; vec2f m_width_height; }; } //namespace curry diff --git a/src/gamelib/drawing_queue.cpp b/src/gamelib/drawing_queue.cpp new file mode 100644 index 0000000..053a7f9 --- /dev/null +++ b/src/gamelib/drawing_queue.cpp @@ -0,0 +1,167 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#include "drawing_queue.hpp" +#include "sdlmain.hpp" +#include "sizeratio.hpp" +#include "rect_to_sdl.hpp" +#include "texture.hpp" +#include +#include +#include +#include + +namespace curry { + namespace { +#if !defined(NDEBUG) + bool are_equal_rel (float parA, float parB, float parEpsilon) a_pure; + + //see: http://stackoverflow.com/questions/4548004/how-to-correctly-and-standardly-compare-floats + bool are_equal_rel (float parA, float parB, float parEpsilon) { + return (std::fabs(parA - parB) <= parEpsilon * std::max(std::fabs(parA), std::fabs(parB))); + } +#endif + + ///---------------------------------------------------------------------- + ///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& parSrc, Rect& parDest, const Rect& parClip) { + typedef Rect RectFloat; + assert(are_equal_rel(parSrc.width(), parDest.width(), 0.00001f)); + 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; + + RectFloat dst; + dst.from.x() = std::max(parDest.from.x(), parClip.from.x()); + dst.from.y() = std::max(parDest.from.y(), parClip.from.y()); + dst.to.x() = std::min(parDest.to.x(), parClip.to.x()); + dst.to.y() = std::min(parDest.to.y(), parClip.to.y()); + + if (not dst.is_valid()) + return false; + + assert(parDest.from <= dst.from); + assert(parDest.to >= dst.to); + + RectFloat src; + { + const vec2f srcWidthHeight(parSrc.width_height()); + const vec2f scaledOffs((dst.from - parDest.from) / parDest.width_height()); + src.from = parSrc.from + scaledOffs * srcWidthHeight; + const vec2f scaledCrop((parDest.to - dst.to) / parDest.width_height()); + src.to = parSrc.to - scaledCrop * srcWidthHeight; + assert(src.is_valid()); + + assert(dst.is_valid()); + assert(dst.from >= parClip.from); + assert(dst.to <= parClip.to); + assert(are_equal_rel(src.width(), dst.width(), 0.00001f)); + } + parDest = dst; + parSrc = src; + return true; + } + } //unnamed namespace + + DrawingQueue::ItemInfo::ItemInfo() = default; + DrawingQueue::ItemInfo::ItemInfo (ItemInfo&&) = default; + DrawingQueue::ItemInfo::~ItemInfo() noexcept = default; + DrawingQueue::ItemInfo& DrawingQueue::ItemInfo::operator=(ItemInfo&&) = default; + + struct DrawingQueue::LocalData { + typedef std::vector TextureList; + typedef std::vector LayerList; + + explicit LocalData (cloonel::SDLMain* parSDLMain) : + sdlmain(parSDLMain), + screen_res(0.0f), + def_layer_id(0) + { + } + + LayerList layers; + cloonel::SDLMain* sdlmain; + vec2f screen_res; + std::size_t def_layer_id; + }; + + DrawingQueue::DrawingQueue (cloonel::SDLMain* parSDLMain, const cloonel::DeferredRegister& parDeferredRegister) : + SizeNotifiableBase(parSDLMain, parDeferredRegister), + m_local_data(new LocalData(parSDLMain)) + { + assert(parSDLMain); + } + + DrawingQueue::~DrawingQueue() noexcept = default; + + std::size_t DrawingQueue::add_layer() { + m_local_data->layers.push_back(LocalData::TextureList()); + return m_local_data->layers.size() - 1; + } + + std::size_t DrawingQueue::default_layer_id() const { + return m_local_data->def_layer_id; + } + + void DrawingQueue::flush_to_renderer() { + assert(not m_local_data->layers.empty()); + for (auto& layer : m_local_data->layers) { + for (auto& itm : layer) { + draw_clipped(*itm.texture, itm.source, itm.destination); + } + layer.clear(); + } + } + + void DrawingQueue::add_for_rendering (std::size_t parLayer, ItemInfo&& parItem) { + auto& layers = m_local_data->layers; + assert(parLayer < layers.size()); + assert(parItem.source.is_valid()); + assert(parItem.destination.is_valid()); + assert(parItem.texture); + layers[parLayer].push_back(std::move(parItem)); + assert(not layers[parLayer].empty()); + assert(layers[parLayer].back().source.is_valid()); + assert(layers[parLayer].back().destination.is_valid()); + } + + void DrawingQueue::draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest) { + const vec2f lefttop(0.0f); + const vec2f& rightbottom = m_local_data->screen_res; + clip_rect(parSrc, parDest, Rect(lefttop, rightbottom)); + + auto src = make_sdlrect(parSrc); + auto dst = make_sdlrect(parDest); + assert(src.w == dst.w); + assert(src.h == dst.h); + SDL_RenderCopy(m_local_data->sdlmain->GetRenderer(), parTexture.texture(), &src, &dst); + } + + void DrawingQueue::OnResChanged (const cloonel::SizeRatio& parSizeRatio) { + m_local_data->screen_res = vec2f(cl_vec2us(parSizeRatio.Resolution())); + } +} //namespace curry diff --git a/src/gamelib/drawing_queue.hpp b/src/gamelib/drawing_queue.hpp new file mode 100644 index 0000000..a89b97d --- /dev/null +++ b/src/gamelib/drawing_queue.hpp @@ -0,0 +1,69 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#pragma once + +#include "safe_ptr.hh" +#include "rect.hpp" +#include "sizenotifiable.hpp" +#include + +namespace cloonel { + class SDLMain; +} //namespace cloonel + +namespace curry { + class Texture; + + class DrawingQueue : public cloonel::SizeNotifiable { + typedef cloonel::SizeNotifiable SizeNotifiableBase; + public: + struct ItemInfo; + + DrawingQueue (cloonel::SDLMain* parSDLMain, const cloonel::DeferredRegister& parDeferredRegister); + virtual ~DrawingQueue() noexcept; + + std::size_t add_layer(); + std::size_t default_layer_id() const; + void flush_to_renderer(); + void add_for_rendering (std::size_t parLayer, ItemInfo&& parItem); + + private: + void draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest); + virtual void OnResChanged ( const cloonel::SizeRatio& parSizeRatio ) override; + + struct LocalData; + + std::unique_ptr m_local_data; + }; + + struct DrawingQueue::ItemInfo { + ItemInfo(); + ItemInfo (ItemInfo&&); + ItemInfo (const ItemInfo&) = delete; + ~ItemInfo() noexcept; + + ItemInfo& operator= (ItemInfo&&); + ItemInfo& operator= (const ItemInfo&) = delete; + + Rect source; + Rect destination; + Kakoune::SafePtr texture; + }; +} //namespace curry diff --git a/src/gamelib/gamescenebase.cpp b/src/gamelib/gamescenebase.cpp index 340a06f..7d01b2a 100644 --- a/src/gamelib/gamescenebase.cpp +++ b/src/gamelib/gamescenebase.cpp @@ -20,9 +20,8 @@ #include "gamescenebase.hpp" #include "inputbag.hpp" #include "sdlmain.hpp" -#include "rect_to_sdl.hpp" #include "rect.hpp" -#include "texture.hpp" +#include "drawing_queue.hpp" #include #include #include @@ -34,15 +33,6 @@ namespace curry { namespace { -#if !defined(NDEBUG) - bool are_equal_rel (float parA, float parB, float parEpsilon) a_pure; - - //see: http://stackoverflow.com/questions/4548004/how-to-correctly-and-standardly-compare-floats - bool are_equal_rel (float parA, float parB, float parEpsilon) { - return (std::fabs(parA - parB) <= parEpsilon * std::max(std::fabs(parA), std::fabs(parB))); - } -#endif - ///--------------------------------------------------------------------- ///--------------------------------------------------------------------- bool DoEvents (cloonel::InputBag& parInput, cloonel::SDLMain* parSdlMain) { @@ -76,59 +66,12 @@ namespace curry { } 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& parSrc, Rect& parDest, const Rect& parClip) { - typedef Rect RectFloat; - assert(are_equal_rel(parSrc.width(), parDest.width(), 0.00001f)); - 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; - - RectFloat dst; - dst.from.x() = std::max(parDest.from.x(), parClip.from.x()); - dst.from.y() = std::max(parDest.from.y(), parClip.from.y()); - dst.to.x() = std::min(parDest.to.x(), parClip.to.x()); - dst.to.y() = std::min(parDest.to.y(), parClip.to.y()); - - if (not dst.is_valid()) - return false; - - assert(parDest.from <= dst.from); - assert(parDest.to >= dst.to); - - RectFloat src; - { - const vec2f srcWidthHeight(parSrc.width_height()); - const vec2f scaledOffs((dst.from - parDest.from) / parDest.width_height()); - src.from = parSrc.from + scaledOffs * srcWidthHeight; - const vec2f scaledCrop((parDest.to - dst.to) / parDest.width_height()); - src.to = parSrc.to - scaledCrop * srcWidthHeight; - assert(src.is_valid()); - - assert(dst.is_valid()); - assert(dst.from >= parClip.from); - assert(dst.to <= parClip.to); - assert(are_equal_rel(src.width(), dst.width(), 0.00001f)); - } - parDest = dst; - parSrc = src; - return true; - } } //unnamed namespace GameSceneBase::GameSceneBase (cloonel::SDLMain* parSdlMain) : m_time0(std::chrono::steady_clock::now()), m_input(std::make_unique()), + m_drawing_queue(std::make_unique(parSdlMain, cloonel::DeferredRegister())), m_sdlmain(parSdlMain), m_screen_width(static_cast(m_sdlmain->WidthHeight().x())), m_screen_height(static_cast(m_sdlmain->WidthHeight().y())), @@ -170,6 +113,7 @@ namespace curry { const float delta = std::chrono::duration(time1 - m_time0).count(); m_time0 = time1; this->on_update(delta); + m_drawing_queue->flush_to_renderer(); SDL_RenderPresent(this->sdl_main()->GetRenderer()); } @@ -181,15 +125,11 @@ namespace curry { return *m_input; } - void GameSceneBase::draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest) { - const vec2f lefttop(0.0f); - const vec2f rightbottom(m_screen_width, m_screen_height); - clip_rect(parSrc, parDest, Rect(lefttop, rightbottom)); + DrawingQueue& GameSceneBase::drawing_queue() { + return *m_drawing_queue; + } - auto src = make_sdlrect(parSrc); - auto dst = make_sdlrect(parDest); - assert(src.w == dst.w); - assert(src.h == dst.h); - SDL_RenderCopy(m_sdlmain->GetRenderer(), parTexture.texture(), &src, &dst); + const DrawingQueue& GameSceneBase::drawing_queue() const { + return *m_drawing_queue; } } //namespace curry diff --git a/src/gamelib/gamescenebase.hpp b/src/gamelib/gamescenebase.hpp index f5e072f..d92599f 100644 --- a/src/gamelib/gamescenebase.hpp +++ b/src/gamelib/gamescenebase.hpp @@ -28,8 +28,8 @@ namespace cloonel { } //namespace cloonel namespace curry { - class Texture; template class Rect; + class DrawingQueue; class GameSceneBase { public: @@ -50,11 +50,13 @@ namespace curry { virtual void on_update (float parDeltaT) = 0; cloonel::SDLMain* sdl_main(); cloonel::InputBag& input_bag(); - void draw_clipped (Texture& parTexture, Rect parSrc, Rect parDest); + DrawingQueue& drawing_queue(); + const DrawingQueue& drawing_queue() const; private: std::chrono::time_point m_time0; std::unique_ptr m_input; + std::unique_ptr m_drawing_queue; cloonel::SDLMain* m_sdlmain; float m_screen_width; float m_screen_height; diff --git a/src/gamelib/ingamescene.cpp b/src/gamelib/ingamescene.cpp index 30e8ded..aed8d9b 100644 --- a/src/gamelib/ingamescene.cpp +++ b/src/gamelib/ingamescene.cpp @@ -32,6 +32,8 @@ #include "worlditems.hpp" #include "gameactions.hpp" #include "vector.hpp" +#include "drawing_queue.hpp" +#include "safe_stack_object.hpp" #include #include #include @@ -39,6 +41,7 @@ #include #include #include +#include namespace curry { namespace { @@ -55,10 +58,13 @@ namespace curry { WorldGrid world; WorldViewport viewport; - Texture worldtiles; + SafeStackObject worldtiles; MovingObject player; Character character; WorldItems moveable_items; +#if !defined(NDEBUG) + std::size_t debug_layer_id; +#endif }; IngameScene::IngameScene (cloonel::SDLMain* parSDLMain) : @@ -73,12 +79,18 @@ namespace curry { inp.AddAction(ActionUp, Key(InputDevice_Keyboard, SDL_SCANCODE_UP), "Move up"); inp.AddAction(ActionRight, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right"); inp.AddAction(ActionDown, Key(InputDevice_Keyboard, SDL_SCANCODE_DOWN), "Move down"); +#if !defined(NDEBUG) + //TODO: client code should be able to register named layers so other + //parts of the code can try and request a layer without the need to pass + //dynamic ids around + m_local_data->debug_layer_id = drawing_queue().add_layer(); +#endif } IngameScene::~IngameScene() noexcept = default; void IngameScene::on_prepare() { - m_local_data->worldtiles.load(RESOURCES_PATH "nonfree_texture.png", *this->sdl_main(), RGBA{255, 255, 255, 0}); + m_local_data->worldtiles->load(RESOURCES_PATH "nonfree_texture.png", *this->sdl_main(), RGBA{255, 255, 255, 0}); CSVJointData tiles = load_csv({ RESOURCES_PATH "nonfree_map_ground.csv", RESOURCES_PATH "nonfree_map_transparent.csv" @@ -92,7 +104,7 @@ namespace curry { #endif m_local_data->viewport.allow_overscan(false); - m_local_data->character.load(RESOURCES_PATH "LPC_Sara_Preview.png", *this->sdl_main()); + m_local_data->character.add_texture(RESOURCES_PATH "LPC_Sara_Preview.png", *this->sdl_main()); const float speed_per_sec = static_cast( std::max(m_local_data->world.tile_size().x(), m_local_data->world.tile_size().y()) @@ -110,8 +122,9 @@ namespace curry { m_local_data->moveable_items.move_items(parDeltaT); viewport.set_position(m_local_data->character.position() - (viewport.size() - m_local_data->character.width_height()) / 2.0f); + //TODO: move drawing code into the world map or something const auto tilesize(static_cast(world.tile_size())); - const auto tilecount(m_local_data->worldtiles.width_height() / world.tile_size()); + const auto tilecount(m_local_data->worldtiles->width_height() / world.tile_size()); for (auto tile : viewport) { for (uint16_t z = 0; z < m_local_data->world.layer_count(); ++z) { if (tile.index[z] < 0) @@ -122,15 +135,34 @@ namespace curry { Rect src_rect(src_rect_xy, src_rect_xy + tilesize); Rect dst_rect(pixel_pos, pixel_pos + tilesize); - this->draw_clipped(m_local_data->worldtiles, src_rect, dst_rect); + this->draw(layer_id_def(), m_local_data->worldtiles, src_rect, dst_rect); } } - this->draw_clipped(m_local_data->character.texture(), m_local_data->character.source_rect(), m_local_data->character.destination_rect(viewport.position())); + this->draw(layer_id_def(), m_local_data->character.texture(), m_local_data->character.source_rect(), m_local_data->character.destination_rect(viewport.position())); } void IngameScene::on_destroy() noexcept { m_local_data->moveable_items.unregister_all(); - m_local_data->worldtiles.unload(); - m_local_data->character.unload(); + m_local_data->worldtiles->unload(); + m_local_data->character.unload_textures(); } + + void IngameScene::draw (std::size_t parLayer, Kakoune::SafePtr& parTexture, Rect parSrc, Rect parDest) { + DrawingQueue::ItemInfo item{}; + item.source = parSrc; + item.destination = parDest; + item.texture = parTexture; + drawing_queue().add_for_rendering(parLayer, std::move(item)); + assert(not item.texture); + } + + std::size_t IngameScene::layer_id_def() const { + return drawing_queue().default_layer_id(); + } + +#if !defined(NDEBUG) + std::size_t IngameScene::layer_id_debug() const { + return m_local_data->debug_layer_id; + } +#endif } //namespace curry diff --git a/src/gamelib/ingamescene.hpp b/src/gamelib/ingamescene.hpp index 55c8900..008433d 100644 --- a/src/gamelib/ingamescene.hpp +++ b/src/gamelib/ingamescene.hpp @@ -20,13 +20,17 @@ #pragma once #include "gamescenebase.hpp" +#include "safe_ptr.hh" #include +#include namespace cloonel { class SDLMain; } //namespace cloonel namespace curry { + class Texture; + class IngameScene : public GameSceneBase { public: explicit IngameScene (cloonel::SDLMain* parSDLMain); @@ -36,6 +40,11 @@ namespace curry { virtual void on_prepare() override; virtual void on_destroy() noexcept override; virtual void on_update (float parDeltaT) override; + void draw (std::size_t parLayer, Kakoune::SafePtr& parTexture, Rect parSrc, Rect parDest); + std::size_t layer_id_def() const; +#if !defined(NDEBUG) + std::size_t layer_id_debug() const; +#endif private: struct LocalData; diff --git a/src/gamelib/safe_stack_object.hpp b/src/gamelib/safe_stack_object.hpp new file mode 100644 index 0000000..f9e0439 --- /dev/null +++ b/src/gamelib/safe_stack_object.hpp @@ -0,0 +1,87 @@ +/* + Copyright 2016, 2017 Michele "King_DuckZ" Santullo + + This file is part of MyCurry. + + MyCurry is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + MyCurry is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with MyCurry. If not, see . +*/ + +#pragma once + +#include "safe_ptr.hh" +#include + +namespace curry { + template + class SafeStackObject { + public: + typedef Kakoune::SafePtr safe_ptr; + + SafeStackObject(); + SafeStackObject (SafeStackObject&& parOther); + SafeStackObject (const SafeStackObject& parOther) = delete; + ~SafeStackObject() noexcept = default; + + SafeStackObject& operator= (SafeStackObject&& parOther) = delete; + SafeStackObject& operator= (const SafeStackObject& parOther) = delete; + + operator Kakoune::SafePtr&(); + safe_ptr& operator*(); + safe_ptr& operator->(); + + private: + T m_obj; + safe_ptr m_obj_ptr; + }; + + template + SafeStackObject::SafeStackObject() : + m_obj(), + m_obj_ptr(&m_obj) + { + } + + template + SafeStackObject::SafeStackObject (SafeStackObject&& parOther) : + m_obj(std::move(parOther.m_obj)), + m_obj_ptr(&m_obj) + { + } + + //template + //SafeStackObject& SafeStackObject::operator= (SafeStackObject&& parOther) { + // m_obj = std::move(parOther.m_obj); + // m_obj_ptr = std::move(parOther.m_obj_ptr); + // m_ob + //} + + //template + //SafeStackObject& SafeStackObject::operator= (const SafeStackObject& parOther) { + //} + + template + SafeStackObject::operator Kakoune::SafePtr&() { + return m_obj_ptr; + } + + template + auto SafeStackObject::operator*() -> safe_ptr& { + return m_obj_ptr; + } + + template + auto SafeStackObject::operator->() -> safe_ptr& { + return m_obj_ptr; + } +} //namespace curry diff --git a/src/gamelib/texture.cpp b/src/gamelib/texture.cpp index 2eba3ea..8a040c2 100644 --- a/src/gamelib/texture.cpp +++ b/src/gamelib/texture.cpp @@ -73,6 +73,20 @@ namespace curry { m_texture = load_texture(parPath, parSDLMain, true, parColorKey); } + void Texture::load_empty (cloonel::SDLMain& parSDLMain, const vec2us& parSize) { + assert(parSize > 0); + m_texture = SDLTextureAuto( + SDL_CreateTexture( + parSDLMain.GetRenderer(), + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_TARGET, + static_cast(parSize.x()), + static_cast(parSize.y()) + ), + &SDL_DestroyTexture + ); + } + void Texture::unload() noexcept { m_texture.reset(nullptr); } diff --git a/src/gamelib/texture.hpp b/src/gamelib/texture.hpp index f6a2003..12ab27c 100644 --- a/src/gamelib/texture.hpp +++ b/src/gamelib/texture.hpp @@ -20,6 +20,7 @@ #pragma once #include "vector.hpp" +#include "safe_ptr.hh" #include #include @@ -37,14 +38,17 @@ namespace curry { uint8_t a; }; - class Texture { + class Texture : public Kakoune::SafeCountable { public: Texture(); Texture (const char* parPath, cloonel::SDLMain& parSDLMain); + Texture (Texture&&) = default; + Texture (const Texture&) = delete; ~Texture() noexcept; void load (const char* parPath, cloonel::SDLMain& parSDLMain); void load (const char* parPath, cloonel::SDLMain& parSDLMain, RGBA parColorKey); + void load_empty (cloonel::SDLMain& parSDLMain, const vec2us& parSize); void unload() noexcept; SDL_Texture* texture(); const SDL_Texture* texture() const;