kepler_ra/techtron/webgl/
texture.rs1
2use log::info;
26use once_cell::sync::Lazy;
27use std::borrow::Borrow;
28use std::ops::Deref;
29use std::rc::Rc;
30use std::sync::atomic::{AtomicU32, Ordering};
31use std::sync::Mutex;
32use web_sys::{WebGl2RenderingContext, WebGlTexture};
33
34use super::context::*;
35
36type GL2 = WebGl2RenderingContext;
37
38const MAX_TEXTURE_ID: u32 =
50 WebGl2RenderingContext::MAX_COMBINED_TEXTURE_IMAGE_UNITS - WebGl2RenderingContext::TEXTURE0 - 1;
51
52static TEXTURE_ID: Lazy<Mutex<Vec<u32>>> =
53 Lazy::new(|| Mutex::new((0..MAX_TEXTURE_ID).rev().collect()));
54
55pub fn gen_texture_id() -> Result<u32, String> {
56 TEXTURE_ID
57 .lock()
58 .or(Err(String::from("Cannot lock TEXTURE_ID.")))
59 .and_then(|mut v| v.pop().ok_or(String::from("Texture id exhausted.")))
60}
61
62pub fn release_texture_id(id: u32) -> Result<(), String> {
63 if id < MAX_TEXTURE_ID {
64 TEXTURE_ID
65 .lock()
66 .or(Err(String::from("Cannot lock TEXTURE_ID.")))
67 .and_then(|mut v| Ok(v.push(id)))
68 } else {
69 Err(String::from("Texture id is out of range."))
70 }
71}
72
73pub trait LoadTexture {
74 fn load_texture(&self, context: &GLContext) -> LoadedTexture;
75}
76
77pub struct Texture3DRGBA16 {
78 width: i32,
79 height: i32,
80 depth: i32,
81 data: Rc<Vec<u16>>,
82}
83
84impl Texture3DRGBA16 {
85 pub fn new(width: i32, height: i32, depth: i32, data: Rc<Vec<u16>>) -> Self {
86 Texture3DRGBA16 {
87 width,
88 height,
89 depth,
90 data,
91 }
92 }
93
94}
95
96impl LoadTexture for Texture3DRGBA16 {
97 fn load_texture(&self, context: &GLContext) -> LoadedTexture {
98 let gl = context.clone();
99 let level = 0;
100 let border = 0;
101 let internal_format = GL2::RGBA as i32;
102 let source_format = GL2::RGBA;
103 let source_type = GL2::UNSIGNED_SHORT_4_4_4_4;
104 let id = gen_texture_id().expect("Cannot generate texture id.");
105
106 let handle = gl.create_texture().expect("Failed to crate texture.");
108 gl.bind_texture(GL2::TEXTURE_3D, Some(&handle));
109
110 let data: &[u16] = self.data.as_slice();
112 let array = unsafe { &js_sys::Uint16Array::view(data) };
113
114 gl.tex_image_3d_with_opt_array_buffer_view(
115 GL2::TEXTURE_3D,
116 level,
117 internal_format,
118 self.width,
119 self.height,
120 self.depth,
121 border,
122 source_format,
123 source_type,
124 Some(array),
125 );
126 let error = gl.get_error();
127 if error != 0 {
128 panic!("copying error: {}.", error);
129 } else {
130 info!("finish copying.");
131 }
132
133 set_default_texture_param(&gl);
134 LoadedTexture {
135 context: context.clone(),
136 handle,
137 id,
138 }
139
140 }
141}
142
143#[derive(Debug)]
144pub struct LoadedTexture {
145 pub context: GLContext,
146 pub handle: WebGlTexture,
147 pub id: u32,
148 }
151impl Drop for LoadedTexture {
152 fn drop(&mut self) {
153 release_texture_id(self.id);
155 self.context.delete_texture(Some(&self.handle));
156 }
157}
158
159impl Deref for LoadedTexture {
160 type Target = WebGlTexture;
161 fn deref(&self) -> &Self::Target {
162 &self.handle
163 }
164}
165
166impl LoadedTexture {
167 pub fn activate(&self) {
168 self.context.active_texture(GL2::TEXTURE0 + self.id)
169 }
170}
171
172pub fn set_default_texture_param(gl: &WebGl2RenderingContext) {
173 type GL2 = WebGl2RenderingContext;
174 gl.tex_parameteri(
176 GL2::TEXTURE_3D,
177 GL2::TEXTURE_WRAP_S,
178 GL2::CLAMP_TO_EDGE.try_into().unwrap(),
179 );
180 gl.tex_parameteri(
181 GL2::TEXTURE_3D,
182 GL2::TEXTURE_WRAP_T,
183 GL2::CLAMP_TO_EDGE.try_into().unwrap(),
184 );
185 gl.tex_parameteri(
186 GL2::TEXTURE_3D,
187 GL2::TEXTURE_WRAP_R,
188 GL2::CLAMP_TO_EDGE.try_into().unwrap(),
189 );
190 gl.tex_parameteri(
191 GL2::TEXTURE_3D,
192 GL2::TEXTURE_MIN_FILTER,
193 GL2::LINEAR.try_into().unwrap(),
194 );
196 gl.tex_parameteri(
197 GL2::TEXTURE_3D,
198 GL2::TEXTURE_MAG_FILTER,
199 GL2::LINEAR.try_into().unwrap(),
200 );
202}
203
204
205pub trait GenTexture<T> {
206 fn gen_texture3d(&self) -> T;
207}
208
209pub struct Texture3DRGB8 {
210 width: i32,
211 height: i32,
212 depth: i32,
213 data: Rc<Vec<u8>>,
214}
215
216impl Texture3DRGB8 {
217 pub fn new(width: i32, height: i32, depth: i32, data: Rc<Vec<u8>>) -> Self {
218 Texture3DRGB8 {
219 width,
220 height,
221 depth,
222 data,
223 }
224 }
225
226}
227
228impl LoadTexture for Texture3DRGB8 {
229 fn load_texture(&self, context: &GLContext) -> LoadedTexture {
230 let gl = context.clone();
231 let border = 0;
233 let level = 0;
234
235 let data = self.data.as_slice();
236 let lut_array_view = unsafe { js_sys::Uint8Array::view(&data) };
237 let handle = gl.create_texture().expect("Failed to create LUT texture.");
238 let id = gen_texture_id().expect("Cannot generate texture id.");
239 gl.bind_texture(GL2::TEXTURE_3D, Some(&handle));
240 gl.tex_image_3d_with_opt_array_buffer_view(
241 GL2::TEXTURE_3D,
242 level,
243 GL2::RGB8 as i32,
244 self.width,
245 self.height,
246 self.depth,
247 border,
248 GL2::RGB,
249 GL2::UNSIGNED_BYTE,
250 Some(&lut_array_view),
251 )
252 .expect("Failed to copy LUT data to GPU.");
253 set_default_texture_param(&gl);
254
255 LoadedTexture {
256 context: context.clone(),
257 handle,
258 id,
259 }
260 }
261}