radar-gi/src/pg/modules/ppi.rs
2024-08-21 00:03:35 +08:00

382 lines
11 KiB
Rust

use collections::agg_fast_path::{AggFastPath, AggFastPathConfig, Path};
use core::f32;
use font::{FontConfig, LineStyle, PositionText, TextLine};
use glow::HasContext;
use std::rc::Rc;
use tracker::track;
use transforms::viewport;
use crate::font_manager::{FontSize, FontStyle};
use crate::graphics::{font::Text, *};
use crate::pg::layout_type::ViewPort;
use crate::ui::helper_components::colorbar::colorbar;
use crate::ui::operation::{self, Operation};
use crate::SETTING;
use crate::{
data_loader::Data,
errors::*,
font_manager::FontManager,
ui::typ,
utils::{cache::CachedData, resources::ManagedResource},
};
use imgui::VerticalSlider;
use ppi::{PPIConfig, PPI};
use threed::Trackball;
use super::{Attach, Module, ModuleCursor};
pub struct PPIModule<'b, 'a: 'b> {
gl: &'a glow::Context,
ppi_program: &'b mut PPI,
line_program: &'b mut AggFastPath,
text_program: &'b mut Text<'a>,
}
impl<'b, 'a: 'b> PPIModule<'b, 'a> {
pub fn new(
gl: &'a glow::Context,
ppi: &'b mut PPI,
text: &'b mut Text<'a>,
line: &'b mut AggFastPath,
) -> Result<Self> {
let config = PPIConfig::default();
Ok(Self {
gl,
ppi_program: ppi,
text_program: text,
line_program: line,
})
}
fn bind_ppi_pg(
&self,
attach: &mut Attach,
data: &Data,
config: &PPIModuleConfig,
) -> Result<()> {
let (vbo, ebo, len) = self.ppi_program.bake(data, &config.to_ppi_config())?;
attach.bind_data(&vbo, ebo.as_ref(), len);
Ok(())
}
fn bind_line_pg(
&self,
attach: &mut Attach,
data: &Data,
config: &PPIModuleConfig,
) -> Result<()> {
let config = config.to_line_config();
// Create the path
let mut path = Path::new(true);
// Will be changed in the future
let outskirt = 10.0;
for seg in 0..500 {
let angle = 2f32 * f32::consts::PI / 500.0 * seg as f32;
let x = (angle.cos() * outskirt) as f32;
let y = (angle.sin() * outskirt) as f32;
path.push([x, y, 0.0]);
}
path.finish();
let (vbo, ebo, len) = self.line_program.bake(&vec![path], &config)?;
attach.bind_data(&vbo, ebo.as_ref(), len);
Ok(())
}
fn bind_tick(&self, attach: &mut Attach, data: &Data, config: &PPIModuleConfig) -> Result<()> {
let font_style = config.to_font_config();
match font_style {
FontConfig::Textline(line_style, font_style) => {
let new_text = TextLine::new("ABC", Some(font_style), None);
let position_text =
PositionText::new(new_text, [0.0, 0.0, 0.0], font::Anchor::BottomCenter);
let text_pg_config = config.to_font_config();
let (vbo, ebo, len) = self.text_program.bake(&position_text, &text_pg_config)?;
attach.bind_data(&vbo, ebo.as_ref(), len);
}
}
Ok(())
}
}
impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> {
type Cursor = PPIPackage<'a>;
type Data = Data;
type Operation = Trackball;
fn render<'dt>(
&mut self,
cursor: &mut Self::Cursor,
operation: &Operation<Self::Operation>,
viewport: &ViewPort,
) -> Result<()> {
// Mount PPI Program
self.ppi_program.mount(&self.gl)?;
// Deal with the operation
operation.attach_with_program(&self.gl, self.ppi_program.program());
// PPI Program
let ppi_attach = &mut cursor.ppi_attach;
let data = &cursor.ppi_data.borrow();
let config = &mut cursor.ppi_config;
// Update the config
self.ppi_program
.set_config(&self.gl, &config.to_ppi_config())?;
// if the layer is changed, we need to rebind the data
if config.changed_layer() {
self.bind_ppi_pg(ppi_attach, data, config);
}
// PPI Draw
ppi_attach.bind_self();
self.ppi_program.draw(&self.gl, ppi_attach.len())?;
ppi_attach.unbind_self();
// Unmount PPI Program
self.ppi_program.unmount(&self.gl)?;
// Mount Line Program
self.line_program.mount(&self.gl)?;
// Deal with the operation
operation.attach_with_program(&self.gl, self.line_program.program());
// Set the viewport, this is important
self.line_program.set_viewport(&self.gl, viewport.size());
// Update the config
self.line_program
.set_config(&self.gl, &config.to_line_config());
// PPI Tick Draw
let attach = &mut cursor.line_attach;
attach.bind_self();
self.line_program.draw(&self.gl, attach.len())?;
attach.unbind_self();
self.line_program.unmount(&self.gl)?;
self.text_program.mount(&self.gl);
let tick_attach = &mut cursor.tick_attach;
// Deal with the operation
operation.attach_with_program(&self.gl, self.text_program.program_mut());
self.text_program.set_viewport(viewport.size());
self.text_program
.set_config(&self.gl, &config.to_font_config());
tick_attach.bind_self();
self.text_program.draw(&self.gl, tick_attach.len())?;
tick_attach.unbind_self();
config.reset();
Ok(())
}
fn load_data<'dt>(&self, data: &CachedData<Self::Data>) -> Result<Self::Cursor> {
let _data = data.borrow();
// Check if the data is valid
if _data.blocks.len() == 0 {
return Err(Error::InvalidDataType);
}
// Init the memory
let (vao, vbo, ebo) = self.ppi_program.init(&self.gl);
let mut ppi_attach = Attach::new(&self.gl, vao, vbo, ebo, None);
// Get the data info
let (r, a, t, max_layer, unvalid) = self.ppi_program.data_info(&_data)?;
// Find the color map
let cmap = SETTING.find(&t);
// Check if the color map is valid
if cmap.is_none() {
return Err(Error::InvalidDataType);
}
let cmap = cmap.unwrap();
// Init the memory for the line program
let (vao, vbo, ebo) = self.line_program.init(&self.gl);
let mut line_attach = Attach::new(&self.gl, vao, vbo, ebo, None);
// Tick Label
let (vao, vbo, ebo) = self.text_program.init(&self.gl);
let mut tick_attach = Attach::new(&self.gl, vao, vbo, ebo, None);
let mut config = PPIModuleConfig::default();
config.rdpi = r;
config.adpi = a;
config.max_layer = max_layer;
config.unvalid_value = unvalid;
config.colors = cmap.color()?;
config.color_range = cmap.value_range();
// Bind the data
self.bind_ppi_pg(&mut ppi_attach, &data.borrow(), &config);
self.bind_line_pg(&mut line_attach, &data.borrow(), &config);
self.bind_tick(&mut tick_attach, &data.borrow(), &config);
Ok(PPIPackage::new(
config,
ppi_attach,
line_attach,
tick_attach,
data,
))
}
}
pub struct PPIPackage<'gl> {
draw_helper: bool,
ppi_config: PPIModuleConfig,
ppi_attach: Attach<'gl>,
line_attach: Attach<'gl>,
tick_attach: Attach<'gl>,
ppi_data: CachedData<Data>,
}
impl<'gl> PPIPackage<'gl> {
fn new(
ppi_config: PPIModuleConfig,
ppi_attach: Attach<'gl>,
line_attach: Attach<'gl>,
tick_attach: Attach<'gl>,
data: &CachedData<Data>,
) -> Self {
Self {
draw_helper: true,
ppi_config,
ppi_attach,
line_attach,
tick_attach,
ppi_data: Rc::clone(data),
}
}
}
impl<'gl> ModuleCursor for PPIPackage<'gl> {
type Module = PPIModule<'gl, 'gl>;
type Data = Data;
type Config = PPIModuleConfig;
fn set_config<F>(&mut self, f: F)
where
F: FnOnce(&mut Self::Config),
{
f(&mut self.ppi_config);
}
fn ui_build(&mut self, ui: &imgui::Ui) -> bool {
let mut layer = self.ppi_config.layer;
let mut is_three_d = self.ppi_config.is_three_d;
ui.text("PPI Data Config");
ui.slider("Layer", 0, self.ppi_config.max_layer - 1, &mut layer);
ui.checkbox("three d?", &mut is_three_d);
ui.separator();
let mut line_width = self.ppi_config.line_width;
let mut line_antialias = self.ppi_config.line_antialias;
ui.text("PPI Line Config");
ui.slider("line width", 0.1, 10.0, &mut line_width);
ui.slider("line ana", 0.1, 10.0, &mut line_antialias);
self.ppi_config.set_layer(layer);
self.ppi_config.set_is_three_d(is_three_d);
self.ppi_config.set_line_width(line_width);
self.ppi_config.set_line_antialias(line_antialias);
self.ppi_config.changed_any()
}
fn helper_layer(&self, canvas: &mut femtovg::Canvas<femtovg::renderer::OpenGl>) -> bool {
colorbar(canvas, &self.ppi_config.colors, &vec![]);
true
}
}
#[track]
#[derive(PartialEq)]
pub struct PPIModuleConfig {
pub ticks: bool,
pub line_color: [f32; 4],
pub line_width: f32,
pub line_antialias: f32,
pub layer: usize,
pub colors: Vec<[u8; 4]>,
pub color_range: [f32; 2],
pub is_three_d: bool,
pub tick_label_color: [f32; 4],
pub tick_label_size: f32,
#[do_not_track]
pub unvalid_value: f32,
#[do_not_track]
pub max_layer: usize,
#[do_not_track]
pub rdpi: f32,
#[do_not_track]
pub adpi: f32,
}
impl Default for PPIModuleConfig {
fn default() -> Self {
Self {
ticks: true,
line_color: [1.0, 1.0, 1.0, 1.0],
line_width: 2.0,
line_antialias: 2.0,
layer: 0,
colors: vec![],
color_range: [0.0, 0.0],
is_three_d: true,
unvalid_value: 0.0,
tick_label_color: [1.0, 1.0, 1.0, 1.0],
tick_label_size: 24.0,
max_layer: 0,
rdpi: 0.0,
adpi: 0.0,
tracker: 0,
}
}
}
impl PPIModuleConfig {
fn to_ppi_config(&self) -> PPIConfig {
PPIConfig {
unvalid_value: self.unvalid_value,
color_range: self.color_range,
colors: self.colors.clone(),
layer: self.layer,
rdpi: self.rdpi,
adpi: self.adpi,
three_d: self.is_three_d,
}
}
fn to_line_config(&self) -> AggFastPathConfig {
AggFastPathConfig {
color: self.line_color,
linewidth: self.line_width,
antialias: self.line_antialias,
}
}
fn to_font_config(&self) -> FontConfig {
let line_style = LineStyle::default();
let mut font_style = FontStyle::default();
font_style.size = FontSize::Absolute(self.tick_label_size);
font_style.color = self.tick_label_color;
FontConfig::Textline(line_style, font_style)
}
}