Subversion Repositories filter_foundry

Compare Revisions

Regard whitespace Rev 289 → Rev 290

/trunk/funcs.c
173,23 → 173,60
return abs(a-b);
}
 
uint16_t gFactoryRndIndexCounter1 = 0;
uint16_t gFactoryRndIndexCounter2 = 31;
struct factoryRngState {
uint16_t gFactoryRndIndexCounter1;
uint16_t gFactoryRndIndexCounter2;
uint32_t gFactoryRndLookup[56];
uint32_t gFactoryRndSeed;
uint32_t gFactoryRndSeedSave;
} gRngState;
 
void factory_fill_rnd_lookup(uint32_t seed);
void factory_fill_rnd_lookup(uint32_t seed, struct factoryRngState* state) {
// Algorithm of Filter Factory
// Filter Factory uses Donald E.Knuth's subtractive
// random number generator algorithm ("ran3"), which has been published
// in Page 283 of "The Art of Computer Programming, volume 2: Seminumerical Algorithms",
// Addison-Wesley, Reading, MA, second edition, 1981.
// https://www.cec.uchile.cl/cinetica/pcordero/MC_libros/NumericalRecipesinC.pdf (PDF Page 307)
 
uint32_t factory_rnd(uint32_t a, uint32_t b) {
long mj, mk;
int i, ii, k;
 
// 161803398 = 1.61803398 * 10^8 ~= phi * 10^8
mj = 161803398 - (seed & 0x7fff);
state->gFactoryRndLookup[55] = mj;
 
mk = 1;
ii = 0;
for (i=1; i<=54; ++i) {
if ((ii += 21) >= 55) ii -= 55; // ii = (21*i)%55;
state->gFactoryRndLookup[ii] = mk;
mk = mj - mk;
mj = state->gFactoryRndLookup[ii];
}
 
for (k=1; k<=4; ++k) {
ii = 30;
for (i=1; i<=55; ++i) {
if ((ii += 1) >= 55) ii -= 55;
state->gFactoryRndLookup[i] -= state->gFactoryRndLookup[1 + ii]; // 1 + (i+30)%55
}
}
 
state->gFactoryRndSeedSave = seed;
 
return;
}
 
uint32_t factory_rnd(uint32_t a, uint32_t b, struct factoryRngState* state) {
uint32_t mj; // Note: This must be "uint32_t". With "long" (as described by Knuth), it won't match FilterFactory's algorithm
int range;
 
if (gFactoryRndSeed != gFactoryRndSeedSave) {
if (state->gFactoryRndSeed != state->gFactoryRndSeedSave) {
// (Intentional) behavior of Filter Foundry
factory_fill_rnd_lookup(gFactoryRndSeed);
gFactoryRndIndexCounter1 = 0;
gFactoryRndIndexCounter2 = 31;
factory_fill_rnd_lookup(state->gFactoryRndSeed, &gRngState);
state->gFactoryRndIndexCounter1 = 0;
state->gFactoryRndIndexCounter2 = 31;
}
 
// Algorithm of Filter Factory
199,96 → 236,72
// Addison-Wesley, Reading, MA, second edition, 1981.
// https://www.cec.uchile.cl/cinetica/pcordero/MC_libros/NumericalRecipesinC.pdf (PDF Page 307)
 
if (++gFactoryRndIndexCounter1 == 56) gFactoryRndIndexCounter1 = 1;
if (++gFactoryRndIndexCounter2 == 56) gFactoryRndIndexCounter2 = 1;
if (++state->gFactoryRndIndexCounter1 == 56) state->gFactoryRndIndexCounter1 = 1;
if (++state->gFactoryRndIndexCounter2 == 56) state->gFactoryRndIndexCounter2 = 1;
 
mj = gFactoryRndLookup[gFactoryRndIndexCounter1] -
gFactoryRndLookup[gFactoryRndIndexCounter2];
gFactoryRndLookup[gFactoryRndIndexCounter1] = mj;
mj = state->gFactoryRndLookup[state->gFactoryRndIndexCounter1] -
state->gFactoryRndLookup[state->gFactoryRndIndexCounter2];
state->gFactoryRndLookup[state->gFactoryRndIndexCounter1] = mj;
 
// This is Filter Factory specific:
// Squeeze result into interval [a..b]
if (a == 0) {
// This part is optional; it is intended to increase the
// performance by avoiding modulo/divide if possible.
switch (b) {
// Reduce result into interval [a..b] by applying (a + (mj % (b - a + 1))
// Try to avoid modulo in order to increase performance
range = b - a;
if (range < 0) return 0;
switch (range) {
case 255:
return mj & 0xFF;
return a + (mj & 0xFF);
case 127:
return mj & 0x7F;
return a + (mj & 0x7F);
case 63:
return mj & 0x3F;
return a + (mj & 0x3F);
case 31:
return mj & 0x1F;
return a + (mj & 0x1F);
case 15:
return mj & 0xF;
return a + (mj & 0xF);
case 7:
return mj & 0x7;
return a + (mj & 0x7);
case 3:
return mj & 0x3;
return a + (mj & 0x3);
case 1:
return mj & 0x1;
}
}
range = b - a;
if (range < 0) return 0;
return a + (mj & 0x1);
case 0:
return a;
default:
return a + (mj % (range + 1));
}
 
void factory_fill_rnd_lookup(uint32_t seed) {
// Algorithm of Filter Factory
// Filter Factory uses Donald E.Knuth's subtractive
// random number generator algorithm ("ran3"), which has been published
// in Page 283 of "The Art of Computer Programming, volume 2: Seminumerical Algorithms",
// Addison-Wesley, Reading, MA, second edition, 1981.
// https://www.cec.uchile.cl/cinetica/pcordero/MC_libros/NumericalRecipesinC.pdf (PDF Page 307)
 
long mj, mk;
int i, ii, k;
 
// 161803398 = 1.61803398 * 10^8 ~= phi * 10^8
mj = 161803398 - (seed & 0x7fff);
gFactoryRndLookup[55] = mj;
 
mk = 1;
for (i=1; i<=54; ++i) {
ii = (21 * i) % 55;
gFactoryRndLookup[ii] = mk;
mk = mj - mk;
mj = gFactoryRndLookup[ii];
}
 
for (k=1; k<=4; ++k) {
for (i=1; i<=55; ++i) {
gFactoryRndLookup[i] -= gFactoryRndLookup[1+(i + 30) % 55];
}
}
int32_t factory_rst(uint32_t seed, struct factoryRngState* state) {
// We implement rst(i) completely differently in Filter Foundry:
// Every call of rst() will renew the lookup table.
// In Filter Factory, there are strange/buggy things going
// on: rst(i) only sets a seed and the lookup table is renewed
// at the NEXT invocation of the filter. Furthermore, in FilterFactory,
// the state is not reset between invocations, therefore, the preview image
// will influence the PRNG state of the final image...
// More information at "Filter Factory Compatibility.md"
 
gFactoryRndSeedSave = seed;
state->gFactoryRndSeed = seed;
 
return;
}
// Force renewal of the PRNG state in the next rnd(a,b) call.
// This allows us to use:
// (x==0?rst(1):0), rnd(0,255)
// But it is slower and this won't work anymore:
// rst(0), rnd(0,255)
state->gFactoryRndSeedSave = seed+1;
 
int32_t factory_rst(uint32_t seed) {
// We implement rst(i) differently in Filter Foundry:
// Every call of rst() will renew the lookup table,
// while in Filter Factory, there are strange things going
// on, like only setting the state in pixel [0,0,0] and
// only before rnd() is called, etc.
 
gFactoryRndSeed = seed;
 
return 0;
}
 
void factory_initialize_rnd_variables() {
gFactoryRndSeed = 0; // default seed
gFactoryRndSeedSave = gFactoryRndSeed + 1; // force rnd() to call factory_fill_rnd_lookup()
gRngState.gFactoryRndSeed = 0; // default seed
gRngState.gFactoryRndSeedSave = gRngState.gFactoryRndSeed + 1; // force rnd() to call factory_fill_rnd_lookup()
}
 
/* rnd(a,b) Random number between a and b, inclusive */
value_type ff_rnd(value_type a,value_type b){
return factory_rnd(a,b);
return factory_rnd(a,b,&gRngState);
// return (int)((abs(a-b)+1)*(rand()/(RAND_MAX+1.))) + ff_min(a,b);
// return ((unsigned)rand() % (ff_dif(a,b)+1)) + ff_min(a,b);
}
468,7 → 481,7
/* rst(i) sets a random seed and returns 0. (undocumented Filter Factory function).
Added by DM, 18 Dec 2018 */
value_type ff_rst(value_type seed){
factory_rst(seed);
factory_rst(seed,&gRngState);
// srand(seed);
return 0;
}