Skip to main content

ass_renderer/pipeline/compositing/
mod.rs

1//! Layer compositing module
2
3#[cfg(feature = "nostd")]
4use alloc::{vec, vec::Vec};
5#[cfg(not(feature = "nostd"))]
6use std::vec::Vec;
7
8use crate::pipeline::IntermediateLayer;
9use crate::utils::RenderError;
10
11/// Compositing mode
12#[derive(Debug, Clone, Copy)]
13pub enum CompositeMode {
14    /// Normal alpha blending
15    Normal,
16    /// Additive blending
17    Add,
18    /// Multiply blending
19    Multiply,
20    /// XOR blending for shapes
21    Xor,
22}
23
24/// Composite multiple layers into a single buffer
25pub fn composite_layers(
26    layers: &[IntermediateLayer],
27    width: u32,
28    height: u32,
29) -> Result<Vec<u8>, RenderError> {
30    let mut output = vec![0u8; (width * height * 4) as usize];
31
32    for layer in layers {
33        composite_layer(layer, &mut output, width, height)?;
34    }
35
36    Ok(output)
37}
38
39/// Composite a single layer onto the output buffer
40fn composite_layer(
41    layer: &IntermediateLayer,
42    output: &mut [u8],
43    width: u32,
44    height: u32,
45) -> Result<(), RenderError> {
46    // TODO: Implement proper compositing
47    let _ = (layer, output, width, height);
48    Ok(())
49}
50
51/// Apply alpha blending using libass-compatible formula
52///
53/// Uses integer arithmetic with specific rounding to match libass exactly:
54/// - Multiply and add 255 for rounding bias
55/// - Right shift by 8 instead of division by 255
56/// - This matches libass's MUL_BITMAPS/IMUL_BITMAPS operations
57pub fn alpha_blend(src: [u8; 4], dst: [u8; 4]) -> [u8; 4] {
58    // Use integer arithmetic matching libass implementation
59    let src_alpha = src[3] as u32;
60
61    if src_alpha == 0 {
62        // Fully transparent source, keep destination
63        return dst;
64    }
65
66    if src_alpha == 255 && dst[3] == 0 {
67        // Opaque source over transparent destination
68        return src;
69    }
70
71    // libass uses this formula: ((src * alpha + 255) >> 8)
72    // The +255 provides rounding bias to match libass exactly
73    let inv_src_alpha = 255 - src_alpha;
74
75    // Blend colors using libass formula with rounding
76    let out_r = ((src[0] as u32 * src_alpha + dst[0] as u32 * inv_src_alpha + 255) >> 8) as u8;
77    let out_g = ((src[1] as u32 * src_alpha + dst[1] as u32 * inv_src_alpha + 255) >> 8) as u8;
78    let out_b = ((src[2] as u32 * src_alpha + dst[2] as u32 * inv_src_alpha + 255) >> 8) as u8;
79
80    // Alpha calculation using same integer formula
81    let dst_alpha = dst[3] as u32;
82    let out_alpha = ((src_alpha * 255 + dst_alpha * inv_src_alpha + 255) >> 8) as u8;
83
84    [out_r, out_g, out_b, out_alpha]
85}