|
|
|
@ -27,13 +27,9 @@ MTS_NAMESPACE_BEGIN
|
|
|
|
|
/*! @{ */
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
// Miscellaneous
|
|
|
|
|
//! @{ \name String-related utility functions
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static const int primeTableSize = 1000;
|
|
|
|
|
/// Table of the first 1000 prime numbers
|
|
|
|
|
extern const int MTS_EXPORT_CORE primeTable[primeTableSize];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Given a list of delimiters, tokenize
|
|
|
|
|
* a std::string into a vector of strings
|
|
|
|
@ -63,6 +59,30 @@ extern MTS_EXPORT_CORE std::string timeString(Float time, bool precise = false);
|
|
|
|
|
/// Turn a memory size into a human-readable string
|
|
|
|
|
extern MTS_EXPORT_CORE std::string memString(size_t size);
|
|
|
|
|
|
|
|
|
|
/// Return a string representation of a list of objects
|
|
|
|
|
template<class Iterator> std::string containerToString(const Iterator &start, const Iterator &end) {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "{" << endl;
|
|
|
|
|
Iterator it = start;
|
|
|
|
|
while (it != end) {
|
|
|
|
|
oss << " " << indent((*it)->toString());
|
|
|
|
|
++it;
|
|
|
|
|
if (it != end)
|
|
|
|
|
oss << "," << endl;
|
|
|
|
|
else
|
|
|
|
|
oss << endl;
|
|
|
|
|
}
|
|
|
|
|
oss << "}";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! @}
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
//! @{ \name Miscellaneous
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/// Allocate an aligned region of memory
|
|
|
|
|
extern MTS_EXPORT_CORE void * __restrict allocAligned(size_t size);
|
|
|
|
|
|
|
|
|
@ -104,6 +124,82 @@ extern MTS_EXPORT_CORE bool disableFPExceptions();
|
|
|
|
|
/// Restore floating point exceptions to the specified state
|
|
|
|
|
extern MTS_EXPORT_CORE void restoreFPExceptions(bool state);
|
|
|
|
|
|
|
|
|
|
/// Cast between types that have an identical binary representation.
|
|
|
|
|
template<typename T, typename U> inline T union_cast(const U &val) {
|
|
|
|
|
BOOST_STATIC_ASSERT(sizeof(T) == sizeof(U));
|
|
|
|
|
|
|
|
|
|
union {
|
|
|
|
|
U u;
|
|
|
|
|
T t;
|
|
|
|
|
} caster = {val};
|
|
|
|
|
|
|
|
|
|
return caster.t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Swaps the byte order of the underlying representation
|
|
|
|
|
template<typename T> inline T endianness_swap(T value) {
|
|
|
|
|
union {
|
|
|
|
|
T value;
|
|
|
|
|
uint8_t byteValue[sizeof(T)];
|
|
|
|
|
} u;
|
|
|
|
|
|
|
|
|
|
u.value = value;
|
|
|
|
|
std::reverse(&u.byteValue[0], &u.byteValue[sizeof(T)]);
|
|
|
|
|
return u.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This algorithm is based on Donald Knuth's book
|
|
|
|
|
* "The Art of Computer Programming, Volume 3: Sorting and Searching"
|
|
|
|
|
* (1st edition, section 5.2, page 595)
|
|
|
|
|
*
|
|
|
|
|
* Given a permutation and an array of values, it applies the permutation
|
|
|
|
|
* in linear time without requiring additional memory. This is based on
|
|
|
|
|
* the fact that each permutation can be decomposed into a disjoint set
|
|
|
|
|
* of permutations, which can then be applied individually.
|
|
|
|
|
*/
|
|
|
|
|
template <typename T> void permute_inplace(T *values, std::vector<size_t> &perm) {
|
|
|
|
|
for (size_t i=0; i<perm.size(); i++) {
|
|
|
|
|
if (perm[i] != i) {
|
|
|
|
|
/* The start of a new cycle has been found. Save
|
|
|
|
|
the value at this position, since it will be
|
|
|
|
|
overwritten */
|
|
|
|
|
size_t j = i;
|
|
|
|
|
T curval = values[i];
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
/* Shuffle backwards */
|
|
|
|
|
size_t k = perm[j];
|
|
|
|
|
values[j] = values[k];
|
|
|
|
|
|
|
|
|
|
/* Also fix the permutations on the way */
|
|
|
|
|
perm[j] = j;
|
|
|
|
|
j = k;
|
|
|
|
|
|
|
|
|
|
/* Until the end of the cycle has been found */
|
|
|
|
|
} while (perm[j] != i);
|
|
|
|
|
|
|
|
|
|
/* Fix the final position with the saved value */
|
|
|
|
|
values[j] = curval;
|
|
|
|
|
perm[j] = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! @}
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
//! @{ \name Numerical utility functions
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static const int primeTableSize = 1000;
|
|
|
|
|
/// Table of the first 1000 prime numbers
|
|
|
|
|
extern const int MTS_EXPORT_CORE primeTable[primeTableSize];
|
|
|
|
|
|
|
|
|
|
/// sqrt(a^2 + b^2) without underflow (like 'hypot' on compilers that support C99)
|
|
|
|
|
extern MTS_EXPORT_CORE Float hypot2(Float a, Float b);
|
|
|
|
|
|
|
|
|
|
/// Base-2 logarithm
|
|
|
|
|
extern MTS_EXPORT_CORE Float log2(Float value);
|
|
|
|
|
|
|
|
|
@ -130,40 +226,133 @@ inline int log2i(size_t value) {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/// Check if an integer is a power of two (unsigned 32 bit version)
|
|
|
|
|
inline bool isPowerOfTwo(uint32_t i) { return (i & (i-1)) == 0; }
|
|
|
|
|
inline bool isPow2(uint32_t i) { return (i & (i-1)) == 0; }
|
|
|
|
|
|
|
|
|
|
/// Check if an integer is a power of two (signed 32 bit version)
|
|
|
|
|
inline bool isPowerOfTwo(int32_t i) { return i > 0 && (i & (i-1)) == 0; }
|
|
|
|
|
inline bool isPow2(int32_t i) { return i > 0 && (i & (i-1)) == 0; }
|
|
|
|
|
|
|
|
|
|
/// Check if an integer is a power of two (64 bit version)
|
|
|
|
|
inline bool isPowerOfTwo(uint64_t i) { return (i & (i-1)) == 0; }
|
|
|
|
|
inline bool isPow2(uint64_t i) { return (i & (i-1)) == 0; }
|
|
|
|
|
|
|
|
|
|
/// Check if an integer is a power of two (signed 64 bit version)
|
|
|
|
|
inline bool isPowerOfTwo(int64_t i) { return i > 0 && (i & (i-1)) == 0; }
|
|
|
|
|
inline bool isPow2(int64_t i) { return i > 0 && (i & (i-1)) == 0; }
|
|
|
|
|
|
|
|
|
|
#if defined(MTS_AMBIGUOUS_SIZE_T)
|
|
|
|
|
inline int isPowerOfTwo(size_t value) {
|
|
|
|
|
inline bool isPow2(size_t value) {
|
|
|
|
|
if (sizeof(size_t) == 8)
|
|
|
|
|
return isPowerOfTwo((uint64_t) value);
|
|
|
|
|
return isPow2((uint64_t) value);
|
|
|
|
|
else
|
|
|
|
|
return isPowerOfTwo((uint32_t) value);
|
|
|
|
|
return isPow2((uint32_t) value);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/// Round an integer to the next power of two
|
|
|
|
|
extern MTS_EXPORT_CORE uint32_t roundToPowerOfTwo(uint32_t i);
|
|
|
|
|
extern MTS_EXPORT_CORE uint32_t roundToPow2(uint32_t i);
|
|
|
|
|
|
|
|
|
|
/// Round an integer to the next power of two (64 bit version)
|
|
|
|
|
extern MTS_EXPORT_CORE uint64_t roundToPowerOfTwo(uint64_t i);
|
|
|
|
|
extern MTS_EXPORT_CORE uint64_t roundToPow2(uint64_t i);
|
|
|
|
|
|
|
|
|
|
#if defined(MTS_AMBIGUOUS_SIZE_T)
|
|
|
|
|
inline size_t roundToPow2(size_t value) {
|
|
|
|
|
if (sizeof(size_t) == 8)
|
|
|
|
|
return (size_t) roundToPow2((uint64_t) value);
|
|
|
|
|
else
|
|
|
|
|
return (size_t) roundToPow2((uint32_t) value);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//// Windowed sinc filter (Lanczos envelope, tau=number of cycles)
|
|
|
|
|
extern MTS_EXPORT_CORE Float lanczosSinc(Float t, Float tau = 2);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Solve a quadratic equation of the form a*x^2 + b*x + c = 0.
|
|
|
|
|
* Returns true if a solution could be found
|
|
|
|
|
* \return \c true if a solution could be found
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE bool solveQuadratic(Float a, Float b, Float c, Float &x0, Float &x1);
|
|
|
|
|
extern MTS_EXPORT_CORE bool solveQuadratic(Float a, Float b,
|
|
|
|
|
Float c, Float &x0, Float &x1);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculate the radical inverse function
|
|
|
|
|
* (Implementation based on "Instant Radiosity" by Alexander Keller
|
|
|
|
|
* in Computer Graphics Proceedings, Annual Conference Series,
|
|
|
|
|
* SIGGRAPH 97, pp. 49-56.
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Float radicalInverse(int b, int i);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Incrementally calculate the radical inverse function
|
|
|
|
|
* (Implementation based on "Instant Radiosity" by Alexander Keller
|
|
|
|
|
* in Computer Graphics Proceedings, Annual Conference Series,
|
|
|
|
|
* SIGGRAPH 97, pp. 49-56.
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Float radicalInverseIncremental(int b, Float x);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Rational approximation to the inverse normal
|
|
|
|
|
* cumulative distribution function
|
|
|
|
|
* Source: http://home.online.no/~pjacklam/notes/invnorm/impl/sprouse/ltqnorm.c
|
|
|
|
|
* \author Peter J. Acklam
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE double normalQuantile(double p);
|
|
|
|
|
|
|
|
|
|
//// Convert radians to degrees
|
|
|
|
|
inline Float radToDeg(Float value) { return value * (180.0f / M_PI); }
|
|
|
|
|
|
|
|
|
|
/// Convert degrees to radians
|
|
|
|
|
inline Float degToRad(Float value) { return value * (M_PI / 180.0f); }
|
|
|
|
|
|
|
|
|
|
/// Simple floating point clamping function
|
|
|
|
|
inline Float clamp(Float value, Float min, Float max) {
|
|
|
|
|
if (value < min)
|
|
|
|
|
return min;
|
|
|
|
|
else if (value > max)
|
|
|
|
|
return max;
|
|
|
|
|
else return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Simple integer clamping function
|
|
|
|
|
inline int clamp(int value, int min, int max) {
|
|
|
|
|
if (value < min)
|
|
|
|
|
return min;
|
|
|
|
|
else if (value > max)
|
|
|
|
|
return max;
|
|
|
|
|
else return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Linearly interpolate between two values
|
|
|
|
|
inline Float lerp(Float t, Float v1, Float v2) {
|
|
|
|
|
return ((Float) 1 - t) * v1 + t * v2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// S-shaped smoothly varying interpolation between two values
|
|
|
|
|
inline Float smoothStep(Float min, Float max, Float value) {
|
|
|
|
|
Float v = clamp((value - min) / (max - min), (Float) 0, (Float) 1);
|
|
|
|
|
return v * v * (-2 * v + 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Numerically well-behaved routine for computing the angle
|
|
|
|
|
* between two unit direction vectors
|
|
|
|
|
*
|
|
|
|
|
* This should be used wherever one is tempted to compute the
|
|
|
|
|
* arc cosine of a dot product!
|
|
|
|
|
*
|
|
|
|
|
* Proposed by Don Hatch at
|
|
|
|
|
* http://www.plunk.org/~hatch/rightway.php
|
|
|
|
|
*/
|
|
|
|
|
template <typename VectorType> inline Float unitAngle(const VectorType &u, const VectorType &v) {
|
|
|
|
|
if (dot(u, v) < 0)
|
|
|
|
|
return M_PI - 2 * std::asin((v+u).length()/2);
|
|
|
|
|
else
|
|
|
|
|
return 2 * std::asin((v-u).length()/2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//! @}
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
//! @{ \name Warping and sampling-related utility functions
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Solve a 2x2 linear equation system using basic linear algebra
|
|
|
|
@ -227,44 +416,8 @@ extern MTS_EXPORT_CORE Point2 squareToDiskConcentric(const Point2 &sample);
|
|
|
|
|
/// Convert an uniformly distributed square sample into barycentric coordinates
|
|
|
|
|
extern MTS_EXPORT_CORE Point2 squareToTriangle(const Point2 &sample);
|
|
|
|
|
|
|
|
|
|
/// Convert radians to degrees
|
|
|
|
|
inline Float radToDeg(Float rad) {
|
|
|
|
|
return 180.0f * rad / M_PI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert degrees to radians
|
|
|
|
|
inline Float degToRad(Float deg) {
|
|
|
|
|
return deg * M_PI / 180.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Simple floating point clamping function
|
|
|
|
|
inline Float clamp(Float value, Float min, Float max) {
|
|
|
|
|
if (value < min)
|
|
|
|
|
return min;
|
|
|
|
|
else if (value > max)
|
|
|
|
|
return max;
|
|
|
|
|
else return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Simple integer clamping function
|
|
|
|
|
inline int clamp(int value, int min, int max) {
|
|
|
|
|
if (value < min)
|
|
|
|
|
return min;
|
|
|
|
|
else if (value > max)
|
|
|
|
|
return max;
|
|
|
|
|
else return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Linearly interpolate between two values
|
|
|
|
|
inline Float lerp(Float t, Float v1, Float v2) {
|
|
|
|
|
return ((Float) 1 - t) * v1 + t * v2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// S-shaped smoothly varying interpolation between two values
|
|
|
|
|
inline Float smoothStep(Float min, Float max, Float value) {
|
|
|
|
|
Float v = clamp((value - min) / (max - min), (Float) 0, (Float) 1);
|
|
|
|
|
return v * v * (-2 * v + 3);
|
|
|
|
|
}
|
|
|
|
|
//! @}
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the unpolarized fresnel reflection coefficient for a
|
|
|
|
@ -279,8 +432,8 @@ inline Float smoothStep(Float min, Float max, Float value) {
|
|
|
|
|
* \param etaInt
|
|
|
|
|
* Refraction coefficient inside the material
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Float fresnelDielectric(Float cosTheta1, Float cosTheta2,
|
|
|
|
|
Float etaExt, Float etaInt);
|
|
|
|
|
extern MTS_EXPORT_CORE Float fresnelDielectric(Float cosTheta1,
|
|
|
|
|
Float cosTheta2, Float etaExt, Float etaInt);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the unpolarized fresnel reflection coefficient for a
|
|
|
|
@ -293,7 +446,8 @@ extern MTS_EXPORT_CORE Float fresnelDielectric(Float cosTheta1, Float cosTheta2,
|
|
|
|
|
* \param etaInt
|
|
|
|
|
* Refraction coefficient inside the material
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Float fresnel(Float cosTheta1, Float etaExt, Float etaInt);
|
|
|
|
|
extern MTS_EXPORT_CORE Float fresnel(Float cosTheta1, Float etaExt,
|
|
|
|
|
Float etaInt);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculates the unpolarized fresnel reflection coefficient on
|
|
|
|
@ -306,127 +460,8 @@ extern MTS_EXPORT_CORE Float fresnel(Float cosTheta1, Float etaExt, Float etaInt
|
|
|
|
|
* \param k
|
|
|
|
|
* Absorption coefficient (per wavelength)
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosTheta, const Spectrum &eta, const Spectrum &k);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculate the radical inverse function
|
|
|
|
|
* (Implementation based on "Instant Radiosity" by Alexander Keller
|
|
|
|
|
* in Computer Graphics Proceedings, Annual Conference Series,
|
|
|
|
|
* SIGGRAPH 97, pp. 49-56.
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Float radicalInverse(int b, int i);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Incrementally calculate the radical inverse function
|
|
|
|
|
* (Implementation based on "Instant Radiosity" by Alexander Keller
|
|
|
|
|
* in Computer Graphics Proceedings, Annual Conference Series,
|
|
|
|
|
* SIGGRAPH 97, pp. 49-56.
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE Float radicalInverseIncremental(int b, Float x);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Rational approximation to the inverse normal
|
|
|
|
|
* cumulative distribution function
|
|
|
|
|
* Source: http://home.online.no/~pjacklam/notes/invnorm/impl/sprouse/ltqnorm.c
|
|
|
|
|
* \author Peter J. Acklam
|
|
|
|
|
*/
|
|
|
|
|
extern MTS_EXPORT_CORE double normalQuantile(double p);
|
|
|
|
|
|
|
|
|
|
/// sqrt(a^2 + b^2) without underflow (like 'hypot' on compilers that support C99)
|
|
|
|
|
extern MTS_EXPORT_CORE Float hypot2(Float a, Float b);
|
|
|
|
|
|
|
|
|
|
/// Cast between types, which have an identical binary representation.
|
|
|
|
|
template<typename T, typename U> inline T union_cast(const U &val) {
|
|
|
|
|
BOOST_STATIC_ASSERT(sizeof(T) == sizeof(U));
|
|
|
|
|
|
|
|
|
|
union {
|
|
|
|
|
U u;
|
|
|
|
|
T t;
|
|
|
|
|
} caster = {val};
|
|
|
|
|
|
|
|
|
|
return caster.t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Swaps the byte order of the underlying representation
|
|
|
|
|
template<typename T> inline T endianness_swap(T value) {
|
|
|
|
|
union {
|
|
|
|
|
T value;
|
|
|
|
|
uint8_t byteValue[sizeof(T)];
|
|
|
|
|
} u;
|
|
|
|
|
|
|
|
|
|
u.value = value;
|
|
|
|
|
std::reverse(&u.byteValue[0], &u.byteValue[sizeof(T)]);
|
|
|
|
|
return u.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Return a string representation of a list of objects
|
|
|
|
|
template<class Iterator> std::string containerToString(const Iterator &start, const Iterator &end) {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << "{" << endl;
|
|
|
|
|
Iterator it = start;
|
|
|
|
|
while (it != end) {
|
|
|
|
|
oss << " " << indent((*it)->toString());
|
|
|
|
|
++it;
|
|
|
|
|
if (it != end)
|
|
|
|
|
oss << "," << endl;
|
|
|
|
|
else
|
|
|
|
|
oss << endl;
|
|
|
|
|
}
|
|
|
|
|
oss << "}";
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Numerically well-behaved routine for computing
|
|
|
|
|
* the angle between two unit vectors
|
|
|
|
|
*
|
|
|
|
|
* Suggested by Don Hatch at
|
|
|
|
|
* http://www.plunk.org/~hatch/rightway.php
|
|
|
|
|
*/
|
|
|
|
|
template <typename VectorType> inline Float unitAngle(const VectorType &u, const VectorType &v) {
|
|
|
|
|
if (dot(u, v) < 0)
|
|
|
|
|
return M_PI - 2 * std::asin((v+u).length()/2);
|
|
|
|
|
else
|
|
|
|
|
return 2 * std::asin((v-u).length()/2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This algorithm is based on Donald Knuth's book
|
|
|
|
|
* "The Art of Computer Programming, Volume 3: Sorting and Searching"
|
|
|
|
|
* (1st edition, section 5.2, page 595)
|
|
|
|
|
*
|
|
|
|
|
* Given a permutation and an array of values, it applies the permutation
|
|
|
|
|
* in linear time without requiring additional memory. This is based on
|
|
|
|
|
* the fact that each permutation can be decomposed into a disjoint set
|
|
|
|
|
* of permutations, which can then be applied individually.
|
|
|
|
|
*/
|
|
|
|
|
template <typename T> void permute_inplace(T *values, std::vector<size_t> &perm) {
|
|
|
|
|
for (size_t i=0; i<perm.size(); i++) {
|
|
|
|
|
if (perm[i] != i) {
|
|
|
|
|
/* The start of a new cycle has been found. Save
|
|
|
|
|
the value at this position, since it will be
|
|
|
|
|
overwritten */
|
|
|
|
|
size_t j = i;
|
|
|
|
|
T curval = values[i];
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
/* Shuffle backwards */
|
|
|
|
|
size_t k = perm[j];
|
|
|
|
|
values[j] = values[k];
|
|
|
|
|
|
|
|
|
|
/* Also fix the permutations on the way */
|
|
|
|
|
perm[j] = j;
|
|
|
|
|
j = k;
|
|
|
|
|
|
|
|
|
|
/* Until the end of the cycle has been found */
|
|
|
|
|
} while (perm[j] != i);
|
|
|
|
|
|
|
|
|
|
/* Fix the final position with the saved value */
|
|
|
|
|
values[j] = curval;
|
|
|
|
|
perm[j] = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosTheta,
|
|
|
|
|
const Spectrum &eta, const Spectrum &k);
|
|
|
|
|
|
|
|
|
|
/*! @} */
|
|
|
|
|
|
|
|
|
|