28 static const SVertexAttribDesc st_attrib_end = VERTEX_ATTRIB_END();
61 _height_scale(copy._height_scale)
85 GeomEnums::NT_stdfloat, GeomEnums::C_point,
86 InternalName::get_texcoord(), 3,
87 GeomEnums::NT_stdfloat, GeomEnums::C_texcoord));
88 set_vertex_format(format);
106 Filename fullpath = Filename::text_filename(terrain_filename);
109 if (!vfs->
exists(fullpath)) {
110 speedtree_cat.warning()
111 <<
"Couldn't find " << terrain_filename <<
"\n";
116 fullpath =
Filename(fullpath,
"terrain.txt");
121 speedtree_cat.warning()
122 <<
"Couldn't open " << terrain_filename <<
"\n";
147 while (in && !in.eof()) {
148 if (keyword ==
"area") {
153 _size = csqrt(area) * speedtree_area_scale;
155 }
else if (keyword ==
"height_scale") {
158 }
else if (keyword ==
"normalmap_b_scale") {
159 PN_stdfloat normalmap_b_scale;
160 in >> normalmap_b_scale;
162 }
else if (keyword ==
"heightmap") {
163 read_quoted_filename(_height_map, in, dirname);
165 }
else if (keyword ==
"texture") {
167 read_quoted_filename(splat._filename, in, dirname);
169 splat._color.set(1.0f, 1.0f, 1.0f, 1.0f);
170 _splat_layers.push_back(splat);
172 }
else if (keyword ==
"color") {
176 if (!_splat_layers.empty()) {
177 _splat_layers.back()._color.set(r, g, b, 1.0f);
180 }
else if (keyword ==
"ambient" || keyword ==
"diffuse" || keyword ==
"specular" || keyword ==
"emissive") {
184 }
else if (keyword ==
"shininess") {
189 speedtree_cat.error()
190 <<
"Invalid token " << keyword <<
" in " << pathname <<
"\n";
205 speedtree_cat.error()
206 <<
"Unexpected text in " << pathname <<
" at \"" << text <<
"\"\n";
211 if (!_splat_layers.empty()) {
212 _normal_map = _splat_layers[0]._filename;
213 _splat_layers.erase(_splat_layers.begin());
215 if (!_splat_layers.empty()) {
216 _splat_map = _splat_layers[0]._filename;
217 _splat_layers.erase(_splat_layers.begin());
237 if (!read_height_map()) {
251 return _height_data.calc_bilinear_interpolation(x / _size, y / _size);
261 return _height_data.calc_smooth(x / _size, y / _size, radius / _size);
272 return _slope_data.calc_bilinear_interpolation(x / _size, y / _size);
288 PN_stdfloat start_x, PN_stdfloat start_y,
289 PN_stdfloat size_xy,
int num_xy)
const {
290 nassertv(data->get_format() == _vertex_format);
294 PN_stdfloat vertex_scale = 1.0 / (PN_stdfloat)(num_xy - 1);
295 PN_stdfloat texcoord_scale = 1.0 / _size;
296 for (
int xi = 0; xi < num_xy; ++xi) {
297 PN_stdfloat xt = xi * vertex_scale;
298 PN_stdfloat x = start_x + xt * size_xy;
299 for (
int yi = 0; yi < num_xy; ++yi) {
300 PN_stdfloat yt = yi * vertex_scale;
301 PN_stdfloat y = start_y + yt * size_xy;
305 vertex.set_data3(x, y, z);
306 texcoord.
set_data3(x * texcoord_scale, -y * texcoord_scale, 1.0f);
314 void STBasicTerrain::
315 output(ostream &out)
const {
322 void STBasicTerrain::
323 write(ostream &out,
int indent_level)
const {
332 bool STBasicTerrain::
335 if (!image.is_valid()) {
339 _height_data.reset(image.get_x_size(), image.get_y_size());
340 _min_height = FLT_MAX;
341 _max_height = FLT_MIN;
343 PN_stdfloat scalar = _size * _height_scale / image.get_num_channels();
345 for (
int yi = image.get_y_size() - 1; yi >= 0; --yi) {
346 for (
int xi = 0; xi < image.get_x_size(); ++xi) {
347 LColord rgba = image.get_xel_a(xi, yi);
348 PN_stdfloat v = rgba[0] + rgba[1] + rgba[2] + rgba[3];
350 _height_data._data[pi] = v;
352 _min_height = std::min(_min_height, v);
353 _max_height = std::max(_max_height, v);
366 void STBasicTerrain::
367 compute_slope(PN_stdfloat smoothing) {
368 nassertv(!_height_data._data.empty());
370 int width = _height_data._width;
371 int height = _height_data._height;
372 _slope_data.reset(width, height);
374 PN_stdfloat u_spacing = _size / (PN_stdfloat)width;
375 PN_stdfloat v_spacing = _size / (PN_stdfloat)height;
377 for (
int i = 0; i < width; ++i) {
378 int left = (i + width - 1) % width;
379 int right = (i + 1) % width;
381 for (
int j = 0; j < height; ++j) {
382 int top = (j + height - 1) % height;
383 int bottom = (j + 1) % height;
385 PN_stdfloat slope = 0.0f;
386 PN_stdfloat this_height = _height_data._data[i + j * width];
387 slope += catan2(cabs(this_height - _height_data._data[right + j * width]), u_spacing);
388 slope += catan2(cabs(this_height - _height_data._data[left + j * width]), u_spacing);
389 slope += catan2(cabs(this_height - _height_data._data[i + top * width]), v_spacing);
390 slope += catan2(cabs(this_height - _height_data._data[i + bottom * width]), v_spacing);
392 slope *= (0.5f / MathNumbers::pi_f);
397 _slope_data._data[i + j * width] = slope;
401 if (smoothing > 0.0f) {
403 InterpolationData<PN_stdfloat> smoothing_data;
404 smoothing_data.reset(width, height);
405 PN_stdfloat *smoothed = &smoothing_data._data[0];
407 int steps = int(smoothing);
408 PN_stdfloat last_interpolation = smoothing - steps;
410 for (
int si = 0; si < steps; ++si) {
413 for (
int i = 0; i < width; ++i) {
414 int left = (i + width - 1) % width;
415 int right = (i + 1) % width;
417 for (
int j = 0; j < height; ++j) {
418 int top = (j + height - 1) % height;
419 int bottom = (j + 1) % height;
421 smoothed[i + j * width] = (_slope_data._data[right + j * width] +
422 _slope_data._data[left + j * width] +
423 _slope_data._data[i + top * width] +
424 _slope_data._data[i + bottom * width] +
425 _slope_data._data[right + top * width] +
426 _slope_data._data[right + bottom * width] +
427 _slope_data._data[left + top * width] +
428 _slope_data._data[left + bottom * width]);
429 smoothed[i + j * width] *= 0.125f;
434 if (si == steps - 1) {
436 for (
int i = 0; i < width; ++i) {
437 for (
int j = 0; j < height; ++j) {
438 _slope_data._data[i + j * width] = interpolate(_slope_data._data[i + j * width], smoothed[i + j * width], last_interpolation);
444 _slope_data = smoothing_data;
454 void STBasicTerrain::
455 read_quoted_filename(
Filename &result, istream &in,
const Filename &dirname) {
461 if (filename.size() >= 2 && filename[0] ==
'"' && filename[filename.size() - 1] ==
'"') {
462 filename = filename.substr(1, filename.size() - 2);
std::string get_dirname() const
Returns the directory part of the filename.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A specific implementation of STTerrain that supports basic heightmaps loaded from an image file,...
void clear()
Resets the terrain to its initial, unloaded state.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row.
A hierarchy of directories and files that appears to be one continuous file system,...
std::istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read,...
virtual PN_stdfloat get_height(PN_stdfloat x, PN_stdfloat y) const
After load_data() has been called, this should return the computed height value at point (x,...
This is the abstract base class that defines the interface needed to describe a terrain for rendering...
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
virtual void fill_vertices(GeomVertexData *data, PN_stdfloat start_x, PN_stdfloat start_y, PN_stdfloat size_xy, int num_xy) const
After load_data() has been called, this will be called occasionally to populate the vertices for a te...
virtual void load_data()
This will be called at some point after initialization.
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
void output(std::ostream &out) const
Outputs the Namable.
bool setup_terrain(const Filename &terrain_filename)
Sets up the terrain by reading a terrain.txt file as defined by SpeedTree.
virtual PN_stdfloat get_slope(PN_stdfloat x, PN_stdfloat y) const
After load_data() has been called, this should return the directionless slope at point (x,...
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
bool is_directory(const Filename &filename) const
Convenience function; returns true if the named file exists and is a directory.
The name of a file, such as a texture file or an Egg file.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
bool is_local() const
Returns true if the filename is local, e.g.
std::string get_basename() const
Returns the basename part of the filename.
virtual void clear()
Resets the terrain to its initial, unloaded state.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
virtual PN_stdfloat get_smooth_height(PN_stdfloat x, PN_stdfloat y, PN_stdfloat radius) const
After load_data() has been called, this should return the approximate average height value over a cir...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...