diff options
| author | tslil clingman <> | 2021-10-12 22:33:03 -0400 |
|---|---|---|
| committer | tslil clingman <> | 2021-10-12 22:33:03 -0400 |
| commit | 7fa4ae345c8c8483c0513b21eda7b612315c1a4c (patch) | |
| tree | 5587997f247ba1c5eee2cf02c5ab5e92eee9f869 /src | |
| parent | 739ae8d04c5fe4624501785b23b2e91886b3b149 (diff) | |
It almost works, but for some reason everything only has 3 sides...?
Diffstat (limited to 'src')
| -rw-r--r-- | src/level.zig | 9 | ||||
| -rw-r--r-- | src/render.zig | 239 |
2 files changed, 154 insertions, 94 deletions
diff --git a/src/level.zig b/src/level.zig index dce2a14..9f5217d 100644 --- a/src/level.zig +++ b/src/level.zig @@ -35,11 +35,12 @@ pub const Cell = struct { floor_texture: u8 = 0, ceiling_texture: u8 = 2, - vertices: [][2]f32 = [][2]f32{ + vertices: [5][2]f32 = [5][2]f32{ + .{ 0, 0 }, + .{ 0.5, 0 }, + .{ 0.5, 0.5 }, + .{ 0, 0.5 }, .{ 0, 0 }, - .{ 1, 0 }, - .{ 1, 1 }, - .{ 0, 1 }, }, pub const floor = Cell{}; diff --git a/src/render.zig b/src/render.zig index 5879b31..0e68a93 100644 --- a/src/render.zig +++ b/src/render.zig @@ -72,29 +72,26 @@ fn fasterColourBlend(onto: Colour, from: Colour) Colour { fn hitDistLocalCoords( ray0: [2]f32, ray1: [2]f32, - vertices: [][2]f32, + vertices: []const [2]f32, ) ?f32 { const rdy = ray1[1] - ray0[1]; const rdx = ray1[0] - ray0[0]; var vp = vertices[0]; var crossp: f32 = rdy * (vp[0] - ray0[0]) - rdx * (vp[1] - ray0[1]); - - // TODO: there is currently a bug in the logic, if vp->v is parallel to - // ray0->ray1, then we'll return the distance ray0->vp (even if v is - // closer). This is incorrect. + var return_val: ?f32 = null; if (crossp == 0) { // hit a vertex exactly const dx = vp[0] - ray0[0]; const dy = vp[1] - ray0[1]; - return math.sqrt(dx * dx + dy * dy); + return std.math.sqrt(dx * dx + dy * dy); } var i: usize = 1; var v = vertices[i]; var cross: f32 = rdy * (v[0] - ray0[0]) - rdx * (v[1] - ray0[1]); - while (i < vertices.len) : ({ + while (i + 1< vertices.len) : ({ i += 1; vp = v; v = vertices[i]; @@ -104,7 +101,12 @@ fn hitDistLocalCoords( if (cross == 0) { const dx = v[0] - ray0[0]; const dy = v[1] - ray0[1]; - return math.sqrt(dx * dx + dy * dy); + const new_distance = std.math.sqrt(dx * dx + dy * dy); + if (return_val) |local_distance| { + if (new_distance < local_distance) return_val = new_distance; + } else { + return_val = new_distance; + } } else { if (crossp * cross < 0) { // If the segment from ray0->ray1 has vp and v on opposite sides @@ -115,13 +117,21 @@ fn hitDistLocalCoords( const vdx = v[0] - vp[0]; const vdy = v[1] - vp[1]; - const dx = rdx * cross; // this should really be negative, but we square it... - const dy = rdy * (vdx * (ray0[1] - v[1]) - vdy * (ray0[0] - v[0])); - return math.sqrt(dx * dx + dy * dy) / (rdx * vdy - vdx * rdy); + const t = (vdx * (ray0[1] - v[1]) - vdy * (ray0[0] - v[0])) / (rdx * vdy - vdx * rdy); + const new_distance = std.math.sqrt(rdx * rdx + rdy * rdy) * t; + // const s = cross / (rdx * vdy - vdx * rdy); + // const dx = v[0] + vdx * s - ray0[0]; + // const dy = v[1] + vdy * s - ray0[1]; + // const new_distance = std.math.sqrt(dx * dx + dy * dy); + if (return_val) |local_distance| { + if (new_distance < local_distance) return_val = new_distance; + } else { + return_val = new_distance; + } } } } - return null; + return return_val; } pub fn Renderer(PlaneWidth: f32, PlaneHeight: f32) type { @@ -328,128 +338,177 @@ pub fn Renderer(PlaneWidth: f32, PlaneHeight: f32) type { var top_of_floor: f32 = undefined; var bottom_of_ceiling: f32 = undefined; + var distance: f32 = 0; - var still_drawing = true; + var next_distance: f32 = 0; + var hit_horizontal: bool = undefined; + var next_hit_horizontal: bool = undefined; + + if (dist_y < dist_x) { + hit_horizontal = false; + distance = dist_y; + dist_y += dy_for_x_step; + ipos_x += step_x; + } else { + hit_horizontal = true; + distance = dist_x; + dist_x += dx_for_y_step; + ipos_y += step_y; + } + + if (dist_y < dist_x) { + next_hit_horizontal = false; + next_distance = dist_y; + } else { + next_hit_horizontal = true; + next_distance = dist_x; + } + var highest_drawn: f32 = 0; var lowest_drawn: f32 = PlaneHeight - 1; - var horizontal_hit: bool = undefined; + var still_drawing = true; + while (still_drawing and map.inBounds(ipos_x, ipos_y)) : ({ // Find the next cell on our path if (dist_y < dist_x) { - horizontal_hit = false; + hit_horizontal = false; distance = dist_y; dist_y += dy_for_x_step; ipos_x += step_x; } else { - horizontal_hit = true; + hit_horizontal = true; distance = dist_x; dist_x += dx_for_y_step; ipos_y += step_y; } + + if (dist_y < dist_x) { + next_distance = dist_y; + next_hit_horizontal = false; + } else { + next_distance = dist_x; + next_hit_horizontal = true; + } }) { const cell = map.lookup(ipos_x, ipos_y); // Are we drawing vertical surfaces? if (cell.floor_height > 0 or cell.draw_down) { - if (hitDistLocalCoords(ray0, ray1, cell.vertices)) |local_distance| { + const ray0: [2]f32 = if (hit_horizontal) + [2]f32{ + std.math.modf(distance * cosra + ppos_x).fpart, + (if (step_y > 0) 0 else 1), + } + else + [2]f32{ + (if (step_x > 0) 0 else 1), + std.math.modf(distance * sinra + ppos_y).fpart, + }; - } - // project the top of the bottom and the bottom of the top - top_of_floor = PlaneHeight / 2 + PlaneDist * (cell.floor_height - pheight) / distance; - bottom_of_ceiling = PlaneHeight / 2 + PlaneDist * (cell.ceiling_height - pheight) / distance; + const ray1: [2]f32 = if (next_hit_horizontal) + [2]f32{ + std.math.modf(next_distance * cosra + ppos_x).fpart, + (if (step_y > 0) 1 else 0), + } + else + [2]f32{ + (if (step_x > 0) 1 else 0), + std.math.modf(next_distance * sinra + ppos_y).fpart, + }; + + if (hitDistLocalCoords(ray0, ray1, &cell.vertices)) |local_distance| { + const adj_distance = distance + local_distance; + + // project the top of the bottom and the bottom of the top + top_of_floor = PlaneHeight / 2 + PlaneDist * (cell.floor_height - pheight) / adj_distance; + bottom_of_ceiling = PlaneHeight / 2 + PlaneDist * (cell.ceiling_height - pheight) / adj_distance; - const draw_lower = top_of_floor > highest_drawn; - const draw_upper = cell.draw_down and bottom_of_ceiling < lowest_drawn; + const draw_lower = cell.floor_height > 0 and top_of_floor > highest_drawn; + const draw_upper = cell.draw_down and bottom_of_ceiling < lowest_drawn; - // Are we able to see any vertical faces? - if (draw_upper or draw_lower) { - // we need the distance to calculate the fractional - // part of the relevant coordinate for texture - // mapping of the walls - const hit_coordinate = if (horizontal_hit) distance * cosra + ppos_x else distance * sinra + ppos_y; - var texfrac = std.math.modf(hit_coordinate).fpart; + // Are we able to see any vertical faces? + if (draw_upper or draw_lower) { + // we need the distance to calculate the fractional + // part of the relevant coordinate for texture + // mapping of the walls + var texfrac = if (hit_horizontal) ray0[0] else ray0[1]; - // we also want to be sure that we're consistently orienting - // textures, in this case clockwise - if ((horizontal_hit and sinra < 0) or (!horizontal_hit and cosra > 0)) texfrac = 1 - texfrac; - const texstrip = @floatToInt(c_uint, constants.TextureDim * texfrac); + // we also want to be sure that we're consistently orienting + // textures, in this case clockwise + if ((hit_horizontal and sinra < 0) or (!hit_horizontal and cosra > 0)) texfrac = 1 - texfrac; + const texstrip = @floatToInt(c_uint, constants.TextureDim * texfrac); - // height of a unit-height wall at this distance - const nominal_length = PlaneDist / distance; - // used for texel indexing - const inv_nom_len = distance / PlaneDist; + // height of a unit-height wall at this distance + const nominal_length = PlaneDist / adj_distance; + // used for texel indexing + const inv_nom_len = adj_distance / PlaneDist; - const td = @floatToInt(c_uint, constants.TextureDim); - if (draw_lower) { - // which texture index? - const t_lower_off = cell.lower_texture * td; - // Note the bizarre rounding we have to do to avoid artifacts - const constrained_top = std.math.floor(std.math.min(top_of_floor, lowest_drawn)); - const proj_height = cell.floor_height * nominal_length; - const constrained_bottom = std.math.max(highest_drawn, top_of_floor - proj_height); - const stop = @floatToInt(usize, PlaneWidth * (PlaneHeight - constrained_bottom)) + col; - const pix_y = @floatToInt(usize, std.math.ceil(std.math.max(PlaneHeight - constrained_top - 1, 0))); - var pix_index = pix_y * @floatToInt(usize, PlaneWidth) + col; - var texel_y: f32 = std.math.max((top_of_floor - constrained_top) / nominal_length, 0); + const td = @floatToInt(c_uint, constants.TextureDim); + if (draw_lower) { + // which texture index? + const t_lower_off = cell.lower_texture * td; + // Note the bizarre rounding we have to do to avoid artifacts + const constrained_top = std.math.floor(std.math.min(top_of_floor, lowest_drawn)); + const proj_height = cell.floor_height * nominal_length; + const constrained_bottom = std.math.max(highest_drawn, top_of_floor - proj_height); + const stop = @floatToInt(usize, PlaneWidth * (PlaneHeight - constrained_bottom)) + col; + const pix_y = @floatToInt(usize, std.math.ceil(std.math.max(PlaneHeight - constrained_top - 1, 0))); + var pix_index = pix_y * @floatToInt(usize, PlaneWidth) + col; + var texel_y: f32 = std.math.max((top_of_floor - constrained_top) / nominal_length, 0); - // now we have what we need to draw the face, - // and update the z-buffer. - while (pix_index < stop) : ({ - pix_index += @floatToInt(usize, PlaneWidth); - texel_y += inv_nom_len; - }) { - const ty = @floatToInt(c_uint, std.math.modf(texel_y).fpart * constants.TextureDim); - const texel = walls_image.getPixel(.{ .x = t_lower_off + texstrip, .y = ty }); + // now we have what we need to draw the face, + // and update the z-buffer. + while (pix_index < stop) : ({ + pix_index += @floatToInt(usize, PlaneWidth); + texel_y += inv_nom_len; + }) { + const ty = @floatToInt(c_uint, std.math.modf(texel_y).fpart * constants.TextureDim); + const texel = walls_image.getPixel(.{ .x = t_lower_off + texstrip, .y = ty }); - pixels[pix_index] = texel; - self.z_buffer[pix_index] = distance; + pixels[pix_index] = texel; + self.z_buffer[pix_index] = adj_distance; + } + highest_drawn = constrained_top; } - highest_drawn = constrained_top; - } - if (draw_upper) { - const proj_default_end = PlaneHeight / 2 + PlaneDist * (level.Cell.DEFAULT_HEIGHT - pheight) / distance; - const constrained_top = std.math.min(lowest_drawn, proj_default_end); - const constrained_bottom = std.math.ceil(std.math.max(bottom_of_ceiling, highest_drawn)); - const stop = @floatToInt(usize, PlaneWidth * (PlaneHeight - constrained_bottom)) + col; - const t_upper_off = cell.upper_texture * td; - const pix_y = @floatToInt(usize, std.math.ceil(std.math.max(PlaneHeight - constrained_top - 1, 0))); - var pix_index = pix_y * @floatToInt(usize, PlaneWidth) + col; - var texel_y: f32 = constants.TextureDim - (constrained_top - constrained_bottom) / nominal_length; - while (pix_index < stop) : ({ - pix_index += @floatToInt(usize, PlaneWidth); - texel_y += inv_nom_len; - }) { - const ty = @floatToInt(c_uint, std.math.modf(texel_y).fpart * constants.TextureDim); - const texel = walls_image.getPixel(.{ .x = t_upper_off + texstrip, .y = ty }); + if (draw_upper) { + const proj_default_end = PlaneHeight / 2 + PlaneDist * (level.Cell.DEFAULT_HEIGHT - pheight) / adj_distance; + const constrained_top = std.math.min(lowest_drawn, proj_default_end); + const constrained_bottom = std.math.ceil(std.math.max(bottom_of_ceiling, highest_drawn)); + const stop = @floatToInt(usize, PlaneWidth * (PlaneHeight - constrained_bottom)) + col; + const t_upper_off = cell.upper_texture * td; + const pix_y = @floatToInt(usize, std.math.ceil(std.math.max(PlaneHeight - constrained_top - 1, 0))); + var pix_index = pix_y * @floatToInt(usize, PlaneWidth) + col; + var texel_y: f32 = constants.TextureDim - (constrained_top - constrained_bottom) / nominal_length; + while (pix_index < stop) : ({ + pix_index += @floatToInt(usize, PlaneWidth); + texel_y += inv_nom_len; + }) { + const ty = @floatToInt(c_uint, std.math.modf(texel_y).fpart * constants.TextureDim); + const texel = walls_image.getPixel(.{ .x = t_upper_off + texstrip, .y = ty }); - pixels[pix_index] = texel; - self.z_buffer[pix_index] = distance; + pixels[pix_index] = texel; + self.z_buffer[pix_index] = adj_distance; + } + lowest_drawn = constrained_bottom; } - lowest_drawn = constrained_bottom; } } } // do we potentially draw floor and or ceiling for this cell? if (highest_drawn < PlaneHeight / 2 or (cell.draw_down and lowest_drawn > PlaneHeight / 2)) { - if (dist_y < dist_x) { - distance = dist_y; - } else { - distance = dist_x; - } - // Note: next_top can never exceed PlaneHeight / 2 in // the body of the next block. If the wall is taller // than us the back edge is lower than the front one so // this check will fail as we just drew it (or higher // than it). If the wall is shorter then the back edge // is at most the horizon. Similarly so for next_bottom - const next_top = PlaneHeight / 2 + PlaneDist * (cell.floor_height - pheight) / distance; - const next_bottom = PlaneHeight / 2 + PlaneDist * (cell.ceiling_height - pheight) / distance; + const next_top = PlaneHeight / 2 + PlaneDist * (cell.floor_height - pheight) / next_distance; + const next_bottom = PlaneHeight / 2 + PlaneDist * (cell.ceiling_height - pheight) / next_distance; // draw floor? - if (next_top > highest_drawn) { + if (false and next_top > highest_drawn) { const toff = cell.floor_texture * @floatToInt(c_uint, constants.TextureDim); top_of_floor = std.math.ceil(std.math.min(std.math.min(next_top, lowest_drawn), PlaneHeight / 2 - 1)); @@ -478,7 +537,7 @@ pub fn Renderer(PlaneWidth: f32, PlaneHeight: f32) type { } // draw ceiling? - if (cell.draw_down and next_bottom < lowest_drawn) { + if (false and cell.draw_down and next_bottom < lowest_drawn) { const toff = cell.ceiling_texture * @floatToInt(c_uint, constants.TextureDim); bottom_of_ceiling = std.math.ceil(lowest_drawn); |
