separate render logic

This commit is contained in:
Oleg Sobolev 2024-06-11 19:18:47 +07:00
parent 50a30b74b5
commit 206f30f3af
3 changed files with 170 additions and 153 deletions

View file

@ -1,6 +1,4 @@
use cgmath::InnerSpace; pub mod renderer;
use crate::{vertex::RenderData, Vertex};
type Vector2 = cgmath::Vector2<f64>; type Vector2 = cgmath::Vector2<f64>;
@ -46,153 +44,4 @@ impl PolyLine {
pub fn new() -> Self { pub fn new() -> Self {
Self { points: Vec::new() } Self { points: Vec::new() }
} }
pub fn get_render_data(&self, width: f64) -> RenderData {
let mut result = RenderData::new();
for i in 1..self.points.len() {
result = result.merge(self.get_segment_render_data(i, width));
}
for i in 1..self.points.len() - 1 {
result = result.merge(self.get_connection_render_data(i, width));
}
result
}
fn get_segment_render_data(&self, i: usize, width: f64) -> RenderData {
let start_points = self.get_adjusted_start_points(i - 1, width);
let end_points = self.get_adjusted_end_points(i, width);
let vertices: Vec<Vertex> = [start_points.0, start_points.1, end_points.0, end_points.1]
.map(Vector2::into)
.map(Vertex::new_f64)
.into_iter()
.collect();
let indices: Vec<_> = vec![0, 2, 3, 0, 3, 1];
RenderData { vertices, indices }
}
fn get_connection_render_data(&self, i: usize, width: f64) -> RenderData {
let vertices: Vec<_> = match self.get_connection(i, width) {
Some((intersection, false)) => {
vec![
self.get_end_points(i, width).1,
intersection,
self.get_start_points(i, width).1,
]
}
Some((intersection, true)) => {
vec![
self.get_end_points(i, width).0,
intersection,
self.get_start_points(i, width).0,
]
}
None => vec![],
}
.into_iter()
.map(Vector2::into)
.map(Vertex::new_f64)
.collect();
let indices = if vertices.is_empty() {
vec![]
} else {
vec![0, 1, 2]
};
RenderData { vertices, indices }
}
fn get_adjusted_start_points(&self, i: usize, width: f64) -> (Vector2, Vector2) {
let start_points = self.get_start_points(i, width);
if i == 0 {
return start_points;
}
match self.get_connection(i, width) {
Some((intersection, false)) => (intersection, start_points.1),
Some((intersection, true)) => (start_points.0, intersection),
None => start_points,
}
}
fn get_adjusted_end_points(&self, i: usize, width: f64) -> (Vector2, Vector2) {
let end_points = self.get_end_points(i, width);
if i + 1 == self.points.len() {
return end_points;
}
match self.get_connection(i, width) {
Some((intersection, false)) => (intersection, end_points.1),
Some((intersection, true)) => (end_points.0, intersection),
None => end_points,
}
}
fn get_connection(&self, i: usize, width: f64) -> Option<(Vector2, bool)> {
let start_points = self.get_start_points(i - 1, width);
let end_points = self.get_end_points(i, width);
let next_start_points = self.get_start_points(i, width);
let next_end_points = self.get_end_points(i + 1, width);
let lines = (
Self::line(start_points.0, end_points.0),
Self::line(start_points.1, end_points.1),
);
let next_lines = (
Self::line(next_start_points.0, next_end_points.0),
Self::line(next_start_points.1, next_end_points.1),
);
use geo::algorithm::line_intersection::{line_intersection, LineIntersection};
let intersections = (
line_intersection(lines.0, next_lines.0),
line_intersection(lines.1, next_lines.1),
);
match intersections {
(Some(LineIntersection::SinglePoint { intersection, .. }), None) => {
Some((Vector2::new(intersection.x, intersection.y), false))
}
(None, Some(LineIntersection::SinglePoint { intersection, .. })) => {
Some((Vector2::new(intersection.x, intersection.y), true))
}
_ => None,
}
}
fn get_start_points(&self, i: usize, width: f64) -> (Vector2, Vector2) {
if i + 1 == self.points.len() {
panic!();
}
Self::offset_by_direction(
self.points[i],
(self.points[i + 1] - self.points[i]).normalize() * width,
)
}
fn get_end_points(&self, i: usize, width: f64) -> (Vector2, Vector2) {
if i == 0 {
panic!();
}
Self::offset_by_direction(
self.points[i],
(self.points[i] - self.points[i - 1]).normalize() * width,
)
}
fn line(start: Vector2, end: Vector2) -> geo::Line<f64> {
geo::Line {
start: geo::Coord {
x: start.x,
y: start.y,
},
end: geo::Coord { x: end.x, y: end.y },
}
}
fn offset_by_direction(point: Vector2, direction: Vector2) -> (Vector2, Vector2) {
(
point + vec2(direction.y, -direction.x),
point + vec2(-direction.y, direction.x),
)
}
} }

167
src/curve/renderer.rs Normal file
View file

@ -0,0 +1,167 @@
use cgmath::InnerSpace;
use super::vec2;
use super::PolyLine;
use super::Vector2;
use crate::{vertex::RenderData, Vertex};
pub struct ConnectionRenderer {
}
impl ConnectionRenderer {
pub fn new() -> ConnectionRenderer {
ConnectionRenderer {}
}
pub fn render(&self, line: &PolyLine, width: f64) -> RenderData {
let mut result = RenderData::new();
for i in 1..line.points.len() {
result = result.merge(Self::get_segment_render_data(line, i, width));
}
for i in 1..line.points.len() - 1 {
result = result.merge(Self::get_connection_render_data(line, i, width));
}
result
}
fn get_segment_render_data(line: &PolyLine, i: usize, width: f64) -> RenderData {
let start_points = Self::get_adjusted_start_points(line, i - 1, width);
let end_points = Self::get_adjusted_end_points(line, i, width);
let vertices: Vec<Vertex> = [start_points.0, start_points.1, end_points.0, end_points.1]
.map(Vector2::into)
.map(Vertex::new_f64)
.into_iter()
.collect();
let indices: Vec<_> = vec![0, 2, 3, 0, 3, 1];
RenderData { vertices, indices }
}
fn get_connection_render_data(line: &PolyLine, i: usize, width: f64) -> RenderData {
let vertices: Vec<_> = match Self::get_connection(line, i, width) {
Some((intersection, false)) => {
vec![
Self::get_end_points(line, i, width).1,
intersection,
Self::get_start_points(line, i, width).1,
]
}
Some((intersection, true)) => {
vec![
Self::get_end_points(line, i, width).0,
intersection,
Self::get_start_points(line, i, width).0,
]
}
None => vec![],
}
.into_iter()
.map(Vector2::into)
.map(Vertex::new_f64)
.collect();
let indices = if vertices.is_empty() {
vec![]
} else {
vec![0, 1, 2]
};
RenderData { vertices, indices }
}
fn get_adjusted_start_points(line: &PolyLine, i: usize, width: f64) -> (Vector2, Vector2) {
let start_points = Self::get_start_points(line, i, width);
if i == 0 {
return start_points;
}
match Self::get_connection(line, i, width) {
Some((intersection, false)) => (intersection, start_points.1),
Some((intersection, true)) => (start_points.0, intersection),
None => start_points,
}
}
fn get_adjusted_end_points(line: &PolyLine, i: usize, width: f64) -> (Vector2, Vector2) {
let end_points = Self::get_end_points(line, i, width);
if i + 1 == line.points.len() {
return end_points;
}
match Self::get_connection(line, i, width) {
Some((intersection, false)) => (intersection, end_points.1),
Some((intersection, true)) => (end_points.0, intersection),
None => end_points,
}
}
fn get_connection(line: &PolyLine, i: usize, width: f64) -> Option<(Vector2, bool)> {
let start_points = Self::get_start_points(line, i - 1, width);
let end_points = Self::get_end_points(line, i, width);
let next_start_points = Self::get_start_points(line, i, width);
let next_end_points = Self::get_end_points(line, i + 1, width);
let lines = (
make_line(start_points.0, end_points.0),
make_line(start_points.1, end_points.1),
);
let next_lines = (
make_line(next_start_points.0, next_end_points.0),
make_line(next_start_points.1, next_end_points.1),
);
use geo::algorithm::line_intersection::{line_intersection, LineIntersection};
let intersections = (
line_intersection(lines.0, next_lines.0),
line_intersection(lines.1, next_lines.1),
);
match intersections {
(Some(LineIntersection::SinglePoint { intersection, .. }), None) => {
Some((Vector2::new(intersection.x, intersection.y), false))
}
(None, Some(LineIntersection::SinglePoint { intersection, .. })) => {
Some((Vector2::new(intersection.x, intersection.y), true))
}
_ => None,
}
}
fn get_start_points(line: &PolyLine, i: usize, width: f64) -> (Vector2, Vector2) {
if i + 1 == line.points.len() {
panic!();
}
Self::offset_by_direction(
line.points[i],
(line.points[i + 1] - line.points[i]).normalize() * width,
)
}
fn get_end_points(line: &PolyLine, i: usize, width: f64) -> (Vector2, Vector2) {
if i == 0 {
panic!();
}
Self::offset_by_direction(
line.points[i],
(line.points[i] - line.points[i - 1]).normalize() * width,
)
}
fn offset_by_direction(point: Vector2, direction: Vector2) -> (Vector2, Vector2) {
(
point + vec2(direction.y, -direction.x),
point + vec2(-direction.y, direction.x),
)
}
}
fn make_line(start: Vector2, end: Vector2) -> geo::Line<f64> {
geo::Line {
start: geo::Coord {
x: start.x,
y: start.y,
},
end: geo::Coord { x: end.x, y: end.y },
}
}

View file

@ -194,7 +194,8 @@ impl<'window> State<'window> {
) )
.subdivide(count); .subdivide(count);
let data = poly_line.get_render_data(width); let renderer = crate::curve::renderer::ConnectionRenderer::new();
let data = renderer.render(&poly_line, width);
self.queue self.queue
.write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(&data.vertices)); .write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(&data.vertices));