micro_games_kit/assets/
shader.rs

1use 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}