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'.
This commit is contained in:
parent
75a927e192
commit
96b44a4eb2
2 changed files with 132 additions and 29 deletions
127
fenscaster.cpp
127
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);
|
||||
|
||||
float fixed_depth = depth * std::cos(player_angle - start_angle);
|
||||
|
||||
float wall_height = 21000 / fixed_depth;
|
||||
|
||||
if(wall_height > window.height()){
|
||||
wall_height = window.height();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(rayDirY < 0) {
|
||||
stepY = -1;
|
||||
sideDistY = (posY - mapY) * deltaDistY;
|
||||
} else {
|
||||
stepY = 1;
|
||||
sideDistY = (mapY + 1.0 - posY) * deltaDistY;
|
||||
}
|
||||
|
||||
// perform DDA
|
||||
while(hit == 0) {
|
||||
if(sideDistX < sideDistY) {
|
||||
sideDistX += deltaDistX;
|
||||
mapX += stepX;
|
||||
side = 0;
|
||||
} else {
|
||||
sideDistY += deltaDistY;
|
||||
mapY += stepY;
|
||||
side = 1;
|
||||
}
|
||||
|
||||
if(map[mapY][mapX] > 0) hit = 1;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
|
34
matrix.hpp
34
matrix.hpp
|
@ -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…
Add table
Add a link
Reference in a new issue