mittens_engine/engine/ecs/component/
texture.rs1use crate::engine::ecs::ComponentId;
2use crate::engine::ecs::component::Component;
3use crate::engine::graphics::TextureHandle;
4use std::path::Path;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum CatEngineTextureFormat {
12 Rgba8,
14 DdsBc7,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum TextureSource {
24 Uri(String),
27 Handle(TextureHandle),
29}
30
31impl CatEngineTextureFormat {
32 pub fn from_uri(uri: &str) -> Self {
33 let raw_path_str = uri.strip_prefix("file://").unwrap_or(uri);
35 let ext = Path::new(raw_path_str)
36 .extension()
37 .and_then(|e| e.to_str())
38 .unwrap_or("");
39
40 if ext.eq_ignore_ascii_case("dds") {
41 CatEngineTextureFormat::DdsBc7
42 } else {
43 CatEngineTextureFormat::Rgba8
44 }
45 }
46}
47
48#[derive(Debug, Clone)]
54pub struct TextureComponent {
55 pub source: TextureSource,
56 pub format: CatEngineTextureFormat,
57 pub render_image: Option<String>,
58}
59
60impl TextureComponent {
61 pub fn new(uri: impl Into<String>) -> Self {
62 let uri = uri.into();
63 let format = CatEngineTextureFormat::from_uri(&uri);
64 Self {
65 source: TextureSource::Uri(uri),
66 format,
67 render_image: None,
68 }
69 }
70
71 pub fn unresolved() -> Self {
72 Self {
73 source: TextureSource::Uri(String::new()),
74 format: CatEngineTextureFormat::Rgba8,
75 render_image: None,
76 }
77 }
78
79 pub fn with_uri(uri: impl Into<String>) -> Self {
80 Self::new(uri)
81 }
82
83 pub fn render_image(selector: impl Into<String>) -> Self {
84 Self {
85 source: TextureSource::Uri(String::new()),
86 format: CatEngineTextureFormat::Rgba8,
87 render_image: Some(selector.into()),
88 }
89 }
90
91 pub fn from_handle(handle: TextureHandle) -> Self {
92 Self {
93 source: TextureSource::Handle(handle),
94 format: CatEngineTextureFormat::Rgba8,
97 render_image: None,
98 }
99 }
100
101 pub fn from_png(uri: impl Into<String>) -> Self {
106 let mut c = Self::new(uri);
107 c.format = CatEngineTextureFormat::Rgba8;
108 c
109 }
110
111 pub fn from_dds(uri: impl Into<String>) -> Self {
113 let mut c = Self::new(uri);
114 c.format = CatEngineTextureFormat::DdsBc7;
115 c
116 }
117
118 pub fn refresh_format_from_uri(&mut self) {
119 if let TextureSource::Uri(uri) = &self.source {
120 self.format = CatEngineTextureFormat::from_uri(uri);
121 }
122 }
123
124 pub fn uri(&self) -> Option<&str> {
125 match &self.source {
126 TextureSource::Uri(s) if !s.is_empty() => Some(s.as_str()),
127 TextureSource::Handle(_) => None,
128 TextureSource::Uri(_) => None,
129 }
130 }
131}
132
133impl Component for TextureComponent {
134 fn name(&self) -> &'static str {
135 "texture"
136 }
137
138 fn as_any(&self) -> &dyn std::any::Any {
139 self
140 }
141
142 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
143 self
144 }
145
146 fn init(&mut self, emit: &mut dyn crate::engine::ecs::SignalEmitter, component: ComponentId) {
147 emit.push_intent_now(
148 component,
149 crate::engine::ecs::IntentValue::RegisterTexture {
150 component_ids: vec![component],
151 },
152 );
153 }
154
155 fn to_mms_ast(
156 &self,
157 _world: &crate::engine::ecs::World,
158 ) -> crate::scripting::ast::ComponentExpression {
159 use crate::engine::ecs::component::ce_helpers::*;
160 if let Some(selector) = &self.render_image {
161 return ce_call("Texture", "render_image", vec![s(selector)]);
162 }
163 match (&self.source, self.format) {
164 (TextureSource::Uri(uri), _) if uri.is_empty() => ce("Texture"),
165 (TextureSource::Uri(uri), CatEngineTextureFormat::DdsBc7) => {
166 ce_call("Texture", "from_dds", vec![s(uri)])
167 }
168 (TextureSource::Uri(uri), CatEngineTextureFormat::Rgba8) => {
169 ce_call("Texture", "with_uri", vec![s(uri)])
170 }
171 (TextureSource::Handle(_), _) => ce("Texture"),
173 }
174 }
175}