Noise-1.0.0: libnoise/noise/src/module/terrace.cpp
// terrace.cpp
//
// Copyright (C) 2003, 2004 Jason Bevins
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License (COPYING.txt) for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// The developer's email is jlbezigvins@gmzigail.com (for great email, take
// off every 'zig'.)
//
#include "../interp.h"
#include "../misc.h"
#include "terrace.h"
using namespace noise::module;
using namespace noise;
Terrace::Terrace ():
Module (GetSourceModuleCount ()),
m_controlPointCount (0),
m_invertTerraces (false),
m_pControlPoints (NULL)
{
}
Terrace::~Terrace ()
{
delete[] m_pControlPoints;
}
void Terrace::AddControlPoint (double value)
{
// Find the insertion point for the new control point and insert the new
// point at that position. The control point array will remain sorted by
// value.
int insertionPos = FindInsertionPos (value);
InsertAtPos (insertionPos, value);
}
void Terrace::ClearAllControlPoints ()
{
delete[] m_pControlPoints;
m_pControlPoints = NULL;
m_controlPointCount = 0;
}
int Terrace::FindInsertionPos (double value)
{
int insertionPos;
for (insertionPos = 0; insertionPos < m_controlPointCount; insertionPos++) {
if (value < m_pControlPoints[insertionPos]) {
// We found the array index in which to insert the new control point.
// Exit now.
break;
} else if (value == m_pControlPoints[insertionPos]) {
// Each control point is required to contain a unique value, so throw
// an exception.
throw noise::ExceptionInvalidParam ();
}
}
return insertionPos;
}
double Terrace::GetValue (double x, double y, double z) const
{
assert (m_pSourceModule[0] != NULL);
assert (m_controlPointCount >= 2);
// Get the output value from the source module.
double sourceModuleValue = m_pSourceModule[0]->GetValue (x, y, z);
// Find the first element in the control point array that has a value
// larger than the output value from the source module.
int indexPos;
for (indexPos = 0; indexPos < m_controlPointCount; indexPos++) {
if (sourceModuleValue < m_pControlPoints[indexPos]) {
break;
}
}
// Find the two nearest control points so that we can map their values
// onto a quadratic curve.
int index0 = ClampValue (indexPos - 1, 0, m_controlPointCount - 1);
int index1 = ClampValue (indexPos , 0, m_controlPointCount - 1);
// If some control points are missing (which occurs if the output value from
// the source module is greater than the largest value or less than the
// smallest value of the control point array), get the value of the nearest
// control point and exit now.
if (index0 == index1) {
return m_pControlPoints[index1];
}
// Compute the alpha value used for linear interpolation.
double value0 = m_pControlPoints[index0];
double value1 = m_pControlPoints[index1];
double alpha = (sourceModuleValue - value0) / (value1 - value0);
if (m_invertTerraces) {
alpha = 1.0 - alpha;
SwapValues (value0, value1);
}
// Squaring the alpha produces the terrace effect.
alpha *= alpha;
// Now perform the linear interpolation given the alpha value.
return LinearInterp (value0, value1, alpha);
}
void Terrace::InsertAtPos (int insertionPos, double value)
{
// Make room for the new control point at the specified position within
// the control point array. The position is determined by the value of
// the control point; the control points must be sorted by value within
// that array.
double* newControlPoints = new double[m_controlPointCount + 1];
for (int i = 0; i < m_controlPointCount; i++) {
if (i < insertionPos) {
newControlPoints[i] = m_pControlPoints[i];
} else {
newControlPoints[i + 1] = m_pControlPoints[i];
}
}
delete[] m_pControlPoints;
m_pControlPoints = newControlPoints;
++m_controlPointCount;
// Now that we've made room for the new control point within the array,
// add the new control point.
m_pControlPoints[insertionPos] = value;
}
void Terrace::MakeControlPoints (int controlPointCount)
{
if (controlPointCount < 2) {
throw noise::ExceptionInvalidParam ();
}
ClearAllControlPoints ();
double terraceStep = 2.0 / ((double)controlPointCount - 1.0);
double curValue = -1.0;
for (int i = 0; i < (int)controlPointCount; i++) {
AddControlPoint (curValue);
curValue += terraceStep;
}
}