Fix texture clipping

This commit is contained in:
King_DuckZ 2016-11-09 22:25:57 +01:00
parent 68d179975e
commit a87255ef66

View file

@ -30,6 +30,9 @@
#include <png.h>
#include <endian.h>
#include <vector>
#if !defined(NDEBUG)
# include <cmath>
#endif
#define lengthof(a) (static_cast<int32_t>(sizeof(a) / sizeof(a[0])))
@ -113,6 +116,15 @@ namespace cloonel {
bool IsRectCompletelyInsideRect ( const RectFloat& parInner, const RectFloat& parOuter ) a_pure;
#endif
#if !defined(NDEBUG)
bool areEqualRel (float parA, float parB, float parEpsilon) a_pure;
//see: http://stackoverflow.com/questions/4548004/how-to-correctly-and-standardly-compare-floats
bool areEqualRel (float parA, float parB, float parEpsilon) {
return (std::fabs(parA - parB) <= parEpsilon * std::max(std::fabs(parA), std::fabs(parB)));
}
#endif
///----------------------------------------------------------------------
///----------------------------------------------------------------------
SDL_Surface* SurfaceFromPng (PixelFormat parPixelFormat, ushort2 parSize, const png_structp& parPngPtr, const png_infop& parInfoPtr, std::vector<uint8_t>& parBuff) {
@ -260,6 +272,7 @@ namespace cloonel {
///got set to a valid value, otherwise false.
///----------------------------------------------------------------------
bool ClipRect (RectFloat& parSrc, RectFloat& parDest, const RectFloat& parClip) {
assert(areEqualRel(parSrc.Width(), parDest.Width(), 0.00001f));
assert(parSrc.IsValid());
assert(parDest.IsValid());
@ -268,29 +281,34 @@ namespace cloonel {
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());
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.IsValid())
return false;
parDest.from += parClip.from;
parDest.to += parClip.from;
assert(parDest.from <= dst.from);
assert(parDest.to >= dst.to);
assert(parDest.IsValid());
RectFloat src;
{
const float2 srcWidthHeight(parSrc.WidthHeight());
const float2 scaledOffs((dst.from - parDest.from) / parDest.WidthHeight());
src.from = parSrc.from + scaledOffs * srcWidthHeight;
const float2 scaledCrop((parDest.to - dst.to) / parDest.WidthHeight());
src.to = parSrc.to - scaledCrop * srcWidthHeight;
assert(src.IsValid());
assert(dst.IsValid());
assert(dst.from >= parClip.from);
assert(dst.to <= parClip.to);
assert(areEqualRel(src.Width(), dst.Width(), 0.00001f));
}
parDest = dst;
parSrc = src;
return true;
}