9 #include "AreaShader.h"
26 typedef WFMath::Point<2> Point2;
27 typedef WFMath::Vector<2> Vector2;
29 const WFMath::CoordType ROW_HEIGHT = 1 / 4.0f;
39 Edge(
const Point2& a,
const Point2& b)
42 assert(a.y() != b.y());
54 m_inverseGradient = m_seg.x() / m_seg.y();
58 Point2
start()
const {
return m_start; }
60 Point2
end()
const {
return m_start + m_seg; }
67 WFMath::CoordType
xValueAtZ(WFMath::CoordType z)
const
69 WFMath::CoordType x = m_start.x() + ((z - m_start.y()) * m_inverseGradient);
80 return m_start.y() < other.m_start.y();
88 WFMath::CoordType m_inverseGradient;
98 explicit EdgeAtZ(WFMath::CoordType y) : m_y(y) {}
107 WFMath::CoordType m_y;
110 static void contribute(Surface& s,
111 unsigned int x,
unsigned int z,
112 WFMath::CoordType amount)
114 unsigned int sz = s.getSize() - 1;
115 if ((x == 0) || (x == sz))
118 if ((z == 0) || (z == sz))
121 s(x, z, 0) = std::min(
static_cast<ColorT
>(I_ROUND(amount * 255)) + s(x,z,0), 255);
124 static void span(Surface& s,
126 WFMath::CoordType xStart,
127 WFMath::CoordType xEnd)
129 assert(xStart <= xEnd);
132 unsigned int row = I_ROUND(z),
133 ixStart = I_ROUND(xStart),
134 ixEnd = I_ROUND(xEnd);
138 if (ixStart == ixEnd) {
139 contribute(s, ixStart, row, ROW_HEIGHT * (xEnd - xStart));
141 contribute(s, ixStart, row, ROW_HEIGHT * (ixStart - xStart + 0.5f));
143 for (
unsigned int i=ixStart+1; i < ixEnd; ++i)
144 contribute(s, i, row, ROW_HEIGHT);
146 contribute(s, ixEnd, row, ROW_HEIGHT * (xEnd - ixEnd + 0.5f));
150 static void scanConvert(
const WFMath::Polygon<2>& inPoly, Surface& sf)
152 if (!inPoly.isValid())
return;
154 std::list<Edge> pending;
155 std::vector<Edge> active;
157 Point2 lastPt = inPoly.getCorner(inPoly.numCorners() - 1);
158 for (std::size_t p=0; p < inPoly.numCorners(); ++p) {
159 Point2 curPt = inPoly.getCorner(p);
162 if (curPt.y() != lastPt.y())
163 pending.emplace_back(lastPt, curPt);
168 if (pending.empty())
return;
172 active.push_back(pending.front());
179 WFMath::CoordType z = std::floor(active.front().start().y()) + ROW_HEIGHT * 0.5f;
181 for (; !pending.empty() || !active.empty(); z += ROW_HEIGHT)
183 while (!pending.empty() && (pending.front().start().y() <= z)) {
184 active.push_back(pending.front());
189 std::sort(active.begin(), active.end(), EdgeAtZ(z));
192 for (
unsigned int i=0; i< active.size(); ) {
193 if (active[i].end().y() <= z)
194 active.erase(active.begin() + i);
200 for (
unsigned int i=1; i < active.size(); i += 2)
201 span(sf, z, active[i - 1].xValueAtZ(z), active[i].xValueAtZ(z));
215 return (areas.count(m_layer) > 0);
223 unsigned int buflen = size * size;
224 for (
unsigned int i = 0; i < buflen; ++i) data[i] = 0;
227 auto it = areas.lower_bound(m_layer);
228 auto itend = areas.upper_bound(m_layer);
230 for (;it != itend; ++it) {
232 if (it->second.area->isHole()) {
235 shadeArea(s, *it->second.area);
239 void AreaShader::shadeArea(
Surface& s,
const Area& ar)
const
242 assert(clipped.isValid());
244 if (clipped.numCorners() == 0)
return;
247 clipped.shift(Point2(0,0) - segOrigin);
248 scanConvert(clipped, s);