gavle/
texture.rs

1use glow::{Context, HasContext};
2use std::rc::Rc;
3use crate::access::{AccessLock, UnitAccessLock};
4use std::num::NonZeroU32;
5
6/** Inner shared structure of the texture. */
7#[derive(Debug)]
8pub(crate) struct InnerTexture {
9	/** Reference to the shared context. */
10	pub(crate) context: Rc<Context>,
11	/** Name of this texture inside of that context. */
12	pub(crate) texture: <Context as HasContext>::Texture,
13	/** Access control structure. */
14	pub(crate) access: UnitAccessLock,
15	/** Format this texture is in. */
16	pub(crate) format: TextureFormat,
17	/** Extent of this texture. */
18	pub(crate) extent: TextureExtent,
19}
20impl Drop for InnerTexture {
21	fn drop(&mut self) {
22		unsafe {
23			let _atom = self.access.acquire_write_guarded();
24			self.context.delete_texture(self.texture)
25		}
26	}
27}
28impl AccessLock for InnerTexture {
29	fn write_locks(&self) -> usize {
30		self.access.write_locks()
31	}
32	fn read_locks(&self) -> usize {
33		self.access.read_locks()
34	}
35	fn acquire_write(&self) {
36		self.access.acquire_write();
37	}
38	fn release_write(&self) {
39		self.access.release_write();
40	}
41	fn acquire_read(&self) {
42		self.access.acquire_read();
43	}
44	fn release_read(&self) {
45		self.access.release_read();
46	}
47}
48
49#[derive(Debug)]
50pub struct Texture {
51	/** The inner shared structure of this texture. */
52	pub(crate) inner: Rc<InnerTexture>
53}
54impl Texture {
55	/** The format this texture is stored in. */
56	pub fn format(&self) -> TextureFormat {
57		self.inner.format
58	}
59	/** Returns the underlying handle to the texture object. */
60	pub unsafe fn as_raw_handle(&self) -> <Context as HasContext>::Texture {
61		self.inner.texture
62	}
63}
64impl AccessLock for Texture {
65	fn write_locks(&self) -> usize {
66		self.inner.access.write_locks()
67	}
68	fn read_locks(&self) -> usize {
69		self.inner.access.read_locks()
70	}
71	fn acquire_write(&self) {
72		self.inner.access.acquire_write()
73	}
74	fn release_write(&self) {
75		self.inner.access.release_write()
76	}
77	fn acquire_read(&self) {
78		self.inner.access.acquire_read()
79	}
80	fn release_read(&self) {
81		self.inner.access.release_read()
82	}
83}
84
85/** Formats textures are allowed to have. */
86#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
87pub enum TextureFormat {
88	/** RGBA with a 32-bit floating point for every component. */
89	Rgba32Float,
90	/** RGBA with an 8-bit unsigned integer for every component. */
91	Rgba8Unorm,
92	/** Combined depth-stencil format. 24-bit depth and 8-bit stencil. */
93	Depth24Stencil8
94}
95
96
97/** Filtering options for textures.
98 *
99 * The names in this enum are based on the one-dimensional filtering methods,
100 * however, when used for higher dimensional textures, they correspond to the
101 * higher dimensional equivalent of the method (e.g. "Linear" refers to bilinear
102 * filtering in two dimensions and trilinear filtering in three dimensions). */
103#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
104pub enum TextureFilter {
105	/** Nearest neighbor based filtering. */
106	Nearest,
107	/** Linear based filtering. */
108	Linear
109}
110impl TextureFilter {
111	/** Get the OpenGL enum value for the current variant. */
112	pub(crate) fn as_opengl(&self, min: bool) -> u32 {
113		match self {
114			Self::Nearest => if min { glow::NEAREST_MIPMAP_NEAREST } else { glow::NEAREST },
115			Self::Linear => if min { glow::LINEAR_MIPMAP_LINEAR } else { glow::LINEAR },
116		}
117	}
118}
119
120/** Descriptor specifying all of the parameters for a newly created texture. */
121#[derive(Debug, Copy, Clone)]
122pub struct TextureDescriptor {
123	/** Extent and dimensional layout of this texture. */
124	pub extent: TextureExtent,
125	/** Format the texture is gonna be stored and uploaded in. */
126	pub format: TextureFormat,
127	/** How this texture  */
128	pub mip: Mipmap,
129}
130
131/** Mipmap behavior of a texture. */
132#[derive(Debug, Copy, Clone)]
133pub enum Mipmap {
134	/** No mips will be generated or available for this texture. */
135	None,
136	/** The given number of mips will be available, and the user must provide
137	 * the image data for each of the mips manually. */
138	Manual {
139		/** Number of mip levels of the texture. */
140		levels: NonZeroU32,
141	},
142	/** All of the mip levels that can be generated for this texture will be
143	 * generated automatically by Gavle.
144	 *
145	 * Often, what you'll want is to pre-bake the mipmaps before runtime in
146	 * order to save on initialization time, seeing as mipmap generation is very
147	 * expensive. */
148	#[cfg(feature = "mipmap-generation")]
149	Automatic {
150		/** Filter to be used to scale down the image during generation of the
151		 * mip levels. T */
152		filter: FilterType
153	},
154}
155
156#[cfg(feature = "mipmap-generation")]
157pub use image::imageops::FilterType;
158
159/** Extents of a given texture in their given dimensional layout. */
160#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
161pub enum TextureExtent {
162	/** One-dimensional texture. */
163	D1 {
164		length: u32,
165	},
166	/** Two-dimensional texture. */
167	D2 {
168		width: u32,
169		height: u32,
170	},
171	/** Array of two-dimensional textures. */
172	D2Array {
173		width: u32,
174		height: u32,
175		layers: u32,
176	},
177	/** Three-dimensional texture. */
178	D3 {
179		width: u32,
180		height: u32,
181		depth: u32
182	}
183}
184
185#[derive(Debug, thiserror::Error)]
186pub enum TextureError {
187	#[error("failed to create a new texture: {what}")]
188	CreationError {
189		what: String
190	},
191	#[error("the bounds given to the texture are invalid")]
192	InvalidBounds {
193		what: String
194	}
195}