Skip to content

Instantly share code, notes, and snippets.

@dlandahl
Created December 31, 2019 12:54
Show Gist options
  • Save dlandahl/499a5e91fdba14796f82e25da6d581fe to your computer and use it in GitHub Desktop.
Save dlandahl/499a5e91fdba14796f82e25da6d581fe to your computer and use it in GitHub Desktop.
#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