diff options
| author | tslil clingman <> | 2021-09-22 22:46:47 -0400 |
|---|---|---|
| committer | tslil clingman <> | 2021-09-22 22:59:31 -0400 |
| commit | 9d25e1d69dede7d79ca9115a4ce4e65af49b8ddc (patch) | |
| tree | abb39414cfa08e09a0abb63a8a1809c39d790a11 /src | |
| parent | a657cc828cdcbb07f460d53f78a12dfe00a57325 (diff) | |
Colour blending
Some amount of work went into finding appropriate integer arithmetic
formulae that were reasonably accurate. At this point i've settled for
the incorrect-but-faster version. The better-though-slower formulas
are still there in case i change my mind.
It would help to have an assumption such as, but not limited to, the
surfaces are always going to be fully opaque.
Diffstat (limited to 'src')
| -rw-r--r-- | src/player.zig | 52 | ||||
| -rw-r--r-- | src/sfml/graphics/color.zig | 2 |
2 files changed, 41 insertions, 13 deletions
diff --git a/src/player.zig b/src/player.zig index 8ad3a1e..e69b3ce 100644 --- a/src/player.zig +++ b/src/player.zig @@ -35,6 +35,42 @@ fn playerDistComp(pos: [2]f32, lhs: level.Object, rhs: level.Object) bool { return (lx * lx + ly * ly > rx * rx + ry * ry); } +fn fasterColourBlend(onto: Colour, from: Colour) Colour { + const af: u16 = from.a; + const of: u16 = onto.a; + + const na: u16 = af + @divTrunc(of * (255 - af), 255); + if (na == 0) return Colour.Black; + + const rf: u16 = from.r; + const ro: u16 = onto.r; + const gf: u16 = from.g; + const go: u16 = onto.g; + const bf: u16 = from.b; + const bo: u16 = onto.b; + + // These computations are expensive, but more accurate + // const nr = @divTrunc(af * rf, na) + ro - @divTrunc(af * ro, na); + // const ng = @divTrunc(af * gf, na) + go - @divTrunc(af * go, na); + // const nb = @divTrunc(af * bf, na) + bo - @divTrunc(af * bo, na); + + // These computations are incorrect, but fast + const nr = (af * rf + (255 - af) * ro) / 255; + const ng = (af * gf + (255 - af) * go) / 255; + const nb = (af * bf + (255 - af) * bo) / 255; + + // The most accurate i've found is @divTrunc(ro * na + (rf - ro) * af, na); + // but this requires using signed integers, for which presumably division is + // slower still + + return Colour{ + .a = @intCast(u8, na), + .r = @intCast(u8, nr), + .g = @intCast(u8, ng), + .b = @intCast(u8, nb), + }; +} + pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { const FOV: f32 = std.math.pi / 3.0; const PlanePixels = PlaneWidth * PlaneHeight; @@ -144,17 +180,11 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { // then render the ceilings to our pixel array self.renderCeilingsToTexture(surfaces_image, map, &pixels); - // we're now ready to draw the surfaces - try rendered_surfaces_texture.updateFromPixels(&pixels, null); - window.draw(rendered_surfaces_sprite, null); - - // 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); + // use the z_buffer to render sprites self.renderObjects(objects_image, map, &pixels); + try rendered_surfaces_texture.updateFromPixels(&pixels, null); window.draw(rendered_surfaces_sprite, null); - } fn renderObjects( @@ -236,10 +266,8 @@ pub fn Player(PlaneWidth: f32, PlaneHeight: f32) type { 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; + // TODO: Decide whether being accurate is as important as being fast + pixels[pix_index] = fasterColourBlend(pixels[pix_index], texel); } } } diff --git a/src/sfml/graphics/color.zig b/src/sfml/graphics/color.zig index d6aa850..5555c22 100644 --- a/src/sfml/graphics/color.zig +++ b/src/sfml/graphics/color.zig @@ -55,7 +55,7 @@ pub const Color = packed struct { } /// Creates a color with rgba floats from 0 to 1 - fn fromFloats(red: f32, green: f32, blue: f32, alpha: f32) Color { + pub fn fromFloats(red: f32, green: f32, blue: f32, alpha: f32) Color { return Color{ .r = @floatToInt(u8, math.clamp(red, 0.0, 1.0) * 255.0), .g = @floatToInt(u8, math.clamp(green, 0.0, 1.0) * 255.0), |
