This commit is contained in:
Tsuki 2024-08-21 00:03:35 +08:00
parent 4204f444d6
commit 480888e8fc
15 changed files with 852 additions and 292 deletions

1
Cargo.lock generated
View File

@ -1182,6 +1182,7 @@ dependencies = [
"cfg-if", "cfg-if",
"chlorine", "chlorine",
"mint", "mint",
"pkg-config",
] ]
[[package]] [[package]]

View File

@ -22,7 +22,7 @@ glow = "0.13.1"
glutin = "0.31.3" glutin = "0.31.3"
glutin-winit = "0.4.2" glutin-winit = "0.4.2"
image = "0.25.2" image = "0.25.2"
imgui = {version="0.12.0",features = ["tables-api"]} imgui = {version="0.12.0",features = ["tables-api", "freetype"]}
imgui-glow-renderer = "0.12.0" imgui-glow-renderer = "0.12.0"
imgui-winit-support = "0.12.0" imgui-winit-support = "0.12.0"
include_dir = "0.7.4" include_dir = "0.7.4"

View File

@ -8,77 +8,42 @@ use crate::errors::*;
use crate::graphics::transforms::viewport::Viewport; use crate::graphics::transforms::viewport::Viewport;
use crate::graphics::ty::Ty; use crate::graphics::ty::Ty;
use crate::graphics::{AttaWithBuffer, Config, Graphics}; use crate::graphics::{AttaWithBuffer, Config, Graphics};
use crate::shaders::agg_path::{AggPathFragment, AggPathVertex};
use super::Colletion; use super::Colletion;
pub struct AggFastPath { pub struct AggFastPath {
program: Program, program: Program,
buffer: Vec<Point>, }
indice: Vec<[u32; 3]>,
vao: Option<NativeVertexArray>, pub struct AggFastPathConfig {
vbo: Option<NativeBuffer>, pub color: [f32; 4],
ebo: Option<NativeBuffer>, pub linewidth: f32,
pub antialias: f32,
} }
impl AggFastPath { impl AggFastPath {
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
let vertex = Shader::new( let vertex = Shader::new(
glow::VERTEX_SHADER, glow::VERTEX_SHADER,
CodeType::from_path("agg-fast-path.vert"), CodeType::from_piece(AggPathVertex::new()),
)?; )?;
let fragment = Shader::new( let fragment = Shader::new(
glow::FRAGMENT_SHADER, glow::FRAGMENT_SHADER,
CodeType::from_path("agg-fast-path.frag"), CodeType::from_piece(AggPathFragment::new()),
)?; )?;
let input_snippet = Snippet::new(
"input",
CodeType::from_code(
"
layout(location = 0) in vec3 prev;
layout(location = 1) in vec3 curr;
layout(location = 2) in vec3 next;
layout(location = 3) in float id;
uniform float linewidth;
uniform float antialias;
uniform vec4 color;
",
),
false,
None,
)?;
let vertex = vertex.add_snippet_before(input_snippet);
let program = Program::new(vertex, fragment, None, "330 core"); let program = Program::new(vertex, fragment, None, "330 core");
// program.set_transform(transform); Ok(Self { program })
// program.set_viewport(viewport);
Ok(Self {
program,
buffer: Vec::with_capacity(128),
indice: Vec::with_capacity(128 * 2),
ebo: None,
vao: None,
vbo: None,
})
} }
#[cfg(feature = "inparser")] pub fn set_viewport(&mut self, gl: &glow::Context, viewport: [f32; 2]) {
pub fn set_transform<T: Transform>(&mut self, transform: &T) { let loc = self.program.get_uniform_location(gl, "viewport");
self.program.set_transform(transform); unsafe {
} gl.uniform_2_f32(loc.as_ref(), viewport[0], viewport[1]);
}
#[cfg(feature = "inparser")]
pub fn set_viewport(&mut self, viewport: &Viewport) {
self.program.set_viewport(viewport);
} }
pub fn set_linecolor(&mut self, gl: &glow::Context, color: [f32; 4]) { pub fn set_linecolor(&mut self, gl: &glow::Context, color: [f32; 4]) {
@ -89,7 +54,7 @@ impl AggFastPath {
} }
pub fn set_linewidth(&mut self, gl: &glow::Context, linewidth: f32) { pub fn set_linewidth(&mut self, gl: &glow::Context, linewidth: f32) {
let loc = self.program.get_uniform_location(gl, "linewidth"); let loc = self.program.get_uniform_location(gl, "thickness");
unsafe { unsafe {
gl.uniform_1_f32(loc.as_ref(), linewidth); gl.uniform_1_f32(loc.as_ref(), linewidth);
} }
@ -102,6 +67,12 @@ impl AggFastPath {
} }
} }
pub fn set_config(&mut self, gl: &glow::Context, config: &AggFastPathConfig) {
self.set_linecolor(gl, config.color);
self.set_linewidth(gl, config.linewidth);
self.set_anatialias(gl, config.antialias);
}
pub fn program(&mut self) -> &mut Program { pub fn program(&mut self) -> &mut Program {
&mut self.program &mut self.program
} }
@ -109,102 +80,24 @@ impl AggFastPath {
pub fn program_ref(&self) -> &Program { pub fn program_ref(&self) -> &Program {
&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 {
type Item = Path;
fn append(&mut self, item: Self::Item) {
self.buffer.extend(item.points);
self.indice.extend(item.ebo);
}
} }
impl Graphics for AggFastPath { impl Graphics for AggFastPath {
const id: &'static str = "AggPath"; const id: &'static str = "AggPath";
type Config = (); type Config = AggFastPathConfig;
fn compile(&mut self, gl: &glow::Context) -> Result<()> { fn compile(&mut self, gl: &glow::Context) -> Result<()> {
use bytemuck::cast_slice; self.program.compile(gl)
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));
gl.buffer_data_u8_slice(
glow::ARRAY_BUFFER,
cast_slice(&self.buffer),
glow::STATIC_DRAW,
);
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 40, 0);
gl.enable_vertex_attrib_array(1);
gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, 40, 12);
gl.enable_vertex_attrib_array(2);
gl.vertex_attrib_pointer_f32(2, 3, glow::FLOAT, false, 40, 24);
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);
}
Ok(())
} }
fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> {
unsafe { unsafe {
gl.bind_vertex_array(Some(self.vao.unwrap())); gl.draw_elements(glow::TRIANGLES, count, glow::UNSIGNED_INT, 0);
gl.draw_elements(
glow::TRIANGLES,
(self.indice.len() * 3) as i32,
glow::UNSIGNED_INT,
0,
);
gl.bind_vertex_array(None);
} }
Ok(()) Ok(())
} }
fn destroy(&mut self, gl: &glow::Context) -> Result<()> { fn destroy(&mut self, gl: &glow::Context) -> Result<()> {
self.program.destroy(gl); 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(()) Ok(())
} }
@ -223,7 +116,6 @@ impl Graphics for AggFastPath {
fn mount(&mut self, gl: &glow::Context) -> Result<()> { fn mount(&mut self, gl: &glow::Context) -> Result<()> {
unsafe { unsafe {
gl.use_program(self.program.native_program); gl.use_program(self.program.native_program);
self.init(gl);
} }
Ok(()) Ok(())
} }
@ -237,18 +129,57 @@ impl Graphics for AggFastPath {
} }
impl AttaWithBuffer for AggFastPath { impl AttaWithBuffer for AggFastPath {
type Data = (); type Data = Vec<Path>;
fn bake( fn bake(
&self, &self,
data: &Self::Data, data: &Self::Data,
config: &<Self as Graphics>::Config, config: &<Self as Graphics>::Config,
) -> Result<(Vec<f32>, Option<Vec<u32>>, i32)> { ) -> Result<(Vec<f32>, Option<Vec<u32>>, i32)> {
Ok((vec![], None, 0)) let points = data.iter().map(|v| &v.points).flatten().collect::<Vec<_>>();
let mut vbo = Vec::with_capacity(points.len() * 10);
for p in points {
vbo.extend_from_slice(&[
p.prev[0], p.prev[1], p.prev[2], p.curr[0], p.curr[1], p.curr[2], p.next[0],
p.next[1], p.next[2], p.id,
]);
}
let mut ebo = vec![];
for e in data.iter().map(|v| &v.ebo).flatten() {
ebo.extend_from_slice(e);
}
let len = ebo.len() as i32;
Ok((vbo, Some(ebo), len))
} }
fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option<NativeBuffer>) { fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option<NativeBuffer>) {
(self.vao.unwrap(), self.vbo.unwrap(), self.ebo) 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, 40, 0);
gl.enable_vertex_attrib_array(1);
gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, 40, 12);
gl.enable_vertex_attrib_array(2);
gl.vertex_attrib_pointer_f32(2, 3, glow::FLOAT, false, 40, 24);
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.bind_vertex_array(None);
gl.bind_buffer(glow::ARRAY_BUFFER, None);
(vao, vbo, Some(ebo))
}
} }
} }
#[repr(C)] #[repr(C)]
@ -269,6 +200,11 @@ impl std::fmt::Display for Point {
) )
} }
} }
impl Point {
fn f32_slice(&self) -> &[f32] {
unsafe { std::slice::from_raw_parts(self as *const Self as *const f32, 13) }
}
}
impl Ty for Point {} impl Ty for Point {}

View File

@ -2,14 +2,15 @@ mod esdt;
use esdt::{Image2d, Unorm8}; use esdt::{Image2d, Unorm8};
use glow::{HasContext, TEXTURE_2D}; use glow::{HasContext, TEXTURE_2D};
use std::{cell::RefCell, collections::HashMap}; use std::{cell::RefCell, collections::HashMap};
use text_items::{LineStyle, Text as TextTrait}; use text_items::Text as TextTrait;
mod text_items; mod text_items;
pub use text_items::{Anchor, PositionText, TextLine}; pub use text_items::{Anchor, LineStyle, PositionText, TextLine};
use crate::{ use crate::{
components::{CodeType, Program, Shader}, components::{CodeType, Program, Shader},
errors::*, errors::*,
font_manager::{FontManager, FontStyle}, font_manager::{FontManager, FontStyle},
shaders::font::{FontFragment, FontGeometry, FontVertex},
utils::resources::RcGlTexture, utils::resources::RcGlTexture,
}; };
@ -18,14 +19,12 @@ pub struct Text<'a> {
gl: &'a glow::Context, gl: &'a glow::Context,
font_manager: RefCell<FontManager>, font_manager: RefCell<FontManager>,
cache: RefCell<HashMap<String, Cache<'a>>>, cache: RefCell<HashMap<String, Cache<'a>>>,
items: Vec<PositionText>,
program: Program, program: Program,
} }
pub struct Cache<'a> { pub struct Cache<'a> {
gl: &'a glow::Context, gl: &'a glow::Context,
cache: HashMap<char, TextVType>, cache: HashMap<char, TextVType>,
// cache_tex: Vec<u8>,
width: usize, width: usize,
height: usize, height: usize,
last_pos: [usize; 2], last_pos: [usize; 2],
@ -115,14 +114,20 @@ impl<'a> Cache<'a> {
self.cache.insert( self.cache.insert(
c, c,
TextVType { TextVType {
// tex_coords: [
// x as f32,
// (y + height - 1) as f32,
// (x + width - 1) as f32,
// (y + height - 1) as f32,
// (x + width - 1) as f32,
// y as f32,
// x as f32,
// y as f32,
// ],
tex_coords: [ tex_coords: [
x as f32, x as f32,
(y + height - 1) as f32, (y + height - 1) as f32,
(x + width - 1) as f32, (x + width - 1) as f32,
(y + height - 1) as f32,
(x + width - 1) as f32,
y as f32,
x as f32,
y as f32, y as f32,
], ],
// tex_coords: [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0], // tex_coords: [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],
@ -146,34 +151,65 @@ impl<'a> Cache<'a> {
#[derive(Clone)] #[derive(Clone)]
pub struct TextVType { pub struct TextVType {
tex_coords: [f32; 8], tex_coords: [f32; 4],
}
impl TextVType {
fn left_top(&self) -> [f32; 2] {
[self.tex_coords[0], self.tex_coords[1]]
}
fn right_bottom(&self) -> [f32; 2] {
[self.tex_coords[2], self.tex_coords[3]]
}
} }
impl<'a> Text<'a> { impl<'a> Text<'a> {
pub fn new(gl: &'a glow::Context, font_manager: FontManager) -> Result<Self> { pub fn new(gl: &'a glow::Context, font_manager: FontManager) -> Result<Self> {
let vertex = Shader::new( let vertex = Shader::new(
glow::VERTEX_SHADER, glow::VERTEX_SHADER,
crate::components::CodeType::from_path("font.vert"), crate::components::CodeType::from_piece(FontVertex::new()),
)?; )?;
let fragment = Shader::new(glow::FRAGMENT_SHADER, CodeType::from_path("font.frag"))?; let geom = Shader::new(
glow::GEOMETRY_SHADER,
crate::components::CodeType::from_piece(FontGeometry::new()),
)?;
let mut program = Program::new(vertex, fragment, None, "330 core"); let fragment = Shader::new(
#[cfg(feature = "inparser")] glow::FRAGMENT_SHADER,
program.set_transform(&transform); CodeType::from_piece(FontFragment::new()),
)?;
let mut program = Program::new(vertex, fragment, Some(geom), "330 core");
Ok(Self { Ok(Self {
gl, gl,
font_manager: RefCell::new(font_manager), font_manager: RefCell::new(font_manager),
cache: RefCell::new(HashMap::new()), cache: RefCell::new(HashMap::new()),
items: Vec::new(),
program, program,
}) })
} }
#[cfg(feature = "inparser")] pub fn set_viewport(&self, viewport: [f32; 2]) {
pub fn set_viewport(&mut self, viewport: &Viewport) { let loc = self.program.get_uniform_location(&self.gl, "viewport");
self.program.set_viewport(viewport); unsafe {
self.gl
.uniform_2_f32(loc.as_ref(), viewport[0], viewport[1]);
}
}
pub fn set_config(&self, config: FontConfig) {
match config {
FontConfig::Textline(style, font) => {
let loc = self.program.get_uniform_location(&self.gl, "location");
let anchor = self.program.get_uniform_location(&self.gl, "anchor");
unsafe {
self.gl.uniform_3_f32(loc.as_ref(), 0.0, 0.0, 1.0);
self.gl.uniform_3_f32(anchor.as_ref(), 0.0, 0.0, 0.0);
}
}
}
} }
fn set_uniforms(&self) { fn set_uniforms(&self) {
@ -207,9 +243,6 @@ impl<'a> Graphics for Text<'a> {
fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> {
unsafe { unsafe {
gl.clear(glow::COLOR_BUFFER_BIT);
// gl.polygon_mode(glow::FRONT_AND_BACK, glow::LINE);
let loc = self.program.get_uniform_location(gl, "atlas_data"); let loc = self.program.get_uniform_location(gl, "atlas_data");
gl.uniform_1_i32(loc.as_ref(), 0); gl.uniform_1_i32(loc.as_ref(), 0);
@ -227,7 +260,7 @@ impl<'a> Graphics for Text<'a> {
self.set_uniforms(); self.set_uniforms();
gl.draw_elements(glow::TRIANGLES, count / 2 * 3, glow::UNSIGNED_INT, 0); gl.draw_arrays(glow::POINTS, 0, count);
} }
Ok(()) Ok(())
} }
@ -241,6 +274,16 @@ impl<'a> Graphics for Text<'a> {
} }
fn set_config(&mut self, gl: &glow::Context, config: &Self::Config) -> Result<()> { fn set_config(&mut self, gl: &glow::Context, config: &Self::Config) -> Result<()> {
unsafe {
match config {
FontConfig::Textline(style, font) => {
let loc = self.program.get_uniform_location(gl, "location");
let anchor = self.program.get_uniform_location(gl, "anchor");
gl.uniform_3_f32(loc.as_ref(), 0.0, 0.0, 2.0);
gl.uniform_3_f32(anchor.as_ref(), 0.0, 0.0, 0.0);
}
}
}
Ok(()) Ok(())
} }
} }
@ -259,19 +302,7 @@ impl<'a> AttaWithBuffer for Text<'a> {
&mut *self.cache.borrow_mut(), &mut *self.cache.borrow_mut(),
)?; )?;
let mut ebos = Vec::with_capacity(v.len() / 2 * 3); Ok((v.vertex(), None, v.len() as i32))
for i in 0..v.len() / 4 {
let i = i as u32;
ebos.push(i * 4);
ebos.push(i * 4 + 1);
ebos.push(i * 4 + 3);
ebos.push(i * 4 + 1);
ebos.push(i * 4 + 2);
ebos.push(i * 4 + 3);
}
Ok((v.vertex(), Some(ebos), v.len() as i32))
} }
fn init( fn init(
@ -288,17 +319,15 @@ impl<'a> AttaWithBuffer for Text<'a> {
let vbo = gl.create_buffer().unwrap(); let vbo = gl.create_buffer().unwrap();
gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
gl.enable_vertex_attrib_array(0); gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 20, 0); gl.vertex_attrib_pointer_f32(0, 4, glow::FLOAT, false, 32, 0);
gl.enable_vertex_attrib_array(1); gl.enable_vertex_attrib_array(1);
gl.vertex_attrib_pointer_f32(1, 2, glow::FLOAT, false, 20, 12); gl.vertex_attrib_pointer_f32(1, 4, glow::FLOAT, false, 32, 16);
let ebo = gl.create_buffer().unwrap();
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ebo));
gl.bind_vertex_array(None); gl.bind_vertex_array(None);
gl.bind_buffer(glow::ARRAY_BUFFER, None);
(vao, vbo, Some(ebo)) (vao, vbo, None)
} }
} }
} }

View File

@ -100,8 +100,8 @@ impl Default for TextAlign {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Zeroable, Pod)] #[derive(Clone, Copy, Zeroable, Pod)]
pub struct TextVertexItem { pub struct TextVertexItem {
position: [f32; 3], tex_coords: [f32; 4],
tex_coords: [f32; 2], position: [f32; 4],
} }
pub struct TextVertexArray { pub struct TextVertexArray {
@ -123,22 +123,25 @@ impl TextVertexArray {
self.points.push(item); self.points.push(item);
} }
pub fn insert_text(&mut self, tex_coords: TextVType, positions: [[f32; 3]; 4]) { pub fn insert_text(&mut self, tex_coords: TextVType, position: [f32; 2], size: [f32; 2]) {
for i in 0..4 { let tex_left_top = tex_coords.left_top();
self.push(TextVertexItem { let tex_right_bottom = tex_coords.right_bottom();
position: positions[i],
tex_coords: [ self.push(TextVertexItem {
tex_coords.tex_coords[i * 2], position: [position[0], position[1], size[0], size[1]],
tex_coords.tex_coords[i * 2 + 1], tex_coords: [
], tex_left_top[0],
}); tex_left_top[1],
} tex_right_bottom[0],
tex_right_bottom[1],
],
});
} }
pub fn vertex(&self) -> Vec<f32> { pub fn vertex(&self) -> Vec<f32> {
let mut result = Vec::with_capacity(self.len() * 6); let mut result = Vec::with_capacity(self.len() * 8);
self.points.iter().for_each(|v| { self.points.iter().for_each(|v| {
result.extend_from_slice(&v.position);
result.extend_from_slice(&v.tex_coords); result.extend_from_slice(&v.tex_coords);
result.extend_from_slice(&v.position);
}); });
result result
} }
@ -205,24 +208,25 @@ impl Text for TextLine {
}); });
let metrics = font.get_metrics(char); let metrics = font.get_metrics(char);
let bear_x = metrics.horiBearingX; let width = (metrics.width >> 6) as f32;
let bear_y = metrics.horiBearingY; let height = (metrics.height >> 6) as f32;
let bear_x = (metrics.horiBearingX >> 6) as f32;
let bear_y = (metrics.horiBearingY >> 6) as f32;
let x0 = pen[0] + bear_x as f32 + x_kerning; let x0 = pen[0] + bear_x as f32 + x_kerning;
let y0 = pen[1] - bear_y as f32; let y0 = pen[1] - bear_y as f32;
let x1 = pen[0] + metrics.width as f32 + x_kerning; let x1 = pen[0] + metrics.width as f32 + x_kerning;
let y1 = pen[1] + metrics.height as f32; let y1 = pen[1] + metrics.height as f32;
let position = [[x0, y0, 0.0], [x1, y0, 0.0], [x1, y1, 0.0], [x1, y0, 0.0]];
if let Some(cache) = cache.get(char) { if let Some(cache) = cache.get(char) {
baked.insert_text(cache.to_owned(), position); baked.insert_text(cache.to_owned(), [x0, y0], [width, height]);
} else { } else {
let char_glyph = font.get_char(char, 64)?; let char_glyph = font.get_char(char, 64)?;
let mut img = char_glyph.into(); let mut img = char_glyph.into();
let (result, _) = glyph_to_sdf(&mut img, SDF_PARAM, None); let (result, _) = glyph_to_sdf(&mut img, SDF_PARAM, None);
let b = cache.insert_glyph(result, char); let b = cache.insert_glyph(result, char);
baked.insert_text(b.to_owned(), position); baked.insert_text(b.to_owned(), [x0, y0], [width, height]);
} }
pen[0] += x_advanced; pen[0] += x_advanced;

View File

@ -203,7 +203,7 @@ impl AttaWithBuffer for PPI {
vertices.extend([r, *azi, *ele, *dt]); vertices.extend([r, *azi, *ele, *dt]);
} }
} }
let len = vertices.len() as i32 / 3; let len = vertices.len() as i32 / 4;
return Ok((vertices, None, len)); return Ok((vertices, None, len));
} else { } else {
return Err(Error::InvalidDataType); return Err(Error::InvalidDataType);
@ -219,6 +219,7 @@ impl AttaWithBuffer for PPI {
gl.enable_vertex_attrib_array(0); gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer_f32(0, 4, glow::FLOAT, false, 16, 0); gl.vertex_attrib_pointer_f32(0, 4, glow::FLOAT, false, 16, 0);
gl.bind_vertex_array(None); gl.bind_vertex_array(None);
gl.bind_buffer(glow::ARRAY_BUFFER, None);
(vao, vbo, None) (vao, vbo, None)
} }

View File

@ -86,6 +86,10 @@ impl<T: Resource> ViewPort<T> {
pub fn fbo(&self) -> &RcGlRcFramebuffer { pub fn fbo(&self) -> &RcGlRcFramebuffer {
&self.main_fbo &self.main_fbo
} }
pub fn size(&self) -> [f32; 2] {
self.renderer_size
}
} }
impl ViewPort<NativeTexture> { impl ViewPort<NativeTexture> {

View File

@ -2,13 +2,16 @@ mod app;
use femtovg::renderer::OpenGl; use femtovg::renderer::OpenGl;
use femtovg::Canvas; use femtovg::Canvas;
use glow::HasContext; use glow::HasContext;
use layout_type::ViewPort;
pub mod layout_type; pub mod layout_type;
mod modules; mod modules;
use crate::font_manager::FontManager; use crate::font_manager::FontManager;
use crate::graphics::collections::agg_fast_path::AggFastPath;
use crate::graphics::font::Text; use crate::graphics::font::Text;
use crate::graphics::ppi::PPI; use crate::graphics::ppi::PPI;
use crate::graphics::threed::Trackball; use crate::graphics::threed::Trackball;
use crate::graphics::transforms::viewport;
use crate::graphics::{AttaWithProgram, AttachWithMouse}; use crate::graphics::{AttaWithProgram, AttachWithMouse};
use crate::ui::operation::Operation; use crate::ui::operation::Operation;
use crate::ui::typ::LayoutAttach; use crate::ui::typ::LayoutAttach;
@ -25,6 +28,7 @@ pub(super) struct Programs<'gl> {
gl: &'gl GL, gl: &'gl GL,
_ppi: PPI, _ppi: PPI,
_text: Text<'gl>, _text: Text<'gl>,
_line: AggFastPath,
} }
impl<'gl> Programs<'gl> { impl<'gl> Programs<'gl> {
@ -35,21 +39,25 @@ impl<'gl> Programs<'gl> {
gl, gl,
_ppi: PPI::new()?, _ppi: PPI::new()?,
_text: Text::new(gl, font_manager)?, _text: Text::new(gl, font_manager)?,
_line: AggFastPath::new()?,
}) })
} }
pub fn prepare(&mut self) -> Result<()> { pub fn prepare(&mut self) -> Result<()> {
self._ppi.program().compile(&self.gl)?; self._ppi.program().compile(&self.gl)?;
self._line.program().compile(&self.gl)?;
self._text.program_mut().compile(&self.gl)?;
Ok(()) Ok(())
} }
pub fn ppi<'b>(&'b mut self) -> modules::PPIModule<'b, 'gl> { pub fn ppi<'b>(&'b mut self) -> modules::PPIModule<'b, 'gl> {
modules::PPIModule::new(&self.gl, &mut self._ppi, &mut self._text).unwrap() modules::PPIModule::new(&self.gl, &mut self._ppi, &mut self._text, &mut self._line).unwrap()
} }
pub fn destroy(&mut self) -> Result<()> { pub fn destroy(&mut self) -> Result<()> {
self._ppi.destroy(&self.gl)?; self._ppi.destroy(&self.gl)?;
self._text.destroy(&self.gl)?; self._text.destroy(&self.gl)?;
self._line.destroy(&self.gl)?;
Ok(()) Ok(())
} }
@ -78,12 +86,11 @@ impl<'gl> Programs<'gl> {
&mut self, &mut self,
modules: &mut ModulePackage<'gl>, modules: &mut ModulePackage<'gl>,
operation: &Operation<Trackball>, operation: &Operation<Trackball>,
viewport: &ViewPort,
) -> Result<()> { ) -> Result<()> {
match &mut modules.modules { match &mut modules.modules {
_ModulePackage::PPI(ppi) => { _ModulePackage::PPI(ppi) => {
self.ppi().start(); self.ppi().render(ppi, operation, viewport)?;
self.ppi().render(ppi, operation)?;
self.ppi().end();
} }
} }
modules.need_update = false; modules.need_update = false;

View File

@ -15,7 +15,7 @@ mod ppi;
use crate::errors::*; use crate::errors::*;
pub use ppi::{PPIModule, PPIPackage}; pub use ppi::{PPIModule, PPIPackage};
use super::Data; use super::{layout_type::ViewPort, Data};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Attach<'a> { struct Attach<'a> {
@ -43,23 +43,43 @@ impl<'a> Attach<'a> {
} }
} }
fn bind_self(&self) {
self.vao.bind(glow::VERTEX_ARRAY);
self.vbo.bind(glow::ARRAY_BUFFER);
if let Some(ebo) = self.ebo.as_ref() {
ebo.bind(glow::ELEMENT_ARRAY_BUFFER);
}
}
fn unbind_self(&self) {
self.vao.unbind(glow::VERTEX_ARRAY);
self.vbo.unbind(glow::ARRAY_BUFFER);
if let Some(ebo) = self.ebo.as_ref() {
ebo.unbind(glow::ELEMENT_ARRAY_BUFFER);
}
}
fn bind_data(&mut self, vbo: &Vec<f32>, ebo: Option<&Vec<u32>>, len: i32) { fn bind_data(&mut self, vbo: &Vec<f32>, ebo: Option<&Vec<u32>>, len: i32) {
use bytemuck::cast_slice; use bytemuck::cast_slice;
self.vao.bind(glow::VERTEX_ARRAY); self.vbo.bind(glow::ARRAY_BUFFER);
unsafe { unsafe {
self.gl self.gl
.buffer_data_u8_slice(glow::ARRAY_BUFFER, cast_slice(&vbo), glow::STATIC_DRAW); .buffer_data_u8_slice(glow::ARRAY_BUFFER, cast_slice(&vbo), glow::STATIC_DRAW);
if let Some(ebo) = ebo { if let Some(ebo) = ebo {
self.ebo.as_ref().unwrap().bind(glow::ELEMENT_ARRAY_BUFFER); self.gl.bind_buffer(
glow::ELEMENT_ARRAY_BUFFER,
Some(self.ebo.as_ref().unwrap().native()),
);
self.gl.buffer_data_u8_slice( self.gl.buffer_data_u8_slice(
glow::ELEMENT_ARRAY_BUFFER, glow::ELEMENT_ARRAY_BUFFER,
cast_slice(&ebo), cast_slice(&ebo),
glow::STATIC_DRAW, glow::STATIC_DRAW,
); );
self.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, None);
} }
} }
self.vbo.unbind(glow::ARRAY_BUFFER);
self.vao.unbind(glow::VERTEX_ARRAY);
self.len = len; self.len = len;
} }
@ -77,13 +97,9 @@ pub trait Module: Sized {
&mut self, &mut self,
cursor: &mut Self::Cursor, cursor: &mut Self::Cursor,
operation: &Operation<Self::Operation>, operation: &Operation<Self::Operation>,
viewport: &ViewPort,
) -> Result<()>; ) -> Result<()>;
fn resize(&self, size: [f32; 2]);
fn destroy(&self);
fn start(&mut self);
// fn init(&mut self, info: &Operation<Self::Operation>) -> Result<()>;
fn end(&mut self);
fn load_data<'dt>(&self, data: &CachedData<Self::Data>) -> Result<Self::Cursor>; fn load_data<'dt>(&self, data: &CachedData<Self::Data>) -> Result<Self::Cursor>;
} }

View File

@ -1,7 +1,14 @@
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 std::rc::Rc;
use tracker::track; use tracker::track;
use transforms::viewport;
use crate::font_manager::{FontSize, FontStyle};
use crate::graphics::{font::Text, *}; use crate::graphics::{font::Text, *};
use crate::pg::layout_type::ViewPort;
use crate::ui::helper_components::colorbar::colorbar; use crate::ui::helper_components::colorbar::colorbar;
use crate::ui::operation::{self, Operation}; use crate::ui::operation::{self, Operation};
use crate::SETTING; use crate::SETTING;
@ -20,35 +27,81 @@ use super::{Attach, Module, ModuleCursor};
pub struct PPIModule<'b, 'a: 'b> { pub struct PPIModule<'b, 'a: 'b> {
gl: &'a glow::Context, gl: &'a glow::Context,
ppi_program: &'b mut PPI, ppi_program: &'b mut PPI,
line_program: &'b mut AggFastPath,
text_program: &'b mut Text<'a>, text_program: &'b mut Text<'a>,
} }
impl<'b, 'a: 'b> PPIModule<'b, 'a> { impl<'b, 'a: 'b> PPIModule<'b, 'a> {
pub fn new(gl: &'a glow::Context, ppi: &'b mut PPI, text: &'b mut Text<'a>) -> Result<Self> { 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(); let config = PPIConfig::default();
Ok(Self { Ok(Self {
gl, gl,
ppi_program: ppi, ppi_program: ppi,
text_program: text, text_program: text,
line_program: line,
}) })
} }
fn rebind(&self, attach: &mut Attach, data: &Data, config: &PPIModuleConfig) -> Result<()> { fn bind_ppi_pg(
let (vbo, ebo, len) = self.ppi_program.bake( &self,
data, attach: &mut Attach,
&PPIConfig { data: &Data,
unvalid_value: config.unvalid_value, config: &PPIModuleConfig,
color_range: config.color_range, ) -> Result<()> {
colors: config.colors.clone(), let (vbo, ebo, len) = self.ppi_program.bake(data, &config.to_ppi_config())?;
layer: config.layer,
rdpi: config.rdpi,
adpi: config.adpi,
three_d: config.is_three_d,
},
)?;
attach.bind_data(&vbo, ebo.as_ref(), len); attach.bind_data(&vbo, ebo.as_ref(), len);
Ok(()) 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> { impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> {
@ -56,116 +109,155 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> {
type Data = Data; type Data = Data;
type Operation = Trackball; type Operation = Trackball;
fn start(&mut self) {
self.ppi_program.mount(&self.gl).unwrap();
}
fn end(&mut self) {
self.ppi_program.unmount(&self.gl).unwrap();
}
fn render<'dt>( fn render<'dt>(
&mut self, &mut self,
cursor: &mut Self::Cursor, cursor: &mut Self::Cursor,
operation: &Operation<Self::Operation>, operation: &Operation<Self::Operation>,
viewport: &ViewPort,
) -> Result<()> { ) -> Result<()> {
// Mount PPI Program
self.ppi_program.mount(&self.gl)?;
// Deal with the operation
operation.attach_with_program(&self.gl, self.ppi_program.program()); operation.attach_with_program(&self.gl, self.ppi_program.program());
let attach = &mut cursor.ppi_attach; // PPI Program
let ppi_attach = &mut cursor.ppi_attach;
let data = &cursor.ppi_data.borrow(); let data = &cursor.ppi_data.borrow();
let config = &mut cursor.ppi_config; let config = &mut cursor.ppi_config;
self.ppi_program.set_config( // Update the config
&self.gl, self.ppi_program
&PPIConfig { .set_config(&self.gl, &config.to_ppi_config())?;
unvalid_value: config.unvalid_value,
color_range: config.color_range,
colors: config.colors.clone(),
layer: config.layer,
rdpi: config.rdpi,
adpi: config.adpi,
three_d: config.is_three_d,
},
)?;
// if the layer is changed, we need to rebind the data
if config.changed_layer() { if config.changed_layer() {
self.rebind(attach, data, config); self.bind_ppi_pg(ppi_attach, data, config);
config.reset();
} }
attach.vao.bind(glow::VERTEX_ARRAY);
self.ppi_program.draw(&self.gl, attach.len())?; // PPI Draw
attach.vao.unbind(glow::VERTEX_ARRAY); 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(()) Ok(())
} }
fn resize(&self, size: [f32; 2]) {}
fn destroy(&self) {}
fn load_data<'dt>(&self, data: &CachedData<Self::Data>) -> Result<Self::Cursor> { fn load_data<'dt>(&self, data: &CachedData<Self::Data>) -> Result<Self::Cursor> {
let _data = data.borrow(); let _data = data.borrow();
// Check if the data is valid
if _data.blocks.len() == 0 { if _data.blocks.len() == 0 {
return Err(Error::InvalidDataType); return Err(Error::InvalidDataType);
} }
// Init the memory
let (vao, vbo, ebo) = self.ppi_program.init(&self.gl); let (vao, vbo, ebo) = self.ppi_program.init(&self.gl);
let mut attach = Attach::new(&self.gl, vao, vbo, ebo, None); 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)?; let (r, a, t, max_layer, unvalid) = self.ppi_program.data_info(&_data)?;
// Find the color map
let cmap = SETTING.find(&t); let cmap = SETTING.find(&t);
// Check if the color map is valid
if cmap.is_none() { if cmap.is_none() {
return Err(Error::InvalidDataType); return Err(Error::InvalidDataType);
} }
let cmap = cmap.unwrap(); let cmap = cmap.unwrap();
let config = PPIModuleConfig { // Init the memory for the line program
color_range: cmap.value_range(), let (vao, vbo, ebo) = self.line_program.init(&self.gl);
colors: cmap.color()?, let mut line_attach = Attach::new(&self.gl, vao, vbo, ebo, None);
layer: 0,
rdpi: r,
adpi: a,
max_layer,
unvalid_value: unvalid,
is_three_d: true,
tracker: 0,
};
self.rebind(&mut attach, &data.borrow(), &config); // Tick Label
let (vao, vbo, ebo) = self.text_program.init(&self.gl);
let mut tick_attach = Attach::new(&self.gl, vao, vbo, ebo, None);
Ok(PPIPackage::new(config, attach, data)) 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,
))
} }
} }
#[track]
#[derive(PartialEq)]
pub struct PPIModuleConfig {
pub layer: usize,
pub colors: Vec<[u8; 4]>,
pub color_range: [f32; 2],
pub is_three_d: bool,
#[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,
}
pub struct PPIPackage<'gl> { pub struct PPIPackage<'gl> {
draw_helper: bool, draw_helper: bool,
ppi_config: PPIModuleConfig, ppi_config: PPIModuleConfig,
ppi_attach: Attach<'gl>, ppi_attach: Attach<'gl>,
line_attach: Attach<'gl>,
tick_attach: Attach<'gl>,
ppi_data: CachedData<Data>, ppi_data: CachedData<Data>,
} }
impl<'gl> PPIPackage<'gl> { impl<'gl> PPIPackage<'gl> {
fn new(ppi_config: PPIModuleConfig, ppi_attach: Attach<'gl>, data: &CachedData<Data>) -> Self { fn new(
ppi_config: PPIModuleConfig,
ppi_attach: Attach<'gl>,
line_attach: Attach<'gl>,
tick_attach: Attach<'gl>,
data: &CachedData<Data>,
) -> Self {
Self { Self {
draw_helper: true, draw_helper: true,
ppi_config, ppi_config,
ppi_attach, ppi_attach,
line_attach,
tick_attach,
ppi_data: Rc::clone(data), ppi_data: Rc::clone(data),
} }
} }
@ -192,8 +284,17 @@ impl<'gl> ModuleCursor for PPIPackage<'gl> {
ui.checkbox("three d?", &mut is_three_d); ui.checkbox("three d?", &mut is_three_d);
ui.separator(); 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_layer(layer);
self.ppi_config.set_is_three_d(is_three_d); 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() self.ppi_config.changed_any()
} }
@ -202,3 +303,79 @@ impl<'gl> ModuleCursor for PPIPackage<'gl> {
true 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)
}
}

126
src/shaders/agg_path.rs Normal file
View File

@ -0,0 +1,126 @@
use glsl::syntax::ShaderStage;
use glsl::syntax::TranslationUnit;
use glsl::transpiler::glsl::show_translation_unit;
use glsl_quasiquote::glsl;
use crate::impl_code_piece;
use super::{trackball::Trackball, CodePiece};
pub struct AggPathVertex(ShaderStage);
pub struct AggPathFragment(ShaderStage);
impl AggPathVertex {
pub fn new() -> Self {
let mut transform = Trackball::new().0;
let raw = glsl! {
layout(location = 0) in vec3 prev;
layout(location = 1) in vec3 curr;
layout(location = 2) in vec3 next;
layout(location = 3) in float id;
uniform float antialias;
uniform float thickness;
uniform vec2 viewport;
uniform vec4 color;
out float v_distance;
out vec4 v_color;
void main() {
vec4 ndc_prev = transform(position(prev));
vec4 ndc_curr = transform(position(curr));
vec4 ndc_next = transform(position(next));
// screen space
vec2 screen_prev = viewport * ((ndc_prev.xy/ndc_prev.w) + 1.0)/2.0;
vec2 screen_curr = viewport * ((ndc_curr.xy/ndc_curr.w) + 1.0)/2.0;
vec2 screen_next = viewport * ((ndc_next.xy/ndc_next.w) + 1.0)/2.0;
vec2 P;
float w = thickness/2.0 + antialias;
if (prev.xy == curr.xy) {
vec2 v = normalize(screen_next.xy - screen_curr.xy);
vec2 normal = normalize(vec2(-v.y, v.x));
P = screen_curr.xy + w*normal*id;
} else if (curr.xy == next.xy) {
vec2 v = normalize(screen_curr.xy - screen_prev.xy);
vec2 normal = normalize(vec2(-v.y, v.x));
P = screen_curr.xy + w*normal*id;
} else {
vec2 v0 = normalize(screen_curr.xy - screen_prev.xy);
vec2 v1 = normalize(screen_next.xy - screen_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 = screen_curr.xy + l*miter*sign(id);
}
v_color = color;
if (abs(id) > 1.5) v_color.a = 0.0;
v_distance = w * id;
// Back to NDC coordinates
gl_Position = vec4(2.0*P/viewport-1.0, ndc_curr.z / ndc_curr.w, 1.0);
}
};
transform.extend(raw);
Self(transform)
}
}
impl AggPathFragment {
pub fn new() -> Self {
let raw = glsl! {
uniform float antialias;
uniform float thickness;
in float v_distance;
in vec4 v_color;
out vec4 fragColor;
vec4 stroke(float distance, float linewidth, float antialias, vec4 fg_color)
{
vec4 frag_color;
float t = linewidth/2.0 - antialias;
float signed_distance = distance;
float border_distance = abs(signed_distance) - t;
float alpha = border_distance/antialias;
alpha = exp(-alpha*alpha);
if( border_distance < 0.0 )
frag_color = fg_color;
else
frag_color = vec4(fg_color.rgb, fg_color.a * alpha);
return frag_color;
}
vec4 stroke(float distance, float linewidth, float antialias, vec4 fg_color, vec4 bg_color)
{
return stroke(distance, linewidth, antialias, fg_color);
}
void main() {
if (v_color.a == 0) {discard;}
fragColor = stroke(v_distance, thickness, antialias, v_color);
}
};
Self(raw)
}
}
impl_code_piece!(AggPathVertex, 0);
impl_code_piece!(AggPathFragment, 0);

216
src/shaders/font.rs Normal file
View File

@ -0,0 +1,216 @@
use super::trackball::Trackball;
use super::CodePiece;
use crate::impl_code_piece;
use glsl::syntax::ShaderStage;
use glsl::syntax::TranslationUnit;
use glsl::transpiler::glsl::show_translation_unit;
use glsl_quasiquote::glsl;
pub struct FontVertex(pub ShaderStage);
pub struct FontFragment(pub ShaderStage);
pub struct FontGeometry(pub ShaderStage);
impl FontVertex {
pub fn new() -> Self {
let raw = glsl! {
// texcoord (left top, right bottom)
layout(location = 0) in vec4 texcoord;
// Relative position (x, y, width, height)
layout(location = 1) in vec4 relative_position;
out VS_OUT {
vec4 texcoord;
vec4 pos;
} vs_out;
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
vs_out.texcoord = texcoord;
vs_out.pos = relative_position;
}
};
Self(raw)
}
}
impl FontGeometry {
pub fn new() -> Self {
let mut transform = Trackball::new().0;
let raw = glsl! {
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
// Uniforms
uniform vec3 location;
uniform vec3 anchor;
uniform vec2 viewport;
// Texture Shape
uniform vec2 atlas_shape;
out vec2 v_texCoord;
in VS_OUT {
vec4 texcoord;
vec4 pos;
} gs_in[];
void main() {
vec4 pos = gs_in[0].pos;
float x, y, width, hgt;
// Char position and size
x = pos.x;
y = pos.y;
width = pos.z;
hgt = pos.w;
// texcoord
vec2 tex_coord_lt = gs_in[0].texcoord.xy / atlas_shape;
vec2 tex_coord_rb = gs_in[0].texcoord.zw / atlas_shape;
// Char Size
vec2 size = vec2(width, hgt);
// Base Text Location
vec3 base_pos = location + anchor;
// base_pos in NDC
vec4 ndc_base_pos = transform(position(base_pos));
// Screen Space
vec2 screen_base_pos = viewport * ((ndc_base_pos.xy / ndc_base_pos.w) + 1.0) / 2.0;
// Billboard Type
vec2 left_top = screen_base_pos + vec2(x, y);
vec2 right_bottom = left_top + size;
vec2 ndc_left_top = (2.0 * left_top / viewport - 1.0);
vec2 ndc_right_bottom = (2.0 * right_bottom / viewport - 1.0);
// Emit vertices
gl_Position = vec4(ndc_left_top.x, ndc_right_bottom.y, ndc_base_pos.z / ndc_base_pos.w, 1.0);
v_texCoord = vec2(tex_coord_lt.x, tex_coord_lt.y);
EmitVertex();
gl_Position = vec4(ndc_right_bottom.xy, ndc_base_pos.z / ndc_base_pos.w, 1.0);
v_texCoord = tex_coord_rb;
EmitVertex();
gl_Position = vec4(ndc_left_top.xy, ndc_base_pos.z / ndc_base_pos.w, 1.0);
v_texCoord = tex_coord_lt;
EmitVertex();
gl_Position = vec4(ndc_right_bottom.x, ndc_left_top.y, ndc_base_pos.z / ndc_base_pos.w, 1.0);
v_texCoord = vec2(tex_coord_rb.x, tex_coord_lt.y);
EmitVertex();
EndPrimitive();
}
};
transform.extend(raw);
Self(transform)
}
}
impl FontFragment {
pub fn new() -> Self {
let raw = glsl! {
uniform sampler2D atlas_data;
in vec2 v_texCoord;
uniform vec4 uClipUV;
uniform vec4 uSdfConfig;
uniform int uMode;
uniform vec4 uBorder;
uniform vec4 uStroke;
uniform vec4 uFill;
float getUVScale(vec2 sdfUV) {
float dx = dFdx(sdfUV.x);
float dy = dFdy(sdfUV.y);
return (sqrt(dx * dx + dy * dy) + sqrt(dy * dy + dx * dx)) * 0.5;
}
struct SDF {
float outer;
float inner;
};
vec4 getTexture(vec2 uv) {
return texture(atlas_data, uv);
}
vec4 getMask(vec4 color, vec2 uv, vec2 st) {
return color; // 默认不修改颜色
}
out vec4 fragColor;
void main() {
vec4 fillColor = uFill;
vec4 strokeColor = uStroke;
float scale = getUVScale(v_texCoord);
vec4 texture = getTexture(v_texCoord);
float dis = texture.r;
if (dis<0.5) {
discard;
}else {
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
// float sdfRaw = 0.0;
// float mark = 0.0;
// float sdf;
// float sdfRadius = uSdfConfig.x;
// float expand = uBorder.x;
// float bleed = uBorder.y;
// float d = (texture.r - 0.75) * sdfRadius;
// float s = (d + expand / uSdfConfig.y) / scale + 0.5 + bleed;
// sdf = s; // Assuming SDF returns a single float, adjust as necessary
// if (uMode == -2) {
// fillColor = vec4(texture.rgb, fillColor.a);
// }
// // if (gl_FragCoord.x < uClipUV.x || gl_FragCoord.y < uClipUV.y || gl_FragCoord.x > uClipUV.z || gl_FragCoord.y > uClipUV.w) {
// // discard;
// // }
// // Compute mask based on SDF
// float mask = clamp(sdf, 0.0, 1.0);
// // Final color blending logic here
// if(mask < 0.5) {
// fragColor = vec4(0.0, 0.0, 0.0, 0.0);
// } else {
// fragColor = vec4(fillColor.rgb, 1.0);
// }
// fragColor = vec4(fillColor.rgb + mark, fillColor.a * mask + mark);
// fragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
};
Self(raw)
}
}
impl_code_piece!(FontVertex, 0);
impl_code_piece!(FontGeometry, 0);
impl_code_piece!(FontFragment, 0);

View File

@ -1,4 +1,6 @@
pub mod agg_path;
pub mod colormap; pub mod colormap;
pub mod font;
pub mod math; pub mod math;
pub mod polar; pub mod polar;
pub mod ppi; pub mod ppi;

View File

@ -21,6 +21,46 @@ impl Trackball {
* trackball_model * trackball_model
* position; * position;
} }
vec4 position(float x)
{
return vec4(x, 0.0, 0.0, 1.0);
}
vec4 position(float x, float y)
{
return vec4(x, y, 0.0, 1.0);
}
vec4 position(vec2 xy)
{
return vec4(xy, 0.0, 1.0);
}
vec4 position(float x, float y, float z)
{
return vec4(x, y, z, 1.0);
}
vec4 position(vec3 xyz)
{
return vec4(xyz, 1.0);
}
vec4 position(vec4 xyzw)
{
return xyzw;
}
vec4 position(vec2 xy, float z)
{
return vec4(xy, z, 1.0);
}
vec4 position(float x, vec2 yz)
{
return vec4(x, yz, 1.0);
}
}; };
Self(raw) Self(raw)

View File

@ -81,11 +81,12 @@ impl LayoutMod for MainLoad {
let dsp_size = ui.io().display_size; let dsp_size = ui.io().display_size;
let content_size = ui.content_region_avail(); let content_size = ui.content_region_avail();
// Change the size of the viewport
apptyp.main_viewport.set_size(content_size); apptyp.main_viewport.set_size(content_size);
// context.helper.set_size(content_size, scale[0]); // context.helper.set_size(content_size, scale[0]);
let draws = ui.get_window_draw_list(); let draws = ui.get_window_draw_list();
draws.channels_split(2, |channels| { draws.channels_split(2, |channels| {
channels.set_current(0); channels.set_current(0);
let fbo = apptyp.main_viewport.fbo(); let fbo = apptyp.main_viewport.fbo();
@ -191,7 +192,7 @@ impl<'gl> LayoutAttach<'gl> for MainLoadAttach<'gl> {
programs: &mut crate::pg::Programs<'gl>, programs: &mut crate::pg::Programs<'gl>,
helper: &mut Helper, helper: &mut Helper,
) -> crate::errors::Result<()> { ) -> crate::errors::Result<()> {
helper.draw_modules(gl, &self.packages); // helper.draw_modules(gl, &self.packages);
if self.packages.iter().any(|v| v.need_update) || self.operation.is_need_update() { if self.packages.iter().any(|v| v.need_update) || self.operation.is_need_update() {
// Helper task // Helper task
self.main_viewport.bind(gl); self.main_viewport.bind(gl);
@ -201,7 +202,7 @@ impl<'gl> LayoutAttach<'gl> for MainLoadAttach<'gl> {
} }
for package in self.packages.iter_mut() { for package in self.packages.iter_mut() {
programs.draw_modules(package, &self.operation)?; programs.draw_modules(package, &self.operation, &self.main_viewport)?;
} }
} }