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
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::prelude::*;

use macroquad::material::{self, load_material};

#[derive(Debug, Clone)]
pub struct Material {
    compiled: Option<material::Material>,
    vertex_src: String,
    fragment_src: String,
    textures: Vec<String>,
    uniforms: HashMap<String, UniformType>,
    pipeline_params: PipelineParams,
}

impl Material {
    pub async fn new<P: AsRef<Path>>(
        vertex_path: P,
        fragment_path: P,
        params: MaterialParams,
    ) -> Result<Self> {
        let vertex_path = vertex_path.as_ref();
        let fragment_path = fragment_path.as_ref();

        let vertex_bytes = load_file(vertex_path).await?;
        let vertex_src = String::from_utf8(vertex_bytes)?;

        let fragment_bytes = load_file(fragment_path).await?;
        let fragment_src = String::from_utf8(fragment_bytes)?;

        let textures = params.textures;
        let uniforms = HashMap::from_iter(params.uniforms.into_iter());

        let res = Material {
            compiled: None,
            vertex_src,
            fragment_src,
            textures,
            uniforms,
            pipeline_params: PipelineParams {
                ..Default::default()
            },
        };

        Ok(res)
    }

    pub fn is_compiled(&self) -> bool {
        self.compiled.is_some()
    }

    pub fn compile(&mut self) -> Result<()> {
        if let Some(compiled) = &mut self.compiled {
            compiled.delete();
        }

        let textures = self.textures.clone();
        let uniforms = self
            .uniforms
            .iter()
            .map(|(key, value)| (key.clone(), *value))
            .collect();

        let pipeline_params = self.pipeline_params.clone();

        let res = load_material(
            &self.vertex_src,
            &self.fragment_src,
            MaterialParams {
                textures,
                uniforms,
                pipeline_params,
            },
        )?;

        self.compiled = Some(res);

        Ok(())
    }

    pub fn compile_and_use(&mut self) -> Result<()> {
        self.compile()?;
        self.use_material()?;

        Ok(())
    }

    pub fn delete_compiled(&mut self) -> Result<()> {
        if let Some(compiled) = &mut self.compiled {
            compiled.delete();
        } else {
            let err = Error::new_const(
                ErrorKind::Material,
                &"Attempting to delete a material that has not been compiled",
            );
            return Err(err);
        }

        Ok(())
    }

    pub fn use_material(&self) -> Result<()> {
        if let Some(material) = self.compiled.clone() {
            gl_use_material(material);
        } else {
            let err = Error::new_const(
                ErrorKind::Material,
                &"Attempting to use a material that has not been compiled",
            );
            return Err(err);
        }

        Ok(())
    }
}

pub fn use_default_material() {
    gl_use_default_material()
}

pub fn use_material(material: &Material) -> Result<()> {
    material.use_material()
}