Refactor raster draw methods

This commit is contained in:
mniip 2023-04-03 18:48:50 +02:00 committed by mniip
parent e93db9c06a
commit caab738184
6 changed files with 372 additions and 362 deletions

View File

@ -88,10 +88,12 @@ public:
PlaneAdapter(PlaneAdapter &&) = default;
// PlaneAdapter<T> can be constructed from (Vec2, T &&)
// PlaneAdapter<T &> can be constructed from (Vec2, T &)
PlaneAdapter(Vec2<int> size, T &&base):
xExtent<Width>(size.X),
yExtent<Height>(size.Y),
Base(std::move(base))
Base(std::forward<T>(base))
{}
template<typename... Args>

View File

@ -1,15 +1,16 @@
#include <algorithm>
#include <bzlib.h>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <memory>
#include <png.h>
#include "common/platform/Platform.h"
#include "FontReader.h"
#include "Graphics.h"
#include "resampler/resampler.h"
#include "SimulationConfig.h"
#include "RasterDrawMethodsImpl.h"
VideoBuffer::VideoBuffer(Vec2<int> 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<VideoBuffer>;
pixel *Graphics::resample_img_nn(pixel * src, int sw, int sh, int rw, int rh)
{
int y, x;

View File

@ -61,6 +61,8 @@ public:
[[deprecated("Use Crop(Rect<int>)")]]
void Crop(int width, int height, int x, int y);
using RasterDrawMethods<VideoBuffer>::BlendPixel;
[[deprecated("Use BlendPixel(Vec2<int>, RGBA<uint8_t>)")]]
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<VideoBuffer>::AddPixel;
[[deprecated("Use AddPixel(Vec2<int>, RGBA<uint8_t>)")]]
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;

View File

@ -10,23 +10,79 @@ class VideoBuffer;
template<typename Derived>
struct RasterDrawMethods
{
void DrawPixel(Vec2<int>, RGB<uint8_t>);
void BlendPixel(Vec2<int>, RGBA<uint8_t>);
void AddPixel(Vec2<int>, RGBA<uint8_t>);
void XorPixel(Vec2<int>);
void DrawLine(Vec2<int>, Vec2<int>, RGB<uint8_t>);
void BlendLine(Vec2<int>, Vec2<int>, RGBA<uint8_t>);
void AddLine(Vec2<int>, Vec2<int>, RGBA<uint8_t>);
void XorLine(Vec2<int>, Vec2<int>);
void DrawRect(Rect<int>, RGB<uint8_t>);
void BlendRect(Rect<int>, RGBA<uint8_t>);
void XorDottedRect(Rect<int>);
void DrawFilledRect(Rect<int>, RGB<uint8_t>);
void BlendFilledRect(Rect<int>, RGBA<uint8_t>);
void BlendEllipse(Vec2<int> center, Vec2<int> size, RGBA<uint8_t>);
void BlendFilledEllipse(Vec2<int> center, Vec2<int> size, RGBA<uint8_t>);
void BlendImage(pixel const *, uint8_t alpha, Rect<int>);
void BlendImage(pixel const *, uint8_t alpha, Rect<int>, size_t rowStride);
void XorImage(unsigned char const *, Rect<int>);
void XorImage(unsigned char const *, Rect<int>, size_t rowStride);
// Returns width of character
int BlendChar(Vec2<int>, String::value_type, RGBA<uint8_t>);
int AddChar(Vec2<int>, String::value_type, RGBA<uint8_t>);
// Returns the offset between the first character and the
// would-be-next character
Vec2<int> BlendText(Vec2<int>, String const &, RGBA<uint8_t>);
Vec2<int> BlendTextOutline(Vec2<int>, String const &, RGBA<uint8_t>);
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);
};

View File

@ -1,118 +1,327 @@
#include <cmath>
#include <cstring>
#include "RasterDrawMethods.h"
#include "Graphics.h"
#include "common/RasterGeometry.h"
#include "FontReader.h"
#include "Graphics.h"
#include "RasterDrawMethods.h"
#define vid() (static_cast<Derived &>(*this).video.RowIterator(Vec2(0, 0)))
#define video() (static_cast<Derived &>(*this).video)
#define clipRect() (static_cast<Derived const &>(*this).getClipRect())
#define VIDXRES (static_cast<Derived const &>(*this).video.Size().X)
#define VIDYRES (static_cast<Derived const &>(*this).video.Size().Y)
template<typename Derived>
int RasterDrawMethods<Derived>::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a)
template<typename Derived, typename V>
static inline void drawPixelUnchecked(RasterDrawMethods<Derived> &self, V Derived::*video, Vec2<int> pos, RGB<uint8_t> colour)
{
drawtext(x-1, y-1, s, 0, 0, 0, 120);
drawtext(x+1, y+1, s, 0, 0, 0, 120);
(static_cast<Derived &>(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<typename Derived, typename V>
static inline void blendPixelUnchecked(RasterDrawMethods<Derived> &self, V Derived::*video, Vec2<int> pos, RGBA<uint8_t> colour)
{
pixel &px = (static_cast<Derived &>(self).*video)[pos];
px = RGB<uint8_t>::Unpack(px).Blend(colour).Pack();
}
return drawtext(x, y, s, r, g, b, a);
template<typename Derived, typename V>
static inline void xorPixelUnchecked(RasterDrawMethods<Derived> &self, V Derived::*video, Vec2<int> pos)
{
pixel &px = (static_cast<Derived &>(self).*video)[pos];
auto const c = RGB<uint8_t>::Unpack(px);
if (2 * c.Red + 3 * c.Green + c.Blue < 512)
px = 0xC0C0C0_rgb .Pack();
else
px = 0x404040_rgb .Pack();
}
template<typename Derived>
int RasterDrawMethods<Derived>::drawtext(int x, int y, const String &str, int r, int g, int b, int a)
inline void RasterDrawMethods<Derived>::DrawPixel(Vec2<int> pos, RGB<uint8_t> colour)
{
if(!str.size())
return 0;
if (clipRect().Contains(pos))
drawPixelUnchecked(*this, &Derived::video, pos, colour);
}
template<typename Derived>
inline void RasterDrawMethods<Derived>::BlendPixel(Vec2<int> pos, RGBA<uint8_t> colour)
{
if (clipRect().Contains(pos))
blendPixelUnchecked(*this, &Derived::video, pos, colour);
}
template<typename Derived>
inline void RasterDrawMethods<Derived>::AddPixel(Vec2<int> pos, RGBA<uint8_t> colour)
{
if (clipRect().Contains(pos))
{
pixel &px = (static_cast<Derived &>(*this).video)[pos];
px = RGB<uint8_t>::Unpack(px).Add(colour).Pack();
}
}
template<typename Derived>
inline void RasterDrawMethods<Derived>::XorPixel(Vec2<int> pos)
{
if (clipRect().Contains(pos))
xorPixelUnchecked(*this, &Derived::video, pos);
}
template<typename Derived>
void RasterDrawMethods<Derived>::DrawLine(Vec2<int> pos1, Vec2<int> pos2, RGB<uint8_t> colour)
{
RasterizeLine<false>(pos1, pos2, [this, colour](Vec2<int> pos) {
DrawPixel(pos, colour);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::BlendLine(Vec2<int> pos1, Vec2<int> pos2, RGBA<uint8_t> colour)
{
RasterizeLine<false>(pos1, pos2, [this, colour](Vec2<int> pos) {
BlendPixel(pos, colour);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::AddLine(Vec2<int> pos1, Vec2<int> pos2, RGBA<uint8_t> colour)
{
RasterizeLine<false>(pos1, pos2, [this, colour](Vec2<int> pos) {
AddPixel(pos, colour);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::XorLine(Vec2<int> pos1, Vec2<int> pos2)
{
RasterizeLine<false>(pos1, pos2, [this](Vec2<int> pos) {
XorPixel(pos);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::DrawRect(Rect<int> rect, RGB<uint8_t> colour)
{
RasterizeRect(rect, [this, colour](Vec2<int> pos) {
DrawPixel(pos, colour);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::BlendRect(Rect<int> rect, RGBA<uint8_t> colour)
{
RasterizeRect(rect, [this, colour](Vec2<int> pos) {
BlendPixel(pos, colour);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::XorDottedRect(Rect<int> rect)
{
RasterizeDottedRect(rect, [this](Vec2<int> pos) {
XorPixel(pos);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::DrawFilledRect(Rect<int> rect, RGB<uint8_t> colour)
{
rect &= clipRect();
pixel packed = colour.Pack();
auto &video = static_cast<Derived &>(*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<typename Derived>
void RasterDrawMethods<Derived>::BlendFilledRect(Rect<int> rect, RGBA<uint8_t> colour)
{
for (auto pos : rect & clipRect())
blendPixelUnchecked(*this, &Derived::video, pos, colour);
}
template<typename Derived>
void RasterDrawMethods<Derived>::BlendEllipse(Vec2<int> center, Vec2<int> size, RGBA<uint8_t> colour)
{
RasterizeEllipsePoints(Vec2(float(size.X * size.X), float(size.Y * size.Y)), [this, center, colour](Vec2<int> delta) {
BlendPixel(center + delta, colour);
});
}
template<typename Derived>
void RasterDrawMethods<Derived>::BlendFilledEllipse(Vec2<int> center, Vec2<int> size, RGBA<uint8_t> 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<typename Derived>
void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Rect<int> rect)
{
BlendImage(data, alpha, rect, rect.Size().X);
}
template<typename Derived>
void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Rect<int> rect, size_t rowStride)
{
auto origin = rect.TopLeft;
rect &= clipRect();
if (alpha == 0xFF)
{
auto &video = static_cast<Derived &>(*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<uint8_t>::Unpack(px).WithAlpha(alpha));
}
}
}
template<typename Derived>
void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> rect)
{
XorImage(data, rect, rect.Size().X);
}
template<typename Derived>
void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> 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<typename Derived>
int RasterDrawMethods<Derived>::BlendChar(Vec2<int> pos, String::value_type ch, RGBA<uint8_t> colour)
{
FontReader reader(ch);
auto const rect = RectSized(Vec2(0, -2), Vec2(reader.GetWidth(), FONT_H));
for (auto off : rect.template Range<TOP_TO_BOTTOM, LEFT_TO_RIGHT>())
BlendPixel(pos + off, colour.NoAlpha().WithAlpha(reader.NextPixel() * colour.Alpha / 3));
return reader.GetWidth();
}
template<typename Derived>
int RasterDrawMethods<Derived>::AddChar(Vec2<int> pos, String::value_type ch, RGBA<uint8_t> colour)
{
FontReader reader(ch);
RGB<uint8_t> const c = colour.NoAlpha();
auto const rect = RectSized(Vec2(0, -2), Vec2(reader.GetWidth(), FONT_H));
for (auto off : rect.template Range<TOP_TO_BOTTOM, LEFT_TO_RIGHT>())
AddPixel(pos + off, c.WithAlpha(reader.NextPixel() * colour.Alpha / 3));
return reader.GetWidth();
}
template<typename Derived>
Vec2<int> RasterDrawMethods<Derived>::BlendText(Vec2<int> orig_pos, String const &str, RGBA<uint8_t> 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<uint8_t> colour = orig_colour.NoAlpha();
uint8_t alpha = orig_colour.Alpha;
Vec2<int> 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);
for (int i = 0; i < dx; i++)
BlendPixel(pos + Vec2(i, FONT_H), colour.WithAlpha(alpha));
pos.X += dx;
}
}
characterX = newCharacterX;
}
}
return x;
return pos - orig_pos;
}
template<typename Derived>
Vec2<int> RasterDrawMethods<Derived>::BlendTextOutline(Vec2<int> pos, String const &str, RGBA<uint8_t> 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<typename Derived>
void RasterDrawMethods<Derived>::Clear()
{
auto &video = static_cast<Derived &>(*this).video;
std::fill_n(video.data(), video.Size().X * video.Size().Y, 0x000000_rgb .Pack());
}
template<typename Derived>
int RasterDrawMethods<Derived>::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<uint8_t>(r, g, b, a)).X;
}
template<typename Derived>
int RasterDrawMethods<Derived>::drawtext(int x, int y, const String &str, int r, int g, int b, int a)
{
return x + BlendText(Vec2(x, y), str, RGBA<uint8_t>(r, g, b, a)).X;
}
template<typename Derived>
int RasterDrawMethods<Derived>::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<uint8_t>(r, g, b, a));
}
template<typename Derived>
@ -128,359 +337,91 @@ 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 (!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<typename Derived>
void RasterDrawMethods<Derived>::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<uint8_t>(r, g, b));
else
BlendPixel(Vec2(x, y), RGBA<uint8_t>(r, g, b, a));
}
template<typename Derived>
void RasterDrawMethods<Derived>::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<uint8_t>(r, g, b, a));
}
template<typename Derived>
void RasterDrawMethods<Derived>::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<y2) ? 1 : -1;
for (x=x1; x<=x2; x++)
{
if (cp)
xor_pixel(y, x);
else
xor_pixel(x, y);
e += de;
if (e >= 0.5f)
{
y += sy;
e -= 1.0f;
}
}
XorLine(Vec2(x1, y1), Vec2(x2, y2));
}
template<typename Derived>
void RasterDrawMethods<Derived>::xor_rect(int x, int y, int w, int h)
{
int i;
for (i=0; i<w; i+=2)
{
xor_pixel(x+i, y);
}
if (h != 1)
{
if (h%2 == 1) i = 2;
else i = 1;
for (; i<w; i+=2)
{
xor_pixel(x+i, y+h-1);
}
}
for (i=2; i<h; i+=2)
{
xor_pixel(x, y+i);
}
if (w != 1)
{
if (w%2 == 1) i = 2;
else i = 1;
for (; i<h-1; i+=2)
{
xor_pixel(x+w-1, y+i);
}
}
XorDottedRect(RectSized(Vec2(x, y), Vec2(w, h)));
}
template<typename Derived>
void RasterDrawMethods<Derived>::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<typename Derived>
void RasterDrawMethods<Derived>::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<uint8_t>(r, g, b));
else
de = 0.0f;
y = y1;
sy = (y1<y2) ? 1 : -1;
for (x=x1; x<=x2; x++)
{
if (cp)
blendpixel(y, x, r, g, b, a);
else
blendpixel(x, y, r, g, b, a);
e += de;
if (e >= 0.5f)
{
y += sy;
e -= 1.0f;
}
}
BlendLine(Vec2(x1, y1), Vec2(x2, y2), RGBA<uint8_t>(r, g, b, a));
}
template<typename Derived>
void RasterDrawMethods<Derived>::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<h; i++)
{
blendpixel(x, y+i, r, g, b, a);
blendpixel(x+w, y+i, r, g, b, a);
}
if (a == 0xFF)
DrawRect(RectSized(Vec2(x, y), Vec2(w, h)), RGB<uint8_t>(r, g, b));
else
BlendRect(RectSized(Vec2(x, y), Vec2(w, h)), RGBA<uint8_t>(r, g, b, a));
}
template<typename Derived>
void RasterDrawMethods<Derived>::fillrect(int x, int y, int w, int h, int r, int g, int b, int a)
{
int i,j;
for (j=0; j<h; j++)
for (i=0; i<w; i++)
blendpixel(x+i, y+j, r, g, b, a);
if (a == 0xFF)
DrawFilledRect(RectSized(Vec2(x, y), Vec2(w, h)), RGB<uint8_t>(r, g, b));
else
BlendFilledRect(RectSized(Vec2(x, y), Vec2(w, h)), RGBA<uint8_t>(r, g, b, a));
}
template<typename Derived>
void RasterDrawMethods<Derived>::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<uint8_t>(r, g, b, a));
}
template<typename Derived>
void RasterDrawMethods<Derived>::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<typename Derived>
void RasterDrawMethods<Derived>::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<uint8_t>(r, g, b, a));
}
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 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<h; i++)
memset(vid()+(x+(VIDXRES)*(y+i)), 0, PIXELSIZE*w);
DrawFilledRect(RectSized(Vec2(x + 1, y + 1), Vec2(w - 1, h - 1)), 0x000000_rgb);
}
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 > 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<typename Derived>
@ -488,3 +429,6 @@ void RasterDrawMethods<Derived>::draw_image(const VideoBuffer * vidBuf, int x, i
{
draw_image(vidBuf->Buffer.data(), x, y, vidBuf->Width, vidBuf->Height, a);
}
#undef video
#undef clipRect

View File

@ -6,9 +6,6 @@
#include "simulation/ElementGraphics.h"
#include "simulation/Simulation.h"
#undef VIDXRES
#undef VIDYRES
constexpr auto VIDXRES = WINDOWW;
constexpr auto VIDYRES = WINDOWH;