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:
parent
8a65faf45c
commit
d9a943ee4a
15 changed files with 480 additions and 100 deletions
|
@ -1 +1 @@
|
|||
Subproject commit 77e2bf539f21431d5b0b883d5113a2e396a3233e
|
||||
Subproject commit ceb3e180fee15ba3d6e7b17e8f88261b35d4ae92
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
167
src/gamelib/drawing_queue.cpp
Normal file
167
src/gamelib/drawing_queue.cpp
Normal 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
|
69
src/gamelib/drawing_queue.hpp
Normal file
69
src/gamelib/drawing_queue.hpp
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
87
src/gamelib/safe_stack_object.hpp
Normal file
87
src/gamelib/safe_stack_object.hpp
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue