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 .get(0)
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 mut 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 let id = generate(context);
164 let number_of_mip_maps = calculate_number_of_mip_maps::<T>(mipmap, width, height, None);
165 let texture = Self {
166 context: context.clone(),
167 id,
168 width,
169 height,
170 depth,
171 number_of_mip_maps,
172 data_byte_size: std::mem::size_of::<T>(),
173 };
174 texture.bind();
175 set_parameters(
176 context,
177 crate::context::TEXTURE_2D_ARRAY,
178 min_filter,
179 mag_filter,
180 if number_of_mip_maps == 1 {
181 None
182 } else {
183 mipmap
184 },
185 wrap_s,
186 wrap_t,
187 None,
188 );
189 unsafe {
190 context.tex_storage_3d(
191 crate::context::TEXTURE_2D_ARRAY,
192 number_of_mip_maps as i32,
193 T::internal_format(),
194 width as i32,
195 height as i32,
196 depth as i32,
197 );
198 }
199 texture.generate_mip_maps();
200 texture
201 }
202
203 pub fn fill<T: TextureDataType>(&mut self, data: &[&[T]]) {
211 for (i, data) in data.iter().enumerate() {
212 self.fill_layer(i as u32, data);
213 }
214 }
215
216 pub fn fill_layer<T: TextureDataType>(&mut self, layer: u32, data: &[T]) {
224 if layer >= self.depth {
225 panic!(
226 "cannot fill the layer {} with data, since there are only {} layers in the texture array",
227 layer, self.depth
228 )
229 }
230 check_data_length::<T>(self.width, self.height, 1, self.data_byte_size, data.len());
231 self.bind();
232 let mut data = (*data).to_owned();
233 flip_y(&mut data, self.width as usize, self.height as usize);
234 unsafe {
235 self.context.tex_sub_image_3d(
236 crate::context::TEXTURE_2D_ARRAY,
237 0,
238 0,
239 0,
240 layer as i32,
241 self.width as i32,
242 self.height as i32,
243 1,
244 format_from_data_type::<T>(),
245 T::data_type(),
246 crate::context::PixelUnpackData::Slice(to_byte_slice(&data)),
247 );
248 }
249 self.generate_mip_maps();
250 }
251
252 pub fn as_color_target<'a>(
261 &'a mut self,
262 layers: &'a [u32],
263 mip_level: Option<u32>,
264 ) -> ColorTarget<'a> {
265 ColorTarget::new_texture_2d_array(&self.context, self, layers, mip_level)
266 }
267
268 pub fn width(&self) -> u32 {
270 self.width
271 }
272
273 pub fn height(&self) -> u32 {
275 self.height
276 }
277
278 pub fn depth(&self) -> u32 {
280 self.depth
281 }
282
283 pub fn number_of_mip_maps(&self) -> u32 {
285 self.number_of_mip_maps
286 }
287
288 pub(in crate::core) fn generate_mip_maps(&self) {
289 if self.number_of_mip_maps > 1 {
290 self.bind();
291 unsafe {
292 self.context
293 .generate_mipmap(crate::context::TEXTURE_2D_ARRAY);
294 }
295 }
296 }
297
298 pub(in crate::core) fn bind_as_color_target(&self, layer: u32, channel: u32, mip_level: u32) {
299 unsafe {
300 self.context.framebuffer_texture_layer(
301 crate::context::DRAW_FRAMEBUFFER,
302 crate::context::COLOR_ATTACHMENT0 + channel,
303 Some(self.id),
304 mip_level as i32,
305 layer as i32,
306 );
307 }
308 }
309
310 pub(in crate::core) fn bind(&self) {
311 unsafe {
312 self.context
313 .bind_texture(crate::context::TEXTURE_2D_ARRAY, Some(self.id));
314 }
315 }
316}
317
318impl Drop for Texture2DArray {
319 fn drop(&mut self) {
320 unsafe {
321 self.context.delete_texture(self.id);
322 }
323 }
324}