aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortslil clingman <>2021-09-22 22:46:47 -0400
committertslil clingman <>2021-09-22 22:59:31 -0400
commit9d25e1d69dede7d79ca9115a4ce4e65af49b8ddc (patch)
treeabb39414cfa08e09a0abb63a8a1809c39d790a11
parenta657cc828cdcbb07f460d53f78a12dfe00a57325 (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.
-rw-r--r--src/player.zig52
-rw-r--r--src/sfml/graphics/color.zig2
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),