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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
use std::io::{self, Write}; use std::mem::size_of; use bytemuck::{bytes_of, Pod, Zeroable}; use crate::std140::Writer; /// Trait implemented for all `std140` primitives. Generally should not be /// implemented outside this crate. pub unsafe trait Std140: Copy + Zeroable + Pod { /// The required alignment of the type. Must be a power of two. /// /// This is distinct from the value returned by `std::mem::align_of` because /// `AsStd140` structs do not use Rust's alignment. This enables them to /// control and zero their padding bytes, making converting them to and from /// slices safe. const ALIGNMENT: usize; /// Casts the type to a byte array. Implementors should not override this /// method. /// /// # Safety /// This is always safe due to the requirements of [`bytemuck::Pod`] being a /// prerequisite for this trait. fn as_bytes(&self) -> &[u8] { bytes_of(self) } } /** Trait implemented for all types that can be turned into `std140` values. This trait can often be `#[derive]`'d instead of manually implementing it. Any struct which contains only fields that also implement `AsStd140` can derive `AsStd140`. Types from the mint crate implement `AsStd140`, making them convenient for use in uniform types. Most Rust geometry crates, like cgmath, nalgebra, and ultraviolet support mint. ## Example ```glsl uniform CAMERA { mat4 view; mat4 projection; } camera; ``` ``` use cgmath::prelude::*; use cgmath::{Matrix4, Deg, perspective}; use crevice::std140::{AsStd140, Std140}; #[derive(AsStd140)] struct CameraUniform { view: mint::ColumnMatrix4<f32>, projection: mint::ColumnMatrix4<f32>, } let camera = CameraUniform { view: Matrix4::identity().into(), projection: perspective(Deg(60.0), 16.0/9.0, 0.01, 100.0).into(), }; # fn write_to_gpu_buffer(bytes: &[u8]) {} let camera_std140 = camera.as_std140(); write_to_gpu_buffer(camera_std140.as_bytes()); ``` */ pub trait AsStd140 { /// The `std140` version of this value. type Std140Type: Std140; /// Convert this value into the `std140` version of itself. fn as_std140(&self) -> Self::Std140Type; /// Returns the size of the `std140` version of this type. Useful for /// pre-sizing buffers. fn std140_size_static() -> usize { size_of::<Self::Std140Type>() } } impl<T> AsStd140 for T where T: Std140, { type Std140Type = Self; fn as_std140(&self) -> Self { *self } } /// Trait implemented for all types that can be written into a buffer as /// `std140` bytes. This type is more general than [`AsStd140`]: all `AsStd140` /// types implement `WriteStd140`, but not the other way around. /// /// While `AsStd140` requires implementers to return a type that implements the /// `Std140` trait, `WriteStd140` directly writes bytes using a [`Writer`]. This /// makes `WriteStd140` usable for writing slices or other DSTs that could not /// implement `AsStd140` without allocating new memory on the heap. pub trait WriteStd140 { /// Writes this value into the given [`Writer`] using `std140` layout rules. /// /// Should return the offset of the first byte of this type, as returned by /// the first call to [`Writer::write`]. fn write_std140<W: Write>(&self, writer: &mut Writer<W>) -> io::Result<usize>; /// The space required to write this value using `std140` layout rules. This /// does not include alignment padding that may be needed before or after /// this type when written as part of a larger buffer. fn std140_size(&self) -> usize { let mut writer = Writer::new(io::sink()); self.write_std140(&mut writer).unwrap(); writer.len() } } impl<T> WriteStd140 for T where T: AsStd140, { fn write_std140<W: Write>(&self, writer: &mut Writer<W>) -> io::Result<usize> { writer.write_std140(&self.as_std140()) } fn std140_size(&self) -> usize { size_of::<<Self as AsStd140>::Std140Type>() } } impl<T> WriteStd140 for [T] where T: WriteStd140, { fn write_std140<W: Write>(&self, writer: &mut Writer<W>) -> io::Result<usize> { let mut offset = None; for item in self.iter() { let item_offset = item.write_std140(writer)?; if offset.is_none() { offset = Some(item_offset); } } Ok(offset.unwrap_or(writer.len())) } fn std140_size(&self) -> usize { let mut writer = Writer::new(io::sink()); self.write_std140(&mut writer).unwrap(); writer.len() } }