Skip to content

Commit

Permalink
Added GLSL generation support for arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
ElectronicRU committed Nov 1, 2021
1 parent 4e79e3a commit cdef9f8
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 30 deletions.
17 changes: 10 additions & 7 deletions crevice-derive/src/glsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ pub fn emit(input: DeriveInput) -> TokenStream {
let glsl_fields = fields.named.iter().map(|field| {
let field_ty = &field.ty;
let field_name_str = Literal::string(&field.ident.as_ref().unwrap().to_string());
let field_as = quote! {<#field_ty as ::crevice::glsl::GlslArray>};

quote! {
::crevice::glsl::GlslField {
ty: <#field_ty as ::crevice::glsl::Glsl>::NAME,
name: #field_name_str,
}
s.push_str("\t");
s.push_str(#field_as::NAME);
s.push_str(" ");
s.push_str(#field_name_str);
<#field_as::ArraySize as ::crevice::glsl::DimensionList>::push_to_string(s);
s.push_str(";\n");
}
});

Expand All @@ -38,9 +41,9 @@ pub fn emit(input: DeriveInput) -> TokenStream {
}

unsafe impl #impl_generics #struct_trait_path for #name #ty_generics #where_clause {
const FIELDS: &'static [::crevice::glsl::GlslField] = &[
#( #glsl_fields, )*
];
fn enumerate_fields(s: &mut String) {
#( #glsl_fields )*
}
}
}
}
29 changes: 25 additions & 4 deletions crevice-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,16 +342,37 @@ fn array_strides_small_value() {

#[test]
fn array_strides_vec3() {
#[derive(Debug, PartialEq, AsStd140, AsStd430)]
struct ArrayOfSmallValues {
#[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)]
struct ArrayOfVector3 {
inner: [Vector3<f32>; 4],
}

assert_std140!((size = 64, align = 16) ArrayOfSmallValues {
assert_std140!((size = 64, align = 16) ArrayOfVector3 {
inner: 0,
});

assert_std430!((size = 64, align = 16) ArrayOfSmallValues {
assert_std430!((size = 64, align = 16) ArrayOfVector3 {
inner: 0,
});

test_round_trip_struct(ArrayOfVector3 {
inner: [[0.0, 1.0, 2.0].into(); 4],
})
}

#[test]
fn complex_array_glsl() {
#[derive(Debug, PartialEq, AsStd140, AsStd430, GlslStruct)]
struct Wrap {
inner: [[f32; 4]; 4],
}

test_round_trip_struct(Wrap {
inner: [
[0.0, 1.0, 2.0, 3.0],
[1.0, 2.0, 3.0, 0.0],
[2.0, 3.0, 0.0, 1.0],
[3.0, 0.0, 1.0, 2.0],
],
})
}
65 changes: 48 additions & 17 deletions src/glsl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
//! Defines traits and types for generating GLSL code from Rust definitions.

pub use crevice_derive::GlslStruct;
use std::marker::PhantomData;

/// Type-level linked list of array dimensions
pub struct Dimension<A, const N: usize> {
_marker: PhantomData<A>,
}

/// Type-level linked list terminator for array dimensions.
pub struct DimensionNil;

/// Trait for type-level array dimensions. Probably shouldn't be implemented outside this crate.
pub unsafe trait DimensionList {
/// Write dimensions in square brackets to a string, list tail to list head.
fn push_to_string(s: &mut String);
}

unsafe impl DimensionList for DimensionNil {
fn push_to_string(_: &mut String) {}
}

unsafe impl<A: DimensionList, const N: usize> DimensionList for Dimension<A, N> {
fn push_to_string(s: &mut String) {
use std::fmt::Write;
A::push_to_string(s);
write!(s, "[{}]", N).unwrap();
}
}

/// Trait for types that have a GLSL equivalent. Useful for generating GLSL code
/// from Rust structs.
Expand All @@ -9,21 +36,12 @@ pub unsafe trait Glsl {
const NAME: &'static str;
}

/// A field contained within a GLSL struct definition.
pub struct GlslField {
/// The type of the field, like `vec2` or `mat3`.
pub ty: &'static str,

/// The field's name. This must be a valid GLSL identifier.
pub name: &'static str,
}

/// Trait for types that can be represented as a struct in GLSL.
///
/// This trait should not generally be implemented by hand, but can be derived.
pub unsafe trait GlslStruct: Glsl {
/// The fields contained in this struct.
const FIELDS: &'static [GlslField];
fn enumerate_fields(s: &mut String);

/// Generates GLSL code that represents this struct and its fields.
fn glsl_definition() -> String {
Expand All @@ -32,19 +50,26 @@ pub unsafe trait GlslStruct: Glsl {
output.push_str(Self::NAME);
output.push_str(" {\n");

for field in Self::FIELDS {
output.push('\t');
output.push_str(field.ty);
output.push(' ');
output.push_str(field.name);
output.push_str(";\n");
}
Self::enumerate_fields(&mut output);

output.push_str("};");
output
}
}

/// Trait for types that are expressible as a GLSL type with (possibly zero) array dimensions.
pub unsafe trait GlslArray {
/// Base type name.
const NAME: &'static str;
/// Type-level linked list of array dimensions, ordered outer to inner.
type ArraySize: DimensionList;
}

unsafe impl<T: Glsl> GlslArray for T {
const NAME: &'static str = <T as Glsl>::NAME;
type ArraySize = DimensionNil;
}

unsafe impl Glsl for f32 {
const NAME: &'static str = "float";
}
Expand All @@ -60,3 +85,9 @@ unsafe impl Glsl for i32 {
unsafe impl Glsl for u32 {
const NAME: &'static str = "uint";
}

unsafe impl<T: GlslArray, const N: usize> GlslArray for [T; N] {
const NAME: &'static str = T::NAME;

type ArraySize = Dimension<T::ArraySize, N>;
}
2 changes: 1 addition & 1 deletion src/std140/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ where
res[i] = MaybeUninit::new(Std140Convertible::from_std140(self[i].as_std140()));
}

return Self::Output::from_uninit_array(res);
Self::Output::from_uninit_array(res)
}

fn from_std140(val: Self::Output) -> Self {
Expand Down
2 changes: 1 addition & 1 deletion src/std430/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ where
res[i] = MaybeUninit::new(Std430Convertible::from_std430(self[i].as_std430()));
}

return Self::Output::from_uninit_array(res);
Self::Output::from_uninit_array(res)
}

fn from_std430(val: Self::Output) -> Self {
Expand Down
8 changes: 8 additions & 0 deletions tests/snapshots/test__generate_struct_array_glsl.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
source: tests/test.rs
expression: "TestGlsl::glsl_definition()"

---
struct TestGlsl {
vec3 foo[8][4];
};
11 changes: 11 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,14 @@ fn generate_struct_glsl() {

insta::assert_display_snapshot!(TestGlsl::glsl_definition());
}

#[test]
fn generate_struct_array_glsl() {
#[allow(dead_code)]
#[derive(GlslStruct)]
struct TestGlsl {
foo: [[mint::Vector3<f32>; 8]; 4],
}

insta::assert_display_snapshot!(TestGlsl::glsl_definition());
}

0 comments on commit cdef9f8

Please sign in to comment.