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