Add DrawingQueue class.

Big do-it-all commit. Work on this is not finished and there
are a few changes that need to be undone. A bit messy but
that's how it is :/
This commit is contained in:
King_DuckZ 2017-03-15 09:12:16 +00:00
parent 8a65faf45c
commit d9a943ee4a
15 changed files with 480 additions and 100 deletions

@ -1 +1 @@
Subproject commit 77e2bf539f21431d5b0b883d5113a2e396a3233e
Subproject commit ceb3e180fee15ba3d6e7b17e8f88261b35d4ae92

View file

@ -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
};

View file

@ -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)

View file

@ -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<vec2f> m_position;
cloonel::InputBag* m_input_bag;

View file

@ -18,34 +18,74 @@
*/
#include "drawable.hpp"
#include "texture.hpp"
#include "safe_stack_object.hpp"
#include <utility>
#include <algorithm>
#include <ciso646>
#include <cassert>
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<vec2f>(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<Texture> 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<Texture> new_texture;
new_texture->load_empty(parSDLMain, static_cast<vec2us>(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<Texture>& 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<Texture>&& parNewTexture) {
const auto old_wh = m_width_height;
m_width_height = max_size(vector_cast<vec2f>(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

View file

@ -19,24 +19,38 @@
#pragma once
#include "texture.hpp"
#include "safe_ptr.hh"
#include "vector.hpp"
#include <vector>
namespace cloonel {
class SDLMain;
} //namespace cloonel
namespace curry {
template <typename T> 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>& texture();
virtual void draw ( DrawingQueue& parDQ, const WorldViewport& parViewport ) = 0;
private:
size_t store_new_texture (SafeStackObject<Texture>&& parNewTexture);
virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz);
Texture m_texture;
std::vector<SafeStackObject<Texture>> m_textures;
vec2f m_width_height;
};
} //namespace curry

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "drawing_queue.hpp"
#include "sdlmain.hpp"
#include "sizeratio.hpp"
#include "rect_to_sdl.hpp"
#include "texture.hpp"
#include <SDL2/SDL.h>
#include <cassert>
#include <ciso646>
#include <utility>
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<float>& parSrc, Rect<float>& parDest, const Rect<float>& parClip) {
typedef Rect<float> 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<ItemInfo> TextureList;
typedef std::vector<TextureList> 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<float> parSrc, Rect<float> parDest) {
const vec2f lefttop(0.0f);
const vec2f& rightbottom = m_local_data->screen_res;
clip_rect(parSrc, parDest, Rect<float>(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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "safe_ptr.hh"
#include "rect.hpp"
#include "sizenotifiable.hpp"
#include <memory>
namespace cloonel {
class SDLMain;
} //namespace cloonel
namespace curry {
class Texture;
class DrawingQueue : public cloonel::SizeNotifiable<cloonel::regbehaviours::AutoRegister> {
typedef cloonel::SizeNotifiable<cloonel::regbehaviours::AutoRegister> 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<float> parSrc, Rect<float> parDest);
virtual void OnResChanged ( const cloonel::SizeRatio& parSizeRatio ) override;
struct LocalData;
std::unique_ptr<LocalData> m_local_data;
};
struct DrawingQueue::ItemInfo {
ItemInfo();
ItemInfo (ItemInfo&&);
ItemInfo (const ItemInfo&) = delete;
~ItemInfo() noexcept;
ItemInfo& operator= (ItemInfo&&);
ItemInfo& operator= (const ItemInfo&) = delete;
Rect<float> source;
Rect<float> destination;
Kakoune::SafePtr<Texture> texture;
};
} //namespace curry

View file

@ -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 <cassert>
#include <SDL2/SDL.h>
#include <algorithm>
@ -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<float>& parSrc, Rect<float>& parDest, const Rect<float>& parClip) {
typedef Rect<float> 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<cloonel::InputBag>()),
m_drawing_queue(std::make_unique<DrawingQueue>(parSdlMain, cloonel::DeferredRegister())),
m_sdlmain(parSdlMain),
m_screen_width(static_cast<float>(m_sdlmain->WidthHeight().x())),
m_screen_height(static_cast<float>(m_sdlmain->WidthHeight().y())),
@ -170,6 +113,7 @@ namespace curry {
const float delta = std::chrono::duration<float>(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<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));
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

View file

@ -28,8 +28,8 @@ namespace cloonel {
} //namespace cloonel
namespace curry {
class Texture;
template <typename T> 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<float> parSrc, Rect<float> parDest);
DrawingQueue& drawing_queue();
const DrawingQueue& drawing_queue() const;
private:
std::chrono::time_point<std::chrono::steady_clock> m_time0;
std::unique_ptr<cloonel::InputBag> m_input;
std::unique_ptr<DrawingQueue> m_drawing_queue;
cloonel::SDLMain* m_sdlmain;
float m_screen_width;
float m_screen_height;

View file

@ -32,6 +32,8 @@
#include "worlditems.hpp"
#include "gameactions.hpp"
#include "vector.hpp"
#include "drawing_queue.hpp"
#include "safe_stack_object.hpp"
#include <SDL2/SDL.h>
#include <algorithm>
#include <vector>
@ -39,6 +41,7 @@
#include <boost/utility/string_ref.hpp>
#include <boost/lexical_cast.hpp>
#include <cassert>
#include <ciso646>
namespace curry {
namespace {
@ -55,10 +58,13 @@ namespace curry {
WorldGrid world;
WorldViewport viewport;
Texture worldtiles;
SafeStackObject<Texture> 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<float>(
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<vec2f>(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<float> src_rect(src_rect_xy, src_rect_xy + tilesize);
Rect<float> 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<Texture>& parTexture, Rect<float> parSrc, Rect<float> 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

View file

@ -20,13 +20,17 @@
#pragma once
#include "gamescenebase.hpp"
#include "safe_ptr.hh"
#include <memory>
#include <cstddef>
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<Texture>& parTexture, Rect<float> parSrc, Rect<float> parDest);
std::size_t layer_id_def() const;
#if !defined(NDEBUG)
std::size_t layer_id_debug() const;
#endif
private:
struct LocalData;

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "safe_ptr.hh"
#include <utility>
namespace curry {
template <typename T>
class SafeStackObject {
public:
typedef Kakoune::SafePtr<T> 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<T>&();
safe_ptr& operator*();
safe_ptr& operator->();
private:
T m_obj;
safe_ptr m_obj_ptr;
};
template <typename T>
SafeStackObject<T>::SafeStackObject() :
m_obj(),
m_obj_ptr(&m_obj)
{
}
template <typename T>
SafeStackObject<T>::SafeStackObject (SafeStackObject&& parOther) :
m_obj(std::move(parOther.m_obj)),
m_obj_ptr(&m_obj)
{
}
//template <typename T>
//SafeStackObject& SafeStackObject<T>::operator= (SafeStackObject&& parOther) {
// m_obj = std::move(parOther.m_obj);
// m_obj_ptr = std::move(parOther.m_obj_ptr);
// m_ob
//}
//template <typename T>
//SafeStackObject& SafeStackObject<T>::operator= (const SafeStackObject& parOther) {
//}
template <typename T>
SafeStackObject<T>::operator Kakoune::SafePtr<T>&() {
return m_obj_ptr;
}
template <typename T>
auto SafeStackObject<T>::operator*() -> safe_ptr& {
return m_obj_ptr;
}
template <typename T>
auto SafeStackObject<T>::operator->() -> safe_ptr& {
return m_obj_ptr;
}
} //namespace curry

View file

@ -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<int>(parSize.x()),
static_cast<int>(parSize.y())
),
&SDL_DestroyTexture
);
}
void Texture::unload() noexcept {
m_texture.reset(nullptr);
}

View file

@ -20,6 +20,7 @@
#pragma once
#include "vector.hpp"
#include "safe_ptr.hh"
#include <memory>
#include <cstdint>
@ -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;