225 lines
4.4 KiB
C++
225 lines
4.4 KiB
C++
#include <sprstk/sprstk.h>
|
|
|
|
#include <simplexnoise1234.h>
|
|
|
|
#include <cmath>
|
|
|
|
namespace
|
|
{
|
|
|
|
constexpr int SIZE = 512;
|
|
|
|
double octaves(SimplexNoise1234& simplex, double x, double y, int layers, double persistence, double frequency)
|
|
{
|
|
double ampl = 1;
|
|
double maxval = 0;
|
|
double val = 0;
|
|
|
|
for (int i = 0; i < layers; i++)
|
|
{
|
|
val += simplex.noise(x * frequency, y * frequency) * ampl;
|
|
|
|
maxval += ampl;
|
|
|
|
ampl *= persistence;
|
|
frequency *= 2;
|
|
}
|
|
|
|
return val / maxval;
|
|
}
|
|
|
|
uint8_t data[SIZE * SIZE];
|
|
|
|
double split_point = 0.5;
|
|
|
|
double ease_f(double n)
|
|
{
|
|
return pow(n, 0.7);
|
|
}
|
|
|
|
double ease_g(double n)
|
|
{
|
|
return pow(n, 2);
|
|
}
|
|
|
|
double prime(double (*fn)(double), double n)
|
|
{
|
|
constexpr double DELTA = 0.001;
|
|
|
|
return (fn(n + DELTA) - fn(n)) / DELTA;
|
|
}
|
|
|
|
double ease(double n)
|
|
{
|
|
const double fprime = prime(ease_f, n);
|
|
const double gprime = prime(ease_g, n);
|
|
|
|
const double scale = (fprime / gprime) * (ease_g(1) - ease_g(split_point)) + ease_f(split_point);
|
|
|
|
if (n < split_point) { return ease_f(n) / scale; }
|
|
return (fprime / gprime * (ease_g(n) - ease_g(split_point)) + ease_f(split_point)) / scale;
|
|
}
|
|
|
|
uint32_t color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
|
{
|
|
return (r << 0) | (g << 8) | (b << 16) | (a << 24);
|
|
}
|
|
|
|
uint32_t color(double r, double g, double b, double a)
|
|
{
|
|
if (r < 0) { r = 0; }
|
|
if (r > 1) { r = 1; }
|
|
if (g < 0) { g = 0; }
|
|
if (g > 1) { g = 1; }
|
|
if (b < 0) { b = 0; }
|
|
if (b > 1) { b = 1; }
|
|
if (a < 0) { a = 0; }
|
|
if (a > 1) { a = 1; }
|
|
|
|
uint8_t r8 = r * 255.0;
|
|
uint8_t g8 = g * 255.0;
|
|
uint8_t b8 = b * 255.0;
|
|
uint8_t a8 = a * 255.0;
|
|
|
|
return color(r8, g8, b8, a8);
|
|
}
|
|
|
|
constexpr double ALPHA = 0.7;
|
|
|
|
const sprstk_palette* water_palette()
|
|
{
|
|
static sprstk_palette pal;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
pal.colors[i] = color(i / 32.0, i / 16.0, i / 8.0, ALPHA);
|
|
}
|
|
|
|
return &pal;
|
|
}
|
|
|
|
const sprstk_palette* sand_palette()
|
|
{
|
|
static sprstk_palette pal;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
pal.colors[i] = color(i / 20.0 + 0.3, i / 20.0 + 0.2, i / 20.0 + 0.1, ALPHA);
|
|
}
|
|
|
|
return &pal;
|
|
}
|
|
|
|
const sprstk_palette* land_palette()
|
|
{
|
|
static sprstk_palette pal;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
if (i <= 19)
|
|
{
|
|
pal.colors[i] = color(i / 24.0 + 0.1, i / 36.0 + 0.05, i / 48.0, ALPHA);
|
|
}
|
|
else
|
|
{
|
|
pal.colors[i] = color(i / 40.0 - 0.1, i / 40.0 + 0.1, 0.1, ALPHA);
|
|
}
|
|
}
|
|
|
|
return &pal;
|
|
}
|
|
|
|
const sprstk_palette* stone_palette()
|
|
{
|
|
static sprstk_palette pal;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
const double offset = (i < 28 ? -0.2 : 0.2);
|
|
pal.colors[i] = color(i / 35.2 + offset, i / 32.0 + offset, i / 29.0 + offset, ALPHA);
|
|
}
|
|
|
|
return &pal;
|
|
}
|
|
|
|
const sprstk_palette* shadow_palette()
|
|
{
|
|
static sprstk_palette pal;
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
pal.colors[i] = color(0, 0, 0, 0.3);
|
|
}
|
|
|
|
return &pal;
|
|
}
|
|
|
|
int pick_pal(uint8_t height)
|
|
{
|
|
if (height < 8) { return 0; } // water
|
|
if (height < 13) { return 1; } // sand
|
|
if (height < 24) { return 2; } // land
|
|
return 3;
|
|
}
|
|
|
|
void init(sprstk* instance, void* userdata)
|
|
{
|
|
sprstk_set_palette(instance, 0, water_palette());
|
|
sprstk_set_palette(instance, 1, sand_palette());
|
|
sprstk_set_palette(instance, 2, land_palette());
|
|
sprstk_set_palette(instance, 3, stone_palette());
|
|
sprstk_set_palette(instance, 4, shadow_palette());
|
|
|
|
sprstk_set_scale(instance, 0.5);
|
|
|
|
SimplexNoise1234 simplex;
|
|
for (int i = 0; i < SIZE; i++)
|
|
{
|
|
for (int j = 0; j < SIZE; j++)
|
|
{
|
|
double value = octaves(simplex, i, j, 6, 0.4, 1.0 / 128.0);
|
|
data[i + j * SIZE] = 30 * ease((value + 1) / 2) + 1;
|
|
}
|
|
}
|
|
|
|
sprstk_clear(instance);
|
|
for (int i = 0; i < SIZE; i++)
|
|
{
|
|
for (int j = 0; j < SIZE; j++)
|
|
{
|
|
sprstk_tile_info info = {};
|
|
info.position = { i - SIZE / 2, j - SIZE / 2 };
|
|
info.layers = data[i + SIZE * j];
|
|
info.layer_modifiers = { 0, 15 };
|
|
info.palette_index = pick_pal(data[i + SIZE * j]);
|
|
info.layer_order_offset = 1;
|
|
sprstk_put(instance, info);
|
|
|
|
info.palette_index = 4;
|
|
info.layer_modifiers = { 0.5, 15.5 };
|
|
info.layer_order_offset = 0;
|
|
sprstk_put(instance, info);
|
|
}
|
|
}
|
|
}
|
|
|
|
void update(sprstk* instance, float dt, float* userdata)
|
|
{
|
|
*userdata += dt / 2;
|
|
sprstk_set_angle(instance, *userdata);
|
|
}
|
|
|
|
}
|
|
|
|
int main()
|
|
{
|
|
float data = 0;
|
|
sprstk* instance = sprstk_new({.init = init, .update = (sprstk_update_fn)update}, &data);
|
|
|
|
sprstk_run(instance);
|
|
|
|
sprstk_del(instance);
|
|
|
|
return 0;
|
|
}
|