willow_codegen/lib.rs
1#![cfg_attr(debug_assertions, allow(dead_code))]
2
3extern crate proc_macro;
4
5use proc_macro2::TokenStream;
6use syn::Result;
7
8mod gen;
9mod parse;
10
11/// Derives a user-friendly wrapper for `WebGlProgram` from a struct.
12///
13/// The struct must only contain the following fields:
14/// - Exactly one `ProgramData` field
15/// - `Uniform<T>` fields (use `#[willow(uniform(T)]` if aliased)
16/// - `Attribute<T>` fields (use `#[willow(attribute(T))]` if aliased)
17///
18/// In the struct attribute, the path to the GLSL shaders must be specified:
19/// ```ignore
20/// #[willow(path = "scene")]
21/// ```
22///
23/// This will load the GLSL shaders by running `include_str!("scene.vert")` and
24/// `include_str!("scene.frag")`.
25///
26/// If they are already loaded in a constant, write this instead:
27/// ```ignore
28/// #[willow(vert = VERTEX_SHADER_CODE, frag = FRAGMENT_SHADER_CODE)]
29/// ```
30///
31/// # Example
32/// ```ignore
33/// #[derive(willow::Program)]
34/// #[willow(path = "scene")]
35/// struct Scene {
36/// vertices: Attribute<Vector3<f32>>,
37/// normals: Attribute<Vector3<f32>>,
38/// projection: Uniform<Matrix4<f32>>,
39/// }
40/// ```
41///
42/// With the files `scene.vert` and `scene.frag` containing at least these declarations:
43/// ```glsl
44/// attribute vec3 vertices;
45/// attribute vec3 normals;
46/// uniform mat4 projection;
47/// ```
48///
49/// Then it can be used like this:
50/// ```ignore
51/// fn render(
52/// gl: &WebGlRenderingContext,
53/// scene: &Scene,
54/// buffer: &Buffer,
55/// projection: Matrix,
56/// ) {
57/// scene.call()
58/// .vertices(vertices)
59/// .normals(normals)
60/// .projection(projection)
61/// .draw_indexed(WebGlRenderingContext::TRIANGLES, indices);
62/// }
63/// ```
64#[proc_macro_derive(Program, attributes(willow))]
65pub fn program(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
66 program_imp(input.into())
67 .unwrap_or_else(|err| err.to_compile_error())
68 .into()
69}
70
71fn program_imp(input: TokenStream) -> Result<TokenStream> {
72 let info = parse::parse_input(input)?;
73
74 Ok(gen::gen_code(&info))
75}