use iridia_interface::{BlendFactor, OutputUse, RenderState};
use crate::flow::Node;
use crate::{Interface, ProgramGraph, SystemValue};
pub fn output_uses(
interface: &Interface,
graph: Option<&ProgramGraph>,
state: &RenderState,
) -> Vec<OutputUse> {
let tested = graph.map(|g| {
g.values
.reached_from(g.values.discards().iter().flatten().copied())
});
interface
.outputs
.iter()
.filter_map(|v| {
let target = match v.system {
None => v.label.index,
Some(SystemValue::Target(n)) => n,
Some(_) => return None,
};
let blend_weight = if weighs_by_source_alpha(state, target) {
1 << 3
} else {
0
};
let mut discard_tested = 0u8;
if let (Some(g), Some(tested)) = (graph, &tested) {
for lane in 0..4u8 {
if let Some(id) = g.values.output_labelled(&g.interface, &v.label, lane)
&& !matches!(g.values.node(id), Node::Literal(_))
&& tested.contains(&id)
{
discard_tested |= 1 << lane;
}
}
}
Some(OutputUse {
label: v.label.clone(),
target,
blend_weight,
discard_tested,
})
})
.collect()
}
mod alpha;
pub use alpha::{AlphaDither, AlphaExpr, AlphaTest, Known, Linear, alpha_tests, discard_compares};
fn weighs_by_source_alpha(state: &RenderState, target: u32) -> bool {
let blend = usize::try_from(target)
.ok()
.and_then(|t| state.targets.get(t).copied().flatten())
.and_then(|t| t.blend)
.or(if target == 0 { state.blend } else { None });
blend.is_some_and(|b| {
[b.colour.source, b.colour.destination]
.iter()
.any(|f| matches!(f, BlendFactor::SrcAlpha | BlendFactor::OneMinusSrcAlpha))
})
}