1mod texture2d;
5#[doc(inline)]
6pub use texture2d::*;
7
8mod texture_cube_map;
9#[doc(inline)]
10pub use texture_cube_map::*;
11
12mod depth_texture2d;
13#[doc(inline)]
14pub use depth_texture2d::*;
15
16mod texture2d_array;
17#[doc(inline)]
18pub use texture2d_array::*;
19
20mod texture2d_multisample;
21#[doc(inline)]
22pub(in crate::core) use texture2d_multisample::*;
23
24mod texture3d;
25#[doc(inline)]
26pub use texture3d::*;
27
28mod depth_texture2d_array;
29#[doc(inline)]
30pub use depth_texture2d_array::*;
31
32mod depth_texture_cube_map;
33#[doc(inline)]
34pub use depth_texture_cube_map::*;
35
36mod depth_texture2d_multisample;
37#[doc(inline)]
38pub(in crate::core) use depth_texture2d_multisample::*;
39
40use data_type::*;
41pub use three_d_asset::texture::{
42    Interpolation, Mipmap, Texture2D as CpuTexture, Texture3D as CpuTexture3D, TextureData,
43    Wrapping,
44};
45
46pub trait TextureDataType: DataType {}
48impl TextureDataType for u8 {}
49impl TextureDataType for f16 {}
50impl TextureDataType for f32 {}
51
52impl<T: TextureDataType + PrimitiveDataType> TextureDataType for Vector2<T> {}
53impl<T: TextureDataType + PrimitiveDataType> TextureDataType for Vector3<T> {}
54impl<T: TextureDataType + PrimitiveDataType> TextureDataType for Vector4<T> {}
55impl<T: TextureDataType + PrimitiveDataType> TextureDataType for [T; 2] {}
56impl<T: TextureDataType + PrimitiveDataType> TextureDataType for [T; 3] {}
57impl<T: TextureDataType + PrimitiveDataType> TextureDataType for [T; 4] {}
58
59impl TextureDataType for Quat {}
60
61pub trait DepthTextureDataType: DepthDataType {}
63
64#[allow(non_camel_case_types)]
66#[derive(Clone, Copy, Default, Debug)]
67pub struct f24 {}
68
69impl DepthTextureDataType for f16 {}
70impl DepthTextureDataType for f24 {}
71impl DepthTextureDataType for f32 {}
72
73#[derive(Clone, Copy)]
77#[allow(missing_docs)]
78pub enum ColorTexture<'a> {
79    Single(&'a Texture2D),
81    Array {
83        texture: &'a Texture2DArray,
84        layers: &'a [u32],
85    },
86    CubeMap {
88        texture: &'a TextureCubeMap,
89        sides: &'a [CubeMapSide],
90    },
91}
92
93impl ColorTexture<'_> {
94    pub fn width(&self) -> u32 {
98        match self {
99            ColorTexture::Single(texture) => texture.width(),
100            ColorTexture::Array { texture, .. } => texture.width(),
101            ColorTexture::CubeMap { texture, .. } => texture.width(),
102        }
103    }
104
105    pub fn height(&self) -> u32 {
109        match self {
110            ColorTexture::Single(texture) => texture.height(),
111            ColorTexture::Array { texture, .. } => texture.height(),
112            ColorTexture::CubeMap { texture, .. } => texture.height(),
113        }
114    }
115
116    pub fn fragment_shader_source(&self) -> String {
120        match self {
121            Self::Single(_) => "
122                uniform sampler2D colorMap;
123                vec4 sample_color(vec2 uv)
124                {
125                    return texture(colorMap, uv);
126                }"
127            .to_owned(),
128            Self::Array { .. } => "
129                uniform sampler2DArray colorMap;
130                uniform int colorLayers[4];
131                vec4 sample_color(vec2 uv)
132                {
133                    return texture(colorMap, vec3(uv, colorLayers[0]));
134                }
135                vec4 sample_layer(vec2 uv, int index)
136                {
137                    return texture(colorMap, vec3(uv, colorLayers[index]));
138                }"
139            .to_owned(),
140            Self::CubeMap { .. } => todo!(),
141        }
142    }
143
144    pub fn id(&self) -> u16 {
148        match self {
149            Self::Single { .. } => 1u16 << 3,
150            Self::Array { .. } => 10u16 << 3,
151            Self::CubeMap { .. } => {
152                todo!()
153            }
154        }
155    }
156
157    pub fn use_uniforms(&self, program: &Program) {
161        match self {
162            Self::Single(texture) => program.use_texture("colorMap", texture),
163            Self::Array { texture, layers } => {
164                let mut la: [i32; 4] = [0; 4];
165                layers
166                    .iter()
167                    .enumerate()
168                    .for_each(|(i, l)| la[i] = *l as i32);
169                program.use_uniform_array("colorLayers", &la);
170                program.use_texture_array("colorMap", texture);
171            }
172            Self::CubeMap { .. } => todo!(),
173        }
174    }
175}
176
177#[derive(Clone, Copy)]
181#[allow(missing_docs)]
182pub enum DepthTexture<'a> {
183    Single(&'a DepthTexture2D),
185    Array {
187        texture: &'a DepthTexture2DArray,
188        layer: u32,
189    },
190    CubeMap {
192        texture: &'a DepthTextureCubeMap,
193        side: CubeMapSide,
194    },
195}
196
197impl DepthTexture<'_> {
198    pub fn width(&self) -> u32 {
202        match self {
203            DepthTexture::Single(texture) => texture.width(),
204            DepthTexture::Array { texture, .. } => texture.width(),
205            DepthTexture::CubeMap { texture, .. } => texture.width(),
206        }
207    }
208
209    pub fn height(&self) -> u32 {
213        match self {
214            DepthTexture::Single(texture) => texture.height(),
215            DepthTexture::Array { texture, .. } => texture.height(),
216            DepthTexture::CubeMap { texture, .. } => texture.height(),
217        }
218    }
219    pub fn fragment_shader_source(&self) -> String {
223        match self {
224            Self::Single { .. } => "
225                uniform sampler2D depthMap;
226                float sample_depth(vec2 uv)
227                {
228                    return texture(depthMap, uv).x;
229                }"
230            .to_owned(),
231            Self::Array { .. } => "
232                uniform sampler2DArray depthMap;
233                uniform int depthLayer;
234                float sample_depth(vec2 uv)
235                {
236                    return texture(depthMap, vec3(uv, depthLayer)).x;
237                }"
238            .to_owned(),
239            Self::CubeMap { .. } => {
240                todo!()
241            }
242        }
243    }
244
245    pub fn id(&self) -> u16 {
249        match self {
250            Self::Single { .. } => 1u16,
251            Self::Array { .. } => 10u16,
252            Self::CubeMap { .. } => {
253                todo!()
254            }
255        }
256    }
257
258    pub fn use_uniforms(&self, program: &Program) {
262        match self {
263            Self::Single(texture) => program.use_depth_texture("depthMap", texture),
264            Self::Array { texture, layer } => {
265                program.use_uniform("depthLayer", layer);
266                program.use_depth_texture_array("depthMap", texture);
267            }
268            Self::CubeMap { .. } => todo!(),
269        }
270    }
271}
272
273use crate::core::*;
274
275fn generate(context: &Context) -> crate::context::Texture {
278    unsafe { context.create_texture().expect("Failed creating texture") }
279}
280
281fn set_parameters(
282    context: &Context,
283    target: u32,
284    min_filter: Interpolation,
285    mag_filter: Interpolation,
286    mipmap: Option<Mipmap>,
287    wrap_s: Wrapping,
288    wrap_t: Wrapping,
289    wrap_r: Option<Wrapping>,
290) {
291    unsafe {
292        match mipmap {
293            None => context.tex_parameter_i32(
294                target,
295                crate::context::TEXTURE_MIN_FILTER,
296                interpolation_from(min_filter),
297            ),
298            Some(Mipmap {
299                filter: Interpolation::Nearest,
300                ..
301            }) => {
302                if min_filter == Interpolation::Nearest {
303                    context.tex_parameter_i32(
304                        target,
305                        crate::context::TEXTURE_MIN_FILTER,
306                        crate::context::NEAREST_MIPMAP_NEAREST as i32,
307                    );
308                } else {
309                    context.tex_parameter_i32(
310                        target,
311                        crate::context::TEXTURE_MIN_FILTER,
312                        crate::context::LINEAR_MIPMAP_NEAREST as i32,
313                    )
314                }
315            }
316            Some(Mipmap {
317                filter: Interpolation::Linear,
318                ..
319            }) => {
320                if min_filter == Interpolation::Nearest {
321                    context.tex_parameter_i32(
322                        target,
323                        crate::context::TEXTURE_MIN_FILTER,
324                        crate::context::NEAREST_MIPMAP_LINEAR as i32,
325                    );
326                } else {
327                    context.tex_parameter_i32(
328                        target,
329                        crate::context::TEXTURE_MIN_FILTER,
330                        crate::context::LINEAR_MIPMAP_LINEAR as i32,
331                    )
332                }
333            }
334            _ => panic!("Can only sample textures using 'NEAREST' or 'LINEAR' interpolation"),
335        }
336        if let Some(Mipmap { max_ratio, .. }) = mipmap {
337            let extensions = context.supported_extensions();
338            if extensions.contains("GL_ARB_texture_filter_anisotropic") ||
340                extensions.contains("GL_EXT_texture_filter_anisotropic") ||
341                extensions.contains("EXT_texture_filter_anisotropic")
343            {
344                let max_ratio = max_ratio.min(
345                    context.get_parameter_i32(crate::context::MAX_TEXTURE_MAX_ANISOTROPY_EXT)
346                        as u32,
347                );
348                context.tex_parameter_i32(
349                    target,
350                    crate::context::TEXTURE_MAX_ANISOTROPY_EXT,
351                    max_ratio as i32,
352                );
353            }
354        }
355        context.tex_parameter_i32(
356            target,
357            crate::context::TEXTURE_MAG_FILTER,
358            interpolation_from(mag_filter),
359        );
360        context.tex_parameter_i32(
361            target,
362            crate::context::TEXTURE_WRAP_S,
363            wrapping_from(wrap_s),
364        );
365        context.tex_parameter_i32(
366            target,
367            crate::context::TEXTURE_WRAP_T,
368            wrapping_from(wrap_t),
369        );
370        if let Some(r) = wrap_r {
371            context.tex_parameter_i32(target, crate::context::TEXTURE_WRAP_R, wrapping_from(r));
372        }
373    }
374}
375
376fn calculate_number_of_mip_maps<T: TextureDataType>(
377    mipmap: Option<Mipmap>,
378    width: u32,
379    height: u32,
380    depth: Option<u32>,
381) -> u32 {
382    if (T::data_type() == crate::context::FLOAT || T::data_type() == crate::context::HALF_FLOAT)
384        && T::size() == 3
385    {
386        return 1;
387    }
388
389    if let Some(Mipmap { max_levels, .. }) = mipmap {
390        let max_size = width.max(height).max(depth.unwrap_or(0));
391        if max_size < 2 {
392            1
393        } else {
394            let power_of_two = max_size.next_power_of_two();
395            ((power_of_two as f64).log2() as u32).min(max_levels.max(1))
396        }
397    } else {
398        1
399    }
400}
401
402fn wrapping_from(wrapping: Wrapping) -> i32 {
403    (match wrapping {
404        Wrapping::Repeat => crate::context::REPEAT,
405        Wrapping::MirroredRepeat => crate::context::MIRRORED_REPEAT,
406        Wrapping::ClampToEdge => crate::context::CLAMP_TO_EDGE,
407    }) as i32
408}
409
410fn interpolation_from(interpolation: Interpolation) -> i32 {
411    (match interpolation {
412        Interpolation::Nearest => crate::context::NEAREST,
413        Interpolation::Linear => crate::context::LINEAR,
414        _ => panic!("Can only sample textures using 'NEAREST' or 'LINEAR' interpolation"),
415    }) as i32
416}
417
418fn check_data_length<T: TextureDataType>(
419    width: u32,
420    height: u32,
421    depth: u32,
422    data_byte_size: usize,
423    data_len: usize,
424) {
425    let expected_bytes = width as usize * height as usize * depth as usize * data_byte_size;
426    let actual_bytes = data_len * std::mem::size_of::<T>();
427    if expected_bytes != actual_bytes {
428        panic!(
429            "invalid size of texture data (expected {} bytes but got {} bytes)",
430            expected_bytes, actual_bytes
431        )
432    }
433}
434
435fn ru8_data(t: &CpuTexture) -> &[u8] {
436    if let TextureData::RU8(data) = &t.data {
437        data
438    } else {
439        panic!("all of the images used for cube map sides must have the same texture data type")
440    }
441}
442
443fn rgu8_data(t: &CpuTexture) -> &[[u8; 2]] {
444    if let TextureData::RgU8(data) = &t.data {
445        data
446    } else {
447        panic!("all of the images used for cube map sides must have the same texture data type")
448    }
449}
450
451fn rgbu8_data(t: &CpuTexture) -> &[[u8; 3]] {
452    if let TextureData::RgbU8(data) = &t.data {
453        data
454    } else {
455        panic!("all of the images used for cube map sides must have the same texture data type")
456    }
457}
458
459fn rgbau8_data(t: &CpuTexture) -> &[[u8; 4]] {
460    if let TextureData::RgbaU8(data) = &t.data {
461        data
462    } else {
463        panic!("all of the images used for cube map sides must have the same texture data type")
464    }
465}
466
467fn rf16_data(t: &CpuTexture) -> &[f16] {
468    if let TextureData::RF16(data) = &t.data {
469        data
470    } else {
471        panic!("all of the images used for cube map sides must have the same texture data type")
472    }
473}
474
475fn rgf16_data(t: &CpuTexture) -> &[[f16; 2]] {
476    if let TextureData::RgF16(data) = &t.data {
477        data
478    } else {
479        panic!("all of the images used for cube map sides must have the same texture data type")
480    }
481}
482
483fn rgbf16_data(t: &CpuTexture) -> &[[f16; 3]] {
484    if let TextureData::RgbF16(data) = &t.data {
485        data
486    } else {
487        panic!("all of the images used for cube map sides must have the same texture data type")
488    }
489}
490
491fn rgbaf16_data(t: &CpuTexture) -> &[[f16; 4]] {
492    if let TextureData::RgbaF16(data) = &t.data {
493        data
494    } else {
495        panic!("all of the images used for cube map sides must have the same texture data type")
496    }
497}
498
499fn rf32_data(t: &CpuTexture) -> &[f32] {
500    if let TextureData::RF32(data) = &t.data {
501        data
502    } else {
503        panic!("all of the images used for cube map sides must have the same texture data type")
504    }
505}
506
507fn rgf32_data(t: &CpuTexture) -> &[[f32; 2]] {
508    if let TextureData::RgF32(data) = &t.data {
509        data
510    } else {
511        panic!("all of the images used for cube map sides must have the same texture data type")
512    }
513}
514
515fn rgbf32_data(t: &CpuTexture) -> &[[f32; 3]] {
516    if let TextureData::RgbF32(data) = &t.data {
517        data
518    } else {
519        panic!("all of the images used for cube map sides must have the same texture data type")
520    }
521}
522
523fn rgbaf32_data(t: &CpuTexture) -> &[[f32; 4]] {
524    if let TextureData::RgbaF32(data) = &t.data {
525        data
526    } else {
527        panic!("all of the images used for cube map sides must have the same texture data type")
528    }
529}