use std::io::Write; #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum TextureType { Regular, Compressed, Srgb, CompressedSrgb, Integral, Unsigned, Depth, Stencil, DepthStencil, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum TextureDimensions { Texture1d, Texture2d, Texture2dMultisample, Texture3d, Texture1dArray, Texture2dArray, Texture2dMultisampleArray, Cubemap, CubemapArray, } impl TextureDimensions { fn is_array(&self) -> bool { match self { TextureDimensions::Texture1dArray => true, TextureDimensions::Texture2dArray => true, TextureDimensions::Texture2dMultisampleArray => true, TextureDimensions::CubemapArray => true, _ => false } } fn is_multisample(&self) -> bool { match self { TextureDimensions::Texture2dMultisample => true, TextureDimensions::Texture2dMultisampleArray => true, _ => false } } fn is_cube(&self) -> bool { match self { TextureDimensions::Cubemap => true, TextureDimensions::CubemapArray => true, _ => false } } } pub fn build_texture_file(dest: &mut W) { build_texture(dest, TextureType::Regular, TextureDimensions::Texture1d); build_texture(dest, TextureType::Compressed, TextureDimensions::Texture1d); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture1d); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::Texture1d); build_texture(dest, TextureType::Integral, TextureDimensions::Texture1d); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture1d); build_texture(dest, TextureType::Depth, TextureDimensions::Texture1d); build_texture(dest, TextureType::Stencil, TextureDimensions::Texture1d); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture1d); build_texture(dest, TextureType::Regular, TextureDimensions::Texture2d); build_texture(dest, TextureType::Compressed, TextureDimensions::Texture2d); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture2d); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::Texture2d); build_texture(dest, TextureType::Integral, TextureDimensions::Texture2d); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2d); build_texture(dest, TextureType::Depth, TextureDimensions::Texture2d); build_texture(dest, TextureType::Stencil, TextureDimensions::Texture2d); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture2d); build_texture(dest, TextureType::Regular, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::Integral, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::Depth, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::Stencil, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture2dMultisample); build_texture(dest, TextureType::Regular, TextureDimensions::Texture3d); build_texture(dest, TextureType::Compressed, TextureDimensions::Texture3d); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture3d); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::Texture3d); build_texture(dest, TextureType::Integral, TextureDimensions::Texture3d); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture3d); build_texture(dest, TextureType::Depth, TextureDimensions::Texture3d); //build_texture(dest, TextureType::Stencil, TextureDimensions::Texture3d); // forbidden build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture3d); build_texture(dest, TextureType::Regular, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Compressed, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Integral, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Depth, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Stencil, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture1dArray); build_texture(dest, TextureType::Regular, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Compressed, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Integral, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Depth, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Stencil, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture2dArray); build_texture(dest, TextureType::Regular, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::Srgb, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::Integral, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::Unsigned, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::Depth, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::Stencil, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Texture2dMultisampleArray); build_texture(dest, TextureType::Regular, TextureDimensions::Cubemap); build_texture(dest, TextureType::Compressed, TextureDimensions::Cubemap); build_texture(dest, TextureType::Srgb, TextureDimensions::Cubemap); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::Cubemap); build_texture(dest, TextureType::Integral, TextureDimensions::Cubemap); build_texture(dest, TextureType::Unsigned, TextureDimensions::Cubemap); build_texture(dest, TextureType::Depth, TextureDimensions::Cubemap); build_texture(dest, TextureType::Stencil, TextureDimensions::Cubemap); build_texture(dest, TextureType::DepthStencil, TextureDimensions::Cubemap); build_texture(dest, TextureType::Regular, TextureDimensions::CubemapArray); build_texture(dest, TextureType::Compressed, TextureDimensions::CubemapArray); build_texture(dest, TextureType::Srgb, TextureDimensions::CubemapArray); build_texture(dest, TextureType::CompressedSrgb, TextureDimensions::CubemapArray); build_texture(dest, TextureType::Integral, TextureDimensions::CubemapArray); build_texture(dest, TextureType::Unsigned, TextureDimensions::CubemapArray); build_texture(dest, TextureType::Depth, TextureDimensions::CubemapArray); build_texture(dest, TextureType::Stencil, TextureDimensions::CubemapArray); build_texture(dest, TextureType::DepthStencil, TextureDimensions::CubemapArray); } fn build_texture(dest: &mut W, ty: TextureType, dimensions: TextureDimensions) { // building the name of the module let module_name: String = { let prefix = match ty { TextureType::Regular => "", TextureType::Compressed => "compressed_", TextureType::Srgb => "srgb_", TextureType::CompressedSrgb => "compressed_srgb_", TextureType::Integral => "integral_", TextureType::Unsigned => "unsigned_", TextureType::Depth => "depth_", TextureType::Stencil => "stencil_", TextureType::DepthStencil => "depth_stencil_", }; let suffix = match dimensions { TextureDimensions::Texture1d => "texture1d", TextureDimensions::Texture2d => "texture2d", TextureDimensions::Texture2dMultisample => "texture2d_multisample", TextureDimensions::Texture3d => "texture3d", TextureDimensions::Texture1dArray => "texture1d_array", TextureDimensions::Texture2dArray => "texture2d_array", TextureDimensions::Texture2dMultisampleArray => "texture2d_multisample_array", TextureDimensions::Cubemap => "cubemap", TextureDimensions::CubemapArray => "cubemap_array", }; format!("{}{}", prefix, suffix) }; // building the name of the texture type let name: String = { let prefix = match ty { TextureType::Regular => "", TextureType::Compressed => "Compressed", TextureType::Srgb => "Srgb", TextureType::CompressedSrgb => "CompressedSrgb", TextureType::Integral => "Integral", TextureType::Unsigned => "Unsigned", TextureType::Depth => "Depth", TextureType::Stencil => "Stencil", TextureType::DepthStencil => "DepthStencil", }; let suffix = match dimensions { TextureDimensions::Texture1d => "Texture1d", TextureDimensions::Texture2d => "Texture2d", TextureDimensions::Texture2dMultisample => "Texture2dMultisample", TextureDimensions::Texture3d => "Texture3d", TextureDimensions::Texture1dArray => "Texture1dArray", TextureDimensions::Texture2dArray => "Texture2dArray", TextureDimensions::Texture2dMultisampleArray => "Texture2dMultisampleArray", TextureDimensions::Cubemap => "Cubemap", TextureDimensions::CubemapArray => "CubemapArray", }; format!("{}{}", prefix, suffix) }; // the trait corresponding to the data source let data_source_trait = match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => "Texture1dDataSource", TextureDimensions::Texture2d | TextureDimensions::Texture2dArray => "Texture2dDataSource", TextureDimensions::Texture3d => "Texture3dDataSource", TextureDimensions::Texture2dMultisample | TextureDimensions::Texture2dMultisampleArray | TextureDimensions::Cubemap | TextureDimensions::CubemapArray => { "unreachable" }, }; // the format enum corresponding to this texture let relevant_format = match ty { TextureType::Regular => "UncompressedFloatFormat", TextureType::Compressed => "CompressedFormat", TextureType::Srgb => "SrgbFormat", TextureType::CompressedSrgb => "CompressedSrgbFormat", TextureType::Integral => "UncompressedIntFormat", TextureType::Unsigned => "UncompressedUintFormat", TextureType::Depth => "DepthFormat", TextureType::Stencil => "StencilFormat", TextureType::DepthStencil => "DepthStencilFormat", }; // the default format to use when none is specified let default_format = match ty { TextureType::Compressed => "TextureFormatRequest::AnyCompressed", TextureType::Regular => "TextureFormatRequest::AnyFloatingPoint", TextureType::CompressedSrgb => "TextureFormatRequest::AnyCompressedSrgb", TextureType::Srgb => "TextureFormatRequest::AnySrgb", TextureType::Integral => "TextureFormatRequest::AnyIntegral", TextureType::Unsigned => "TextureFormatRequest::AnyUnsigned", TextureType::Depth => "TextureFormatRequest::AnyDepth", TextureType::Stencil => "TextureFormatRequest::AnyStencil", TextureType::DepthStencil => "TextureFormatRequest::AnyDepthStencil", }; // whether this is a internally compressed texture object let is_compressed = matches!(ty, TextureType::Compressed | TextureType::CompressedSrgb); let client_format_any_ty = match ty { TextureType::Compressed => "ClientFormatAny::CompressedFormat", TextureType::CompressedSrgb => "ClientFormatAny::CompressedSrgbFormat", _ => "ClientFormatAny::ClientFormat", }; let mipmaps_option_ty = match ty { TextureType::Compressed | TextureType::CompressedSrgb => "CompressedMipmapsOption", _ => "MipmapsOption", }; let mipmap_default = match ty { TextureType::Compressed | TextureType::CompressedSrgb => "CompressedMipmapsOption::NoMipmap", TextureType::Unsigned | TextureType::Integral => "MipmapsOption::NoMipmap", _ => "MipmapsOption::AutoGeneratedMipmaps", }; // let dimensions_parameters_input = match dimensions { TextureDimensions::Texture1d => "width: u32", TextureDimensions::Texture2d => "width: u32, height: u32", TextureDimensions::Texture2dMultisample => "width: u32, height: u32, samples: u32", TextureDimensions::Texture3d => "width: u32, height: u32, depth: u32", TextureDimensions::Texture1dArray => "width: u32, array_size: u32", TextureDimensions::Texture2dArray => "width: u32, height: u32, array_size: u32", TextureDimensions::Texture2dMultisampleArray => "width: u32, height: u32, array_size: u32, samples: u32", TextureDimensions::Cubemap => "dimension: u32", TextureDimensions::CubemapArray => "dimension: u32, array_size: u32", }; let dimensions_parameters_passing = match dimensions { TextureDimensions::Texture1d => { "Dimensions::Texture1d { width: width }" }, TextureDimensions::Texture2d => { "Dimensions::Texture2d { width: width, height: height }" }, TextureDimensions::Texture2dMultisample => { "Dimensions::Texture2dMultisample { width: width, height: height, samples: samples }" }, TextureDimensions::Texture3d => { "Dimensions::Texture3d { width: width, height: height, depth: depth }" }, TextureDimensions::Texture1dArray => { "Dimensions::Texture1dArray { width: width, array_size: array_size }" }, TextureDimensions::Texture2dArray => { "Dimensions::Texture2dArray { width: width, height: height, array_size: array_size }" }, TextureDimensions::Texture2dMultisampleArray => { "Dimensions::Texture2dMultisampleArray { width: width, height: height, array_size: array_size, samples: samples }" }, TextureDimensions::Cubemap => { "Dimensions::Cubemap { dimension: dimension }" }, TextureDimensions::CubemapArray => { "Dimensions::CubemapArray { dimension: dimension, array_size: array_size }" }, }; // writing the `use module::*;` statement writeln!(dest, "pub use self::{}::{};", module_name, name).unwrap(); // opening `mod module {` writeln!(dest, " /// Contains the implementation of `{}`. pub mod {} {{\ // the list of imports we need depends on the texture type, don't bother with this #![allow(unused_imports)] use std::borrow::Cow; use crate::texture::any::{{self, TextureAny, TextureAnyLayer, TextureAnyMipmap}}; use crate::texture::any::{{TextureAnyLayerMipmap, TextureAnyImage, Dimensions}}; use crate::texture::bindless::{{ResidentTexture, BindlessTexturesNotSupportedError}}; use crate::texture::get_format::{{InternalFormat, InternalFormatType, GetFormatError}}; use crate::texture::pixel_buffer::PixelBuffer; use crate::texture::{{TextureCreationError, Texture1dDataSource, Texture2dDataSource}}; use crate::texture::{{Texture3dDataSource, Texture2dDataSink, MipmapsOption, CompressedMipmapsOption}}; use crate::texture::{{RawImage1d, RawImage2d, RawImage3d, CubeLayer}}; use crate::texture::pixel::PixelValue; use crate::image_format::{{ClientFormatAny, TextureFormatRequest}}; use crate::image_format::{{UncompressedFloatFormat, UncompressedIntFormat}}; use crate::image_format::{{CompressedFormat, DepthFormat, DepthStencilFormat, StencilFormat}}; use crate::image_format::{{CompressedSrgbFormat, SrgbFormat, UncompressedUintFormat}}; use crate::backend::Facade; use crate::uniforms::{{UniformValue, AsUniformValue, Sampler, ImageUnit, ImageUnitError, ImageUnitFormat}}; use crate::framebuffer; use crate::Rect; use crate::GlObject; use crate::TextureExt; use crate::TextureMipmapExt; use crate::gl; ", name, module_name).unwrap(); // writing the struct with doc-comment (write!(dest, "/// ")).unwrap(); (write!(dest, "{}", match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture2dMultisample | TextureDimensions::Texture3d | TextureDimensions::Cubemap => "A ", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray | TextureDimensions::Texture2dMultisampleArray | TextureDimensions::CubemapArray => "An array of ", })).unwrap(); if is_compressed { (write!(dest, "compressed ")).unwrap(); } (write!(dest, "{}", match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture1dArray => "one-dimensional ", TextureDimensions::Texture2d | TextureDimensions::Texture2dArray | TextureDimensions::Texture2dMultisample | TextureDimensions::Texture2dMultisampleArray => { "two-dimensional " }, TextureDimensions::Texture3d => "three-dimensional ", TextureDimensions::Cubemap | TextureDimensions::CubemapArray => "cube ", })).unwrap(); (write!(dest, "{}", match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture2dMultisample | TextureDimensions::Texture3d | TextureDimensions::Cubemap => "texture ", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray | TextureDimensions::Texture2dMultisampleArray | TextureDimensions::CubemapArray => "textures ", })).unwrap(); (write!(dest, "{}", match ty { TextureType::Regular | TextureType::Compressed => " containing floating-point data", TextureType::Srgb | TextureType::CompressedSrgb => " containing sRGB floating-point data", TextureType::Integral => " containing signed integral data", TextureType::Unsigned => " containing unsigned integral data", TextureType::Depth => " containing depth data", TextureType::Stencil => " containing stencil data", TextureType::DepthStencil => " containing both depth and stencil data", })).unwrap(); (writeln!(dest, ".")).unwrap(); (writeln!(dest, "pub struct {}(TextureAny);", name)).unwrap(); // `GlObject` trait impl (writeln!(dest, " impl GlObject for {} {{ type Id = gl::types::GLuint; #[inline] fn get_id(&self) -> gl::types::GLuint {{ self.0.get_id() }} }} ", name)).unwrap(); // `Debug` trait impl (writeln!(dest, " impl ::std::fmt::Debug for {} {{ #[inline] fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {{ self.0.fmt(f) }} }} ", name)).unwrap(); // 'Deref' impl to common type. (writeln!(dest, " impl ::std::ops::Deref for {} {{ type Target = TextureAny; #[inline] fn deref<'a>(&'a self) -> &'a TextureAny {{ &self.0 }} }} ", name)).unwrap(); // `UniformValue` trait impl for samplers { match ty { TextureType::Regular | TextureType::Compressed | TextureType::Srgb | TextureType::CompressedSrgb | TextureType::Integral | TextureType::Unsigned | TextureType::Depth => { (writeln!(dest, " impl<'a> AsUniformValue for &'a {myname} {{ #[inline] fn as_uniform_value(&self) -> UniformValue {{ UniformValue::{myname}(*self, None) }} }} impl AsUniformValue for {myname} {{ #[inline] fn as_uniform_value(&self) -> UniformValue {{ UniformValue::{myname}(self, None) }} }} impl<'a> AsUniformValue for Sampler<'a, {myname}> {{ #[inline] fn as_uniform_value(&self) -> UniformValue {{ UniformValue::{myname}(self.0, Some(self.1)) }} }} impl {myname} {{ /// Builds a `Sampler` marker object that allows you to indicate /// how the texture should be sampled from inside a shader. /// /// # Example /// /// ```no_run /// # #[macro_use] extern crate glium; /// # fn example(texture: glium::texture::Texture2d) {{ /// let uniforms = uniform! {{ /// color_texture: texture.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest) /// }}; /// # }} /// ``` #[inline] pub fn sampled(&self) -> Sampler<{myname}> {{ Sampler(self, Default::default()) }} }} ", myname = name)).unwrap(); }, _ => () } } // Generate implementations of image_unit if (ty == TextureType::Regular || ty == TextureType::Integral || ty == TextureType::Unsigned) && (dimensions != TextureDimensions::Texture2dMultisample && dimensions != TextureDimensions::Texture2dMultisampleArray ){ let image_variant = name.replace("Texture", "Image").replace("Cubemap", "ImageCube"); writeln!(dest, " impl<'a> AsUniformValue for ImageUnit<'a, {myname}> {{ #[inline] fn as_uniform_value(&self) -> UniformValue {{ UniformValue::{valname}(self.0, Some(self.1)) }} }} impl {myname} {{ /// Builds an image unit marker object that allows you to indicate how the /// texture should be bound to an image unit. #[inline] pub fn image_unit(&self, format: ImageUnitFormat) -> Result, ImageUnitError> {{ ImageUnit::new(self, format) }} }} ", myname = name, valname = image_variant).unwrap(); } // `ToXXXAttachment` trait impl if dimensions == TextureDimensions::Texture2d || dimensions == TextureDimensions::Texture2dMultisample || dimensions == TextureDimensions::Texture1d { match ty { TextureType::Regular | TextureType::Srgb | TextureType::Integral | TextureType::Unsigned => { (writeln!(dest, " impl<'t> crate::framebuffer::ToColorAttachment<'t> for &'t {name} {{ #[inline] fn to_color_attachment(self) -> crate::framebuffer::ColorAttachment<'t> {{ crate::framebuffer::ColorAttachment::Texture(self.0.main_level().first_layer().into_image(None).unwrap()) }} }} ", name = name)).unwrap(); }, TextureType::Depth => { (writeln!(dest, " impl<'t> crate::framebuffer::ToDepthAttachment<'t> for &'t {name} {{ #[inline] fn to_depth_attachment(self) -> crate::framebuffer::DepthAttachment<'t> {{ crate::framebuffer::DepthAttachment::Texture(self.0.main_level().first_layer().into_image(None).unwrap()) }} }} ", name = name)).unwrap(); }, TextureType::Stencil => { (writeln!(dest, " impl<'t> crate::framebuffer::ToStencilAttachment<'t> for &'t {name} {{ #[inline] fn to_stencil_attachment(self) -> crate::framebuffer::StencilAttachment<'t> {{ crate::framebuffer::StencilAttachment::Texture(self.0.main_level().first_layer().into_image(None).unwrap()) }} }} ", name = name)).unwrap(); }, TextureType::DepthStencil => { (writeln!(dest, " impl<'t> crate::framebuffer::ToDepthStencilAttachment<'t> for &'t {name} {{ #[inline] fn to_depth_stencil_attachment(self) -> crate::framebuffer::DepthStencilAttachment<'t> {{ crate::framebuffer::DepthStencilAttachment::Texture(self.0.main_level().first_layer().into_image(None).unwrap()) }} }} ", name = name)).unwrap(); }, _ => () } } // opening `impl Texture` block (writeln!(dest, "impl {} {{", name)).unwrap(); // writing `get_internal_format` writeln!(dest, " /// Determines the internal format of this texture. /// /// The backend may not support querying the actual format, in which case an error /// is returned. #[inline] pub fn get_internal_format(&self) -> Result {{ self.0.get_internal_format() }} ").unwrap(); // writing the `new` function if !dimensions.is_multisample() && !dimensions.is_cube() { let param = match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture3d => "T", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "Vec", _ => unreachable!() }; let gen_doc = if is_compressed { "/// No mipmap level (except for the main level) will be allocator nor generated." } else { "/// This function will automatically generate all mipmaps of the texture." }; (writeln!(dest, " /// Builds a new texture by uploading data. /// {gen_doc} #[inline] pub fn new<'a, F: ?Sized, T>(facade: &F, data: {param}) -> Result<{name}, TextureCreationError> where T: {data_source_trait}<'a>, F: Facade {{ {name}::new_impl(facade, data, None, {mipmap_default}) }} ", data_source_trait = data_source_trait, param = param, name = name, mipmap_default = mipmap_default, gen_doc = gen_doc)).unwrap(); } // writing the `with_mipmaps` function if !dimensions.is_multisample() && !dimensions.is_cube() { let param = match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture3d => "T", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "Vec", _ => unreachable!() }; (writeln!(dest, " /// Builds a new texture by uploading data. #[inline] pub fn with_mipmaps<'a, F: ?Sized, T>(facade: &F, data: {param}, mipmaps: {mipmaps}) -> Result<{name}, TextureCreationError> where T: {data_source_trait}<'a>, F: Facade {{ {name}::new_impl(facade, data, None, mipmaps) }} ", data_source_trait = data_source_trait, param = param, name = name, mipmaps = mipmaps_option_ty)).unwrap(); } // writing the `with_compressed_data` function if is_compressed && !dimensions.is_multisample() && !dimensions.is_cube() { let param = match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture3d => "&[u8]", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "Vec<&[u8]>", _ => unreachable!() }; (writeln!(dest, " /// Builds a new texture with a specific format. The input data must also be of the /// specified compressed format. #[inline] pub fn with_compressed_data(facade: &F, data: {param}, {dim_params}, format: {format}, mipmaps: {mipmaps}) -> Result<{name}, TextureCreationError> where F: Facade {{ let data = Cow::Borrowed(data.as_ref()); let client_format = {client_format_any}(format); Ok({name}(any::new_texture(facade, {default_format}, Some((client_format, data)), mipmaps.into(), {dim_params_passing})?)) }} ", dim_params = dimensions_parameters_input, dim_params_passing = dimensions_parameters_passing, param = param, client_format_any = client_format_any_ty, name = name, format = relevant_format, default_format = default_format, mipmaps = mipmaps_option_ty).unwrap()); } // writing the `with_format` function if !dimensions.is_multisample() && !dimensions.is_cube() { let param = match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture3d => "T", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "Vec", _ => unreachable!() }; (writeln!(dest, " /// Builds a new texture with a specific format. #[inline] pub fn with_format<'a, F: ?Sized, T>(facade: &F, data: {param}, format: {format}, mipmaps: {mipmaps}) -> Result<{name}, TextureCreationError> where T: {data_source_trait}<'a>, F: Facade {{ {name}::new_impl(facade, data, Some(format), mipmaps) }} ", data_source_trait = data_source_trait, param = param, format = relevant_format, name = name, mipmaps = mipmaps_option_ty)).unwrap(); } // writing the `new_impl` function if !dimensions.is_multisample() && !dimensions.is_cube() { let param = match dimensions { TextureDimensions::Texture1d | TextureDimensions::Texture2d | TextureDimensions::Texture3d => "T", TextureDimensions::Texture1dArray | TextureDimensions::Texture2dArray => "Vec", _ => unreachable!() }; (writeln!(dest, " #[inline] fn new_impl<'a, F: ?Sized, T>(facade: &F, data: {param}, format: Option<{relevant_format}>, mipmaps: {mipmaps}) -> Result<{name}, TextureCreationError> where T: {data_source_trait}<'a>, F: Facade {{ ", data_source_trait = data_source_trait, param = param, name = name, relevant_format = relevant_format, mipmaps = mipmaps_option_ty)).unwrap(); // writing the `let format = ...` line (write!(dest, "let format = format.map(|f| {{ TextureFormatRequest::Specific(f.to_texture_format()) }}).unwrap_or({});", default_format)).unwrap(); match dimensions { TextureDimensions::Texture1d => (write!(dest, " let RawImage1d {{ data, width, format: client_format }} = data.into_raw(); ")).unwrap(), TextureDimensions::Texture2d => (write!(dest, " let RawImage2d {{ data, width, height, format: client_format }} = data.into_raw(); ")).unwrap(), TextureDimensions::Texture3d => (write!(dest, " let RawImage3d {{ data, width, height, depth, format: client_format }} = data.into_raw(); ")).unwrap(), TextureDimensions::Texture1dArray => (write!(dest, " let vec_raw = data.into_iter().map(|e| e.into_raw()).collect(); let RawImage2d {{data, width, height: array_size, format: client_format }} = RawImage2d::from_vec_raw1d(&vec_raw); ")).unwrap(), // TODO: panic if dimensions are inconsistent TextureDimensions::Texture2dArray => (write!(dest, " let vec_raw = data.into_iter().map(|e| e.into_raw()).collect(); let RawImage3d {{data, width, height, depth: array_size, format: client_format }} = RawImage3d::from_vec_raw2d(&vec_raw); ")).unwrap(), // TODO: panic if dimensions are inconsistent _ => unreachable!() } (write!(dest, "let client_format = ClientFormatAny::ClientFormat(client_format);")).unwrap(); // writing the constructor (write!(dest, "Ok({}(any::new_texture(facade, format, \ Some((client_format, data)), mipmaps.into(), {}", name, dimensions_parameters_passing)).unwrap(); (writeln!(dest, ")?))")).unwrap(); // end of "new" function block (writeln!(dest, "}}")).unwrap(); } // writing the `empty` function if !is_compressed { // opening function (writeln!(dest, " /// Creates an empty texture. /// /// No mipmap level (except for the main level) will be allocated or generated. /// /// The texture will contain undefined data. #[inline] pub fn empty(facade: &F, {dim_params}) -> Result<{name}, TextureCreationError> where F: Facade {{ let format = {format}; ", format = default_format, dim_params = dimensions_parameters_input, name = name, )).unwrap(); // writing the constructor (write!(dest, "any::new_texture::<_, u8>(facade, format, None, {mipmap}::NoMipmap.into(), {}).map(|t| {}(t))", dimensions_parameters_passing, name, mipmap = mipmaps_option_ty)).unwrap(); // closing function (writeln!(dest, "}}")).unwrap(); } // writing the `empty_with_format` function if true { // opening function (writeln!(dest, " /// Creates an empty texture with a specific format. /// /// The texture (and its mipmaps) will contain undefined data. #[inline] pub fn empty_with_format(facade: &F, format: {format}, mipmaps: {mipmaps}, {dim_params}) -> Result<{name}, TextureCreationError> where F: Facade {{ let format = format.to_texture_format(); let format = TextureFormatRequest::Specific(format); ", format = relevant_format, dim_params = dimensions_parameters_input, name = name, mipmaps = mipmaps_option_ty)).unwrap(); // writing the constructor (write!(dest, "let t = any::new_texture::<_, u8>(facade, format, None, mipmaps.into(), {});", dimensions_parameters_passing)).unwrap(); (writeln!(dest, " t.map(|t| {}(t))", name)).unwrap(); // closing function (writeln!(dest, "}}")).unwrap(); } // writing the `empty_with_mipmaps` function if !is_compressed { // opening function (writeln!(dest, " /// Creates an empty texture. Specifies whether is has mipmaps. /// /// The texture (and its mipmaps) will contain undefined data. #[inline] pub fn empty_with_mipmaps(facade: &F, mipmaps: {mipmaps}, {dim_params}) -> Result<{name}, TextureCreationError> where F: Facade {{ let format = {format}; ", format = default_format, dim_params = dimensions_parameters_input, name = name, mipmaps = mipmaps_option_ty)).unwrap(); // writing the constructor (write!(dest, "any::new_texture::<_, u8>(facade, format, None, mipmaps.into(), {})", dimensions_parameters_passing)).unwrap(); (writeln!(dest, ".map(|t| {}(t))", name)).unwrap(); // closing function (writeln!(dest, "}}")).unwrap(); } // writing the 'from_id' function (writeln!(dest, " /// Builds a new texture reference from an existing, externally created OpenGL texture. /// If `owned` is true, this reference will take ownership of the texture and be responsible /// for cleaning it up. Otherwise, the texture must be cleaned up externally, but only /// after this reference's lifetime has ended. pub unsafe fn from_id(facade: &F, format: {format}, id: gl::types::GLuint, owned: bool, mipmap: MipmapsOption, ty: Dimensions) -> {name} {{ let format = format.to_texture_format(); let format = TextureFormatRequest::Specific(format); {name}(any::from_id(facade, format, id, owned, mipmap, ty)) }} ", format = relevant_format, name = name)).unwrap(); // writing the 'new_from_fd' function (writeln!(dest, r#" /// Builds a new texture reference from an existing texture, externally created by a foreign /// API like Vulkan. The texture is imported via an opaque file descriptor. You must make /// sure all of the texture parameters match those used to create the texture in Vulkan. #[cfg(target_os = "linux")] pub unsafe fn new_from_fd(facade: &F, format: {format}, mipmaps: MipmapsOption, ty: Dimensions, params: crate::texture::ImportParameters, fd: std::fs::File) -> Result<{name}, crate::texture::TextureImportError> {{ let format = format.to_texture_format(); Ok({name}(any::new_from_fd(facade, format, mipmaps, ty, params, fd)?)) }} "#, format = relevant_format, name = name)).unwrap(); // dimensions getters write_dimensions_getters(dest, dimensions, "self.0", true); // writing the `as_surface` function if (dimensions == TextureDimensions::Texture2d || dimensions == TextureDimensions::Texture2dMultisample) && (ty == TextureType::Regular || ty == TextureType::Integral || ty == TextureType::Unsigned) { (write!(dest, " /// Starts drawing on the texture. /// /// All the function calls to the framebuffer will draw on the texture instead /// of the screen. /// /// ## Low-level information /// /// The first time that this function is called, a FrameBuffer Object will be /// created and cached. The following calls to `as_surface` will load the existing /// FBO and re-use it. When the texture is destroyed, the FBO is destroyed too. /// #[inline] pub fn as_surface<'a>(&'a self) -> framebuffer::SimpleFrameBuffer<'a> {{ self.sync_shader_writes_for_surface(); framebuffer::SimpleFrameBuffer::new(self.0.get_context(), self).unwrap() }} /// Call this function if you write to this texture in a shader with Image Store /// operations, and you want to use the texture as a Surface or Framebuffer Object. /// /// This function issues a memory barrier if the texture has been written to in a /// shader via Image Store operations. #[inline] pub fn sync_shader_writes_for_surface(&self) {{ use crate::ContextExt; let mut ctxt = self.0.get_context().make_current(); self.0.prepare_for_access(&mut ctxt, crate::TextureAccess::Framebuffer); }} ")).unwrap(); } // writing the `get_mipmap_levels` function (write!(dest, " /// Returns the number of mipmap levels of the texture. /// /// The minimum value is 1, since there is always a main texture. #[inline] pub fn get_mipmap_levels(&self) -> u32 {{ self.0.get_mipmap_levels() }} ")).unwrap(); // writing the `read` functions // TODO: implement for other types too if dimensions == TextureDimensions::Texture2d && (ty == TextureType::Regular || ty == TextureType::Srgb || ty == TextureType::Unsigned || is_compressed) { (write!(dest, r#" /// Reads the content of the texture to RAM. This method may only read `U8U8U8U8` /// data, as it is the only format guaranteed to be supported across all OpenGL /// versions. /// /// You should avoid doing this at all cost during performance-critical /// operations (for example, while you're drawing). /// Use `read_to_pixel_buffer` instead. #[inline] pub fn read(&self) -> T where T: Texture2dDataSink<(u8, u8, u8, u8)> {{ unsafe {{ self.unchecked_read() }} }} "#)).unwrap(); (write!(dest, r#" /// Reads the content of the texture into a buffer in video memory. This method may /// only read `U8U8U8U8` data, as it is the only format guaranteed to be supported /// across all OpenGL versions. /// /// This operation copies the texture's data into a buffer in video memory /// (a pixel buffer). Contrary to the `read` function, this operation is /// done asynchronously and doesn't need a synchronization. #[inline] pub fn read_to_pixel_buffer(&self) -> PixelBuffer<(u8, u8, u8, u8)> {{ unsafe {{ self.unchecked_read_to_pixel_buffer() }} }} "#)).unwrap(); (write!(dest, r#" /// Unsafely reads the content of the texture to RAM in the specified pixel format. /// It is possible that the current OpenGL context does not support the given /// format, in which case the returned data will be invalid. /// /// You should avoid doing this at all cost during performance-critical /// operations (for example, while you're drawing). /// Use `read_to_pixel_buffer` instead. #[inline] pub unsafe fn unchecked_read(&self) -> T where T: Texture2dDataSink

, P: PixelValue {{ let rect = Rect {{ left: 0, bottom: 0, width: self.get_width(), height: self.get_height().unwrap_or(1) }}; self.0.main_level().first_layer().into_image(None).unwrap().raw_read(&rect) }} "#)).unwrap(); (write!(dest, r#" /// Unsafely reads the content of the texture into a buffer in video memory. It is /// possible that the current OpenGL context does not support the given format, in /// which case the returned data will be invalid. /// /// This operation copies the texture's data into a buffer in video memory /// (a pixel buffer). Contrary to the `read` function, this operation is /// done asynchronously and doesn't need a synchronization. #[inline] pub unsafe fn unchecked_read_to_pixel_buffer

(&self) -> PixelBuffer

where P: PixelValue {{ let rect = Rect {{ left: 0, bottom: 0, width: self.get_width(), height: self.get_height().unwrap_or(1) }}; let pb = PixelBuffer::new_empty(self.0.get_context(), rect.width as usize * rect.height as usize); self.0.main_level().first_layer().into_image(None).unwrap() .raw_read_to_pixel_buffer(&rect, &pb); pb }} "#)).unwrap(); } // writing the `read_compressed_data` function if is_compressed && !dimensions.is_array() { (write!(dest, r#" /// Reads the content of the texture to RAM without decompressing it before. /// /// You should avoid doing this at all cost during performance-critical /// operations (for example, while you're drawing). /// /// Returns the compressed format of the texture and the compressed data, gives /// `None` when the internal compression format is generic or unknown. #[inline] pub fn read_compressed_data(&self) -> Option<({format}, Vec)> {{ self.main_level().read_compressed_data() }} "#, format = relevant_format)).unwrap(); } // writing the `write` function // TODO: implement for other types too if dimensions == TextureDimensions::Texture2d && (ty == TextureType::Regular || ty == TextureType::Srgb || is_compressed) { let compressed_restrictions = if is_compressed { r#" /// /// Calling this for compressed textures will result in a panic of type INVALID_OPERATION /// if `Rect::bottom` or `Rect::width` is not equal to 0 (border). In addition, the contents /// of any texel outside the region modified by such a call are undefined. These /// restrictions may be relaxed for specific compressed internal formats whose images /// are easily edited. "# } else { "" }; (write!(dest, r#" /// Uploads some data in the texture. /// /// Note that this may cause a synchronization if you use the texture right before /// or right after this call. Prefer creating a whole new texture if you change a /// huge part of it. /// /// ## Panic /// /// Panics if the the dimensions of `data` don't match the `Rect`. {compressed_restrictions} #[inline] pub fn write<'a, T>(&self, rect: Rect, data: T) where T: {data_source_trait}<'a> {{ self.main_level().write(rect, data) }} "#, data_source_trait = data_source_trait, compressed_restrictions = compressed_restrictions)).unwrap(); } // writing the `write_compressed_data` function // TODO: implement for other types too if dimensions == TextureDimensions::Texture2d && is_compressed { (write!(dest, r#" /// Uploads some data in the texture by using a compressed format as input. /// /// Note that this may cause a synchronization if you use the texture right before /// or right after this call. Prefer creating a whole new texture if you change a /// huge part of it. /// /// ## Panic /// /// Panics if the the dimensions of `data` don't match the `Rect`. /// /// Calling this will result in a panic of type INVALID_OPERATION error if `Rect::width` /// or `Rect::height` is not equal to 0 (border), or if the written dimensions do not match /// the original texture dimensions. The contents of any texel outside the region modified /// by the call are undefined. These restrictions may be relaxed for specific compressed /// internal formats whose images are easily edited. #[inline] pub fn write_compressed_data(&self, rect: Rect, data: &[u8], width: u32, height: u32, format: {format}) -> Result<(), ()> {{ // FIXME is having width and height as parameter redundant as rect kinda of // already provides them? self.main_level().write_compressed_data(rect, data, width, height, format) }} "#, format = relevant_format)).unwrap(); } // `resident_if_supported` (write!(dest, r#" /// Turns the texture into a `ResidentTexture`. /// /// This allows you to use the texture in a much more efficient way by storing /// a "reference to it" in a buffer (actually not a reference but a raw pointer). /// /// See the documentation of `ResidentTexture` for more infos. #[inline] pub fn resident(self) -> Result {{ ResidentTexture::new(self.0) }} "#)).unwrap(); // writing the layer & mipmap access functions if dimensions.is_array() { (write!(dest, r#" /// Access the first layer of this texture. #[inline] pub fn first_layer(&self) -> {name}Layer {{ self.layer(0).unwrap() }} /// Access a single layer of this texture. #[inline] pub fn layer(&self, layer: u32) -> Option<{name}Layer> {{ self.0.layer(layer).map(|l| {name}Layer(l, self)) }} "#, name = name)).unwrap(); } (write!(dest, r#" /// Access a single mipmap level of this texture. #[inline] pub fn mipmap(&self, level: u32) -> Option<{name}Mipmap> {{ self.0.mipmap(level).map(|m| {name}Mipmap(m, self)) }} /// Access the main mipmap level of this texture. #[inline] pub fn main_level(&self) -> {name}Mipmap {{ self.mipmap(0).unwrap() }} "#, name = name)).unwrap(); // closing `impl Texture` block (writeln!(dest, "}}")).unwrap(); // the `Layer` struct if dimensions.is_array() { // writing the struct (write!(dest, r#" /// Represents a single layer of a `{name}`. /// /// Can be obtained by calling `{name}::layer()`. #[derive(Copy, Clone)] pub struct {name}Layer<'t>(TextureAnyLayer<'t>, &'t {name}); "#, name = name)).unwrap(); // opening `impl Layer` block (writeln!(dest, "impl<'t> {}Layer<'t> {{", name)).unwrap(); // dimensions getters write_dimensions_getters(dest, dimensions, "(self.1).0", false); // writing the `get_layer` and `get_texture` functions (write!(dest, " /// Returns the corresponding texture. #[inline] pub fn get_texture(&self) -> &'t {name} {{ &self.1 }} /// Returns the layer index. #[inline] pub fn get_layer(&self) -> u32 {{ self.0.get_layer() }} ", name = name)).unwrap(); // writing the `get_mipmap_levels` function (write!(dest, " /// Returns the number of mipmap levels of the texture. /// /// The minimum value is 1, since there is always a main texture. #[inline] pub fn get_mipmap_levels(&self) -> u32 {{ self.0.get_texture().get_mipmap_levels() }} ")).unwrap(); // writing the layer & mipmap access functions (write!(dest, r#" /// Access a single mipmap level of this layer. #[inline] pub fn mipmap(&self, level: u32) -> Option<{name}LayerMipmap<'t>> {{ self.0.mipmap(level).map(|m| {name}LayerMipmap(m, self.1)) }} /// Access the main mipmap level of this layer. #[inline] pub fn main_level(&self) -> {name}LayerMipmap<'t> {{ self.mipmap(0).unwrap() }} "#, name = name)).unwrap(); // closing `impl Layer` block (writeln!(dest, "}}")).unwrap(); } // the `Mipmap` struct { // writing the struct (write!(dest, r#" /// Represents a single mipmap level of a `{name}`. /// /// Can be obtained by calling `{name}::mipmap()`, `{name}::main_level()`, /// `{name}Layer::mipmap()` or `{name}Layer::main_level()`. #[derive(Copy, Clone)] pub struct {name}Mipmap<'t>(TextureAnyMipmap<'t>, &'t {name}); impl<'a> ::std::ops::Deref for {name}Mipmap<'a> {{ type Target = TextureAnyMipmap<'a>; #[inline] fn deref(&self) -> &TextureAnyMipmap<'a> {{ &self.0 }} }} "#, name = name)).unwrap(); // opening `impl Mipmap` block (writeln!(dest, "impl<'t> {}Mipmap<'t> {{", name)).unwrap(); // dimensions getters write_dimensions_getters(dest, dimensions, "self.0", true); // writing the `write` function for mipmaps. // TODO: implement for other types too if dimensions == TextureDimensions::Texture2d && (ty == TextureType::Regular || ty == TextureType::Srgb || is_compressed) { let compressed_restrictions = if is_compressed { r#" /// /// Calling this for compressed textures will result in a panic of type INVALID_OPERATION /// if `Rect::bottom` or `Rect::width` is not equal to 0 (border). In addition, the contents /// of any texel outside the region modified by such a call are undefined. These /// restrictions may be relaxed for specific compressed internal formats whose images /// are easily edited. "# } else { "" }; (write!(dest, r#" /// Uploads some data in the texture level. /// /// Note that this may cause a synchronization if you use the texture right before /// or right after this call. /// /// ## Panic /// /// Panics if the the dimensions of `data` don't match the `Rect`. {compressed_restrictions} pub fn write<'a, T>(&self, rect: Rect, data: T) where T: {data_source_trait}<'a> {{ let RawImage2d {{ data, width, height, format: client_format }} = data.into_raw(); assert_eq!(width, rect.width); assert_eq!(height, rect.height); let client_format = ClientFormatAny::ClientFormat(client_format); self.0.upload_texture(rect.left, rect.bottom, 0, (client_format, data), width, Some(height), None, true).unwrap() }} "#, data_source_trait = data_source_trait, compressed_restrictions = compressed_restrictions)).unwrap(); } // writing the `write_compressed_data` function for mipmaps. // TODO: implement for other types too if dimensions == TextureDimensions::Texture2d && is_compressed { (write!(dest, r#" /// Uploads some data in the texture level by using a compressed format as input. /// /// Note that this may cause a synchronization if you use the texture right before /// or right after this call. /// /// ## Panic /// /// Panics if the the dimensions of `data` don't match the `Rect`. /// /// Calling this will result in a panic of type INVALID_OPERATION error if `Rect::width` /// or `Rect::height` is not equal to 0 (border), or if the written dimensions do not match /// the original texture dimensions. The contents of any texel outside the region modified /// by the call are undefined. These restrictions may be relaxed for specific compressed /// internal formats whose images are easily edited. pub fn write_compressed_data(&self, rect: Rect, data: &[u8], width: u32, height: u32, format: {format}) -> Result<(), ()> {{ // FIXME is having width and height as parameter redundant as rect kinda of // already provides them? assert_eq!(width, rect.width); assert_eq!(height, rect.height); let data = Cow::Borrowed(data.as_ref()); let client_format = {client_format_any}(format); self.0.upload_texture(rect.left, rect.bottom, 0, (client_format, data), width, Some(height), None, false) }} "#, format = relevant_format, client_format_any = client_format_any_ty)).unwrap(); } // writing the `read_compressed_data` function for mipmaps if is_compressed && !dimensions.is_array() { (write!(dest, r#" /// Reads the content of the texture level to RAM without decompressing it before. /// /// You should avoid doing this at all cost during performance-critical /// operations (for example, while you're drawing). /// /// Returns the compressed format of the texture and the compressed data, gives /// `None` when the internal compression format is generic or unknown. #[inline] pub fn read_compressed_data(&self) -> Option<({format}, Vec)> {{ match self.0.download_compressed_data() {{ Some(({client_format_any}(format), buf)) => Some((format, buf)), None => None, _ => unreachable!(), }} }} "#, format = relevant_format, client_format_any = client_format_any_ty)).unwrap(); } // writing the `get_level` and `get_texture` functions (write!(dest, " /// Returns the corresponding texture. #[inline] pub fn get_texture(&self) -> &'t {name} {{ self.1 }} /// Returns the texture level. #[inline] pub fn get_level(&self) -> u32 {{ self.0.get_level() }} ", name = name)).unwrap(); if dimensions.is_array() { (write!(dest, " /// Access the first layer of this texture. #[inline] pub fn first_layer(&self) -> {name}LayerMipmap<'t> {{ self.layer(0).unwrap() }} /// Access a single layer of this texture. #[inline] pub fn layer(&self, layer: u32) -> Option<{name}LayerMipmap<'t>> {{ self.0.layer(layer).map(|l| {name}LayerMipmap(l, self.1)) }} ", name = name)).unwrap(); } if !dimensions.is_array() && dimensions.is_cube() { writeln!(dest, "/// Provides an object representing a single layer of this cubemap. pub fn image(&self, layer: CubeLayer) -> {name}Image<'t> {{ {name}Image(self.0.first_layer().into_image(Some(layer)).unwrap(), self.1) }}", name = name).unwrap(); } // closing `impl Mipmap` block (writeln!(dest, "}}")).unwrap(); if !dimensions.is_array() && !dimensions.is_cube() { // into raw image (writeln!(dest, "impl<'t> Into> for {name}Mipmap<'t> {{ fn into(self) -> TextureAnyImage<'t> {{ self.0.first_layer().into_image(None).unwrap() }} }}", name = name)).unwrap(); } } // the `LayerMipmap` struct if dimensions.is_array() { // writing the struct (write!(dest, r#" /// Represents a single layer of a mipmap level of a `{name}`. #[derive(Copy, Clone)] pub struct {name}LayerMipmap<'t>(TextureAnyLayerMipmap<'t>, &'t {name}); "#, name = name)).unwrap(); // opening `impl LayerMipmap` block (writeln!(dest, "impl<'t> {}LayerMipmap<'t> {{", name)).unwrap(); // dimensions getters write_dimensions_getters(dest, dimensions, "self.0", false); // to the image struct if dimensions.is_cube() { writeln!(dest, "/// Provides an object representing a single layer of this cubemap. pub fn image(&self, layer: CubeLayer) -> {name}Image<'t> {{ {name}Image(self.0.into_image(Some(layer)).unwrap(), self.1) }}", name = name).unwrap(); } // closing `impl LayerMipmap` block (writeln!(dest, "}}")).unwrap(); // attachment traits if !dimensions.is_cube() { // into raw image (writeln!(dest, "impl<'t> Into> for {name}LayerMipmap<'t> {{ fn into(self) -> TextureAnyImage<'t> {{ self.0.into_image(None).unwrap() }} }}", name = name)).unwrap(); } } // the `Image` struct, only for cubemaps if dimensions.is_cube() { // writing the struct (write!(dest, r#" /// Represents a single image of a mipmap level of a layer of `{name}`. #[derive(Copy, Clone)] pub struct {name}Image<'t>(TextureAnyImage<'t>, &'t {name}); "#, name = name)).unwrap(); // opening `impl Image` block (writeln!(dest, "impl<'t> {}Image<'t> {{", name)).unwrap(); // dimensions getters write_dimensions_getters(dest, dimensions, "self.0", false); // closing `impl Image` block (writeln!(dest, "}}")).unwrap(); // into raw image (writeln!(dest, "impl<'t> Into> for {name}Image<'t> {{ fn into(self) -> TextureAnyImage<'t> {{ self.0 }} }}", name = name)).unwrap(); } // implement the attachments traits { let attachment_type = if dimensions.is_cube() { format!("{}Image", name) } else if dimensions.is_array() { format!("{}LayerMipmap", name) } else { format!("{}Mipmap", name) }; match ty { TextureType::Regular | TextureType::Srgb | TextureType::Integral | TextureType::Unsigned => { (writeln!(dest, " impl<'t> crate::framebuffer::ToColorAttachment<'t> for {ty}<'t> {{ #[inline] fn to_color_attachment(self) -> crate::framebuffer::ColorAttachment<'t> {{ crate::framebuffer::ColorAttachment::Texture(self.into()) }} }} ", ty = attachment_type)).unwrap(); }, TextureType::Depth => { (writeln!(dest, " impl<'t> crate::framebuffer::ToDepthAttachment<'t> for {ty}<'t> {{ #[inline] fn to_depth_attachment(self) -> crate::framebuffer::DepthAttachment<'t> {{ crate::framebuffer::DepthAttachment::Texture(self.into()) }} }} ", ty = attachment_type)).unwrap(); }, TextureType::Stencil => { (writeln!(dest, " impl<'t> crate::framebuffer::ToStencilAttachment<'t> for {ty}<'t> {{ #[inline] fn to_stencil_attachment(self) -> crate::framebuffer::StencilAttachment<'t> {{ crate::framebuffer::StencilAttachment::Texture(self.into()) }} }} ", ty = attachment_type)).unwrap(); }, TextureType::DepthStencil => { (writeln!(dest, " impl<'t> crate::framebuffer::ToDepthStencilAttachment<'t> for {ty}<'t> {{ #[inline] fn to_depth_stencil_attachment(self) -> crate::framebuffer::DepthStencilAttachment<'t> {{ crate::framebuffer::DepthStencilAttachment::Texture(self.into()) }} }} ", ty = attachment_type)).unwrap(); }, _ => () } } // closing `mod module {` writeln!(dest, "}}").unwrap(); } fn write_dimensions_getters(dest: &mut W, dimensions: TextureDimensions, accessor: &str, write_array_size: bool) { writeln!(dest, r#" /// Returns the width of that image. #[inline] pub fn width(&self) -> u32 {{ {}.get_width() }} "#, accessor).unwrap(); match dimensions { TextureDimensions::Texture2d | TextureDimensions::Texture2dMultisample | TextureDimensions::Texture3d | TextureDimensions::Texture2dArray | TextureDimensions::Texture2dMultisampleArray | TextureDimensions::Cubemap | TextureDimensions::CubemapArray => { writeln!(dest, r#" /// Returns the height of that image. #[inline] pub fn height(&self) -> u32 {{ {}.get_height().unwrap() }} "#, accessor).unwrap(); }, _ => () }; match dimensions { TextureDimensions::Texture3d => { writeln!(dest, r#" /// Returns the depth of that image. #[inline] pub fn depth(&self) -> u32 {{ {}.get_depth().unwrap() }} "#, accessor).unwrap(); }, _ => () }; if write_array_size { match dimensions { TextureDimensions::Texture2dArray | TextureDimensions::Texture2dMultisampleArray | TextureDimensions::CubemapArray => { writeln!(dest, r#" /// Returns the number of array layers. #[inline] pub fn array_size(&self) -> u32 {{ {}.get_array_size().unwrap() }} "#, accessor).unwrap(); }, _ => () } }; match dimensions { TextureDimensions::Texture2dMultisample | TextureDimensions::Texture2dMultisampleArray => { writeln!(dest, r#" /// Returns the number of samples of that image. #[inline] pub fn samples(&self) -> u32 {{ {}.get_samples().unwrap() }} "#, accessor).unwrap(); }, _ => () }; match dimensions { TextureDimensions::Texture2d | TextureDimensions::Texture2dMultisample | TextureDimensions::Texture2dArray | TextureDimensions::Texture2dMultisampleArray => { writeln!(dest, r#" /// Returns the width and height of that image. #[inline] pub fn dimensions(&self) -> (u32, u32) {{ (self.width(), self.height()) }} "#).unwrap(); }, TextureDimensions::Texture3d => { writeln!(dest, r#" /// Returns the width, height and depth of that image. #[inline] pub fn dimensions(&self) -> (u32, u32, u32) {{ (self.width(), self.height(), self.depth()) }} "#).unwrap(); }, TextureDimensions::Cubemap | TextureDimensions::CubemapArray => { writeln!(dest, r#" /// Returns the dimension of that image. #[inline] pub fn dimensions(&self) -> u32 {{ self.width() }} "#).unwrap(); }, _ => () }; }