mercator  0.4.0
A terrain generation library for the Worldforge system.
GrassShader.cpp
1 // This file may be redistributed and modified only under the terms of
2 // the GNU General Public License (See COPYING for details).
3 // Copyright (C) 2003 Alistair Riddoch
4 
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif
8 
9 #include "GrassShader.h"
10 
11 #include "Segment.h"
12 #include "Surface.h"
13 
14 #include <cmath>
15 
16 #include <cassert>
17 
18 namespace Mercator {
19 
20 const std::string GrassShader::key_lowThreshold("lowThreshold");
21 const std::string GrassShader::key_highThreshold("highThreshold");
22 const std::string GrassShader::key_cutoff("cutoff");
23 const std::string GrassShader::key_intercept("intercept");
24 
25 const float GrassShader::default_lowThreshold = 1.f;
26 const float GrassShader::default_highThreshold = 20.f;
27 const float GrassShader::default_cutoff = 1.f;
28 const float GrassShader::default_intercept = 2.f;
29 
30 GrassShader::GrassShader(float lowThreshold, float highThreshold,
31  float cutoff, float intercept) :
32  m_lowThreshold(lowThreshold), m_highThreshold(highThreshold),
33  m_cutoff(cutoff), m_intercept(intercept)
34 {
35 }
36 
38  m_lowThreshold(default_lowThreshold),
39  m_highThreshold(default_highThreshold),
40  m_cutoff(default_cutoff),
41  m_intercept(default_intercept)
42 {
43  auto I = params.find(key_lowThreshold);
44  auto Iend = params.end();
45  if (I != Iend) {
46  m_lowThreshold = I->second;
47  }
48  I = params.find(key_highThreshold);
49  if (I != Iend) {
50  m_highThreshold = I->second;
51  }
52  I = params.find(key_cutoff);
53  if (I != Iend) {
54  m_cutoff = I->second;
55  }
56  I = params.find(key_intercept);
57  if (I != Iend) {
58  m_intercept = I->second;
59  }
60 
61 }
62 
63 GrassShader::~GrassShader() = default;
64 
65 inline ColorT GrassShader::slopeToAlpha(float height, float slope) const
66 {
67  if ((height < m_lowThreshold) ||
68  (height > m_highThreshold) ||
69  (slope > m_intercept)) {
70  return colorMin;
71  } else if (slope < m_cutoff) {
72  return colorMax;
73  } else {
74  return (ColorT)(colorMax * ((slope - m_cutoff) / (m_intercept - m_cutoff)));
75  }
76 }
77 
78 bool GrassShader::checkIntersect(const Segment & s) const
79 {
80  if ((s.getMin() < m_highThreshold) &&
81  (s.getMax() > m_lowThreshold)) {
82  return true;
83  } else {
84  return false;
85  }
86 }
87 
88 void GrassShader::shade(Surface & s) const
89 {
90  unsigned int channels = s.getChannels();
91  assert(channels > 0);
92  unsigned int chanAlpha = channels - 1;
93  const Segment & seg = s.getSegment();
94  ColorT * data = s.getData();
95  const float * height_data = seg.getPoints();
96  if (height_data == nullptr) {
97  std::cerr << "WARNING: Mercator: Attempting to shade empty segment."
98  << std::endl << std::flush;
99  return;
100  }
101  int size = seg.getSize();
102  int res = seg.getResolution();
103 
104  unsigned int data_count = size * size * channels;
105  for (unsigned int i = 0; i < data_count; ++i) {
106  data[i] = colorMax;
107  }
108 
109  // Deal with corner points
110  s(0, 0, chanAlpha) = slopeToAlpha(seg.get(0,0), 0.f);
111  s(res, 0, chanAlpha) = slopeToAlpha(seg.get(res,0), 0.f);
112  s(0, res, chanAlpha) = slopeToAlpha(seg.get(0,res), 0.f);
113  s(res, res, chanAlpha) = slopeToAlpha(seg.get(res,res), 0.f);
114 
115  for (int i = 1; i < res; ++i) {
116  float height = seg.get(i, 0);
117  float avgSlope = (std::fabs(seg.get(i - 1, 0) - height) +
118  std::fabs(seg.get(i + 1, 0) - height)) / 2.f;
119  s(i, 0, chanAlpha) = slopeToAlpha(height, avgSlope);
120 
121  height = seg.get(i, res);
122  avgSlope = (std::fabs(seg.get(i - 1, res) - height) +
123  std::fabs(seg.get(i + 1, res) - height)) / 2.f;
124  s(i, res, chanAlpha) = slopeToAlpha(height, avgSlope);
125 
126  height = seg.get(0, i);
127  avgSlope = (std::fabs(seg.get(0, i - 1) - height) +
128  std::fabs(seg.get(0, i + 1) - height)) / 2.f;
129  s(0, i, chanAlpha) = slopeToAlpha(height, avgSlope);
130 
131  height = seg.get(res, i);
132  avgSlope = (std::fabs(seg.get(res, i - 1) - height) +
133  std::fabs(seg.get(res, i + 1) - height)) / 2.f;
134  s(res, i, chanAlpha) = slopeToAlpha(height, avgSlope);
135  for (int j = 1; j < res; ++j) {
136  height = seg.get(i, j);
137  avgSlope = (std::fabs(seg.get(i + 1, j ) - height) +
138  std::fabs(seg.get(i , j + 1) - height) +
139  std::fabs(seg.get(i - 1, j ) - height) +
140  std::fabs(seg.get(i , j - 1) - height)) / 4.f;
141  s(i, j, chanAlpha) = slopeToAlpha(height, avgSlope);
142  }
143  }
144 }
145 
146 } // namespace Mercator
DataType * getData()
Accessor for a pointer to buffer containing data values.
Definition: Buffer.h:63
unsigned int getChannels() const
Accessor for the number of data values per height point.
Definition: Buffer.h:58
static const std::string key_lowThreshold
Key string used when specifying the low threshold parameter.
Definition: GrassShader.h:70
static const std::string key_cutoff
Key string used when specifying the cutoff parameter.
Definition: GrassShader.h:74
static const float default_lowThreshold
Default level above which the shader renders.
Definition: GrassShader.h:79
void shade(Surface &) const override
Populate a Surface with data.
Definition: GrassShader.cpp:88
GrassShader(float lowThreshold=default_lowThreshold, float highThreshold=default_highThreshold, float cutoff=default_cutoff, float intercept=default_intercept)
Constructor.
Definition: GrassShader.cpp:30
static const float default_highThreshold
Default level below which the shader renders.
Definition: GrassShader.h:81
bool checkIntersect(const Segment &) const override
Check whether this Shader has any effect on the given Segment.
Definition: GrassShader.cpp:78
static const float default_intercept
Default slope steeper than which no grass grows.
Definition: GrassShader.h:85
static const std::string key_highThreshold
Key string used when specifying the high threshold parameter.
Definition: GrassShader.h:72
static const float default_cutoff
Default slope below which grass is opaque.
Definition: GrassShader.h:83
static const std::string key_intercept
Key string used when specifying the intercept parameter.
Definition: GrassShader.h:76
Class storing heightfield and other data for a single fixed size square area of terrain defined by fo...
Definition: Segment.h:37
int getResolution() const
Accessor for resolution of this segment.
Definition: Segment.h:83
int getSize() const
Accessor for array size of this segment.
Definition: Segment.h:88
const float * getPoints() const
Accessor for buffer containing height points.
Definition: Segment.h:143
float getMin() const
Accessor for the minimum height value in this Segment.
Definition: Segment.h:191
float getMax() const
Accessor for the maximum height value in this Segment.
Definition: Segment.h:189
float get(int x, int z) const
Get the height at a relative integer position in the Segment.
Definition: Segment.h:173
std::map< std::string, float > Parameters
STL map of parameter values for a shader constructor.
Definition: Shader.h:59
Data store for terrain surface data.
Definition: Surface.h:23
const Segment & getSegment() const
Accessor for the terrain height segment this surface is associated with.
Definition: Surface.h:37