Clip texture before rendering.

This commit is contained in:
King_DuckZ 2014-03-24 21:32:24 +01:00
parent 8af4e432e7
commit a1e507ef12

View file

@ -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<float>(parRect.x), static_cast<float>(parRect.y)),
to(static_cast<float>(parRect.x + parRect.w), static_cast<float>(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<int>(from.x()), static_cast<int>(from.y()), static_cast<int>(Width()), static_cast<int>(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<ushort2>(parPos * parScaling + 0.5f));
const ushort2 siz(static_cast<ushort2>(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<float2>(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<int>(m_size.x()));
assert(sdlsrc.h >= 0 and sdlsrc.h <= static_cast<int>(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