RandomGenerator;

This commit is contained in:
bjorn 2017-07-26 22:02:17 -07:00
parent 39ba6d3f12
commit 8b34330079
5 changed files with 234 additions and 0 deletions

View File

@ -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);

View File

@ -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 }

View File

@ -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 }
};

View File

@ -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);
}

View File

@ -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);