diff --git a/examples/al-gw.html b/examples/al-gw.html index c09ab433..3b209720 100644 --- a/examples/al-gw.html +++ b/examples/al-gw.html @@ -14,7 +14,7 @@ A.init.then(() => { aladin = A.aladin('#aladin-lite-div', {showReticle: true, showSurveyStackControl: true, showOverlayStackControl: false, projection: "TAN", target: '15 16 57.636 -60 55 7.49', showProjectionControl: true, realFullscreen: true, showZoomControl: true, showSimbadPointerControl: true, showShareControl: true, showContextMenu: true, showCooGridControl: true, fullScreen: true, showCooGrid: true, fov: 90}); - var moc_0_99 = A.MOCFromURL("./data//gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.0, lineWidth: 3, fill: false, perimeter: true}); + var moc_0_99 = A.MOCFromURL("./data//gw/gw_0.9.fits",{ name: "GW 90%", color: "#ff0000", opacity: 0.0, lineWidth: 10, fill: false, perimeter: true}); var moc_0_95 = A.MOCFromURL("./data/gw/gw_0.6.fits",{ name: "GW 60%", color: "#00ff00", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true}); var moc_0_5 = A.MOCFromURL("./data/gw/gw_0.3.fits",{ name: "GW 30%", color: "#00ffff", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true}); var moc_0_2 = A.MOCFromURL("./data/gw/gw_0.1.fits",{ name: "GW 10%", color: "#ff00ff", opacity: 0.5, lineWidth: 3, fill: true, perimeter: true}); diff --git a/examples/al-init-custom-options.html b/examples/al-init-custom-options.html index 1b02b5d9..1dc96761 100644 --- a/examples/al-init-custom-options.html +++ b/examples/al-init-custom-options.html @@ -23,6 +23,7 @@ reticleColor: '#ff89ff', // change reticle color reticleSize: 64, // change reticle size showContextMenu: true, + showCooGrid: true, } ); }); diff --git a/src/core/al-core/src/object/array_buffer_instanced.rs b/src/core/al-core/src/object/array_buffer_instanced.rs index a6e5a0f0..f4f0d218 100644 --- a/src/core/al-core/src/object/array_buffer_instanced.rs +++ b/src/core/al-core/src/object/array_buffer_instanced.rs @@ -6,6 +6,7 @@ use crate::webgl_ctx::WebGlContext; pub struct ArrayBufferInstanced { buffer: WebGlBuffer, + len: usize, num_packed_data: usize, offset_idx: u32, @@ -39,7 +40,7 @@ impl ArrayBufferInstanced { offset_idx: u32, stride: usize, sizes: &[usize], - _offsets: &[usize], + offsets: &[usize], usage: u32, data: B, ) -> ArrayBufferInstanced { @@ -49,29 +50,43 @@ impl ArrayBufferInstanced { let num_f32_in_buf = data.len() as i32; let num_instances = num_f32_in_buf / (num_f32_per_instance as i32); + let len = data.len(); - let buffer = gl.create_buffer().ok_or("failed to create buffer").unwrap_abort(); + let buffer = gl + .create_buffer() + .ok_or("failed to create buffer") + .unwrap_abort(); // Bind the buffer gl.bind_buffer(WebGlRenderingCtx::ARRAY_BUFFER, Some(buffer.as_ref())); // Pass the vertices data to the buffer f32::buffer_data_with_array_buffer_view(gl, data, WebGlRenderingCtx::ARRAY_BUFFER, usage); // Link to the shader - let idx = offset_idx; + for (idx, (size, offset)) in sizes.iter().zip(offsets.iter()).enumerate() { + let idx = (idx as u32) + offset_idx; - f32::vertex_attrib_pointer_with_i32(gl, idx, *sizes.first().unwrap_abort() as i32, 0, 0); - gl.enable_vertex_attrib_array(idx); + f32::vertex_attrib_pointer_with_i32( + gl, + idx, + *size as i32, + stride as i32, + *offset as i32, + ); - #[cfg(feature = "webgl2")] - gl.vertex_attrib_divisor(idx, 1); - #[cfg(feature = "webgl1")] - gl.ext.angles.vertex_attrib_divisor_angle(idx, 1); + gl.enable_vertex_attrib_array(idx); + + #[cfg(feature = "webgl2")] + gl.vertex_attrib_divisor(idx, 1); + #[cfg(feature = "webgl1")] + gl.ext.angles.vertex_attrib_divisor_angle(idx, 1); + } let num_packed_data = sizes.len(); let gl = gl.clone(); // Returns an instance that keeps only the buffer ArrayBufferInstanced { buffer, + len, num_packed_data, offset_idx, @@ -119,13 +134,30 @@ impl ArrayBufferInstanced { self.gl.disable_vertex_attrib_array(loc as u32); } - pub fn update<'a, B: BufferDataStorage<'a, f32>>(&self, buffer: B) { + pub fn update<'a, B: BufferDataStorage<'a, f32>>(&mut self, usage: u32, data: B) { self.bind(); - f32::buffer_sub_data_with_i32_and_array_buffer_view( + if self.len >= data.len() { + f32::buffer_sub_data_with_i32_and_array_buffer_view( + &self.gl, + data, + WebGlRenderingCtx::ARRAY_BUFFER, + ); + } else { + self.len = data.len(); + + f32::buffer_data_with_array_buffer_view( + &self.gl, + data, + WebGlRenderingCtx::ARRAY_BUFFER, + usage, + ); + } + + /*f32::buffer_sub_data_with_i32_and_array_buffer_view( &self.gl, buffer, WebGlRenderingCtx::ARRAY_BUFFER, - ); + );*/ /*self.gl.buffer_sub_data_with_i32_and_array_buffer_view( WebGlRenderingCtx::ARRAY_BUFFER, 0, diff --git a/src/core/al-core/src/object/vertex_array_object.rs b/src/core/al-core/src/object/vertex_array_object.rs index e34f8595..87b91ba2 100644 --- a/src/core/al-core/src/object/vertex_array_object.rs +++ b/src/core/al-core/src/object/vertex_array_object.rs @@ -9,8 +9,8 @@ pub mod vao { use crate::object::element_array_buffer::ElementArrayBuffer; use crate::webgl_ctx::WebGlContext; - use std::collections::HashMap; use crate::Abort; + use std::collections::HashMap; pub struct VertexArrayObject { array_buffer: HashMap<&'static str, ArrayBuffer>, @@ -88,7 +88,10 @@ pub mod vao { }*/ pub fn num_elements(&self) -> usize { - self.element_array_buffer.as_ref().unwrap_abort().num_elements() + self.element_array_buffer + .as_ref() + .unwrap_abort() + .num_elements() } pub fn num_instances(&self) -> i32 { @@ -143,13 +146,14 @@ pub mod vao { pub fn update_instanced_array>( &mut self, attr: &'static str, + usage: u32, array_data: B, ) -> &mut Self { self.vao .array_buffer_instanced .get_mut(attr) .unwrap_abort() - .update(array_data); + .update(usage, array_data); self } @@ -333,13 +337,14 @@ pub mod vao { pub fn update_instanced_array>( &mut self, attr: &'static str, + usage: u32, array_data: B, ) -> &mut Self { self.vao .array_buffer_instanced .get_mut(attr) .unwrap_abort() - .update(array_data); + .update(usage, array_data); self } @@ -444,7 +449,10 @@ pub mod vao { }*/ pub fn num_elements(&self) -> usize { - self.element_array_buffer.as_ref().unwrap_abort().num_elements() + self.element_array_buffer + .as_ref() + .unwrap_abort() + .num_elements() } pub fn num_instances(&self) -> i32 { @@ -694,13 +702,14 @@ pub mod vao { pub fn update_instanced_array>( &mut self, attr: &'static str, + usage: u32, array_data: B, ) -> &mut Self { self.vao .array_buffer_instanced .get_mut(attr) .expect("cannot get attribute from the array buffer") - .update(array_data); + .update(usage, array_data); self } diff --git a/src/core/src/renderable/catalog/manager.rs b/src/core/src/renderable/catalog/manager.rs index 409f2cc2..e21b54e3 100644 --- a/src/core/src/renderable/catalog/manager.rs +++ b/src/core/src/renderable/catalog/manager.rs @@ -26,6 +26,7 @@ impl From for JsValue { } } +// Num of shapes const _NUM_SHAPES: usize = 5; pub struct Manager { gl: WebGlContext, @@ -457,7 +458,11 @@ impl Catalog { #[cfg(feature = "webgl2")] self.vertex_array_object_catalog .bind_for_update() - .update_instanced_array("center", VecData(&sources)); + .update_instanced_array( + "center", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&sources), + ); } fn draw( diff --git a/src/core/src/renderable/line/mod.rs b/src/core/src/renderable/line/mod.rs index 751366b6..53fc8d7d 100644 --- a/src/core/src/renderable/line/mod.rs +++ b/src/core/src/renderable/line/mod.rs @@ -11,14 +11,11 @@ use super::Renderer; use al_api::color::ColorRGBA; use al_core::SliceData; -use lyon::algorithms::{ - math::point, - measure::{PathMeasurements, SampleType}, - path::Path, -}; +use lyon::algorithms::{math::point, path::Path}; struct Meta { color: ColorRGBA, + thickness: f32, off_indices: usize, num_indices: usize, } @@ -35,9 +32,16 @@ pub struct RasterizedLineRenderer { shader: Shader, vao: VertexArrayObject, + shader_line_instanced: Shader, + + vao_idx: usize, + vertices: Vec, indices: Vec, meta: Vec, + + instanced_line_vaos: Vec, + meta_instanced: Vec, } use wasm_bindgen::JsValue; @@ -68,6 +72,38 @@ impl RasterizedLineRenderer { include_str!("../../../../glsl/webgl2/line/line_vertex.glsl"), include_str!("../../../../glsl/webgl2/line/line_frag.glsl"), )?; + let shader_line_instanced = Shader::new( + &gl, + r#"#version 300 es + precision lowp float; + layout (location = 0) in vec2 p_a; + layout (location = 1) in vec2 p_b; + layout (location = 2) in vec2 vertex; + + out vec2 out_uv; + out vec3 out_p; + + uniform float u_width; + + void main() { + vec2 x_b = p_b - p_a; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); + + vec2 p = p_a + x_b * vertex.x + y_b * u_width * 0.001 * vertex.y; + gl_Position = vec4(p, 0.f, 1.f); + }"#, + r#"#version 300 es + precision lowp float; + out vec4 color; + + uniform vec4 u_color; + + void main() { + // Multiply vertex color with texture color (in linear space). + // Linear color is written and blended in Framebuffer and converted to sRGB later + color = u_color; + }"#, + )?; let mut vao = VertexArrayObject::new(&gl); vao.bind_for_update() @@ -87,10 +123,17 @@ impl RasterizedLineRenderer { .unbind(); let meta = vec![]; + let meta_instanced = vec![]; let gl = gl.clone(); + + let instanced_line_vaos = vec![]; Ok(Self { gl, shader, + shader_line_instanced, + vao_idx: 0, + instanced_line_vaos, + meta_instanced, vao, meta, vertices, @@ -167,22 +210,57 @@ impl RasterizedLineRenderer { self.meta.push(Meta { off_indices, num_indices, + thickness: 1.0, color: color.clone(), }); } + fn create_instanced_vao(&mut self) { + let mut vao = VertexArrayObject::new(&self.gl); + + vao.bind_for_update() + // Store the cartesian position of the center of the source in the a instanced VBO + .add_instanced_array_buffer( + "ndc_pos", + 4 * std::mem::size_of::(), + &[2, 2], + &[0, 2 * std::mem::size_of::()], + WebGl2RenderingContext::DYNAMIC_DRAW, + SliceData(&[]), + ) + .add_array_buffer( + "vertices", + 2 * std::mem::size_of::(), + &[2], + &[0], + WebGl2RenderingContext::STATIC_DRAW, + SliceData(&[ + 0_f32, -0.5_f32, 1_f32, -0.5_f32, 1_f32, 0.5_f32, 0_f32, 0.5_f32, + ]), + ) + // Set the element buffer + .add_element_buffer( + WebGl2RenderingContext::STATIC_DRAW, + SliceData(&[0_u16, 1_u16, 2_u16, 0_u16, 2_u16, 3_u16]), + ) + // Unbind the buffer + .unbind(); + + self.instanced_line_vaos.push(vao); + } + pub fn add_stroke_paths( &mut self, paths: impl Iterator>, thickness: f32, color: &ColorRGBA, - style: &Style, + _style: &Style, ) where T: AsRef<[[f32; 2]]>, { - let num_vertices = (self.vertices.len() / 2) as u32; + //let num_vertices = (self.vertices.len() / 2) as u32; - let mut path_builder = Path::builder(); + /*let mut path_builder = Path::builder(); match &style { Style::None => { @@ -268,17 +346,40 @@ impl RasterizedLineRenderer { .unwrap_abort(); } - let VertexBuffers { vertices, indices } = geometry; + let VertexBuffers { vertices, indices } = geometry;*/ + if self.vao_idx == self.instanced_line_vaos.len() { + // create a vao + self.create_instanced_vao(); + } - let num_indices = indices.len(); - let off_indices = self.indices.len(); + let vao = &mut self.instanced_line_vaos[self.vao_idx]; + self.vao_idx += 1; - self.vertices.extend(vertices.iter().flatten()); - self.indices.extend(indices.iter()); + let mut buf: Vec = vec![]; - self.meta.push(Meta { - off_indices, - num_indices, + for PathVertices { vertices } in paths { + let vertices = vertices.as_ref(); + let path_vertices_buf_iter = vertices + .iter() + .zip(vertices.iter().skip(1)) + .map(|(a, b)| [a[0], a[1], b[0], b[1]]) + .flatten(); + + buf.extend(path_vertices_buf_iter); + } + + vao.bind_for_update().update_instanced_array( + "ndc_pos", + WebGl2RenderingContext::DYNAMIC_DRAW, + VecData(&buf), + ); + + let num_instances = buf.len() / 4; + + self.meta_instanced.push(Meta { + off_indices: 0, + thickness, + num_indices: num_instances, color: color.clone(), }); } @@ -308,6 +409,21 @@ impl RasterizedLineRenderer { } //self.gl.enable(WebGl2RenderingContext::CULL_FACE); + + // draw the lines + let shader_bound = self.shader_line_instanced.bind(&self.gl); + for (idx, meta) in self.meta_instanced.iter().enumerate() { + let vao_bound = shader_bound + .attach_uniform("u_color", &meta.color) + .attach_uniform("u_width", &meta.thickness) + .bind_vertex_array_object_ref(&self.instanced_line_vaos[idx]); + + vao_bound.draw_elements_instanced_with_i32( + WebGl2RenderingContext::TRIANGLES, + 0, + meta.num_indices as i32, + ); + } self.gl.disable(WebGl2RenderingContext::BLEND); Ok(()) @@ -318,8 +434,10 @@ impl Renderer for RasterizedLineRenderer { fn begin(&mut self) { self.vertices.clear(); self.indices.clear(); - self.meta.clear(); + + self.meta_instanced.clear(); + self.vao_idx = 0; } fn end(&mut self) { diff --git a/src/js/DefaultActionsForContextMenu.js b/src/js/DefaultActionsForContextMenu.js index 9915725a..3151d21b 100644 --- a/src/js/DefaultActionsForContextMenu.js +++ b/src/js/DefaultActionsForContextMenu.js @@ -164,7 +164,7 @@ export let DefaultActionsForContextMenu = (function () { files.forEach(file => { const url = URL.createObjectURL(file); - let moc = A.MOCFromURL(url, { name: file.name, fill: true, opacity: 0.4 }); + let moc = A.MOCFromURL(url, { name: file.name, edge: true }); a.addMOC(moc); }); }; diff --git a/src/js/MOC.js b/src/js/MOC.js index 4b04829d..46f9e8ae 100644 --- a/src/js/MOC.js +++ b/src/js/MOC.js @@ -36,7 +36,7 @@ export let MOC = (function() { * * @class * @constructs MOC - * @param {MOCOptions} options - Configuration options for the MOC. + * @param {MOCOptions} options - Configuration options for the MOC */ let MOC = function(options) { //this.order = undefined;