From 2a88947f036ca3c9f88a9e2265229ceb5ae3367d Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Sat, 22 Apr 2023 00:47:10 -0400 Subject: [PATCH] initial --- .gitignore | 1 + Makefile | 42 +++++++++ src/main.c | 21 +++++ src/renderer.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++ src/renderer.h | 13 +++ src/screen.c | 130 ++++++++++++++++++++++++++++ src/screen.h | 24 ++++++ 7 files changed, 457 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/main.c create mode 100644 src/renderer.c create mode 100644 src/renderer.h create mode 100644 src/screen.c create mode 100644 src/screen.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e321478 --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +CC = gcc + +INCFLAGS = -Isrc + +CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2 +CCFLAGS += $(INCFLAGS) + +LDFLAGS += $(INCFLAGS) +LDFLAGS += -lSDL2 +LDFLAGS += -lm + +BIN = bin +APP = $(BIN)/app +SRC = $(shell find src -name "*.c") +OBJ = $(SRC:%.c=$(BIN)/%.o) + +.PHONY: dirs run clean build install uninstall + +EOF: clean build + +dirs: + mkdir -p ./$(BIN) + mkdir -p ./$(BIN)/src + +run: build + $(APP) + +build: dirs ${OBJ} + ${CC} -o $(APP) $(filter %.o,$^) $(LDFLAGS) + +$(BIN)/%.o: %.c + $(CC) -o $@ -c $< $(CCFLAGS) + +clean: + rm -rf $(APP) + rm -rf $(BIN) + +install: + cp $(APP) /usr/local/bin/wrapper + +uninstall: + rm /usr/local/bin/wrapper diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..36b819f --- /dev/null +++ b/src/main.c @@ -0,0 +1,21 @@ +#include "renderer.h" +#include "screen.h" + +int main (void) { + Screen screen; + init_screen(&screen, "test", 1920, 1080); + + Camera camera; + init_camera(&camera); + + while(screen.open) { + poll_screen(&screen); + draw_screen(&screen); + render(&screen, &camera); + + update_camera(&camera, &screen); + } + free_screen(&screen); + + return EXIT_SUCCESS; +} diff --git a/src/renderer.c b/src/renderer.c new file mode 100644 index 0000000..8eee037 --- /dev/null +++ b/src/renderer.c @@ -0,0 +1,226 @@ +#include "renderer.h" +#include "screen.h" + +#include + +#define PI 3.14159265358979323846 +#define PIH 1.57079632679489661923 +#define PI2 6.28318530718 + +void init_camera(Camera* camera) { + camera->x = 3; + camera->y = 3; + camera->angle = PI / 4; +} + +typedef struct { + float x, y; +} v2; + +typedef struct { + int x, y; +} v2i; + +#define MOVE_SPEED 1 +#define ROTATE_SPEED PI / 2 +void update_camera(Camera* camera, Screen* screen) { + double rotate = 0; + + if (key_pressed(screen, SDL_SCANCODE_LEFT)) + rotate -= ROTATE_SPEED; + + if (key_pressed(screen, SDL_SCANCODE_RIGHT)) + rotate += ROTATE_SPEED; + + + rotate *= screen->delta; + rotate += camera->angle; + while (rotate >= PI2) rotate -= PI2; + while (rotate < 0) rotate += PI2; + camera->angle = rotate; + + v2 forward = { cos(camera->angle), sin(camera->angle) }; + v2 left = { forward.y, -forward.x }; + v2 move = { 0, 0 }; + + if (key_pressed(screen, SDL_SCANCODE_W)) { + move.x += forward.x; + move.y += forward.y; + } + + if (key_pressed(screen, SDL_SCANCODE_S)) { + move.x -= forward.x; + move.y -= forward.y; + } + + if (key_pressed(screen, SDL_SCANCODE_A)) { + move.x += left.x; + move.y += left.y; + } + + if (key_pressed(screen, SDL_SCANCODE_D)) { + move.x -= left.x; + move.y -= left.y; + } + + camera->x += move.x * MOVE_SPEED * screen->delta; + camera->y += move.y * MOVE_SPEED * screen->delta; +} + + +#define MAP_SIZE 8 +static uint8_t MAPDATA[MAP_SIZE * MAP_SIZE] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 3, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 2, 0, 4, 4, 0, 1, + 1, 0, 0, 0, 4, 0, 0, 1, + 1, 0, 3, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, +}; + +static void verline(Screen* screen, int x, int y0, int y1, uint32_t color) { + for (int y = y0; y <= y1; y++) { + screen->pixels[(y * screen->width) + x] = color; + } +} + +static float v2_cross(v2 a, v2 b) { + return fabs(a.x * b.y - a.y * b.x); +} + +static float v2_len(v2 a) { + return sqrt(a.x * a.x + a.y * a.y); +} + +static float v2_square_dist(v2 a, v2 b) { + return pow(a.x - b.x, 2) + pow(a.y - b.y, 2); +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define sign(a) ((a) < 0 ? -1 : 1) +#define value(x, y) (MAPDATA[(x) + MAP_SIZE * (y)]) + +void render(Screen* screen, const Camera* camera) { + + const double fov = PI / 3; + + const v2 cam_right = { + -sin(camera->angle), + cos(camera->angle) + }; + + const v2 pos = { + camera->x, + camera->y + }; + + for (int sx = 0; sx < screen->width; sx++) { + + const float xcam = (2 * (sx / (float) (screen->width))) - 1; + const float change = fov * atan(xcam); + + const v2i move = { + sign(cos(camera->angle + change)), + sign(sin(camera->angle + change)), + }; + + const v2i offset = { + move.x == -1 ? 1 : 0, + move.y == -1 ? 1 : 0 + }; + + const float tanc = tan(camera->angle + change); + const float cotc = tan(PIH - (camera->angle + change)); + + v2i posi = { + (int)pos.x + offset.x, + (int)pos.y + offset.y + }; + + bool fx = false; + uint32_t vx = 0; + float x; + + while (!fx) { + posi.y += move.y; + x = cotc * (posi.y - pos.y) + pos.x; + + if (fabs(x) - pos.x >= MAP_SIZE) break; + + vx = value((int)x, posi.y - offset.y); + + if (vx != 0) { + fx = true; + } + } + + bool fy = false; + uint32_t vy = 0; + float y; + + while (!fy) { + posi.x += move.x; + y = tanc * (posi.x - pos.x) + pos.y; + + if (fabs(y) - pos.y >= MAP_SIZE) break; + + vy = value(posi.x - offset.x, (int)y); + + if (vy != 0) { + fy = true; + } + } + + uint32_t hit; + if (!fx && !fy) { + hit = 0; + x = pos.x + 1000 * move.x; + y = pos.y + 1000 * move.y; + } else if (fx && !fy) { + hit = vx; + y = posi.y; + } else if (fy && !fx) { + hit = vy; + x = posi.x; + } else { + const v2 posx = {x, posi.y}; + const v2 posy = {posi.x, y}; + if (v2_square_dist(posx, pos) < v2_square_dist(posy, pos)) { + hit = vx; + y = posi.y; + } else { + hit = vy; + x = posi.x; + } + } + + const v2 relative = { + x - pos.x, + y - pos.y + }; + + float len = v2_cross(relative, cam_right) / v2_len(cam_right); + if (len < 0.00001) len = 0.00001; + + uint32_t color; + switch (hit) { + case 1: color = 0xFF0000FF; break; + case 2: color = 0x00FF00FF; break; + case 3: color = 0x0000FFFF; break; + case 4: color = 0xFF00FFFF; break; + case 5: color = 0x00FFFFFF; break; + default: color = 0x000000FF; break; + } + const int + h = (int) (screen->height / len), + y0 = max((screen->height / 2) - (h / 2), 0), + y1 = min((screen->height / 2) + (h / 2), screen->height - 1); + + verline(screen, sx, 0, y0, 0x202020FF); + verline(screen, sx, y0, y1, color); + verline(screen, sx, y1, screen->height - 1, 0x505050FF); + } +} diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..ca184a9 --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,13 @@ +#pragma once + +#include "screen.h" + +typedef struct { + float x, y; + float angle; +} Camera; + +void init_camera(Camera* camera); +void update_camera(Camera* camera, Screen* screeen); + +void render(Screen* screen, const Camera* camera); diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..5e23e0b --- /dev/null +++ b/src/screen.c @@ -0,0 +1,130 @@ +#include "screen.h" + +#include +#include +#include +#include + +void init_screen(Screen* screen, const char* title, uint16_t width, uint16_t height) { + screen->width = width; + screen->height = height; + size_t pixel_count = screen->width * screen->height; + screen->pixels = malloc(pixel_count * sizeof(uint32_t)); + memset(screen->pixels, 0, pixel_count * sizeof(uint32_t)); + + SDL_Init(SDL_INIT_VIDEO); + + screen->window = + SDL_CreateWindow( + title, + SDL_WINDOWPOS_CENTERED_DISPLAY(0), + SDL_WINDOWPOS_CENTERED_DISPLAY(0), + screen->width, + screen->height, + 0 + ); + + if (!screen->window) { + printf("fatal: failed to create sdl window\n"); + exit(EXIT_FAILURE); + } + + screen->renderer = + SDL_CreateRenderer( + screen->window, + -1, + SDL_RENDERER_ACCELERATED + | SDL_RENDERER_PRESENTVSYNC + ); + + if (!screen->renderer) { + printf("fatal: failed to create sdl renderer\n"); + exit(EXIT_FAILURE); + } + + screen->texture = + SDL_CreateTexture( + screen->renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, + screen->width, + screen->height + ); + + if (!screen->texture) { + printf("fatal: failed to create window texture\n"); + exit(EXIT_FAILURE); + } + + screen->open = true; + screen->delta = 0; +} + +static long last = 0; +void poll_screen(Screen* screen) { + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + long now = round(spec.tv_nsec / 1.0e6) + spec.tv_sec * 1000; + if (last == 0) { + screen->delta = 0; + } else { + screen->delta = (now - last) / 1000.0; + } + last = now; + + SDL_Event ev; + while (SDL_PollEvent(&ev)) { + switch (ev.type) { + case SDL_QUIT: + screen->open = false; + break; + default: + break; + } + } + + screen->key_state = SDL_GetKeyboardState(NULL); +} + +void draw_screen(Screen* screen) { + void *px; + int pitch; + SDL_LockTexture(screen->texture, NULL, &px, &pitch); + { + for (uint16_t y = 0; y < screen->height; y++) { + memcpy( + &((uint8_t*) px)[y * pitch], + &screen->pixels[y * screen->width], + screen->width * sizeof(uint32_t) + ); + } + } + SDL_UnlockTexture(screen->texture); + + SDL_SetRenderTarget(screen->renderer, NULL); + SDL_SetRenderDrawColor(screen->renderer, 0, 0, 0, 0xFF); + SDL_SetRenderDrawBlendMode(screen->renderer, SDL_BLENDMODE_NONE); + + SDL_RenderClear(screen->renderer); + SDL_RenderCopyEx( + screen->renderer, + screen->texture, + NULL, + NULL, + 0.0, + NULL, + SDL_FLIP_VERTICAL); + + SDL_RenderCopy(screen->renderer, NULL, NULL, &((SDL_Rect) { 0, 0, 512, 512 })); + SDL_RenderPresent(screen->renderer); +} + +void free_screen(Screen* screen) { + SDL_DestroyTexture(screen->texture); + SDL_DestroyRenderer(screen->renderer); + SDL_DestroyWindow(screen->window); +} + +bool key_pressed(Screen* screen, SDL_Scancode code) { + return screen->key_state[code & 0xFFFF]; +} diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..1b601d8 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,24 @@ +#pragma once + +#define _POSIX_C_SOURCE 200809L +#include +#include + +typedef struct { + uint16_t width; + uint16_t height; + SDL_Window* window; + SDL_Renderer* renderer; + SDL_Texture* texture; + uint32_t* pixels; + const uint8_t* key_state; + bool open; + float delta; +} Screen; + +void init_screen(Screen* screen, const char* title, uint16_t width, uint16_t height); +void draw_screen(Screen* screen); +void poll_screen(Screen* screen); +void free_screen(Screen* screen); + +bool key_pressed(Screen* screen, SDL_Scancode code);