Skip to content

Commit

Permalink
Added repeating crackle pattern.
Browse files Browse the repository at this point in the history
The `crackle` pattern now accepts a `repeat VECTOR` modifier, specifying along which axes the pattern is to be repeated, and at which intervals. Values of 0 indicate no repetition along that axis. Repetition intervals must be positive integers.
  • Loading branch information
c-lipka committed Mar 9, 2016
1 parent c5f8d78 commit 1eca8d0
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 18 deletions.
24 changes: 23 additions & 1 deletion source/base/mathutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
// Module config header file must be the first file included within POV-Ray unit header files
#include "base/configbase.h"

#include <assert.h>

#include "base/types.h"

namespace pov_base
Expand Down Expand Up @@ -88,7 +90,7 @@ inline T forcePrecision(T val)
return tempVal;
}

// wrap value into the range [0..upperLimit);
// wrap floating-point value into the range [0..upperLimit);
// (this is equivalent to fmod() for positive values, but not for negative ones)
template<typename T>
inline T wrap(T val, T upperLimit)
Expand Down Expand Up @@ -116,6 +118,26 @@ inline T wrap(T val, T upperLimit)
return tempVal;
}

// wrap signed integer value into the range [0..upperLimit);
// (this is equivalent to the modulus operator for positive values, but not for negative ones)
template<typename T>
inline T wrapInt(T val, T upperLimit)
{
T tempVal = val % upperLimit;

if (tempVal < T(0))
{
// For negative values, the modulus operator may return a value in the range [1-upperLimit..-1];
// transpose such results into the range [1..upperLimit-1].
tempVal += upperLimit;
}

// sanity check; this should never kick in, unless wrapInt() has an implementation error.
POV_MATHUTIL_ASSERT((tempVal >= 0) && (tempVal < upperLimit));

return tempVal;
}

// round up/down to a multiple of some value
template<typename T1, typename T2>
inline T1 RoundDownToMultiple(T1 x, T2 base) { return x - (x % base); }
Expand Down
2 changes: 1 addition & 1 deletion source/base/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
#define OFFICIAL_VERSION_STRING "3.7.1"
#define OFFICIAL_VERSION_NUMBER 371

#define POV_RAY_PRERELEASE "alpha.8509766"
#define POV_RAY_PRERELEASE "alpha.8514084"

#if (POV_RAY_IS_AUTOBUILD == 1) && ((POV_RAY_IS_OFFICIAL == 1) || (POV_RAY_IS_SEMI_OFFICIAL == 1))
#ifdef POV_RAY_PRERELEASE
Expand Down
59 changes: 46 additions & 13 deletions source/core/material/pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5518,6 +5518,7 @@ static int IntPickInCube(int tvx, int tvy, int tvz, Vector3d& p1);

DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const
{
Vector3d tmpPoint = EPoint;
DBL sum, minsum, minsum2, minsum3, tf;
int minVecIdx = 0;
Vector3d dv;
Expand All @@ -5527,22 +5528,29 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
bool UseSquare = ( crackleMetric == 2);
bool UseUnity = ( crackleMetric == 1);

if (repeat.x())
tmpPoint.x() = wrap(tmpPoint.x(), DBL(repeat.x()));
if (repeat.y())
tmpPoint.y() = wrap(tmpPoint.y(), DBL(repeat.y()));
if (repeat.z())
tmpPoint.z() = wrap(tmpPoint.z(), DBL(repeat.z()));

/*
* This uses floor() not FLOOR, so it will not be a mirror
* image about zero in the range -1.0 to 1.0. The viewer
* won't see an artefact around the origin.
*/

flox = (int)floor(EPoint[X] - EPSILON);
floy = (int)floor(EPoint[Y] - EPSILON);
floz = (int)floor(EPoint[Z] - EPSILON);
flox = (int)floor(tmpPoint[X] - EPSILON);
floy = (int)floor(tmpPoint[Y] - EPSILON);
floz = (int)floor(tmpPoint[Z] - EPSILON);

/*
* Check to see if the input point is in the same unit cube as the last
* call to this function, to use cache of cubelets for speed.
*/

CrackleCellCoord ccoord(flox, floy, floz);
CrackleCellCoord ccoord(flox, floy, floz, repeat.x(), repeat.y(), repeat.z());
pThread->Stats()[CrackleCache_Tests]++;

CrackleCacheEntry dummy_entry;
Expand Down Expand Up @@ -5580,7 +5588,32 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
// see InitializeCrackleCubes() below.
int *pc = gaCrackleCubeTable;
for (int i = 0; i < 81; i++, pc += 3)
IntPickInCube(flox + pc[X], floy + pc[Y], floz + pc[Z], entry->aCellNuclei[i]);
{
Vector3d wrappingOffset(0.0);
int cacheX = flox + pc[X];
int cacheY = floy + pc[Y];
int cacheZ = floz + pc[Z];
if (repeat.x())
{
int wrapped = wrapInt(cacheX, repeat.x());
wrappingOffset.x() += (cacheX - wrapped);
cacheX = wrapped;
}
if (repeat.y())
{
int wrapped = wrapInt(cacheY, repeat.y());
wrappingOffset.y() += (cacheY - wrapped);
cacheY = wrapped;
}
if (repeat.z())
{
int wrapped = wrapInt(cacheZ, repeat.z());
wrappingOffset.z() += (cacheZ - wrapped);
cacheZ = wrapped;
}
IntPickInCube(cacheX, cacheY, cacheZ, entry->aCellNuclei[i]);
entry->aCellNuclei[i] += wrappingOffset;
}
}
else
{
Expand All @@ -5590,26 +5623,26 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse

// Find the 3 points with the 3 shortest distances from the input point.
// Set up the loop so the invariant is true: minsum <= minsum2 <= minsum3
dv = entry->aCellNuclei[0] - EPoint;
dv = entry->aCellNuclei[0] - tmpPoint;

if(UseSquare)
{
minsum = dv.lengthSqr();

dv = entry->aCellNuclei[1] - EPoint;
dv = entry->aCellNuclei[1] - tmpPoint;
minsum2 = dv.lengthSqr();

dv = entry->aCellNuclei[2] - EPoint;
dv = entry->aCellNuclei[2] - tmpPoint;
minsum3 = dv.lengthSqr();
}
else if(UseUnity)
{
minsum = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);

dv = entry->aCellNuclei[1] - EPoint;
dv = entry->aCellNuclei[1] - tmpPoint;
minsum2 = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);

dv = entry->aCellNuclei[2] - EPoint;
dv = entry->aCellNuclei[2] - tmpPoint;
minsum3 = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
}
else
Expand All @@ -5618,12 +5651,12 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
pow(fabs(dv[Y]), crackleMetric) +
pow(fabs(dv[Z]), crackleMetric);

dv = entry->aCellNuclei[1] - EPoint;
dv = entry->aCellNuclei[1] - tmpPoint;
minsum2 = pow(fabs(dv[X]), crackleMetric) +
pow(fabs(dv[Y]), crackleMetric) +
pow(fabs(dv[Z]), crackleMetric);

dv = entry->aCellNuclei[2] - EPoint;
dv = entry->aCellNuclei[2] - tmpPoint;
minsum3 = pow(fabs(dv[X]), crackleMetric) +
pow(fabs(dv[Y]), crackleMetric) +
pow(fabs(dv[Z]), crackleMetric);
Expand All @@ -5650,7 +5683,7 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
// Loop for the 81 cubelets to find closest and 2nd closest.
for(int i = 3; i < 81; i++)
{
dv = entry->aCellNuclei[i] - EPoint;
dv = entry->aCellNuclei[i] - tmpPoint;

if(UseSquare)
sum = dv.lengthSqr();
Expand Down
22 changes: 20 additions & 2 deletions source/core/material/pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ struct CracklePattern : public ContinuousPattern
DBL crackleMetric;
DBL crackleOffset;
short crackleIsSolid;
IntVector3d repeat;

virtual PatternPtr Clone() const { return BasicPattern::Clone(*this); }
virtual DBL EvaluateRaw(const Vector3d& EPoint, const Intersection *pIsection, const Ray *pRay, TraceThreadData *pThread) const;
Expand Down Expand Up @@ -972,8 +973,13 @@ class CrackleCellCoord
{
public:

CrackleCellCoord() : mX(0), mY(0), mZ(0) {}
CrackleCellCoord(int x, int y, int z) : mX(x), mY(y), mZ(z) {}
CrackleCellCoord() : mX(0), mY(0), mZ(0), mRepeatX(0), mRepeatY(0), mRepeatZ(0) {}
CrackleCellCoord(int x, int y, int z, int rx, int ry, int rz) : mX(x), mY(y), mZ(z), mRepeatX(rx), mRepeatY(ry), mRepeatZ(rz)
{
WrapCellCoordinate(mX, mRepeatX);
WrapCellCoordinate(mY, mRepeatY);
WrapCellCoordinate(mZ, mRepeatZ);
}

bool operator==(CrackleCellCoord const& other) const
{
Expand Down Expand Up @@ -1003,6 +1009,18 @@ class CrackleCellCoord
int mX;
int mY;
int mZ;
int mRepeatX;
int mRepeatY;
int mRepeatZ;

static inline void WrapCellCoordinate(int& v, int& repeat)
{
if (!repeat)
return;
v = wrapInt(v, repeat);
if ((v >= 2) && (v < repeat - 2))
repeat = 0;
}
};

/// Helper class to implement the crackle cache.
Expand Down
1 change: 1 addition & 0 deletions source/core/math/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ typedef GenericVector2d<SNGL> SnglVector2d; ///< Single-precision 2D vector.

typedef GenericVector3d<DBL> Vector3d; ///< Double-precision 3D vector.
typedef GenericVector3d<SNGL> SnglVector3d; ///< Single-precision 3D vector.
typedef GenericVector3d<int> IntVector3d; ///< Integer 3D vector.

typedef Vector3d Matrix3x3[3]; ///< Double-precision 3x3 matrix.

Expand Down
12 changes: 12 additions & 0 deletions source/parser/parser_materials.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2144,6 +2144,18 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type)
Set_Flag(New, DONT_SCALE_BUMPS_FLAG);
END_CASE

CASE (REPEAT_TOKEN)
if (!dynamic_cast<CracklePattern*>(New->pattern.get()))
Only_In("repeat","crackle");
Parse_Vector(Local_Vector);
dynamic_cast<CracklePattern*>(New->pattern.get())->repeat = IntVector3d(Local_Vector);
if((dynamic_cast<CracklePattern*>(New->pattern.get())->repeat.x() < 0) ||
(dynamic_cast<CracklePattern*>(New->pattern.get())->repeat.y() < 0) ||
(dynamic_cast<CracklePattern*>(New->pattern.get())->repeat.z() < 0))
Error("Repeat vector must be non-negative.");
EXIT
END_CASE

OTHERWISE
UNGET
EXIT
Expand Down
2 changes: 1 addition & 1 deletion unix/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.7.1-alpha.8509766
3.7.1-alpha.8514084

0 comments on commit 1eca8d0

Please sign in to comment.