yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
headless_overlay_renderer.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5#include <cstdint>
6
7namespace yaze {
8namespace app {
9namespace service {
10
12 int width, int height,
13 float scale)
14 : rgba_(rgba), width_(width), height_(height), scale_(scale) {}
15
16void HeadlessOverlayRenderer::BlendPixel(int px, int py, uint8_t r, uint8_t g,
17 uint8_t b, uint8_t a) {
18 if (px < 0 || px >= width_ || py < 0 || py >= height_)
19 return;
20 const size_t base = static_cast<size_t>((py * width_ + px) * 4);
21 if (base + 3 >= rgba_.size())
22 return;
23
24 if (a == 255) {
25 rgba_[base + 0] = r;
26 rgba_[base + 1] = g;
27 rgba_[base + 2] = b;
28 rgba_[base + 3] = 255;
29 return;
30 }
31
32 // Porter-Duff src-over alpha blend.
33 const float fa = a / 255.0f;
34 const float fb = 1.0f - fa;
35 rgba_[base + 0] = static_cast<uint8_t>(r * fa + rgba_[base + 0] * fb);
36 rgba_[base + 1] = static_cast<uint8_t>(g * fa + rgba_[base + 1] * fb);
37 rgba_[base + 2] = static_cast<uint8_t>(b * fa + rgba_[base + 2] * fb);
38 rgba_[base + 3] = static_cast<uint8_t>(255 * fa + rgba_[base + 3] * fb);
39}
40
41void HeadlessOverlayRenderer::DrawFilledRect(float x, float y, float w, float h,
42 uint8_t r, uint8_t g, uint8_t b,
43 uint8_t a) {
44 const int x0 = static_cast<int>(std::floor(x * scale_));
45 const int y0 = static_cast<int>(std::floor(y * scale_));
46 const int x1 = static_cast<int>(std::ceil((x + w) * scale_));
47 const int y1 = static_cast<int>(std::ceil((y + h) * scale_));
48 for (int py = y0; py < y1; ++py) {
49 for (int px = x0; px < x1; ++px) {
50 BlendPixel(px, py, r, g, b, a);
51 }
52 }
53}
54
55void HeadlessOverlayRenderer::DrawRect(float x, float y, float w, float h,
56 uint8_t r, uint8_t g, uint8_t b,
57 uint8_t a) {
58 const int x0 = static_cast<int>(std::floor(x * scale_));
59 const int y0 = static_cast<int>(std::floor(y * scale_));
60 const int x1 = static_cast<int>(std::ceil((x + w) * scale_)) - 1;
61 const int y1 = static_cast<int>(std::ceil((y + h) * scale_)) - 1;
62
63 // Top and bottom edges.
64 for (int px = x0; px <= x1; ++px) {
65 BlendPixel(px, y0, r, g, b, a);
66 BlendPixel(px, y1, r, g, b, a);
67 }
68 // Left and right edges.
69 for (int py = y0 + 1; py < y1; ++py) {
70 BlendPixel(x0, py, r, g, b, a);
71 BlendPixel(x1, py, r, g, b, a);
72 }
73}
74
75void HeadlessOverlayRenderer::DrawLine(float x0, float y0, float x1, float y1,
76 uint8_t r, uint8_t g, uint8_t b,
77 uint8_t a) {
78 int px0 = static_cast<int>(x0 * scale_);
79 int py0 = static_cast<int>(y0 * scale_);
80 int px1 = static_cast<int>(x1 * scale_);
81 int py1 = static_cast<int>(y1 * scale_);
82
83 // Bresenham's line algorithm.
84 const int dx = std::abs(px1 - px0);
85 const int dy = std::abs(py1 - py0);
86 const int sx = (px0 < px1) ? 1 : -1;
87 const int sy = (py0 < py1) ? 1 : -1;
88 int err = dx - dy;
89
90 while (true) {
91 BlendPixel(px0, py0, r, g, b, a);
92 if (px0 == px1 && py0 == py1)
93 break;
94 const int e2 = 2 * err;
95 if (e2 > -dy) {
96 err -= dy;
97 px0 += sx;
98 }
99 if (e2 < dx) {
100 err += dx;
101 py0 += sy;
102 }
103 }
104}
105
106} // namespace service
107} // namespace app
108} // namespace yaze
void DrawRect(float x, float y, float w, float h, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
void BlendPixel(int px, int py, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
void DrawLine(float x0, float y0, float x1, float y1, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
void DrawFilledRect(float x, float y, float w, float h, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
HeadlessOverlayRenderer(std::vector< uint8_t > &rgba, int width, int height, float scale=1.0f)