Skip to content

Commit 1eca8d0

Browse files
committed
Added repeating crackle pattern.
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.
1 parent c5f8d78 commit 1eca8d0

File tree

7 files changed

+104
-18
lines changed

7 files changed

+104
-18
lines changed

source/base/mathutil.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
// Module config header file must be the first file included within POV-Ray unit header files
4040
#include "base/configbase.h"
4141

42+
#include <assert.h>
43+
4244
#include "base/types.h"
4345

4446
namespace pov_base
@@ -88,7 +90,7 @@ inline T forcePrecision(T val)
8890
return tempVal;
8991
}
9092

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

121+
// wrap signed integer value into the range [0..upperLimit);
122+
// (this is equivalent to the modulus operator for positive values, but not for negative ones)
123+
template<typename T>
124+
inline T wrapInt(T val, T upperLimit)
125+
{
126+
T tempVal = val % upperLimit;
127+
128+
if (tempVal < T(0))
129+
{
130+
// For negative values, the modulus operator may return a value in the range [1-upperLimit..-1];
131+
// transpose such results into the range [1..upperLimit-1].
132+
tempVal += upperLimit;
133+
}
134+
135+
// sanity check; this should never kick in, unless wrapInt() has an implementation error.
136+
POV_MATHUTIL_ASSERT((tempVal >= 0) && (tempVal < upperLimit));
137+
138+
return tempVal;
139+
}
140+
119141
// round up/down to a multiple of some value
120142
template<typename T1, typename T2>
121143
inline T1 RoundDownToMultiple(T1 x, T2 base) { return x - (x % base); }

source/base/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
#define OFFICIAL_VERSION_STRING "3.7.1"
4646
#define OFFICIAL_VERSION_NUMBER 371
4747

48-
#define POV_RAY_PRERELEASE "alpha.8509766"
48+
#define POV_RAY_PRERELEASE "alpha.8514084"
4949

5050
#if (POV_RAY_IS_AUTOBUILD == 1) && ((POV_RAY_IS_OFFICIAL == 1) || (POV_RAY_IS_SEMI_OFFICIAL == 1))
5151
#ifdef POV_RAY_PRERELEASE

source/core/material/pattern.cpp

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5518,6 +5518,7 @@ static int IntPickInCube(int tvx, int tvy, int tvz, Vector3d& p1);
55185518

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

5531+
if (repeat.x())
5532+
tmpPoint.x() = wrap(tmpPoint.x(), DBL(repeat.x()));
5533+
if (repeat.y())
5534+
tmpPoint.y() = wrap(tmpPoint.y(), DBL(repeat.y()));
5535+
if (repeat.z())
5536+
tmpPoint.z() = wrap(tmpPoint.z(), DBL(repeat.z()));
5537+
55305538
/*
55315539
* This uses floor() not FLOOR, so it will not be a mirror
55325540
* image about zero in the range -1.0 to 1.0. The viewer
55335541
* won't see an artefact around the origin.
55345542
*/
55355543

5536-
flox = (int)floor(EPoint[X] - EPSILON);
5537-
floy = (int)floor(EPoint[Y] - EPSILON);
5538-
floz = (int)floor(EPoint[Z] - EPSILON);
5544+
flox = (int)floor(tmpPoint[X] - EPSILON);
5545+
floy = (int)floor(tmpPoint[Y] - EPSILON);
5546+
floz = (int)floor(tmpPoint[Z] - EPSILON);
55395547

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

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

55485556
CrackleCacheEntry dummy_entry;
@@ -5580,7 +5588,32 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
55805588
// see InitializeCrackleCubes() below.
55815589
int *pc = gaCrackleCubeTable;
55825590
for (int i = 0; i < 81; i++, pc += 3)
5583-
IntPickInCube(flox + pc[X], floy + pc[Y], floz + pc[Z], entry->aCellNuclei[i]);
5591+
{
5592+
Vector3d wrappingOffset(0.0);
5593+
int cacheX = flox + pc[X];
5594+
int cacheY = floy + pc[Y];
5595+
int cacheZ = floz + pc[Z];
5596+
if (repeat.x())
5597+
{
5598+
int wrapped = wrapInt(cacheX, repeat.x());
5599+
wrappingOffset.x() += (cacheX - wrapped);
5600+
cacheX = wrapped;
5601+
}
5602+
if (repeat.y())
5603+
{
5604+
int wrapped = wrapInt(cacheY, repeat.y());
5605+
wrappingOffset.y() += (cacheY - wrapped);
5606+
cacheY = wrapped;
5607+
}
5608+
if (repeat.z())
5609+
{
5610+
int wrapped = wrapInt(cacheZ, repeat.z());
5611+
wrappingOffset.z() += (cacheZ - wrapped);
5612+
cacheZ = wrapped;
5613+
}
5614+
IntPickInCube(cacheX, cacheY, cacheZ, entry->aCellNuclei[i]);
5615+
entry->aCellNuclei[i] += wrappingOffset;
5616+
}
55845617
}
55855618
else
55865619
{
@@ -5590,26 +5623,26 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
55905623

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

55955628
if(UseSquare)
55965629
{
55975630
minsum = dv.lengthSqr();
55985631

5599-
dv = entry->aCellNuclei[1] - EPoint;
5632+
dv = entry->aCellNuclei[1] - tmpPoint;
56005633
minsum2 = dv.lengthSqr();
56015634

5602-
dv = entry->aCellNuclei[2] - EPoint;
5635+
dv = entry->aCellNuclei[2] - tmpPoint;
56035636
minsum3 = dv.lengthSqr();
56045637
}
56055638
else if(UseUnity)
56065639
{
56075640
minsum = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
56085641

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

5612-
dv = entry->aCellNuclei[2] - EPoint;
5645+
dv = entry->aCellNuclei[2] - tmpPoint;
56135646
minsum3 = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
56145647
}
56155648
else
@@ -5618,12 +5651,12 @@ DBL CracklePattern::EvaluateRaw(const Vector3d& EPoint, const Intersection *pIse
56185651
pow(fabs(dv[Y]), crackleMetric) +
56195652
pow(fabs(dv[Z]), crackleMetric);
56205653

5621-
dv = entry->aCellNuclei[1] - EPoint;
5654+
dv = entry->aCellNuclei[1] - tmpPoint;
56225655
minsum2 = pow(fabs(dv[X]), crackleMetric) +
56235656
pow(fabs(dv[Y]), crackleMetric) +
56245657
pow(fabs(dv[Z]), crackleMetric);
56255658

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

56555688
if(UseSquare)
56565689
sum = dv.lengthSqr();

source/core/material/pattern.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ struct CracklePattern : public ContinuousPattern
425425
DBL crackleMetric;
426426
DBL crackleOffset;
427427
short crackleIsSolid;
428+
IntVector3d repeat;
428429

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

975-
CrackleCellCoord() : mX(0), mY(0), mZ(0) {}
976-
CrackleCellCoord(int x, int y, int z) : mX(x), mY(y), mZ(z) {}
976+
CrackleCellCoord() : mX(0), mY(0), mZ(0), mRepeatX(0), mRepeatY(0), mRepeatZ(0) {}
977+
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)
978+
{
979+
WrapCellCoordinate(mX, mRepeatX);
980+
WrapCellCoordinate(mY, mRepeatY);
981+
WrapCellCoordinate(mZ, mRepeatZ);
982+
}
977983

978984
bool operator==(CrackleCellCoord const& other) const
979985
{
@@ -1003,6 +1009,18 @@ class CrackleCellCoord
10031009
int mX;
10041010
int mY;
10051011
int mZ;
1012+
int mRepeatX;
1013+
int mRepeatY;
1014+
int mRepeatZ;
1015+
1016+
static inline void WrapCellCoordinate(int& v, int& repeat)
1017+
{
1018+
if (!repeat)
1019+
return;
1020+
v = wrapInt(v, repeat);
1021+
if ((v >= 2) && (v < repeat - 2))
1022+
repeat = 0;
1023+
}
10061024
};
10071025

10081026
/// Helper class to implement the crackle cache.

source/core/math/vector.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ typedef GenericVector2d<SNGL> SnglVector2d; ///< Single-precision 2D vector.
576576

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

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

source/parser/parser_materials.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,18 @@ void Parser::Parse_Pattern (PATTERN_T *New, BlendMapTypeId TPat_Type)
21442144
Set_Flag(New, DONT_SCALE_BUMPS_FLAG);
21452145
END_CASE
21462146

2147+
CASE (REPEAT_TOKEN)
2148+
if (!dynamic_cast<CracklePattern*>(New->pattern.get()))
2149+
Only_In("repeat","crackle");
2150+
Parse_Vector(Local_Vector);
2151+
dynamic_cast<CracklePattern*>(New->pattern.get())->repeat = IntVector3d(Local_Vector);
2152+
if((dynamic_cast<CracklePattern*>(New->pattern.get())->repeat.x() < 0) ||
2153+
(dynamic_cast<CracklePattern*>(New->pattern.get())->repeat.y() < 0) ||
2154+
(dynamic_cast<CracklePattern*>(New->pattern.get())->repeat.z() < 0))
2155+
Error("Repeat vector must be non-negative.");
2156+
EXIT
2157+
END_CASE
2158+
21472159
OTHERWISE
21482160
UNGET
21492161
EXIT

unix/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.7.1-alpha.8509766
1+
3.7.1-alpha.8514084

0 commit comments

Comments
 (0)