458 lines
11 KiB
Rust
458 lines
11 KiB
Rust
use std::ops::{Deref, DerefMut};
|
|
|
|
use bytemuck::{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::{AttaWithBuffer, Config, Graphics};
|
|
|
|
use super::Colletion;
|
|
|
|
pub struct AggFastPath {
|
|
program: Program,
|
|
buffer: Vec<Point>,
|
|
indice: Vec<[u32; 3]>,
|
|
|
|
vao: Option<NativeVertexArray>,
|
|
vbo: Option<NativeBuffer>,
|
|
ebo: Option<NativeBuffer>,
|
|
}
|
|
|
|
impl AggFastPath {
|
|
pub fn new() -> Result<Self> {
|
|
let vertex = Shader::new(
|
|
glow::VERTEX_SHADER,
|
|
CodeType::<String>::Path("agg-fast-path.vert".into()),
|
|
)?;
|
|
|
|
let fragment = Shader::new(
|
|
glow::FRAGMENT_SHADER,
|
|
CodeType::<String>::Path("agg-fast-path.frag".into()),
|
|
)?;
|
|
|
|
let input_snippet = Snippet::new(
|
|
"input",
|
|
CodeType::<&'static str>::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");
|
|
|
|
// program.set_transform(transform);
|
|
// program.set_viewport(viewport);
|
|
|
|
Ok(Self {
|
|
program,
|
|
buffer: Vec::with_capacity(128),
|
|
indice: Vec::with_capacity(128 * 2),
|
|
ebo: None,
|
|
vao: None,
|
|
vbo: None,
|
|
})
|
|
}
|
|
|
|
pub fn set_transform<T: Transform>(&mut self, transform: &T) {
|
|
self.program.set_transform(transform);
|
|
}
|
|
|
|
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]) {
|
|
let loc = self.program.get_uniform_location(gl, "color");
|
|
unsafe {
|
|
gl.uniform_4_f32(loc.as_ref(), color[0], color[1], color[2], color[3]);
|
|
}
|
|
}
|
|
|
|
pub fn set_linewidth(&mut self, gl: &glow::Context, linewidth: f32) {
|
|
let loc = self.program.get_uniform_location(gl, "linewidth");
|
|
unsafe {
|
|
gl.uniform_1_f32(loc.as_ref(), linewidth);
|
|
}
|
|
}
|
|
|
|
pub fn set_anatialias(&mut self, gl: &glow::Context, antialias: f32) {
|
|
let loc = self.program.get_uniform_location(gl, "antialias");
|
|
unsafe {
|
|
gl.uniform_1_f32(loc.as_ref(), antialias);
|
|
}
|
|
}
|
|
|
|
pub fn program(&mut self) -> &mut Program {
|
|
&mut self.program
|
|
}
|
|
|
|
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 {
|
|
type Item = Path;
|
|
|
|
fn append(&mut self, item: Self::Item) {
|
|
self.buffer.extend(item.points);
|
|
self.indice.extend(item.ebo);
|
|
}
|
|
}
|
|
|
|
impl Graphics for AggFastPath {
|
|
const id: &'static str = "AggPath";
|
|
type Config = ();
|
|
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));
|
|
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<()> {
|
|
unsafe {
|
|
gl.clear(glow::COLOR_BUFFER_BIT);
|
|
gl.bind_vertex_array(Some(self.vao.unwrap()));
|
|
gl.draw_elements(
|
|
glow::TRIANGLES,
|
|
(self.indice.len() * 3) as i32,
|
|
glow::UNSIGNED_INT,
|
|
0,
|
|
);
|
|
gl.bind_vertex_array(None);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn destroy(&mut self, gl: &glow::Context) -> Result<()> {
|
|
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: &Self::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,
|
|
config: &<Self as Graphics>::Config,
|
|
) -> Result<(Vec<f32>, Option<Vec<u32>>, i32)> {
|
|
Ok((vec![], None, 0))
|
|
}
|
|
|
|
fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option<NativeBuffer>) {
|
|
(self.vao.unwrap(), self.vbo.unwrap(), self.ebo)
|
|
}
|
|
}
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
|
pub struct Point {
|
|
prev: [f32; 3],
|
|
curr: [f32; 3],
|
|
next: [f32; 3],
|
|
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<Point>,
|
|
ebo: Vec<[u32; 3]>,
|
|
|
|
is_closed: bool,
|
|
is_empty: bool,
|
|
}
|
|
|
|
impl Default for Path {
|
|
fn default() -> Self {
|
|
Self {
|
|
points: Vec::with_capacity(500),
|
|
ebo: Vec::with_capacity(500),
|
|
|
|
is_closed: false,
|
|
is_empty: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct PathBuilder {
|
|
is_closed: bool,
|
|
}
|
|
|
|
impl Default for PathBuilder {
|
|
fn default() -> Self {
|
|
Self { is_closed: false }
|
|
}
|
|
}
|
|
|
|
impl PathBuilder {
|
|
pub fn is_closed(&mut self, is_closed: bool) -> &mut Self {
|
|
self.is_closed = is_closed;
|
|
self
|
|
}
|
|
|
|
pub fn build(&self) -> Path {
|
|
Path {
|
|
points: Vec::with_capacity(500),
|
|
is_closed: self.is_closed,
|
|
ebo: Vec::with_capacity(500),
|
|
|
|
is_empty: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
pub fn builder() -> PathBuilder {
|
|
PathBuilder::default()
|
|
}
|
|
|
|
pub fn push(&mut self, point: [f32; 3]) {
|
|
if self.is_empty {
|
|
self.points.push(Point {
|
|
prev: point,
|
|
curr: point,
|
|
next: point,
|
|
id: 1.0,
|
|
});
|
|
|
|
self.points.push(Point {
|
|
prev: point,
|
|
curr: point,
|
|
next: point,
|
|
id: -1.0,
|
|
});
|
|
|
|
self.is_empty = false;
|
|
} else {
|
|
let len = self.points.len();
|
|
let prev = self.points[len - 1].curr;
|
|
let curr = point;
|
|
let next = point;
|
|
self.points.push(Point {
|
|
prev,
|
|
curr,
|
|
next,
|
|
id: 1.0,
|
|
});
|
|
self.points.push(Point {
|
|
prev,
|
|
curr,
|
|
next,
|
|
id: -1.0,
|
|
});
|
|
|
|
self.points[len - 1].next = curr;
|
|
self.points[len - 2].next = curr;
|
|
}
|
|
}
|
|
|
|
pub fn finish(&mut self) {
|
|
if self.is_closed {
|
|
let len = self.points.len();
|
|
let curr = self.points.first().unwrap().curr;
|
|
let prev = self.points[len - 1].curr;
|
|
let next = self.points[1].next;
|
|
self.points.push(Point {
|
|
prev,
|
|
curr,
|
|
next,
|
|
id: 1.0,
|
|
});
|
|
self.points.push(Point {
|
|
prev,
|
|
curr,
|
|
next,
|
|
id: -1.0,
|
|
});
|
|
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 {
|
|
self.points.len()
|
|
}
|
|
}
|
|
|
|
impl Deref for Path {
|
|
type Target = [u8];
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
use bytemuck::cast_slice;
|
|
cast_slice(&self.points)
|
|
}
|
|
}
|
|
|
|
impl DerefMut for Path {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
use bytemuck::cast_slice_mut;
|
|
cast_slice_mut(&mut self.points)
|
|
}
|
|
}
|
|
|
|
mod test {
|
|
|
|
use crate::graphics::transforms::{polar::Polar, position::Position, trackball::Trackball};
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_path() {
|
|
let mut path = Path::builder().is_closed(false).build();
|
|
|
|
path.push([9.0, 9.0, 9.0]);
|
|
|
|
path.push([9.0, 19.0, 9.0]);
|
|
|
|
path.finish();
|
|
|
|
println!("{:?}, len: {}", path, path.len());
|
|
}
|
|
|
|
#[test]
|
|
fn test_agg() {
|
|
// let viewport = Trackball::new().unwrap();
|
|
// let trans = Polar::new().unwrap();
|
|
// let position = Position::new().unwrap();
|
|
|
|
// let transform = viewport.chain(trans.chain(position));
|
|
|
|
// let viewport = &Viewport::new().unwrap();
|
|
|
|
// let agg_path = AggFastPath::new(&transform, &viewport).unwrap();
|
|
}
|
|
}
|