mRandom.cpp

Engine/source/math/mRandom.cpp

More...

Public Functions

Detailed Description

Public Variables

MRandomLCG gRandGen 
U32 gRandGenSeed 
U32 msSeed 

Public Functions

generateSeed()

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "math/mRandom.h"
 26#include "core/util/journal/journal.h"
 27
 28MRandomLCG gRandGen;
 29U32 gRandGenSeed = 1376312589;
 30
 31void MRandomLCG::setGlobalRandSeed(U32 seed)
 32{
 33   if (Journal::IsPlaying())
 34      Journal::Read(&gRandGenSeed);
 35   else
 36   {
 37      gRandGenSeed = seed;
 38      if (Journal::IsRecording())
 39         Journal::Write(gRandGenSeed);
 40   }
 41
 42   //now actually set the seed
 43   gRandGen.setSeed(gRandGenSeed);
 44}
 45
 46static U32 msSeed = 1376312589;
 47
 48inline U32 generateSeed()
 49{
 50   // A very, VERY crude LCG but good enough to generate
 51   // a nice range of seed values
 52   msSeed = (msSeed * 0x015a4e35L) + 1;
 53   msSeed = (msSeed>>16)&0x7fff;
 54   return (msSeed);
 55}
 56
 57//--------------------------------------
 58void MRandomGenerator::setSeed()
 59{
 60   setSeed(generateSeed());
 61}
 62
 63
 64//--------------------------------------
 65const S32 MRandomLCG::msQuotient  = S32_MAX / 16807L;
 66const S32 MRandomLCG::msRemainder = S32_MAX % 16807L;
 67
 68
 69//--------------------------------------
 70MRandomLCG::MRandomLCG()
 71{
 72   setSeed(generateSeed());
 73}
 74
 75MRandomLCG::MRandomLCG(S32 s)
 76{
 77   setSeed(s);
 78}
 79
 80
 81//--------------------------------------
 82void MRandomLCG::setSeed(S32 s)
 83{
 84   mSeed = s;
 85}
 86
 87
 88//--------------------------------------
 89U32 MRandomLCG::randI()
 90{
 91   if ( mSeed <= msQuotient )
 92      mSeed = (mSeed * 16807) % S32_MAX;
 93   else
 94   {
 95      S32 high_part = mSeed / msQuotient;
 96      S32 low_part  = mSeed % msQuotient;
 97
 98      S32 test = (16807 * low_part) - (msRemainder * high_part);
 99
100      if ( test > 0 )
101         mSeed = test;
102      else
103         mSeed = test + S32_MAX;
104
105   }
106   return mSeed;
107}
108
109
110
111//--------------------------------------
112MRandomR250::MRandomR250()
113{
114   setSeed(generateSeed());
115}
116
117MRandomR250::MRandomR250(S32 s)
118{
119   setSeed(s);
120}
121
122
123//--------------------------------------
124void MRandomR250::setSeed(S32 s)
125{
126   mSeed = s;
127   MRandomLCG lcg( s );
128   mIndex = 0;
129
130   S32 j;
131   for (j = 0; j < 250; j++)        // fill r250 buffer with bit values
132      mBuffer[j] = lcg.randI();
133
134   for (j = 0; j < 250; j++)        // set some MSBs to 1
135      if ( lcg.randI() > 0x40000000L )
136         mBuffer[j] |= 0x80000000L;
137
138
139   U32 msb  = 0x80000000;           // turn on diagonal bit
140   U32 mask = 0xffffffff;           // turn off the leftmost bits
141
142   for (j = 0; j < 32; j++)
143   {
144      S32 k = 7 * j + 3;            // select a word to operate on
145      mBuffer[k] &= mask;           // turn off bits left of the diagonal
146      mBuffer[k] |= msb;            // turn on the diagonal bit
147      mask >>= 1;
148      msb  >>= 1;
149   }
150}
151
152
153//--------------------------------------
154U32 MRandomR250::randI()
155{
156   S32 j;
157
158   // wrap pointer around
159   if ( mIndex >= 147 ) j = mIndex - 147;
160   else                 j = mIndex + 103;
161
162   U32 new_rand = mBuffer[ mIndex ] ^ mBuffer[ j ];
163   mBuffer[ mIndex ] = new_rand;
164
165   // increment pointer for next time
166   if ( mIndex >= 249 ) mIndex = 0;
167   else                 mIndex++;
168
169   return new_rand >> 1;
170}
171
172
173