diff --git a/src/common/Plane.h b/src/common/Plane.h index ca154a8c2..a40f66a28 100644 --- a/src/common/Plane.h +++ b/src/common/Plane.h @@ -88,10 +88,12 @@ public: PlaneAdapter(PlaneAdapter &&) = default; + // PlaneAdapter can be constructed from (Vec2, T &&) + // PlaneAdapter can be constructed from (Vec2, T &) PlaneAdapter(Vec2 size, T &&base): xExtent(size.X), yExtent(size.Y), - Base(std::move(base)) + Base(std::forward(base)) {} template diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp index 1145d2eef..3fd6ed6a4 100644 --- a/src/graphics/Graphics.cpp +++ b/src/graphics/Graphics.cpp @@ -1,15 +1,16 @@ #include -#include #include #include #include #include +#include #include #include "common/platform/Platform.h" #include "FontReader.h" #include "Graphics.h" #include "resampler/resampler.h" #include "SimulationConfig.h" +#include "RasterDrawMethodsImpl.h" VideoBuffer::VideoBuffer(Vec2 size): video(size) @@ -128,6 +129,8 @@ int VideoBuffer::AddCharacter(int x, int y, String::value_type c, int r, int g, return x + reader.GetWidth(); } +template class RasterDrawMethods; + pixel *Graphics::resample_img_nn(pixel * src, int sw, int sh, int rw, int rh) { int y, x; diff --git a/src/graphics/Graphics.h b/src/graphics/Graphics.h index 41de6ae15..084e793ca 100644 --- a/src/graphics/Graphics.h +++ b/src/graphics/Graphics.h @@ -61,6 +61,8 @@ public: [[deprecated("Use Crop(Rect)")]] void Crop(int width, int height, int x, int y); + using RasterDrawMethods::BlendPixel; + [[deprecated("Use BlendPixel(Vec2, RGBA)")]] TPT_INLINE void BlendPixel(int x, int y, int r, int g, int b, int a) { pixel t; @@ -76,6 +78,7 @@ public: Buffer[y*(Width)+x] = PIXRGB(r,g,b); } + [[deprecated("Use DrawPixel")]] TPT_INLINE void SetPixel(int x, int y, int r, int g, int b, int a) { if (x<0 || y<0 || x>=Width || y>=Height) @@ -83,6 +86,8 @@ public: Buffer[y*(Width)+x] = PIXRGB((r*a)>>8, (g*a)>>8, (b*a)>>8); } + using RasterDrawMethods::AddPixel; + [[deprecated("Use AddPixel(Vec2, RGBA)")]] TPT_INLINE void AddPixel(int x, int y, int r, int g, int b, int a) { pixel t; @@ -100,8 +105,11 @@ public: b = 255; Buffer[y*(Width)+x] = PIXRGB(r,g,b); } + [[deprecated("Use BlendChar")]] int SetCharacter(int x, int y, String::value_type c, int r, int g, int b, int a); + [[deprecated("Use BlendChar")]] int BlendCharacter(int x, int y, String::value_type c, int r, int g, int b, int a); + [[deprecated("Use AddChar")]] int AddCharacter(int x, int y, String::value_type c, int r, int g, int b, int a); bool WritePNG(const ByteString &path) const; diff --git a/src/graphics/RasterDrawMethods.h b/src/graphics/RasterDrawMethods.h index 86cf66462..8d17630f4 100644 --- a/src/graphics/RasterDrawMethods.h +++ b/src/graphics/RasterDrawMethods.h @@ -10,23 +10,79 @@ class VideoBuffer; template struct RasterDrawMethods { + void DrawPixel(Vec2, RGB); + void BlendPixel(Vec2, RGBA); + void AddPixel(Vec2, RGBA); + void XorPixel(Vec2); + + void DrawLine(Vec2, Vec2, RGB); + void BlendLine(Vec2, Vec2, RGBA); + void AddLine(Vec2, Vec2, RGBA); + void XorLine(Vec2, Vec2); + + void DrawRect(Rect, RGB); + void BlendRect(Rect, RGBA); + + void XorDottedRect(Rect); + + void DrawFilledRect(Rect, RGB); + void BlendFilledRect(Rect, RGBA); + + void BlendEllipse(Vec2 center, Vec2 size, RGBA); + + void BlendFilledEllipse(Vec2 center, Vec2 size, RGBA); + + void BlendImage(pixel const *, uint8_t alpha, Rect); + void BlendImage(pixel const *, uint8_t alpha, Rect, size_t rowStride); + void XorImage(unsigned char const *, Rect); + void XorImage(unsigned char const *, Rect, size_t rowStride); + + // Returns width of character + int BlendChar(Vec2, String::value_type, RGBA); + int AddChar(Vec2, String::value_type, RGBA); + + // Returns the offset between the first character and the + // would-be-next character + Vec2 BlendText(Vec2, String const &, RGBA); + + Vec2 BlendTextOutline(Vec2, String const &, RGBA); + + void Clear(); + + [[deprecated("Use BlendTextOutline")]] int drawtext_outline(int x, int y, const String &, int r, int g, int b, int a); + [[deprecated("Use BlendText")]] int drawtext(int x, int y, const String &, int r, int g, int b, int a); + [[deprecated("Use BlendChar")]] int drawchar(int x, int y, String::value_type, int r, int g, int b, int a); + [[deprecated("Use AddChar")]] int addchar(int x, int y, String::value_type, int r, int g, int b, int a); + [[deprecated("Use XorPixel")]] void xor_pixel(int x, int y); + [[deprecated("Use DrawPixel/BlendPixel")]] void blendpixel(int x, int y, int r, int g, int b, int a); + [[deprecated("Use AddPixel")]] void addpixel(int x, int y, int r, int g, int b, int a); + [[deprecated("Use XorLine")]] void xor_line(int x1, int y1, int x2, int y2); + [[deprecated("Use XorDottedRect")]] void xor_rect(int x, int y, int w, int h); + [[deprecated("Use XorImage")]] void xor_bitmap(unsigned char *bitmap, int x, int y, int w, int h); + [[deprecated("Use DrawLine/BlendLine")]] void draw_line(int x1, int y1, int x2, int y2, int r, int g, int b, int a); + [[deprecated("Use DrawRect/BlendRect")]] void drawrect(int x, int y, int w, int h, int r, int g, int b, int a); + [[deprecated("Use DrawFilledRect/BlendFilledRect")]] void fillrect(int x, int y, int w, int h, int r, int g, int b, int a); + [[deprecated("Use BlendEllipse")]] void drawcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); + [[deprecated("Use BlendFilledEllipse")]] void fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); - void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); + [[deprecated("Use DrawFilledRect (beware off by 1)")]] void clearrect(int x, int y, int w, int h); + [[deprecated("Use BlendImage")]] void draw_image(pixel const *, int x, int y, int w, int h, int a); + [[deprecated("Use BlendImage")]] void draw_image(VideoBuffer const *, int x, int y, int a); }; diff --git a/src/graphics/RasterDrawMethodsImpl.h b/src/graphics/RasterDrawMethodsImpl.h index 6a655c41d..774214b5d 100644 --- a/src/graphics/RasterDrawMethodsImpl.h +++ b/src/graphics/RasterDrawMethodsImpl.h @@ -1,118 +1,327 @@ #include #include -#include "RasterDrawMethods.h" -#include "Graphics.h" +#include "common/RasterGeometry.h" #include "FontReader.h" +#include "Graphics.h" +#include "RasterDrawMethods.h" -#define vid() (static_cast(*this).video.RowIterator(Vec2(0, 0))) +#define video() (static_cast(*this).video) #define clipRect() (static_cast(*this).getClipRect()) -#define VIDXRES (static_cast(*this).video.Size().X) -#define VIDYRES (static_cast(*this).video.Size().Y) -template -int RasterDrawMethods::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a) +template +static inline void drawPixelUnchecked(RasterDrawMethods &self, V Derived::*video, Vec2 pos, RGB colour) { - drawtext(x-1, y-1, s, 0, 0, 0, 120); - drawtext(x+1, y+1, s, 0, 0, 0, 120); + (static_cast(self).*video)[pos] = colour.Pack(); +} - drawtext(x-1, y+1, s, 0, 0, 0, 120); - drawtext(x+1, y-1, s, 0, 0, 0, 120); +template +static inline void blendPixelUnchecked(RasterDrawMethods &self, V Derived::*video, Vec2 pos, RGBA colour) +{ + pixel &px = (static_cast(self).*video)[pos]; + px = RGB::Unpack(px).Blend(colour).Pack(); +} - return drawtext(x, y, s, r, g, b, a); +template +static inline void xorPixelUnchecked(RasterDrawMethods &self, V Derived::*video, Vec2 pos) +{ + pixel &px = (static_cast(self).*video)[pos]; + auto const c = RGB::Unpack(px); + if (2 * c.Red + 3 * c.Green + c.Blue < 512) + px = 0xC0C0C0_rgb .Pack(); + else + px = 0x404040_rgb .Pack(); } template -int RasterDrawMethods::drawtext(int x, int y, const String &str, int r, int g, int b, int a) +inline void RasterDrawMethods::DrawPixel(Vec2 pos, RGB colour) { - if(!str.size()) - return 0; + if (clipRect().Contains(pos)) + drawPixelUnchecked(*this, &Derived::video, pos, colour); +} +template +inline void RasterDrawMethods::BlendPixel(Vec2 pos, RGBA colour) +{ + if (clipRect().Contains(pos)) + blendPixelUnchecked(*this, &Derived::video, pos, colour); +} + +template +inline void RasterDrawMethods::AddPixel(Vec2 pos, RGBA colour) +{ + if (clipRect().Contains(pos)) + { + pixel &px = (static_cast(*this).video)[pos]; + px = RGB::Unpack(px).Add(colour).Pack(); + } +} + +template +inline void RasterDrawMethods::XorPixel(Vec2 pos) +{ + if (clipRect().Contains(pos)) + xorPixelUnchecked(*this, &Derived::video, pos); +} + +template +void RasterDrawMethods::DrawLine(Vec2 pos1, Vec2 pos2, RGB colour) +{ + RasterizeLine(pos1, pos2, [this, colour](Vec2 pos) { + DrawPixel(pos, colour); + }); +} + +template +void RasterDrawMethods::BlendLine(Vec2 pos1, Vec2 pos2, RGBA colour) +{ + RasterizeLine(pos1, pos2, [this, colour](Vec2 pos) { + BlendPixel(pos, colour); + }); +} + +template +void RasterDrawMethods::AddLine(Vec2 pos1, Vec2 pos2, RGBA colour) +{ + RasterizeLine(pos1, pos2, [this, colour](Vec2 pos) { + AddPixel(pos, colour); + }); +} + +template +void RasterDrawMethods::XorLine(Vec2 pos1, Vec2 pos2) +{ + RasterizeLine(pos1, pos2, [this](Vec2 pos) { + XorPixel(pos); + }); +} + +template +void RasterDrawMethods::DrawRect(Rect rect, RGB colour) +{ + RasterizeRect(rect, [this, colour](Vec2 pos) { + DrawPixel(pos, colour); + }); +} + +template +void RasterDrawMethods::BlendRect(Rect rect, RGBA colour) +{ + RasterizeRect(rect, [this, colour](Vec2 pos) { + BlendPixel(pos, colour); + }); +} + +template +void RasterDrawMethods::XorDottedRect(Rect rect) +{ + RasterizeDottedRect(rect, [this](Vec2 pos) { + XorPixel(pos); + }); +} + +template +void RasterDrawMethods::DrawFilledRect(Rect rect, RGB colour) +{ + rect &= clipRect(); + pixel packed = colour.Pack(); + auto &video = static_cast(*this).video; + if (rect) + for (int y = rect.TopLeft.Y; y <= rect.BottomRight.Y; y++) + std::fill_n(video.RowIterator(Vec2(rect.TopLeft.X, y)), rect.Size().X, packed); +} + +template +void RasterDrawMethods::BlendFilledRect(Rect rect, RGBA colour) +{ + for (auto pos : rect & clipRect()) + blendPixelUnchecked(*this, &Derived::video, pos, colour); +} + +template +void RasterDrawMethods::BlendEllipse(Vec2 center, Vec2 size, RGBA colour) +{ + RasterizeEllipsePoints(Vec2(float(size.X * size.X), float(size.Y * size.Y)), [this, center, colour](Vec2 delta) { + BlendPixel(center + delta, colour); + }); +} + +template +void RasterDrawMethods::BlendFilledEllipse(Vec2 center, Vec2 size, RGBA colour) +{ + RasterizeEllipseRows(Vec2(float(size.X * size.X), float(size.Y * size.Y)), [this, center, colour](int xLim, int dy) { + for (auto pos : clipRect() & RectBetween(center + Vec2(-xLim, dy), center + Vec2(xLim, dy))) + blendPixelUnchecked(*this, &Derived::video, pos, colour); + }); +} + +template +void RasterDrawMethods::BlendImage(pixel const *data, uint8_t alpha, Rect rect) +{ + BlendImage(data, alpha, rect, rect.Size().X); +} + +template +void RasterDrawMethods::BlendImage(pixel const *data, uint8_t alpha, Rect rect, size_t rowStride) +{ + auto origin = rect.TopLeft; + rect &= clipRect(); + if (alpha == 0xFF) + { + auto &video = static_cast(*this).video; + for (int y = rect.TopLeft.Y; y <= rect.BottomRight.Y; y++) + std::copy_n( + data + (rect.TopLeft.X - origin.X) + (y - origin.Y) * rowStride, + rect.Size().X, + video.RowIterator(Vec2(rect.TopLeft.X, y)) + ); + } + else + { + for (auto pos : rect) + { + pixel const px = data[(pos.X - origin.X) + (pos.Y - origin.Y) * rowStride]; + blendPixelUnchecked(*this, &Derived::video, pos, RGB::Unpack(px).WithAlpha(alpha)); + } + } +} + +template +void RasterDrawMethods::XorImage(unsigned char const *data, Rect rect) +{ + XorImage(data, rect, rect.Size().X); +} + +template +void RasterDrawMethods::XorImage(unsigned char const *data, Rect rect, size_t rowStride) +{ + auto origin = rect.TopLeft; + rect &= clipRect(); + for (auto pos : rect) + if (data[(pos.X - origin.X) + (pos.Y - origin.Y) * rowStride]) + xorPixelUnchecked(*this, &Derived::video, pos); +} + +template +int RasterDrawMethods::BlendChar(Vec2 pos, String::value_type ch, RGBA colour) +{ + FontReader reader(ch); + auto const rect = RectSized(Vec2(0, -2), Vec2(reader.GetWidth(), FONT_H)); + for (auto off : rect.template Range()) + BlendPixel(pos + off, colour.NoAlpha().WithAlpha(reader.NextPixel() * colour.Alpha / 3)); + return reader.GetWidth(); +} + +template +int RasterDrawMethods::AddChar(Vec2 pos, String::value_type ch, RGBA colour) +{ + FontReader reader(ch); + RGB const c = colour.NoAlpha(); + auto const rect = RectSized(Vec2(0, -2), Vec2(reader.GetWidth(), FONT_H)); + for (auto off : rect.template Range()) + AddPixel(pos + off, c.WithAlpha(reader.NextPixel() * colour.Alpha / 3)); + return reader.GetWidth(); +} + +template +Vec2 RasterDrawMethods::BlendText(Vec2 orig_pos, String const &str, RGBA orig_colour) +{ bool underline = false; - int invert = 0; - int oR = r, oG = g, oB = b; - int characterX = x, characterY = y; - int startX = characterX; + bool invert = false; + RGB colour = orig_colour.NoAlpha(); + uint8_t alpha = orig_colour.Alpha; + Vec2 pos = orig_pos; for (size_t i = 0; i < str.length(); i++) { if (str[i] == '\n') { - characterX = startX; - characterY += FONT_H; + pos.X = orig_pos.X; + pos.Y += FONT_H; } else if (str[i] == '\x0F') { - if (str.length() <= i+3) + if (str.length() <= i + 3) break; - oR = r; - oG = g; - oB = b; - r = (unsigned char)str[i + 1]; - g = (unsigned char)str[i + 2]; - b = (unsigned char)str[i + 3]; + colour.Red = str[i + 1]; + colour.Green = str[i + 2]; + colour.Blue = str[i + 3]; i += 3; } else if (str[i] == '\x0E') { - r = oR; - g = oG; - b = oB; + colour = orig_colour.NoAlpha(); } else if (str[i] == '\x01') { invert = !invert; - r = 255-r; - g = 255-g; - b = 255-b; + colour = colour.Inverse(); } else if (str[i] == '\b') { if (str.length() <= i + 1) break; - auto colorCode = false; + bool colourCode = true; switch (str[i + 1]) { - case 'U': underline = !underline; break; - case 'w': r = 255; g = 255; b = 255; colorCode = true; break; - case 'g': r = 192; g = 192; b = 192; colorCode = true; break; - case 'o': r = 255; g = 216; b = 32; colorCode = true; break; - case 'r': r = 255; g = 0; b = 0; colorCode = true; break; - case 'l': r = 255; g = 75; b = 75; colorCode = true; break; - case 'b': r = 0; g = 0; b = 255; colorCode = true; break; - case 't': b = 255; g = 170; r = 32; colorCode = true; break; - case 'u': r = 147; g = 83; b = 211; colorCode = true; break; - } - if (colorCode && invert) - { - r = 255-r; - g = 255-g; - b = 255-b; + case 'U': underline = !underline; colourCode = false; break; + case 'w': colour = 0xFFFFFF_rgb; break; + case 'g': colour = 0xC0C0C0_rgb; break; + case 'o': colour = 0xFFD820_rgb; break; + case 'r': colour = 0xFF0000_rgb; break; + case 'l': colour = 0xFF4B4B_rgb; break; + case 'b': colour = 0x0000FF_rgb; break; + case 't': colour = 0x20AAFF_rgb; break; + case 'u': colour = 0x9353D3_rgb; break; } + if (colourCode && invert) + colour = colour.Inverse(); i++; } else { - auto newCharacterX = drawchar(characterX, characterY, str[i], r, g, b, a); + int dx = BlendChar(pos, str[i], colour.WithAlpha(alpha)); if (underline) - { - for (int i = characterX; i < newCharacterX; ++i) - { - blendpixel(i, y + FONT_H, r, g, b, a); - } - } - characterX = newCharacterX; + for (int i = 0; i < dx; i++) + BlendPixel(pos + Vec2(i, FONT_H), colour.WithAlpha(alpha)); + pos.X += dx; } } - return x; + return pos - orig_pos; +} + +template +Vec2 RasterDrawMethods::BlendTextOutline(Vec2 pos, String const &str, RGBA colour) +{ + BlendText(pos + Vec2(-1, -1), str, 0x000000_rgb .WithAlpha(0x78)); + BlendText(pos + Vec2(-1, +1), str, 0x000000_rgb .WithAlpha(0x78)); + BlendText(pos + Vec2(+1, -1), str, 0x000000_rgb .WithAlpha(0x78)); + BlendText(pos + Vec2(+1, +1), str, 0x000000_rgb .WithAlpha(0x78)); + + return BlendText(pos, str, colour); +} + +template +void RasterDrawMethods::Clear() +{ + auto &video = static_cast(*this).video; + std::fill_n(video.data(), video.Size().X * video.Size().Y, 0x000000_rgb .Pack()); +} + +template +int RasterDrawMethods::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a) +{ + return x + BlendTextOutline(Vec2(x, y), s, RGBA(r, g, b, a)).X; +} + +template +int RasterDrawMethods::drawtext(int x, int y, const String &str, int r, int g, int b, int a) +{ + return x + BlendText(Vec2(x, y), str, RGBA(r, g, b, a)).X; } template int RasterDrawMethods::drawchar(int x, int y, String::value_type c, int r, int g, int b, int a) { - FontReader reader(c); - for (int j = -2; j < FONT_H - 2; j++) - for (int i = 0; i < reader.GetWidth(); i++) - blendpixel(x + i, y + j, r, g, b, reader.NextPixel() * a / 3); - return x + reader.GetWidth(); + return x + BlendChar(Vec2(x, y), c, RGBA(r, g, b, a)); } template @@ -128,359 +337,91 @@ int RasterDrawMethods::addchar(int x, int y, String::value_type c, int template void RasterDrawMethods::xor_pixel(int x, int y) { - int c; - if (!clipRect().Contains(Vec2(x, y))) - return; - c = vid()[y*(VIDXRES)+x]; - c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c); - if (c<512) - vid()[y*(VIDXRES)+x] = PIXPACK(0xC0C0C0); - else - vid()[y*(VIDXRES)+x] = PIXPACK(0x404040); + XorPixel(Vec2(x, y)); } template void RasterDrawMethods::blendpixel(int x, int y, int r, int g, int b, int a) { - pixel t; - if (!clipRect().Contains(Vec2(x, y))) - return; - if (a!=255) - { - t = vid()[y*(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; - } - vid()[y*(VIDXRES)+x] = PIXRGB(r,g,b); + if (a == 0xFF) + DrawPixel(Vec2(x, y), RGB(r, g, b)); + else + BlendPixel(Vec2(x, y), RGBA(r, g, b, a)); } template void RasterDrawMethods::addpixel(int x, int y, int r, int g, int b, int a) { - pixel t; - if (!clipRect().Contains(Vec2(x, y))) - return; - t = vid()[y*(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; - vid()[y*(VIDXRES)+x] = PIXRGB(r,g,b); + AddPixel(Vec2(x, y), RGBA(r, g, b, a)); } template void RasterDrawMethods::xor_line(int x1, int y1, int x2, int y2) { - int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy; - float e, de; - if (cp) - { - y = x1; - x1 = y1; - y1 = y; - y = x2; - x2 = y2; - y2 = y; - } - if (x1 > x2) - { - y = x1; - x1 = x2; - x2 = y; - y = y1; - y1 = y2; - y2 = y; - } - dx = x2 - x1; - dy = abs(y2 - y1); - e = 0.0f; - if (dx) - de = dy/(float)dx; - else - de = 0.0f; - y = y1; - sy = (y1= 0.5f) - { - y += sy; - e -= 1.0f; - } - } + XorLine(Vec2(x1, y1), Vec2(x2, y2)); } template void RasterDrawMethods::xor_rect(int x, int y, int w, int h) { - int i; - for (i=0; i void RasterDrawMethods::xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h) { - for(int x1 = 0; x1 < w; x1++) - { - for(int y1 = 0; y1 < h; y1++) - { - if(bitmap[y1*w+x1]) - xor_pixel(x+x1, y+y1); - } - } + XorImage(bitmap, RectSized(Vec2(x, y), Vec2(w, h))); } template void RasterDrawMethods::draw_line(int x1, int y1, int x2, int y2, int r, int g, int b, int a) { - int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy; - float e, de; - if (cp) - { - y = x1; - x1 = y1; - y1 = y; - y = x2; - x2 = y2; - y2 = y; - } - if (x1 > x2) - { - y = x1; - x1 = x2; - x2 = y; - y = y1; - y1 = y2; - y2 = y; - } - dx = x2 - x1; - dy = abs(y2 - y1); - e = 0.0f; - if (dx) - de = dy/(float)dx; + if (a == 0xFF) + DrawLine(Vec2(x1, y1), Vec2(x2, y2), RGB(r, g, b)); else - de = 0.0f; - y = y1; - sy = (y1= 0.5f) - { - y += sy; - e -= 1.0f; - } - } + BlendLine(Vec2(x1, y1), Vec2(x2, y2), RGBA(r, g, b, a)); } template void RasterDrawMethods::drawrect(int x, int y, int w, int h, int r, int g, int b, int a) { - int i; - w--; - h--; - for (i=0; i<=w; i++) - { - blendpixel(x+i, y, r, g, b, a); - blendpixel(x+i, y+h, r, g, b, a); - } - for (i=1; i(r, g, b)); + else + BlendRect(RectSized(Vec2(x, y), Vec2(w, h)), RGBA(r, g, b, a)); } template void RasterDrawMethods::fillrect(int x, int y, int w, int h, int r, int g, int b, int a) { - int i,j; - for (j=0; j(r, g, b)); + else + BlendFilledRect(RectSized(Vec2(x, y), Vec2(w, h)), RGBA(r, g, b, a)); } template void RasterDrawMethods::drawcircle(int x, int y, int rx, int ry, int r, int g, int b, int a) { - int yTop = ry, yBottom, i, j; - if (!rx) - { - for (j = -ry; j <= ry; j++) - blendpixel(x, y+j, r, g, b, a); - return; - } - for (i = 0; i <= rx; i++) { - yBottom = yTop; - while (pow(i-rx,2.0)*pow(ry,2.0) + pow(yTop-ry,2.0)*pow(rx,2.0) <= pow(rx,2.0)*pow(ry,2.0)) - yTop++; - if (yBottom != yTop) - yTop--; - for (int j = yBottom; j <= yTop; j++) - { - blendpixel(x+i-rx, y+j-ry, r, g, b, a); - if (i != rx) - blendpixel(x-i+rx, y+j-ry, r, g, b, a); - if (j != ry) - { - blendpixel(x+i-rx, y-j+ry, r, g, b, a); - if (i != rx) - blendpixel(x-i+rx, y-j+ry, r, g, b, a); - } - } - } + BlendEllipse(Vec2(x, y), Vec2(rx, ry), RGBA(r, g, b, a)); } template void RasterDrawMethods::fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a) { - int yTop = ry+1, yBottom, i, j; - if (!rx) - { - for (j = -ry; j <= ry; j++) - blendpixel(x, y+j, r, g, b, a); - return; - } - for (i = 0; i <= rx; i++) - { - while (pow(i-rx,2.0)*pow(ry,2.0) + pow(yTop-ry,2.0)*pow(rx,2.0) <= pow(rx,2.0)*pow(ry,2.0)) - yTop++; - yBottom = 2*ry - yTop; - for (int j = yBottom+1; j < yTop; j++) - { - blendpixel(x+i-rx, y+j-ry, r, g, b, a); - if (i != rx) - blendpixel(x-i+rx, y+j-ry, r, g, b, a); - } - } -} - -template -void RasterDrawMethods::gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2) -{ - + BlendFilledEllipse(Vec2(x, y), Vec2(rx, ry), RGBA(r, g, b, a)); } template void RasterDrawMethods::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 rect = clipRect() & RectSized(Vec2(x, y), Vec2(w, h)); - x = rect.TopLeft.X; - y = rect.TopLeft.Y; - w = rect.Size().X; - h = rect.Size().Y; - - if (w<0 || h<0) - return; - - for (i=0; i void RasterDrawMethods::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 > VIDYRES) - h = ((VIDYRES)-y)-1; - // Too big - if (x + w > VIDXRES) - 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 (clipRect().Contains(Vec2(x + i, y + j))) - vid()[(y+j)*(VIDXRES)+(x+i)] = *img; - img++; - } - } - else - { - int r, g, b; - for (int j = 0; j < h; j++) - { - 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++; - } - } - } + BlendImage(img, a, RectSized(Vec2(x, y), Vec2(w, h))); } template @@ -488,3 +429,6 @@ void RasterDrawMethods::draw_image(const VideoBuffer * vidBuf, int x, i { draw_image(vidBuf->Buffer.data(), x, y, vidBuf->Width, vidBuf->Height, a); } + +#undef video +#undef clipRect diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index 9d12f05f4..2f956822f 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -6,9 +6,6 @@ #include "simulation/ElementGraphics.h" #include "simulation/Simulation.h" -#undef VIDXRES -#undef VIDYRES - constexpr auto VIDXRES = WINDOWW; constexpr auto VIDYRES = WINDOWH;