diff --git a/Cargo.lock b/Cargo.lock index c65155a..a1d20a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1470,9 +1470,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.31.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" dependencies = [ "memchr", ] @@ -1670,9 +1670,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" dependencies = [ "ab_glyph", "log", @@ -2051,9 +2051,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07" +checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" dependencies = [ "cc", "downcast-rs", @@ -2065,9 +2065,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.3" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133" +checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" dependencies = [ "bitflags 2.5.0", "rustix", @@ -2137,9 +2137,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.2" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565" +checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" dependencies = [ "proc-macro2", "quick-xml", @@ -2148,9 +2148,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.2" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" +checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" dependencies = [ "dlib", "log", diff --git a/Cargo.toml b/Cargo.toml index 4a59cbf..e92762b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ glutin = "0.31.3" glutin-winit = "0.4.2" copypasta = "0.10.1" raw-window-handle = "0.5.2" -winit = "0.29.15" +winit = "0.29.3" cgmath = "0.18.0" nalgebra-glm = "0.18.0" regex = "1.10.5" diff --git a/shaders/agg-fast-path.frag b/shaders/agg-fast-path.frag index ebfa685..bc925be 100644 --- a/shaders/agg-fast-path.frag +++ b/shaders/agg-fast-path.frag @@ -21,4 +21,5 @@ void main() if (v_color.a == 0) { discard; } FragColor = stroke(v_distance, v_linewidth, v_antialias, v_color); + // FragColor = v_color; } \ No newline at end of file diff --git a/shaders/agg-fast-path.vert b/shaders/agg-fast-path.vert index 9326a31..bd96493 100644 --- a/shaders/agg-fast-path.vert +++ b/shaders/agg-fast-path.vert @@ -33,47 +33,67 @@ void main () // This function is externally generated // fetch_uniforms(); - float id = gl_VertexID; v_linewidth = linewidth; v_antialias = antialias; v_color = color; // transform prev/curr/next - vec4 prev_ = ; - vec4 curr_ = ; - vec4 next_ = ; + // vec4 prev_ = ; + // vec4 curr_ = ; + // vec4 next_ = ; // prev/curr/next in viewport coordinates - vec2 _prev = NDC_to_viewport(prev_, .zw); - vec2 _curr = NDC_to_viewport(curr_, .zw); - vec2 _next = NDC_to_viewport(next_, .zw); + // vec2 _prev = NDC_to_viewport(prev_, .zw); + // vec2 _curr = NDC_to_viewport(curr_, .zw); + // vec2 _next = NDC_to_viewport(next_, .zw); // Compute vertex final position (in viewport coordinates) float w = linewidth/2.0 + 1.5*antialias; float z; vec2 P; + // if( curr == prev) { + // vec2 v = normalize(_next.xy - _curr.xy); + // vec2 normal = normalize(vec2(-v.y,v.x)); + // P = _curr.xy + normal*w*id; + // } else if (curr == next) { + // vec2 v = normalize(_curr.xy - _prev.xy); + // vec2 normal = normalize(vec2(-v.y,v.x)); + // P = _curr.xy + normal*w*id; + // } else { + // vec2 v0 = normalize(_curr.xy - _prev.xy); + // vec2 v1 = normalize(_next.xy - _curr.xy); + // vec2 normal = normalize(vec2(-v0.y,v0.x)); + // vec2 tangent = normalize(v0+v1); + // vec2 miter = vec2(-tangent.y, tangent.x); + // float l = abs(w / dot(miter,normal)); + // P = _curr.xy + miter*l*sign(id); + // } + if( curr == prev) { - vec2 v = normalize(_next.xy - _curr.xy); + vec2 v = normalize(next.xy - curr.xy); vec2 normal = normalize(vec2(-v.y,v.x)); - P = _curr.xy + normal*w*id; + P = curr.xy + normal*w*id; } else if (curr == next) { - vec2 v = normalize(_curr.xy - _prev.xy); + vec2 v = normalize(curr.xy - prev.xy); vec2 normal = normalize(vec2(-v.y,v.x)); - P = _curr.xy + normal*w*id; + P = curr.xy + normal*w*id; } else { - vec2 v0 = normalize(_curr.xy - _prev.xy); - vec2 v1 = normalize(_next.xy - _curr.xy); + vec2 v0 = normalize(curr.xy - prev.xy); + vec2 v1 = normalize(next.xy - curr.xy); vec2 normal = normalize(vec2(-v0.y,v0.x)); vec2 tangent = normalize(v0+v1); vec2 miter = vec2(-tangent.y, tangent.x); float l = abs(w / dot(miter,normal)); - P = _curr.xy + miter*l*sign(id); + P = curr.xy + miter*l*sign(id); } if( abs(id) > 1.5 ) v_color.a = 0.0; v_distance = w*id; - gl_Position = viewport_to_NDC(P, .zw, curr_.z / curr_.w); + // gl_Position = viewport_to_NDC(P, .zw, curr_.z / curr_.w); + // gl_Position = curr.xy + miter * l * sign(id); - ; + gl_Position = vec4(P , 0.0, 1.0); + + // ; } \ No newline at end of file diff --git a/shaders/hello.vert b/shaders/hello.vert index 03311ef..e9bd4a6 100644 --- a/shaders/hello.vert +++ b/shaders/hello.vert @@ -1,12 +1,7 @@ +layout(location = 0) in vec3 vertex; uniform mat4 projection; uniform mat4 view; -const vec2 verts[3] = vec2[3]( - vec2(0.5f, 1.0f), - vec2(0.0f, 0.0f), - vec2(1.0f, 0.0f) -); - out vec2 vert; out vec4 color; @@ -23,7 +18,7 @@ vec4 srgb_to_linear(vec4 srgb_color) { } void main() { - vert = verts[gl_VertexID]; + vert = vec2(vertex.xy); color = srgb_to_linear(vec4(vert, 0.5, 1.0)); - gl_Position = vec4(vert - 0.5, 0.0, 1.0); + gl_Position = vec4(vert, 0.0, 1.0); } \ No newline at end of file diff --git a/shaders/ppi.geom b/shaders/ppi.geom index d37cc1d..95336c2 100644 --- a/shaders/ppi.geom +++ b/shaders/ppi.geom @@ -3,6 +3,10 @@ layout(points) in; layout(triangle_strip, max_vertices = 4) out; +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + // conf: Range, Elevation, Resolution, 0.0 uniform vec4 conf; in float in_value[]; diff --git a/shaders/ppi.vert b/shaders/ppi.vert index 1cb4270..5997ba6 100644 --- a/shaders/ppi.vert +++ b/shaders/ppi.vert @@ -1,4 +1,6 @@ // Layout + + layout(location = 0) in vec3 position; out float in_value; diff --git a/src/camera.rs b/src/camera.rs index 8305e73..d508d0a 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,25 +1,23 @@ -use std::num::NonZeroU32; use cgmath::Euler; use glow::NativeProgram; -use nalgebra_glm::{ - Vec3, Mat4x4, look_at -}; +use nalgebra_glm::{look_at, Mat4x4, Vec3}; +use std::num::NonZeroU32; +#[derive(Clone)] pub(crate) struct Camera { pos: Vec3, upward: Vec3, - front: Vec3 + front: Vec3, } pub type CameraPositon = Vec3; impl Camera { pub(crate) fn new(world_loc: CameraPositon, upward: Vec3, front: Vec3) -> Self { - Self { pos: world_loc, upward, - front + front, } } @@ -51,5 +49,4 @@ impl Camera { let l = self.pos + self.front; look_at(&self.pos, &l, &self.upward) } - -} \ No newline at end of file +} diff --git a/src/final_pg.rs b/src/final_pg.rs deleted file mode 100644 index 87a48b8..0000000 --- a/src/final_pg.rs +++ /dev/null @@ -1,68 +0,0 @@ -use glow::HasContext; - -use crate::{ - components::{CodeType, Program, Shader}, - graphics::transforms::{ - polar::Polar, position::Position, trackball::Trackball, viewport::Viewport, Transform, - }, -}; - -// pub struct PPI { -// transform: Trackball, -// program: Program, -// } - -// impl PPI { -// pub fn new(version: &'static str) -> Self { -// let trackball = Trackball::new().unwrap(); -// let projection = Polar::new().unwrap(); -// let position = Position::new().unwrap(); - -// // let transform = trackball.chain(projection.chain(position)); - -// let vertex = Shader::new( -// glow::VERTEX_SHADER, -// CodeType::<&'static str>::Path("agg-fast-path.vert".into()), -// ) -// .unwrap(); - -// let fragment = Shader::new( -// glow::FRAGMENT_SHADER, -// CodeType::<&'static str>::Path("agg-fast-path.frag".into()), -// ) -// .unwrap(); - -// let mut program = Program::new(vertex, fragment, None, version); - -// let viewport = Viewport::new().unwrap(); - -// // program.set_transform(&transform); - -// program.set_viewport(&viewport); - -// Self { transform, program } -// } - -// pub fn compile(&mut self, gl: &glow::Context) { -// self.program.compile(gl); -// } - -// pub fn program(&self) -> &Program { -// &self.program -// } - -// pub fn native_program(&self) -> Option<::Program> { -// self.program.native_program -// } -// } - -mod test { - use super::*; - - #[test] - fn test_ppi() { - // let ppi = PPI::new("450"); - - // println!("{}", ppi.program.vertex()); - } -} diff --git a/src/graphics/collections/agg_fast_path.rs b/src/graphics/collections/agg_fast_path.rs index ca97129..86ac83c 100644 --- a/src/graphics/collections/agg_fast_path.rs +++ b/src/graphics/collections/agg_fast_path.rs @@ -8,16 +8,18 @@ use crate::errors::*; use crate::graphics::transforms::viewport::Viewport; use crate::graphics::transforms::Transform; use crate::graphics::ty::Ty; -use crate::graphics::Graphics; +use crate::graphics::{AttaWithBuffer, Config, Graphics}; use super::Colletion; pub struct AggFastPath { program: Program, buffer: Vec, + indice: Vec<[u32; 3]>, vao: Option, vbo: Option, + ebo: Option, } impl AggFastPath { @@ -63,6 +65,8 @@ impl AggFastPath { Ok(Self { program, buffer: Vec::with_capacity(128), + indice: Vec::with_capacity(128 * 2), + ebo: None, vao: None, vbo: None, }) @@ -104,6 +108,12 @@ impl AggFastPath { pub fn program_ref(&self) -> &Program { &self.program } + + fn init(&mut self, gl: &glow::Context) { + self.set_anatialias(gl, 0.005); + self.set_linecolor(gl, [1.0, 1.0, 1.0, 1.0]); + self.set_linewidth(gl, 0.02); + } } impl Colletion for AggFastPath { @@ -111,6 +121,7 @@ impl Colletion for AggFastPath { fn append(&mut self, item: Self::Item) { self.buffer.extend(item.points); + self.indice.extend(item.ebo); } } @@ -118,10 +129,15 @@ impl Graphics for AggFastPath { fn compile(&mut self, gl: &glow::Context) -> Result<()> { use bytemuck::cast_slice; self.program.compile(gl)?; + unsafe { let vao = gl.create_vertex_array().unwrap(); gl.bind_vertex_array(Some(vao)); + for p in self.buffer.iter() { + println!("{}", p); + } + println!("{:?}", self.indice); let vbo = gl.create_buffer().unwrap(); gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); @@ -143,8 +159,18 @@ impl Graphics for AggFastPath { gl.enable_vertex_attrib_array(3); gl.vertex_attrib_pointer_f32(3, 1, glow::FLOAT, false, 40, 36); + let ebo = gl.create_buffer().unwrap(); + gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ebo)); + + gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + cast_slice(&self.indice), + glow::STATIC_DRAW, + ); + self.vao = Some(vao); self.vbo = Some(vbo); + self.ebo = Some(ebo); gl.bind_vertex_array(None); } @@ -152,13 +178,16 @@ impl Graphics for AggFastPath { Ok(()) } - fn draw(&self, gl: &glow::Context) -> Result<()> { + fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { unsafe { gl.clear(glow::COLOR_BUFFER_BIT); - gl.use_program(Some(self.program.native_program.unwrap())); gl.bind_vertex_array(Some(self.vao.unwrap())); - gl.draw_arrays(glow::TRIANGLE_STRIP, 0, self.buffer.len() as i32); - + gl.draw_elements( + glow::TRIANGLES, + (self.indice.len() * 3) as i32, + glow::UNSIGNED_INT, + 0, + ); gl.bind_vertex_array(None); } @@ -169,14 +198,53 @@ impl Graphics for AggFastPath { self.program.destroy(gl); unsafe { + self.ebo.map(|ebo| gl.delete_buffer(ebo)); self.vao.map(|vao| gl.delete_vertex_array(vao)); self.vbo.map(|vbo| gl.delete_buffer(vbo)); } Ok(()) } + + fn program_ref(&self) -> &Program { + &self.program + } + + fn program_mut(&mut self) -> &mut Program { + &mut self.program + } + + fn set_config(&mut self, gl: &glow::Context, config: Option<&Config>) -> Result<()> { + Ok(()) + } + + fn mount(&mut self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.use_program(self.program.native_program); + self.init(gl); + } + Ok(()) + } + + fn unmount(&mut self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.use_program(None); + } + Ok(()) + } } +impl AttaWithBuffer for AggFastPath { + type Data = (); + + fn bake(&self, data: &Self::Data) -> Result<(Vec, Option>, i32)> { + Ok((vec![], None, 0)) + } + + fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option) { + (self.vao.unwrap(), self.vbo.unwrap(), self.ebo) + } +} #[repr(C)] #[derive(Debug, Clone, Copy, Zeroable, Pod)] pub struct Point { @@ -186,11 +254,23 @@ pub struct Point { id: f32, } +impl std::fmt::Display for Point { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Point {{ prev: {:?}, curr: {:?}, next: {:?}, id: {} }}", + self.prev, self.curr, self.next, self.id + ) + } +} + impl Ty for Point {} #[derive(Debug)] pub struct Path { points: Vec, + ebo: Vec<[u32; 3]>, + is_closed: bool, is_empty: bool, } @@ -199,6 +279,8 @@ impl Default for Path { fn default() -> Self { Self { points: Vec::with_capacity(500), + ebo: Vec::with_capacity(500), + is_closed: false, is_empty: true, } @@ -225,6 +307,8 @@ impl PathBuilder { Path { points: Vec::with_capacity(500), is_closed: self.is_closed, + ebo: Vec::with_capacity(500), + is_empty: true, } } @@ -234,6 +318,7 @@ impl Path { pub fn new(is_closed: bool) -> Self { Self { points: Vec::with_capacity(500), + ebo: Vec::with_capacity(500), is_closed, is_empty: true, } @@ -304,6 +389,11 @@ impl Path { self.points[len - 1].next = curr; self.points[len - 2].next = curr; } + for s in 0..(self.points.len() / 2) - 1 { + let s = s as u32; + self.ebo.push([s * 2, s * 2 + 1, (s + 1) * 2 + 1]); + self.ebo.push([s * 2, (s + 1) * 2 + 1, (s + 1) * 2]); + } } pub fn len(&self) -> usize { diff --git a/src/graphics/hello.rs b/src/graphics/hello.rs index f6b63ef..cb37be8 100644 --- a/src/graphics/hello.rs +++ b/src/graphics/hello.rs @@ -1,20 +1,21 @@ use std::ops::{Deref, DerefMut}; -use bytemuck::{Pod, Zeroable}; +use bytemuck::{cast_slice, Pod, Zeroable}; use glow::{HasContext, NativeBuffer, NativeVertexArray}; use crate::components::{fetchcode, CodeComponent, CodeType, Program, Shader, Snippet}; use crate::errors::*; -use crate::graphics::transforms::viewport::Viewport; -use crate::graphics::transforms::Transform; use crate::graphics::ty::Ty; use crate::graphics::Graphics; +use super::{AttaWithBuffer, Config}; + pub struct Hello { program: Program, buffer: Vec, vao: Option, + vbo: Option, } impl Hello { @@ -38,6 +39,7 @@ impl Hello { program, buffer: Vec::with_capacity(128), vao: None, + vbo: None, }) } @@ -58,19 +60,46 @@ impl Graphics for Hello { .create_vertex_array() .expect("Cannot create vertex array"); + let buffer: Vec<[f32; 3]> = vec![ + [-0.5, -0.5, 0.0], + [-0.5, 0.5, 0.0], + [0.5, 0.5, 0.0], + [0.5, -0.5, 0.0], + ]; + + gl.bind_vertex_array(Some(vertex_array)); + + let vbo = gl.create_buffer().unwrap(); + + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, cast_slice(&buffer), glow::STATIC_DRAW); + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 12, 0); + + let ebo = gl.create_buffer().unwrap(); + // let e: [[u32; 3]; 2] = [[0, 1, 3], [0, 2, 3]]; + let e: [[u32; 3]; 2] = [[0, 1, 2], [2, 3, 0]]; + gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ebo)); + gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + cast_slice(&e), + glow::STATIC_DRAW, + ); + self.vao = Some(vertex_array); + self.vbo = Some(vbo); } Ok(()) } - fn draw(&self, gl: &glow::Context) -> Result<()> { + fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { unsafe { gl.clear_color(0.05, 0.05, 0.1, 1.0); gl.clear(glow::COLOR_BUFFER_BIT); - gl.use_program(Some(self.program.native_program.unwrap())); gl.bind_vertex_array(self.vao); - gl.draw_arrays(glow::TRIANGLES, 0, 3); + + gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0); } Ok(()) @@ -80,11 +109,51 @@ impl Graphics for Hello { self.program.destroy(gl); unsafe { + self.vbo.map(|vbo| gl.delete_buffer(vbo)); self.vao.map(|vao| gl.delete_vertex_array(vao)); } Ok(()) } + + fn program_ref(&self) -> &Program { + &self.program + } + + fn program_mut(&mut self) -> &mut Program { + &mut self.program + } + + fn set_config(&mut self, gl: &glow::Context, config: Option<&Config>) -> Result<()> { + Ok(()) + } + + fn mount(&mut self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.use_program(self.program.native_program); + } + + Ok(()) + } + + fn unmount(&mut self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.use_program(None); + } + Ok(()) + } +} + +impl AttaWithBuffer for Hello { + type Data = (); + + fn bake(&self, data: &Self::Data) -> Result<(Vec, Option>, i32)> { + return Ok((vec![], None, 0)); + } + + fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option) { + panic!("Not implemented"); + } } #[repr(C)] diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 73d45ea..acbf9d8 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -3,20 +3,31 @@ pub mod colormap; mod colormesh; pub mod hello; pub mod ppi; +pub mod threed; pub mod tools; pub mod transforms; pub mod ty; use crate::{components::Program, errors::*}; -pub use colormesh::ColorMesh; -use imgui::TextureId; +use glow::{NativeBuffer, NativeVertexArray}; +use ppi::PPIConfig; -pub trait Graphics { - fn draw(&self, gl: &glow::Context) -> Result<()>; +pub trait Graphics: AttaWithBuffer { + fn draw(&self, gl: &glow::Context, count: i32) -> Result<()>; fn compile(&mut self, gl: &glow::Context) -> Result<()>; fn destroy(&mut self, gl: &glow::Context) -> Result<()>; + + fn program_ref(&self) -> &Program; + + fn program_mut(&mut self) -> &mut Program; + + fn mount(&mut self, gl: &glow::Context) -> Result<()>; + + fn unmount(&mut self, gl: &glow::Context) -> Result<()>; + + fn set_config(&mut self, gl: &glow::Context, config: Option<&Config>) -> Result<()>; } pub trait AttaWithProgram { @@ -25,12 +36,36 @@ pub trait AttaWithProgram { pub trait AttaWithBuffer { type Data; - fn attach_with_buffer(&mut self, gl: &glow::Context, data: &Self::Data) -> Result<()>; + + fn bake(&self, data: &Self::Data) -> Result<(Vec, Option>, i32)>; + fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option); } +macro_rules! config_for_everyitem { + ($({$conf:ty => $name:tt},)+) => { + $( + impl From<$conf> for Config { + fn from(value: $conf) -> Self { + Self::$name(value) + } + } + )+ -pub trait AttaWithWindow { + }; +} - fn attach_with_window(&mut self, gl: &glow::Context) -> Result; - -} \ No newline at end of file +#[derive(Clone)] +pub enum Config { + PPI(PPIConfig), +} + +config_for_everyitem!({PPIConfig => PPI},); + +pub trait AttachWithMouse { + fn attach_with_mouse(&mut self, state: MouseState); +} + +#[derive(Debug, Clone)] +pub enum MouseState { + Drag { from: [f32; 2], delta: [f32; 2] }, +} diff --git a/src/graphics/ppi.rs b/src/graphics/ppi.rs index 4911d55..b365e42 100644 --- a/src/graphics/ppi.rs +++ b/src/graphics/ppi.rs @@ -1,30 +1,18 @@ -use std::cell::RefCell; -use std::rc::Rc; +use glow::{HasContext, NativeBuffer, NativeVertexArray}; -use bytemuck::cast_slice; -use glow::{HasContext, NativeBuffer, NativeFramebuffer, NativeTexture, NativeVertexArray}; -use ndarray::{s, IndexLonger}; - -use crate::components::{CodeType, Program, Shader, Snippet}; +use crate::components::{CodeType, Program, Shader}; use crate::data_loader::{CoordType, Data, DataType}; use crate::errors::*; use super::colormap::ColorMap; +use super::threed::ThreeD; use super::transforms::viewport::Viewport; -use super::transforms::Transform; -use super::{ty, AttaWithBuffer, AttaWithWindow, Graphics}; +use super::{transforms, AttaWithBuffer, Config, Graphics}; pub struct PPI { program: Program, layer: isize, - vao: Option, - vbo: Option, - cmap: Option>, - - framebuffer: Option, - frametexture: Option, - buffer: Vec<[f32; 3]>, } impl PPI { @@ -44,24 +32,18 @@ impl PPI { CodeType::::Path("ppi.frag".into()), )?; - let program = Program::new(vertex, fragment, Some(geom), "330 core"); + let transform = ThreeD::new(1.0, 2.0, 1000.0, 45.0)?; + + let mut program = Program::new(vertex, fragment, Some(geom), "330 core"); + program.set_transform(&transform); Ok(Self { program, layer: 0, - vao: None, - vbo: None, - buffer: Vec::with_capacity(180 * 50), - framebuffer: None, - frametexture: None, cmap: None, }) } - pub fn set_transform(&mut self, transform: &T) { - self.program.set_transform(transform); - } - pub fn set_viewport(&mut self, viewport: &Viewport) { self.program.set_viewport(viewport); } @@ -75,23 +57,14 @@ impl PPI { &mut self.program } - fn set_conf(&self, gl: &glow::Context, dpir: f32, dpie: f32) { + fn set_conf(&self, gl: &glow::Context, rdpi: f32, adpi: f32) { let location = self.program.get_uniform_location(gl, "conf"); unsafe { - gl.uniform_4_f32(location.as_ref(), dpir, dpie, 0f32, 0f32); + gl.uniform_4_f32(location.as_ref(), rdpi, adpi, 0f32, 0f32); } } - pub fn add_ppi_layer(&mut self, layer: isize) { - self.layer = self.layer + layer; - self.layer.clamp(0, 23); - } - - pub fn program_ref(&self) -> &Program { - &self.program - } - - fn bake_data(&self, data: &Data) -> Result> { + fn bake_data(&self, data: &Data) -> Result<(Vec, i32)> { let first_block = data.blocks.get(0).unwrap(); let first_block_data = first_block.data.view(); if let CoordType::Polar { @@ -113,16 +86,17 @@ impl PPI { let dt = first_block_data .get([self.layer as usize, azi_idx, r_idx]) .unwrap(); - vertices.push([r, *azi, *dt]); + vertices.extend([r, *azi, *dt]); } } - return Ok(vertices); + let len = vertices.len() as i32 / 3; + return Ok((vertices, len)); } else { return Err(Error::InvalidDataType); } } - fn data_info(&self, data: &Data) -> Result<(f32, f32, DataType)> { + pub fn data_info(&self, data: &Data) -> Result<(f32, f32, DataType)> { let first_block = data.blocks.get(0).unwrap(); if let CoordType::Polar { azimuth, @@ -140,6 +114,23 @@ impl PPI { return Err(Error::InvalidDataType); } } + + fn init(&mut self, gl: &glow::Context, config: &PPIConfig) { + self.cmap + .as_mut() + .unwrap() + .attach_with_program(gl, &self.program) + .unwrap(); + + let origin = self.program.get_uniform_location(gl, "polar_origin"); + + let rdpi = config.rdpi; + let adpi = config.adpi; + self.set_conf(gl, rdpi, adpi); + unsafe { + gl.uniform_1_f32(origin.as_ref(), 90.0f32.to_radians()); + } + } } fn min_step(data: &Vec) -> f32 { @@ -173,84 +164,57 @@ fn max_step(data: &Vec) -> f32 { impl Graphics for PPI { fn compile(&mut self, gl: &glow::Context) -> Result<()> { self.program.compile(gl)?; - self.cmap - .as_mut() - .unwrap() - .attach_with_program(gl, &self.program)?; - unsafe { - let vao = gl.create_vertex_array().unwrap(); - gl.bind_vertex_array(Some(vao)); - let vbo = gl.create_buffer().unwrap(); - gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); - gl.enable_vertex_attrib_array(0); - gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 12, 0); - - self.vao = Some(vao); - self.vbo = Some(vbo); - gl.bind_vertex_array(None); - } - - // let location = self.program.get_uniform_location(gl, "conf"); - let origin = self.program.get_uniform_location(gl, "polar_origin"); - - unsafe { - // gl.uniform_4_f32(location.as_ref(), dpir, dpie, 0.0, 0.0); - gl.uniform_1_f32(origin.as_ref(), 90.0f32.to_radians()); - } - Ok(()) } fn destroy(&mut self, gl: &glow::Context) -> Result<()> { self.program.destroy(gl); - unsafe { - self.vao.map(|vao| gl.delete_vertex_array(vao)); - self.vbo.map(|vbo| gl.delete_buffer(vbo)); - self.framebuffer.map(|fb| gl.delete_framebuffer(fb)); - self.frametexture.map(|ft| gl.delete_texture(ft)); - self.cmap.as_mut().unwrap().destroy(gl); - } - Ok(()) } - fn draw(&self, gl: &glow::Context) -> Result<()> { + fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { unsafe { gl.clear(glow::COLOR_BUFFER_BIT); - gl.use_program(Some(self.program.native_program.unwrap())); self.cmap .as_ref() .unwrap() .bind_texture(gl, &self.program)?; - if self.framebuffer.is_some() { - gl.bind_framebuffer(glow::FRAMEBUFFER, self.framebuffer); + gl.draw_arrays(glow::POINTS, 0, count); + } + Ok(()) + } + + fn program_ref(&self) -> &Program { + &self.program + } + + fn program_mut(&mut self) -> &mut Program { + &mut self.program + } + + fn set_config(&mut self, gl: &glow::Context, config: Option<&Config>) -> Result<()> { + if let Some(config) = config { + if let Config::PPI(config) = config { + self.init(gl, config); + } else { + panic!("Errr config type"); } + } - gl.depth_mask(false); - gl.bind_vertex_array(Some(self.vao.unwrap())); - gl.draw_arrays(glow::POINTS, 0, self.buffer.len() as i32); - gl.depth_mask(true); + Ok(()) + } - if self.framebuffer.is_some() { - gl.framebuffer_texture_2d( - glow::FRAMEBUFFER, - glow::COLOR_ATTACHMENT0, - glow::TEXTURE_2D, - self.frametexture, - 0, - ); + fn mount(&mut self, gl: &glow::Context) -> Result<()> { + unsafe { + gl.use_program(self.program.native_program); + } + Ok(()) + } - assert_eq!( - gl.check_framebuffer_status(glow::FRAMEBUFFER), - glow::FRAMEBUFFER_COMPLETE - ); - gl.bind_texture(glow::TEXTURE_2D, None); - gl.bind_framebuffer(glow::FRAMEBUFFER, None); - } - - gl.bind_vertex_array(None); + fn unmount(&mut self, gl: &glow::Context) -> Result<()> { + unsafe { gl.use_program(None); } Ok(()) @@ -260,68 +224,33 @@ impl Graphics for PPI { impl AttaWithBuffer for PPI { type Data = Data; - fn attach_with_buffer(&mut self, gl: &glow::Context, data: &Self::Data) -> Result<()> { - let (rdpi, adpi, data_type) = self.data_info(data)?; + fn bake(&self, data: &Self::Data) -> Result<(Vec, Option>, i32)> { + // let (rdpi, adpi, data_type) = self.data_info(data)?; let baked_buffer = self.bake_data(data)?; - self.buffer = baked_buffer; - unsafe { - gl.use_program(self.program.native_program); - self.set_conf(gl, rdpi, adpi); - gl.bind_vertex_array(self.vao); - gl.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - cast_slice(&self.buffer), - glow::STATIC_DRAW, - ); - } + Ok((baked_buffer.0, None, baked_buffer.1)) + } - Ok(()) + fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option) { + unsafe { + let vao = gl.create_vertex_array().unwrap(); + gl.bind_vertex_array(Some(vao)); + let vbo = gl.create_buffer().unwrap(); + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); + gl.enable_vertex_attrib_array(0); + gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 12, 0); + gl.bind_vertex_array(None); + + (vao, vbo, None) + } } } -impl AttaWithWindow for PPI { - fn attach_with_window(&mut self, gl: &glow::Context) -> Result { - unsafe { - if self.framebuffer.is_none() { - let framebuffer = gl.create_framebuffer().unwrap(); - gl.bind_framebuffer(glow::FRAMEBUFFER, Some(framebuffer)); - - let texture = gl.create_texture().unwrap(); - - gl.bind_texture(glow::TEXTURE_2D, Some(texture)); - gl.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::RGB8 as i32, - 800, - 600, - 0, - glow::RGB, - glow::UNSIGNED_BYTE, - None, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::LINEAR as i32, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::LINEAR as i32, - ); - - gl.bind_framebuffer(glow::FRAMEBUFFER, None); - gl.bind_texture(glow::TEXTURE_2D, None); - self.frametexture = Some(texture); - Ok(imgui::TextureId::from(texture.0.get() as usize)) - } else { - Ok(imgui::TextureId::from( - self.frametexture.unwrap().0.get() as usize - )) - } - } - } +#[derive(Default, Clone)] +pub struct PPIConfig { + pub layer: usize, + pub rdpi: f32, + pub adpi: f32, + pub trackball: ThreeD, } mod test { diff --git a/src/graphics/threed.rs b/src/graphics/threed.rs new file mode 100644 index 0000000..3f110e4 --- /dev/null +++ b/src/graphics/threed.rs @@ -0,0 +1,82 @@ +use std::rc::Rc; + +use super::transforms::Transform; +use super::transforms::{position::Position, trackball::Trackball, ChainedTransform}; +use super::{AttaWithProgram, AttachWithMouse}; +use crate::camera::Camera; +use crate::errors::*; +use glow::HasContext; +use nalgebra_glm::Vec3; + +#[derive(Clone)] +pub struct ThreeD { + transform: Rc, + projection: nalgebra_glm::Mat4, + trackball: Trackball, + camera: Camera, +} + +impl ThreeD { + pub fn new(aspect: f32, z_far: f32, z_near: f32, fov: f32) -> Result { + let trackball = Trackball::new()?; + let transform = ChainedTransform::from(&trackball).chain(&Position::new()?); + + let camera = Camera::new( + Vec3::new(0.0, 0.0, 0.0), + Vec3::new(0.0, 0.0, -1.0), + Vec3::new(0.0, 1.0, 0.0), + ); + + let projection = nalgebra_glm::perspective(aspect, fov, z_near, z_far); + + Ok(Self { + transform: Rc::new(transform), + trackball, + camera, + projection, + }) + } +} + +impl Default for ThreeD { + fn default() -> Self { + Self::new(1.0, 2.0, 1000.0, 45.0).unwrap() + } +} + +impl AttaWithProgram for ThreeD { + fn attach_with_program( + &self, + gl: &glow::Context, + program: &crate::components::Program, + ) -> Result<()> { + unsafe { + let view = program.get_uniform_location(gl, "trackball_view"); + let projection = program.get_uniform_location(gl, "trackball_projection"); + self.trackball.attach_with_program(gl, program)?; + + gl.uniform_matrix_4_f32_slice( + view.as_ref(), + false, + self.camera.get_view_matrix().as_slice(), + ); + gl.uniform_matrix_4_f32_slice(projection.as_ref(), false, self.projection.as_slice()); + } + Ok(()) + } +} + +impl Transform for ThreeD { + fn snippet(&self) -> &crate::components::Snippet { + self.transform.snippet() + } +} + +impl AttachWithMouse for ThreeD { + fn attach_with_mouse(&mut self, state: super::MouseState) { + if let super::MouseState::Drag { from, delta } = state { + self.trackball + .on_mouse_drag(from[0], from[1], delta[0], delta[1]); + } + } +} diff --git a/src/graphics/transforms/mod.rs b/src/graphics/transforms/mod.rs index 56d69f7..f17c483 100644 --- a/src/graphics/transforms/mod.rs +++ b/src/graphics/transforms/mod.rs @@ -12,19 +12,19 @@ pub struct ChainedTransform { } impl ChainedTransform { - pub fn from(transform: T) -> Self { + pub fn from(transform: &T) -> Self { let snippet = transform.snippet().clone(); // let snippet = transform.snippet().to_owned(); Self { snippet, - chain: vec![Box::new(transform)], + chain: vec![Box::new(transform.clone())], } } - pub fn chain(mut self, other: impl Transform + 'static) -> Self { + pub fn chain(mut self, other: &P) -> Self { let new_snippet = self.snippet.clone().chain(other.snippet().to_owned()); self.snippet = new_snippet; - self.chain.push(Box::new(other)); + self.chain.push(Box::new(other.clone())); self } } diff --git a/src/graphics/transforms/position.rs b/src/graphics/transforms/position.rs index 201bc2c..14ae616 100644 --- a/src/graphics/transforms/position.rs +++ b/src/graphics/transforms/position.rs @@ -4,6 +4,7 @@ use crate::{ errors::*, graphics::AttaWithProgram, }; +#[derive(Debug, Clone)] pub struct Position { snippet: Snippet, } diff --git a/src/graphics/transforms/trackball.rs b/src/graphics/transforms/trackball.rs index c4e1ffe..a153d27 100644 --- a/src/graphics/transforms/trackball.rs +++ b/src/graphics/transforms/trackball.rs @@ -7,6 +7,7 @@ use super::Transform; use glow::HasContext; use nalgebra::{Matrix4, Quaternion, Translation3, Unit, UnitQuaternion, Vector3}; +#[derive(Debug, Clone)] pub struct TrackballModel { rotation: UnitQuaternion, count: usize, @@ -36,7 +37,7 @@ impl TrackballModel { trackball } - pub fn drag_to(&mut self, x: f32, y: f32, dx: f32, dy: f32) { + fn drag_to(&mut self, x: f32, y: f32, dx: f32, dy: f32) { let q = self.rotate(x, y, dx, dy); self.rotation *= q; self.count += 1; @@ -47,23 +48,23 @@ impl TrackballModel { self.model = self.rotation.to_homogeneous(); } - pub fn model(&self) -> &Matrix4 { + fn model(&self) -> &Matrix4 { &self.model } - pub fn theta(&self) -> f32 { + fn theta(&self) -> f32 { self.theta } - pub fn set_theta(&mut self, theta: f32) { + fn set_theta(&mut self, theta: f32) { self.set_orientation(theta % 360.0, self.phi % 360.0); } - pub fn phi(&self) -> f32 { + fn phi(&self) -> f32 { self.phi } - pub fn set_phi(&mut self, phi: f32) { + fn set_phi(&mut self, phi: f32) { self.set_orientation(self.theta % 360.0, phi % 360.0); } @@ -128,17 +129,10 @@ impl TrackballModel { } } +#[derive(Debug, Clone)] pub struct Trackball { snippet: Snippet, - - znear: f32, - zfar: f32, - zoom: f32, - aspect: f32, model: TrackballModel, - - projection: nalgebra_glm::Mat4x4, - view: nalgebra::Matrix4, } impl Trackball { @@ -152,82 +146,18 @@ impl Trackball { let model = TrackballModel::new(45.0, 45.0); - let aspect = 1.0; - let fovy = 45.0; - let near = 2.0; - let far = 1000.0; - - let projection = nalgebra_glm::perspective(aspect, fovy, near, far); - - let mut view: Matrix4 = Matrix4::identity(); - - let distance: f32 = 8.0; - - let translation = Translation3::new(0.0, 0.0, -distance.abs()); - view = translation.to_homogeneous() * view; - Ok(Self { snippet: snippets, - znear: near, - zfar: far, - zoom: fovy, - aspect, model, - projection, - view, }) } - pub fn on_mouse_drag( - &mut self, - gl: &glow::Context, - program: &mut Program, - x: f32, - y: f32, - dx: f32, - dy: f32, - ) { + pub fn on_mouse_drag(&mut self, x: f32, y: f32, dx: f32, dy: f32) { self.model.drag_to(x, y, dx, dy); - unsafe { - let model = self.snippet.find_symbol("trackball_model").unwrap(); - let l = program.get_uniform_location(gl, &model); - gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); - } } - pub fn on_mouse_scroll( - &mut self, - gl: &glow::Context, - program: &mut Program, - x: f32, - y: f32, - dz: f32, - ) { - self.zoom += dz; - self.projection = nalgebra_glm::perspective(self.aspect, self.zoom, self.znear, self.zfar); - unsafe { - let model = self.snippet.find_symbol("trackball_projection").unwrap(); - let l = program.get_uniform_location(gl, &model); - gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); - } - } - - fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { - unsafe { - let model = self.snippet.find_symbol("trackball_model").unwrap(); - let l = program.get_uniform_location(gl, &model); - gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); - - let projection = self.snippet.find_symbol("trackball_projection").unwrap(); - let l = program.get_uniform_location(gl, &projection); - gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.projection.as_slice()); - - let view = self.snippet.find_symbol("trackball_view").unwrap(); - let l = program.get_uniform_location(gl, &view); - gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.view.as_slice()); - } - - Ok(()) + pub fn model(&self) -> &Matrix4 { + self.model.model() } } @@ -239,7 +169,13 @@ impl Transform for Trackball { impl AttaWithProgram for Trackball { fn attach_with_program(&self, gl: &glow::Context, program: &Program) -> Result<()> { - self.attach_with_program(gl, program) + unsafe { + let model = self.snippet.find_symbol("trackball_model").unwrap(); + let l = program.get_uniform_location(gl, &model); + gl.uniform_matrix_4_f32_slice(l.as_ref(), false, self.model.model().as_slice()); + } + + Ok(()) } } diff --git a/src/main.rs b/src/main.rs index cef3258..adcea6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,83 +1,16 @@ -use std::cell::RefCell; -use std::rc::Rc; - -use data_loader::Data; -use graphics::colormap::linear::LinearColormap; -use graphics::ppi::PPI; -use graphics::transforms::position::Position; -use graphics::transforms::viewport::Viewport; -use graphics::{AttaWithBuffer, Graphics, AttaWithWindow}; -use imgui::Condition; - +mod ui; +use pg::App; mod camera; mod components; mod data_loader; mod errors; mod graphics; +mod pg; mod support; mod utils; -use imgui::*; - -mod final_pg; +use support::supporter::run; fn main() { env_logger::init(); - - let transform = Position::new().unwrap(); - let mut viewport = Viewport::new().unwrap(); - viewport.set_global(0.0, 0.0, 600.0, 800.0); - - let mut cmap = LinearColormap::new().unwrap(); - - cmap.set_colors(vec![ - [170, 170, 170, 255], - [0, 34, 255, 255], - [1, 160, 246, 255], - [0, 236, 236, 255], - [0, 216, 0, 255], - [1, 144, 0, 255], - [255, 255, 0, 255], - [231, 192, 0, 255], - [255, 144, 0, 255], - [255, 0, 0, 255], - [214, 0, 0, 255], - [192, 0, 0, 255], - [255, 0, 240, 255], - [150, 0, 180, 255], - ]); - - cmap.set_range(0.0, 70.0); - - let mut ppi = PPI::new().unwrap(); - ppi.set_transform(&transform); - ppi.set_viewport(&viewport); - ppi.set_colormap(Box::new(cmap)); - - let ppi = Rc::new(RefCell::new(ppi)); - - let registers = vec![ppi.clone()]; - let registers = registers.into_iter().map(|r| { - r as Rc> - }).collect(); - - - support::supporter::init(move |run, ui, window, gl| { - let mut ppi = ppi.borrow_mut(); - let texture = ppi.attach_with_window(gl).unwrap(); - - ui.window("test").build(||{ - if ui.button("load") { - let data = Data::from_path(r#"C:\Users\qwin7\Downloads\ZJSXAA_20230113070200_R.dat.gz"#).unwrap(); - ppi.attach_with_buffer(gl, &data).unwrap(); - } - }); - - ui.window("Test").size([200.0,400.0], imgui::Condition::FirstUseEver).build(|| { - imgui::Image::new(texture, [200.0, 400.0]).build(ui); - }); - - - }, - registers, -); -} \ No newline at end of file + run(move |gl| App::new(gl).unwrap()); +} diff --git a/src/pg.rs b/src/pg.rs new file mode 100644 index 0000000..17c3310 --- /dev/null +++ b/src/pg.rs @@ -0,0 +1,740 @@ +use crate::data_loader::Data; +use crate::graphics::colormap::linear::LinearColormap; +use crate::graphics::ppi::PPIConfig; +use crate::graphics::transforms::position::Position; +use crate::graphics::transforms::viewport::Viewport; +use crate::graphics::transforms::ChainedTransform; +use crate::graphics::{ppi::PPI, Graphics}; +use crate::graphics::{AttaWithBuffer, AttaWithProgram, Config, MouseState}; +use crate::{errors::*, ui::base}; +use glow::{HasContext, NativeBuffer, NativeFramebuffer, NativeTexture, NativeVertexArray}; +use imgui::{ImStr, ImString, Textures, Ui}; +use log::info; +use serde::de; +use std::collections::HashSet; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use winit::window; +pub type Graphic = Rc>>; +type RcGraphic = Rc>; + +pub struct App<'a> { + pub ui_state: State, + gl: &'a glow::Context, + viewport: Viewport, + windows: HashMap, + programs: [Graphic; 1], + pub ppi_module: RcGraphic, + program_with_window: HashMap>, + // Auto clean up + all_vaos: HashMap, + all_other_buffers: HashMap, + all_framebuffers: HashMap, + all_frametextures: HashMap, +} + +impl<'a> App<'a> { + pub fn new(gl: &'a glow::Context) -> Result { + let viewport = Viewport::new()?; + + let mut cmap = LinearColormap::new().unwrap(); + cmap.set_colors(vec![ + [170, 170, 170, 255], + [0, 34, 255, 255], + [1, 160, 246, 255], + [0, 236, 236, 255], + [0, 216, 0, 255], + [1, 144, 0, 255], + [255, 255, 0, 255], + [231, 192, 0, 255], + [255, 144, 0, 255], + [255, 0, 0, 255], + [214, 0, 0, 255], + [192, 0, 0, 255], + [255, 0, 240, 255], + [150, 0, 180, 255], + ]); + cmap.set_range(0.0, 70.0); + let cmap = Box::new(cmap); + + let mut ppi = PPI::new()?; + ppi.set_viewport(&viewport); + ppi.set_colormap(cmap); + + let ppi = Rc::new(RefCell::new(ppi)); + let programs = [ppi.clone() as Graphic]; + + Ok(Self { + ui_state: State {}, + viewport, + programs, + windows: HashMap::new(), + ppi_module: ppi, + gl, + program_with_window: HashMap::new(), + all_vaos: HashMap::with_capacity(30), + all_other_buffers: HashMap::with_capacity(30), + all_framebuffers: HashMap::with_capacity(30), + all_frametextures: HashMap::with_capacity(30), + }) + } + + pub fn render(&mut self) { + let mut need_clean = false; + for (id, program) in self.programs.iter().enumerate() { + let mut p = program.borrow_mut(); + + if self.program_with_window.len() == 0 { + return; + } + + p.mount(&self.gl).unwrap(); + self.program_with_window.get(&id).map(|windows| { + for window in windows.iter() { + let window_info = self.windows.get_mut(window).unwrap(); + if !window_info.need_redraw { + continue; + } + + let conf = if window_info.re_init { + window_info.config.as_ref() + } else { + None + }; + + { + p.set_config(self.gl, conf).unwrap(); + window_info.re_init = false; + } + + unsafe { + self.gl + .bind_framebuffer(glow::FRAMEBUFFER, window_info.framebuffer); + + let attach = window_info.attach.as_ref(); + + if attach.is_some() { + self.gl.bind_vertex_array(Some(attach.unwrap().vao)); + } + + if attach.is_some() { + let window_size = window_info.size; + + self.gl + .viewport(0, 0, window_size[0] as i32, window_size[1] as i32); + p.draw(&self.gl, attach.as_ref().unwrap().len).unwrap(); + } + + if attach.is_some() { + self.gl.bind_vertex_array(None); + } + self.gl.bind_framebuffer(glow::FRAMEBUFFER, None); + window_info.need_redraw = false; + need_clean = true; + } + } + }); + p.unmount(&self.gl).unwrap(); + } + + if need_clean { + self.clean(); + } + } + + pub fn render_ui(&mut self, ui: &Ui, window: &winit::window::Window, run: &mut bool) { + base(ui, window, run, self); + } + + pub fn create_framebuffer( + &mut self, + id: &str, + size: (i32, i32), + ) -> Result<(NativeFramebuffer, NativeTexture)> { + let id = &ImString::new(id); + let gl = self.gl; + let tex = unsafe { + let already = self.windows.contains_key(id) + && self.windows.get(id).unwrap().framebuffer.is_some(); + + if already { + return Ok(( + self.windows[id].framebuffer.unwrap(), + self.windows[id].frametexture.unwrap(), + )); + } + + let framebuffer = gl.create_framebuffer().unwrap(); + gl.bind_framebuffer(glow::FRAMEBUFFER, Some(framebuffer)); + + let texture = gl.create_texture().unwrap(); + gl.bind_texture(glow::TEXTURE_2D, Some(texture)); + gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGB8 as i32, + size.0, + size.1, + 0, + glow::RGB, + glow::UNSIGNED_BYTE, + None, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as i32, + ); + gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as i32, + ); + + gl.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + Some(texture), + 0, + ); + + assert_eq!( + gl.check_framebuffer_status(glow::FRAMEBUFFER), + glow::FRAMEBUFFER_COMPLETE + ); + + gl.bind_framebuffer(glow::FRAMEBUFFER, None); + gl.bind_texture(glow::TEXTURE_2D, None); + + self.all_framebuffers_add(&framebuffer); + self.all_frametextures_add(&texture); + (framebuffer, texture) + }; + + Ok(tex) + } + + pub fn prepare(&mut self) { + for program in self.programs.iter() { + let mut p = program.borrow_mut(); + p.compile(&self.gl).unwrap(); + } + } + + pub fn destroy(&mut self) { + for p in self.programs.iter() { + let mut p = p.borrow_mut(); + p.unmount(&self.gl).unwrap(); + p.destroy(&self.gl).unwrap(); + } + + info!("Cleaning up all resources"); + + unsafe { + for vao in self.all_vaos.keys() { + self.gl.delete_vertex_array(*vao); + } + + for vbo in self.all_other_buffers.keys() { + self.gl.delete_buffer(*vbo); + } + + for framebuffer in self.all_framebuffers.keys() { + self.gl.delete_framebuffer(*framebuffer); + } + + for texture in self.all_frametextures.keys() { + self.gl.delete_texture(*texture); + } + } + } + + pub fn create_ppi_render(&mut self, id: &str, config: Option) { + let id = &ImString::new(id); + let (vao, vbo, ebo) = self.ppi_module.borrow().init(&self.gl); + self.windows.get_mut(id).map(|w| { + w.attach = Some(Attach { + vao, + vbo, + ebo, + len: 0, + }); + w.need_redraw = true; + w.program = 0; + w.config = Some(config.unwrap_or_default().into()); + }); + + let v = self.program_with_window.entry(0).or_insert(vec![]); + v.push(id.clone()); + + self.all_vaos_add(&vao); + self.all_other_buffers_add(&vbo); + ebo.map(|ebo| self.all_other_buffers_add(&ebo)); + } + + pub fn bind_data(&mut self, id: &str, data: &Data) -> Result<()> { + let id = &ImString::new(id); + use bytemuck::cast_slice; + + let window = self.windows.get_mut(id).unwrap(); + + let program = window.program; + let program = self.programs[program].borrow(); + + let data = program.bake(data)?; + + assert!(window.attach.is_some()); + let attach = window.attach.as_mut().unwrap(); + + attach.len = data.2; + + unsafe { + self.gl.bind_buffer(glow::VERTEX_ARRAY, Some(attach.vbo)); + self.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + cast_slice(data.0.as_slice()), + glow::STATIC_DRAW, + ); + if let Some(ebo) = attach.ebo { + self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, attach.ebo); + self.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + cast_slice(&data.1.as_ref().unwrap()), + glow::STATIC_DRAW, + ); + + self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None); + } + self.gl.bind_buffer(glow::VERTEX_ARRAY, None); + } + + Ok(()) + } + + fn all_framebuffers_add(&mut self, framebuffer: &NativeFramebuffer) { + self.all_framebuffers + .entry(*framebuffer) + .and_modify(|v| *v += 1) + .or_insert(1); + + info!( + "Framebuffer: {:?} + 1, Framebuffer {:?}: {}", + framebuffer, framebuffer, self.all_framebuffers[framebuffer] + ); + } + + fn all_framebuffers_minus(&mut self, framebuffer: &NativeFramebuffer) { + self.all_framebuffers + .entry(*framebuffer) + .and_modify(|v| *v -= 1); + + info!( + "Framebuffer: {:?} - 1, Framebuffer {:?}: {}", + framebuffer, framebuffer, self.all_framebuffers[framebuffer] + ); + } + + fn all_frametextures_add(&mut self, texture: &NativeTexture) { + self.all_frametextures + .entry(*texture) + .and_modify(|v| *v += 1) + .or_insert(1); + + info!( + "Texture: {:?} + 1, Frametexture {:?}: {}", + texture, texture, self.all_frametextures[texture] + ); + } + + fn all_frametextures_minus(&mut self, texture: &NativeTexture) { + self.all_frametextures + .entry(*texture) + .and_modify(|v| *v -= 1); + + info!( + "Texture: {:?} - 1, Frametexture {:?}: {}", + texture, texture, self.all_frametextures[texture] + ); + } + + fn all_vaos_add(&mut self, vao: &NativeVertexArray) { + self.all_vaos + .entry(*vao) + .and_modify(|v| *v += 1) + .or_insert(1); + + info!("Vao: {:?} + 1, Vao {:?}: {}", vao, vao, self.all_vaos[vao]); + } + + fn all_vaos_minus(&mut self, vao: &NativeVertexArray) { + self.all_vaos.entry(*vao).and_modify(|v| *v -= 1); + + info!("Vao: {:?} - 1, Vao {:?}: {}", vao, vao, self.all_vaos[vao]); + } + + fn all_other_buffers_add(&mut self, buffer: &NativeBuffer) { + self.all_other_buffers + .entry(*buffer) + .and_modify(|v| *v += 1) + .or_insert(1); + + info!( + "Buffer: {:?} + 1, Buffer {:?}: {}", + buffer, buffer, self.all_other_buffers[buffer] + ); + } + + fn all_other_buffers_minus(&mut self, buffer: &NativeBuffer) { + self.all_other_buffers + .entry(*buffer) + .and_modify(|v| *v -= 1); + + info!( + "Buffer: {:?} - 1, Buffer {:?}: {}", + buffer, buffer, self.all_other_buffers[buffer] + ); + } + + pub fn show_window(&mut self, ui: &Ui) { + let mut need_resize = vec![]; + + for (id, window) in self.windows.iter_mut() { + ui.window(&window.title) + .size(window.size, imgui::Condition::FirstUseEver) + .opened(&mut window.open) + .flags(imgui::WindowFlags::NO_SCROLLBAR) + .build(|| { + if ui.is_mouse_clicked(imgui::MouseButton::Left) { + let io = ui.io(); + let pos = io.mouse_pos; + window.last_mouse_position = pos; + } + + if ui.is_mouse_dragging(imgui::MouseButton::Left) { + let delta = ui.mouse_drag_delta(); + window.last_mouse_delta = delta; + window.accmulate_mouse_delta = [ + window.accmulate_mouse_delta[0] + delta[0], + window.accmulate_mouse_delta[1] + delta[1], + ]; + window.motion = Some(MouseState::Drag { + from: window.last_mouse_position, + delta: delta, + }); + } + if ui.is_mouse_released(imgui::MouseButton::Left) { + if window.size != ui.window_size() { + window.size = ui.window_size(); + println!("resized: {:?}", window.size); + need_resize.push((window.title.clone(), ui.window_size())); + } + } + + if let Some(texture) = window.frametexture { + let cursor = ui.cursor_pos(); + imgui::Image::new( + imgui::TextureId::new(texture.0.get() as usize), + ui.window_size(), + ) + .build(ui); + ui.set_cursor_pos(cursor); + if ui.invisible_button(&window.title, ui.window_size()) { + let io = ui.io(); + let pos = io.mouse_pos; + let window_pos = ui.window_pos(); + let related_pos = [pos[0] - window_pos[0], pos[1] - window_pos[1]]; + } + } + }); + } + + for (id, size) in need_resize.iter() { + self.reset_window_size(id, *size); + } + } + + // pub fn copy_window_resource( + // &mut self, + // src: &str, + // dst: &str, + // stick: bool, + // ) -> Option { + // let src = &ImString::new(src); + // let window_info = self.windows.get(src).unwrap(); + + // let new_texture = if stick { + // let new_framebuffer_tex = self.create_framebuffer(dst, (300, 300)).unwrap(); + // unsafe { + // self.gl + // .bind_framebuffer(glow::READ_FRAMEBUFFER, window_info.framebuffer); + // self.gl + // .bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.framebuffers[dst].0)); + // self.gl.blit_framebuffer( + // 0, + // 0, + // 300, + // 300, + // 0, + // 0, + // 300, + // 300, + // glow::COLOR_BUFFER_BIT, + // glow::NEAREST, + // ); + // self.gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); + // self.gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); + // } + + // self.framebuffers + // .get_mut(dst) + // .map(|(_, redraw, program, atta)| { + // *atta = new_framebuffer.as_ref().map(|v| v.3.clone()).flatten(); + // *redraw = true; + // *program = new_framebuffer.as_ref().map(|v| v.2).unwrap(); + // }); + + // Some(new_framebuffer_tex) + // } else { + // let texture = self.frametextures.get(src).map(|texture| *texture); + // if let Some(ref framebuffer) = new_framebuffer { + // if let Some(ref texture) = texture { + // self.all_framebuffers_add(&framebuffer.0); + // self.all_frametextures_add(&texture); + // self.framebuffers + // .insert(ImString::new(dst), framebuffer.clone()); + // self.frametextures + // .insert(ImString::new(dst), texture.clone()); + // } + // } + // texture + // }; + + // new_framebuffer.map(|framebuffer| { + // new_texture.map(|_| { + // self.all_vaos_add(&framebuffer.3.as_ref().unwrap().vao); + // self.all_other_buffers_add(&framebuffer.3.as_ref().unwrap().vbo); + // framebuffer.3.as_ref().unwrap().ebo.map(|ebo| { + // self.all_other_buffers_add(&ebo); + // }); + + // self.program_with_window.get_mut(&framebuffer.2).map(|v| { + // v.push(ImString::new(dst)); + // }); + // }); + // }); + + // new_texture + // } + pub fn create_render_window(&mut self, title: &str, size: [f32; 2]) -> Result<()> { + // Insert the window data into the windows hashmap + let id = ImString::new(title); + let mut data = WindowData::new(id.clone(), size); + let (fb, tex) = + self.create_framebuffer(title, (size[0].floor() as i32, size[1].floor() as i32))?; + + data.framebuffer = Some(fb); + data.frametexture = Some(tex); + self.windows.insert(id, data); + Ok(()) + } + + pub fn set_config(&mut self, id: &str) -> Option<&mut Config> { + let id = &ImString::new(id); + self.windows + .get_mut(id) + .map(|v| { + v.re_init = true; + v.config.as_mut() + }) + .flatten() + } + + fn reset_window_size(&mut self, id: &ImString, size: [f32; 2]) { + let window_info = self.windows.get_mut(id).unwrap(); + window_info.need_redraw = true; + let tex = unsafe { + self.gl + .bind_framebuffer(glow::FRAMEBUFFER, window_info.framebuffer); + let texture = self.gl.create_texture().unwrap(); + self.gl.bind_texture(glow::TEXTURE_2D, Some(texture)); + self.gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGB8 as i32, + size[0].floor() as i32, + size[1].floor() as i32, + 0, + glow::RGB, + glow::UNSIGNED_BYTE, + None, + ); + self.gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MIN_FILTER, + glow::LINEAR as i32, + ); + self.gl.tex_parameter_i32( + glow::TEXTURE_2D, + glow::TEXTURE_MAG_FILTER, + glow::LINEAR as i32, + ); + + self.gl.framebuffer_texture_2d( + glow::FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::TEXTURE_2D, + Some(texture), + 0, + ); + + assert_eq!( + self.gl.check_framebuffer_status(glow::FRAMEBUFFER), + glow::FRAMEBUFFER_COMPLETE + ); + + self.gl.bind_framebuffer(glow::FRAMEBUFFER, None); + self.gl.bind_texture(glow::TEXTURE_2D, None); + + texture + }; + let raw_tex = window_info.frametexture.as_ref().unwrap().to_owned(); + self.all_frametextures_minus(&raw_tex); + self.all_frametextures_add(&tex); + } + + pub fn destroy_window(&mut self) { + let ids: Vec<_> = self + .windows + .iter() + .filter(|v| v.1.open == false) + .map(|v| v.0.clone()) + .collect(); + + for id in ids.iter() { + let window = self.windows.remove(id).unwrap(); + + window.framebuffer.map(|framebuffer| { + self.all_framebuffers_minus(&framebuffer); + }); + + window.frametexture.map(|texture| { + self.all_frametextures_minus(&texture); + }); + + if let Some(atta) = window.attach { + self.all_vaos_minus(&atta.vao); + self.all_other_buffers_minus(&atta.vbo); + atta.ebo.map(|ebo| { + self.all_other_buffers_minus(&ebo); + }); + } + } + } + + fn clean(&mut self) { + info!("Cleaning up unused resources"); + unsafe { + self.all_framebuffers + .iter() + .filter(|v| *v.1 == 0) + .for_each(|(bf, _)| { + info!("Deleting framebuffer: {:?}", bf); + self.gl.delete_framebuffer(*bf); + }); + + self.all_frametextures + .iter() + .filter(|v| *v.1 == 0) + .for_each(|(bf, _)| { + info!("Deleting texture: {:?}", bf); + self.gl.delete_texture(*bf); + }); + + self.all_vaos + .iter() + .filter(|v| *v.1 == 0) + .for_each(|(bf, _)| { + info!("Deleting vao: {:?}", bf); + self.gl.delete_vertex_array(*bf); + }); + + self.all_other_buffers + .iter() + .filter(|v| *v.1 == 0) + .for_each(|(bf, _)| { + info!("Deleting buffer: {:?}", bf); + self.gl.delete_buffer(*bf); + }); + } + self.all_framebuffers.retain(|_, v| *v > 0); + self.all_frametextures.retain(|_, v| *v > 0); + self.all_vaos.retain(|_, v| *v > 0); + self.all_other_buffers.retain(|_, v| *v > 0); + } +} + +#[derive(Debug, Clone)] +pub struct Attach { + pub vao: NativeVertexArray, + pub vbo: NativeBuffer, + pub ebo: Option, + pub len: i32, +} + +pub struct State {} + +pub struct WindowData { + pub title: ImString, + pub open: bool, + pub copy_from: Option, + pub size: [f32; 2], + framebuffer: Option, + frametexture: Option, + need_redraw: bool, + program: usize, + attach: Option, + + re_init: bool, + last_mouse_position: [f32; 2], + last_mouse_delta: [f32; 2], + accmulate_mouse_delta: [f32; 2], + mouse_position: [f32; 2], + motion: Option, + config: Option, +} + +impl WindowData { + pub fn new(title: ImString, size: [f32; 2]) -> Self { + Self { + title, + open: true, + copy_from: None, + size, + last_mouse_position: [0.0, 0.0], + last_mouse_delta: [0.0, 0.0], + accmulate_mouse_delta: [0.0, 0.0], + mouse_position: [0.0, 0.0], + motion: None, + + framebuffer: None, + frametexture: None, + need_redraw: false, + program: 0, + attach: None, + re_init: false, + config: None, + } + } + + fn set_current_mouse_delta(&mut self, delta: [f32; 2]) { + self.last_mouse_delta = delta; + self.accmulate_mouse_delta = [ + self.accmulate_mouse_delta[0] + delta[0], + self.accmulate_mouse_delta[1] + delta[1], + ]; + } + + fn set_mouse_postion(&mut self, pos: [f32; 2]) { + self.mouse_position = pos; + } +} diff --git a/src/support/_s.rs b/src/support/_s.rs new file mode 100644 index 0000000..b1a7b78 --- /dev/null +++ b/src/support/_s.rs @@ -0,0 +1,215 @@ +use std::num::NonZeroU32; + +use glow::HasContext; +use glutin::{ + config::ConfigTemplateBuilder, + context::{ContextApi, ContextAttributesBuilder, NotCurrentGlContext, PossiblyCurrentContext}, + display::{GetGlDisplay, GlDisplay}, + surface::{GlSurface, Surface, SurfaceAttributesBuilder, SwapInterval, WindowSurface}, +}; +use imgui_winit_support::WinitPlatform; +use raw_window_handle::HasRawWindowHandle; +use winit::{ + dpi::LogicalSize, + event_loop::EventLoop, + window::{Window, WindowBuilder}, +}; + +pub fn create_window( + title: &str, + context_api: Option, +) -> ( + EventLoop<()>, + Window, + Surface, + PossiblyCurrentContext, +) { + let event_loop = EventLoop::new().unwrap(); + + let window_builder = WindowBuilder::new() + .with_title(title) + .with_inner_size(LogicalSize::new(1024, 768)); + let (window, cfg) = glutin_winit::DisplayBuilder::new() + .with_window_builder(Some(window_builder)) + .build(&event_loop, ConfigTemplateBuilder::new(), |mut configs| { + configs.next().unwrap() + }) + .expect("Failed to create OpenGL window"); + + let window = window.unwrap(); + + let mut context_attribs = ContextAttributesBuilder::new(); + if let Some(context_api) = context_api { + context_attribs = context_attribs.with_context_api(context_api); + } + let context_attribs = context_attribs.build(Some(window.raw_window_handle())); + let context = unsafe { + cfg.display() + .create_context(&cfg, &context_attribs) + .expect("Failed to create OpenGL context") + }; + + let surface_attribs = SurfaceAttributesBuilder::::new() + .with_srgb(Some(true)) + .build( + window.raw_window_handle(), + NonZeroU32::new(1024).unwrap(), + NonZeroU32::new(768).unwrap(), + ); + let surface = unsafe { + cfg.display() + .create_window_surface(&cfg, &surface_attribs) + .expect("Failed to create OpenGL surface") + }; + + let context = context + .make_current(&surface) + .expect("Failed to make OpenGL context current"); + + surface + .set_swap_interval(&context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())) + .expect("Failed to set swap interval"); + + (event_loop, window, surface, context) +} + +pub fn glow_context(context: &PossiblyCurrentContext) -> glow::Context { + unsafe { + glow::Context::from_loader_function_cstr(|s| context.display().get_proc_address(s).cast()) + } +} + +pub fn imgui_init(window: &Window) -> (WinitPlatform, imgui::Context) { + let mut imgui_context = imgui::Context::create(); + imgui_context.set_ini_filename(None); + + let mut winit_platform = WinitPlatform::init(&mut imgui_context); + winit_platform.attach_window( + imgui_context.io_mut(), + window, + imgui_winit_support::HiDpiMode::Rounded, + ); + + imgui_context + .fonts() + .add_font(&[imgui::FontSource::DefaultFontData { config: None }]); + + imgui_context.io_mut().font_global_scale = (1.0 / winit_platform.hidpi_factor()) as f32; + + (winit_platform, imgui_context) +} + +pub struct Triangler { + pub program: ::Program, + pub vertex_array: ::VertexArray, +} + +impl Triangler { + pub fn new(gl: &glow::Context, shader_header: &str) -> Self { + const VERTEX_SHADER_SOURCE: &str = r#" +const vec2 verts[3] = vec2[3]( + vec2(0.5f, 1.0f), + vec2(0.0f, 0.0f), + vec2(1.0f, 0.0f) +); + +out vec2 vert; +out vec4 color; + +vec4 srgb_to_linear(vec4 srgb_color) { + // Calcuation as documented by OpenGL + vec3 srgb = srgb_color.rgb; + vec3 selector = ceil(srgb - 0.04045); + vec3 less_than_branch = srgb / 12.92; + vec3 greater_than_branch = pow((srgb + 0.055) / 1.055, vec3(2.4)); + return vec4( + mix(less_than_branch, greater_than_branch, selector), + srgb_color.a + ); +} + +void main() { + vert = verts[gl_VertexID]; + color = srgb_to_linear(vec4(vert, 0.5, 1.0)); + gl_Position = vec4(vert - 0.5, 0.0, 1.0); +} +"#; + const FRAGMENT_SHADER_SOURCE: &str = r#" +in vec2 vert; +in vec4 color; + +out vec4 frag_color; + +vec4 linear_to_srgb(vec4 linear_color) { + vec3 linear = linear_color.rgb; + vec3 selector = ceil(linear - 0.0031308); + vec3 less_than_branch = linear * 12.92; + vec3 greater_than_branch = pow(linear, vec3(1.0/2.4)) * 1.055 - 0.055; + return vec4( + mix(less_than_branch, greater_than_branch, selector), + linear_color.a + ); +} + +void main() { + frag_color = linear_to_srgb(color); +} +"#; + + let mut shaders = [ + (glow::VERTEX_SHADER, VERTEX_SHADER_SOURCE, None), + (glow::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE, None), + ]; + + unsafe { + let vertex_array = gl + .create_vertex_array() + .expect("Cannot create vertex array"); + + let program = gl.create_program().expect("Cannot create program"); + + for (kind, source, handle) in &mut shaders { + let shader = gl.create_shader(*kind).expect("Cannot create shader"); + gl.shader_source(shader, &format!("{}\n{}", shader_header, *source)); + gl.compile_shader(shader); + if !gl.get_shader_compile_status(shader) { + panic!("{}", gl.get_shader_info_log(shader)); + } + gl.attach_shader(program, shader); + *handle = Some(shader); + } + + gl.link_program(program); + if !gl.get_program_link_status(program) { + panic!("{}", gl.get_program_info_log(program)); + } + + for &(_, _, shader) in &shaders { + gl.detach_shader(program, shader.unwrap()); + gl.delete_shader(shader.unwrap()); + } + + Self { + program, + vertex_array, + } + } + } + + pub fn render(&self, gl: &glow::Context) { + unsafe { + gl.clear_color(0.05, 0.05, 0.1, 1.0); + gl.clear(glow::COLOR_BUFFER_BIT); + gl.use_program(Some(self.program)); + gl.bind_vertex_array(Some(self.vertex_array)); + gl.draw_arrays(glow::TRIANGLES, 0, 3); + } + } + + pub fn destroy(&self, gl: &glow::Context) { + unsafe { + gl.delete_program(self.program); + gl.delete_vertex_array(self.vertex_array); + } + } +} diff --git a/src/support/supporter.rs b/src/support/supporter.rs index 1f3b67f..15f2cd0 100644 --- a/src/support/supporter.rs +++ b/src/support/supporter.rs @@ -1,8 +1,4 @@ -use crate::camera::Camera; -use crate::graphics::colormap::linear::LinearColormap; -use crate::graphics::ppi::PPI; -use crate::graphics::transforms::{position, ChainedTransform}; -use crate::graphics::{hello, AttaWithBuffer, AttaWithProgram, Graphics}; +use crate::pg::App; use crate::{ graphics::{ collections::agg_fast_path::AggFastPath, @@ -12,7 +8,6 @@ use crate::{ }, utils::Triangler, }; -use cgmath::InnerSpace; use glow::HasContext; use glutin::{ config::ConfigTemplateBuilder, @@ -32,35 +27,35 @@ use imgui_winit_support::{ use nalgebra_glm::perspective; use nalgebra_glm::Vec3; use raw_window_handle::HasRawWindowHandle; -use std::cell::RefCell; use std::num::NonZeroU32; -use std::rc::Rc; use std::time::Instant; -pub fn init(mut run_ui: FUi, mut register: Vec>>) +pub fn run(mut app: F) where - FUi: FnMut(&mut bool, &mut Ui, &Window, &glow::Context) + 'static, + F: for<'b> FnMut(&'b glow::Context) -> App<'b>, { + // Create Window let (event_loop, window, surface, context) = create_window(); let (mut winit_platform, mut imgui_context) = imgui_init(&window); - let gl = unsafe { - let gl = glow_context(&context); - gl.enable(glow::DEPTH_TEST); - gl.enable(glow::BLEND); - gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); - gl - }; + // OpenGL context + let gl = glow_context(&context); // OpenGL renderer from this crate let mut ig_renderer = imgui_glow_renderer::AutoRenderer::initialize(gl, &mut imgui_context) .expect("failed to create renderer"); + + let gl_app = ig_renderer.gl_context().clone(); let gl_context = ig_renderer.gl_context().clone(); - for r in register.iter_mut() { - r.borrow_mut().compile(&gl_context).unwrap(); - } - + // let mut run = true; + let mut app = app(&gl_app); + + let mut run = true; + + // Prepare + app.prepare(); + let mut last_frame = Instant::now(); event_loop @@ -86,32 +81,15 @@ where } => { // Render your custom scene, note we need to borrow the OpenGL // context from the `AutoRenderer`, which takes ownership of it. - unsafe { - gl_context.clear(glow::DEPTH_BUFFER_BIT); - gl_context.clear(glow::COLOR_BUFFER_BIT); + gl_context.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT); } + app.render(); let ui = imgui_context.frame(); + app.render_ui(&ui, &window, &mut run); - if ui.is_mouse_pos_valid(ui.io().mouse_pos) { - let mouse_pos = ui.io().mouse_pos; - if ui.is_mouse_dragging(imgui::MouseButton::Right) { - } - } - - for r in register.iter_mut() { - r.borrow_mut().draw(&gl_context).unwrap(); - } - - let mut run = true; - - run_ui(&mut run, ui, &window, ig_renderer.gl_context()); - - if !run { - window_target.exit(); - } - + winit_platform.prepare_render(ui, &window); let draw_data = imgui_context.render(); // Render imgui on top of it @@ -140,16 +118,11 @@ where NonZeroU32::new(new_size.width).unwrap(), NonZeroU32::new(new_size.height).unwrap(), ); - } winit_platform.handle_event(imgui_context.io_mut(), &window, &event); } winit::event::Event::LoopExiting => { - - for r in register.iter_mut() { - r.borrow_mut().destroy(&gl_context).unwrap(); - } - + app.destroy(); } event => { winit_platform.handle_event(imgui_context.io_mut(), &window, &event); @@ -159,51 +132,6 @@ where .unwrap() } -fn mouse_callback( - last_position: &mut Option>, - current_position: PhysicalPosition, - sensitivity: f64, - pitch: &mut f64, - yaw: &mut f64, - camera: &mut Camera, -) { - use cgmath::{Deg, Euler, Quaternion}; - - let xpos = current_position.x; - let ypos = current_position.y; - - if last_position.is_none() { - *last_position = Some(PhysicalPosition::new(xpos, ypos)); - } - - let _last_position = last_position.unwrap(); - - let mut xoffset = xpos - _last_position.x; - let mut yoffset = _last_position.y - ypos; // reversed since y-coordinates go from bottom to top - - *last_position = Some(PhysicalPosition::new(xpos, ypos)); - - xoffset *= sensitivity; - yoffset *= sensitivity; - - *yaw += xoffset; - *pitch += yoffset; - - if *pitch > 89.0 { - *pitch = 89.0; - } - - if *pitch < -89.0 { - *pitch = -89.0; - } - - let euler_deg = Euler::new(Deg(*pitch), Deg(*yaw), Deg(0.0)); - - let c = Quaternion::from(euler_deg).normalize(); - - camera.set_front(Vec3::new(c.v.x as f32, c.v.y as f32, c.v.z as f32)); -} - fn create_window() -> ( EventLoop<()>, Window, diff --git a/src/ui.rs b/src/ui.rs new file mode 100644 index 0000000..e0ecbf4 --- /dev/null +++ b/src/ui.rs @@ -0,0 +1,44 @@ +use crate::errors::*; +use crate::graphics::Config; +use crate::pg::App; +use crate::{data_loader::Data, pg::WindowData}; +use glow::NativeTexture; +use imgui::{ImString, Ui}; + +pub fn base(ui: &Ui, window: &winit::window::Window, run: &mut bool, app: &mut App) { + ui.window("test") + .size([300.0, 200.0], imgui::Condition::FirstUseEver) + .build(|| { + if ui.button("PPI") { + let data = + load_data(r#"/Users/tsuki/Desktop/ZJSXAA_20230113070200_R.dat.gz"#).unwrap(); + app.create_render_window("ppi", [300.0, 300.0]).unwrap(); + app.create_ppi_render("ppi", None); + app.bind_data("ppi", &data).unwrap(); + + let (rdpi, adpi, _) = { + let ppi = app.ppi_module.borrow_mut(); + ppi.data_info(&data).unwrap() + }; + + app.set_config("ppi").map(|config| { + if let Config::PPI(config) = config { + config.rdpi = rdpi; + config.adpi = adpi; + } + }); + } + }); + + app.show_window(ui); + app.destroy_window(); +} + +fn create_display_window(title: &str, size: [f32; 2], copy_from: Option) -> WindowData { + WindowData::new(ImString::new(title), size) +} + +fn load_data(path: impl AsRef) -> Result { + let data = Data::from_path(path)?; + Ok(data) +}