summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-04-22 00:47:10 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-04-22 00:47:10 -0400
commit2a88947f036ca3c9f88a9e2265229ceb5ae3367d (patch)
tree97e399ac6efd7c58d91fe27a5bf9ae87232412e5
downloadraycaster-2a88947f036ca3c9f88a9e2265229ceb5ae3367d.tar.gz
raycaster-2a88947f036ca3c9f88a9e2265229ceb5ae3367d.tar.bz2
raycaster-2a88947f036ca3c9f88a9e2265229ceb5ae3367d.zip
initial
-rw-r--r--.gitignore1
-rw-r--r--Makefile42
-rw-r--r--src/main.c21
-rw-r--r--src/renderer.c226
-rw-r--r--src/renderer.h13
-rw-r--r--src/screen.c130
-rw-r--r--src/screen.h24
7 files changed, 457 insertions, 0 deletions
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 <math.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+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 <SDL2/SDL.h>
+#include <stdbool.h>
+
+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);