micro_games_kit/assets/
shader.rs1use crate::{assets::name_from_path, context::GameContext, game::GameSubsystem};
2use anput::world::World;
3use keket::{
4 database::{handle::AssetHandle, path::AssetPathStatic},
5 protocol::AssetProtocol,
6};
7use std::{borrow::Cow, error::Error};
8
9pub struct ShaderAsset {
10 pub vertex: Cow<'static, str>,
11 pub fragment: Cow<'static, str>,
12}
13
14impl ShaderAsset {
15 pub fn new(vertex: &'static str, fragment: &'static str) -> Self {
16 Self {
17 vertex: vertex.into(),
18 fragment: fragment.into(),
19 }
20 }
21}
22
23pub struct ShaderAssetSubsystem;
24
25impl GameSubsystem for ShaderAssetSubsystem {
26 fn run(&mut self, context: GameContext, _: f32) {
27 for entity in context.assets.storage.added().iter_of::<ShaderAsset>() {
28 if let Some((path, asset)) = context
29 .assets
30 .storage
31 .lookup_one::<true, (&AssetPathStatic, &ShaderAsset)>(entity)
32 {
33 context.draw.shaders.insert(
34 name_from_path(&path).to_owned().into(),
35 context
36 .graphics
37 .shader(asset.vertex.trim(), asset.fragment.trim())
38 .unwrap(),
39 );
40 }
41 }
42 for entity in context.assets.storage.removed().iter_of::<ShaderAsset>() {
43 if let Some(path) = context
44 .assets
45 .storage
46 .lookup_one::<true, &AssetPathStatic>(entity)
47 {
48 context.draw.shaders.remove(name_from_path(&path));
49 }
50 }
51 }
52}
53
54pub struct ShaderAssetProtocol;
55
56impl AssetProtocol for ShaderAssetProtocol {
57 fn name(&self) -> &str {
58 "shader"
59 }
60
61 fn process_bytes(
62 &mut self,
63 handle: AssetHandle,
64 storage: &mut World,
65 bytes: Vec<u8>,
66 ) -> Result<(), Box<dyn Error>> {
67 enum Mode {
68 Vertex,
69 Fragment,
70 }
71
72 let mut vertex = String::default();
73 let mut fragment = String::default();
74 let mut mode = Mode::Vertex;
75 for line in std::str::from_utf8(&bytes)?.lines() {
76 let trimmed = line.trim();
77 if let Some(comment) = trimmed.strip_prefix("///") {
78 let comment = comment.trim().to_lowercase();
79 if comment == "[vertex]" {
80 mode = Mode::Vertex;
81 continue;
82 }
83 if comment == "[fragment]" {
84 mode = Mode::Fragment;
85 continue;
86 }
87 }
88 match mode {
89 Mode::Vertex => {
90 vertex.push_str(line);
91 vertex.push('\n');
92 }
93 Mode::Fragment => {
94 fragment.push_str(line);
95 fragment.push('\n');
96 }
97 }
98 }
99
100 storage.insert(
101 handle.entity(),
102 (ShaderAsset {
103 vertex: vertex.into(),
104 fragment: fragment.into(),
105 },),
106 )?;
107
108 Ok(())
109 }
110}