diff --git a/src/texture.cpp b/src/texture.cpp index 43966c7..5d3379b 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -65,11 +65,48 @@ namespace cloonel { GraphicFormat enumvalue; }; + struct RectFloat { + float2 from; + float2 to; + + RectFloat ( void ) = default; + RectFloat ( const RectFloat& parOther ) : + from(parOther.from), + to(parOther.to) + { + assert(IsValid()); + } + + RectFloat ( const SDL_Rect& parRect ) : + from(static_cast(parRect.x), static_cast(parRect.y)), + to(static_cast(parRect.x + parRect.w), static_cast(parRect.y + parRect.h)) + { + assert(IsValid()); + } + + RectFloat ( const float2& parFrom, const float2& parTo ) : + from(parFrom), + to(parTo) + { + assert(IsValid()); + } + + ~RectFloat ( void ) noexcept = default; + + operator SDL_Rect ( void ) const noexcept { return { static_cast(from.x()), static_cast(from.y()), static_cast(Width()), static_cast(Height()) }; } + + float Width ( void ) const noexcept { return to.x() - from.x(); } + float Height ( void ) const noexcept { return to.y() - from.y(); } + float2 WidthHeight ( void ) const noexcept { return float2(Width(), Height()); } + bool IsValid ( void ) const noexcept { return from <= to; } + }; + const GraphicFormatItem g_graphicFormatItems[] = { {".png", 4, GraphicFormat_Png} }; GraphicFormat GuessGraphicFormatFromName (const std::string& parPath) __attribute__((pure)); + bool ClipRect ( RectFloat& parSrc, RectFloat& parDest, const RectFloat& parClip ); ///---------------------------------------------------------------------- ///---------------------------------------------------------------------- @@ -210,6 +247,47 @@ namespace cloonel { return retSurf; } + + ///---------------------------------------------------------------------- + ///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 ClipRect (RectFloat& parSrc, RectFloat& parDest, const RectFloat& parClip) { + assert(parSrc.IsValid()); + assert(parDest.IsValid()); + + //If the dest rect is completely out of the clipping region, there + //is nothing to do at all. + if (parDest.to <= parClip.from or parDest.from >= parClip.to) + return false; + + { + const RectFloat clip(float2(0.0f), float2(1.0f)); + const float2 srcWidthHeight(parSrc.WidthHeight()); + const float2 scaledOffs((parDest.from - parClip.from) / parClip.WidthHeight()); + parSrc.from -= float2(std::min(0.0f, scaledOffs.x() * srcWidthHeight.x()), std::min(0.0f, scaledOffs.y() * srcWidthHeight.y())); + const float2 scaledCrop((parClip.to - parDest.to) / parClip.WidthHeight()); + parSrc.to += float2(std::min(0.0f, scaledCrop.x() * srcWidthHeight.x()), std::min(0.0f, scaledCrop.y() * srcWidthHeight.y())); + assert(parSrc.IsValid()); + } + + RectFloat dst(parDest.from - parClip.from, parDest.to - parClip.from); + dst.from.x() = std::max(dst.from.x(), parClip.from.x()); + dst.from.y() = std::max(dst.from.y(), parClip.from.y()); + dst.to.x() = std::min(dst.to.x(), parClip.to.x()); + dst.to.y() = std::min(dst.to.y(), parClip.to.y()); + + if (not dst.IsValid()) + return false; + + parDest.from += parClip.from; + parDest.to += parClip.from; + + assert(parDest.IsValid()); + return true; + } } //unnamed namespace ///-------------------------------------------------------------------------- @@ -271,10 +349,28 @@ namespace cloonel { ///-------------------------------------------------------------------------- void Texture::Render (const float2& parPos, const float2& parSize, const float2& parScaling) const { assert(IsLoaded()); - const ushort2 pos(static_cast(parPos * parScaling + 0.5f)); - const ushort2 siz(static_cast(parSize * parScaling + 0.5f)); - const int screenHeight = m_sdlmain->WidthHeight().y(); - const SDL_Rect dest = { pos.x(), screenHeight - pos.y() - siz.y(), siz.x(), siz.y() }; - SDL_RenderCopy(m_sdlmain->GetRenderer(), m_texture, nullptr, &dest); + + const float2 pos(parPos * parScaling); + const float2 siz(parSize * parScaling); + RectFloat dest(pos, pos + siz); + RectFloat src(float2(0.0f), m_size); + + const RectFloat clip(float2(0.0f), static_cast(m_sdlmain->WidthHeight())); + const bool visible = ClipRect(src, dest, clip); + if (not visible) + return; + + const SDL_Rect sdlsrc(src); + //std::cout << "src = " << src.from << " - " << src.to << ", size is " << m_size << "\n"; + SDL_Rect sdldst(dest); + sdldst.y = m_sdlmain->WidthHeight().y() - sdldst.y - sdldst.h; + + //By here everything is nice and clean + assert(sdlsrc.x >= 0 and sdlsrc.y >= 0); + assert(sdlsrc.w >= 0 and sdlsrc.w <= static_cast(m_size.x())); + assert(sdlsrc.h >= 0 and sdlsrc.h <= static_cast(m_size.y())); + assert(sdlsrc.x + sdlsrc.w <= m_sdlmain->WidthHeight().x()); + assert(sdlsrc.y + sdlsrc.h <= m_sdlmain->WidthHeight().y()); + SDL_RenderCopy(m_sdlmain->GetRenderer(), m_texture, &sdlsrc, &sdldst); } } //namespace cloonel