1use crate::core::texture::*;
2
3pub struct Texture2D {
7 context: Context,
8 id: crate::context::Texture,
9 width: u32,
10 height: u32,
11 number_of_mip_maps: u32,
12 data_byte_size: usize,
13}
14
15impl Texture2D {
16 pub fn new(context: &Context, cpu_texture: &CpuTexture) -> 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: &CpuTexture,
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.min_filter,
48 cpu_texture.mag_filter,
49 cpu_texture.mipmap,
50 cpu_texture.wrap_s,
51 cpu_texture.wrap_t,
52 );
53 texture.fill(data);
54 texture
55 }
56
57 pub fn new_empty<T: TextureDataType>(
65 context: &Context,
66 width: u32,
67 height: u32,
68 min_filter: Interpolation,
69 mag_filter: Interpolation,
70 mipmap: Option<Mipmap>,
71 wrap_s: Wrapping,
72 wrap_t: Wrapping,
73 ) -> Self {
74 let id = generate(context);
75 let number_of_mip_maps = calculate_number_of_mip_maps::<T>(mipmap, width, height, None);
76 let texture = Self {
77 context: context.clone(),
78 id,
79 width,
80 height,
81 number_of_mip_maps,
82 data_byte_size: std::mem::size_of::<T>(),
83 };
84 texture.bind();
85 set_parameters(
86 context,
87 crate::context::TEXTURE_2D,
88 min_filter,
89 mag_filter,
90 if number_of_mip_maps == 1 {
91 None
92 } else {
93 mipmap
94 },
95 wrap_s,
96 wrap_t,
97 None,
98 );
99 unsafe {
100 context.tex_storage_2d(
101 crate::context::TEXTURE_2D,
102 number_of_mip_maps as i32,
103 T::internal_format(),
104 width as i32,
105 height as i32,
106 );
107 }
108 texture.generate_mip_maps();
109 texture
110 }
111
112 pub fn fill<T: TextureDataType>(&mut self, data: &[T]) {
120 check_data_length::<T>(self.width, self.height, 1, self.data_byte_size, data.len());
121 self.bind();
122 let mut data = data.to_owned();
123 flip_y(&mut data, self.width as usize, self.height as usize);
124 unsafe {
125 self.context.tex_sub_image_2d(
126 crate::context::TEXTURE_2D,
127 0,
128 0,
129 0,
130 self.width as i32,
131 self.height as i32,
132 format_from_data_type::<T>(),
133 T::data_type(),
134 crate::context::PixelUnpackData::Slice(to_byte_slice(&data)),
135 );
136 }
137 self.generate_mip_maps();
138 }
139
140 pub fn as_color_target(&mut self, mip_level: Option<u32>) -> ColorTarget<'_> {
149 ColorTarget::new_texture2d(&self.context, self, mip_level)
150 }
151
152 pub fn width(&self) -> u32 {
154 self.width
155 }
156
157 pub fn height(&self) -> u32 {
159 self.height
160 }
161
162 pub fn number_of_mip_maps(&self) -> u32 {
164 self.number_of_mip_maps
165 }
166
167 pub(crate) fn generate_mip_maps(&self) {
168 if self.number_of_mip_maps > 1 {
169 self.bind();
170 unsafe {
171 self.context.generate_mipmap(crate::context::TEXTURE_2D);
172 }
173 }
174 }
175
176 pub(in crate::core) fn bind_as_color_target(&self, channel: u32, mip_level: u32) {
177 unsafe {
178 self.context.framebuffer_texture_2d(
179 crate::context::FRAMEBUFFER,
180 crate::context::COLOR_ATTACHMENT0 + channel,
181 crate::context::TEXTURE_2D,
182 Some(self.id),
183 mip_level as i32,
184 );
185 }
186 }
187 pub(in crate::core) fn bind(&self) {
188 unsafe {
189 self.context
190 .bind_texture(crate::context::TEXTURE_2D, Some(self.id));
191 }
192 }
193}
194
195impl Drop for Texture2D {
196 fn drop(&mut self) {
197 unsafe {
198 self.context.delete_texture(self.id);
199 }
200 }
201}