diff --git a/compile b/compile index 1a9cdf1..0238428 100755 --- a/compile +++ b/compile @@ -1,8 +1,8 @@ #!/bin/bash CC=clang -CFLAGS="-g -Wall -Werror -pedantic" -LIBS="-lSDL2" +CFLAGS="-g" +LIBS="-lm -lSDL2" SRC="main.c" OUT="main" diff --git a/compile_commands.json b/compile_commands.json index 951c132..37acc45 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -4,9 +4,6 @@ "/usr/bin/clang", "-c", "-g", - "-Wall", - "-Werror", - "-pedantic", "-o", "main", "main.c" @@ -62,9 +59,6 @@ "/include", "-internal-externc-isystem", "/usr/include", - "-Wall", - "-Werror", - "-pedantic", "-fdebug-compilation-dir=/home/abdelrahman/Sources/programming/starfield", "-ferror-limit", "19", @@ -77,11 +71,11 @@ "-x", "c", "-o", - "/tmp/main-7469c3.o", + "/tmp/main-118336.o", "main.c" ], "directory": "/home/abdelrahman/Sources/programming/starfield", "file": "/home/abdelrahman/Sources/programming/starfield/main.c", - "output": "/tmp/main-7469c3.o" + "output": "/tmp/main-118336.o" } ] diff --git a/main.c b/main.c index 2cdb33b..bc55a4d 100644 --- a/main.c +++ b/main.c @@ -1,25 +1,71 @@ +#include "aliases.h" #include #include #include #include #include +#include #include +#include #include #include #include #include #include +#include #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 -#define BG_COLOR 0x060616ff +#define NORMALISED_MIN -1 +#define NORMALISED_MAX 1 -void render_clear(SDL_Surface *surface, uint32_t color); -void fill_rect(SDL_Surface *surface, uint32_t x, uint32_t y, uint32_t w, - uint32_t h, uint32_t color); +#define STAR_COUNT 2500 +#define STAR_SPREAD 500 +#define STAR_SPEED 50 + +#define BG_COLOR 0x060616ff +#define STAR_COLOR 0xd4d4ddff + +#define PROJECTION_PLANE 1.0 + +typedef struct { + u32 x; + u32 y; +} vec2i_t; + +typedef struct { + f64 x; + f64 y; +} vec2f_t; + +typedef struct { + f64 x; + f64 y; + f64 z; +} vec3f_t; + +f64 absf(f64 val); +void render_clear(SDL_Surface *surface, u32 color); +void set_pixel(SDL_Surface *surface, vec2i_t pos, u32 color); + +#if 0 +void fill_rect(SDL_Surface *surface, vec2i_t pos, u32 w, u32 h, u32 color); +f64 normalise(f64 abs_val, f64 abs_min, f64 abs_max, f64 norm_min, + f64 norm_max); +#endif + +f64 denormalise(f64 norm_val, f64 norm_min, f64 norm_max, f64 abs_min, + f64 abs_max); +void init_starfield(vec3f_t *stars, u32 count, i32 spread); +void update_startfield(vec3f_t *stars, u32 count, i32 spread, u32 speed, + f64 delta); +void render_starfield(SDL_Surface *surface, vec3f_t *stars, u32 count, + i32 spread, f64 aov); int main(void) { + srand(time(NULL)); + SDL_Init(SDL_INIT_EVERYTHING); SDL_Window *window = SDL_CreateWindow("Starfield", SDL_WINDOWPOS_CENTERED, @@ -35,6 +81,12 @@ int main(void) { SDL_Event event = {0}; + vec3f_t stars[STAR_COUNT]; + + init_starfield(stars, STAR_COUNT, STAR_SPREAD); + + f64 delta = 1.0 / 60.0; // constant delta + while (running) { while (SDL_PollEvent(&event)) { switch (event.type) { @@ -44,8 +96,15 @@ int main(void) { } } + update_startfield(stars, STAR_COUNT, STAR_SPREAD, STAR_SPEED, delta); + render_clear(canvas, BG_COLOR); + u32 scalar = 10; + vec2i_t pos; + + render_starfield(canvas, stars, STAR_COUNT, STAR_SPREAD, 60.0); + SDL_BlitSurface(canvas, NULL, surface, NULL); SDL_UpdateWindowSurface(window); @@ -58,29 +117,51 @@ int main(void) { return EXIT_SUCCESS; } -void render_clear(SDL_Surface *surface, uint32_t color) { - uint32_t length = surface->w * surface->h; +f64 absf(f64 val) { + if (val < 0) { + val *= -1.0; + } + + return val; +} + +void render_clear(SDL_Surface *surface, u32 color) { + u32 length = surface->w * surface->h; SDL_LockSurface(surface); - uint32_t *pixels = (uint32_t *)(surface->pixels); + u32 *pixels = (u32 *)(surface->pixels); - for (uint32_t i = 0; i < length; ++i) { + for (u32 i = 0; i < length; ++i) { pixels[i] = color; } SDL_UnlockSurface(surface); } -void fill_rect(SDL_Surface *surface, uint32_t x, uint32_t y, uint32_t w, - uint32_t h, uint32_t color) { +void set_pixel(SDL_Surface *surface, vec2i_t pos, u32 color) { SDL_LockSurface(surface); - uint32_t *pixels = (uint32_t *)(surface->pixels); + u32 *pixels = (u32 *)(surface->pixels); - for (uint32_t row = 0; row < h; ++row) { - for (uint32_t col = 0; col < w; ++col) { - uint32_t i = (y + row) * surface->w + (x + col); + u32 index = pos.y * surface->w + pos.x; + + if (index < surface->w * surface->h) { + pixels[index] = color; + } + + SDL_UnlockSurface(surface); +} + +#if 0 +void fill_rect(SDL_Surface *surface, vec2i_t pos, u32 w, u32 h, u32 color) { + SDL_LockSurface(surface); + + u32 *pixels = (u32 *)(surface->pixels); + + for (u32 row = 0; row < h; ++row) { + for (u32 col = 0; col < w; ++col) { + u32 i = (pos.y + row) * surface->w + (pos.x + col); pixels[i] = color; } @@ -88,3 +169,84 @@ void fill_rect(SDL_Surface *surface, uint32_t x, uint32_t y, uint32_t w, SDL_UnlockSurface(surface); } + +f64 normalise(f64 abs_val, f64 abs_min, f64 abs_max, f64 norm_min, + f64 norm_max) { + if (abs_min - abs_max == 0.0) { + return NAN; + } + + f64 ratio = (abs_val - abs_max) / (abs_min - abs_max); + + return ratio * (norm_min - norm_max) + norm_max; +} +#endif + +f64 denormalise(f64 norm_val, f64 norm_min, f64 norm_max, f64 abs_min, + f64 abs_max) { + if (norm_min - norm_max == 0.0) { + return NAN; + } + + f64 ratio = (norm_val - norm_max) / (norm_min - norm_max); + + return ratio * (abs_min - abs_max) + abs_max; +} + +vec3f_t init_star_position(i32 spread) { + i32 spread_half = spread / 2; + + return (vec3f_t){.x = ((rand() % spread) - spread_half) * 2.0, + .y = ((rand() % spread) - spread_half) * 2.0, + .z = (rand() % spread) + PROJECTION_PLANE}; +} + +void init_starfield(vec3f_t *stars, u32 count, i32 spread) { + for (u32 i = 0; i < count; ++i) { + stars[i] = init_star_position(spread); + } +} + +void update_startfield(vec3f_t *stars, u32 count, i32 spread, u32 speed, + f64 delta) { + for (u32 i = 0; i < count; ++i) { + stars[i].z -= speed * delta; + + if (stars[i].z < PROJECTION_PLANE) { + stars[i] = init_star_position(spread); + } + } +} + +void render_starfield(SDL_Surface *surface, vec3f_t *stars, u32 count, + i32 spread, f64 aov) { + vec2f_t projected[count]; + vec2i_t coords; + + for (u32 i = 0; i < count; ++i) { + if (stars[i].z == 0.0) { + continue; + } + + projected[i] = + (vec2f_t){.x = stars[i].x / stars[i].z, .y = stars[i].y / stars[i].z}; + + if (projected[i].x < NORMALISED_MIN || projected[i].x > NORMALISED_MAX || + projected[i].y < NORMALISED_MIN || projected[i].y > NORMALISED_MAX || + (projected[i].x == 0.0 && projected[i].y == 0.0)) { + stars[i] = init_star_position(spread); + + continue; + } + + projected[i].x = denormalise(projected[i].x, NORMALISED_MIN, NORMALISED_MAX, + 0, WINDOW_WIDTH); + projected[i].y = denormalise(projected[i].y, NORMALISED_MIN, NORMALISED_MAX, + 0, WINDOW_HEIGHT); + + coords = + (vec2i_t){.x = (u32)ceil(projected[i].x), .y = (u32)projected[i].y}; + + set_pixel(surface, coords, STAR_COLOR); + } +}