Created
December 31, 2019 12:54
-
-
Save dlandahl/499a5e91fdba14796f82e25da6d581fe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <math.h> | |
#include <iostream> | |
#include "SDL2/SDL.h" | |
uint16_t const screen_width = 48 * 5; | |
uint16_t const screen_height = 32 * 5; | |
float const circle = 6.28318530; | |
template <typename T> struct vec2 | |
{ | |
T x; | |
T y; | |
}; | |
template <int size> | |
struct sine_table | |
{ | |
sine_table() { | |
for (int n = 0; n < size; n++) | |
data[n] = sinf(n * circle / size); | |
} | |
__attribute__((always_inline)) float const read(float index) const | |
{ | |
//index = fmod(index, size); | |
return data[int(index / circle * size)]; | |
} | |
private: | |
float data[size] = { 0 }; | |
}; | |
sine_table<512> const sine; | |
float cos_interpolate(float const a, float const b, float const ratio) { | |
float mu = (1.f - sine.read(ratio * circle / 2.f + circle / 4)) / 2.f; | |
return (1.0f - mu) * a + mu * b; | |
} | |
struct PerlinNoise | |
{ | |
enum GridIndex { | |
top_left =0b00, top_right =0b01, bottom_left =0b10, bottom_right =0b11 | |
}; | |
int seed = 0; | |
float get_gradient_at_cell(vec2<int> cell) const | |
{ | |
srand(seed + cell.x + cell.y * cell.x); | |
uint64_t r = rand(); | |
float val = (float) r / RAND_MAX; | |
return val * circle; | |
} | |
vec2<int> get_cell_coordinates(vec2<float> location, GridIndex cell_index) const | |
{ | |
int cell_x = (int) location.x; | |
int cell_y = (int) location.y; | |
if (cell_index & 0b01) cell_x++; | |
if (cell_index & 0b10) cell_y++; | |
return { cell_x, cell_y }; | |
} | |
float get_distance_to_cell(vec2<float> location, GridIndex grid_index) const | |
{ | |
vec2<int> cell_location = get_cell_coordinates(location, grid_index); | |
return sqrtf((cell_location.x - location.x) * (cell_location.x - location.x) + (cell_location.y - location.y) * (cell_location.y - location.y)); | |
} | |
float get_dot_product(vec2<float> location, GridIndex grid_index) const | |
{ | |
vec2<int> cell_location = get_cell_coordinates(location, grid_index); | |
float gradient_at_grid = get_gradient_at_cell(cell_location); | |
float x_distance = location.x - cell_location.x; | |
float y_distance = location.y - cell_location.y; | |
float x_product = x_distance * sine.read(gradient_at_grid + circle / 4); | |
float y_product = y_distance * sine.read(gradient_at_grid); | |
return x_product + y_product; | |
} | |
float get_perlin_value(float x, float y) const | |
{ | |
float products[4]; | |
for (int n = 0; n < 4; n++) products[n] = get_dot_product(vec2<float> {x, y}, (GridIndex) n); | |
int x0 = x; | |
int y0 = y; | |
float sx = x - x0; | |
float sy = y - y0; | |
float ix0, ix1, value; | |
ix0 = cos_interpolate(products[0], products[1], sx); | |
ix1 = cos_interpolate(products[2], products[3], sx); | |
value = cos_interpolate(ix0, ix1, sy); | |
return value; | |
} | |
}; | |
struct rgb_colour | |
{ | |
uint8_t r = 0, g = 0, b = 0, a = 255; | |
rgb_colour(float r, float g, float b) : r(255*r), g(255*g), b(255*b) {} | |
rgb_colour(int r, int g, int b) : r(r), g(g), b(b) {} | |
rgb_colour() = default; | |
uint8_t& operator[](unsigned n) | |
{ | |
return *((uint8_t*) this + n); | |
} | |
operator uint32_t() const { return ( r << 24 | g << 16 | b << 8 | a ); } | |
}; | |
int main(int argc, const char ** argv) | |
{ | |
SDL_Init(SDL_INIT_VIDEO); | |
SDL_Window* const output_window = SDL_CreateWindow("Map Game", 0, 0, screen_width * 4, screen_height * 4, SDL_WINDOW_SHOWN); | |
SDL_Surface* const output_surface = SDL_GetWindowSurface(output_window); | |
SDL_Surface* const surface = SDL_CreateRGBSurface(0, screen_width, screen_height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); | |
PerlinNoise noise; | |
// for (int n = 0; n < 2000; n++) std::cout << noise.get_perlin_value(n+n/123452345.f, 0.5) << std::endl; | |
if (argc > 1) { | |
for (char c = -1, n = 0; c != 0; n++) { | |
c = argv[1][n]; | |
noise.seed += c; | |
} | |
} | |
SDL_Event ev; | |
bool run = 1; | |
float phase = 0; | |
while (run) { | |
SDL_BlitScaled(surface, NULL, output_surface, NULL); | |
SDL_UpdateWindowSurface(output_window); | |
//SDL_SetRenderDrawColor(output_renderer, 32, 32, 32, 255); | |
//SDL_RenderClear(output_renderer); | |
for (int x = 0; x < screen_width; x++) { | |
for (int y = 0; y < screen_height; y++) { | |
rgb_colour col = { 1.f, 1.f, 1.f }; | |
float _x = x + phase; | |
float val = (noise.get_perlin_value(_x / 80.f, y / 80.f)) + 0.25; | |
val += (noise.get_perlin_value(_x / 20.f + 15.135, y / 20.f) + 0.5) * 0.4; | |
val += (noise.get_perlin_value(_x / 5.f, y / 5.f) + 0.5) * 0.15; | |
if (val < 0.4) col = {0.01f, 0.5, 0.7}; | |
else if (val < 0.5) col = {0.01f, 0.7, 0.9}; | |
else if (val < 0.55) col = {0.75f, 0.75f, 0.6f}; | |
else if (val < 0.6) col = {0.26f, 0.69f, 0.3f}; | |
else if (val < 0.75) col = {0.1f, 0.4f, 0.15f}; | |
else if (val < 0.95) col = { 0.16f, 0.14f, 0.14f }; | |
((uint32_t*)surface->pixels)[x + (surface->pitch / 4) * y] = col; | |
} | |
} | |
phase += 1; | |
//SDL_Delay(50); | |
while (SDL_PollEvent(&ev)) if (ev.type == SDL_QUIT) run = 0; | |
} | |
SDL_DestroyWindow(output_window); | |
SDL_Quit(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment