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
pub mod cross;
#[cfg(feature = "dxil")]
pub mod dxil;
mod spirv;
pub mod targets;

use crate::back::targets::OutputTarget;
use crate::error::{ShaderCompileError, ShaderReflectError};
use crate::reflect::semantics::ShaderSemantics;
use crate::reflect::{ReflectShader, ShaderReflection};
use std::fmt::Debug;

/// The output of the shader compiler.
#[derive(Debug)]
pub struct ShaderCompilerOutput<T, Context = ()> {
    /// The output for the vertex shader.
    pub vertex: T,
    /// The output for the fragment shader.
    pub fragment: T,
    /// Additional context provided by the shader compiler.
    pub context: Context,
}

/// A trait for objects that can be compiled into a shader.
pub trait CompileShader<T: OutputTarget> {
    /// Options provided to the compiler.
    type Options;
    /// Additional context returned by the compiler after compilation.
    type Context;

    /// Consume the object and return the compiled output of the shader.
    fn compile(
        self,
        options: Self::Options,
    ) -> Result<ShaderCompilerOutput<T::Output, Self::Context>, ShaderCompileError>;
}

/// Marker trait for combinations of targets and compilations that can be reflected and compiled
/// successfully.
///
/// This trait is automatically implemented for reflected outputs that have [`FromCompilation`](crate::back::FromCompilation) implement
/// for a given target that also implement [`CompileShader`](crate::back::CompileShader) for that target.
pub trait CompileReflectShader<T: OutputTarget, C>:
    CompileShader<
        T,
        Options = <T as FromCompilation<C>>::Options,
        Context = <T as FromCompilation<C>>::Context,
    > + ReflectShader
where
    T: FromCompilation<C>,
{
}

impl<T, C, O> CompileReflectShader<T, C> for O
where
    T: OutputTarget,
    T: FromCompilation<C>,
    O: ReflectShader,
    O: CompileShader<
        T,
        Options = <T as FromCompilation<C>>::Options,
        Context = <T as FromCompilation<C>>::Context,
    >,
{
}

impl<T, E> CompileShader<E> for CompilerBackend<T>
where
    T: CompileShader<E>,
    E: OutputTarget,
{
    type Options = T::Options;
    type Context = T::Context;

    fn compile(
        self,
        options: Self::Options,
    ) -> Result<ShaderCompilerOutput<E::Output, Self::Context>, ShaderCompileError> {
        self.backend.compile(options)
    }
}

/// A trait for reflectable compilations that can be transformed into an object ready for reflection or compilation.
pub trait FromCompilation<T> {
    /// The target that the transformed object is expected to compile for.
    type Target: OutputTarget;
    /// Options provided to the compiler.
    type Options;
    /// Additional context returned by the compiler after compilation.
    type Context;

    /// The output type after conversion.
    type Output: CompileShader<Self::Target, Context = Self::Context, Options = Self::Options>
        + ReflectShader;

    /// Tries to convert the input object into an object ready for compilation.
    fn from_compilation(compile: T) -> Result<CompilerBackend<Self::Output>, ShaderReflectError>;
}

/// A wrapper for a compiler backend.
pub struct CompilerBackend<T> {
    pub(crate) backend: T,
}

impl<T> ReflectShader for CompilerBackend<T>
where
    T: ReflectShader,
{
    fn reflect(
        &mut self,
        pass_number: usize,
        semantics: &ShaderSemantics,
    ) -> Result<ShaderReflection, ShaderReflectError> {
        self.backend.reflect(pass_number, semantics)
    }
}