1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
/*
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Array.h>
#include <AK/GenericShorthands.h>
#include <AK/Vector.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/PaintStyle.h>
#include <LibGfx/Painter.h>
#include <LibGfx/Path.h>
namespace Gfx {
namespace Detail {
static auto constexpr coverage_lut = [] {
Array<u8, 256> coverage_lut {};
for (u32 sample = 0; sample <= 255; sample++)
coverage_lut[sample] = popcount(sample);
return coverage_lut;
}();
template<unsigned SamplesPerPixel>
struct Sample {
static_assert(!first_is_one_of(SamplesPerPixel, 8u, 16u, 32u), "EdgeFlagPathRasterizer: Invalid samples per pixel!");
};
// See paper for diagrams for how these offsets work, but they allow for nicely spread out samples in each pixel.
template<>
struct Sample<8> {
using Type = u8;
static constexpr Array nrooks_subpixel_offsets {
(5.0f / 8.0f),
(0.0f / 8.0f),
(3.0f / 8.0f),
(6.0f / 8.0f),
(1.0f / 8.0f),
(4.0f / 8.0f),
(7.0f / 8.0f),
(2.0f / 8.0f),
};
static u8 compute_coverage(Type sample)
{
return coverage_lut[sample];
}
};
template<>
struct Sample<16> {
using Type = u16;
static constexpr Array nrooks_subpixel_offsets {
(1.0f / 16.0f),
(8.0f / 16.0f),
(4.0f / 16.0f),
(15.0f / 16.0f),
(11.0f / 16.0f),
(2.0f / 16.0f),
(6.0f / 16.0f),
(14.0f / 16.0f),
(10.0f / 16.0f),
(3.0f / 16.0f),
(7.0f / 16.0f),
(12.0f / 16.0f),
(0.0f / 16.0f),
(9.0f / 16.0f),
(5.0f / 16.0f),
(13.0f / 16.0f),
};
static u8 compute_coverage(Type sample)
{
return (
coverage_lut[(sample >> 0) & 0xff]
+ coverage_lut[(sample >> 8) & 0xff]);
}
};
template<>
struct Sample<32> {
using Type = u32;
static constexpr Array nrooks_subpixel_offsets {
(28.0f / 32.0f),
(13.0f / 32.0f),
(6.0f / 32.0f),
(23.0f / 32.0f),
(0.0f / 32.0f),
(17.0f / 32.0f),
(10.0f / 32.0f),
(27.0f / 32.0f),
(4.0f / 32.0f),
(21.0f / 32.0f),
(14.0f / 32.0f),
(31.0f / 32.0f),
(8.0f / 32.0f),
(25.0f / 32.0f),
(18.0f / 32.0f),
(3.0f / 32.0f),
(12.0f / 32.0f),
(29.0f / 32.0f),
(22.0f / 32.0f),
(7.0f / 32.0f),
(16.0f / 32.0f),
(1.0f / 32.0f),
(26.0f / 32.0f),
(11.0f / 32.0f),
(20.0f / 32.0f),
(5.0f / 32.0f),
(30.0f / 32.0f),
(15.0f / 32.0f),
(24.0f / 32.0f),
(9.0f / 32.0f),
(2.0f / 32.0f),
(19.0f / 32.0f),
};
static u8 compute_coverage(Type sample)
{
return (
coverage_lut[(sample >> 0) & 0xff]
+ coverage_lut[(sample >> 8) & 0xff]
+ coverage_lut[(sample >> 16) & 0xff]
+ coverage_lut[(sample >> 24) & 0xff]);
}
};
struct Edge {
float x;
int min_y;
int max_y;
float dxdy;
i8 winding;
Edge* next_edge;
};
}
template<unsigned SamplesPerPixel = 32>
class EdgeFlagPathRasterizer {
public:
EdgeFlagPathRasterizer(IntSize);
void fill(Painter&, Path const&, Color, Painter::WindingRule, FloatPoint offset = {});
void fill(Painter&, Path const&, PaintStyle const&, Painter::WindingRule, FloatPoint offset = {});
private:
using SubpixelSample = Detail::Sample<SamplesPerPixel>;
using SampleType = typename SubpixelSample::Type;
static u8 coverage_to_alpha(u8 coverage)
{
constexpr auto alpha_shift = AK::log2(256 / SamplesPerPixel);
if (!coverage)
return 0;
return (coverage << alpha_shift) - 1;
}
void fill_internal(Painter&, Path const&, auto color_or_function, Painter::WindingRule, FloatPoint offset);
Detail::Edge* plot_edges_for_scanline(int scanline, auto plot_edge, Detail::Edge* active_edges = nullptr);
void accumulate_even_odd_scanline(Painter&, int scanline, auto& color_or_function);
void accumulate_non_zero_scanline(Painter&, int scanline, auto& color_or_function);
Color scanline_color(int scanline, int offset, u8 alpha, auto& color_or_function);
void write_pixel(Painter&, int scanline, int offset, SampleType sample, auto& color_or_function);
struct WindingCounts {
// NOTE: This only allows up to 256 winding levels. Increase this if required (i.e. to an i16).
i8 counts[SamplesPerPixel];
};
IntSize m_size;
IntPoint m_blit_origin;
IntRect m_clip;
Vector<SampleType> m_scanline;
Vector<WindingCounts> m_windings;
Vector<Detail::Edge*> m_edge_table;
};
extern template class EdgeFlagPathRasterizer<8>;
extern template class EdgeFlagPathRasterizer<16>;
extern template class EdgeFlagPathRasterizer<32>;
}
|