From 96b44a4eb286b0bd4aa81f0c6859248fc467fcdb Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 9 Jan 2025 12:54:00 -0500 Subject: [PATCH] Fenscaster is now using the first version of Lode's DDA raycasting algorithm but the coordinates/angles in the left map view don't matchthe right view, and the right view distorts the distance to far wall so they're viewed at 'infinity'. --- fenscaster.cpp | 115 +++++++++++++++++++++++++++++++++++++++++-------- matrix.hpp | 34 ++++++++++++--- 2 files changed, 126 insertions(+), 23 deletions(-) diff --git a/fenscaster.cpp b/fenscaster.cpp index 218ddfa..d37f68d 100644 --- a/fenscaster.cpp +++ b/fenscaster.cpp @@ -78,7 +78,7 @@ void draw_map(Fenster &window, Matrix &map) { } } -void draw_line(Fenster &window, Point start, Point end) { +void draw_line(Fenster &window, Point start, Point end, uint32_t color) { int x = int(start.x); int y = int(start.y); int x1 = int(end.x); @@ -102,7 +102,7 @@ void draw_line(Fenster &window, Point start, Point end) { y = y + sy; } - window.px(x, y) = rgba_color(200, 20, 20, 255); + window.px(x, y) = color; } } @@ -116,29 +116,110 @@ void clear(Fenster &window) { void draw_map_rays(Fenster &window, int col, int row, Point target) { draw_map_rect(window, col, row, rgba_color(100, 20, 20, 255)); - draw_line(window, {size_t(player_x), size_t(player_y)}, target); + draw_line(window, {size_t(player_x), size_t(player_y)}, target, rgba_color(200, 20, 20, 255)); } -void draw_3d_view(Fenster &window, int depth, float start_angle, int ray) { - uint8_t color = 255 / (1 + depth * depth * 0.0001); +void ray_casting(Fenster &window, Matrix& map) { + int w = THREED_VIEW_WIDTH; + int h = THREED_VIEW_HEIGHT; + + // x and y start position + double posX = player_x / TILE_SIZE; + double posY = player_y / TILE_SIZE; + + // initial direction vector + double dirX = std::cos(player_angle); + double dirY = 0; + + // the 2d raycaster version of camera plane + double planeX = 0; + double planeY = 0.66; + + // time of current frame + double time = 0; + // time of previous frame + double oldTime = 0; + + for(int x = 0; x < w; x++) { + // calculate ray position and direction + double cameraX = 2 * x / double(w) - 1; // x-coord in camera space + double rayDirX = dirX + planeX * cameraX; + double rayDirY = dirY + planeY * cameraX; + + // which box of the map we're in + int mapX = int(posX); + int mapY = int(posY); + + // length of ray from current pos to next x or y-side + double sideDistX; + double sideDistY; + + // length of ray from one x or y-side to next x or y-side + double deltaDistX = (rayDirX == 0) ? 1e30 : std::abs(1.0 / rayDirX); + double deltaDistY = (rayDirY == 0) ? 1e30 : std::abs(1.0 / rayDirY); + double perpWallDist; + + int stepX = 0; + int stepY = 0; + int hit = 0; + int side = 0; + + // calculate step and initial sideDist + if(rayDirX < 0) { + stepX = -1; + sideDistX = (posX - mapX) * deltaDistX; + } else { + stepX = 1; + sideDistX = (mapX + 1.0 - posX) * deltaDistX; + } - float fixed_depth = depth * std::cos(player_angle - start_angle); + if(rayDirY < 0) { + stepY = -1; + sideDistY = (posY - mapY) * deltaDistY; + } else { + stepY = 1; + sideDistY = (mapY + 1.0 - posY) * deltaDistY; + } - float wall_height = 21000 / fixed_depth; + // perform DDA + while(hit == 0) { + if(sideDistX < sideDistY) { + sideDistX += deltaDistX; + mapX += stepX; + side = 0; + } else { + sideDistY += deltaDistY; + mapY += stepY; + side = 1; + } - if(wall_height > window.height()){ - wall_height = window.height(); - } + if(map[mapY][mapX] > 0) hit = 1; + } - draw_rect(window, - {size_t(window.height() + ray * SCALE), - size_t((window.height() / 2) - wall_height / 2)}, - {size_t(SCALE), size_t(wall_height)}, - gray_color(color)); + if(side == 0) { + perpWallDist = (sideDistX - deltaDistX); + } else { + perpWallDist = (sideDistY - deltaDistY); + } + + int lineHeight = int(h / perpWallDist); + + int drawStart = -lineHeight / 2 + h / 2; + if(drawStart < 0) drawStart = 0; + + int drawEnd = lineHeight / 2 + h / 2; + if(drawEnd >= h) drawEnd = h - 1; + + uint32_t color = gray_color(std::min(lineHeight, 255)); + + draw_line(window, + {size_t(x + THREED_VIEW_WIDTH), size_t(drawStart)}, + {size_t(x + THREED_VIEW_WIDTH), size_t(drawEnd)}, color); + } } -void ray_casting(Fenster &window, Matrix& map) { +void map_view_casting(Fenster &window, Matrix& map) { float start_angle = player_angle - HALF_FOV; for(int ray = 0; ray < CASTED_RAYS; ray++, start_angle += STEP_ANGLE) @@ -152,7 +233,6 @@ void ray_casting(Fenster &window, Matrix& map) { if(map[row][col] == 1) { draw_map_rays(window, col, row, {size_t(target_x), size_t(target_y)}); - draw_3d_view(window, depth, start_angle, ray); break; } } @@ -174,6 +254,7 @@ void draw_everything(Fenster &window) { clear(window); draw_map(window, MAP); draw_ceiling_floor(window); + map_view_casting(window, MAP); ray_casting(window, MAP); } diff --git a/matrix.hpp b/matrix.hpp index e9266fa..e07488e 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -10,8 +10,15 @@ namespace matrix { using std::vector, std::queue, std::array; using std::min, std::max, std::floor; - typedef vector Row; - typedef vector Matrix; + template + using BaseRow = vector; + + template + using Base = vector>; + + using Row = vector; + using Matrix = vector; + /* * Just a quick thing to reset a matrix to a value. @@ -40,6 +47,17 @@ namespace matrix { return mat.size(); } + template + inline Base make_base(size_t width, size_t height) { + Base result(height, BaseRow(width)); + return result; + } + + inline Matrix make(size_t width, size_t height) { + Matrix result(height, Row(width)); + return result; + } + inline size_t next_x(size_t x, size_t width) { return (x + 1) * ((x + 1) < width); } @@ -150,6 +168,10 @@ namespace matrix { size_t bottom = 0; box_t(MAT &mat, size_t at_x, size_t at_y, size_t size) : + box_t(mat, at_x, at_y, size, size) { + } + + box_t(MAT &mat, size_t at_x, size_t at_y, size_t width, size_t height) : from_x(at_x), from_y(at_y) { size_t h = matrix::height(mat); @@ -157,15 +179,15 @@ namespace matrix { // keeps it from going below zero // need extra -1 to compensate for the first next() - left = max(from_x, size) - size; + left = max(from_x, width) - width; x = left - 1; // must be -1 for next() // keeps it from going above width - right = min(from_x + size + 1, w); + right = min(from_x + width + 1, w); // same for these two - top = max(from_y, size) - size; + top = max(from_y, height) - height; y = top - (left == 0); - bottom = min(from_y + size + 1, h); + bottom = min(from_y + height + 1, h); } bool next() {