Create tile primitives
This commit is contained in:
parent
4b9e21c6a0
commit
00fb5ca5de
|
@ -17,7 +17,7 @@ extern crate quickcheck;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use euclid::{Point2D, Rect, Size2D, Transform2D, Vector2D};
|
use euclid::{Point2D, Rect, Size2D, Transform2D};
|
||||||
use jemallocator;
|
use jemallocator;
|
||||||
use lyon_geom::cubic_bezier::Flattened;
|
use lyon_geom::cubic_bezier::Flattened;
|
||||||
use lyon_geom::{CubicBezierSegment, LineSegment, QuadraticBezierSegment};
|
use lyon_geom::{CubicBezierSegment, LineSegment, QuadraticBezierSegment};
|
||||||
|
@ -27,7 +27,6 @@ use pathfinder_path_utils::stroke::{StrokeStyle, StrokeToFillIter};
|
||||||
use quick_xml::Reader;
|
use quick_xml::Reader;
|
||||||
use quick_xml::events::Event;
|
use quick_xml::events::Event;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::env;
|
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -70,15 +69,16 @@ fn main() {
|
||||||
println!("bounds: {:?}", scene.bounds);
|
println!("bounds: {:?}", scene.bounds);
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut primitives = vec![];
|
let mut built_scene = BuiltScene::new();
|
||||||
for _ in 0..runs {
|
for _ in 0..runs {
|
||||||
primitives = scene.generate_tiles();
|
built_scene = scene.build();
|
||||||
}
|
}
|
||||||
let elapsed_time = Instant::now() - start_time;
|
let elapsed_time = Instant::now() - start_time;
|
||||||
let elapsed_ms = elapsed_time.as_secs() as f64 * 1000.0 +
|
let elapsed_ms = elapsed_time.as_secs() as f64 * 1000.0 +
|
||||||
elapsed_time.subsec_micros() as f64 / 1000.0;
|
elapsed_time.subsec_micros() as f64 / 1000.0;
|
||||||
println!("{}ms elapsed", elapsed_ms / runs as f64);
|
println!("{:.3}ms elapsed", elapsed_ms / runs as f64);
|
||||||
println!("{} primitives generated", primitives.len());
|
println!("{} fill primitives generated", built_scene.fills.len());
|
||||||
|
println!("{} tiles generated", built_scene.tiles.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -93,6 +93,7 @@ struct Scene {
|
||||||
struct PathObject {
|
struct PathObject {
|
||||||
outline: Outline,
|
outline: Outline,
|
||||||
style: StyleId,
|
style: StyleId,
|
||||||
|
color: ColorU,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,15 +266,18 @@ impl Scene {
|
||||||
&self.styles[style.0 as usize]
|
&self.styles[style.0 as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_tiles(&self) -> Vec<Primitive> {
|
fn build(&self) -> BuiltScene {
|
||||||
let mut primitives = vec![];
|
let mut built_scene = BuiltScene::new();
|
||||||
for (index, object) in self.objects.iter().enumerate() {
|
for (index, object) in self.objects.iter().enumerate() {
|
||||||
//println!("{} ({}): {:?}", index, object.name, object.outline.bounds);
|
//println!("{} ({}): {:?}", index, object.name, object.outline.bounds);
|
||||||
let mut tiler = Tiler::from_outline(&object.outline, &self.view_box, &mut primitives);
|
let mut tiler = Tiler::from_outline(&object.outline,
|
||||||
|
object.color,
|
||||||
|
&self.view_box,
|
||||||
|
&mut built_scene);
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles();
|
||||||
// TODO(pcwalton)
|
// TODO(pcwalton)
|
||||||
}
|
}
|
||||||
primitives
|
built_scene
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_svg_path(&mut self, value: &str, style: StyleId, name: String) {
|
fn push_svg_path(&mut self, value: &str, style: StyleId, name: String) {
|
||||||
|
@ -284,8 +288,14 @@ impl Scene {
|
||||||
let path = PathIter::new(path);
|
let path = PathIter::new(path);
|
||||||
let path = StrokeToFillIter::new(path, StrokeStyle::new(computed_style.stroke_width));
|
let path = StrokeToFillIter::new(path, StrokeStyle::new(computed_style.stroke_width));
|
||||||
let outline = Outline::from_path_events(path, computed_style);
|
let outline = Outline::from_path_events(path, computed_style);
|
||||||
|
|
||||||
|
let color = match computed_style.stroke_color {
|
||||||
|
None => ColorU::black(),
|
||||||
|
Some(color) => ColorU::from_svg_color(color),
|
||||||
|
};
|
||||||
|
|
||||||
self.bounds = self.bounds.union(&outline.bounds);
|
self.bounds = self.bounds.union(&outline.bounds);
|
||||||
self.objects.push(PathObject::new(outline, style, name.clone()));
|
self.objects.push(PathObject::new(outline, color, style, name.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.get_style(style).fill_color.is_some() {
|
if self.get_style(style).fill_color.is_some() {
|
||||||
|
@ -293,15 +303,21 @@ impl Scene {
|
||||||
let mut path_parser = PathParser::from(&*value);
|
let mut path_parser = PathParser::from(&*value);
|
||||||
let path = SvgPathToPathEvents::new(&mut path_parser);
|
let path = SvgPathToPathEvents::new(&mut path_parser);
|
||||||
let outline = Outline::from_path_events(path, computed_style);
|
let outline = Outline::from_path_events(path, computed_style);
|
||||||
|
|
||||||
|
let color = match computed_style.fill_color {
|
||||||
|
None => ColorU::black(),
|
||||||
|
Some(color) => ColorU::from_svg_color(color),
|
||||||
|
};
|
||||||
|
|
||||||
self.bounds = self.bounds.union(&outline.bounds);
|
self.bounds = self.bounds.union(&outline.bounds);
|
||||||
self.objects.push(PathObject::new(outline, style, name));
|
self.objects.push(PathObject::new(outline, color, style, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathObject {
|
impl PathObject {
|
||||||
fn new(outline: Outline, style: StyleId, name: String) -> PathObject {
|
fn new(outline: Outline, color: ColorU, style: StyleId, name: String) -> PathObject {
|
||||||
PathObject { outline, style, name }
|
PathObject { outline, color, style, name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,18 +418,9 @@ impl Outline {
|
||||||
outline
|
outline
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn iter(&self) -> OutlineIter {
|
|
||||||
OutlineIter { outline: self, contour_iter: None, contour_index: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn segment_after(&self, endpoint_index: PointIndex) -> Segment {
|
fn segment_after(&self, endpoint_index: PointIndex) -> Segment {
|
||||||
self.contours[endpoint_index.contour_index].segment_after(endpoint_index.point_index)
|
self.contours[endpoint_index.contour_index].segment_after(endpoint_index.point_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_point(&self, index: PointIndex) -> &Point2D<f32> {
|
|
||||||
&self.contours[index.contour_index].points[index.point_index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Contour {
|
impl Contour {
|
||||||
|
@ -521,40 +528,11 @@ struct PointIndex {
|
||||||
point_index: usize,
|
point_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OutlineIter<'a> {
|
|
||||||
outline: &'a Outline,
|
|
||||||
contour_iter: Option<ContourIter<'a>>,
|
|
||||||
contour_index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContourIter<'a> {
|
struct ContourIter<'a> {
|
||||||
contour: &'a Contour,
|
contour: &'a Contour,
|
||||||
index: usize,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for OutlineIter<'a> {
|
|
||||||
type Item = PathEvent;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<PathEvent> {
|
|
||||||
if let Some(ref mut contour_iter) = self.contour_iter {
|
|
||||||
match contour_iter.next() {
|
|
||||||
Some(event) => return Some(event),
|
|
||||||
None => {
|
|
||||||
self.contour_iter = None;
|
|
||||||
self.contour_index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.contour_index == self.outline.contours.len() {
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
self.contour_iter = Some(self.outline.contours[self.contour_index].iter());
|
|
||||||
self.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for ContourIter<'a> {
|
impl<'a> Iterator for ContourIter<'a> {
|
||||||
type Item = PathEvent;
|
type Item = PathEvent;
|
||||||
|
|
||||||
|
@ -644,7 +622,10 @@ impl Segment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_primitives(&self, range: Range<f32>, primitives: &mut Vec<Primitive>) {
|
fn generate_fill_primitives(&self,
|
||||||
|
range: Range<f32>,
|
||||||
|
tile_index: u32,
|
||||||
|
primitives: &mut Vec<FillPrimitive>) {
|
||||||
let segment = CubicBezierSegment {
|
let segment = CubicBezierSegment {
|
||||||
from: self.from,
|
from: self.from,
|
||||||
ctrl1: self.ctrl0,
|
ctrl1: self.ctrl0,
|
||||||
|
@ -655,7 +636,7 @@ impl Segment {
|
||||||
let mut from = self.from;
|
let mut from = self.from;
|
||||||
for to in flattener {
|
for to in flattener {
|
||||||
if f32::min(from.x, to.x) >= range.start && f32::max(from.x, to.x) <= range.end {
|
if f32::min(from.x, to.x) >= range.start && f32::max(from.x, to.x) <= range.end {
|
||||||
primitives.push(Primitive { from, to });
|
primitives.push(FillPrimitive { from, to, tile_index });
|
||||||
}
|
}
|
||||||
from = to;
|
from = to;
|
||||||
}
|
}
|
||||||
|
@ -721,26 +702,6 @@ impl Segment {
|
||||||
|
|
||||||
const TOLERANCE: f32 = 0.01;
|
const TOLERANCE: f32 = 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate(&self, by: &Vector2D<f32>) -> Segment {
|
|
||||||
let flags = self.flags;
|
|
||||||
let (from, to) = if flags.contains(SegmentFlags::HAS_ENDPOINTS) {
|
|
||||||
(self.from + *by, self.to + *by)
|
|
||||||
} else {
|
|
||||||
(Point2D::zero(), Point2D::zero())
|
|
||||||
};
|
|
||||||
let ctrl0 = if flags.contains(SegmentFlags::HAS_CONTROL_POINT_0) {
|
|
||||||
self.ctrl0 + *by
|
|
||||||
} else {
|
|
||||||
Point2D::zero()
|
|
||||||
};
|
|
||||||
let ctrl1 = if flags.contains(SegmentFlags::HAS_CONTROL_POINT_1) {
|
|
||||||
self.ctrl1 + *by
|
|
||||||
} else {
|
|
||||||
Point2D::zero()
|
|
||||||
};
|
|
||||||
Segment { from, ctrl0, ctrl1, to, flags }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClippedSegments {
|
struct ClippedSegments {
|
||||||
|
@ -763,7 +724,8 @@ const TILE_HEIGHT: f32 = 16.0;
|
||||||
|
|
||||||
struct Tiler<'o, 'p> {
|
struct Tiler<'o, 'p> {
|
||||||
outline: &'o Outline,
|
outline: &'o Outline,
|
||||||
primitives: &'p mut Vec<Primitive>,
|
fill_color: ColorU,
|
||||||
|
built_scene: &'p mut BuiltScene,
|
||||||
|
|
||||||
view_box: Option<Rect<f32>>,
|
view_box: Option<Rect<f32>>,
|
||||||
|
|
||||||
|
@ -774,12 +736,14 @@ struct Tiler<'o, 'p> {
|
||||||
|
|
||||||
impl<'o, 'p> Tiler<'o, 'p> {
|
impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
fn from_outline(outline: &'o Outline,
|
fn from_outline(outline: &'o Outline,
|
||||||
|
fill_color: ColorU,
|
||||||
view_box: &Option<Rect<f32>>,
|
view_box: &Option<Rect<f32>>,
|
||||||
primitives: &'p mut Vec<Primitive>)
|
built_scene: &'p mut BuiltScene)
|
||||||
-> Tiler<'o, 'p> {
|
-> Tiler<'o, 'p> {
|
||||||
Tiler {
|
Tiler {
|
||||||
outline,
|
outline,
|
||||||
primitives,
|
fill_color,
|
||||||
|
built_scene,
|
||||||
|
|
||||||
view_box: *view_box,
|
view_box: *view_box,
|
||||||
|
|
||||||
|
@ -819,26 +783,54 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
|
|
||||||
self.active_intervals.reset(max_x);
|
self.active_intervals.reset(max_x);
|
||||||
self.active_edges.clear();
|
self.active_edges.clear();
|
||||||
|
|
||||||
let mut next_edge_index_index = 0;
|
let mut next_edge_index_index = 0;
|
||||||
|
|
||||||
let mut tile_top = f32::floor(bounds.origin.y / TILE_HEIGHT) * TILE_HEIGHT;
|
let mut strip_origin =
|
||||||
while tile_top < max_y {
|
Point2D::new(f32::floor(bounds.origin.x / TILE_WIDTH) * TILE_WIDTH,
|
||||||
let tile_extent = Point2D::new(max_x, tile_top + TILE_HEIGHT);
|
f32::floor(bounds.origin.y / TILE_HEIGHT) * TILE_HEIGHT);
|
||||||
|
|
||||||
|
while strip_origin.y < max_y {
|
||||||
|
let first_tile_index = self.built_scene.tiles.len() as u32;
|
||||||
|
|
||||||
|
let strip_extent = Point2D::new(max_x, strip_origin.y + TILE_HEIGHT);
|
||||||
|
let strip_bounds = Rect::new(strip_origin,
|
||||||
|
Size2D::new(strip_extent.x - strip_origin.x,
|
||||||
|
strip_extent.y - strip_origin.y));
|
||||||
|
|
||||||
let above_view_box = match self.view_box {
|
let above_view_box = match self.view_box {
|
||||||
Some(ref view_box) => tile_extent.y <= view_box.origin.y,
|
Some(ref view_box) => strip_extent.y <= view_box.origin.y,
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(pcwalton): Populate tile strip with active intervals.
|
// Populate tile strip with active intervals.
|
||||||
|
for interval in &self.active_intervals.ranges {
|
||||||
|
if interval.winding == 0.0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let left = Point2D::new(interval.start, strip_origin.y);
|
||||||
|
let right = Point2D::new(interval.end, strip_origin.y);
|
||||||
|
let line_segment = if interval.winding < 0.0 {
|
||||||
|
LineSegment { from: left, to: right }
|
||||||
|
} else {
|
||||||
|
LineSegment { from: right, to: left }
|
||||||
|
};
|
||||||
|
let mut segment = Segment::from_line(&line_segment);
|
||||||
|
process_active_edge(&mut segment,
|
||||||
|
&strip_bounds,
|
||||||
|
first_tile_index,
|
||||||
|
Some(&mut self.built_scene.fills),
|
||||||
|
None);
|
||||||
|
}
|
||||||
|
|
||||||
// Process old active edges.
|
// Process old active edges.
|
||||||
for active_edge in &mut self.active_edges {
|
for active_edge in &mut self.active_edges {
|
||||||
let primitives = if above_view_box { None } else { Some(&mut *self.primitives) };
|
let fills = if above_view_box { None } else { Some(&mut self.built_scene.fills) };
|
||||||
process_active_edge(active_edge,
|
process_active_edge(active_edge,
|
||||||
&tile_extent,
|
&strip_bounds,
|
||||||
primitives,
|
first_tile_index,
|
||||||
&mut self.active_intervals)
|
fills,
|
||||||
|
Some(&mut self.active_intervals))
|
||||||
}
|
}
|
||||||
self.active_edges.retain(|edge| !edge.is_none());
|
self.active_edges.retain(|edge| !edge.is_none());
|
||||||
|
|
||||||
|
@ -846,15 +838,16 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
while next_edge_index_index < self.sorted_edge_indices.len() {
|
while next_edge_index_index < self.sorted_edge_indices.len() {
|
||||||
let mut segment =
|
let mut segment =
|
||||||
self.outline.segment_after(self.sorted_edge_indices[next_edge_index_index]);
|
self.outline.segment_after(self.sorted_edge_indices[next_edge_index_index]);
|
||||||
if segment.min_y() > tile_extent.y {
|
if segment.min_y() > strip_extent.y {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let primitives = if above_view_box { None } else { Some(&mut *self.primitives) };
|
let fills = if above_view_box { None } else { Some(&mut self.built_scene.fills) };
|
||||||
process_active_edge(&mut segment,
|
process_active_edge(&mut segment,
|
||||||
&tile_extent,
|
&strip_bounds,
|
||||||
primitives,
|
first_tile_index,
|
||||||
&mut self.active_intervals);
|
fills,
|
||||||
|
Some(&mut self.active_intervals));
|
||||||
if !segment.is_none() {
|
if !segment.is_none() {
|
||||||
self.active_edges.push(segment);
|
self.active_edges.push(segment);
|
||||||
}
|
}
|
||||||
|
@ -862,18 +855,29 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
||||||
next_edge_index_index += 1;
|
next_edge_index_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_top = tile_extent.y;
|
// Flush tiles.
|
||||||
|
let mut tile_left = strip_origin.x;
|
||||||
|
while tile_left < max_x {
|
||||||
|
let strip_origin = Point2D::new(tile_left, strip_origin.y);
|
||||||
|
self.built_scene.tiles.push(TilePrimitive::new(&strip_origin, self.fill_color));
|
||||||
|
tile_left += TILE_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
strip_origin.y = strip_extent.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_active_edge(active_edge: &mut Segment,
|
fn process_active_edge(active_edge: &mut Segment,
|
||||||
strip_extent: &Point2D<f32>,
|
strip_bounds: &Rect<f32>,
|
||||||
primitives: Option<&mut Vec<Primitive>>,
|
first_tile_index: u32,
|
||||||
active_intervals: &mut Intervals) {
|
fills: Option<&mut Vec<FillPrimitive>>,
|
||||||
|
active_intervals: Option<&mut Intervals>) {
|
||||||
|
let strip_extent = strip_bounds.bottom_right();
|
||||||
let clipped = active_edge.clip_y(strip_extent.y);
|
let clipped = active_edge.clip_y(strip_extent.y);
|
||||||
|
|
||||||
if let Some(upper_segment) = clipped.min {
|
if let Some(upper_segment) = clipped.min {
|
||||||
if let Some(primitives) = primitives {
|
if let Some(fills) = fills {
|
||||||
// FIXME(pcwalton): Assumes x-monotonicity!
|
// FIXME(pcwalton): Assumes x-monotonicity!
|
||||||
// FIXME(pcwalton): Don't hardcode a view box left of 0!
|
// FIXME(pcwalton): Don't hardcode a view box left of 0!
|
||||||
let mut min_x = f32::min(upper_segment.from.x, upper_segment.to.x);
|
let mut min_x = f32::min(upper_segment.from.x, upper_segment.to.x);
|
||||||
|
@ -883,18 +887,25 @@ fn process_active_edge(active_edge: &mut Segment,
|
||||||
|
|
||||||
let tile_left = f32::floor(min_x / TILE_WIDTH) * TILE_WIDTH;
|
let tile_left = f32::floor(min_x / TILE_WIDTH) * TILE_WIDTH;
|
||||||
let tile_right = f32::ceil(max_x / TILE_WIDTH) * TILE_WIDTH;
|
let tile_right = f32::ceil(max_x / TILE_WIDTH) * TILE_WIDTH;
|
||||||
active_edge.generate_primitives(tile_left..tile_right, primitives);
|
|
||||||
|
let left_tile_index =
|
||||||
|
first_tile_index +
|
||||||
|
((tile_left - strip_bounds.origin.x) as u32 / TILE_WIDTH as u32);
|
||||||
|
|
||||||
|
active_edge.generate_fill_primitives(tile_left..tile_right, left_tile_index, fills);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): Assumes x-monotonicity!
|
if let Some(active_intervals) = active_intervals {
|
||||||
let mut from_x = f32::max(0.0, f32::min(active_intervals.extent(), upper_segment.from.x));
|
// FIXME(pcwalton): Assumes x-monotonicity!
|
||||||
let mut to_x = f32::max(0.0, f32::min(active_intervals.extent(), upper_segment.to.x));
|
let mut from_x = clamp(upper_segment.from.x, 0.0, active_intervals.extent());
|
||||||
from_x = clamp(from_x, 0.0, strip_extent.x);
|
let mut to_x = clamp(upper_segment.to.x, 0.0, active_intervals.extent());
|
||||||
to_x = clamp(to_x, 0.0, strip_extent.x);
|
from_x = clamp(from_x, 0.0, strip_extent.x);
|
||||||
if from_x < to_x {
|
to_x = clamp(to_x, 0.0, strip_extent.x);
|
||||||
active_intervals.add(IntervalRange::new(from_x, to_x, -1.0))
|
if from_x < to_x {
|
||||||
} else {
|
active_intervals.add(IntervalRange::new(from_x, to_x, -1.0))
|
||||||
active_intervals.add(IntervalRange::new(to_x, from_x, 1.0))
|
} else {
|
||||||
|
active_intervals.add(IntervalRange::new(to_x, from_x, 1.0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,10 +917,53 @@ fn process_active_edge(active_edge: &mut Segment,
|
||||||
|
|
||||||
// Primitives
|
// Primitives
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BuiltScene {
|
||||||
|
fills: Vec<FillPrimitive>,
|
||||||
|
tiles: Vec<TilePrimitive>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct Primitive {
|
struct FillPrimitive {
|
||||||
from: Point2D<f32>,
|
from: Point2D<f32>,
|
||||||
to: Point2D<f32>,
|
to: Point2D<f32>,
|
||||||
|
tile_index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct TilePrimitive {
|
||||||
|
position: Point2D<f32>,
|
||||||
|
color: ColorU,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
struct ColorU {
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
a: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltScene {
|
||||||
|
fn new() -> BuiltScene {
|
||||||
|
BuiltScene { fills: vec![], tiles: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TilePrimitive {
|
||||||
|
fn new(position: &Point2D<f32>, color: ColorU) -> TilePrimitive {
|
||||||
|
TilePrimitive { position: *position, color }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorU {
|
||||||
|
fn black() -> ColorU {
|
||||||
|
ColorU { r: 0, g: 0, b: 0, a: 255 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_svg_color(svg_color: SvgColor) -> ColorU {
|
||||||
|
ColorU { r: svg_color.red, g: svg_color.green, b: svg_color.blue, a: 255 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intervals
|
// Intervals
|
||||||
|
@ -1021,10 +1075,6 @@ impl IntervalRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains(&self, value: f32) -> bool {
|
|
||||||
value >= self.start && value < self.end
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.start == self.end
|
self.start == self.end
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue