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: public:
#ifdef KAK_DEBUG #ifdef KAK_DEBUG
SafeCountable() : m_count(0) {} SafeCountable() : m_count(0) {}
SafeCountable (SafeCountable&&) : m_count(0) {}
~SafeCountable() ~SafeCountable()
{ {
kak_assert(m_count == 0); kak_assert(m_count == 0);
@ -94,8 +95,8 @@ struct SafeCountablePolicy
#endif #endif
} }
#else #else
static void inc_ref(const SafeCountable*, void* ptr) noexcept {} static void inc_ref(const SafeCountable*, void*) noexcept {}
static void dec_ref(const SafeCountable*, void* ptr) noexcept {} static void dec_ref(const SafeCountable*, void*) noexcept {}
static void ptr_moved(const SafeCountable*, void*, void*) noexcept {} static void ptr_moved(const SafeCountable*, void*, void*) noexcept {}
#endif #endif
}; };

View file

@ -20,6 +20,7 @@ add_library(${PROJECT_NAME}
moveable.cpp moveable.cpp
grid_raytrace.cpp grid_raytrace.cpp
drawable.cpp drawable.cpp
drawing_queue.cpp
) )
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 14)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)

View file

@ -48,7 +48,7 @@ namespace curry {
void set_speed (float parSpeed); void set_speed (float parSpeed);
private: 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; ConstrainedPosition<vec2f> m_position;
cloonel::InputBag* m_input_bag; cloonel::InputBag* m_input_bag;

View file

@ -18,34 +18,74 @@
*/ */
#include "drawable.hpp" #include "drawable.hpp"
#include "texture.hpp"
#include "safe_stack_object.hpp"
#include <utility>
#include <algorithm>
#include <ciso646>
#include <cassert>
namespace curry { 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() : Drawable::Drawable() :
m_width_height(0.0f) m_width_height(0.0f)
{ {
} }
void Drawable::load (const char* parTexturePath, cloonel::SDLMain& parSDLMain) { Drawable::~Drawable() noexcept = default;
const auto old_wh = m_width_height;
m_texture.load(parTexturePath, parSDLMain); size_t Drawable::add_texture (const char* parTexturePath, cloonel::SDLMain& parSDLMain) {
m_width_height = vector_cast<vec2f>(m_texture.width_height()); SafeStackObject<Texture> new_texture;
const auto& new_wh = m_width_height; new_texture->load(parTexturePath, parSDLMain);
if (new_wh != old_wh) const auto retval = store_new_texture(std::move(new_texture));
this->on_texture_size_changed(old_wh, new_wh); return retval;
} }
void Drawable::unload() { size_t Drawable::add_texture (const vec2f& parSize, cloonel::SDLMain& parSDLMain) {
m_texture.unload(); 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 { const vec2f& Drawable::width_height() const {
return m_width_height; return m_width_height;
} }
Texture& Drawable::texture() { Kakoune::SafePtr<Texture>& Drawable::texture() {
return m_texture; assert(not m_textures.empty());
auto& retval = m_textures[0];
return retval;
} }
void Drawable::on_texture_size_changed (const vec2f&, const vec2f&) { 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 } //namespace curry

View file

@ -19,24 +19,38 @@
#pragma once #pragma once
#include "texture.hpp" #include "safe_ptr.hh"
#include "vector.hpp" #include "vector.hpp"
#include <vector>
namespace cloonel {
class SDLMain;
} //namespace cloonel
namespace curry { namespace curry {
template <typename T> class SafeStackObject;
class Texture;
class DrawingQueue;
class WorldViewport;
class Drawable { class Drawable {
public: public:
Drawable(); Drawable();
virtual ~Drawable() noexcept = default; virtual ~Drawable() noexcept;
void load (const char* parTexturePath, cloonel::SDLMain& parSDLMain); size_t add_texture (const char* parTexturePath, cloonel::SDLMain& parSDLMain);
void unload(); size_t add_texture (const vec2f& parSize, cloonel::SDLMain& parSDLMain);
void unload_textures() noexcept;
const vec2f& width_height() const; const vec2f& width_height() const;
Texture& texture(); Kakoune::SafePtr<Texture>& texture();
virtual void draw ( DrawingQueue& parDQ, const WorldViewport& parViewport ) = 0;
private: private:
size_t store_new_texture (SafeStackObject<Texture>&& parNewTexture);
virtual void on_texture_size_changed (const vec2f& parOldSz, const vec2f& parNewSz); 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; vec2f m_width_height;
}; };
} //namespace curry } //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 "gamescenebase.hpp"
#include "inputbag.hpp" #include "inputbag.hpp"
#include "sdlmain.hpp" #include "sdlmain.hpp"
#include "rect_to_sdl.hpp"
#include "rect.hpp" #include "rect.hpp"
#include "texture.hpp" #include "drawing_queue.hpp"
#include <cassert> #include <cassert>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <algorithm> #include <algorithm>
@ -34,15 +33,6 @@
namespace curry { namespace curry {
namespace { 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) { bool DoEvents (cloonel::InputBag& parInput, cloonel::SDLMain* parSdlMain) {
@ -76,59 +66,12 @@ 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(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 } //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_drawing_queue(std::make_unique<DrawingQueue>(parSdlMain, cloonel::DeferredRegister())),
m_sdlmain(parSdlMain), m_sdlmain(parSdlMain),
m_screen_width(static_cast<float>(m_sdlmain->WidthHeight().x())), m_screen_width(static_cast<float>(m_sdlmain->WidthHeight().x())),
m_screen_height(static_cast<float>(m_sdlmain->WidthHeight().y())), 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(); 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);
m_drawing_queue->flush_to_renderer();
SDL_RenderPresent(this->sdl_main()->GetRenderer()); SDL_RenderPresent(this->sdl_main()->GetRenderer());
} }
@ -181,15 +125,11 @@ namespace curry {
return *m_input; return *m_input;
} }
void GameSceneBase::draw_clipped (Texture& parTexture, Rect<float> parSrc, Rect<float> parDest) { DrawingQueue& GameSceneBase::drawing_queue() {
const vec2f lefttop(0.0f); return *m_drawing_queue;
const vec2f rightbottom(m_screen_width, m_screen_height); }
clip_rect(parSrc, parDest, Rect<float>(lefttop, rightbottom));
auto src = make_sdlrect(parSrc); const DrawingQueue& GameSceneBase::drawing_queue() const {
auto dst = make_sdlrect(parDest); return *m_drawing_queue;
assert(src.w == dst.w);
assert(src.h == dst.h);
SDL_RenderCopy(m_sdlmain->GetRenderer(), parTexture.texture(), &src, &dst);
} }
} //namespace curry } //namespace curry

View file

@ -28,8 +28,8 @@ namespace cloonel {
} //namespace cloonel } //namespace cloonel
namespace curry { namespace curry {
class Texture;
template <typename T> class Rect; template <typename T> class Rect;
class DrawingQueue;
class GameSceneBase { class GameSceneBase {
public: public:
@ -50,11 +50,13 @@ 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); DrawingQueue& drawing_queue();
const DrawingQueue& drawing_queue() const;
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;
std::unique_ptr<DrawingQueue> m_drawing_queue;
cloonel::SDLMain* m_sdlmain; cloonel::SDLMain* m_sdlmain;
float m_screen_width; float m_screen_width;
float m_screen_height; float m_screen_height;

View file

@ -32,6 +32,8 @@
#include "worlditems.hpp" #include "worlditems.hpp"
#include "gameactions.hpp" #include "gameactions.hpp"
#include "vector.hpp" #include "vector.hpp"
#include "drawing_queue.hpp"
#include "safe_stack_object.hpp"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
@ -39,6 +41,7 @@
#include <boost/utility/string_ref.hpp> #include <boost/utility/string_ref.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <cassert> #include <cassert>
#include <ciso646>
namespace curry { namespace curry {
namespace { namespace {
@ -55,10 +58,13 @@ namespace curry {
WorldGrid world; WorldGrid world;
WorldViewport viewport; WorldViewport viewport;
Texture worldtiles; SafeStackObject<Texture> worldtiles;
MovingObject player; MovingObject player;
Character character; Character character;
WorldItems moveable_items; WorldItems moveable_items;
#if !defined(NDEBUG)
std::size_t debug_layer_id;
#endif
}; };
IngameScene::IngameScene (cloonel::SDLMain* parSDLMain) : IngameScene::IngameScene (cloonel::SDLMain* parSDLMain) :
@ -73,12 +79,18 @@ namespace curry {
inp.AddAction(ActionUp, Key(InputDevice_Keyboard, SDL_SCANCODE_UP), "Move up"); inp.AddAction(ActionUp, Key(InputDevice_Keyboard, SDL_SCANCODE_UP), "Move up");
inp.AddAction(ActionRight, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right"); inp.AddAction(ActionRight, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right");
inp.AddAction(ActionDown, Key(InputDevice_Keyboard, SDL_SCANCODE_DOWN), "Move down"); 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; IngameScene::~IngameScene() noexcept = default;
void IngameScene::on_prepare() { 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({ CSVJointData tiles = load_csv({
RESOURCES_PATH "nonfree_map_ground.csv", RESOURCES_PATH "nonfree_map_ground.csv",
RESOURCES_PATH "nonfree_map_transparent.csv" RESOURCES_PATH "nonfree_map_transparent.csv"
@ -92,7 +104,7 @@ namespace curry {
#endif #endif
m_local_data->viewport.allow_overscan(false); 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 = const float speed_per_sec =
static_cast<float>( static_cast<float>(
std::max(m_local_data->world.tile_size().x(), m_local_data->world.tile_size().y()) 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); 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); 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 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 (auto tile : viewport) {
for (uint16_t z = 0; z < m_local_data->world.layer_count(); ++z) { for (uint16_t z = 0; z < m_local_data->world.layer_count(); ++z) {
if (tile.index[z] < 0) if (tile.index[z] < 0)
@ -122,15 +135,34 @@ namespace curry {
Rect<float> src_rect(src_rect_xy, src_rect_xy + tilesize); Rect<float> src_rect(src_rect_xy, src_rect_xy + tilesize);
Rect<float> dst_rect(pixel_pos, pixel_pos + 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 { void IngameScene::on_destroy() noexcept {
m_local_data->moveable_items.unregister_all(); m_local_data->moveable_items.unregister_all();
m_local_data->worldtiles.unload(); m_local_data->worldtiles->unload();
m_local_data->character.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 } //namespace curry

View file

@ -20,13 +20,17 @@
#pragma once #pragma once
#include "gamescenebase.hpp" #include "gamescenebase.hpp"
#include "safe_ptr.hh"
#include <memory> #include <memory>
#include <cstddef>
namespace cloonel { namespace cloonel {
class SDLMain; class SDLMain;
} //namespace cloonel } //namespace cloonel
namespace curry { namespace curry {
class Texture;
class IngameScene : public GameSceneBase { class IngameScene : public GameSceneBase {
public: public:
explicit IngameScene (cloonel::SDLMain* parSDLMain); explicit IngameScene (cloonel::SDLMain* parSDLMain);
@ -36,6 +40,11 @@ namespace curry {
virtual void on_prepare() override; virtual void on_prepare() override;
virtual void on_destroy() noexcept override; virtual void on_destroy() noexcept override;
virtual void on_update (float parDeltaT) 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: private:
struct LocalData; 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); 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 { void Texture::unload() noexcept {
m_texture.reset(nullptr); m_texture.reset(nullptr);
} }

View file

@ -20,6 +20,7 @@
#pragma once #pragma once
#include "vector.hpp" #include "vector.hpp"
#include "safe_ptr.hh"
#include <memory> #include <memory>
#include <cstdint> #include <cstdint>
@ -37,14 +38,17 @@ namespace curry {
uint8_t a; uint8_t a;
}; };
class Texture { class Texture : public Kakoune::SafeCountable {
public: public:
Texture(); Texture();
Texture (const char* parPath, cloonel::SDLMain& parSDLMain); Texture (const char* parPath, cloonel::SDLMain& parSDLMain);
Texture (Texture&&) = default;
Texture (const Texture&) = delete;
~Texture() noexcept; ~Texture() noexcept;
void load (const char* parPath, cloonel::SDLMain& parSDLMain); void load (const char* parPath, cloonel::SDLMain& parSDLMain);
void load (const char* parPath, cloonel::SDLMain& parSDLMain, RGBA parColorKey); void load (const char* parPath, cloonel::SDLMain& parSDLMain, RGBA parColorKey);
void load_empty (cloonel::SDLMain& parSDLMain, const vec2us& parSize);
void unload() noexcept; void unload() noexcept;
SDL_Texture* texture(); SDL_Texture* texture();
const SDL_Texture* texture() const; const SDL_Texture* texture() const;