aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortslil clingman <>2021-09-20 22:38:04 -0400
committertslil clingman <>2021-09-20 22:41:32 -0400
commita657cc828cdcbb07f460d53f78a12dfe00a57325 (patch)
treee36103062a0ff28cfb02a74107c7abd9c70713d0 /src
parent276804c4b8db837e238880d4bc668ed6c65dd42a (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/main.zig10
-rw-r--r--src/player.zig72
2 files changed, 36 insertions, 46 deletions
diff --git a/src/main.zig b/src/main.zig
index 283de07..3c95d20 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -90,12 +90,8 @@ pub fn main() !void {
defer walls_image.destroy();
// Load sprite textures
- var object_textures = try sf.Texture.createFromFile("objects.png");
- defer object_textures.destroy();
- object_textures.setSmooth(false);
-
- var objects_sprite = try sf.Sprite.createFromTexture(object_textures);
- defer objects_sprite.destroy();
+ var objects_image = try sf.Image.createFromFile("objects.png");
+ defer objects_image.destroy();
// Load floor image
var surfaces_image = try sf.Image.createFromFile("surfaces.png");
@@ -171,7 +167,7 @@ pub fn main() !void {
try player.renderWorld(
window,
- objects_sprite,
+ objects_image,
walls_image,
surfaces_image,
rendered_surfaces_texture,
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);
}
}
}