You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
5.5 KiB
C++
164 lines
5.5 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm> // std::swap()
|
|
#include <limits> // std::numeric_limits
|
|
#include <type_traits> // std::make_unsigned
|
|
#include "BaseTypes.h" // uint32, uint64
|
|
#include "CompileTimeAssert.h"
|
|
#include "Cry_Vector2.h"
|
|
#include "Cry_Vector3.h"
|
|
#include "Cry_Vector4.h"
|
|
|
|
|
|
namespace CryRandom_Internal
|
|
{
|
|
template <class R, class T, size_t size>
|
|
struct BoundedRandomUint
|
|
{
|
|
COMPILE_TIME_ASSERT(std::numeric_limits<T>::is_integer);
|
|
COMPILE_TIME_ASSERT(!std::numeric_limits<T>::is_signed);
|
|
COMPILE_TIME_ASSERT(sizeof(T) == size);
|
|
COMPILE_TIME_ASSERT(sizeof(T) <= sizeof(uint32));
|
|
|
|
inline static T Get(R& randomGenerator, const T maxValue)
|
|
{
|
|
const uint32 r = randomGenerator.GenerateUint32();
|
|
// Note that the computation below is biased. An alternative computation
|
|
// (also biased): uint32((uint64)r * ((uint64)maxValue + 1)) >> 32)
|
|
return (T)((uint64)r % ((uint64)maxValue + 1));
|
|
}
|
|
};
|
|
|
|
template <class R, class T>
|
|
struct BoundedRandomUint<R, T, 8>
|
|
{
|
|
COMPILE_TIME_ASSERT(std::numeric_limits<T>::is_integer);
|
|
COMPILE_TIME_ASSERT(!std::numeric_limits<T>::is_signed);
|
|
COMPILE_TIME_ASSERT(sizeof(T) == sizeof(uint64));
|
|
|
|
inline static T Get(R& randomGenerator, const T maxValue)
|
|
{
|
|
const uint64 r = randomGenerator.GenerateUint64();
|
|
if (maxValue >= (std::numeric_limits<uint64>::max)())
|
|
{
|
|
return r;
|
|
}
|
|
// Note that the computation below is biased.
|
|
return (T)(r % ((uint64)maxValue + 1));
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class R, class T, bool bInteger = std::numeric_limits<T>::is_integer>
|
|
struct BoundedRandom;
|
|
|
|
template <class R, class T>
|
|
struct BoundedRandom<R, T, true>
|
|
{
|
|
COMPILE_TIME_ASSERT(std::numeric_limits<T>::is_integer);
|
|
typedef typename std::make_unsigned<T>::type UT;
|
|
COMPILE_TIME_ASSERT(sizeof(T) == sizeof(UT));
|
|
COMPILE_TIME_ASSERT(std::numeric_limits<UT>::is_integer);
|
|
COMPILE_TIME_ASSERT(!std::numeric_limits<UT>::is_signed);
|
|
|
|
inline static T Get(R& randomGenerator, T minValue, T maxValue)
|
|
{
|
|
if (minValue > maxValue)
|
|
{
|
|
std::swap(minValue, maxValue);
|
|
}
|
|
return (T)((UT)minValue + (UT)BoundedRandomUint<R, UT, sizeof(UT)>::Get(randomGenerator, (UT)(maxValue - minValue)));
|
|
}
|
|
};
|
|
|
|
template <class R, class T>
|
|
struct BoundedRandom<R, T, false>
|
|
{
|
|
COMPILE_TIME_ASSERT(!std::numeric_limits<T>::is_integer);
|
|
|
|
inline static T Get(R& randomGenerator, const T minValue, const T maxValue)
|
|
{
|
|
return minValue + (maxValue - minValue) * randomGenerator.GenerateFloat();
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class R, class VT, class T = typename VT::value_type, size_t componentCount = VT::component_count>
|
|
struct BoundedRandomComponentwise;
|
|
|
|
template <class R, class VT, class T>
|
|
struct BoundedRandomComponentwise<R, VT, T, 2>
|
|
{
|
|
inline static VT Get(R& randomGenerator, const VT& minValue, const VT& maxValue)
|
|
{
|
|
const T x = BoundedRandom<R, T>::Get(randomGenerator, minValue.x, maxValue.x);
|
|
const T y = BoundedRandom<R, T>::Get(randomGenerator, minValue.y, maxValue.y);
|
|
return VT(x, y);
|
|
}
|
|
};
|
|
|
|
template <class R, class VT, class T>
|
|
struct BoundedRandomComponentwise<R, VT, T, 3>
|
|
{
|
|
inline static VT Get(R& randomGenerator, const VT& minValue, const VT& maxValue)
|
|
{
|
|
const T x = BoundedRandom<R, T>::Get(randomGenerator, minValue.x, maxValue.x);
|
|
const T y = BoundedRandom<R, T>::Get(randomGenerator, minValue.y, maxValue.y);
|
|
const T z = BoundedRandom<R, T>::Get(randomGenerator, minValue.z, maxValue.z);
|
|
return VT(x, y, z);
|
|
}
|
|
};
|
|
|
|
template <class R, class VT, class T>
|
|
struct BoundedRandomComponentwise<R, VT, T, 4>
|
|
{
|
|
inline static VT Get(R& randomGenerator, const VT& minValue, const VT& maxValue)
|
|
{
|
|
const T x = BoundedRandom<R, T>::Get(randomGenerator, minValue.x, maxValue.x);
|
|
const T y = BoundedRandom<R, T>::Get(randomGenerator, minValue.y, maxValue.y);
|
|
const T z = BoundedRandom<R, T>::Get(randomGenerator, minValue.z, maxValue.z);
|
|
const T w = BoundedRandom<R, T>::Get(randomGenerator, minValue.w, maxValue.w);
|
|
return VT(x, y, z, w);
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
template <class R, class VT>
|
|
inline VT GetRandomUnitVector(R& randomGenerator)
|
|
{
|
|
typedef typename VT::value_type T;
|
|
COMPILE_TIME_ASSERT(!std::numeric_limits<T>::is_integer);
|
|
|
|
VT res;
|
|
T lenSquared;
|
|
|
|
do
|
|
{
|
|
res = BoundedRandomComponentwise<R, VT>::Get(randomGenerator, VT(-1), VT(1));
|
|
lenSquared = res.GetLengthSquared();
|
|
} while (lenSquared > 1);
|
|
|
|
if (lenSquared >= (std::numeric_limits<T>::min)())
|
|
{
|
|
return res * isqrt_tpl(lenSquared);
|
|
}
|
|
|
|
res = VT(ZERO);
|
|
res.x = 1;
|
|
return res;
|
|
}
|
|
} // namespace CryRandom_Internal
|
|
|
|
// eof
|