Refactor RasterDrawMethods some more
This commit is contained in:
parent
7fc046c57d
commit
5daeced716
@ -25,12 +25,12 @@ struct Vec2
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator==(Vec2<T> other) const
|
||||
constexpr inline bool operator==(Vec2<T> other) const
|
||||
{
|
||||
return X == other.X && Y == other.Y;
|
||||
}
|
||||
|
||||
inline bool operator!=(Vec2<T> other) const
|
||||
constexpr inline bool operator!=(Vec2<T> other) const
|
||||
{
|
||||
return X != other.X || Y != other.Y;
|
||||
}
|
||||
@ -41,13 +41,13 @@ struct Vec2
|
||||
return Vec2<decltype(std::declval<T>() + std::declval<S>())>(X + other.X, Y + other.Y);
|
||||
}
|
||||
|
||||
inline Vec2<T> operator-() const
|
||||
constexpr inline Vec2<T> operator-() const
|
||||
{
|
||||
return Vec2<T>(-X, -Y);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<decltype(std::declval<T>() - std::declval<S>())> operator-(Vec2<S> other) const
|
||||
constexpr inline Vec2<decltype(std::declval<T>() - std::declval<S>())> operator-(Vec2<S> other) const
|
||||
{
|
||||
return Vec2<decltype(std::declval<T>() - std::declval<S>())>(X - other.X, Y - other.Y);
|
||||
}
|
||||
@ -59,45 +59,45 @@ struct Vec2
|
||||
}
|
||||
|
||||
template<typename S, typename = std::enable_if<std::is_arithmetic_v<S>, void>>
|
||||
inline Vec2<decltype(std::declval<T>() / std::declval<S>())> operator/(S other) const
|
||||
constexpr inline Vec2<decltype(std::declval<T>() / std::declval<S>())> operator/(S other) const
|
||||
{
|
||||
return Vec2<decltype(std::declval<T>() / std::declval<S>())>(X / other, Y / other);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator+=(Vec2<S> other)
|
||||
constexpr inline Vec2<T> &operator+=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this + other;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator-=(Vec2<S> other)
|
||||
constexpr inline Vec2<T> &operator-=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this - other;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator*=(Vec2<S> other)
|
||||
constexpr inline Vec2<T> &operator*=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this * other;
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
inline Vec2<T> &operator/=(Vec2<S> other)
|
||||
constexpr inline Vec2<T> &operator/=(Vec2<S> other)
|
||||
{
|
||||
return *this = *this / other;
|
||||
}
|
||||
|
||||
inline Vec2<T> Floor() const
|
||||
constexpr inline Vec2<T> Floor() const
|
||||
{
|
||||
return Vec2<T>(std::floor(X), std::floor(Y));
|
||||
}
|
||||
|
||||
// Return a rectangle starting at origin, whose dimensions match this vector
|
||||
template<typename = std::enable_if<std::is_integral_v<T>, void>>
|
||||
inline Rect<T> OriginRect() const
|
||||
constexpr inline Rect<T> OriginRect() const
|
||||
{
|
||||
return RectSized(Vec2<T>::Zero, *this);
|
||||
return RectSized(Vec2<T>(0, 0), *this);
|
||||
}
|
||||
|
||||
static Vec2<T> Zero;
|
||||
@ -150,7 +150,7 @@ template<typename T, typename V>
|
||||
Mat2<T> Mat2<T, V>::CCW = Mat2<T>(0, 1, -1, 0); // reminder: the Y axis points down
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
|
||||
static inline Rect<T> RectBetween(Vec2<T>, Vec2<T>);
|
||||
constexpr static inline Rect<T> RectBetween(Vec2<T>, Vec2<T>);
|
||||
|
||||
template<typename T, typename>
|
||||
struct Rect
|
||||
@ -164,7 +164,7 @@ private:
|
||||
BottomRight(bottomRight)
|
||||
{
|
||||
}
|
||||
friend Rect<T> RectBetween<T>(Vec2<T>, Vec2<T>);
|
||||
friend constexpr Rect<T> RectBetween<T>(Vec2<T>, Vec2<T>);
|
||||
|
||||
struct iterator
|
||||
{
|
||||
@ -202,6 +202,13 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
inline operator bool() const
|
||||
{
|
||||
return BottomRight.X >= TopLeft.X || BottomRight.Y >= TopLeft.Y;
|
||||
}
|
||||
|
||||
// Return the smallest rectangle that contains both input rectangles,
|
||||
// **assuming neither are empty**
|
||||
inline Rect<T> operator|(Rect<T> other) const
|
||||
{
|
||||
return Rect<T>(
|
||||
@ -210,6 +217,15 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
// Return the intersection of two rectangles (possibly empty)
|
||||
inline Rect<T> operator&(Rect<T> other) const
|
||||
{
|
||||
return Rect<T>(
|
||||
Vec2<T>(std::max(TopLeft.X, other.TopLeft.X), std::max(TopLeft.Y, other.TopLeft.Y)),
|
||||
Vec2<T>(std::min(BottomRight.X, other.BottomRight.X), std::min(BottomRight.Y, other.BottomRight.Y))
|
||||
);
|
||||
}
|
||||
|
||||
inline Rect<T> &operator|=(Rect<T> other)
|
||||
{
|
||||
return *this = *this | other;
|
||||
@ -220,16 +236,6 @@ public:
|
||||
return point.X >= TopLeft.X && point.X <= BottomRight.X && point.Y >= TopLeft.Y && point.Y <= BottomRight.Y;
|
||||
}
|
||||
|
||||
inline Vec2<T> Clamp(Vec2<T> point) const
|
||||
{
|
||||
return Vec2<T>(std::clamp(point.X, TopLeft.X, BottomRight.X), std::clamp(point.Y, TopLeft.Y, BottomRight.Y));
|
||||
}
|
||||
|
||||
inline Rect<T> Clamp(Rect<T> other) const
|
||||
{
|
||||
return Rect<T>(Clamp(other.TopLeft), Clamp(other.BottomRight));
|
||||
}
|
||||
|
||||
template<typename = std::enable_if<std::is_integral_v<T>, void>>
|
||||
inline Vec2<T> Size() const
|
||||
{
|
||||
@ -248,7 +254,7 @@ public:
|
||||
};
|
||||
|
||||
template<typename T, typename>
|
||||
static inline Rect<T> RectBetween(Vec2<T> topLeft, Vec2<T> bottomRight)
|
||||
constexpr static inline Rect<T> RectBetween(Vec2<T> topLeft, Vec2<T> bottomRight)
|
||||
{
|
||||
return Rect<T>(topLeft, bottomRight);
|
||||
}
|
||||
@ -260,7 +266,7 @@ static inline Rect<T> RectAt(Vec2<T> pos)
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if<std::is_integral_v<T>, void>>
|
||||
static inline Rect<T> RectSized(Vec2<T> topLeft, Vec2<T> dimen)
|
||||
constexpr static inline Rect<T> RectSized(Vec2<T> topLeft, Vec2<T> dimen)
|
||||
{
|
||||
return RectBetween<T>(topLeft, topLeft + dimen - Vec2<T>(1, 1));
|
||||
}
|
||||
|
@ -745,7 +745,7 @@ VideoBuffer Graphics::DumpFrame()
|
||||
|
||||
void Graphics::SetClipRect(Rect<int> &rect)
|
||||
{
|
||||
auto newRect = RectBetween(WINDOW.OriginRect().Clamp(rect.TopLeft), WINDOW.OriginRect().Clamp(rect.BottomRight));
|
||||
auto newRect = WINDOW.OriginRect() & rect;
|
||||
rect = clip;
|
||||
clip = newRect;
|
||||
}
|
||||
|
@ -73,10 +73,7 @@ class Graphics: public RasterDrawMethods<Graphics>
|
||||
{
|
||||
public:
|
||||
Rect<int> clip;
|
||||
constexpr static bool DoClipCheck = true;
|
||||
constexpr static int VIDXRES = WINDOWW;
|
||||
constexpr static int VIDYRES = WINDOWH;
|
||||
constexpr static auto VIDRES = WINDOW;
|
||||
|
||||
pixel *vid;
|
||||
int sdl_scale;
|
||||
|
@ -3,10 +3,15 @@
|
||||
|
||||
class VideoBuffer;
|
||||
|
||||
// The "Curiously Recurring Template Trick"
|
||||
// The "Curiously Recurring Template Pattern" trick
|
||||
template<typename Derived>
|
||||
struct RasterDrawMethods
|
||||
class RasterDrawMethods
|
||||
{
|
||||
private:
|
||||
pixel &pixelAt(Vec2<int>);
|
||||
Rect<int> clipRect();
|
||||
|
||||
public:
|
||||
int drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a);
|
||||
int drawtext(int x, int y, const String &str, int r, int g, int b, int a);
|
||||
int drawchar(int x, int y, String::value_type c, int r, int g, int b, int a);
|
||||
|
@ -4,6 +4,18 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
template<typename Derived>
|
||||
pixel &RasterDrawMethods<Derived>::pixelAt(Vec2<int> pos)
|
||||
{
|
||||
return static_cast<Derived *>(this)->vid[pos.X + Derived::VIDXRES * pos.Y];
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
Rect<int> RasterDrawMethods<Derived>::clipRect()
|
||||
{
|
||||
return static_cast<Derived *>(this)->clip;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
int RasterDrawMethods<Derived>::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a)
|
||||
{
|
||||
@ -123,74 +135,40 @@ int RasterDrawMethods<Derived>::addchar(int x, int y, String::value_type c, int
|
||||
template<typename Derived>
|
||||
void RasterDrawMethods<Derived>::xor_pixel(int x, int y)
|
||||
{
|
||||
int c;
|
||||
if constexpr (Derived::DoClipCheck)
|
||||
{
|
||||
if (!(static_cast<Derived *>(this))->clip.Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
}
|
||||
if (!clipRect().Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
pixel &c = pixelAt(Vec2<int>(x, y));
|
||||
if (PIXB(c) + 2 * PIXR(c) + 3 * PIXG(c) < 512)
|
||||
c = PIXPACK(0xC0C0C0);
|
||||
else
|
||||
{
|
||||
if (!Derived::VIDRES.OriginRect().Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
}
|
||||
c = (static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x];
|
||||
c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c);
|
||||
if (c<512)
|
||||
(static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x] = PIXPACK(0xC0C0C0);
|
||||
else
|
||||
(static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x] = PIXPACK(0x404040);
|
||||
c = PIXPACK(0x404040);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
void RasterDrawMethods<Derived>::blendpixel(int x, int y, int r, int g, int b, int a)
|
||||
{
|
||||
pixel t;
|
||||
if constexpr (Derived::DoClipCheck)
|
||||
if (!clipRect().Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
pixel &t = pixelAt(Vec2<int>(x, y));
|
||||
if (a != 255)
|
||||
{
|
||||
if (!(static_cast<Derived *>(this))->clip.Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
r = (a * r + (255 - a) * PIXR(t)) >> 8;
|
||||
g = (a * g + (255 - a) * PIXG(t)) >> 8;
|
||||
b = (a * b + (255 - a) * PIXB(t)) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Derived::VIDRES.OriginRect().Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
}
|
||||
if (a!=255)
|
||||
{
|
||||
t = (static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x];
|
||||
r = (a*r + (255-a)*PIXR(t)) >> 8;
|
||||
g = (a*g + (255-a)*PIXG(t)) >> 8;
|
||||
b = (a*b + (255-a)*PIXB(t)) >> 8;
|
||||
}
|
||||
(static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x] = PIXRGB(r,g,b);
|
||||
t = PIXRGB(r, g, b);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
void RasterDrawMethods<Derived>::addpixel(int x, int y, int r, int g, int b, int a)
|
||||
{
|
||||
pixel t;
|
||||
if constexpr (Derived::DoClipCheck)
|
||||
{
|
||||
if (!(static_cast<Derived *>(this))->clip.Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Derived::VIDRES.OriginRect().Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
}
|
||||
t = (static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x];
|
||||
r = (a*r + 255*PIXR(t)) >> 8;
|
||||
g = (a*g + 255*PIXG(t)) >> 8;
|
||||
b = (a*b + 255*PIXB(t)) >> 8;
|
||||
if (r>255)
|
||||
r = 255;
|
||||
if (g>255)
|
||||
g = 255;
|
||||
if (b>255)
|
||||
b = 255;
|
||||
(static_cast<Derived *>(this))->vid[y*(Derived::VIDXRES)+x] = PIXRGB(r,g,b);
|
||||
if (!clipRect().Contains(Vec2<int>(x, y)))
|
||||
return;
|
||||
pixel &t = pixelAt(Vec2<int>(x, y));
|
||||
r = std::min(255, (a * r + 255 * PIXR(t)) >> 8);
|
||||
g = std::min(255, (a * g + 255 * PIXG(t)) >> 8);
|
||||
b = std::min(255, (a * b + 255 * PIXB(t)) >> 8);
|
||||
t = PIXRGB(r, g, b);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
@ -269,94 +247,37 @@ void RasterDrawMethods<Derived>::gradientrect(int x, int y, int width, int heigh
|
||||
template<typename Derived>
|
||||
void RasterDrawMethods<Derived>::clearrect(int x, int y, int w, int h)
|
||||
{
|
||||
int i;
|
||||
|
||||
// TODO: change calls to clearrect to use sensible meanings of x, y, w, h then remove these 4 lines
|
||||
x += 1;
|
||||
y += 1;
|
||||
w -= 1;
|
||||
h -= 1;
|
||||
|
||||
Rect<int> rect = RectSized(Vec2<int>(x, y), Vec2<int>(w, h));
|
||||
if constexpr (Derived::DoClipCheck)
|
||||
rect = (static_cast<Derived *>(this))->clip.Clamp(rect);
|
||||
else
|
||||
rect = Derived::VIDRES.OriginRect().Clamp(rect);
|
||||
|
||||
x = rect.TopLeft.X;
|
||||
y = rect.TopLeft.Y;
|
||||
w = rect.Size().X;
|
||||
h = rect.Size().Y;
|
||||
|
||||
if (w<0 || h<0)
|
||||
Rect<int> rect = clipRect() & RectSized(Vec2<int>(x, y), Vec2<int>(w, h));
|
||||
if (rect.Size().X <= 0 || rect.Size().Y <= 0)
|
||||
return;
|
||||
|
||||
for (i=0; i<h; i++)
|
||||
memset((static_cast<Derived *>(this))->vid+(x+(Derived::VIDXRES)*(y+i)), 0, PIXELSIZE*w);
|
||||
for (int y = rect.TopLeft.Y; y <= rect.BottomRight.Y; y++)
|
||||
std::fill_n(&pixelAt(Vec2<int>(rect.TopLeft.X, y)), rect.Size().X, PIXPACK(0x000000));
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
void RasterDrawMethods<Derived>::draw_image(const pixel *img, int x, int y, int w, int h, int a)
|
||||
{
|
||||
int startX = 0;
|
||||
if (!img)
|
||||
return;
|
||||
// Adjust height to prevent drawing off the bottom
|
||||
if (y + h > Derived::VIDYRES)
|
||||
h = ((Derived::VIDYRES)-y)-1;
|
||||
// Too big
|
||||
if (x + w > Derived::VIDXRES)
|
||||
Rect<int> rect = clipRect() & RectSized(Vec2<int>(x, y), Vec2<int>(w, h));
|
||||
if (rect.Size().X <= 0 || rect.Size().Y <= 0)
|
||||
return;
|
||||
|
||||
// Starts off the top of the screen, adjust
|
||||
if (y < 0 && -y < h)
|
||||
{
|
||||
img += -y*w;
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
// Starts off the left side of the screen, adjust
|
||||
if (x < 0 && -x < w)
|
||||
{
|
||||
startX = -x;
|
||||
}
|
||||
|
||||
if (!h || y < 0 || !w)
|
||||
return;
|
||||
if (a >= 255)
|
||||
for (int j = 0; j < h; j++)
|
||||
{
|
||||
img += startX;
|
||||
for (int i = startX; i < w; i++)
|
||||
{
|
||||
if constexpr (Derived::DoClipCheck)
|
||||
{
|
||||
if ((static_cast<Derived *>(this))->clip.Contains(Vec2<int>(x + i, y + j)))
|
||||
(static_cast<Derived *>(this))->vid[(y+j)*(Derived::VIDXRES)+(x+i)] = *img;
|
||||
}
|
||||
else
|
||||
{
|
||||
(static_cast<Derived *>(this))->vid[(y+j)*(Derived::VIDXRES)+(x+i)] = *img;
|
||||
}
|
||||
img++;
|
||||
}
|
||||
}
|
||||
if (a == 255)
|
||||
for (int outY = rect.TopLeft.Y; outY <= rect.BottomRight.Y; outY++)
|
||||
std::copy_n(&img[(rect.TopLeft.X - x) + (outY - y) * w], rect.Size().X, &pixelAt(Vec2<int>(rect.TopLeft.X, outY)));
|
||||
else
|
||||
{
|
||||
int r, g, b;
|
||||
for (int j = 0; j < h; j++)
|
||||
for (auto pos : rect)
|
||||
{
|
||||
img += startX;
|
||||
for (int i = startX; i < w; i++)
|
||||
{
|
||||
r = PIXR(*img);
|
||||
g = PIXG(*img);
|
||||
b = PIXB(*img);
|
||||
blendpixel(x+i, y+j, r, g, b, a);
|
||||
img++;
|
||||
}
|
||||
pixel px = img[(pos.X - x) + (pos.Y - y) * w];
|
||||
// TODO: ensure this doesn't redo a bounds check
|
||||
blendpixel(pos.X, pos.Y, PIXR(px), PIXG(px), PIXB(px), a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
@ -35,10 +35,8 @@ int HeatToColour(float temp);
|
||||
class Renderer: public RasterDrawMethods<Renderer>
|
||||
{
|
||||
public:
|
||||
constexpr static bool DoClipCheck = false;
|
||||
constexpr static auto VIDRES = WINDOW;
|
||||
constexpr static auto VIDXRES = VIDRES.X;
|
||||
constexpr static auto VIDYRES = VIDRES.Y;
|
||||
constexpr static auto clip = WINDOW.OriginRect();
|
||||
constexpr static auto VIDXRES = WINDOW.X;
|
||||
|
||||
Simulation * sim;
|
||||
Graphics * g;
|
||||
|
Reference in New Issue
Block a user