three_d/core/texture/
texture3d.rs

1use crate::core::texture::*;
2///
3/// A 3D color texture.
4///
5pub struct Texture3D {
6    context: Context,
7    id: crate::context::Texture,
8    width: u32,
9    height: u32,
10    depth: u32,
11    number_of_mip_maps: u32,
12    data_byte_size: usize,
13}
14
15impl Texture3D {
16    ///
17    /// Construcs a new 3D texture with the given data.
18    ///
19    /// **Note:** Mip maps will not be generated for RGB16F and RGB32F format, even if `mip_map_filter` is specified.
20    ///
21    pub fn new(context: &Context, cpu_texture: &CpuTexture3D) -> Self {
22        match cpu_texture.data {
23            TextureData::RU8(ref data) => Self::new_with_data(context, cpu_texture, data),
24            TextureData::RgU8(ref data) => Self::new_with_data(context, cpu_texture, data),
25            TextureData::RgbU8(ref data) => Self::new_with_data(context, cpu_texture, data),
26            TextureData::RgbaU8(ref data) => Self::new_with_data(context, cpu_texture, data),
27            TextureData::RF16(ref data) => Self::new_with_data(context, cpu_texture, data),
28            TextureData::RgF16(ref data) => Self::new_with_data(context, cpu_texture, data),
29            TextureData::RgbF16(ref data) => Self::new_with_data(context, cpu_texture, data),
30            TextureData::RgbaF16(ref data) => Self::new_with_data(context, cpu_texture, data),
31            TextureData::RF32(ref data) => Self::new_with_data(context, cpu_texture, data),
32            TextureData::RgF32(ref data) => Self::new_with_data(context, cpu_texture, data),
33            TextureData::RgbF32(ref data) => Self::new_with_data(context, cpu_texture, data),
34            TextureData::RgbaF32(ref data) => Self::new_with_data(context, cpu_texture, data),
35        }
36    }
37
38    fn new_with_data<T: TextureDataType>(
39        context: &Context,
40        cpu_texture: &CpuTexture3D,
41        data: &[T],
42    ) -> Self {
43        let mut texture = Self::new_empty::<T>(
44            context,
45            cpu_texture.width,
46            cpu_texture.height,
47            cpu_texture.depth,
48            cpu_texture.min_filter,
49            cpu_texture.mag_filter,
50            cpu_texture.mipmap,
51            cpu_texture.wrap_s,
52            cpu_texture.wrap_t,
53            cpu_texture.wrap_r,
54        );
55        texture.fill(data);
56        texture
57    }
58
59    ///
60    /// Creates a new empty 3D color texture.
61    ///
62    /// **Note:** Mip maps will not be generated for RGB16F and RGB32F format, even if `mip_map_filter` is specified.
63    ///
64    pub fn new_empty<T: TextureDataType>(
65        context: &Context,
66        width: u32,
67        height: u32,
68        depth: u32,
69        min_filter: Interpolation,
70        mag_filter: Interpolation,
71        mipmap: Option<Mipmap>,
72        wrap_s: Wrapping,
73        wrap_t: Wrapping,
74        wrap_r: Wrapping,
75    ) -> Self {
76        let id = generate(context);
77        let number_of_mip_maps =
78            calculate_number_of_mip_maps::<T>(mipmap, width, height, Some(depth));
79        let texture = Self {
80            context: context.clone(),
81            id,
82            width,
83            height,
84            depth,
85            number_of_mip_maps,
86            data_byte_size: std::mem::size_of::<T>(),
87        };
88        texture.bind();
89        set_parameters(
90            context,
91            crate::context::TEXTURE_3D,
92            min_filter,
93            mag_filter,
94            if number_of_mip_maps == 1 {
95                None
96            } else {
97                mipmap
98            },
99            wrap_s,
100            wrap_t,
101            Some(wrap_r),
102        );
103        unsafe {
104            context.tex_storage_3d(
105                crate::context::TEXTURE_3D,
106                number_of_mip_maps as i32,
107                T::internal_format(),
108                width as i32,
109                height as i32,
110                depth as i32,
111            );
112        }
113        texture.generate_mip_maps();
114        texture
115    }
116
117    ///
118    /// Fills this texture with the given data.
119    ///
120    /// # Panic
121    /// Will panic if the length of the data does not correspond to the width, height, depth and format specified at construction.
122    /// It is therefore necessary to create a new texture if the texture size or format has changed.
123    ///
124    pub fn fill<T: TextureDataType>(&mut self, data: &[T]) {
125        check_data_length::<T>(
126            self.width,
127            self.height,
128            self.depth,
129            self.data_byte_size,
130            data.len(),
131        );
132        self.bind();
133        unsafe {
134            self.context.tex_sub_image_3d(
135                crate::context::TEXTURE_3D,
136                0,
137                0,
138                0,
139                0,
140                self.width as i32,
141                self.height as i32,
142                self.depth as i32,
143                format_from_data_type::<T>(),
144                T::data_type(),
145                crate::context::PixelUnpackData::Slice(to_byte_slice(data)),
146            );
147        }
148        self.generate_mip_maps();
149    }
150
151    /// The width of this texture.
152    pub fn width(&self) -> u32 {
153        self.width
154    }
155
156    /// The height of this texture.
157    pub fn height(&self) -> u32 {
158        self.height
159    }
160
161    /// The depth of this texture.
162    pub fn depth(&self) -> u32 {
163        self.depth
164    }
165
166    /// The number of mip maps of this texture.
167    pub fn number_of_mip_maps(&self) -> u32 {
168        self.number_of_mip_maps
169    }
170
171    fn generate_mip_maps(&self) {
172        if self.number_of_mip_maps > 1 {
173            self.bind();
174            unsafe {
175                self.context.generate_mipmap(crate::context::TEXTURE_3D);
176            }
177        }
178    }
179    pub(in crate::core) fn bind(&self) {
180        unsafe {
181            self.context
182                .bind_texture(crate::context::TEXTURE_3D, Some(self.id));
183        }
184    }
185}
186
187impl Drop for Texture3D {
188    fn drop(&mut self) {
189        unsafe {
190            self.context.delete_texture(self.id);
191        }
192    }
193}