concinnity_core/components/
shader.rs1use alloc::string::String;
9
10pub use concinnity_asset::{Shader, ShaderKind, ShaderPayload, StageSource};
11
12use crate::ecs::{Component, PayloadLocator};
13
14pub trait StageSourceExt {
23 fn current_platform_source(&self) -> Option<String>;
26}
27
28impl StageSourceExt for StageSource {
29 fn current_platform_source(&self) -> Option<String> {
30 let platform = crate::platform::Platform::current();
31 if let Some(sources) = &self.sources
32 && let Some(src) = sources.get(platform.key())
33 {
34 return Some(src.clone());
35 }
36 if self.source.is_empty() {
37 return None;
38 }
39 let ext = super::path_extension(&self.source).unwrap_or("");
40 if platform.accepts_ext(ext) {
41 Some(self.source.clone())
42 } else {
43 None
44 }
45 }
46}
47
48impl Component for Shader {
49 const NAME: &'static str = "Shader";
50
51 fn from_baked(bytes: &[u8]) -> Result<Self, crate::result::CnResult> {
52 Ok(crate::blob::decode_exact(bytes)?)
53 }
54
55 fn inject_locator(&mut self, locator: PayloadLocator) {
56 self.locator = Some(locator);
57 }
58
59 fn inject_name(&mut self, id: crate::ecs::asset_id::AssetId) {
60 self.asset_id = id;
61 }
62}
63
64pub fn platform_key() -> &'static str {
66 crate::platform::Platform::current().key()
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use alloc::string::ToString;
73
74 #[test]
75 fn compile_kind_maps_each_stage() {
76 assert_eq!(ShaderKind::Vertex.compile_kind(), "vertex");
77 assert_eq!(ShaderKind::VertexInstanced.compile_kind(), "vertex");
78 assert_eq!(ShaderKind::Fragment.compile_kind(), "fragment");
79 assert_eq!(ShaderKind::default(), ShaderKind::Vertex);
80 }
81
82 #[test]
83 fn current_platform_source_resolves_for_any_backend() {
84 let stage = StageSource {
87 sources: Some(
88 [
89 ("metal".to_string(), "v.metal".to_string()),
90 ("hlsl".to_string(), "v.hlsl".to_string()),
91 ("glsl".to_string(), "v.glsl".to_string()),
92 ]
93 .into_iter()
94 .collect(),
95 ),
96 ..Default::default()
97 };
98 assert!(stage.current_platform_source().is_some());
99 }
100
101 #[test]
102 fn single_source_resolves_only_for_matching_extensions() {
103 let stage = StageSource {
104 source: "v.metal".to_string(),
105 sources: None,
106 };
107 let platform = crate::platform::Platform::current();
108 assert_eq!(
109 stage.current_platform_source().is_some(),
110 platform.accepts_ext("metal")
111 );
112 }
113}