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 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 unsafe {
75 Self::new_unchecked::<T>(
76 context,
77 width,
78 height,
79 min_filter,
80 mag_filter,
81 mipmap,
82 wrap_s,
83 wrap_t,
84 |texture| {
85 context.tex_storage_2d(
86 crate::context::TEXTURE_2D,
87 texture.number_of_mip_maps() as i32,
88 T::internal_format(),
89 width as i32,
90 height as i32,
91 );
92 },
93 )
94 }
95 }
96
97 pub fn fill<T: TextureDataType>(&self, data: &[T]) {
105 check_data_length::<T>(self.width, self.height, 1, self.data_byte_size, data.len());
106 self.bind();
107 let mut data = data.to_owned();
108 flip_y(&mut data, self.width as usize, self.height as usize);
109 unsafe {
110 self.context.tex_sub_image_2d(
111 crate::context::TEXTURE_2D,
112 0,
113 0,
114 0,
115 self.width as i32,
116 self.height as i32,
117 format_from_data_type::<T>(),
118 T::data_type(),
119 crate::context::PixelUnpackData::Slice(Some(to_byte_slice(&data))),
120 );
121 }
122 self.generate_mip_maps();
123 }
124
125 pub fn as_color_target(&self, mip_level: Option<u32>) -> ColorTarget<'_> {
134 ColorTarget::new_texture2d(&self.context, self, mip_level)
135 }
136
137 pub fn width(&self) -> u32 {
139 self.width
140 }
141
142 pub fn height(&self) -> u32 {
144 self.height
145 }
146
147 pub fn number_of_mip_maps(&self) -> u32 {
149 self.number_of_mip_maps
150 }
151
152 pub(crate) fn generate_mip_maps(&self) {
153 if self.number_of_mip_maps > 1 {
154 self.bind();
155 unsafe {
156 self.context.generate_mipmap(crate::context::TEXTURE_2D);
157 }
158 }
159 }
160
161 pub(in crate::core) fn bind_as_color_target(&self, channel: u32, mip_level: u32) {
162 unsafe {
163 self.context.framebuffer_texture_2d(
164 crate::context::FRAMEBUFFER,
165 crate::context::COLOR_ATTACHMENT0 + channel,
166 crate::context::TEXTURE_2D,
167 Some(self.id),
168 mip_level as i32,
169 );
170 }
171 }
172 pub(in crate::core) fn bind(&self) {
173 unsafe {
174 self.context
175 .bind_texture(crate::context::TEXTURE_2D, Some(self.id));
176 }
177 }
178
179 pub unsafe fn new_unchecked<T: TextureDataType>(
190 context: &Context,
191 width: u32,
192 height: u32,
193 min_filter: Interpolation,
194 mag_filter: Interpolation,
195 mipmap: Option<Mipmap>,
196 wrap_s: Wrapping,
197 wrap_t: Wrapping,
198 callback: impl FnOnce(&Self),
199 ) -> Self {
200 let id = generate(context);
201 let number_of_mip_maps = calculate_number_of_mip_maps::<T>(mipmap, width, height, None);
202 let texture = Self {
203 context: context.clone(),
204 id,
205 width,
206 height,
207 number_of_mip_maps,
208 data_byte_size: std::mem::size_of::<T>(),
209 };
210 texture.bind();
211 set_parameters(
212 context,
213 crate::context::TEXTURE_2D,
214 min_filter,
215 mag_filter,
216 if number_of_mip_maps == 1 {
217 None
218 } else {
219 mipmap
220 },
221 wrap_s,
222 wrap_t,
223 None,
224 );
225 callback(&texture);
226 texture.generate_mip_maps();
227 texture
228 }
229}
230
231impl Drop for Texture2D {
232 fn drop(&mut self) {
233 unsafe {
234 self.context.delete_texture(self.id);
235 }
236 }
237}