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}