26typedef WFMath::Point<2> Point2;
27typedef WFMath::Vector<2> Vector2;
29const 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;
110static 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);
124static 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));
150static 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);
239void 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);
AreaShader(int layer)
Constructor.
bool checkIntersect(const Segment &) const override
Check whether this Shader has any effect on the given Segment.
void shade(Surface &s) const override
Populate a Surface with data.
Region of terrain surface which is modified.
WFMath::Polygon< 2 > clipToSegment(const Segment &s) const
Clip the shape of this area to a given segment.
DataType * getData()
Accessor for a pointer to buffer containing data values.
The edge of an area parallel to the x axis.
bool operator()(const Edge &u, const Edge &v) const
Determine which edge crosses this edge at a lower x coordinate.
EdgeAtZ(WFMath::CoordType y)
Point2 start() const
Accessor for the point describing the start of the edge.
Point2 end() const
Determine the point describing the end of the edge.
WFMath::CoordType xValueAtZ(WFMath::CoordType z) const
Determine the x coordinate at a given y coordinate.
Edge(const Point2 &a, const Point2 &b)
Constructor.
bool operator<(const Edge &other) const
Compare the y coordinate of the start with another edge.
Class storing heightfield and other data for a single fixed size square area of terrain defined by fo...
std::multimap< int, AreaEntry > Areastore
STL multimap of pointers to Area objects affecting this segment.
WFMath::AxisBox< 2 > getRect() const
The 2d area covered by this segment.
int getSize() const
Accessor for array size of this segment.
const Areastore & getAreas() const
Accessor for multimap of Area objects.
Base class for Shader objects which create surface data for use when rendering terrain.
Data store for terrain surface data.
const Segment & getSegment() const
Accessor for the terrain height segment this surface is associated with.
const Segment & m_segment
The terrain height segment this buffer is associated with.