1use crate::core::texture::*;
2pub 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 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 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 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 unsafe {
77 Self::new_unchecked::<T>(
78 context,
79 width,
80 height,
81 depth,
82 min_filter,
83 mag_filter,
84 mipmap,
85 wrap_s,
86 wrap_t,
87 wrap_r,
88 |texture| {
89 context.tex_storage_3d(
90 crate::context::TEXTURE_3D,
91 texture.number_of_mip_maps() as i32,
92 T::internal_format(),
93 width as i32,
94 height as i32,
95 depth as i32,
96 )
97 },
98 )
99 }
100 }
101
102 pub fn fill<T: TextureDataType>(&self, data: &[T]) {
110 check_data_length::<T>(
111 self.width,
112 self.height,
113 self.depth,
114 self.data_byte_size,
115 data.len(),
116 );
117 self.bind();
118 unsafe {
119 self.context.tex_sub_image_3d(
120 crate::context::TEXTURE_3D,
121 0,
122 0,
123 0,
124 0,
125 self.width as i32,
126 self.height as i32,
127 self.depth as i32,
128 format_from_data_type::<T>(),
129 T::data_type(),
130 crate::context::PixelUnpackData::Slice(Some(to_byte_slice(data))),
131 );
132 }
133 self.generate_mip_maps();
134 }
135
136 pub fn width(&self) -> u32 {
138 self.width
139 }
140
141 pub fn height(&self) -> u32 {
143 self.height
144 }
145
146 pub fn depth(&self) -> u32 {
148 self.depth
149 }
150
151 pub fn number_of_mip_maps(&self) -> u32 {
153 self.number_of_mip_maps
154 }
155
156 fn generate_mip_maps(&self) {
157 if self.number_of_mip_maps > 1 {
158 self.bind();
159 unsafe {
160 self.context.generate_mipmap(crate::context::TEXTURE_3D);
161 }
162 }
163 }
164 pub(in crate::core) fn bind(&self) {
165 unsafe {
166 self.context
167 .bind_texture(crate::context::TEXTURE_3D, Some(self.id));
168 }
169 }
170
171 pub unsafe fn new_unchecked<T: TextureDataType>(
182 context: &Context,
183 width: u32,
184 height: u32,
185 depth: u32,
186 min_filter: Interpolation,
187 mag_filter: Interpolation,
188 mipmap: Option<Mipmap>,
189 wrap_s: Wrapping,
190 wrap_t: Wrapping,
191 wrap_r: Wrapping,
192 callback: impl FnOnce(&Self),
193 ) -> Self {
194 let id = generate(context);
195 let number_of_mip_maps =
196 calculate_number_of_mip_maps::<T>(mipmap, width, height, Some(depth));
197 let texture = Self {
198 context: context.clone(),
199 id,
200 width,
201 height,
202 depth,
203 number_of_mip_maps,
204 data_byte_size: std::mem::size_of::<T>(),
205 };
206 texture.bind();
207 set_parameters(
208 context,
209 crate::context::TEXTURE_3D,
210 min_filter,
211 mag_filter,
212 if number_of_mip_maps == 1 {
213 None
214 } else {
215 mipmap
216 },
217 wrap_s,
218 wrap_t,
219 Some(wrap_r),
220 );
221 callback(&texture);
222 texture.generate_mip_maps();
223 texture
224 }
225}
226
227impl Drop for Texture3D {
228 fn drop(&mut self) {
229 unsafe {
230 self.context.delete_texture(self.id);
231 }
232 }
233}