primase_core/shader/
derivation.rs1use std::sync::Arc;
3
4use iridia_interface::{Label, RenderState};
5
6use crate::shader::{ConstantBinding, InputBinding, Shader, StageBinding, TextureSource};
7use crate::{Component, Entity, Geometry, World};
8
9#[derive(Clone, Debug)]
18pub struct ShaderDerivation {
19 pub name: String,
21 pub result: Result<DerivedStage, String>,
22}
23
24#[derive(Clone, Debug)]
26pub struct DerivedStage {
27 pub stage: StageBinding,
30 pub state: RenderState,
32 pub program: Arc<iridia::Program>,
33 pub notes: Vec<String>,
35 pub vertex_input: Option<DerivedInput>,
37}
38
39#[derive(Clone, Debug)]
42pub struct DerivedInput {
43 pub target: Label,
45 pub name: String,
47 pub program: Arc<iridia::Program>,
48 pub notes: Vec<String>,
50 pub inputs: Vec<InputBinding>,
52 pub constants: Vec<ConstantBinding>,
54}
55
56impl Component for ShaderDerivation {
57 const NAME: &'static str = "core.shader_derivation";
58 const GEOMETRY: Geometry = Geometry::None;
59 fn references(&self, out: &mut Vec<Entity>) {
60 if let Ok(derived) = &self.result {
61 out.push(derived.stage.shader);
62 for t in &derived.stage.textures {
63 if let TextureSource::Texture { texture, .. } = &t.source {
64 out.push(*texture);
65 }
66 }
67 }
68 }
69 fn to_json(&self) -> Result<Option<serde_json::Value>, crate::JsonError> {
70 let result = match &self.result {
71 Ok(d) => serde_json::json!({
72 "shader": d.stage.shader,
73 "variant": d.stage.variant,
74 "outputs": d.stage.outputs,
75 "notes": d.notes,
76 "vertex_input": d.vertex_input.as_ref().map(|v| serde_json::json!({
77 "target": v.target, "name": v.name, "notes": v.notes,
78 })),
79 }),
80 Err(why) => serde_json::json!({ "refusal": why }),
81 };
82 crate::json::to_value(&serde_json::json!({ "name": self.name, "result": result })).map(Some)
83 }
84 fn verify(&self, _entity: Entity, world: &World) -> Result<(), String> {
85 if self.name.is_empty() {
86 return Err("derivation names no derivation".into());
87 }
88 let Ok(derived) = &self.result else {
89 return Ok(());
90 };
91 if world.get::<Shader>(derived.stage.shader).is_none() {
92 return Err("derivation names a source stage whose shader entity has no core.shader".into());
93 }
94 if derived.program.stage != derived.stage.stage {
95 return Err("derived program is not a program of its stage's kind".into());
96 }
97 derived.program.validate().map_err(|e| format!("{e:?}"))?;
98 if let Some(input) = &derived.vertex_input {
99 if input.name.is_empty() {
100 return Err("derived input names no derivation".into());
101 }
102 if !derived
103 .program
104 .interface
105 .inputs
106 .iter()
107 .any(|v| v.label == input.target)
108 {
109 return Err("derived input supplies no input of the derived program".into());
110 }
111 input.program.validate().map_err(|e| format!("{e:?}"))?;
112 }
113 Ok(())
114 }
115 fn apply_linear(&self, _: &crate::Linear) -> crate::world::Linearity<Self> {
116 crate::world::Linearity::Invariant
117 }
118}