|
|
|
@ -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
|
|
|
|
|