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'.

master
Zed A. Shaw 2 months ago
parent 75a927e192
commit 96b44a4eb2
  1. 115
      fenscaster.cpp
  2. 34
      matrix.hpp

@ -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);
}

@ -10,8 +10,15 @@ namespace matrix {
using std::vector, std::queue, std::array;
using std::min, std::max, std::floor;
typedef vector<int> Row;
typedef vector<Row> Matrix;
template<typename T>
using BaseRow = vector<T>;
template<typename T>
using Base = vector<BaseRow<T>>;
using Row = vector<int>;
using Matrix = vector<Row>;
/*
* Just a quick thing to reset a matrix to a value.
@ -40,6 +47,17 @@ namespace matrix {
return mat.size();
}
template<typename T>
inline Base<T> make_base(size_t width, size_t height) {
Base<T> result(height, BaseRow<T>(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() {

Loading…
Cancel
Save