diff options
| author | tslil clingman <> | 2021-09-01 13:57:08 -0400 |
|---|---|---|
| committer | tslil clingman <> | 2021-09-01 14:03:40 -0400 |
| commit | c97c9fc4203dc12982b590d3bfae1d419cf59fbe (patch) | |
| tree | a096a8514da1d5fd25d8fade4c7322d4a5f773c2 /src | |
| parent | dae5c3d1e9bdbabf94f79960b2fca9a5f47b7ac0 (diff) | |
Variable height walls!
Diffstat (limited to 'src')
| -rw-r--r--[-rwxr-xr-x] | src/main.zig | 26 | ||||
| -rw-r--r-- | src/raycast.zig | 51 |
2 files changed, 48 insertions, 29 deletions
diff --git a/src/main.zig b/src/main.zig index e912b5f..64da425 100755..100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,4 +1,4 @@ -// ZiRC, a Zig raycaster for fun +// ZiRC, a Zig raycaster for fun // // Copyright (C) 2021, tslil clingman // @@ -31,25 +31,33 @@ usingnamespace @import("map.zig"); const screenWidth = 1280; const screenHeight = 960; +// TODO: is there anyway i can say fn renderWall : RenderWallFunction? fn renderWall( window: sf.graphics.RenderWindow, sprite: sf.graphics.Sprite, col: i32, // which column top: f32, // top of wall - height: f32, // how tall + total_height: f32, // how tall + draw_frac: f32, texfrac: f32, // how far along the texture texture: u8, // which texture index -) !void { +) void { const hFact = screenWidth / planeWidth; const vFact = screenHeight / planeHeight; + + // we need ceil here so that we draw always to or past the edge of the screen + const draw_height = @floatToInt(c_int, std.math.ceil(draw_frac * wallTextureDim)); + const total_length = total_height * vFact; + const xpos = @intToFloat(f32, col) * hFact; - const length = height * vFact; - const starty = (screenHeight + vFact * planeHeight) / 2 - top * vFact; + const ypos = (screenHeight + vFact * planeHeight) / 2 - top * vFact; + const tind = @as(c_int, texture) * @floatToInt(c_int, 1 + wallTextureDim); + const left = tind + @floatToInt(c_int, texfrac * wallTextureDim); - sprite.setPosition(.{ .x = xpos, .y = starty }); - sprite.setScale(.{ .x = hFact, .y = length / wallTextureDim }); - sprite.setTextureRect(.{ .top = 0, .left = tind + @floatToInt(c_int, texfrac * wallTextureDim), .width = 1, .height = wallTextureDim }); + sprite.setPosition(.{ .x = xpos, .y = ypos }); + sprite.setScale(.{ .x = hFact, .y = total_length / wallTextureDim }); + sprite.setTextureRect(.{ .top = 0, .left = left, .width = 1, .height = draw_height }); window.draw(sprite, null); } @@ -165,7 +173,7 @@ pub fn main() !void { }); window.draw(backSprite, null); - try player.renderMapUsing(window, wallSprite, map, renderWall); + player.renderMapUsing(window, wallSprite, map, renderWall); window.display(); diff --git a/src/raycast.zig b/src/raycast.zig index dec6b46..6acc16b 100644 --- a/src/raycast.zig +++ b/src/raycast.zig @@ -27,10 +27,11 @@ pub const RenderWallFunction: type = fn ( sprite: Sprite, col: i32, // which column we're in top: f32, // top of wall - length: f32, + draw_frac: f32, + length: f32, // length of slice to be drawn texfrac: f32, texture: u8, // which texture index -) anyerror!void; // TODO: narrow this error type. +) void; pub const Player = struct { pos_x: f32, @@ -87,7 +88,7 @@ pub const Player = struct { map: Map, // the abstract the rendering call renderWall: RenderWallFunction, - ) !void { + ) void { const floor = std.math.floor; var col: i32 = 0; @@ -133,6 +134,7 @@ pub const Player = struct { var distance: f32 = 0; var still_drawing = true; + var highest_point: f32 = 0; var horizontal_hit: bool = undefined; while (still_drawing) { @@ -153,28 +155,37 @@ pub const Player = struct { var cell = map.lookup(ipos_x, ipos_y); - // We have a wall to draw - if (cell.height > 0) { - // before we correct the distance to be the perpedicular - // distance from the plane of projection, we need to use it - // to calculate the fractional part of the relevant - // coordinate + // 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 = self.plane_height / 2 + self.plane_dist * (cell.height - self.height) / perp_distance; + + // We have a wall to draw if it protrudes above what we have so far drawn + if (top > highest_point) { + + // did we extend beyond the top of the plane? + if (top > self.plane_height) still_drawing = false; + + // compute the height of this wall + const total_length = self.plane_dist * cell.height / perp_distance; + + // as well as the fraction we'll be drawing + const draw_frac = std.math.min(1, (top - highest_point) / total_length); + + // we need the raw Euclidean distance to calculate the + // fractional part of the relevant coordinate for texture + // mapping of the walls const hit_coordinate = if (horizontal_hit) distance * cosra + self.pos_x else distance * sinra + self.pos_y; var texfrac = std.math.modf(hit_coordinate).fpart; - // we also want to be sure that we're consistently orienting these, say clockwise + // 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; - // now correct the distance to be the shortest distance from - // the plane to the point, that is, perpendicular distance - distance *= std.math.cos(self.ang - ra); - - // project the top of the wall - const top = self.plane_height / 2 + self.plane_dist * (cell.height - self.height) / distance; - const height = self.plane_dist * cell.height / distance; - - try renderWall(window, sprite, col, top, height, texfrac, cell.wall_texture); + renderWall(window, sprite, col, top, total_length, draw_frac, texfrac, cell.wall_texture); - still_drawing = false; + highest_point = top; } } } |
