diff --git a/src/render/cpu/pipeline.zig b/src/render/cpu/pipeline.zig index 49f3c0b..44817a4 100644 --- a/src/render/cpu/pipeline.zig +++ b/src/render/cpu/pipeline.zig @@ -112,16 +112,17 @@ pub const DrawContext = struct { }; } - /// Смешивает цвет в пикселе буфера (bx, by) с учётом opacity текущего трансформа. Bounds не проверяются. + /// Смешивает цвет в пикселе буфера (bx, by). color уже в PMA; opacity трансформа применяется к альфе и к RGB. pub fn blendPixelAtBuffer(self: *DrawContext, bx: u32, by: u32, color: Color.PMA) void { if (bx >= self.buf_width or by >= self.buf_height) return; const t = &self.transform; const idx = by * self.buf_width + bx; const dst = &self.pixels[idx]; const a = @as(f32, @floatFromInt(color.a)) / 255.0 * t.opacity; - const src_r = @as(f32, @floatFromInt(color.r)) * a; - const src_g = @as(f32, @floatFromInt(color.g)) * a; - const src_b = @as(f32, @floatFromInt(color.b)) * a; + // PMA: color.r/g/b уже помножены на color.a; при opacity только масштабируем их на t.opacity + const src_r = @as(f32, @floatFromInt(color.r)) * t.opacity; + const src_g = @as(f32, @floatFromInt(color.g)) * t.opacity; + const src_b = @as(f32, @floatFromInt(color.b)) * t.opacity; const inv_a = 1.0 - a; dst.r = @intFromFloat(std.math.clamp(src_r + inv_a * @as(f32, @floatFromInt(dst.r)), 0, 255)); dst.g = @intFromFloat(std.math.clamp(src_g + inv_a * @as(f32, @floatFromInt(dst.g)), 0, 255));