1use crate::core::texture::*;
2
3pub struct Texture2DArray {
10 context: Context,
11 id: crate::context::Texture,
12 width: u32,
13 height: u32,
14 depth: u32,
15 number_of_mip_maps: u32,
16 data_byte_size: usize,
17}
18
19impl Texture2DArray {
20 pub fn new(context: &Context, cpu_textures: &[&CpuTexture]) -> Self {
27 let cpu_texture = cpu_textures
28 .first()
29 .expect("Expect at least one texture in a texture array");
30 match &cpu_texture.data {
31 TextureData::RU8(_) => Self::new_with_data(
32 context,
33 cpu_texture,
34 &cpu_textures.iter().map(|t| ru8_data(t)).collect::<Vec<_>>(),
35 ),
36 TextureData::RgU8(_) => Self::new_with_data(
37 context,
38 cpu_texture,
39 &cpu_textures
40 .iter()
41 .map(|t| rgu8_data(t))
42 .collect::<Vec<_>>(),
43 ),
44 TextureData::RgbU8(_) => Self::new_with_data(
45 context,
46 cpu_texture,
47 &cpu_textures
48 .iter()
49 .map(|t| rgbu8_data(t))
50 .collect::<Vec<_>>(),
51 ),
52 TextureData::RgbaU8(_) => Self::new_with_data(
53 context,
54 cpu_texture,
55 &cpu_textures
56 .iter()
57 .map(|t| rgbau8_data(t))
58 .collect::<Vec<_>>(),
59 ),
60 TextureData::RF16(_) => Self::new_with_data(
61 context,
62 cpu_texture,
63 &cpu_textures
64 .iter()
65 .map(|t| rf16_data(t))
66 .collect::<Vec<_>>(),
67 ),
68 TextureData::RgF16(_) => Self::new_with_data(
69 context,
70 cpu_texture,
71 &cpu_textures
72 .iter()
73 .map(|t| rgf16_data(t))
74 .collect::<Vec<_>>(),
75 ),
76 TextureData::RgbF16(_) => Self::new_with_data(
77 context,
78 cpu_texture,
79 &cpu_textures
80 .iter()
81 .map(|t| rgbf16_data(t))
82 .collect::<Vec<_>>(),
83 ),
84 TextureData::RgbaF16(_) => Self::new_with_data(
85 context,
86 cpu_texture,
87 &cpu_textures
88 .iter()
89 .map(|t| rgbaf16_data(t))
90 .collect::<Vec<_>>(),
91 ),
92 TextureData::RF32(_) => Self::new_with_data(
93 context,
94 cpu_texture,
95 &cpu_textures
96 .iter()
97 .map(|t| rf32_data(t))
98 .collect::<Vec<_>>(),
99 ),
100 TextureData::RgF32(_) => Self::new_with_data(
101 context,
102 cpu_texture,
103 &cpu_textures
104 .iter()
105 .map(|t| rgf32_data(t))
106 .collect::<Vec<_>>(),
107 ),
108 TextureData::RgbF32(_) => Self::new_with_data(
109 context,
110 cpu_texture,
111 &cpu_textures
112 .iter()
113 .map(|t| rgbf32_data(t))
114 .collect::<Vec<_>>(),
115 ),
116 TextureData::RgbaF32(_) => Self::new_with_data(
117 context,
118 cpu_texture,
119 &cpu_textures
120 .iter()
121 .map(|t| rgbaf32_data(t))
122 .collect::<Vec<_>>(),
123 ),
124 }
125 }
126
127 fn new_with_data<T: TextureDataType>(
128 context: &Context,
129 cpu_texture: &CpuTexture,
130 data: &[&[T]],
131 ) -> Self {
132 let texture = Self::new_empty::<T>(
133 context,
134 cpu_texture.width,
135 cpu_texture.height,
136 data.len() as u32,
137 cpu_texture.min_filter,
138 cpu_texture.mag_filter,
139 cpu_texture.mipmap,
140 cpu_texture.wrap_s,
141 cpu_texture.wrap_t,
142 );
143 texture.fill(data);
144 texture
145 }
146
147 pub fn new_empty<T: TextureDataType>(
153 context: &Context,
154 width: u32,
155 height: u32,
156 depth: u32,
157 min_filter: Interpolation,
158 mag_filter: Interpolation,
159 mipmap: Option<Mipmap>,
160 wrap_s: Wrapping,
161 wrap_t: Wrapping,
162 ) -> Self {
163 unsafe {
164 Self::new_unchecked::<T>(
165 context,
166 width,
167 height,
168 depth,
169 min_filter,
170 mag_filter,
171 mipmap,
172 wrap_s,
173 wrap_t,
174 |texture| {
175 context.tex_storage_3d(
176 crate::context::TEXTURE_2D_ARRAY,
177 texture.number_of_mip_maps() as i32,
178 T::internal_format(),
179 width as i32,
180 height as i32,
181 depth as i32,
182 )
183 },
184 )
185 }
186 }
187
188 pub fn fill<T: TextureDataType>(&self, data: &[&[T]]) {
196 for (i, data) in data.iter().enumerate() {
197 self.fill_layer(i as u32, data);
198 }
199 }
200
201 pub fn fill_layer<T: TextureDataType>(&self, layer: u32, data: &[T]) {
209 if layer >= self.depth {
210 panic!(
211 "cannot fill the layer {} with data, since there are only {} layers in the texture array",
212 layer, self.depth
213 )
214 }
215 check_data_length::<T>(self.width, self.height, 1, self.data_byte_size, data.len());
216 self.bind();
217 let mut data = (*data).to_owned();
218 flip_y(&mut data, self.width as usize, self.height as usize);
219 unsafe {
220 self.context.tex_sub_image_3d(
221 crate::context::TEXTURE_2D_ARRAY,
222 0,
223 0,
224 0,
225 layer as i32,
226 self.width as i32,
227 self.height as i32,
228 1,
229 format_from_data_type::<T>(),
230 T::data_type(),
231 crate::context::PixelUnpackData::Slice(Some(to_byte_slice(&data))),
232 );
233 }
234 self.generate_mip_maps();
235 }
236
237 pub fn as_color_target<'a>(
246 &'a self,
247 layers: &'a [u32],
248 mip_level: Option<u32>,
249 ) -> ColorTarget<'a> {
250 ColorTarget::new_texture_2d_array(&self.context, self, layers, mip_level)
251 }
252
253 pub fn width(&self) -> u32 {
255 self.width
256 }
257
258 pub fn height(&self) -> u32 {
260 self.height
261 }
262
263 pub fn depth(&self) -> u32 {
265 self.depth
266 }
267
268 pub fn number_of_mip_maps(&self) -> u32 {
270 self.number_of_mip_maps
271 }
272
273 pub(in crate::core) fn generate_mip_maps(&self) {
274 if self.number_of_mip_maps > 1 {
275 self.bind();
276 unsafe {
277 self.context
278 .generate_mipmap(crate::context::TEXTURE_2D_ARRAY);
279 }
280 }
281 }
282
283 pub(in crate::core) fn bind_as_color_target(&self, layer: u32, channel: u32, mip_level: u32) {
284 unsafe {
285 self.context.framebuffer_texture_layer(
286 crate::context::DRAW_FRAMEBUFFER,
287 crate::context::COLOR_ATTACHMENT0 + channel,
288 Some(self.id),
289 mip_level as i32,
290 layer as i32,
291 );
292 }
293 }
294
295 pub(in crate::core) fn bind(&self) {
296 unsafe {
297 self.context
298 .bind_texture(crate::context::TEXTURE_2D_ARRAY, Some(self.id));
299 }
300 }
301
302 pub unsafe fn new_unchecked<T: TextureDataType>(
313 context: &Context,
314 width: u32,
315 height: u32,
316 depth: u32,
317 min_filter: Interpolation,
318 mag_filter: Interpolation,
319 mipmap: Option<Mipmap>,
320 wrap_s: Wrapping,
321 wrap_t: Wrapping,
322 callback: impl FnOnce(&Self),
323 ) -> Self {
324 let id = generate(context);
325 let number_of_mip_maps = calculate_number_of_mip_maps::<T>(mipmap, width, height, None);
326 let texture = Self {
327 context: context.clone(),
328 id,
329 width,
330 height,
331 depth,
332 number_of_mip_maps,
333 data_byte_size: std::mem::size_of::<T>(),
334 };
335 texture.bind();
336 set_parameters(
337 context,
338 crate::context::TEXTURE_2D_ARRAY,
339 min_filter,
340 mag_filter,
341 if number_of_mip_maps == 1 {
342 None
343 } else {
344 mipmap
345 },
346 wrap_s,
347 wrap_t,
348 None,
349 );
350 callback(&texture);
351 texture.generate_mip_maps();
352 texture
353 }
354}
355
356impl Drop for Texture2DArray {
357 fn drop(&mut self) {
358 unsafe {
359 self.context.delete_texture(self.id);
360 }
361 }
362}