radar-gi/src/pg.rs
2024-07-22 21:55:59 +08:00

741 lines
24 KiB
Rust

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<Data> = Rc<RefCell<dyn Graphics<Data = Data>>>;
type RcGraphic<T> = Rc<RefCell<T>>;
pub struct App<'a> {
pub ui_state: State,
gl: &'a glow::Context,
viewport: Viewport,
windows: HashMap<ImString, WindowData>,
programs: [Graphic<Data>; 1],
pub ppi_module: RcGraphic<PPI>,
program_with_window: HashMap<usize, Vec<ImString>>,
// Auto clean up
all_vaos: HashMap<NativeVertexArray, usize>,
all_other_buffers: HashMap<NativeBuffer, usize>,
all_framebuffers: HashMap<NativeFramebuffer, usize>,
all_frametextures: HashMap<NativeTexture, usize>,
}
impl<'a> App<'a> {
pub fn new(gl: &'a glow::Context) -> Result<Self> {
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<Data>];
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<PPIConfig>) {
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<NativeTexture> {
// 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<NativeBuffer>,
pub len: i32,
}
pub struct State {}
pub struct WindowData {
pub title: ImString,
pub open: bool,
pub copy_from: Option<ImString>,
pub size: [f32; 2],
framebuffer: Option<NativeFramebuffer>,
frametexture: Option<NativeTexture>,
need_redraw: bool,
program: usize,
attach: Option<Attach>,
re_init: bool,
last_mouse_position: [f32; 2],
last_mouse_delta: [f32; 2],
accmulate_mouse_delta: [f32; 2],
mouse_position: [f32; 2],
motion: Option<MouseState>,
config: Option<Config>,
}
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;
}
}