Last active
April 14, 2023 03:00
-
-
Save Demizdor/e916ba765336c389af4ecd2c557a6be6 to your computer and use it in GitHub Desktop.
Noise Planets
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
// ======================================================================== | |
// NOISE PLANETS WITH RAYLIB | |
// BASED ON: https://avinayak.github.io/art/2021/01/09/noise-planets.html | |
// ======================================================================== | |
#include <raylib.h> | |
#include <stdlib.h> | |
#include <limits.h> | |
#include <math.h> | |
#include <time.h> | |
// ==================================== | |
// https://github.com/Auburn/FastNoise | |
// ==================================== | |
#define FNL_IMPL | |
#include "FastNoiseLite.h" | |
// ==================================== | |
#define TAU PI*2 | |
#define SCREEN_WIDTH 800 | |
#define SCREEN_HEIGHT 450 | |
#define UPSCALE 2 | |
#define NUM_POINTS 500 | |
#define BORDER 10 | |
#define BGCOLOR (Color){0xf9, 0xf8, 0xf4, 0xff} | |
// ==================================== | |
// GLOBALS | |
// ==================================== | |
typedef Vector2 Point; | |
Point* points; | |
RenderTexture2D render = {0}; | |
bool Reset = true; | |
fnl_state Noise; | |
const char* NoiseType[] = { | |
"OPENSIMPLEX2", | |
"OPENSIMPLEX2S", | |
"CELLULAR", | |
"PERLIN", | |
"CUBIC", | |
"VALUE" | |
}; | |
// ==================================== | |
// ==================================== | |
// FUNCTIONS | |
// ==================================== | |
static inline void Initialize(); | |
static inline void Cleanup(); | |
static inline void Update(); | |
static inline void Draw(); | |
static inline float RandomFloat(); | |
void GenerateRandomPoints(); | |
// ==================================== | |
int main(int argc, char **argv) | |
{ | |
Initialize(); | |
// Main loop | |
while (!WindowShouldClose()) | |
{ | |
Update(); | |
BeginDrawing(); | |
ClearBackground(BGCOLOR); | |
Draw(); | |
EndDrawing(); | |
} | |
Cleanup(); | |
return 0; | |
} | |
inline void Initialize() | |
{ | |
// Initialize raylib | |
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_HIGHDPI); | |
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "[raylib] Noise Planets"); | |
SetTargetFPS(60); | |
render = LoadRenderTexture(SCREEN_WIDTH*UPSCALE, SCREEN_HEIGHT*UPSCALE); | |
SetTextureFilter(render.texture, FILTER_BILINEAR); | |
// Set initial random seed | |
srand(time(NULL)); | |
// Initialize noise | |
Noise = fnlCreateState(); | |
Noise.noise_type = FNL_NOISE_PERLIN; | |
// Allocate memory and generate points | |
points = calloc(NUM_POINTS, sizeof*points); | |
if(points == NULL) TraceLog(LOG_FATAL, "Failed to allocate memory!"); | |
GenerateRandomPoints(); | |
} | |
inline void Cleanup() | |
{ | |
UnloadRenderTexture(render); | |
CloseWindow(); | |
free(points); | |
} | |
inline void Update() | |
{ | |
if(IsKeyPressed(KEY_SPACE)) { | |
Noise.seed = _fnlHash2D(time(NULL), PRIME_X, PRIME_Y); | |
GenerateRandomPoints(); | |
Reset = true; | |
} else if(IsKeyPressed(KEY_ENTER)) { | |
Noise.noise_type = GetRandomValue(FNL_NOISE_OPENSIMPLEX2, FNL_NOISE_VALUE); | |
GenerateRandomPoints(); | |
Reset = true; | |
} | |
} | |
inline void Draw() | |
{ | |
// NOTE: to make everything look smoother we need to draw to a upscaled texture | |
// FIXME: isn't there a better way to do this!? | |
const int w = GetScreenWidth()*UPSCALE; | |
const int h = GetScreenHeight()*UPSCALE; | |
int s = (w > h ? h : w); | |
float radius = (float)(s-BORDER*2.0)/2.0; | |
int pts = 0; // active points (points that are still inside the circle) | |
// Render to upscale texture | |
BeginTextureMode(render); | |
if(!Reset) { | |
for(int i=0; i<NUM_POINTS; ++i) | |
{ | |
float n = fnlGetNoise2D(&Noise, points[i].x*0.1, points[i].y*0.1); | |
Point p = points[i]; | |
p.x += sin(n*TAU); | |
p.y += cos(n*TAU); | |
if(CheckCollisionPointCircle(p, (Vector2){w/2, h/2}, radius)) { | |
points[i] = p; | |
DrawRectangle((int)points[i].x, (int)points[i].y, 2, 2, DARKGRAY); | |
++pts; | |
} | |
} | |
} | |
else | |
{ | |
ClearBackground(BGCOLOR); | |
Reset = false; | |
} | |
DrawRing((Vector2){w/2, h/2}, radius, radius + 3.0, 0, 360, 0, LIGHTGRAY); | |
EndTextureMode(); | |
// Render the texture downscaled to fit the screen | |
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) | |
DrawTexturePro(render.texture, (Rectangle){0,0,render.texture.width, -render.texture.height}, (Rectangle){0,0,GetScreenWidth(), GetScreenHeight()}, | |
(Vector2){0, 0}, 0.0f, WHITE); | |
DrawText(TextFormat("FPS: %02i\n==============================\n" | |
"SEED: 0x%08X [SPACE]\nNOISE: %s [ENTER]\n==============================\n" | |
"POINTS: %i\n==============================", GetFPS(), Noise.seed, NoiseType[Noise.noise_type], pts), 10, 10, 10,BLACK); | |
} | |
// Returns a random float between 0.0 and 1.0 | |
static inline float RandomFloat() { | |
return (float)rand()/RAND_MAX; | |
} | |
// Generate random points inside a circle. The circle radius is calculated based on the screen width/height and BORDER | |
// NOTE: Points are drawn to a upscaled texture so take that into account when doing the calculations | |
void GenerateRandomPoints() | |
{ | |
const int w = GetScreenWidth()*UPSCALE; | |
const int h = GetScreenHeight()*UPSCALE; | |
int s = (w > h ? h : w); | |
for(int i=0; i<NUM_POINTS; ++i) | |
{ | |
float a = RandomFloat() * 2 * PI; | |
float r = (float)(s-BORDER*2.)/2. * sqrtf(RandomFloat()); | |
points[i].x = w/2.0 + r*sin(a); | |
points[i].y = h/2.0 + r*cos(a); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Made the graphics smoother now (thanks @raysan5)