Skip to content

Instantly share code, notes, and snippets.

@Demizdor
Last active April 14, 2023 03:00
Show Gist options
  • Save Demizdor/e916ba765336c389af4ecd2c557a6be6 to your computer and use it in GitHub Desktop.
Save Demizdor/e916ba765336c389af4ecd2c557a6be6 to your computer and use it in GitHub Desktop.
Noise Planets
// ========================================================================
// 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);
}
}
@Demizdor
Copy link
Author

screenshot000
Made the graphics smoother now (thanks @raysan5)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment