Finalise the starfield code

This commit is contained in:
Abdelrahman Said 2023-08-19 16:59:16 +01:00
parent 78b2b8bfd1
commit 16c6048296
3 changed files with 180 additions and 24 deletions

View File

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
CC=clang CC=clang
CFLAGS="-g -Wall -Werror -pedantic" CFLAGS="-g"
LIBS="-lSDL2" LIBS="-lm -lSDL2"
SRC="main.c" SRC="main.c"
OUT="main" OUT="main"

View File

@ -4,9 +4,6 @@
"/usr/bin/clang", "/usr/bin/clang",
"-c", "-c",
"-g", "-g",
"-Wall",
"-Werror",
"-pedantic",
"-o", "-o",
"main", "main",
"main.c" "main.c"
@ -62,9 +59,6 @@
"/include", "/include",
"-internal-externc-isystem", "-internal-externc-isystem",
"/usr/include", "/usr/include",
"-Wall",
"-Werror",
"-pedantic",
"-fdebug-compilation-dir=/home/abdelrahman/Sources/programming/starfield", "-fdebug-compilation-dir=/home/abdelrahman/Sources/programming/starfield",
"-ferror-limit", "-ferror-limit",
"19", "19",
@ -77,11 +71,11 @@
"-x", "-x",
"c", "c",
"-o", "-o",
"/tmp/main-7469c3.o", "/tmp/main-118336.o",
"main.c" "main.c"
], ],
"directory": "/home/abdelrahman/Sources/programming/starfield", "directory": "/home/abdelrahman/Sources/programming/starfield",
"file": "/home/abdelrahman/Sources/programming/starfield/main.c", "file": "/home/abdelrahman/Sources/programming/starfield/main.c",
"output": "/tmp/main-7469c3.o" "output": "/tmp/main-118336.o"
} }
] ]

190
main.c
View File

@ -1,25 +1,71 @@
#include "aliases.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_pixels.h> #include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_rect.h> #include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h> #include <SDL2/SDL_surface.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#define WINDOW_WIDTH 800 #define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600 #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); #define STAR_COUNT 2500
void fill_rect(SDL_Surface *surface, uint32_t x, uint32_t y, uint32_t w, #define STAR_SPREAD 500
uint32_t h, uint32_t color); #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) { int main(void) {
srand(time(NULL));
SDL_Init(SDL_INIT_EVERYTHING); SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("Starfield", SDL_WINDOWPOS_CENTERED, SDL_Window *window = SDL_CreateWindow("Starfield", SDL_WINDOWPOS_CENTERED,
@ -35,6 +81,12 @@ int main(void) {
SDL_Event event = {0}; 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 (running) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { 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); 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_BlitSurface(canvas, NULL, surface, NULL);
SDL_UpdateWindowSurface(window); SDL_UpdateWindowSurface(window);
@ -58,29 +117,51 @@ int main(void) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
void render_clear(SDL_Surface *surface, uint32_t color) { f64 absf(f64 val) {
uint32_t length = surface->w * surface->h; 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); 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; pixels[i] = color;
} }
SDL_UnlockSurface(surface); SDL_UnlockSurface(surface);
} }
void fill_rect(SDL_Surface *surface, uint32_t x, uint32_t y, uint32_t w, void set_pixel(SDL_Surface *surface, vec2i_t pos, u32 color) {
uint32_t h, uint32_t color) {
SDL_LockSurface(surface); SDL_LockSurface(surface);
uint32_t *pixels = (uint32_t *)(surface->pixels); u32 *pixels = (u32 *)(surface->pixels);
for (uint32_t row = 0; row < h; ++row) { u32 index = pos.y * surface->w + pos.x;
for (uint32_t col = 0; col < w; ++col) {
uint32_t i = (y + row) * surface->w + (x + col); 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; 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); 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);
}
}