From 6e7ce771656153f84f462bf03bd3eabf4bc15783 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Thu, 19 Dec 2013 11:40:24 +0100 Subject: [PATCH] minor improvements to the heightfield shape --- src/shapes/heightfield.cpp | 93 ++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/src/shapes/heightfield.cpp b/src/shapes/heightfield.cpp index e8b64e32..33e1d665 100644 --- a/src/shapes/heightfield.cpp +++ b/src/shapes/heightfield.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -81,6 +83,13 @@ namespace { * this parameter specifies the resolution at which it should * be rasterized to create a height field made of bilinear patches. * } + * \parameter{scale}{\Float}{Scale factor that is applied to the height field + * values\default{No scaling, i.e. \code{1}} + * } + * \parameter{filename}{\String}{ + * File name of an image file containing height field values. Alternatively, + * a nested texture can be provided (see below). + * } * \parameter{\Unnamed}{\Texture}{ * A nested texture that specifies the height field values. This * could be a bitmap-backed texture or one that is procedurally defined. @@ -104,13 +113,8 @@ namespace { * * \begin{xml}[caption={Declaring a height field from a monochromatic scaled bitmap texture}, label=lst:heightfield-bitmap] * - * - * - * - * - * - * - * + * + * * * \end{xml} */ @@ -126,6 +130,11 @@ public: m_objectToWorld = props.getTransform("toWorld", Transform()); m_shadingNormals = props.getBoolean("shadingNormals", true); m_flipNormals = props.getBoolean("flipNormals", false); + m_scale = props.getFloat("scale", 1); + + m_filename = props.getString("filename", ""); + if (!m_filename.empty()) + m_filename = Thread::getThread()->getFileResolver()->resolve(m_filename); } Heightfield(Stream *stream, InstanceManager *manager) @@ -134,6 +143,8 @@ public: m_objectToWorld = Transform(stream); m_shadingNormals = stream->readBool(); m_flipNormals = stream->readBool(); + m_scale = stream->readFloat(); + m_filename = stream->readString(); m_dataSize = Vector2i(stream); size_t size = (size_t) m_dataSize.x * (size_t) m_dataSize.y; m_data = (Float *) allocAligned(size * sizeof(Float)); @@ -162,6 +173,8 @@ public: m_objectToWorld.serialize(stream); stream->writeBool(m_shadingNormals); stream->writeBool(m_flipNormals); + stream->writeFloat(m_scale); + stream->writeString(m_filename.string()); m_dataSize.serialize(stream); stream->writeFloatArray(m_data, (size_t) m_dataSize.x * (size_t) m_dataSize.y); } @@ -479,34 +492,43 @@ public: if (m_minmax) return; - if (m_bitmap.get()) { - m_dataSize = m_bitmap->getSize(); - if (m_dataSize.x < 2) m_dataSize.x = 2; - if (m_dataSize.y < 2) m_dataSize.y = 2; - if (!isPowerOfTwo(m_dataSize.x - 1)) m_dataSize.x = (int) roundToPowerOfTwo((uint32_t) m_dataSize.x - 1) + 1; - if (!isPowerOfTwo(m_dataSize.y - 1)) m_dataSize.y = (int) roundToPowerOfTwo((uint32_t) m_dataSize.y - 1) + 1; - - if (m_bitmap->getSize() != m_dataSize) { - m_bitmap = m_bitmap->convert(Bitmap::ELuminance, Bitmap::EFloat); - - Log(EInfo, "Resampling heightfield texture from %ix%i to %ix%i ..", - m_bitmap->getWidth(), m_bitmap->getHeight(), m_dataSize.x, m_dataSize.y); - - m_bitmap = m_bitmap->resample(m_rfilter, ReconstructionFilter::EClamp, - ReconstructionFilter::EClamp, m_dataSize, - -std::numeric_limits::infinity(), - std::numeric_limits::infinity()); - } - - size_t size = (size_t) m_dataSize.x * (size_t) m_dataSize.y * sizeof(Float); - m_data = (Float *) allocAligned(size); - m_bitmap->convert(m_data, Bitmap::ELuminance, Bitmap::EFloat); - - m_objectToWorld = m_objectToWorld * Transform::translate(Vector(-1, -1, 0)) * Transform::scale(Vector( - (Float) 2 / (m_dataSize.x-1), - (Float) 2 / (m_dataSize.y-1), 1)); + if (!m_filename.empty()) { + if (m_bitmap.get()) + Log(EError, "Cannot specify a file name and a nested texture at the same time!"); + ref fs = new FileStream(m_filename, FileStream::EReadOnly); + m_bitmap = new Bitmap(Bitmap::EAuto, fs); + } else if (!m_bitmap.get()) { + Log(EError, "A height field texture must be specified (either as a nested texture, or using the 'filename' parameter)"); } + m_dataSize = m_bitmap->getSize(); + if (m_dataSize.x < 2) m_dataSize.x = 2; + if (m_dataSize.y < 2) m_dataSize.y = 2; + if (!isPowerOfTwo(m_dataSize.x - 1)) m_dataSize.x = (int) roundToPowerOfTwo((uint32_t) m_dataSize.x - 1) + 1; + if (!isPowerOfTwo(m_dataSize.y - 1)) m_dataSize.y = (int) roundToPowerOfTwo((uint32_t) m_dataSize.y - 1) + 1; + + if (m_bitmap->getSize() != m_dataSize) { + m_bitmap = m_bitmap->convert(Bitmap::ELuminance, Bitmap::EFloat); + + Log(EInfo, "Resampling heightfield texture from %ix%i to %ix%i ..", + m_bitmap->getWidth(), m_bitmap->getHeight(), m_dataSize.x, m_dataSize.y); + + m_bitmap = m_bitmap->resample(m_rfilter, ReconstructionFilter::EClamp, + ReconstructionFilter::EClamp, m_dataSize, + -std::numeric_limits::infinity(), + std::numeric_limits::infinity()); + } + + size_t size = (size_t) m_dataSize.x * (size_t) m_dataSize.y * sizeof(Float); + m_data = (Float *) allocAligned(size); + m_bitmap->convert(m_data, Bitmap::ELuminance, Bitmap::EFloat, 1.0f, m_scale); + + m_objectToWorld = m_objectToWorld * Transform::translate(Vector(-1, -1, 0)) * Transform::scale(Vector( + (Float) 2 / (m_dataSize.x-1), + (Float) 2 / (m_dataSize.y-1), 1)); + + m_bitmap = NULL; + size_t storageSize = (size_t) m_dataSize.x * (size_t) m_dataSize.y * sizeof(Float); Log(EInfo, "Building acceleration data structure for %ix%i height field ..", m_dataSize.x, m_dataSize.y); @@ -525,7 +547,8 @@ public: m_blockSizeF[0] = Vector2(1, 1); m_invSize = Vector2((Float) 1 / m_levelSize[0].x, (Float) 1 / m_levelSize[0].y); m_surfaceArea = 0; - size_t size = (size_t) m_levelSize[0].x * (size_t) m_levelSize[0].y * sizeof(Interval); + + size = (size_t) m_levelSize[0].x * (size_t) m_levelSize[0].y * sizeof(Interval); m_minmax[0] = (Interval *) allocAligned(size); storageSize += size; @@ -724,6 +747,8 @@ private: AABB m_dataAABB; bool m_shadingNormals; bool m_flipNormals; + Float m_scale; + fs::path m_filename; /* Height field data */ Float *m_data;