mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
Improve random
This commit is contained in:
parent
fb87883b54
commit
3d96a0ebdb
|
|
@ -9,7 +9,7 @@
|
||||||
class PerlinNoise_SPU//: public Synth
|
class PerlinNoise_SPU//: public Synth
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static const int MAX_NOISE_LEVELS = 16;
|
static const int MAX_NOISE_LEVELS = 256;
|
||||||
|
|
||||||
ImprovedNoise_SPU noiseLevels[MAX_NOISE_LEVELS];
|
ImprovedNoise_SPU noiseLevels[MAX_NOISE_LEVELS];
|
||||||
int levels;
|
int levels;
|
||||||
|
|
|
||||||
|
|
@ -1,82 +1,90 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ImprovedNoise.h"
|
#include "ImprovedNoise.h"
|
||||||
|
#include "Random.h" // íàø óëó÷øåííûé Random
|
||||||
|
#include <cmath> // äëÿ floor, åñëè íóæíî, íî èñïîëüçóåì static_cast
|
||||||
|
|
||||||
ImprovedNoise::ImprovedNoise()
|
ImprovedNoise::ImprovedNoise()
|
||||||
{
|
{
|
||||||
Random random;
|
Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
|
||||||
init(&random);
|
init(&random);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImprovedNoise::ImprovedNoise(Random *random)
|
ImprovedNoise::ImprovedNoise(Random* random)
|
||||||
{
|
{
|
||||||
init(random);
|
init(random);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImprovedNoise::init(Random *random)
|
void ImprovedNoise::init(Random* random)
|
||||||
{
|
{
|
||||||
p = new int[512];
|
// Ñëó÷àéíûå ñìåùåíèÿ äëÿ êàæäîé êîîðäèíàòû (óáèðàþò ñèììåòðèþ)
|
||||||
|
xo = random->nextDouble() * 256.0;
|
||||||
|
yo = random->nextDouble() * 256.0;
|
||||||
|
zo = random->nextDouble() * 256.0;
|
||||||
|
|
||||||
xo = random->nextDouble() * 256;
|
// Çàïîëíÿåì permutation table ÷èñëàìè 0..255 â ñëó÷àéíîì ïîðÿäêå
|
||||||
yo = random->nextDouble() * 256;
|
for (int i = 0; i < 256; ++i)
|
||||||
zo = random->nextDouble() * 256;
|
|
||||||
for (int i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
p[i] = i;
|
p[i] = i;
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
int j = random->nextInt(256 - i) + i;
|
int j = random->nextInt(256 - i) + i; // ñëó÷àéíàÿ ïåðåñòàíîâêà
|
||||||
int tmp = p[i];
|
int tmp = p[i];
|
||||||
p[i] = p[j];
|
p[i] = p[j];
|
||||||
p[j] = tmp;
|
p[j] = tmp;
|
||||||
|
|
||||||
p[i + 256] = p[i];
|
p[i + 256] = p[i]; // äóáëèðóåì äëÿ èçáåæàíèÿ ïðîâåðîê ãðàíèö
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImprovedNoise::~ImprovedNoise()
|
// ----------------------------------------------------------------------
|
||||||
|
// Îñíîâíîé ìåòîä âû÷èñëåíèÿ 3D øóìà Ïåðëèíà
|
||||||
|
double ImprovedNoise::noise(double x, double y, double z) const
|
||||||
{
|
{
|
||||||
delete [] p;
|
// Äîáàâëÿåì óíèêàëüíîå ñìåùåíèå äëÿ ýòîãî ýêçåìïëÿðà
|
||||||
}
|
x += xo;
|
||||||
|
y += yo;
|
||||||
|
z += zo;
|
||||||
|
|
||||||
double ImprovedNoise::noise(double _x, double _y, double _z)
|
// Öåëàÿ ÷àñòü êîîðäèíàò (îïðåäåëÿåì êóá, ñîäåðæàùèé òî÷êó)
|
||||||
{
|
int X = static_cast<int>(std::floor(x)) & 255;
|
||||||
double x = _x + xo;
|
int Y = static_cast<int>(std::floor(y)) & 255;
|
||||||
double y = _y + yo;
|
int Z = static_cast<int>(std::floor(z)) & 255;
|
||||||
double z = _z + zo;
|
|
||||||
|
|
||||||
int xf = static_cast<int>(x);
|
// Îòíîñèòåëüíûå êîîðäèíàòû âíóòðè êóáà [0,1)
|
||||||
int yf = static_cast<int>(y);
|
x -= std::floor(x);
|
||||||
int zf = static_cast<int>(z);
|
y -= std::floor(y);
|
||||||
|
z -= std::floor(z);
|
||||||
|
|
||||||
if (x < xf) xf--;
|
// Ïëàâíàÿ êðèâàÿ (fade function): 6t^5 - 15t^4 + 10t^3
|
||||||
if (y < yf) yf--;
|
double u = x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
|
||||||
if (z < zf) zf--;
|
double v = y * y * y * (y * (y * 6.0 - 15.0) + 10.0);
|
||||||
|
double w = z * z * z * (z * (z * 6.0 - 15.0) + 10.0);
|
||||||
|
|
||||||
int X = xf & 255, // FIND UNIT CUBE THAT
|
// Õåøè èíäåêñîâ âîñüìè óãëîâ êóáà
|
||||||
Y = yf & 255, // CONTAINS POINT.
|
int A = p[X] + Y;
|
||||||
Z = zf & 255;
|
int AA = p[A] + Z;
|
||||||
|
int AB = p[A + 1] + Z;
|
||||||
|
int B = p[X + 1] + Y;
|
||||||
|
int BA = p[B] + Z;
|
||||||
|
int BB = p[B + 1] + Z;
|
||||||
|
|
||||||
x -= xf; // FIND RELATIVE X,Y,Z
|
// Èíòåðïîëÿöèÿ
|
||||||
y -= yf; // OF POINT IN CUBE.
|
double y1 = lerp(u,
|
||||||
z -= zf;
|
grad(p[AA], x, y, z),
|
||||||
|
grad(p[BA], x - 1, y, z));
|
||||||
double u = x * x * x * (x * (x * 6 - 15) + 10), // COMPUTE FADE CURVES
|
double y2 = lerp(u,
|
||||||
v = y * y * y * (y * (y * 6 - 15) + 10), // FOR EACH OF X,Y,Z.
|
grad(p[AB], x, y - 1, z),
|
||||||
w = z * z * z * (z * (z * 6 - 15) + 10);
|
grad(p[BB], x - 1, y - 1, z));
|
||||||
|
double y3 = lerp(u,
|
||||||
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF
|
grad(p[AA + 1], x, y, z - 1),
|
||||||
B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS,
|
grad(p[BA + 1], x - 1, y, z - 1));
|
||||||
|
double y4 = lerp(u,
|
||||||
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD
|
grad(p[AB + 1], x, y - 1, z - 1),
|
||||||
grad(p[BA], x - 1, y, z)), // BLENDED
|
grad(p[BB + 1], x - 1, y - 1, z - 1));
|
||||||
lerp(u, grad(p[AB], x, y - 1, z), // RESULTS
|
|
||||||
grad(p[BB], x - 1, y - 1, z))),// FROM 8
|
|
||||||
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS
|
|
||||||
grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE
|
|
||||||
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
|
|
||||||
|
|
||||||
|
double z1 = lerp(v, y1, y2);
|
||||||
|
double z2 = lerp(v, y3, y4);
|
||||||
|
return lerp(w, z1, z2);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ImprovedNoise::lerp(double t, double a, double b)
|
double ImprovedNoise::lerp(double t, double a, double b)
|
||||||
|
|
@ -84,29 +92,28 @@ double ImprovedNoise::lerp(double t, double a, double b)
|
||||||
return a + t * (b - a);
|
return a + t * (b - a);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ImprovedNoise::grad2(int hash, double x, double z)
|
// 3D ãðàäèåíò (èñïîëüçóåòñÿ â noise)
|
||||||
{
|
|
||||||
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
|
|
||||||
|
|
||||||
double u = (1-((h&8)>>3))*x, // INTO 12 GRADIENT DIRECTIONS.
|
|
||||||
v = h < 4 ? 0 : h == 12 || h == 14 ? x : z;
|
|
||||||
|
|
||||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
|
||||||
}
|
|
||||||
|
|
||||||
double ImprovedNoise::grad(int hash, double x, double y, double z)
|
double ImprovedNoise::grad(int hash, double x, double y, double z)
|
||||||
{
|
{
|
||||||
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
|
int h = hash & 15; // ìëàäøèå 4 áèòà
|
||||||
|
double u = h < 8 ? x : y;
|
||||||
double u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
|
double v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
|
||||||
v = h < 4 ? y : h == 12 || h == 14 ? x : z;
|
|
||||||
|
|
||||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2D ãðàäèåíò (èñïîëüçóåòñÿ â add() äëÿ ñëó÷àÿ ySize==1)
|
||||||
|
double ImprovedNoise::grad2(int hash, double x, double z)
|
||||||
|
{
|
||||||
|
int h = hash & 15;
|
||||||
|
double u = (h & 8) ? x : z; // àëüòåðíàòèâíîå ðàñïðåäåëåíèå äëÿ 2D
|
||||||
|
double v = (h < 4) ? 0 : (h == 12 || h == 14 ? x : z);
|
||||||
|
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synth èíòåðôåéñ
|
||||||
double ImprovedNoise::getValue(double x, double y)
|
double ImprovedNoise::getValue(double x, double y)
|
||||||
{
|
{
|
||||||
return noise(x, y, 0);
|
return noise(x, y, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ImprovedNoise::getValue(double x, double y, double z)
|
double ImprovedNoise::getValue(double x, double y, double z)
|
||||||
|
|
@ -114,102 +121,98 @@ double ImprovedNoise::getValue(double x, double y, double z)
|
||||||
return noise(x, y, z);
|
return noise(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImprovedNoise::add(doubleArray buffer, double _x, double _y, double _z, int xSize, int ySize, int zSize, double xs, double ys, double zs, double pow)
|
// ----------------------------------------------------------------------
|
||||||
|
// Ìåòîä add – áûñòðîå çàïîëíåíèå áóôåðà çíà÷åíèÿìè øóìà äëÿ ïðÿìîóãîëüíîé îáëàñòè
|
||||||
|
// (îïòèìèçèðîâàí, ÷òîáû èçáåæàòü ïîâòîðíûõ âû÷èñëåíèé ãðàäèåíòîâ)
|
||||||
|
void ImprovedNoise::add(doubleArray buffer, double _x, double _y, double _z,
|
||||||
|
int xSize, int ySize, int zSize,
|
||||||
|
double xs, double ys, double zs, double pow) const
|
||||||
{
|
{
|
||||||
if (ySize==1)
|
double invPow = 1.0 / pow;
|
||||||
|
int idx = 0; // èíäåêñ â áóôåðå
|
||||||
|
|
||||||
|
if (ySize == 1)
|
||||||
{
|
{
|
||||||
int A = 0, AA = 0, B = 0, BA = 0;
|
// Îïòèìèçàöèÿ äëÿ 2D ñðåçà (y ôèêñèðîâàí)
|
||||||
double vv0 = 0, vv2 = 0;
|
for (int xx = 0; xx < xSize; ++xx)
|
||||||
int pp = 0;
|
|
||||||
double scale = 1.0 / pow;
|
|
||||||
for (int xx = 0; xx < xSize; xx++)
|
|
||||||
{
|
{
|
||||||
double x = _x + (xx) * xs + xo;
|
double x = _x + xx * xs + xo;
|
||||||
int xf = static_cast<int>(x);
|
int X = static_cast<int>(std::floor(x)) & 255;
|
||||||
if (x < xf) xf--;
|
double dx = x - std::floor(x);
|
||||||
int X = xf & 255;
|
double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
|
||||||
x -= xf;
|
|
||||||
double u = x * x * x * (x * (x * 6 - 15) + 10);
|
|
||||||
|
|
||||||
for (int zz = 0; zz < zSize; zz++)
|
for (int zz = 0; zz < zSize; ++zz)
|
||||||
{
|
{
|
||||||
double z = _z + (zz) * zs + zo;
|
double z = _z + zz * zs + zo;
|
||||||
int zf = static_cast<int>(z);
|
int Z = static_cast<int>(std::floor(z)) & 255;
|
||||||
if (z < zf) zf--;
|
double dz = z - std::floor(z);
|
||||||
int Z = zf & 255;
|
double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
|
||||||
z -= zf;
|
|
||||||
double w = z * z * z * (z * (z * 6 - 15) + 10);
|
|
||||||
|
|
||||||
A = p[X] + 0;
|
int A = p[X];
|
||||||
AA = p[A] + Z;
|
int AA = p[A] + Z;
|
||||||
B = p[X + 1] + 0;
|
int B = p[X + 1];
|
||||||
BA = p[B] + Z;
|
int BA = p[B] + Z;
|
||||||
vv0 = lerp(u, grad2(p[AA], x, z), grad(p[BA], x - 1, 0, z));
|
|
||||||
vv2 = lerp(u, grad(p[AA + 1], x, 0, z - 1), grad(p[BA + 1], x - 1, 0, z - 1));
|
|
||||||
|
|
||||||
double val = lerp(w, vv0, vv2);
|
double v0 = lerp(u,
|
||||||
|
grad2(p[AA], dx, dz),
|
||||||
|
grad2(p[BA], dx - 1.0, dz));
|
||||||
|
double v2 = lerp(u,
|
||||||
|
grad2(p[AA + 1], dx, dz - 1.0),
|
||||||
|
grad2(p[BA + 1], dx - 1.0, dz - 1.0));
|
||||||
|
|
||||||
buffer[pp++] += val * scale;
|
buffer[idx++] += lerp(w, v0, v2) * invPow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
int pp = 0;
|
else
|
||||||
double scale = 1 / pow;
|
|
||||||
int yOld = -1;
|
|
||||||
int A = 0, AA = 0, AB = 0, B = 0, BA = 0, BB = 0;
|
|
||||||
double vv0 = 0, vv1 = 0, vv2 = 0, vv3 = 0;
|
|
||||||
|
|
||||||
for (int xx = 0; xx < xSize; xx++)
|
|
||||||
{
|
{
|
||||||
double x = _x + (xx) * xs + xo;
|
// Ïîëíàÿ 3D âåðñèÿ ñ êýøèðîâàíèåì ïî Y
|
||||||
int xf = static_cast<int>(x);
|
int yPrev = -1;
|
||||||
if (x < xf) xf--;
|
int A, AA, AB, B, BA, BB;
|
||||||
int X = xf & 255;
|
double vv0, vv1, vv2, vv3;
|
||||||
x -= xf;
|
|
||||||
double u = x * x * x * (x * (x * 6 - 15) + 10);
|
|
||||||
|
|
||||||
|
for (int xx = 0; xx < xSize; ++xx)
|
||||||
for (int zz = 0; zz < zSize; zz++)
|
|
||||||
{
|
{
|
||||||
double z = _z + (zz) * zs + zo;
|
double x = _x + xx * xs + xo;
|
||||||
int zf = static_cast<int>(z);
|
int X = static_cast<int>(std::floor(x)) & 255;
|
||||||
if (z < zf) zf--;
|
double dx = x - std::floor(x);
|
||||||
int Z = zf & 255;
|
double u = dx * dx * dx * (dx * (dx * 6.0 - 15.0) + 10.0);
|
||||||
z -= zf;
|
|
||||||
double w = z * z * z * (z * (z * 6 - 15) + 10);
|
|
||||||
|
|
||||||
|
for (int zz = 0; zz < zSize; ++zz)
|
||||||
for (int yy = 0; yy < ySize; yy++)
|
|
||||||
{
|
{
|
||||||
double y = _y + (yy) * ys + yo;
|
double z = _z + zz * zs + zo;
|
||||||
int yf = static_cast<int>(y);
|
int Z = static_cast<int>(std::floor(z)) & 255;
|
||||||
if (y < yf) yf--;
|
double dz = z - std::floor(z);
|
||||||
int Y = yf & 255;
|
double w = dz * dz * dz * (dz * (dz * 6.0 - 15.0) + 10.0);
|
||||||
y -= yf;
|
|
||||||
double v = y * y * y * (y * (y * 6 - 15) + 10);
|
|
||||||
|
|
||||||
if (yy == 0 || Y != yOld)
|
for (int yy = 0; yy < ySize; ++yy)
|
||||||
{
|
{
|
||||||
yOld = Y;
|
double y = _y + yy * ys + yo;
|
||||||
|
int Y = static_cast<int>(std::floor(y)) & 255;
|
||||||
|
double dy = y - std::floor(y);
|
||||||
|
double v = dy * dy * dy * (dy * (dy * 6.0 - 15.0) + 10.0);
|
||||||
|
|
||||||
|
// Êýøèðóåì çíà÷åíèÿ, çàâèñÿùèå òîëüêî îò Y
|
||||||
|
if (yy == 0 || Y != yPrev)
|
||||||
|
{
|
||||||
|
yPrev = Y;
|
||||||
A = p[X] + Y;
|
A = p[X] + Y;
|
||||||
AA = p[A] + Z;
|
AA = p[A] + Z;
|
||||||
AB = p[A + 1] + Z;
|
AB = p[A + 1] + Z;
|
||||||
B = p[X + 1] + Y;
|
B = p[X + 1] + Y;
|
||||||
BA = p[B] + Z;
|
BA = p[B] + Z;
|
||||||
BB = p[B + 1] + Z;
|
BB = p[B + 1] + Z;
|
||||||
vv0 = lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z));
|
|
||||||
vv1 = lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z));
|
|
||||||
vv2 = lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1));
|
|
||||||
vv3 = lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
vv0 = lerp(u, grad(p[AA], dx, dy, dz), grad(p[BA], dx - 1.0, dy, dz));
|
||||||
|
vv1 = lerp(u, grad(p[AB], dx, dy - 1.0, dz), grad(p[BB], dx - 1.0, dy - 1.0, dz));
|
||||||
|
vv2 = lerp(u, grad(p[AA + 1], dx, dy, dz - 1.0), grad(p[BA + 1], dx - 1.0, dy, dz - 1.0));
|
||||||
|
vv3 = lerp(u, grad(p[AB + 1], dx, dy - 1.0, dz - 1.0), grad(p[BB + 1], dx - 1.0, dy - 1.0, dz - 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
double v0 = lerp(v, vv0, vv1);
|
double v0 = lerp(v, vv0, vv1);
|
||||||
double v1 = lerp(v, vv2, vv3);
|
double v1 = lerp(v, vv2, vv3);
|
||||||
double val = lerp(w, v0, v1);
|
buffer[idx++] += lerp(w, v0, v1) * invPow;
|
||||||
|
}
|
||||||
buffer[pp++] += val * scale;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Synth.h"
|
#include "Synth.h"
|
||||||
|
|
||||||
class ImprovedNoise : public Synth
|
class ImprovedNoise : public Synth
|
||||||
{
|
{
|
||||||
friend class PerlinNoise_SPU;
|
friend class PerlinNoise_SPU;
|
||||||
private:
|
private:
|
||||||
int *p;
|
int p[512]; // permutation table (size 512 for easy indexing)
|
||||||
|
double xo, yo, zo; // random offsets for each instance
|
||||||
|
|
||||||
public:
|
public:
|
||||||
double scale;
|
|
||||||
double xo, yo, zo;
|
|
||||||
|
|
||||||
ImprovedNoise();
|
ImprovedNoise();
|
||||||
ImprovedNoise(Random *random);
|
explicit ImprovedNoise(Random* random);
|
||||||
void init(Random *random);
|
void init(Random* random);
|
||||||
|
|
||||||
~ImprovedNoise();
|
double noise(double x, double y, double z) const;
|
||||||
|
static double lerp(double t, double a, double b);
|
||||||
|
static double grad(int hash, double x, double y, double z);
|
||||||
|
static double grad2(int hash, double x, double z); // 2‑D gradient (used in add() for ySize==1)
|
||||||
|
|
||||||
double noise(double _x, double _y, double _z);
|
// Synth interface
|
||||||
|
double getValue(double x, double y) override; // 2D noise (z = 0)
|
||||||
|
double getValue(double x, double y, double z); // 3D noise
|
||||||
|
|
||||||
double lerp(double t, double a, double b);
|
void add(doubleArray buffer, double _x, double _y, double _z,
|
||||||
double grad2(int hash, double x, double z);
|
int xSize, int ySize, int zSize,
|
||||||
double grad(int hash, double x, double y, double z);
|
double xs, double ys, double zs, double pow) const;
|
||||||
virtual double getValue(double x, double y);
|
|
||||||
double getValue(double x, double y, double z);
|
|
||||||
|
|
||||||
void add(doubleArray buffer, double _x, double _y, double _z, int xSize, int ySize, int zSize, double xs, double ys, double zs, double pow);
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,25 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "PerlinNoise.h"
|
#include "PerlinNoise.h"
|
||||||
|
#include "Random.h"
|
||||||
#include "Mth.h"
|
#include "Mth.h"
|
||||||
|
|
||||||
PerlinNoise::PerlinNoise(int levels)
|
PerlinNoise::PerlinNoise(int levels)
|
||||||
{
|
{
|
||||||
Random random;
|
Random random; // èñïîëüçóåò íîâûé âûñîêîýíòðîïèéíûé seed
|
||||||
init(&random, levels);
|
init(&random, levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
PerlinNoise::PerlinNoise(Random *random, int levels)
|
PerlinNoise::PerlinNoise(Random* random, int levels)
|
||||||
{
|
{
|
||||||
init(random, levels);
|
init(random, levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PerlinNoise::init(Random *random, int levels)
|
void PerlinNoise::init(Random* random, int levels)
|
||||||
{
|
{
|
||||||
MemSect(2);
|
MemSect(2);
|
||||||
this->levels = levels;
|
this->levels = levels;
|
||||||
noiseLevels = new ImprovedNoise *[levels];
|
noiseLevels = new ImprovedNoise * [levels];
|
||||||
for (int i = 0; i < levels; i++)
|
for (int i = 0; i < levels; ++i)
|
||||||
{
|
{
|
||||||
noiseLevels[i] = new ImprovedNoise(random);
|
noiseLevels[i] = new ImprovedNoise(random);
|
||||||
}
|
}
|
||||||
|
|
@ -27,72 +28,71 @@ void PerlinNoise::init(Random *random, int levels)
|
||||||
|
|
||||||
PerlinNoise::~PerlinNoise()
|
PerlinNoise::~PerlinNoise()
|
||||||
{
|
{
|
||||||
for( int i = 0; i < levels; i++ )
|
for (int i = 0; i < levels; ++i)
|
||||||
{
|
|
||||||
delete noiseLevels[i];
|
delete noiseLevels[i];
|
||||||
}
|
delete[] noiseLevels;
|
||||||
delete [] noiseLevels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double PerlinNoise::getValue(double x, double y)
|
double PerlinNoise::getValue(double x, double y)
|
||||||
{
|
{
|
||||||
double value = 0;
|
double value = 0.0;
|
||||||
double pow = 1;
|
double amp = 1.0; // àìïëèòóäà (çäåñü 1/pow â îðèãèíàëå)
|
||||||
|
for (int i = 0; i < levels; ++i)
|
||||||
for (int i = 0; i < levels; i++)
|
|
||||||
{
|
{
|
||||||
value += noiseLevels[i]->getValue(x * pow, y * pow) / pow;
|
value += noiseLevels[i]->getValue(x * amp, y * amp) / amp;
|
||||||
pow /= 2;
|
amp *= 0.5; // óìåíüøàåì ÷àñòîòó (pow /= 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double PerlinNoise::getValue(double x, double y, double z)
|
double PerlinNoise::getValue(double x, double y, double z)
|
||||||
{
|
{
|
||||||
double value = 0;
|
double value = 0.0;
|
||||||
double pow = 1;
|
double amp = 1.0;
|
||||||
|
for (int i = 0; i < levels; ++i)
|
||||||
for (int i = 0; i < levels; i++)
|
|
||||||
{
|
{
|
||||||
value += noiseLevels[i]->getValue(x * pow, y * pow, z * pow) / pow;
|
value += noiseLevels[i]->getValue(x * amp, y * amp, z * amp) / amp;
|
||||||
pow /= 2;
|
amp *= 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
doubleArray PerlinNoise::getRegion(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize, double xScale, double yScale, double zScale)
|
doubleArray PerlinNoise::getRegion(doubleArray buffer,
|
||||||
|
int x, int y, int z,
|
||||||
|
int xSize, int ySize, int zSize,
|
||||||
|
double xScale, double yScale, double zScale)
|
||||||
{
|
{
|
||||||
if (buffer.data == nullptr) buffer = doubleArray(xSize * ySize * zSize);
|
// Èíèöèàëèçàöèÿ áóôåðà íóëÿìè, åñëè íåîáõîäèìî
|
||||||
else for (unsigned int i = 0; i < buffer.length; i++)
|
if (buffer.data == nullptr)
|
||||||
buffer[i] = 0;
|
buffer = doubleArray(xSize * ySize * zSize);
|
||||||
|
else
|
||||||
|
for (unsigned int i = 0; i < buffer.length; ++i)
|
||||||
|
buffer[i] = 0.0;
|
||||||
|
|
||||||
|
double freq = 1.0; // ÷àñòîòà (pow)
|
||||||
double pow = 1;
|
for (int i = 0; i < levels; ++i)
|
||||||
|
|
||||||
for (int i = 0; i < levels; i++)
|
|
||||||
{
|
{
|
||||||
// value += noiseLevels[i].getValue(x * pow, y * pow, z * pow) / pow;
|
// Âûçîâ add äëÿ òåêóùåãî óðîâíÿ ñ ïðàâèëüíûì ìàñøòàáèðîâàíèåì
|
||||||
double xx = x * pow * xScale;
|
noiseLevels[i]->add(buffer,
|
||||||
double yy = y * pow * yScale;
|
x * freq * xScale,
|
||||||
double zz = z * pow * zScale;
|
y * freq * yScale,
|
||||||
int64_t xb = Mth::lfloor(xx);
|
z * freq * zScale,
|
||||||
int64_t zb = Mth::lfloor(zz);
|
xSize, ySize, zSize,
|
||||||
xx -= xb;
|
xScale * freq,
|
||||||
zz -= zb;
|
yScale * freq,
|
||||||
xb %= 16777216;
|
zScale * freq,
|
||||||
zb %= 16777216;
|
freq);
|
||||||
xx += xb;
|
freq *= 0.5;
|
||||||
zz += zb;
|
|
||||||
noiseLevels[i]->add(buffer, xx, yy, zz, xSize, ySize, zSize, xScale * pow, yScale * pow, zScale * pow, pow);
|
|
||||||
pow /= 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
doubleArray PerlinNoise::getRegion(doubleArray sr, int x, int z, int xSize, int zSize, double xScale, double zScale, double pow)
|
// Ïåðåãðóçêà äëÿ 2D ðåãèîíà (y ôèêñèðîâàí)
|
||||||
|
doubleArray PerlinNoise::getRegion(doubleArray sr, int x, int z,
|
||||||
|
int xSize, int zSize,
|
||||||
|
double xScale, double zScale, double pow)
|
||||||
{
|
{
|
||||||
return getRegion(sr, x, 10, z, xSize, 1, zSize, xScale, 1, zScale);
|
// Èñïîëüçóåì y = 10 (êàê â îðèãèíàëå), ySize = 1
|
||||||
|
return getRegion(sr, x, 10, z, xSize, 1, zSize, xScale, 1.0, zScale);
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,193 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Random.h"
|
#include "Random.h"
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
|
|
||||||
|
#ifndef USE_LEGACY_RANDOM
|
||||||
|
// Windows API for high-resolution counters and system info
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// C++11 random library and chrono for high-quality seeding
|
||||||
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// Use a 64-bit Mersenne Twister engine
|
||||||
|
static std::mt19937_64& getEngine() {
|
||||||
|
// Make the engine thread-local to avoid data races in multi-threaded code
|
||||||
|
thread_local std::mt19937_64 engine(std::random_device{}());
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Seed generation: combine multiple entropy sources
|
||||||
|
static int64_t generateEntropySeed()
|
||||||
|
{
|
||||||
|
uint64_t entropy = 0;
|
||||||
|
|
||||||
|
// 1. High-resolution performance counter (similar to original)
|
||||||
|
LARGE_INTEGER perfCount;
|
||||||
|
QueryPerformanceCounter(&perfCount);
|
||||||
|
entropy ^= perfCount.QuadPart;
|
||||||
|
|
||||||
|
// 2. System tick count (milliseconds since boot)
|
||||||
|
entropy ^= GetTickCount64();
|
||||||
|
|
||||||
|
// 3. Process and thread IDs
|
||||||
|
entropy ^= static_cast<uint64_t>(GetCurrentProcessId()) << 32;
|
||||||
|
entropy ^= static_cast<uint64_t>(GetCurrentThreadId()) << 16;
|
||||||
|
|
||||||
|
// 4. High-resolution clock with nanoseconds (C++11)
|
||||||
|
auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(now)
|
||||||
|
.time_since_epoch().count();
|
||||||
|
entropy ^= static_cast<uint64_t>(ns);
|
||||||
|
|
||||||
|
// 5. Hardware randomness if available (via random_device)
|
||||||
|
// Note: on some compilers random_device may be deterministic,
|
||||||
|
// but it's a good additional source.
|
||||||
|
try {
|
||||||
|
std::random_device rd;
|
||||||
|
entropy ^= static_cast<uint64_t>(rd()) |
|
||||||
|
(static_cast<uint64_t>(rd()) << 32);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// random_device not available – just ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Address of a stack variable (ASLR provides some randomness)
|
||||||
|
volatile void* stackAddr = &entropy;
|
||||||
|
entropy ^= reinterpret_cast<uintptr_t>(stackAddr);
|
||||||
|
|
||||||
|
// Mix the bits well to avoid correlation
|
||||||
|
// (using a simple but effective hash)
|
||||||
|
entropy ^= entropy >> 33;
|
||||||
|
entropy *= 0xff51afd7ed558ccdULL;
|
||||||
|
entropy ^= entropy >> 33;
|
||||||
|
entropy *= 0xc4ceb9fe1a85ec53ULL;
|
||||||
|
entropy ^= entropy >> 33;
|
||||||
|
|
||||||
|
return static_cast<int64_t>(entropy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Random class implementation
|
||||||
|
|
||||||
|
Random::Random()
|
||||||
|
{
|
||||||
|
// Use the high‑entropy seed generator
|
||||||
|
setSeed(generateEntropySeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
Random::Random(int64_t seed)
|
||||||
|
{
|
||||||
|
setSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::setSeed(int64_t s)
|
||||||
|
{
|
||||||
|
// Store seed for possible inspection
|
||||||
|
seed = s;
|
||||||
|
|
||||||
|
// Seed the Mersenne Twister engine
|
||||||
|
getEngine().seed(static_cast<uint64_t>(s));
|
||||||
|
|
||||||
|
// Reset Gaussian cache
|
||||||
|
haveNextNextGaussian = false;
|
||||||
|
nextNextGaussian = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Core bit generator – replaces the old LCG
|
||||||
|
int Random::next(int bits)
|
||||||
|
{
|
||||||
|
// mt19937_64 produces 64 random bits each call
|
||||||
|
uint64_t raw = getEngine()();
|
||||||
|
|
||||||
|
// Return the required number of most significant bits
|
||||||
|
// (shifting right keeps the higher bits which are usually "more random")
|
||||||
|
return static_cast<int>(raw >> (64 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// All other methods stay exactly as in the original code,
|
||||||
|
// because they all rely on next(bits).
|
||||||
|
|
||||||
|
void Random::nextBytes(byte* bytes, unsigned int count)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
bytes[i] = static_cast<byte>(next(8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double Random::nextDouble()
|
||||||
|
{
|
||||||
|
return ((static_cast<int64_t>(next(26)) << 27) + next(27))
|
||||||
|
/ static_cast<double>(1LL << 53);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Random::nextGaussian()
|
||||||
|
{
|
||||||
|
if (haveNextNextGaussian)
|
||||||
|
{
|
||||||
|
haveNextNextGaussian = false;
|
||||||
|
return nextNextGaussian;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double v1, v2, s;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0
|
||||||
|
v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0
|
||||||
|
s = v1 * v1 + v2 * v2;
|
||||||
|
} while (s >= 1 || s == 0);
|
||||||
|
double multiplier = sqrt(-2 * log(s) / s);
|
||||||
|
nextNextGaussian = v2 * multiplier;
|
||||||
|
haveNextNextGaussian = true;
|
||||||
|
return v1 * multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt()
|
||||||
|
{
|
||||||
|
return next(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt(int n)
|
||||||
|
{
|
||||||
|
// Parameter check (you may replace assert with a thrown exception)
|
||||||
|
// assert(n > 0);
|
||||||
|
if (n <= 0) return 0; // or throw std::invalid_argument("n must be positive");
|
||||||
|
|
||||||
|
// Special case for powers of two (fast path)
|
||||||
|
if ((n & -n) == n)
|
||||||
|
return static_cast<int>((static_cast<int64_t>(next(31)) * n) >> 31);
|
||||||
|
|
||||||
|
int bits, val;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
bits = next(31);
|
||||||
|
val = bits % n;
|
||||||
|
} while (bits - val + (n - 1) < 0);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Random::nextFloat()
|
||||||
|
{
|
||||||
|
return next(24) / static_cast<float>(1 << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Random::nextLong()
|
||||||
|
{
|
||||||
|
return (static_cast<int64_t>(next(32)) << 32) + next(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Random::nextBoolean()
|
||||||
|
{
|
||||||
|
return next(1) != 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
Random::Random()
|
Random::Random()
|
||||||
{
|
{
|
||||||
// 4J - jave now uses the system nanosecond counter added to a "seedUniquifier" to get an initial seed. Our nanosecond timer is actually only millisecond accuate, so
|
// 4J - jave now uses the system nanosecond counter added to a "seedUniquifier" to get an initial seed. Our nanosecond timer is actually only millisecond accuate, so
|
||||||
|
|
@ -104,3 +290,4 @@ bool Random::nextBoolean()
|
||||||
{
|
{
|
||||||
return next(1) != 0;
|
return next(1) != 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,31 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef USE_LEGACY_RANDOM
|
||||||
|
class Random
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int64_t seed; // last seed used (for reference)
|
||||||
|
bool haveNextNextGaussian; // state for nextGaussian()
|
||||||
|
double nextNextGaussian; // cached Gaussian value
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int next(int bits); // generates up to 32 random bits
|
||||||
|
|
||||||
|
public:
|
||||||
|
Random(); // uses a high-entropy seed
|
||||||
|
explicit Random(int64_t seed); // seed with a specific value
|
||||||
|
void setSeed(int64_t s); // re-seed the generator
|
||||||
|
|
||||||
|
void nextBytes(byte* bytes, unsigned int count);
|
||||||
|
double nextDouble();
|
||||||
|
double nextGaussian();
|
||||||
|
int nextInt();
|
||||||
|
int nextInt(int n); // in [0, n)
|
||||||
|
float nextFloat();
|
||||||
|
int64_t nextLong();
|
||||||
|
bool nextBoolean();
|
||||||
|
};
|
||||||
|
#else
|
||||||
class Random
|
class Random
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
@ -21,3 +47,4 @@ public:
|
||||||
int64_t nextLong();
|
int64_t nextLong();
|
||||||
bool nextBoolean();
|
bool nextBoolean();
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue