diff --git a/CMakeLists.txt b/CMakeLists.txt index 67f9c0b..1c33f7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ set(TOWNENGINE_SOURCE_FILES src/text.c src/text.h src/camera.c src/camera.h src/textures/textures.c + src/procgen/perlin2d.c ${SYSTEM_SOURCE_FILES} ) diff --git a/apps/testgame/scenes/ingame.c b/apps/testgame/scenes/ingame.c index 022b909..a7000d1 100644 --- a/apps/testgame/scenes/ingame.c +++ b/apps/testgame/scenes/ingame.c @@ -11,7 +11,8 @@ static void ingame_tick(struct state *state) { world_drawdef(scn->world); player_calc(scn->player); - static t_camera cam = { .pos = { 0, 0, 1 }, .target = { 0, 0, -1 }, .up = { 0, 1, 0 }, .fov = (float)M_PI_2 }; + static t_camera cam = { .pos = { 32, 0, 1 }, .up = { 0, 1, 0 }, .fov = (float)M_PI_2 }; + cam.target = m_vec_norm(((t_fvec3){ -1, 0, 1 })); if (input_is_action_pressed(&ctx.input, "player_left")) cam.pos.x -= 0.01f; @@ -42,21 +43,29 @@ static void ingame_tick(struct state *state) { set_camera(&cam); - unfurl_triangle("/assets/big-violet.png", - (t_fvec3){ -1, -1, 0 }, - (t_fvec3){ 1, -1, 0 }, - (t_fvec3){ 1, 1, 0 }, - (t_shvec2){ 0, 2048 }, - (t_shvec2){ 2048, 2048 }, - (t_shvec2){ 2048, 0 }); + for (int y = 64; --y;) + for (int x = 64; --x;) { + float d0 = sample_perlin_2d((t_fvec2){x, y}, 0.2, 5) * 8 - 6; + float d1 = sample_perlin_2d((t_fvec2){x + 1, y}, 0.2, 5) * 8 - 6; + float d2 = sample_perlin_2d((t_fvec2){x + 1, y - 1}, 0.2, 5) * 8 - 6; + float d3 = sample_perlin_2d((t_fvec2){x, y - 1}, 0.2, 5) * 8 - 6; - unfurl_triangle("/assets/big-violet.png", - (t_fvec3){ 1, 1, 0 }, - (t_fvec3){ -1, 1, 0 }, - (t_fvec3){ -1, -1, 0 }, - (t_shvec2){ 2048, 0 }, - (t_shvec2){ 0, 0 }, - (t_shvec2){ 0, 2048 }); + unfurl_triangle("/assets/grass.gif", + (t_fvec3){ x, d0, y }, + (t_fvec3){ x + 1, d1, y }, + (t_fvec3){ x, d3, y - 1 }, + (t_shvec2){ 0, 768 }, + (t_shvec2){ 1024, 768 }, + (t_shvec2){ 1024, 0 }); + + unfurl_triangle("/assets/grass.gif", + (t_fvec3){ x + 1, d1, y }, + (t_fvec3){ x + 1, d2, y - 1 }, + (t_fvec3){ x, d3, y - 1 }, + (t_shvec2){ 1024, 0 }, + (t_shvec2){ 0, 0 }, + (t_shvec2){ 0, 768 }); + } } diff --git a/data/assets/grass.gif b/data/assets/grass.gif new file mode 100644 index 0000000..af9a09f Binary files /dev/null and b/data/assets/grass.gif differ diff --git a/src/game_api.h b/src/game_api.h index 80f6a12..9b4c55d 100644 --- a/src/game_api.h +++ b/src/game_api.h @@ -7,6 +7,7 @@ #include "rendering.h" #include "audio.h" #include "util.h" +#include "procgen.h" /* application provided */ extern void game_tick(void); diff --git a/src/procgen.h b/src/procgen.h new file mode 100644 index 0000000..c5c77d0 --- /dev/null +++ b/src/procgen.h @@ -0,0 +1,6 @@ +#ifndef PROCGEN_H +#define PROCGEN_H + +#include "procgen/perlin.h" + +#endif diff --git a/src/procgen/perlin.h b/src/procgen/perlin.h new file mode 100644 index 0000000..a3cf81e --- /dev/null +++ b/src/procgen/perlin.h @@ -0,0 +1,10 @@ +#ifndef PROCGEN_PERLIN_H +#define PROCGEN_PERLIN_H + +#include "../vec.h" + +void set_perlin_2d_seed(uint32_t seed); + +float sample_perlin_2d(t_fvec2 position, float frequency, uint8_t octaves); + +#endif diff --git a/src/procgen/perlin2d.c b/src/procgen/perlin2d.c new file mode 100644 index 0000000..42c3a99 --- /dev/null +++ b/src/procgen/perlin2d.c @@ -0,0 +1,70 @@ +#include "perlin.h" +#include "../vec.h" + +static uint32_t seed = 0; + +static const uint8_t hash[] = { 208,34,231,213,32,248,233,56,161,78,24,140,71,48,140,254,245,255,247,247,40, + 185,248,251,245,28,124,204,204,76,36,1,107,28,234,163,202,224,245,128,167,204, + 9,92,217,54,239,174,173,102,193,189,190,121,100,108,167,44,43,77,180,204,8,81, + 70,223,11,38,24,254,210,210,177,32,81,195,243,125,8,169,112,32,97,53,195,13, + 203,9,47,104,125,117,114,124,165,203,181,235,193,206,70,180,174,0,167,181,41, + 164,30,116,127,198,245,146,87,224,149,206,57,4,192,210,65,210,129,240,178,105, + 228,108,245,148,140,40,35,195,38,58,65,207,215,253,65,85,208,76,62,3,237,55,89, + 232,50,217,64,244,157,199,121,252,90,17,212,203,149,152,140,187,234,177,73,174, + 193,100,192,143,97,53,145,135,19,103,13,90,135,151,199,91,239,247,33,39,145, + 101,120,99,3,186,86,99,41,237,203,111,79,220,135,158,42,30,154,120,67,87,167, + 135,176,183,191,253,115,184,21,233,58,129,233,142,39,128,211,118,137,139,255, + 114,20,218,113,154,27,127,246,250,1,8,198,250,209,92,222,173,21,88,102,219 }; + +void set_perlin_2d_seed(uint32_t s) { + seed = s; +} + +static int32_t noise2(int x, int y) +{ + int tmp = hash[(y + seed) % 256]; + return hash[(tmp + x) % 256]; +} + +static float lin_inter(float x, float y, float s) +{ + return x + s * (y-x); +} + +static float smooth_inter(float x, float y, float s) +{ + return lin_inter(x, y, s * s * (3-2*s)); +} + +static float noise2d(float x, float y) +{ + int32_t x_int = (int32_t)x; + int32_t y_int = (int32_t)y; + float x_frac = x - (float)x_int; + float y_frac = y - (float)y_int; + int32_t s = noise2(x_int, y_int); + int32_t t = noise2(x_int + 1, y_int); + int32_t u = noise2(x_int, y_int + 1); + int v = noise2(x_int + 1, y_int + 1); + float low = smooth_inter((float)s, (float)t, x_frac); + float high = smooth_inter((float)u, (float)v, x_frac); + return smooth_inter(low, high, y_frac); +} + +/* https://gist.github.com/nowl/828013 */ +float sample_perlin_2d(t_fvec2 position, float frequency, uint8_t octaves) { + t_fvec2 a = m_vec_scale(position, frequency); + float amp = 1.0; + float fin = 0; + float div = 0.0; + + for(uint8_t i = 0; i < octaves; i++) + { + div += 256 * amp; + fin += noise2d(a.x, a.y) * amp; + amp /= 2; + a = m_vec_scale(a, 2); + } + + return fin/div; +} diff --git a/src/vec.h b/src/vec.h index 2aa5ba2..193c4e1 100644 --- a/src/vec.h +++ b/src/vec.h @@ -70,6 +70,10 @@ static inline t_fvec3 fvec3_sub(t_fvec3 a, t_fvec3 b) { return (t_fvec3) { a.x - b.x, a.y - b.y, a.z - b.z }; } +static inline t_fvec2 fvec2_scale(t_fvec2 a, float s) { + return (t_fvec2) { a.x * s, a.y * s }; +} + static inline t_fvec3 fvec3_scale(t_fvec3 a, float s) { return (t_fvec3) { a.x * s, a.y * s, a.z * s }; } @@ -103,6 +107,7 @@ static inline t_fvec3 fvec3_norm(t_fvec3 a) { )(p_any_vec0, p_any_vec1)) #define m_vec_scale(p_any_vec, p_any_scalar) (_Generic((p_any_vec), \ + t_fvec2: fvec2_scale, \ t_fvec3: fvec3_scale \ )(p_any_vec, p_any_scalar))