server/dep/src/g3dlite/Random.cpp
Lynx3d ae3ad10bcf [10097] Update G3D up to v8.0b4
+ Got rid of zip lib requirement in G3D...
  Still can re-enable code by defining _HAVE_ZIP...

+ Remove silly X11 lib dependency from G3D
  Code doesn't seem to do anything yet anyway, and even if, we don't want it :p

+ Fix another weird G3D build problem...

+ Remove some __asm usage in g3d, which is not available on Win64
  My editor also decided to remove a ton of trailing white spaces...tss...

+ Reapply G3D fixes for 64bit VC

+ not use SSE specific header when SSE not enabled in *nix

+ Updated project files

+ New vmap_assembler VC90/VC80 Project

+ vmap assembler binaries updates

NOTE: Old vmap fikes expected work (as tests show) with new library version.
      But better use new generated versions. Its different in small parts to bad or good...

(based on Lynx3d's repo commit 44798d3)

Signed-off-by: VladimirMangos <vladimir@getmangos.com>
2010-06-23 06:45:25 +04:00

212 lines
5.1 KiB
C++

/**
@file Random.cpp
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2009-01-02
@edited 2009-03-29
Copyright 2000-2009, Morgan McGuire.
All rights reserved.
*/
#include "G3D/Random.h"
namespace G3D {
Random& Random::common() {
static Random r;
return r;
}
Random::Random(void* x) : state(NULL), m_threadsafe(false) {
(void)x;
}
Random::Random(uint32 seed, bool threadsafe) : m_threadsafe(threadsafe) {
const uint32 X = 1812433253UL;
state = new uint32[N];
state[0] = seed;
for (index = 1; index < (int)N; ++index) {
state[index] = X * (state[index - 1] ^ (state[index - 1] >> 30)) + index;
}
}
Random::~Random() {
delete[] state;
state = NULL;
}
uint32 Random::bits() {
// See http://en.wikipedia.org/wiki/Mersenne_twister
// Make a local copy of the index variable to ensure that it
// is not out of bounds
int localIndex = index;
// Automatically checks for index < 0 if corrupted
// by unsynchronized threads.
if ((unsigned int)localIndex >= (unsigned int)N) {
generate();
localIndex = 0;
}
// Increment the global index. It may go out of bounds on
// multiple threads, but the above check ensures that the
// array index actually used never goes out of bounds.
// It doesn't matter if we grab the same array index twice
// on two threads, since the distribution of random numbers
// will still be uniform.
++index;
// Return the next random in the sequence
uint32 r = state[localIndex];
// Temper the result
r ^= r >> U;
r ^= (r << S) & B;
r ^= (r << T) & C;
r ^= r >> L;
return r;
}
/** Generate the next N ints, and store them for readback later */
void Random::generate() {
// Lower R bits
static const uint32 LOWER_MASK = (1LU << R) - 1;
// Upper (32 - R) bits
static const uint32 UPPER_MASK = 0xFFFFFFFF << R;
static const uint32 mag01[2] = {0UL, (uint32)A};
if (m_threadsafe) {
bool contention = ! lock.lock();
if (contention) {
// Another thread just generated a set of numbers; no need for
// this thread to do it too
lock.unlock();
return;
}
}
// First N - M
for (unsigned int i = 0; i < N - M; ++i) {
uint32 x = (state[i] & UPPER_MASK) | (state[i + 1] & LOWER_MASK);
state[i] = state[i + M] ^ (x >> 1) ^ mag01[x & 1];
}
// Rest
for (unsigned int i = N - M + 1; i < N - 1; ++i) {
uint32 x = (state[i] & UPPER_MASK) | (state[i + 1] & LOWER_MASK);
state[i] = state[i + (M - N)] ^ (x >> 1) ^ mag01[x & 1];
}
uint32 y = (state[N - 1] & UPPER_MASK) | (state[0] & LOWER_MASK);
state[N - 1] = state[M - 1] ^ (y >> 1) ^ mag01[y & 1];
index = 0;
if (m_threadsafe) {
lock.unlock();
}
}
int Random::integer(int low, int high) {
int r = iFloor(low + (high - low + 1) * (double)bits() / 0xFFFFFFFFUL);
// There is a *very small* chance of generating
// a number larger than high.
if (r > high) {
return high;
} else {
return r;
}
}
float Random::gaussian(float mean, float stdev) {
// Using Box-Mueller method from http://www.taygeta.com/random/gaussian.html
// Modified to specify standard deviation and mean of distribution
float w, x1, x2;
// Loop until w is less than 1 so that log(w) is negative
do {
x1 = uniform(-1.0, 1.0);
x2 = uniform(-1.0, 1.0);
w = float(square(x1) + square(x2));
} while (w > 1.0f);
// Transform to gassian distribution
// Multiply by sigma (stdev ^ 2) and add mean.
return x2 * (float)square(stdev) * sqrtf((-2.0f * logf(w) ) / w) + mean;
}
void Random::cosHemi(float& x, float& y, float& z) {
const float e1 = uniform();
const float e2 = uniform();
// Jensen's method
const float sin_theta = sqrtf(1.0f - e1);
const float cos_theta = sqrtf(e1);
const float phi = 6.28318531f * e2;
x = cos(phi) * sin_theta;
y = sin(phi) * sin_theta;
z = cos_theta;
// We could also use Malley's method (pbrt p.657), since they are the same cost:
//
// r = sqrt(e1);
// t = 2*pi*e2;
// x = cos(t)*r;
// y = sin(t)*r;
// z = sqrt(1.0 - x*x + y*y);
}
void Random::cosPowHemi(const float k, float& x, float& y, float& z) {
const float e1 = uniform();
const float e2 = uniform();
const float cos_theta = pow(e1, 1.0f / (k + 1.0f));
const float sin_theta = sqrtf(1.0f - square(cos_theta));
const float phi = 6.28318531f * e2;
x = cos(phi) * sin_theta;
y = sin(phi) * sin_theta;
z = cos_theta;
}
void Random::hemi(float& x, float& y, float& z) {
sphere(x, y, z);
z = fabsf(z);
}
void Random::sphere(float& x, float& y, float& z) {
// Squared magnitude
float m2;
// Rejection sample
do {
x = uniform() * 2.0f - 1.0f,
y = uniform() * 2.0f - 1.0f,
z = uniform() * 2.0f - 1.0f;
m2 = x*x + y*y + z*z;
} while (m2 >= 1.0f);
// Divide by magnitude to produce a unit vector
float s = rsqrt(m2);
x *= s;
y *= s;
z *= s;
}
} // G3D