From a657cc828cdcbb07f460d53f78a12dfe00a57325 Mon Sep 17 00:00:00 2001 From: tslil clingman <> Date: Mon, 20 Sep 2021 22:38:04 -0400 Subject: Render objects by writing pixels This confines hardware acceleration to scaling and the background sprite. Unfortunately it would seem that to do proper object rendering (partial transparency) i'll have to implement colour mixing myself. --- src/player.zig | 72 +++++++++++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) (limited to 'src/player.zig') diff --git a/src/player.zig b/src/player.zig index 98f0b47..8ad3a1e 100644 --- a/src/player.zig +++ b/src/player.zig @@ -26,32 +26,6 @@ const Colour = @import("sfml").graphics.Color; const level = @import("level.zig"); const constants = @import("constants.zig"); -fn renderSlice( - window: RenderWindow, - sprite: Sprite, - col: i32, // which column - top: f32, // top of wall - height: f32, // how tall - draw_frac: f32, // how much to draw, as a fraction; > 1 means repeat texture - texfrac: f32, // how far along the texture - texture: u8, // which texture index -) void { - // 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 * constants.TextureDim)); - const total_height = height * constants.VFact; - - const xpos = @intToFloat(f32, col) * constants.HFact; - const ypos = constants.ScreenHeight / 2 + (constants.PlaneHeight / 2 - top) * constants.VFact; - - const tind = texture * @floatToInt(c_int, constants.TextureDim); - const left = tind + @floatToInt(c_int, texfrac * constants.TextureDim); - - sprite.setPosition(.{ .x = xpos, .y = ypos }); - sprite.setScale(.{ .x = constants.HFact, .y = total_height / constants.TextureDim }); - sprite.setTextureRect(.{ .top = 0, .left = left, .width = 1, .height = draw_height }); - window.draw(sprite, null); -} - fn playerDistComp(pos: [2]f32, lhs: level.Object, rhs: level.Object) bool { const lx = lhs.pos_x - pos[0]; const ly = lhs.pos_y - pos[1]; @@ -148,7 +122,7 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { pub fn renderWorld( self: *@This(), window: RenderWindow, - objects_sprite: Sprite, + objects_image: Image, walls_image: Image, surfaces_image: Image, rendered_surfaces_texture: Texture, @@ -161,7 +135,7 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { self.z_buffer.set(i, std.math.inf(f32)); } - var pixels = [_]Colour{Colour.fromRGBA(0, 0, 0, 0)} ** (PlaneWidth * PlaneHeight); + var pixels = [_]Colour{Colour.Transparent} ** (PlaneWidth * PlaneHeight); // then draw all the walls and populate the z_buffer, while also // rendering the surfaces below the horizon to the pixel array @@ -174,15 +148,20 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { try rendered_surfaces_texture.updateFromPixels(&pixels, null); window.draw(rendered_surfaces_sprite, null); - // use the z_buffer to render sprites - self.renderObjects(window, objects_sprite, map); + // TODO: use the z_buffer to render sprites, reset the + // pixel array as a cheap hack to avoid colour mixing ... + pixels = [_]Colour{Colour.Transparent} ** (PlaneWidth * PlaneHeight); + self.renderObjects(objects_image, map, &pixels); + try rendered_surfaces_texture.updateFromPixels(&pixels, null); + window.draw(rendered_surfaces_sprite, null); + } fn renderObjects( self: @This(), - window: RenderWindow, - objects_sprite: Sprite, + objects_image: Image, map: level.Map, + pixels: []Colour, ) void { std.sort.sort(level.Object, map.objects.items, // Wow, context with an arbitrary type! No macros, just @@ -229,25 +208,40 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { // Something is on the screen, let's draw it! const start = std.math.max(0, left); - const end = @floatToInt(i32, std.math.min(left + width, PlaneWidth - 1)); + const end = @floatToInt(usize, std.math.min(left + width, PlaneWidth - 1)); + + const inv_height = 1 / height; var tex_frac: f32 = std.math.clamp((start - left) / width, 0, 1); - var col: i32 = @floatToInt(i32, start); + var col: usize = @floatToInt(usize, start); const tex_frac_step = 1 / width; while (col < end) : ({ col += 1; tex_frac += tex_frac_step; }) { var bottom = std.math.min(top, PlaneHeight); - while (bottom >= 0 and bottom >= top - height) : (bottom -= 1) { - const index = @intCast(usize, col * @floatToInt(i32, PlaneHeight) + @floatToInt(i32, bottom)); + var pix_y = @floatToInt(usize, std.math.ceil(std.math.max(PlaneHeight - bottom, 0))); + var texel_y = (top - bottom) / height; + while (pix_y < PlaneHeight and bottom >= top - height) : ({ + bottom -= 1; + pix_y += 1; + texel_y += inv_height; + }) { + const index = col * @floatToInt(usize, PlaneHeight) + @floatToInt(usize, bottom); if (self.z_buffer.get(index) < scaled_perp_distance) { - bottom += 1; break; + } else { + const tx = @floatToInt(c_uint, tex_frac * constants.TextureDim); + const toff = obj.texture * @floatToInt(c_uint, constants.TextureDim); + const ty = @floatToInt(c_uint, texel_y * constants.TextureDim); + const texel = objects_image.getPixel(.{ .x = toff + tx, .y = ty }); + const pix_index = @floatToInt(usize, PlaneWidth) * pix_y + col; + // TODO: currently i have a cheap hack to + // avoid colour mixing. Is there a better + // way to do this? + pixels[pix_index] = texel; } } - const draw_frac = std.math.clamp((top - bottom) / height, 0, 1); - renderSlice(window, objects_sprite, col, top, height, draw_frac, tex_frac, obj.texture); } } } -- cgit v1.3.1