Allow multiple glyphs to be rendered simultaneously
This commit is contained in:
parent
9b3f9d029c
commit
93277c7c11
|
@ -9,10 +9,15 @@
|
|||
"author": "Patrick Walton <pcwalton@mimiga.net>",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/base64-js": "^1.2.5",
|
||||
"@types/gl-matrix": "^2.2.34",
|
||||
"@types/lodash": "^4.14.73",
|
||||
"@types/node": "^8.0.19",
|
||||
"@types/opentype.js": "0.0.0",
|
||||
"base64-js": "^1.2.1",
|
||||
"bootstrap": "^4.0.0-alpha.6",
|
||||
"gl-matrix": "^2.4.0",
|
||||
"lodash": "^4.17.4",
|
||||
"opentype.js": "^0.7.3",
|
||||
"ts-loader": "^2.3.2",
|
||||
"typescript": "^2.4.2",
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
//
|
||||
// Copyright © 2017 Mozilla Foundation
|
||||
|
||||
const base64js = require('base64-js');
|
||||
const glmatrix = require('gl-matrix');
|
||||
const opentype = require('opentype.js');
|
||||
import * as _ from 'lodash';
|
||||
import * as base64js from 'base64-js';
|
||||
import * as glmatrix from 'gl-matrix';
|
||||
import * as opentype from 'opentype.js';
|
||||
|
||||
const TEXT: string = "G";
|
||||
const TEXT: string = "Lorem ipsum dolor sit amet";
|
||||
const FONT_SIZE: number = 16.0;
|
||||
|
||||
const SCALE_FACTOR: number = 1.0 / 100.0;
|
||||
|
@ -73,6 +74,8 @@ interface UnlinkedShaderProgram {
|
|||
|
||||
type Matrix4D = Float32Array;
|
||||
|
||||
type Rect = Float32Array;
|
||||
|
||||
interface Point2D {
|
||||
x: number;
|
||||
y: number;
|
||||
|
@ -316,7 +319,7 @@ class PathfinderMeshData implements Meshes<ArrayBuffer> {
|
|||
throw new PathfinderError("Failed to partition the font!");
|
||||
const meshes = response.Ok;
|
||||
for (const bufferName of Object.keys(BUFFER_TYPES) as Array<keyof Meshes<void>>)
|
||||
this[bufferName] = base64js.toByteArray(meshes[bufferName]).buffer;
|
||||
this[bufferName] = base64js.toByteArray(meshes[bufferName]).buffer as ArrayBuffer;
|
||||
|
||||
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
|
||||
this.edgeUpperLineIndexCount = this.edgeUpperLineIndices.byteLength / 8;
|
||||
|
@ -407,16 +410,40 @@ class AppController {
|
|||
|
||||
fontLoaded() {
|
||||
this.font = opentype.parse(this.fontData);
|
||||
if (!this.font.supported)
|
||||
if (!(this.font as any).supported)
|
||||
throw new PathfinderError("The font type is unsupported.");
|
||||
|
||||
const glyphIDs = this.font.stringToGlyphs(TEXT).map((glyph: any) => glyph.index);
|
||||
this.glyphs = this.font.stringToGlyphs(TEXT).map(glyph => new PathfinderGlyph(glyph));
|
||||
this.glyphs.sort((a, b) => a.index() - b.index());
|
||||
this.glyphs = _.sortedUniqBy(this.glyphs, glyph => glyph.index());
|
||||
|
||||
// Lay out in the atlas.
|
||||
let atlasWidth = 0, atlasHeight = 0;
|
||||
for (const glyph of this.glyphs) {
|
||||
const metrics = glyph.metrics();
|
||||
const width = metrics.xMax - metrics.xMin;
|
||||
const height = metrics.yMax - metrics.yMin;
|
||||
atlasHeight = Math.max(atlasHeight, height);
|
||||
const newAtlasWidth = atlasWidth + width;
|
||||
glyph.setAtlasLocation(new Float32Array([atlasWidth, 0, newAtlasWidth, height]));
|
||||
atlasWidth = newAtlasWidth;
|
||||
}
|
||||
|
||||
// Build the partitioning request to the server.
|
||||
const request = {
|
||||
otf: base64js.fromByteArray(new Uint8Array(this.fontData)),
|
||||
fontIndex: 0,
|
||||
glyphIDs: glyphIDs,
|
||||
pointSize: FONT_SIZE,
|
||||
glyphs: this.glyphs.map(glyph => {
|
||||
const atlasLocation = glyph.getAtlasLocation();
|
||||
const metrics = glyph.metrics();
|
||||
const tX = atlasLocation[0] - metrics.xMin;
|
||||
const tY = atlasLocation[1] - metrics.yMin;
|
||||
return {
|
||||
id: glyph.index(),
|
||||
transform: [1, 0, 0, 1, tX, tY],
|
||||
};
|
||||
}),
|
||||
pointSize: this.font.unitsPerEm,
|
||||
};
|
||||
|
||||
window.fetch(PARTITION_FONT_ENDPOINT_URL, {
|
||||
|
@ -445,7 +472,8 @@ class AppController {
|
|||
aaLevelSelect: HTMLSelectElement;
|
||||
fpsLabel: HTMLElement;
|
||||
fontData: ArrayBuffer;
|
||||
font: any;
|
||||
font: opentype.Font;
|
||||
glyphs: Array<PathfinderGlyph>;
|
||||
meshes: PathfinderMeshData;
|
||||
}
|
||||
|
||||
|
@ -614,14 +642,14 @@ class PathfinderView {
|
|||
if (event.ctrlKey) {
|
||||
// Zoom event: see https://developer.mozilla.org/en-US/docs/Web/Events/wheel
|
||||
const scaleFactor = 1.0 - event.deltaY * window.devicePixelRatio * SCALE_FACTOR;
|
||||
const scaleFactors = new Float32Array([scaleFactor, scaleFactor, 1.0]);
|
||||
const scaleFactors = new Float32Array([scaleFactor, scaleFactor, 1.0]) as glmatrix.vec3;
|
||||
glmatrix.mat4.scale(this.transform, this.transform, scaleFactors);
|
||||
} else {
|
||||
const delta = new Float32Array([
|
||||
-event.deltaX * window.devicePixelRatio,
|
||||
event.deltaY * window.devicePixelRatio,
|
||||
0.0
|
||||
]);
|
||||
0.0,
|
||||
]) as glmatrix.vec3;
|
||||
glmatrix.mat4.translate(this.transform, this.transform, delta);
|
||||
}
|
||||
|
||||
|
@ -821,7 +849,7 @@ class PathfinderView {
|
|||
quadTexCoordsBuffer: WebGLBuffer;
|
||||
quadElementsBuffer: WebGLBuffer;
|
||||
|
||||
transform: Matrix4D;
|
||||
transform: glmatrix.mat4;
|
||||
|
||||
appController: AppController;
|
||||
|
||||
|
@ -1457,6 +1485,31 @@ interface AntialiasingStrategyTable {
|
|||
ecaa: typeof ECAAStrategy;
|
||||
}
|
||||
|
||||
class PathfinderGlyph {
|
||||
constructor(glyph: opentype.Glyph) {
|
||||
this.glyph = glyph;
|
||||
}
|
||||
|
||||
getAtlasLocation() {
|
||||
return this.atlasLocation;
|
||||
}
|
||||
|
||||
setAtlasLocation(rect: Rect) {
|
||||
this.atlasLocation = rect;
|
||||
}
|
||||
|
||||
index(): number {
|
||||
return (this.glyph as any).index;
|
||||
}
|
||||
|
||||
metrics(): opentype.Metrics {
|
||||
return this.glyph.getMetrics();
|
||||
}
|
||||
|
||||
glyph: opentype.Glyph;
|
||||
private atlasLocation: Rect;
|
||||
}
|
||||
|
||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||
none: NoAAStrategy,
|
||||
ssaa: SSAAStrategy,
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
"target": "ES2017",
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"node"
|
||||
"base64-js",
|
||||
"gl-matrix",
|
||||
"lodash",
|
||||
"node",
|
||||
"opentype.js"
|
||||
],
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
|
|
|
@ -22,7 +22,7 @@ extern crate serde_derive;
|
|||
|
||||
use app_units::Au;
|
||||
use bincode::Infinite;
|
||||
use euclid::{Point2D, Size2D};
|
||||
use euclid::{Point2D, Size2D, Transform2D};
|
||||
use pathfinder_font_renderer::{FontContext, FontInstanceKey, FontKey};
|
||||
use pathfinder_font_renderer::{GlyphKey, GlyphOutlineBuffer};
|
||||
use pathfinder_partitioner::partitioner::Partitioner;
|
||||
|
@ -43,7 +43,7 @@ static STATIC_JS_JQUERY_PATH: &'static str = "../client/node_modules/jquery/dist
|
|||
static STATIC_JS_PATHFINDER_JS_PATH: &'static str = "../client/pathfinder.js";
|
||||
static STATIC_GLSL_PATH: &'static str = "../../shaders";
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
struct IndexRange {
|
||||
start: usize,
|
||||
end: usize,
|
||||
|
@ -57,9 +57,7 @@ impl IndexRange {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_vector_append_and_serialization<T>(dest: &mut Vec<u8>, src: &[T])
|
||||
-> Result<IndexRange, ()>
|
||||
where T: Serialize {
|
||||
fn from_data<T>(dest: &mut Vec<u8>, src: &[T]) -> Result<IndexRange, ()> where T: Serialize {
|
||||
let byte_len_before = dest.len();
|
||||
for src_value in src {
|
||||
try!(bincode::serialize_into(dest, src_value, Infinite).map_err(drop))
|
||||
|
@ -78,10 +76,16 @@ struct PartitionFontRequest {
|
|||
// Base64 encoded.
|
||||
otf: String,
|
||||
fontIndex: u32,
|
||||
glyphIDs: Vec<u32>,
|
||||
glyphs: Vec<PartitionGlyph>,
|
||||
pointSize: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
struct PartitionGlyph {
|
||||
id: u32,
|
||||
transform: Transform2D<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
struct PartitionGlyphDimensions {
|
||||
origin: Point2D<i32>,
|
||||
|
@ -89,7 +93,7 @@ struct PartitionGlyphDimensions {
|
|||
advance: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
struct DecodedOutlineIndices {
|
||||
endpoint_indices: IndexRange,
|
||||
control_point_indices: IndexRange,
|
||||
|
@ -173,15 +177,18 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
|||
|
||||
// Read glyph info.
|
||||
let mut outline_buffer = GlyphOutlineBuffer::new();
|
||||
let decoded_outline_indices: Vec<_> = request.glyphIDs.iter().map(|&glyph_id| {
|
||||
let glyph_key = GlyphKey::new(glyph_id);
|
||||
let decoded_outline_indices: Vec<_> = request.glyphs.iter().map(|glyph| {
|
||||
let glyph_key = GlyphKey::new(glyph.id);
|
||||
|
||||
let first_endpoint_index = outline_buffer.endpoints.len();
|
||||
let first_control_point_index = outline_buffer.control_points.len();
|
||||
let first_subpath_index = outline_buffer.subpaths.len();
|
||||
|
||||
// This might fail; if so, just leave it blank.
|
||||
drop(font_context.push_glyph_outline(&font_instance_key, &glyph_key, &mut outline_buffer));
|
||||
drop(font_context.push_glyph_outline(&font_instance_key,
|
||||
&glyph_key,
|
||||
&mut outline_buffer,
|
||||
&glyph.transform));
|
||||
|
||||
let last_endpoint_index = outline_buffer.endpoints.len();
|
||||
let last_control_point_index = outline_buffer.control_points.len();
|
||||
|
@ -202,13 +209,15 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
|||
let (mut cover_interior_indices, mut cover_curve_indices) = (vec![], vec![]);
|
||||
let (mut edge_upper_line_indices, mut edge_upper_curve_indices) = (vec![], vec![]);
|
||||
let (mut edge_lower_line_indices, mut edge_lower_curve_indices) = (vec![], vec![]);
|
||||
|
||||
partitioner.init(&outline_buffer.endpoints,
|
||||
&outline_buffer.control_points,
|
||||
&outline_buffer.subpaths);
|
||||
|
||||
let mut glyph_info = vec![];
|
||||
for (path_index, (&glyph_id, decoded_outline_indices)) in
|
||||
request.glyphIDs.iter().zip(decoded_outline_indices.iter()).enumerate() {
|
||||
let glyph_key = GlyphKey::new(glyph_id);
|
||||
for (path_index, (&glyph, decoded_outline_indices)) in
|
||||
request.glyphs.iter().zip(decoded_outline_indices.iter()).enumerate() {
|
||||
let glyph_key = GlyphKey::new(glyph.id);
|
||||
|
||||
let dimensions = match font_context.glyph_dimensions(&font_instance_key, &glyph_key) {
|
||||
Some(dimensions) => {
|
||||
|
@ -231,44 +240,64 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
|||
decoded_outline_indices.subpath_indices.start as u32,
|
||||
decoded_outline_indices.subpath_indices.end as u32);
|
||||
|
||||
let path_b_quads = partitioner.b_quads();
|
||||
let path_b_vertex_positions = partitioner.b_vertex_positions();
|
||||
let path_b_vertex_path_ids = partitioner.b_vertex_path_ids();
|
||||
let path_b_vertex_loop_blinn_data = partitioner.b_vertex_loop_blinn_data();
|
||||
let cover_indices = partitioner.cover_indices();
|
||||
let edge_indices = partitioner.edge_indices();
|
||||
|
||||
IndexRange::from_vector_append_and_serialization(&mut b_vertex_positions,
|
||||
path_b_vertex_positions).unwrap();
|
||||
IndexRange::from_vector_append_and_serialization(&mut b_vertex_path_ids,
|
||||
path_b_vertex_path_ids).unwrap();
|
||||
let positions_start = IndexRange::from_data(&mut b_vertex_positions,
|
||||
path_b_vertex_positions).unwrap().start as u32;
|
||||
IndexRange::from_data(&mut b_vertex_path_ids, path_b_vertex_path_ids).unwrap();
|
||||
|
||||
let mut path_b_quads = partitioner.b_quads().to_vec();
|
||||
let mut path_cover_interior_indices = cover_indices.interior_indices.to_vec();
|
||||
let mut path_cover_curve_indices = cover_indices.curve_indices.to_vec();
|
||||
let mut path_edge_upper_line_indices = edge_indices.upper_line_indices.to_vec();
|
||||
let mut path_edge_upper_curve_indices = edge_indices.upper_curve_indices.to_vec();
|
||||
let mut path_edge_lower_line_indices = edge_indices.lower_line_indices.to_vec();
|
||||
let mut path_edge_lower_curve_indices = edge_indices.lower_curve_indices.to_vec();
|
||||
|
||||
for path_b_quad in &mut path_b_quads {
|
||||
path_b_quad.offset(positions_start);
|
||||
}
|
||||
for path_cover_interior_index in &mut path_cover_interior_indices {
|
||||
*path_cover_interior_index += positions_start
|
||||
}
|
||||
for path_cover_curve_index in &mut path_cover_curve_indices {
|
||||
*path_cover_curve_index += positions_start
|
||||
}
|
||||
for path_edge_upper_line_indices in &mut path_edge_upper_line_indices {
|
||||
path_edge_upper_line_indices.offset(positions_start);
|
||||
}
|
||||
for path_edge_upper_curve_indices in &mut path_edge_upper_curve_indices {
|
||||
path_edge_upper_curve_indices.offset(positions_start);
|
||||
}
|
||||
for path_edge_lower_line_indices in &mut path_edge_lower_line_indices {
|
||||
path_edge_lower_line_indices.offset(positions_start);
|
||||
}
|
||||
for path_edge_lower_curve_indices in &mut path_edge_lower_curve_indices {
|
||||
path_edge_lower_curve_indices.offset(positions_start);
|
||||
}
|
||||
|
||||
glyph_info.push(PartitionGlyphInfo {
|
||||
id: glyph_id,
|
||||
id: glyph.id,
|
||||
dimensions: dimensions,
|
||||
bQuadIndices: IndexRange::from_vector_append_and_serialization(&mut b_quads,
|
||||
path_b_quads).unwrap(),
|
||||
bVertexIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut b_vertex_loop_blinn_data,
|
||||
bQuadIndices: IndexRange::from_data(&mut b_quads, &path_b_quads).unwrap(),
|
||||
bVertexIndices: IndexRange::from_data(&mut b_vertex_loop_blinn_data,
|
||||
path_b_vertex_loop_blinn_data).unwrap(),
|
||||
coverInteriorIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut cover_interior_indices,
|
||||
cover_indices.interior_indices).unwrap(),
|
||||
coverCurveIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut cover_curve_indices,
|
||||
cover_indices.curve_indices).unwrap(),
|
||||
edgeUpperLineIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut edge_upper_line_indices,
|
||||
edge_indices.upper_line_indices).unwrap(),
|
||||
edgeUpperCurveIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut edge_upper_curve_indices,
|
||||
edge_indices.upper_curve_indices).unwrap(),
|
||||
edgeLowerLineIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut edge_lower_line_indices,
|
||||
edge_indices.lower_line_indices).unwrap(),
|
||||
edgeLowerCurveIndices: IndexRange::from_vector_append_and_serialization(
|
||||
&mut edge_lower_curve_indices,
|
||||
edge_indices.lower_curve_indices).unwrap(),
|
||||
coverInteriorIndices: IndexRange::from_data(&mut cover_interior_indices,
|
||||
&path_cover_interior_indices).unwrap(),
|
||||
coverCurveIndices: IndexRange::from_data(&mut cover_curve_indices,
|
||||
&path_cover_curve_indices).unwrap(),
|
||||
edgeUpperLineIndices: IndexRange::from_data(&mut edge_upper_line_indices,
|
||||
&path_edge_upper_line_indices).unwrap(),
|
||||
edgeUpperCurveIndices: IndexRange::from_data(&mut edge_upper_curve_indices,
|
||||
&path_edge_upper_curve_indices).unwrap(),
|
||||
edgeLowerLineIndices: IndexRange::from_data(&mut edge_lower_line_indices,
|
||||
&path_edge_lower_line_indices).unwrap(),
|
||||
edgeLowerCurveIndices: IndexRange::from_data(&mut edge_lower_curve_indices,
|
||||
&path_edge_lower_curve_indices).unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ extern crate log;
|
|||
extern crate env_logger;
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::{Point2D, Size2D};
|
||||
use euclid::{Point2D, Size2D, Transform2D};
|
||||
use freetype_sys::{FT_BBox, FT_Done_Face, FT_F26Dot6, FT_Face, FT_GLYPH_FORMAT_OUTLINE};
|
||||
use freetype_sys::{FT_GlyphSlot, FT_Init_FreeType, FT_Int32, FT_LOAD_TARGET_LIGHT, FT_Library};
|
||||
use freetype_sys::{FT_Load_Glyph, FT_Long, FT_New_Memory_Face, FT_Outline_Get_CBox};
|
||||
|
@ -93,13 +93,15 @@ impl FontContext {
|
|||
pub fn push_glyph_outline(&self,
|
||||
font_instance: &FontInstanceKey,
|
||||
glyph_key: &GlyphKey,
|
||||
glyph_outline_buffer: &mut GlyphOutlineBuffer)
|
||||
glyph_outline_buffer: &mut GlyphOutlineBuffer,
|
||||
transform: &Transform2D<f32>)
|
||||
-> Result<(), ()> {
|
||||
self.load_glyph(font_instance, glyph_key).ok_or(()).map(|glyph_slot| {
|
||||
self.push_glyph_outline_from_glyph_slot(font_instance,
|
||||
glyph_key,
|
||||
glyph_slot,
|
||||
glyph_outline_buffer)
|
||||
glyph_outline_buffer,
|
||||
transform)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -111,7 +113,8 @@ impl FontContext {
|
|||
};
|
||||
|
||||
unsafe {
|
||||
FT_Set_Char_Size(face.face, font_instance.size.to_ft_f26dot6(), 0, 0, 0);
|
||||
let point_size = (font_instance.size.to_f64_px() / 72.0).to_ft_f26dot6();
|
||||
FT_Set_Char_Size(face.face, point_size, 0, 72, 0);
|
||||
|
||||
if FT_Load_Glyph(face.face, glyph_key.glyph_index as FT_UInt, GLYPH_LOAD_FLAGS) != 0 {
|
||||
return None
|
||||
|
@ -174,7 +177,8 @@ impl FontContext {
|
|||
_: &FontInstanceKey,
|
||||
_: &GlyphKey,
|
||||
glyph_slot: FT_GlyphSlot,
|
||||
glyph_outline_buffer: &mut GlyphOutlineBuffer) {
|
||||
glyph_outline_buffer: &mut GlyphOutlineBuffer,
|
||||
transform: &Transform2D<f32>) {
|
||||
unsafe {
|
||||
let outline = &(*glyph_slot).outline;
|
||||
let mut first_point_index = 0 as u32;
|
||||
|
@ -189,7 +193,8 @@ impl FontContext {
|
|||
// FIXME(pcwalton): Does FreeType produce multiple consecutive off-curve points
|
||||
// in a row like raw TrueType does?
|
||||
let point = *outline.points.offset(point_index as isize);
|
||||
let point_position = Point2D::new(point.x as f32, point.y as f32);
|
||||
let point_position = transform.transform_point(&Point2D::new(point.x as f32,
|
||||
point.y as f32));
|
||||
if (*outline.tags.offset(point_index as isize) & FREETYPE_POINT_ON_CURVE) != 0 {
|
||||
glyph_outline_buffer.endpoints.push(Endpoint {
|
||||
position: point_position,
|
||||
|
@ -303,8 +308,14 @@ trait ToFtF26Dot6 {
|
|||
fn to_ft_f26dot6(&self) -> FT_F26Dot6;
|
||||
}
|
||||
|
||||
impl ToFtF26Dot6 for f64 {
|
||||
fn to_ft_f26dot6(&self) -> FT_F26Dot6 {
|
||||
(*self * 64.0 + 0.5) as FT_F26Dot6
|
||||
}
|
||||
}
|
||||
|
||||
impl ToFtF26Dot6 for Au {
|
||||
fn to_ft_f26dot6(&self) -> FT_F26Dot6 {
|
||||
(self.to_f64_px() * 64.0 + 0.5) as FT_F26Dot6
|
||||
self.to_f64_px().to_ft_f26dot6()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,20 @@ impl BQuad {
|
|||
pad1: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&mut self, delta: u32) {
|
||||
self.upper_left_vertex_index += delta;
|
||||
self.upper_right_vertex_index += delta;
|
||||
self.lower_left_vertex_index += delta;
|
||||
self.lower_right_vertex_index += delta;
|
||||
if self.upper_control_point_vertex_index < u32::MAX {
|
||||
self.upper_control_point_vertex_index += delta;
|
||||
}
|
||||
if self.lower_control_point_vertex_index < u32::MAX {
|
||||
self.lower_control_point_vertex_index += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -145,6 +159,12 @@ impl LineIndices {
|
|||
right_vertex_index: right_vertex_index,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&mut self, delta: u32) {
|
||||
self.left_vertex_index += delta;
|
||||
self.right_vertex_index += delta;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
|
@ -167,4 +187,13 @@ impl CurveIndices {
|
|||
pad: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&mut self, delta: u32) {
|
||||
self.left_vertex_index += delta;
|
||||
self.right_vertex_index += delta;
|
||||
if self.control_point_vertex_index < u32::MAX {
|
||||
self.control_point_vertex_index += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue