1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crate::material::{
    common::{BakedMaterialShaders, MaterialSignature, MaterialValue},
    graph::{function::MaterialFunction, MaterialGraph},
    MaterialDrawOptions,
};
use core::assets::protocol::{AssetLoadResult, AssetProtocol};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, str::from_utf8};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BakedMaterialAsset {
    pub signature: MaterialSignature,
    pub baked: BakedMaterialShaders,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MaterialAsset {
    None,
    Graph {
        #[serde(default)]
        default_values: HashMap<String, MaterialValue>,
        #[serde(default)]
        draw_options: MaterialDrawOptions,
        content: MaterialGraph,
    },
    Domain(MaterialGraph),
    Baked {
        #[serde(default)]
        default_values: HashMap<String, MaterialValue>,
        #[serde(default)]
        draw_options: MaterialDrawOptions,
        content: Vec<BakedMaterialAsset>,
    },
    Function(MaterialFunction),
}

impl Default for MaterialAsset {
    fn default() -> Self {
        Self::None
    }
}

pub struct MaterialAssetProtocol;

impl AssetProtocol for MaterialAssetProtocol {
    fn name(&self) -> &str {
        "material"
    }

    fn on_load_with_path(&mut self, path: &str, data: Vec<u8>) -> AssetLoadResult {
        let material = if path.ends_with(".json") {
            let data = from_utf8(&data).unwrap();
            serde_json::from_str::<MaterialAsset>(data).unwrap()
        } else {
            bincode::deserialize::<MaterialAsset>(&data).unwrap()
        };
        AssetLoadResult::Data(Box::new(material))
    }

    // on_load_with_path() handles loading so this is not needed, so we just make it unreachable.
    fn on_load(&mut self, _data: Vec<u8>) -> AssetLoadResult {
        unreachable!()
    }
}