aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/raycast.zig67
1 files changed, 40 insertions, 27 deletions
diff --git a/src/raycast.zig b/src/raycast.zig
index aca7db0..3df8cef 100644
--- a/src/raycast.zig
+++ b/src/raycast.zig
@@ -107,22 +107,31 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
map: Map,
renderWall: RenderWallFunction,
) void {
- const floor = std.math.floor;
+ // This is a TERRIBLE hack: for whatever reason *linearly*
+ // interpolating on the direction vectors gives
+ // perspective-correct-seeming walls!
+ const cos_first = std.math.cos(self.ang + 0.5 * FOV);
+ const cos_last = std.math.cos(self.ang - 0.5 * FOV);
+ const sin_first = std.math.sin(self.ang + 0.5 * FOV);
+ const sin_last = std.math.sin(self.ang - 0.5 * FOV);
+
+ const cos_step = (cos_last - cos_first) / PlaneWidth;
+ const sin_step = (sin_last - sin_first) / PlaneWidth;
var col: i32 = 0;
- var ra: f32 = 0.5 * FOV + self.ang;
- const ra_step = FOV / PlaneWidth;
+ var cosra = cos_first;
+ var sinra = sin_first;
while (col < PlaneWidth) : ({
col += 1;
- ra -= ra_step;
+ cosra += cos_step;
+ sinra += sin_step;
}) {
- const cosra = std.math.cos(ra);
- const sinra = std.math.sin(ra);
-
// Observe that sqrt(1+tan^2) = abs(1/cos) sqrt(cos^2+sin^2) =
- // abs(1/cos). Similarly so for cot, hence we obtain the following
- // lengths for the hypotenuses assuming that x (respectively y) are
- // unit length and the angle is ra.
+ // abs(1/cos). Similarly so for cot, hence we obtain the
+ // following lengths for the hypotenuses assuming that x
+ // (respectively y) are unit length and the angle is ra. This
+ // for whatever reasons still works when we linearly interpolate
+ // on cos and sin!
const dy_for_x_step = std.math.fabs(1 / cosra);
const dx_for_y_step = std.math.fabs(1 / sinra);
@@ -132,8 +141,8 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
var dist_x: f32 = undefined;
var dist_y: f32 = undefined;
- var ipos_x: i32 = @floatToInt(i32, floor(self.pos_x));
- var ipos_y: i32 = @floatToInt(i32, floor(self.pos_y));
+ var ipos_x: i32 = @floatToInt(i32, std.math.floor(self.pos_x));
+ var ipos_y: i32 = @floatToInt(i32, std.math.floor(self.pos_y));
// looking right
if (cosra >= 0) {
@@ -171,12 +180,8 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
}) {
var cell = map.lookup(ipos_x, ipos_y);
- // the correct distance is the shortest distance from the plane
- // of projection to the point, that is, perpendicular distance
- const perp_distance = distance * std.math.cos(self.ang - ra);
-
// project the top of the wall
- const top = PlaneHeight / 2 + PlaneDist * (cell.height - self.height) / perp_distance;
+ const top = PlaneHeight / 2 + PlaneDist * (cell.height - self.height) / distance;
// We have a wall to draw if it protrudes above what we have so far drawn
if (top > highest_point) {
@@ -185,7 +190,7 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
if (top > PlaneHeight) still_drawing = false;
// compute the height of this wall
- const total_length = PlaneDist * cell.height / perp_distance;
+ const total_length = PlaneDist * cell.height / distance;
// as well as the fraction we'll be drawing
const draw_length = top - highest_point;
@@ -207,7 +212,7 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
// var y = @floatToInt(i32, top);
// while (y > @floatToInt(i32, highest_point)) : (y -= 1) {
// const index = @intCast(usize, col * @floatToInt(i32, PlaneHeight) + y);
- // self.z_buffer.set(index, perp_distance);
+ // self.z_buffer.set(index, distance);
// }
highest_point = top;
@@ -219,23 +224,31 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type {
pub fn renderFloorsToTexture(self: @This(), floors_image: Image, rendered_floors_texture: Texture, map: Map) !void {
var pixels = [_]Colour{Colour.Black} ** (PlaneWidth * PlaneHeight / 2);
- const ang_step = FOV / PlaneWidth;
+ // Again, another TERRIBLE hack: we do the same nasty linear
+ // interpolation trick and for whatever reason the floors look fine.
+ const cos_first = std.math.cos(self.ang + 0.5*FOV);
+ const sin_first = std.math.sin(self.ang + 0.5*FOV);
+ const cos_last = std.math.cos(self.ang - 0.5*FOV);
+ const sin_last = std.math.sin(self.ang - 0.5*FOV);
+
var row: usize = 0;
while (row < PlaneHeight / 2) : (row += 1) {
const row_dist = self.height * PlaneDist / @intToFloat(f32, row + 1);
+ const dx_step = row_dist * (cos_last - cos_first) / PlaneWidth;
+ const dy_step = row_dist * (sin_last - sin_first) / PlaneWidth;
+
var col: usize = 0;
- var ang = 0.5 * FOV + self.ang;
- var ang_diff: f32 = 0.5 * FOV;
+ var dx = row_dist * cos_first;
+ var dy = row_dist * sin_first;
while (col < PlaneWidth) : ({
col += 1;
- ang -= ang_step;
- ang_diff -= ang_step;
+ dx += dx_step;
+ dy += dy_step;
}) {
- const perp_dist = row_dist / std.math.cos(ang_diff);
- const x = self.pos_x + perp_dist * std.math.cos(ang);
- const y = self.pos_y + perp_dist * std.math.sin(ang);
+ const x = self.pos_x + dx;
+ const y = self.pos_y + dy;
const sx = std.math.modf(x);
const sy = std.math.modf(y);