worldgen: add Perlin noise test
This commit is contained in:
parent
fa68e83260
commit
252ff19f2a
|
@ -21,7 +21,7 @@ fxconv_declare_converters(converters.py)
|
|||
|
||||
add_executable(addin ${SOURCES} ${ASSETS})
|
||||
target_compile_options(addin PRIVATE -Wall -Wextra -Wno-narrowing -Os -std=c++20)
|
||||
target_link_libraries(addin LibProf::LibProf Gint::Gint -lsupc++)
|
||||
target_link_libraries(addin LibProf::LibProf Gint::Gint -lnum -lsupc++)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
message(FATAL_ERROR "This game is not supported on fx-9860G!")
|
||||
|
|
104
src/main.cpp
104
src/main.cpp
|
@ -1,3 +1,4 @@
|
|||
#include <num/num.h>
|
||||
#include "render.h"
|
||||
#include "world.h"
|
||||
#include "graphics.h"
|
||||
|
@ -33,16 +34,115 @@ static void renderGame(Camera *camera)
|
|||
renderText(2, hudY+3, "1 2 3 4 5 6 7 8 9");
|
||||
}
|
||||
|
||||
// --== Perlin noise ==--
|
||||
|
||||
#include <math.h>
|
||||
using namespace libnum;
|
||||
//using num = float;
|
||||
|
||||
struct vec2 {
|
||||
num x, y;
|
||||
};
|
||||
static vec2 perlinGradients[16];
|
||||
|
||||
GCONSTRUCTOR
|
||||
static void precomputeGradients(void)
|
||||
{
|
||||
for(int i = 0; i < 16; i++) {
|
||||
float alpha = 2 * 3.14159 * i / 16;
|
||||
perlinGradients[i].x = num(cosf(alpha));
|
||||
perlinGradients[i].y = num(sinf(alpha));
|
||||
}
|
||||
}
|
||||
|
||||
static num smooth(num t)
|
||||
{
|
||||
return t * t * t * (t * (6 * t - num(15)) + num(10));
|
||||
}
|
||||
|
||||
static num lerp(num x, num y, num t)
|
||||
{
|
||||
return x + t * (y - x);
|
||||
}
|
||||
|
||||
static num dot(vec2 *grid, int GRID_N, int ix, int iy, num fx, num fy)
|
||||
{
|
||||
vec2 g = grid[iy * GRID_N + ix];
|
||||
return (fx - num(ix)) * g.x + (fy - num(iy)) * g.y;
|
||||
}
|
||||
|
||||
static uint8_t *perlinNoise(int N, int PERLIN_CELL_SIZE)
|
||||
{
|
||||
uint8_t *noise = new uint8_t[N * N];
|
||||
if(!noise)
|
||||
return nullptr;
|
||||
|
||||
int GRID_N = (N / PERLIN_CELL_SIZE) + 1;
|
||||
vec2 *grid = new vec2[GRID_N * GRID_N];
|
||||
if(!grid) {
|
||||
delete[] noise;
|
||||
return nullptr;
|
||||
}
|
||||
for(int i = 0; i < GRID_N * GRID_N; i++)
|
||||
grid[i] = perlinGradients[rand() % 16];
|
||||
|
||||
for(int y = 0; y < N; y++)
|
||||
for(int x = 0; x < N; x++) {
|
||||
num fx = num(x) / PERLIN_CELL_SIZE;
|
||||
num fy = num(y) / PERLIN_CELL_SIZE;
|
||||
|
||||
int ix = (int)fx;
|
||||
int iy = (int)fy;
|
||||
|
||||
num d0 = dot(grid, GRID_N, ix, iy, fx, fy);
|
||||
num d1 = dot(grid, GRID_N, ix+1, iy, fx, fy);
|
||||
|
||||
num d2 = dot(grid, GRID_N, ix, iy+1, fx, fy);
|
||||
num d3 = dot(grid, GRID_N, ix+1, iy+1, fx, fy);
|
||||
|
||||
num rx = smooth(fx - num(ix));
|
||||
num ry = smooth(fy - num(iy));
|
||||
|
||||
num v = lerp(lerp(d0, d1, rx), lerp(d2, d3, rx), ry);
|
||||
noise[y * N + x] = 128 + (int)(v * num(127));
|
||||
}
|
||||
|
||||
delete[] grid;
|
||||
return noise;
|
||||
}
|
||||
|
||||
#include <gint/display.h>
|
||||
void perlinTest(void)
|
||||
{
|
||||
uint8_t *noise;
|
||||
int time = prof_exec({ noise = perlinNoise(128, 16); });
|
||||
dclear(C_RED);
|
||||
|
||||
if(noise)
|
||||
for(int y = 0; y < 128; y++)
|
||||
for(int x = 0; x < 128; x++) {
|
||||
int gray = noise[y * 128 + x] >> 3;
|
||||
dpixel(x, y, C_RGB(gray, gray, gray));
|
||||
}
|
||||
dprint(2, DHEIGHT-20, C_WHITE, "time = %d ms", time / 1000);
|
||||
|
||||
dupdate();
|
||||
getkey();
|
||||
}
|
||||
|
||||
// -
|
||||
|
||||
int main(void)
|
||||
{
|
||||
prof_init();
|
||||
srand(0xc0ffee);
|
||||
|
||||
perlinTest();
|
||||
|
||||
World *world = Nooncraft::mkWorld(128, 128);
|
||||
if(!world)
|
||||
return 0;
|
||||
|
||||
srand(0xc0ffee);
|
||||
|
||||
renderClear();
|
||||
renderText(0, 0, "GENERATING WORLD...");
|
||||
renderUpdate();
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
from PIL import Image
|
||||
import random
|
||||
import math
|
||||
|
||||
WIDTH = 128
|
||||
HEIGHT = 128
|
||||
|
||||
BIOMES = 16
|
||||
PERLIN_CELL_SIZE = 8
|
||||
PERLIN_CELL_SIZE = 32
|
||||
|
||||
# Voronoi diagram by jump flooding
|
||||
def voronoi(seeds):
|
||||
|
@ -38,7 +39,7 @@ def voronoi(seeds):
|
|||
|
||||
return world
|
||||
|
||||
# Generate a biome center map but avoid the Voronoi algorithm
|
||||
# --== Generate a biome center map with the jump-flood algorithm ==--
|
||||
|
||||
def random_color():
|
||||
r = random.randint(0, 256)
|
||||
|
@ -64,4 +65,59 @@ def show_biomes(biomes):
|
|||
|
||||
img.show()
|
||||
|
||||
show_biomes(biomes)
|
||||
# show_biomes(biomes)
|
||||
|
||||
# --== Generate some Perlin noise ==--
|
||||
|
||||
pregradients = []
|
||||
for i in range(16):
|
||||
alpha = 2 * math.pi * i / 16
|
||||
pregradients.append((math.cos(alpha), math.sin(alpha)))
|
||||
|
||||
def random_grid(N):
|
||||
N = WIDTH // PERLIN_CELL_SIZE + 1
|
||||
return [[random.choice(pregradients) for x in range(N)] for y in range(N)]
|
||||
|
||||
def smooth(t):
|
||||
return t * t * t * (t * (6 * t - 15) + 10)
|
||||
|
||||
def interp(x, y, t):
|
||||
return y * t + x * (1.0 - t)
|
||||
|
||||
def dot(grid, ix, iy, fx, fy):
|
||||
gx, gy = grid[iy][ix]
|
||||
return (fx - ix) * gx + (fy - iy) * gy
|
||||
|
||||
def perlin_at(grid, fx, fy):
|
||||
ix = int(fx)
|
||||
iy = int(fy)
|
||||
|
||||
d0 = dot(grid, ix, iy, fx, fy)
|
||||
d1 = dot(grid, ix+1, iy, fx, fy)
|
||||
|
||||
d2 = dot(grid, ix, iy+1, fx, fy)
|
||||
d3 = dot(grid, ix+1, iy+1, fx, fy)
|
||||
|
||||
rx = smooth(fx - ix)
|
||||
ry = smooth(fy - iy)
|
||||
|
||||
return interp(interp(d0, d1, rx), interp(d2, d3, rx), ry)
|
||||
|
||||
PERLIN_N = WIDTH // PERLIN_CELL_SIZE
|
||||
grid = random_grid(PERLIN_N)
|
||||
|
||||
def show_perlin(grid):
|
||||
img = Image.new("RGBA", (WIDTH, HEIGHT))
|
||||
px = img.load()
|
||||
|
||||
for y in range(HEIGHT):
|
||||
for x in range(WIDTH):
|
||||
fx, fy = x / PERLIN_CELL_SIZE, y / PERLIN_CELL_SIZE
|
||||
noise = perlin_at(grid, fx, fy)
|
||||
|
||||
gray = 128 + round(noise * 128)
|
||||
px[x, y] = (gray, gray, gray)
|
||||
|
||||
img.show()
|
||||
|
||||
show_perlin(grid)
|
||||
|
|
Loading…
Reference in New Issue