mirror of https://github.com/bjornbytes/lovr.git
RandomGenerator;
This commit is contained in:
parent
39ba6d3f12
commit
8b34330079
|
@ -2,6 +2,7 @@
|
|||
#include "filesystem/blob.h"
|
||||
#include "graphics/mesh.h"
|
||||
#include "math/math.h"
|
||||
#include "math/randomGenerator.h"
|
||||
#include "physics/physics.h"
|
||||
#include "lib/map/map.h"
|
||||
|
||||
|
@ -34,6 +35,7 @@ extern const luaL_Reg lovrMath[];
|
|||
extern const luaL_Reg lovrMesh[];
|
||||
extern const luaL_Reg lovrModel[];
|
||||
extern const luaL_Reg lovrPhysics[];
|
||||
extern const luaL_Reg lovrRandomGenerator[];
|
||||
extern const luaL_Reg lovrShader[];
|
||||
extern const luaL_Reg lovrShape[];
|
||||
extern const luaL_Reg lovrSkybox[];
|
||||
|
@ -71,3 +73,4 @@ int luax_readtransform(lua_State* L, int index, mat4 transform, int uniformScale
|
|||
Blob* luax_readblob(lua_State* L, int index, const char* debug);
|
||||
int luax_pushshape(lua_State* L, Shape* shape);
|
||||
int luax_pushjoint(lua_State* L, Joint* joint);
|
||||
Seed luax_checkrandomseed(lua_State* L, int index);
|
||||
|
|
|
@ -1,15 +1,28 @@
|
|||
#include "api/lovr.h"
|
||||
#include "math/mat4.h"
|
||||
#include "math/quat.h"
|
||||
#include "math/randomGenerator.h"
|
||||
#include "math/transform.h"
|
||||
|
||||
int l_lovrMathInit(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, lovrMath);
|
||||
luax_registertype(L, "RandomGenerator", lovrRandomGenerator);
|
||||
luax_registertype(L, "Transform", lovrTransform);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrMathNewRandomGenerator(lua_State* L) {
|
||||
RandomGenerator* generator = lovrRandomGeneratorCreate();
|
||||
if (lua_gettop(L) > 0){
|
||||
Seed seed = luax_checkrandomseed(L, 1);
|
||||
lovrRandomGeneratorSetSeed(generator, seed);
|
||||
}
|
||||
luax_pushtype(L, RandomGenerator, generator);
|
||||
lovrRelease(&generator->ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrMathNewTransform(lua_State* L) {
|
||||
float matrix[16];
|
||||
luax_readtransform(L, 1, matrix, 0);
|
||||
|
@ -35,6 +48,7 @@ int l_lovrMathLookAt(lua_State* L) {
|
|||
}
|
||||
|
||||
const luaL_Reg lovrMath[] = {
|
||||
{ "newRandomGenerator", l_lovrMathNewRandomGenerator },
|
||||
{ "newTransform", l_lovrMathNewTransform },
|
||||
{ "lookAt", l_lovrMathLookAt },
|
||||
{ NULL, NULL }
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
#include "api/lovr.h"
|
||||
#include "math/randomGenerator.h"
|
||||
|
||||
static double luax_checkrandomseedpart(lua_State* L, int index) {
|
||||
double x = luaL_checknumber(L, index);
|
||||
|
||||
if (!isfinite(x)) {
|
||||
luaL_argerror(L, index, "invalid random seed");
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
Seed luax_checkrandomseed(lua_State* L, int index) {
|
||||
Seed seed;
|
||||
|
||||
if (lua_isnoneornil(L, index + 1)) {
|
||||
seed.b64 = luax_checkrandomseedpart(L, index);
|
||||
} else {
|
||||
seed.b32.lo = luax_checkrandomseedpart(L, index);
|
||||
seed.b32.hi = luax_checkrandomseedpart(L, index + 1);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
int l_lovrRandomGeneratorGetSeed(lua_State* L) {
|
||||
RandomGenerator* generator = luax_checktype(L, 1, RandomGenerator);
|
||||
Seed seed = lovrRandomGeneratorGetSeed(generator);
|
||||
lua_pushnumber(L, seed.b32.lo);
|
||||
lua_pushnumber(L, seed.b32.hi);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int l_lovrRandomGeneratorSetSeed(lua_State* L) {
|
||||
RandomGenerator* generator = luax_checktype(L, 1, RandomGenerator);
|
||||
Seed seed = luax_checkrandomseed(L, 2);
|
||||
lovrRandomGeneratorSetSeed(generator, seed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrRandomGeneratorGetState(lua_State* L) {
|
||||
RandomGenerator* generator = luax_checktype(L, 1, RandomGenerator);
|
||||
size_t length = 32;
|
||||
char state[32];
|
||||
lovrRandomGeneratorGetState(generator, state, length);
|
||||
lua_pushstring(L, state);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrRandomGeneratorSetState(lua_State* L) {
|
||||
RandomGenerator* generator = luax_checktype(L, 1, RandomGenerator);
|
||||
size_t length;
|
||||
const char* state = luaL_checklstring(L, 2, &length);
|
||||
if (lovrRandomGeneratorSetState(generator, state, length)) {
|
||||
return luaL_error(L, "invalid random state %s", state);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrRandomGeneratorRandom(lua_State* L) {
|
||||
RandomGenerator* generator = luax_checktype(L, 1, RandomGenerator);
|
||||
float r = lovrRandomGeneratorRandom(generator);
|
||||
|
||||
if (lua_gettop(L) >= 3) {
|
||||
float lower = luaL_checknumber(L, 2);
|
||||
float upper = luaL_checknumber(L, 3);
|
||||
lua_pushnumber(L, floor(r * (upper - lower + 1)) + lower);
|
||||
} else if (lua_gettop(L) >= 2) {
|
||||
float upper = luaL_checknumber(L, 2);
|
||||
lua_pushnumber(L, floor(r * upper) + 1);
|
||||
} else {
|
||||
lua_pushnumber(L, r);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int l_lovrRandomGeneratorRandomNormal(lua_State* L) {
|
||||
RandomGenerator* generator = luax_checktype(L, 1, RandomGenerator);
|
||||
float sigma = luaL_optnumber(L, 2, 1);
|
||||
float mu = luaL_optnumber(L, 3, 0);
|
||||
lua_pushnumber(L, mu + lovrRandomGeneratorRandomNormal(generator) * sigma);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrRandomGenerator[] = {
|
||||
{ "getSeed", l_lovrRandomGeneratorGetSeed },
|
||||
{ "setSeed", l_lovrRandomGeneratorSetSeed },
|
||||
{ "getState", l_lovrRandomGeneratorGetState },
|
||||
{ "setState", l_lovrRandomGeneratorSetState },
|
||||
{ "random", l_lovrRandomGeneratorRandom },
|
||||
{ "randomNormal", l_lovrRandomGeneratorRandomNormal },
|
||||
{ NULL, NULL }
|
||||
};
|
|
@ -0,0 +1,92 @@
|
|||
#include "math/randomGenerator.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Thomas Wang's 64-bit integer hashing function:
|
||||
// https://web.archive.org/web/20110807030012/http://www.cris.com/%7ETtwang/tech/inthash.htm
|
||||
static uint64_t wangHash64(uint64_t key) {
|
||||
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
|
||||
key = key ^ (key >> 24);
|
||||
key = (key + (key << 3)) + (key << 8); // key * 265
|
||||
key = key ^ (key >> 14);
|
||||
key = (key + (key << 2)) + (key << 4); // key * 21
|
||||
key = key ^ (key >> 28);
|
||||
key = key + (key << 31);
|
||||
return key;
|
||||
}
|
||||
|
||||
// 64 bit Xorshift implementation taken from the end of Sec. 3 (page 4) in
|
||||
// George Marsaglia, "Xorshift RNGs", Journal of Statistical Software, Vol.8 (Issue 14), 2003
|
||||
// Use an 'Xorshift*' variant, as shown here: http://xorshift.di.unimi.it
|
||||
|
||||
RandomGenerator* lovrRandomGeneratorCreate() {
|
||||
RandomGenerator* generator = lovrAlloc(sizeof(RandomGenerator), lovrRandomGeneratorDestroy);
|
||||
if (!generator) return NULL;
|
||||
|
||||
Seed seed = { .b32 = { .lo = 0xCBBF7A44, .hi = 0x0139408D } };
|
||||
lovrRandomGeneratorSetSeed(generator, seed);
|
||||
generator->lastRandomNormal = INFINITY;
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
void lovrRandomGeneratorDestroy(const Ref* ref) {
|
||||
RandomGenerator* generator = containerof(ref, RandomGenerator);
|
||||
free(generator);
|
||||
}
|
||||
|
||||
Seed lovrRandomGeneratorGetSeed(RandomGenerator* generator) {
|
||||
return generator->seed;
|
||||
}
|
||||
|
||||
void lovrRandomGeneratorSetSeed(RandomGenerator* generator, Seed seed) {
|
||||
generator->seed = seed;
|
||||
|
||||
do {
|
||||
seed.b64 = wangHash64(seed.b64);
|
||||
} while (seed.b64 == 0);
|
||||
|
||||
generator->state = seed;
|
||||
}
|
||||
|
||||
void lovrRandomGeneratorGetState(RandomGenerator* generator, char* state, size_t length) {
|
||||
snprintf(state, length, "0x%16llx", generator->state.b64);
|
||||
}
|
||||
|
||||
int lovrRandomGeneratorSetState(RandomGenerator* generator, const char* state, size_t length) {
|
||||
char* end = NULL;
|
||||
Seed newState;
|
||||
newState.b64 = strtoull(state, &end, 16);
|
||||
if (end != NULL && *end != 0) {
|
||||
return 1;
|
||||
} else {
|
||||
generator->state = newState;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
double lovrRandomGeneratorRandom(RandomGenerator* generator) {
|
||||
generator->state.b64 ^= (generator->state.b64 >> 12);
|
||||
generator->state.b64 ^= (generator->state.b64 << 25);
|
||||
generator->state.b64 ^= (generator->state.b64 >> 27);
|
||||
uint64_t r = generator->state.b64 * 2685821657736338717ULL;
|
||||
union { uint64_t i; double d; } u;
|
||||
u.i = ((0x3FFULL) << 52) | (r >> 12);
|
||||
return u.d - 1.;
|
||||
}
|
||||
|
||||
double lovrRandomGeneratorRandomNormal(RandomGenerator* generator) {
|
||||
if (generator->lastRandomNormal != INFINITY) {
|
||||
double r = generator->lastRandomNormal;
|
||||
generator->lastRandomNormal = INFINITY;
|
||||
return r;
|
||||
}
|
||||
|
||||
double a = lovrRandomGeneratorRandom(generator);
|
||||
double b = lovrRandomGeneratorRandom(generator);
|
||||
double r = sqrt(-2. * log(1. - a));
|
||||
double phi = 2 * M_PI * (1. - b);
|
||||
generator->lastRandomNormal = r * cos(phi);
|
||||
return r * sin(phi);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
// Direct port of LÖVE's RandomGenerator
|
||||
|
||||
typedef union {
|
||||
uint64_t b64;
|
||||
struct {
|
||||
uint32_t lo;
|
||||
uint32_t hi;
|
||||
} b32;
|
||||
} Seed;
|
||||
|
||||
typedef struct {
|
||||
Ref ref;
|
||||
Seed seed;
|
||||
Seed state;
|
||||
double lastRandomNormal;
|
||||
} RandomGenerator;
|
||||
|
||||
RandomGenerator* lovrRandomGeneratorCreate();
|
||||
void lovrRandomGeneratorDestroy(const Ref* ref);
|
||||
Seed lovrRandomGeneratorGetSeed(RandomGenerator* generator);
|
||||
void lovrRandomGeneratorSetSeed(RandomGenerator* generator, Seed seed);
|
||||
void lovrRandomGeneratorGetState(RandomGenerator* generator, char* state, size_t length);
|
||||
int lovrRandomGeneratorSetState(RandomGenerator* generator, const char* state, size_t length);
|
||||
double lovrRandomGeneratorRandom(RandomGenerator* generator);
|
||||
double lovrRandomGeneratorRandomNormal(RandomGenerator* generator);
|
Loading…
Reference in New Issue