51 gl::GenTextures(1, &mut handle); |
52 gl::GenTextures(1, &mut handle); |
52 } |
53 } |
53 NonZeroU32::new(handle) |
54 NonZeroU32::new(handle) |
54 } |
55 } |
55 |
56 |
56 fn tex_params(filter: u32) { |
57 fn tex_params(filter: TextureFilter) { |
57 unsafe { |
58 unsafe { |
58 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); |
59 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); |
59 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); |
60 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); |
60 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as i32); |
61 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, filter as i32); |
61 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as i32); |
62 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, filter as i32); |
62 } |
63 } |
63 } |
64 } |
64 |
65 |
|
66 #[derive(Clone, Copy, Debug)] |
|
67 pub enum TextureFormat { |
|
68 Rgba = gl::RGBA as isize, |
|
69 } |
|
70 |
|
71 #[derive(Clone, Copy, Debug)] |
|
72 pub enum TextureInternalFormat { |
|
73 Rgba8 = gl::RGBA as isize, |
|
74 } |
|
75 |
|
76 #[derive(Clone, Copy, Debug)] |
|
77 pub enum TextureDataType { |
|
78 UnsignedByte = gl::UNSIGNED_BYTE as isize, |
|
79 } |
|
80 |
|
81 #[derive(Clone, Copy, Debug)] |
|
82 pub enum TextureFilter { |
|
83 Nearest = gl::NEAREST as isize, |
|
84 Linear = gl::LINEAR as isize, |
|
85 } |
|
86 |
|
87 #[inline] |
|
88 fn get_u32(value: Option<NonZeroU32>) -> u32 { |
|
89 value.map_or(0, |v| v.get()) |
|
90 } |
|
91 |
|
92 fn is_out_of_bounds(data: &[u8], data_stride: Option<NonZeroU32>, texture_size: Size) -> bool { |
|
93 let data_stride = get_u32(data_stride); |
|
94 data_stride == 0 && texture_size.area() * 4 > data.len() |
|
95 || data_stride != 0 |
|
96 && texture_size.width > data_stride as usize |
|
97 && (texture_size.height * data_stride as usize) * 4 > data.len() |
|
98 } |
|
99 |
65 impl Texture2D { |
100 impl Texture2D { |
66 pub fn new(size: Size, internal_format: u32, filter: u32) -> Self { |
101 pub fn new(size: Size, internal_format: TextureInternalFormat, filter: TextureFilter) -> Self { |
67 if let Some(handle) = new_texture() { |
102 if let Some(handle) = new_texture() { |
68 unsafe { |
103 unsafe { |
69 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
104 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
70 gl::TexImage2D( |
105 gl::TexImage2D( |
71 gl::TEXTURE_2D, |
106 gl::TEXTURE_2D, |
72 0, |
107 0, |
73 internal_format as i32, |
108 internal_format as i32, |
74 size.width as i32, |
109 size.width as i32, |
75 size.height as i32, |
110 size.height as i32, |
76 0, |
111 0, |
77 gl::RGBA, |
112 TextureFormat::Rgba as u32, |
78 gl::UNSIGNED_BYTE, |
113 TextureDataType::UnsignedByte as u32, |
79 std::ptr::null(), |
114 std::ptr::null(), |
80 ) |
115 ) |
81 } |
116 } |
82 |
117 |
83 tex_params(filter); |
118 tex_params(filter); |
84 Self { |
119 Self { |
85 handle: Some(handle), |
120 handle: Some(handle), |
|
121 size, |
86 } |
122 } |
87 } else { |
123 } else { |
88 Self { handle: None } |
124 Self { handle: None, size } |
89 } |
125 } |
90 } |
126 } |
91 |
127 |
92 pub fn with_data( |
128 pub fn with_data( |
93 data: &[u8], |
129 data: &[u8], |
94 data_stride: u32, |
130 data_stride: Option<NonZeroU32>, |
95 size: Size, |
131 size: Size, |
96 internal_format: u32, |
132 internal_format: TextureInternalFormat, |
97 format: u32, |
133 format: TextureFormat, |
98 ty: u32, |
134 ty: TextureDataType, |
99 filter: u32, |
135 filter: TextureFilter, |
100 ) -> Self { |
136 ) -> Self { |
|
137 if is_out_of_bounds(data, data_stride, size) { |
|
138 return Self { handle: None, size }; |
|
139 } |
|
140 |
101 if let Some(handle) = new_texture() { |
141 if let Some(handle) = new_texture() { |
102 unsafe { |
142 unsafe { |
103 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
143 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
104 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32); |
144 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, get_u32(data_stride) as i32); |
105 gl::TexImage2D( |
145 gl::TexImage2D( |
106 gl::TEXTURE_2D, |
146 gl::TEXTURE_2D, |
107 0, |
147 0, |
108 internal_format as i32, |
148 internal_format as i32, |
109 size.width as i32, |
149 size.width as i32, |
110 size.height as i32, |
150 size.height as i32, |
111 0, |
151 0, |
112 format as u32, |
152 format as u32, |
113 ty, |
153 ty as u32, |
114 data.as_ptr() as *const _, |
154 data.as_ptr() as *const _, |
115 ) |
155 ) |
116 } |
156 } |
117 |
157 |
118 tex_params(filter); |
158 tex_params(filter); |
119 Self { |
159 Self { |
120 handle: Some(handle), |
160 handle: Some(handle), |
|
161 size, |
121 } |
162 } |
122 } else { |
163 } else { |
123 Self { handle: None } |
164 Self { handle: None, size } |
124 } |
165 } |
125 } |
166 } |
126 |
167 |
127 pub fn update(&self, region: Rect, data: &[u8], data_stride: u32, format: u32, ty: u32) { |
168 pub fn update( |
|
169 &self, |
|
170 region: Rect, |
|
171 data: &[u8], |
|
172 data_stride: Option<NonZeroU32>, |
|
173 format: TextureFormat, |
|
174 ty: TextureDataType, |
|
175 ) { |
|
176 if is_out_of_bounds(data, data_stride, self.size) { |
|
177 return; |
|
178 } |
|
179 |
128 if let Some(handle) = self.handle { |
180 if let Some(handle) = self.handle { |
129 unsafe { |
181 unsafe { |
130 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
182 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
131 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, data_stride as i32); |
183 gl::PixelStorei(gl::UNPACK_ROW_LENGTH, get_u32(data_stride) as i32); |
132 gl::TexSubImage2D( |
184 gl::TexSubImage2D( |
133 gl::TEXTURE_2D, |
185 gl::TEXTURE_2D, |
134 0, // texture level |
186 0, |
135 region.left(), // texture region |
187 region.left(), |
136 region.top(), |
188 region.top(), |
137 region.width() as i32, |
189 region.width() as i32, |
138 region.height() as i32, |
190 region.height() as i32, |
139 format, // data format |
191 format as u32, |
140 ty, // data type |
192 ty as u32, |
141 data.as_ptr() as *const _, // data ptr |
193 data.as_ptr() as *const _, |
142 ); |
194 ); |
143 } |
195 } |
144 } |
196 } |
145 } |
197 } |
146 |
198 |
147 pub fn retrieve(&self, data: &mut [u8]) { |
199 pub fn retrieve(&self, data: &mut [u8]) { |
|
200 if self.size.area() * 4 > data.len() { |
|
201 return; |
|
202 } |
|
203 |
148 if let Some(handle) = self.handle { |
204 if let Some(handle) = self.handle { |
149 unsafe { |
205 unsafe { |
150 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
206 gl::BindTexture(gl::TEXTURE_2D, handle.get()); |
151 gl::GetTexImage( |
207 gl::GetTexImage( |
152 gl::TEXTURE_2D, |
208 gl::TEXTURE_2D, |
153 0, // texture level |
209 0, |
154 gl::RGBA, // data format |
210 TextureFormat::Rgba as u32, |
155 gl::UNSIGNED_BYTE, // data type |
211 TextureDataType::UnsignedByte as u32, |
156 data.as_mut_ptr() as *mut _, // data ptr |
212 data.as_mut_ptr() as *mut _, |
157 ); |
213 ); |
158 } |
214 } |
159 } |
215 } |
160 } |
216 } |
161 } |
217 } |