diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..3e265b2 --- /dev/null +++ b/src/map.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#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, +}; + +#define value(x, y) (MAPDATA[(x) + MAP_SIZE * (y)]) diff --git a/src/ray.c b/src/ray.c new file mode 100644 index 0000000..36e89b4 --- /dev/null +++ b/src/ray.c @@ -0,0 +1,106 @@ +#include "ray.h" +#include "map.h" + +#include + +float v2_cross(v2 a, v2 b) { + return fabs(a.x * b.y - a.y * b.x); +} + +float v2_len(v2 a) { + return sqrt(a.x * a.x + a.y * a.y); +} + +float v2_square_dist(v2 a, v2 b) { + return pow(a.x - b.x, 2) + pow(a.y - b.y, 2); +} + +#define PI 3.14159265358979323846 +#define PIH 1.57079632679489661923 +#define PI2 6.28318530718 + +uint32_t cast_ray(v2 pos, float theta, v2* hit_pos) { + + const v2i move = { + #define sign(a) ((a) < 0 ? -1 : 1) + sign(cos(theta)), + sign(sin(theta)), + }; + + const v2i offset = { + move.x == -1 ? 1 : 0, + move.y == -1 ? 1 : 0 + }; + + const float tanc = tan(theta); + const float cotc = tan(PIH - (theta)); + + 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; + hit_pos->x = pos.x + 1000 * move.x; + hit_pos->y = pos.y + 1000 * move.y; + return false; + } else if (fx && !fy) { + hit = vx; + hit_pos->x = x; + hit_pos->y = posi.y; + } else if (fy && !fx) { + hit = vy; + hit_pos->x = posi.x; + hit_pos->y = y; + } 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; + hit_pos->x = x; + hit_pos->y = posi.y; + } else { + hit = vy; + hit_pos->x = posi.x; + hit_pos->y= y; + } + } + + return hit; +} diff --git a/src/ray.h b/src/ray.h new file mode 100644 index 0000000..8ad2638 --- /dev/null +++ b/src/ray.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +typedef struct { + float x, y; +} v2; + +typedef struct { + int x, y; +} v2i; + + +float v2_cross(v2 a, v2 b); +float v2_len(v2 a); +float v2_square_dist(v2 a, v2 b); +v2 v2_add(v2 a, v2 b); + +uint32_t cast_ray(v2 pos, float theta, v2* hit_pos); diff --git a/src/renderer.c b/src/renderer.c index 8eee037..6d8e1af 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -1,5 +1,6 @@ #include "renderer.h" #include "screen.h" +#include "ray.h" #include @@ -13,16 +14,11 @@ void init_camera(Camera* camera) { camera->angle = PI / 4; } -typedef struct { - float x, y; -} v2; - -typedef struct { - int x, y; -} v2i; +static double fov = PI / 4; #define MOVE_SPEED 1 #define ROTATE_SPEED PI / 2 +#define FOV_CHANGE_SPEED 1 void update_camera(Camera* camera, Screen* screen) { double rotate = 0; @@ -43,7 +39,7 @@ void update_camera(Camera* camera, Screen* screen) { v2 left = { forward.y, -forward.x }; v2 move = { 0, 0 }; - if (key_pressed(screen, SDL_SCANCODE_W)) { + if (key_pressed(screen, SDL_SCANCODE_W)) { move.x += forward.x; move.y += forward.y; } @@ -63,22 +59,25 @@ void update_camera(Camera* camera, Screen* screen) { move.y -= left.y; } + if (key_pressed(screen, SDL_SCANCODE_EQUALS)) { + fov += FOV_CHANGE_SPEED * screen->delta; + } + + if (key_pressed(screen, SDL_SCANCODE_MINUS)) { + fov -= FOV_CHANGE_SPEED * screen->delta; + } + 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, -}; +v2 get_cam_right(const Camera* camera) { + v2 cam_right = { + -sin(camera->angle), + cos(camera->angle) + }; + return cam_right; +} static void verline(Screen* screen, int x, int y0, int y1, uint32_t color) { for (int y = y0; y <= y1; y++) { @@ -86,124 +85,31 @@ static void verline(Screen* screen, int x, int y0, int y1, uint32_t 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 }; + const v2 cam_right = get_cam_right(camera); + for (int sx = 0; sx < screen->width; sx++) { const float xcam = (2 * (sx / (float) (screen->width))) - 1; const float change = fov * atan(xcam); + const float theta = camera->angle + change; - const v2i move = { - sign(cos(camera->angle + change)), - sign(sin(camera->angle + change)), - }; + v2 hit_pos; + uint32_t hit = cast_ray(pos, theta, &hit_pos); - 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)); + hit_pos.x -= pos.x; + hit_pos.y -= pos.y; - 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; + float len = v2_cross(hit_pos, cam_right) / v2_len(cam_right); uint32_t color; switch (hit) { diff --git a/src/renderer.h b/src/renderer.h index ca184a9..998c9d7 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -1,6 +1,7 @@ #pragma once #include "screen.h" +#include "ray.h" typedef struct { float x, y; @@ -9,5 +10,6 @@ typedef struct { void init_camera(Camera* camera); void update_camera(Camera* camera, Screen* screeen); +v2 get_cam_right(const Camera* camera); void render(Screen* screen, const Camera* camera);