Encode path IDs using a sparse representation, not a dense one.

This reduces the size of serialized mesh libraries. It also makes it
much easier to expand meshes and select individual paths for rendering.
This commit is contained in:
Patrick Walton 2017-11-02 11:14:45 -07:00
parent c767141169
commit 572b7cdd4a
5 changed files with 499 additions and 282 deletions

View File

@ -11,13 +11,25 @@
import * as base64js from 'base64-js';
import * as _ from 'lodash';
import {expectNotNull, FLOAT32_SIZE, panic, PathfinderError, UINT16_SIZE} from './utils';
import {UINT32_MAX, UINT32_SIZE} from './utils';
import {expectNotNull, FLOAT32_SIZE, panic, PathfinderError, Range, UINT16_SIZE} from './utils';
import {UINT32_MAX, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils';
interface BufferTypeFourCCTable {
[fourCC: string]: keyof Meshes<void>;
}
interface PathRangeTypeFourCCTable {
[fourCC: string]: keyof PathRanges;
}
interface RangeToCountTable {
[rangeKey: string]: keyof MeshDataCounts;
}
interface RangeToRangeBufferTable {
[rangeKey: string]: keyof Meshes<void>;
}
interface ArrayLike<T> {
[index: number]: T;
}
@ -62,6 +74,17 @@ export const B_QUAD_LOWER_INDICES_OFFSET: number = B_QUAD_LOWER_LEFT_VERTEX_OFFS
const B_QUAD_FIELD_COUNT: number = B_QUAD_SIZE / UINT32_SIZE;
// FIXME(pcwalton): This duplicates information below in `MESH_TYPES`.
const INDEX_SIZE: number = 4;
const B_VERTEX_POSITION_SIZE: number = 4 * 2;
const EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE: number = 4 * 4;
const EDGE_UPPER_LINE_VERTEX_POSITION_SIZE: number = 4 * 4;
const EDGE_LOWER_LINE_VERTEX_POSITION_SIZE: number = 4 * 4;
const EDGE_UPPER_CURVE_VERTEX_POSITION_SIZE: number = 4 * 6;
const EDGE_LOWER_CURVE_VERTEX_POSITION_SIZE: number = 4 * 6;
const SEGMENT_LINE_SIZE: number = 4 * 4;
const SEGMENT_CURVE_SIZE: number = 4 * 6;
const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
bQuads: { type: 'Uint32', size: B_QUAD_FIELD_COUNT },
bVertexLoopBlinnData: { type: 'Uint32', size: 1 },
@ -125,82 +148,140 @@ const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
bqua: 'bQuads',
bvlb: 'bVertexLoopBlinnData',
bvno: 'bVertexNormals',
bvpi: 'bVertexPathIDs',
bvpo: 'bVertexPositions',
cvci: 'coverCurveIndices',
cvii: 'coverInteriorIndices',
ebbp: 'edgeBoundingBoxPathIDs',
ebbv: 'edgeBoundingBoxVertexPositions',
elcp: 'edgeLowerCurvePathIDs',
elcv: 'edgeLowerCurveVertexPositions',
ellp: 'edgeLowerLinePathIDs',
ellv: 'edgeLowerLineVertexPositions',
eucp: 'edgeUpperCurvePathIDs',
eucv: 'edgeUpperCurveVertexPositions',
eulp: 'edgeUpperLinePathIDs',
eulv: 'edgeUpperLineVertexPositions',
scpi: 'segmentCurvePathIDs',
scur: 'segmentCurves',
slin: 'segmentLines',
slpi: 'segmentLinePathIDs',
sncu: 'segmentCurveNormals',
snli: 'segmentLineNormals',
};
// Must match the FourCCs in
// `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`.
const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
bqua: 'bQuadPathRanges',
bver: 'bVertexPathRanges',
cvci: 'coverCurveIndexRanges',
cvii: 'coverInteriorIndexRanges',
ebbo: 'edgeBoundingBoxRanges',
elci: 'edgeLowerCurveIndexRanges',
elli: 'edgeLowerLineIndexRanges',
euci: 'edgeUpperCurveIndexRanges',
euli: 'edgeUpperLineIndexRanges',
scur: 'segmentCurveRanges',
slin: 'segmentLineRanges',
};
const RANGE_TO_COUNT_TABLE: RangeToCountTable = {
bQuadPathRanges: 'bQuadCount',
bVertexPathRanges: 'bVertexCount',
coverCurveIndexRanges: 'coverCurveCount',
coverInteriorIndexRanges: 'coverInteriorCount',
edgeBoundingBoxRanges: 'edgeBoundingBoxCount',
edgeLowerCurveIndexRanges: 'edgeLowerCurveCount',
edgeLowerLineIndexRanges: 'edgeLowerLineCount',
edgeUpperCurveIndexRanges: 'edgeUpperCurveCount',
edgeUpperLineIndexRanges: 'edgeUpperLineCount',
segmentCurveRanges: 'segmentCurveCount',
segmentLineRanges: 'segmentLineCount',
};
const RANGE_TO_RANGE_BUFFER_TABLE: RangeToRangeBufferTable = {
bVertexPathRanges: 'bVertexPathIDs',
edgeBoundingBoxRanges: 'edgeBoundingBoxPathIDs',
edgeLowerCurveIndexRanges: 'edgeLowerCurvePathIDs',
edgeLowerLineIndexRanges: 'edgeLowerLinePathIDs',
edgeUpperCurveIndexRanges: 'edgeUpperCurvePathIDs',
edgeUpperLineIndexRanges: 'edgeUpperLinePathIDs',
segmentCurveRanges: 'segmentCurvePathIDs',
segmentLineRanges: 'segmentLinePathIDs',
};
type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
export interface Meshes<T> {
readonly bQuads: T;
readonly bVertexPositions: T;
readonly bVertexPathIDs: T;
readonly bVertexLoopBlinnData: T;
readonly bVertexNormals: T;
readonly coverInteriorIndices: T;
readonly coverCurveIndices: T;
readonly edgeBoundingBoxPathIDs: T;
readonly edgeBoundingBoxVertexPositions: T;
readonly edgeLowerCurvePathIDs: T;
readonly edgeLowerCurveVertexPositions: T;
readonly edgeLowerLinePathIDs: T;
readonly edgeLowerLineVertexPositions: T;
readonly edgeUpperCurvePathIDs: T;
readonly edgeUpperCurveVertexPositions: T;
readonly edgeUpperLinePathIDs: T;
readonly edgeUpperLineVertexPositions: T;
readonly segmentLines: T;
readonly segmentCurves: T;
readonly segmentLinePathIDs: T;
readonly segmentCurvePathIDs: T;
readonly segmentLineNormals: T;
readonly segmentCurveNormals: T;
bVertexPathIDs: T;
edgeBoundingBoxPathIDs: T;
segmentLinePathIDs: T;
segmentCurvePathIDs: T;
edgeLowerCurvePathIDs: T;
edgeLowerLinePathIDs: T;
edgeUpperCurvePathIDs: T;
edgeUpperLinePathIDs: T;
}
export class PathfinderMeshData implements Meshes<ArrayBuffer> {
interface MeshDataCounts {
readonly bQuadCount: number;
readonly bVertexCount: number;
readonly coverCurveCount: number;
readonly coverInteriorCount: number;
readonly edgeBoundingBoxCount: number;
readonly edgeLowerCurveCount: number;
readonly edgeUpperCurveCount: number;
readonly edgeLowerLineCount: number;
readonly edgeUpperLineCount: number;
readonly segmentLineCount: number;
readonly segmentCurveCount: number;
}
interface PathRanges {
bQuadPathRanges: Range[];
bVertexPathRanges: Range[];
coverInteriorIndexRanges: Range[];
coverCurveIndexRanges: Range[];
edgeBoundingBoxRanges: Range[];
edgeUpperLineIndexRanges: Range[];
edgeUpperCurveIndexRanges: Range[];
edgeLowerLineIndexRanges: Range[];
edgeLowerCurveIndexRanges: Range[];
segmentCurveRanges: Range[];
segmentLineRanges: Range[];
}
export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts, PathRanges {
readonly bQuads: ArrayBuffer;
readonly bVertexPositions: ArrayBuffer;
readonly bVertexPathIDs: ArrayBuffer;
readonly bVertexLoopBlinnData: ArrayBuffer;
readonly bVertexNormals: ArrayBuffer;
readonly coverInteriorIndices: ArrayBuffer;
readonly coverCurveIndices: ArrayBuffer;
readonly edgeBoundingBoxPathIDs: ArrayBuffer;
readonly edgeBoundingBoxVertexPositions: ArrayBuffer;
readonly edgeLowerCurvePathIDs: ArrayBuffer;
readonly edgeLowerCurveVertexPositions: ArrayBuffer;
readonly edgeLowerLinePathIDs: ArrayBuffer;
readonly edgeLowerLineVertexPositions: ArrayBuffer;
readonly edgeUpperCurvePathIDs: ArrayBuffer;
readonly edgeUpperCurveVertexPositions: ArrayBuffer;
readonly edgeUpperLinePathIDs: ArrayBuffer;
readonly edgeUpperLineVertexPositions: ArrayBuffer;
readonly segmentLines: ArrayBuffer;
readonly segmentCurves: ArrayBuffer;
readonly segmentLinePathIDs: ArrayBuffer;
readonly segmentCurvePathIDs: ArrayBuffer;
readonly segmentLineNormals: ArrayBuffer;
readonly segmentCurveNormals: ArrayBuffer;
readonly bQuadCount: number;
readonly bVertexCount: number;
readonly coverCurveCount: number;
readonly coverInteriorCount: number;
readonly edgeBoundingBoxCount: number;
readonly edgeLowerCurveCount: number;
readonly edgeUpperCurveCount: number;
readonly edgeLowerLineCount: number;
@ -208,7 +289,28 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer> {
readonly segmentLineCount: number;
readonly segmentCurveCount: number;
constructor(meshes: ArrayBuffer | Meshes<ArrayBuffer>) {
bVertexPathIDs: ArrayBuffer;
edgeBoundingBoxPathIDs: ArrayBuffer;
edgeLowerCurvePathIDs: ArrayBuffer;
edgeLowerLinePathIDs: ArrayBuffer;
edgeUpperCurvePathIDs: ArrayBuffer;
edgeUpperLinePathIDs: ArrayBuffer;
segmentCurvePathIDs: ArrayBuffer;
segmentLinePathIDs: ArrayBuffer;
bQuadPathRanges: Range[];
bVertexPathRanges: Range[];
coverInteriorIndexRanges: Range[];
coverCurveIndexRanges: Range[];
edgeBoundingBoxRanges: Range[];
edgeUpperLineIndexRanges: Range[];
edgeUpperCurveIndexRanges: Range[];
edgeLowerLineIndexRanges: Range[];
edgeLowerCurveIndexRanges: Range[];
segmentCurveRanges: Range[];
segmentLineRanges: Range[];
constructor(meshes: ArrayBuffer | Meshes<ArrayBuffer>, optionalRanges?: PathRanges) {
if (meshes instanceof ArrayBuffer) {
// RIFF encoded data.
if (toFourCC(meshes, 0) !== RIFF_FOURCC)
@ -219,26 +321,44 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer> {
let offset = 12;
while (offset < meshes.byteLength) {
const fourCC = toFourCC(meshes, offset);
const chunkLength = (new Uint32Array(meshes.slice(offset + 4, offset + 8)))[0];
if (BUFFER_TYPE_FOURCCS.hasOwnProperty(fourCC)) {
const startOffset = offset + 8;
const endOffset = startOffset + chunkLength;
const chunkLength = readUInt32(meshes, offset + 4);
const startOffset = offset + 8;
const endOffset = startOffset + chunkLength;
if (BUFFER_TYPE_FOURCCS.hasOwnProperty(fourCC))
this[BUFFER_TYPE_FOURCCS[fourCC]] = meshes.slice(startOffset, endOffset);
}
offset += chunkLength + 8;
else if (fourCC === 'prng')
this.readPathRanges(meshes.slice(startOffset, endOffset));
offset = endOffset;
}
} else {
for (const bufferName of Object.keys(BUFFER_TYPES) as Array<keyof Meshes<void>>)
this[bufferName] = meshes[bufferName];
const ranges = unwrapUndef(optionalRanges);
for (const range of Object.keys(RANGE_TO_COUNT_TABLE) as Array<keyof PathRanges>)
this[range] = ranges[range];
}
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
this.edgeUpperLineCount = this.edgeUpperLinePathIDs.byteLength / 2;
this.edgeLowerLineCount = this.edgeLowerLinePathIDs.byteLength / 2;
this.edgeUpperCurveCount = this.edgeUpperCurvePathIDs.byteLength / 2;
this.edgeLowerCurveCount = this.edgeLowerCurvePathIDs.byteLength / 2;
this.segmentCurveCount = this.segmentCurvePathIDs.byteLength / 2;
this.segmentLineCount = this.segmentLinePathIDs.byteLength / 2;
this.bVertexCount = this.bVertexPositions.byteLength / B_VERTEX_POSITION_SIZE;
this.coverCurveCount = this.coverCurveIndices.byteLength / INDEX_SIZE;
this.coverInteriorCount = this.coverInteriorIndices.byteLength / INDEX_SIZE;
this.edgeBoundingBoxCount = this.edgeBoundingBoxVertexPositions.byteLength /
EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE;
this.edgeUpperLineCount = this.edgeUpperLineVertexPositions.byteLength /
EDGE_UPPER_LINE_VERTEX_POSITION_SIZE;
this.edgeLowerLineCount = this.edgeLowerLineVertexPositions.byteLength /
EDGE_LOWER_LINE_VERTEX_POSITION_SIZE;
this.edgeUpperCurveCount = this.edgeUpperCurveVertexPositions.byteLength /
EDGE_UPPER_CURVE_VERTEX_POSITION_SIZE;
this.edgeLowerCurveCount = this.edgeLowerCurveVertexPositions.byteLength /
EDGE_LOWER_CURVE_VERTEX_POSITION_SIZE;
this.segmentCurveCount = this.segmentCurves.byteLength / SEGMENT_CURVE_SIZE;
this.segmentLineCount = this.segmentLines.byteLength / SEGMENT_LINE_SIZE;
this.rebuildPathIDBuffers();
}
expand(pathIDs: number[]): PathfinderMeshData {
@ -249,20 +369,34 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer> {
tempExpandedArrays[key] = [];
}
const tempOriginalRanges: Partial<PathRanges> = {};
const tempExpandedRanges: Partial<PathRanges> = {};
for (const key of Object.keys(RANGE_TO_COUNT_TABLE) as Array<keyof PathRanges>) {
tempOriginalRanges[key] = this[key];
const newExpandedRanges = [];
for (const newPathID of pathIDs)
newExpandedRanges.push(new Range(0, 0));
tempExpandedRanges[key] = newExpandedRanges;
}
const originalBuffers: Meshes<PrimitiveTypeArray> = tempOriginalBuffers;
const originalRanges: PathRanges = tempOriginalRanges as PathRanges;
const expandedArrays: Meshes<number[]> = tempExpandedArrays;
const expandedRanges: PathRanges = tempExpandedRanges as PathRanges;
for (let newPathIndex = 0; newPathIndex < pathIDs.length; newPathIndex++) {
const expandedPathID = newPathIndex + 1;
const originalPathID = pathIDs[newPathIndex];
const bVertexCopyResult =
copyVertices(['bVertexPositions', 'bVertexLoopBlinnData'],
'bVertexPathIDs',
expandedArrays,
originalBuffers,
expandedPathID,
originalPathID);
const bVertexCopyResult = copyVertices(['bVertexPositions', 'bVertexLoopBlinnData'],
'bVertexPathRanges',
expandedArrays,
expandedRanges,
originalBuffers,
originalRanges,
expandedPathID,
originalPathID);
if (bVertexCopyResult == null)
continue;
@ -273,31 +407,39 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer> {
// Copy over edge data.
copyVertices(['edgeBoundingBoxVertexPositions'],
'edgeBoundingBoxPathIDs',
'edgeBoundingBoxRanges',
expandedArrays,
expandedRanges,
originalBuffers,
originalRanges,
expandedPathID,
originalPathID);
for (const edgeBufferName of EDGE_BUFFER_NAMES) {
copyVertices([`edge${edgeBufferName}VertexPositions` as keyof Meshes<void>],
`edge${edgeBufferName}PathIDs` as keyof Meshes<void>,
`edge${edgeBufferName}IndexRanges` as keyof PathRanges,
expandedArrays,
expandedRanges,
originalBuffers,
originalRanges,
expandedPathID,
originalPathID);
}
// Copy over indices.
copyIndices(expandedArrays.coverInteriorIndices,
expandedRanges.coverInteriorIndexRanges,
originalBuffers.coverInteriorIndices as Uint32Array,
firstExpandedBVertexIndex,
firstBVertexIndex,
lastBVertexIndex);
lastBVertexIndex,
expandedPathID);
copyIndices(expandedArrays.coverCurveIndices,
expandedRanges.coverCurveIndexRanges,
originalBuffers.coverCurveIndices as Uint32Array,
firstExpandedBVertexIndex,
firstBVertexIndex,
lastBVertexIndex);
lastBVertexIndex,
expandedPathID);
// Copy over B-quads.
let firstBQuadIndex =
@ -329,15 +471,19 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer> {
// Copy over segments.
copySegments(['segmentLines', 'segmentLineNormals'],
'segmentLinePathIDs',
'segmentLineRanges',
expandedArrays,
expandedRanges,
originalBuffers,
originalRanges,
expandedPathID,
originalPathID);
copySegments(['segmentCurves', 'segmentCurveNormals'],
'segmentCurvePathIDs',
'segmentCurveRanges',
expandedArrays,
expandedRanges,
originalBuffers,
originalRanges,
expandedPathID,
originalPathID);
}
@ -353,7 +499,48 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer> {
}
const expandedBuffers = tempExpandedBuffers as Meshes<ArrayBuffer>;
return new PathfinderMeshData(expandedBuffers);
return new PathfinderMeshData(expandedBuffers, expandedRanges);
}
private readPathRanges(meshes: ArrayBuffer): void {
let offset = 0;
while (offset < meshes.byteLength) {
const fourCC = toFourCC(meshes, offset);
const chunkLength = readUInt32(meshes, offset + 4);
const startOffset = offset + 8;
const endOffset = startOffset + chunkLength;
if (PATH_RANGE_TYPE_FOURCCS.hasOwnProperty(fourCC)) {
const key = PATH_RANGE_TYPE_FOURCCS[fourCC];
const ranges = new Uint32Array(meshes.slice(startOffset, endOffset));
this[key] = _.chunk(ranges, 2).map(range => new Range(range[0], range[1]));
}
offset = endOffset;
}
}
private rebuildPathIDBuffers(): void {
for (const rangeKey of Object.keys(RANGE_TO_COUNT_TABLE) as
Array<keyof RangeToCountTable>) {
if (!RANGE_TO_RANGE_BUFFER_TABLE.hasOwnProperty(rangeKey))
continue;
const count = this[RANGE_TO_COUNT_TABLE[rangeKey]];
const ranges = this[rangeKey as keyof PathRanges];
const destBuffer = new Uint16Array(count);
let destIndex = 0;
for (let pathIndex = 0; pathIndex < ranges.length; pathIndex++) {
const range = ranges[pathIndex];
for (let subindex = range.start; subindex < range.end; subindex++) {
destBuffer[destIndex] = pathIndex + 1;
destIndex++;
}
}
(this as any)[RANGE_TO_RANGE_BUFFER_TABLE[rangeKey]] = destBuffer;
}
}
}
@ -383,7 +570,7 @@ export class PathfinderMeshBuffers implements Meshes<WebGLBuffer> {
readonly segmentCurveNormals: WebGLBuffer;
constructor(gl: WebGLRenderingContext, meshData: PathfinderMeshData) {
for (const bufferName of Object.keys(BUFFER_TYPES) as Array<keyof PathfinderMeshBuffers>) {
for (const bufferName of Object.keys(BUFFER_TYPES) as Array<keyof Meshes<void>>) {
const bufferType = gl[BUFFER_TYPES[bufferName]];
const buffer = expectNotNull(gl.createBuffer(), "Failed to create buffer!");
gl.bindBuffer(bufferType, buffer);
@ -394,62 +581,66 @@ export class PathfinderMeshBuffers implements Meshes<WebGLBuffer> {
}
function copyVertices(vertexBufferNames: Array<keyof Meshes<void>>,
pathIDBufferName: keyof Meshes<void>,
rangesName: keyof PathRanges,
expandedMeshes: Meshes<number[]>,
expandedRanges: PathRanges,
originalMeshes: Meshes<PrimitiveTypeArray>,
originalRanges: PathRanges,
expandedPathID: number,
originalPathID: number):
VertexCopyResult | null {
const expandedPathIDs = expandedMeshes[pathIDBufferName];
const originalPathIDs = originalMeshes[pathIDBufferName];
const originalRange = originalRanges[rangesName][originalPathID - 1];
const firstOriginalVertexIndex = _.sortedIndex(originalPathIDs, originalPathID);
if (firstOriginalVertexIndex < 0)
return null;
const firstExpandedVertexIndex = _.reduce(expandedRanges[rangesName],
(maxIndex, range) => Math.max(maxIndex, range.end),
0);
const firstExpandedVertexIndex = expandedPathIDs.length;
let lastOriginalVertexIndex = firstOriginalVertexIndex;
while (lastOriginalVertexIndex < originalPathIDs.length &&
originalPathIDs[lastOriginalVertexIndex] === originalPathID) {
for (let originalVertexIndex = originalRange.start;
originalVertexIndex < originalRange.end;
originalVertexIndex++) {
for (const vertexBufferName of vertexBufferNames) {
const expanded = expandedMeshes[vertexBufferName];
const original = originalMeshes[vertexBufferName];
const size = MESH_TYPES[vertexBufferName].size;
for (let elementIndex = 0; elementIndex < size; elementIndex++) {
const globalIndex = size * lastOriginalVertexIndex + elementIndex;
const globalIndex = size * originalVertexIndex + elementIndex;
expanded.push(original[globalIndex]);
}
}
expandedPathIDs.push(expandedPathID);
lastOriginalVertexIndex++;
}
const lastExpandedVertexIndex = firstExpandedVertexIndex + originalRange.length;
expandedRanges[rangesName][expandedPathID - 1] = new Range(firstExpandedVertexIndex,
lastExpandedVertexIndex);
return {
expandedEndIndex: expandedPathIDs.length,
expandedEndIndex: lastExpandedVertexIndex,
expandedStartIndex: firstExpandedVertexIndex,
originalEndIndex: lastOriginalVertexIndex,
originalStartIndex: firstOriginalVertexIndex,
originalEndIndex: originalRange.end,
originalStartIndex: originalRange.start,
};
}
function copyIndices(destIndices: number[],
destRanges: Range[],
srcIndices: Uint32Array,
firstExpandedIndex: number,
firstIndex: number,
lastIndex: number,
expandedPathID: number,
validateIndex?: (indexIndex: number) => boolean) {
if (firstIndex === lastIndex)
return;
// FIXME(pcwalton): Speed this up somehow.
// FIXME(pcwalton): Speed this up using the original ranges.
let indexIndex = srcIndices.findIndex(index => index >= firstIndex && index < lastIndex);
if (indexIndex < 0)
return;
const firstDestIndex = destIndices.length;
const indexDelta = firstExpandedIndex - firstIndex;
while (indexIndex < srcIndices.length) {
const index = srcIndices[indexIndex];
if (validateIndex == null || validateIndex(indexIndex)) {
@ -459,33 +650,47 @@ function copyIndices(destIndices: number[],
} else {
destIndices.push(index);
}
indexIndex++;
}
const lastDestIndex = destIndices.length;
destRanges[expandedPathID + 1] = new Range(firstExpandedIndex, lastDestIndex - firstDestIndex);
}
function copySegments(segmentBufferNames: Array<keyof Meshes<void>>,
pathIDBufferName: keyof Meshes<void>,
rangesName: keyof PathRanges,
expandedMeshes: Meshes<number[]>,
expandedRanges: PathRanges,
originalMeshes: Meshes<PrimitiveTypeArray>,
originalRanges: PathRanges,
expandedPathID: number,
originalPathID: number):
void {
let segmentIndex = _.indexOf(originalMeshes[pathIDBufferName] as Uint16Array, originalPathID);
while (segmentIndex < originalMeshes[pathIDBufferName].length) {
if (originalMeshes[pathIDBufferName][segmentIndex] !== originalPathID)
break;
const originalRange = originalRanges[rangesName][originalPathID - 1];
const firstExpandedSegmentIndex = _.reduce(expandedRanges[rangesName],
(maxIndex, range) => Math.max(maxIndex, range.end),
0);
for (let originalSegmentIndex = originalRange.start;
originalSegmentIndex < originalRange.end;
originalSegmentIndex++) {
for (const segmentBufferName of segmentBufferNames) {
if (originalMeshes[segmentBufferName].length === 0)
continue;
const size = MESH_TYPES[segmentBufferName].size;
for (let fieldIndex = 0; fieldIndex < size; fieldIndex++) {
const srcIndex = size * segmentIndex + fieldIndex;
const srcIndex = size * originalSegmentIndex + fieldIndex;
expandedMeshes[segmentBufferName].push(originalMeshes[segmentBufferName][srcIndex]);
}
}
expandedMeshes[pathIDBufferName].push(expandedPathID);
segmentIndex++;
}
const lastExpandedSegmentIndex = firstExpandedSegmentIndex + originalRange.length;
expandedRanges[rangesName][expandedPathID - 1] = new Range(firstExpandedSegmentIndex,
lastExpandedSegmentIndex);
}
function sizeOfPrimitive(primitiveType: PrimitiveType): number {
@ -523,3 +728,7 @@ export function parseServerTiming(headers: Headers): number {
const matches = /^Partitioning\s*=\s*([0-9.]+)$/.exec(timing);
return matches != null ? parseFloat(matches[1]) / 1000.0 : 0.0;
}
function readUInt32(buffer: ArrayBuffer, offset: number): number {
return (new Uint32Array(buffer.slice(offset, offset + 4)))[0];
}

View File

@ -426,27 +426,14 @@ class TextDemoRenderer extends TextRenderer {
// Set up the composite VAO.
const blitProgram = this.renderContext.shaderPrograms.blit;
const attributes = blitProgram.attributes;
this.renderContext.gl.useProgram(blitProgram.program);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ARRAY_BUFFER,
this.glyphPositionsBuffer);
this.renderContext.gl.vertexAttribPointer(attributes.aPosition,
2,
this.renderContext.gl.FLOAT,
false,
0,
0);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ARRAY_BUFFER,
this.glyphTexCoordsBuffer);
this.renderContext.gl.vertexAttribPointer(attributes.aTexCoord,
2,
this.renderContext.gl.FLOAT,
false,
0,
0);
this.renderContext.gl.enableVertexAttribArray(attributes.aPosition);
this.renderContext.gl.enableVertexAttribArray(attributes.aTexCoord);
this.renderContext.gl.bindBuffer(this.renderContext.gl.ELEMENT_ARRAY_BUFFER,
this.glyphElementsBuffer);
gl.useProgram(blitProgram.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.glyphPositionsBuffer);
gl.vertexAttribPointer(attributes.aPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.glyphTexCoordsBuffer);
gl.vertexAttribPointer(attributes.aTexCoord, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(attributes.aPosition);
gl.enableVertexAttribArray(attributes.aTexCoord);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.glyphElementsBuffer);
// Create the transform.
const transform = glmatrix.mat4.create();
@ -461,22 +448,22 @@ class TextDemoRenderer extends TextRenderer {
[this.camera.translation[0], this.camera.translation[1], 0.0]);
// Blit.
this.renderContext.gl.uniformMatrix4fv(blitProgram.uniforms.uTransform, false, transform);
this.renderContext.gl.activeTexture(this.renderContext.gl.TEXTURE0);
gl.uniformMatrix4fv(blitProgram.uniforms.uTransform, false, transform);
gl.activeTexture(gl.TEXTURE0);
const destTexture = this.renderContext
.atlas
.ensureTexture(this.renderContext);
this.renderContext.gl.bindTexture(this.renderContext.gl.TEXTURE_2D, destTexture);
this.renderContext.gl.uniform1i(blitProgram.uniforms.uSource, 0);
gl.bindTexture(gl.TEXTURE_2D, destTexture);
gl.uniform1i(blitProgram.uniforms.uSource, 0);
this.setIdentityTexScaleUniform(blitProgram.uniforms);
const totalGlyphCount = this.layout.textFrame.totalGlyphCount;
this.renderContext.gl.drawElements(this.renderContext.gl.TRIANGLES,
totalGlyphCount * 6,
this.renderContext.gl.UNSIGNED_INT,
0);
gl.drawElements(gl.TRIANGLES, totalGlyphCount * 6, gl.UNSIGNED_INT, 0);
}
private layoutText(): void {
const renderContext = this.renderContext;
const gl = renderContext.gl;
this.layout.layoutRuns();
const textBounds = this.layout.textFrame.bounds;
@ -517,18 +504,12 @@ class TextDemoRenderer extends TextRenderer {
}
}
this.glyphPositionsBuffer = unwrapNull(this.renderContext.gl.createBuffer());
this.renderContext.gl.bindBuffer(this.renderContext.gl.ARRAY_BUFFER,
this.glyphPositionsBuffer);
this.renderContext.gl.bufferData(this.renderContext.gl.ARRAY_BUFFER,
glyphPositions,
this.renderContext.gl.STATIC_DRAW);
this.glyphElementsBuffer = unwrapNull(this.renderContext.gl.createBuffer());
this.renderContext.gl.bindBuffer(this.renderContext.gl.ELEMENT_ARRAY_BUFFER,
this.glyphElementsBuffer);
this.renderContext.gl.bufferData(this.renderContext.gl.ELEMENT_ARRAY_BUFFER,
glyphIndices,
this.renderContext.gl.STATIC_DRAW);
this.glyphPositionsBuffer = unwrapNull(gl.createBuffer());
gl.bindBuffer(gl.ARRAY_BUFFER, this.glyphPositionsBuffer);
gl.bufferData(gl.ARRAY_BUFFER, glyphPositions, gl.STATIC_DRAW);
this.glyphElementsBuffer = unwrapNull(gl.createBuffer());
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.glyphElementsBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, glyphIndices, gl.STATIC_DRAW);
}
private buildGlyphs(): void {

View File

@ -100,17 +100,6 @@ pub unsafe extern fn pf_partitioner_b_vertex_positions<'a>(partitioner: *const P
b_vertex_positions.as_ptr() as *const Point2D<f32>
}
#[no_mangle]
pub unsafe extern fn pf_partitioner_b_vertex_path_ids<'a>(partitioner: *const Partitioner<'a>,
out_b_vertex_count: *mut u32)
-> *const u16 {
let b_vertex_path_ids = &(*partitioner).library().b_vertex_path_ids;
if !out_b_vertex_count.is_null() {
*out_b_vertex_count = b_vertex_path_ids.len() as u32
}
b_vertex_path_ids.as_ptr() as *const u16
}
#[no_mangle]
pub unsafe extern fn pf_partitioner_b_vertex_loop_blinn_data<'a>(
partitioner: *const Partitioner<'a>,

View File

@ -22,9 +22,9 @@ use {BQuad, BVertexLoopBlinnData};
#[derive(Debug, Clone)]
pub struct MeshLibrary {
pub path_ranges: Vec<PathRanges>,
pub b_quads: Vec<BQuad>,
pub b_vertex_positions: Vec<Point2D<f32>>,
pub b_vertex_path_ids: Vec<u16>,
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
pub b_vertex_normals: Vec<f32>,
pub cover_indices: MeshLibraryCoverIndices,
@ -37,9 +37,9 @@ impl MeshLibrary {
#[inline]
pub fn new() -> MeshLibrary {
MeshLibrary {
path_ranges: vec![],
b_quads: vec![],
b_vertex_positions: vec![],
b_vertex_path_ids: vec![],
b_vertex_loop_blinn_data: vec![],
b_vertex_normals: vec![],
cover_indices: MeshLibraryCoverIndices::new(),
@ -50,9 +50,9 @@ impl MeshLibrary {
}
pub fn clear(&mut self) {
self.path_ranges.clear();
self.b_quads.clear();
self.b_vertex_positions.clear();
self.b_vertex_path_ids.clear();
self.b_vertex_loop_blinn_data.clear();
self.b_vertex_normals.clear();
self.cover_indices.clear();
@ -61,13 +61,19 @@ impl MeshLibrary {
self.segment_normals.clear();
}
pub(crate) fn ensure_path_ranges(&mut self, path_id: u16) -> &mut PathRanges {
let path_index = (path_id as usize) - 1;
while path_index >= self.path_ranges.len() {
self.path_ranges.push(PathRanges::new())
}
&mut self.path_ranges[path_index]
}
pub(crate) fn add_b_vertex(&mut self,
position: &Point2D<f32>,
path_id: u16,
loop_blinn_data: &BVertexLoopBlinnData,
normal: f32) {
self.b_vertex_positions.push(*position);
self.b_vertex_path_ids.push(path_id);
self.b_vertex_loop_blinn_data.push(*loop_blinn_data);
self.b_vertex_normals.push(normal);
}
@ -75,8 +81,6 @@ impl MeshLibrary {
pub(crate) fn add_b_quad(&mut self, b_quad: &BQuad) {
self.b_quads.push(*b_quad);
let path_id = self.b_vertex_path_ids[b_quad.upper_left_vertex_index as usize];
let upper_left_position =
&self.b_vertex_positions[b_quad.upper_left_vertex_index as usize];
let upper_right_position =
@ -97,14 +101,12 @@ impl MeshLibrary {
upper_left: upper_left_bounding_box_position,
lower_right: lower_right_bounding_box_position,
});
self.edge_data.bounding_box_path_ids.push(path_id);
if b_quad.upper_control_point_vertex_index == u32::MAX {
self.edge_data.upper_line_vertex_positions.push(EdgeLineVertexPositions {
left: *upper_left_position,
right: *upper_right_position,
});
self.edge_data.upper_line_path_ids.push(path_id);
} else {
let upper_control_point_position =
&self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize];
@ -113,7 +115,6 @@ impl MeshLibrary {
control_point: *upper_control_point_position,
right: *upper_right_position,
});
self.edge_data.upper_curve_path_ids.push(path_id);
}
if b_quad.lower_control_point_vertex_index == u32::MAX {
@ -121,7 +122,6 @@ impl MeshLibrary {
left: *lower_left_position,
right: *lower_right_position,
});
self.edge_data.lower_line_path_ids.push(path_id);
} else {
let lower_control_point_position =
&self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize];
@ -130,7 +130,6 @@ impl MeshLibrary {
control_point: *lower_control_point_position,
right: *lower_right_position,
});
self.edge_data.lower_curve_path_ids.push(path_id);
}
}
@ -138,34 +137,27 @@ impl MeshLibrary {
///
/// This enables early Z optimizations.
pub fn optimize(&mut self) {
let mut new_cover_interior_indices =
let mut new_interior_indices =
Vec::with_capacity(self.cover_indices.interior_indices.len());
let mut last_cover_interior_index_index = self.cover_indices.interior_indices.len();
while last_cover_interior_index_index != 0 {
let mut first_cover_interior_index_index = last_cover_interior_index_index - 1;
let path_id =
self.b_vertex_path_ids[self.cover_indices
.interior_indices[first_cover_interior_index_index] as
usize];
while first_cover_interior_index_index != 0 {
let prev_path_id = self.b_vertex_path_ids[
self.cover_indices.interior_indices[first_cover_interior_index_index - 1] as
usize];
if prev_path_id != path_id {
break
}
first_cover_interior_index_index -= 1
}
let range = first_cover_interior_index_index..last_cover_interior_index_index;
new_cover_interior_indices.extend_from_slice(&self.cover_indices
.interior_indices[range]);
last_cover_interior_index_index = first_cover_interior_index_index;
for path_range in &mut self.path_ranges {
let old_interior_indices = &self.cover_indices.interior_indices[..];
let old_range = path_range.cover_interior_indices.clone();
let old_range = (old_range.start as usize)..(old_range.end as usize);
let new_start_index = new_interior_indices.len() as u32;
new_interior_indices.extend_from_slice(&old_interior_indices[old_range]);
let new_end_index = new_interior_indices.len() as u32;
path_range.cover_interior_indices = new_start_index..new_end_index;
}
self.cover_indices.interior_indices = new_cover_interior_indices
self.cover_indices.interior_indices = new_interior_indices
}
pub fn push_segments<I>(&mut self, path_id: u16, stream: I)
where I: Iterator<Item = PathCommand> {
let first_line_index = self.segments.lines.len() as u32;
let first_curve_index = self.segments.curves.len() as u32;
let stream = PathSegmentStream::new(stream);
for (segment, _) in stream {
match segment {
@ -174,7 +166,6 @@ impl MeshLibrary {
endpoint_0: endpoint_0,
endpoint_1: endpoint_1,
});
self.segments.line_path_ids.push(path_id);
}
PathSegment::Curve(endpoint_0, control_point, endpoint_1) => {
self.segments.curves.push(CurveSegment {
@ -182,10 +173,16 @@ impl MeshLibrary {
control_point: control_point,
endpoint_1: endpoint_1,
});
self.segments.curve_path_ids.push(path_id);
}
}
}
let last_line_index = self.segments.lines.len() as u32;
let last_curve_index = self.segments.curves.len() as u32;
let path_ranges = self.ensure_path_ranges(path_id);
path_ranges.segment_curves = first_curve_index..last_curve_index;
path_ranges.segment_lines = first_line_index..last_line_index;
}
/// Computes vertex normals necessary for emboldening and/or stem darkening.
@ -205,46 +202,36 @@ impl MeshLibrary {
// for us, this is guaranteed by construction because each instance of all of the data that
// we're writing has a byte size that is a multiple of 4. So we don't bother with doing it
// explicitly here.
try!(write_chunk(writer, b"bqua", &self.b_quads));
try!(write_chunk(writer, b"bvpo", &self.b_vertex_positions));
try!(write_chunk(writer, b"bvpi", &self.b_vertex_path_ids));
try!(write_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data));
try!(write_chunk(writer, b"bvno", &self.b_vertex_normals));
try!(write_chunk(writer, b"cvii", &self.cover_indices.interior_indices));
try!(write_chunk(writer, b"cvci", &self.cover_indices.curve_indices));
try!(write_chunk(writer, b"ebbv", &self.edge_data.bounding_box_vertex_positions));
try!(write_chunk(writer, b"eulv", &self.edge_data.upper_line_vertex_positions));
try!(write_chunk(writer, b"ellv", &self.edge_data.lower_line_vertex_positions));
try!(write_chunk(writer, b"eucv", &self.edge_data.upper_curve_vertex_positions));
try!(write_chunk(writer, b"elcv", &self.edge_data.lower_curve_vertex_positions));
try!(write_chunk(writer, b"ebbp", &self.edge_data.bounding_box_path_ids));
try!(write_chunk(writer, b"eulp", &self.edge_data.upper_line_path_ids));
try!(write_chunk(writer, b"ellp", &self.edge_data.lower_line_path_ids));
try!(write_chunk(writer, b"eucp", &self.edge_data.upper_curve_path_ids));
try!(write_chunk(writer, b"elcp", &self.edge_data.lower_curve_path_ids));
try!(write_chunk(writer, b"slin", &self.segments.lines));
try!(write_chunk(writer, b"scur", &self.segments.curves));
try!(write_chunk(writer, b"slpi", &self.segments.line_path_ids));
try!(write_chunk(writer, b"scpi", &self.segments.curve_path_ids));
try!(write_chunk(writer, b"snli", &self.segment_normals.line_normals));
try!(write_chunk(writer, b"sncu", &self.segment_normals.curve_normals));
try!(write_chunk(writer, b"prng", |writer| write_path_ranges(writer, &self.path_ranges)));
try!(write_simple_chunk(writer, b"bqua", &self.b_quads));
try!(write_simple_chunk(writer, b"bvpo", &self.b_vertex_positions));
try!(write_simple_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data));
try!(write_simple_chunk(writer, b"bvno", &self.b_vertex_normals));
try!(write_simple_chunk(writer, b"cvii", &self.cover_indices.interior_indices));
try!(write_simple_chunk(writer, b"cvci", &self.cover_indices.curve_indices));
try!(write_simple_chunk(writer, b"ebbv", &self.edge_data.bounding_box_vertex_positions));
try!(write_simple_chunk(writer, b"eulv", &self.edge_data.upper_line_vertex_positions));
try!(write_simple_chunk(writer, b"ellv", &self.edge_data.lower_line_vertex_positions));
try!(write_simple_chunk(writer, b"eucv", &self.edge_data.upper_curve_vertex_positions));
try!(write_simple_chunk(writer, b"elcv", &self.edge_data.lower_curve_vertex_positions));
try!(write_simple_chunk(writer, b"slin", &self.segments.lines));
try!(write_simple_chunk(writer, b"scur", &self.segments.curves));
try!(write_simple_chunk(writer, b"snli", &self.segment_normals.line_normals));
try!(write_simple_chunk(writer, b"sncu", &self.segment_normals.curve_normals));
let total_length = try!(writer.seek(SeekFrom::Current(0)));
try!(writer.seek(SeekFrom::Start(4)));
try!(writer.write_u32::<LittleEndian>((total_length - 8) as u32));
return Ok(());
fn write_chunk<W, T>(writer: &mut W, tag: &[u8; 4], data: &[T]) -> io::Result<()>
where W: Write + Seek, T: Serialize {
fn write_chunk<W, F>(writer: &mut W, tag: &[u8; 4], mut closure: F) -> io::Result<()>
where W: Write + Seek, F: FnMut(&mut W) -> io::Result<()> {
try!(writer.write_all(tag));
try!(writer.write_all(b"\0\0\0\0"));
let start_position = try!(writer.seek(SeekFrom::Current(0)));
for datum in data {
try!(bincode::serialize_into(writer, datum, Infinite).map_err(|_| {
io::Error::from(ErrorKind::Other)
}));
}
try!(closure(writer));
let end_position = try!(writer.seek(SeekFrom::Current(0)));
try!(writer.seek(SeekFrom::Start(start_position - 4)));
@ -252,19 +239,84 @@ impl MeshLibrary {
try!(writer.seek(SeekFrom::Start(end_position)));
Ok(())
}
fn write_simple_chunk<W, T>(writer: &mut W, tag: &[u8; 4], data: &[T]) -> io::Result<()>
where W: Write + Seek, T: Serialize {
write_chunk(writer, tag, |writer| {
for datum in data {
try!(bincode::serialize_into(writer, datum, Infinite).map_err(|_| {
io::Error::from(ErrorKind::Other)
}));
}
Ok(())
})
}
fn write_path_ranges<W>(writer: &mut W, path_ranges: &[PathRanges]) -> io::Result<()>
where W: Write + Seek {
try!(write_path_range(writer, b"bqua", path_ranges, |ranges| &ranges.b_quads));
try!(write_path_range(writer, b"bver", path_ranges, |ranges| &ranges.b_vertices));
try!(write_path_range(writer,
b"cvii",
path_ranges,
|ranges| &ranges.cover_interior_indices));
try!(write_path_range(writer,
b"cvci",
path_ranges,
|ranges| &ranges.cover_curve_indices));
try!(write_path_range(writer,
b"ebbo",
path_ranges,
|ranges| &ranges.edge_bounding_box_indices));
try!(write_path_range(writer,
b"euli",
path_ranges,
|ranges| &ranges.edge_upper_line_indices));
try!(write_path_range(writer,
b"euci",
path_ranges,
|ranges| &ranges.edge_upper_curve_indices));
try!(write_path_range(writer,
b"elli",
path_ranges,
|ranges| &ranges.edge_lower_line_indices));
try!(write_path_range(writer,
b"elci",
path_ranges,
|ranges| &ranges.edge_lower_curve_indices));
try!(write_path_range(writer, b"slin", path_ranges, |ranges| &ranges.segment_lines));
try!(write_path_range(writer, b"scur", path_ranges, |ranges| &ranges.segment_curves));
Ok(())
}
fn write_path_range<W, F>(writer: &mut W,
tag: &[u8; 4],
all_path_ranges: &[PathRanges],
mut get_range: F)
-> io::Result<()>
where W: Write + Seek, F: FnMut(&PathRanges) -> &Range<u32> {
write_chunk(writer, tag, |writer| {
for path_ranges in all_path_ranges {
let range = get_range(path_ranges);
try!(writer.write_u32::<LittleEndian>(range.start));
try!(writer.write_u32::<LittleEndian>(range.end));
}
Ok(())
})
}
}
pub(crate) fn snapshot_lengths(&self) -> MeshLibraryLengths {
MeshLibraryLengths {
b_quads: self.b_quads.len(),
b_vertices: self.b_vertex_positions.len(),
cover_interior_indices: self.cover_indices.interior_indices.len(),
cover_curve_indices: self.cover_indices.curve_indices.len(),
edge_bounding_box_indices: self.edge_data.bounding_box_vertex_positions.len(),
edge_upper_line_indices: self.edge_data.upper_line_vertex_positions.len(),
edge_upper_curve_indices: self.edge_data.upper_curve_vertex_positions.len(),
edge_lower_line_indices: self.edge_data.lower_line_vertex_positions.len(),
edge_lower_curve_indices: self.edge_data.lower_curve_vertex_positions.len(),
b_quads: self.b_quads.len() as u32,
b_vertices: self.b_vertex_positions.len() as u32,
cover_interior_indices: self.cover_indices.interior_indices.len() as u32,
cover_curve_indices: self.cover_indices.curve_indices.len() as u32,
edge_bounding_box_indices: self.edge_data.bounding_box_vertex_positions.len() as u32,
edge_upper_line_indices: self.edge_data.upper_line_vertex_positions.len() as u32,
edge_upper_curve_indices: self.edge_data.upper_curve_vertex_positions.len() as u32,
edge_lower_line_indices: self.edge_data.lower_line_vertex_positions.len() as u32,
edge_lower_curve_indices: self.edge_data.lower_curve_vertex_positions.len() as u32,
}
}
}
@ -291,45 +343,65 @@ impl MeshLibraryCoverIndices {
}
pub(crate) struct MeshLibraryLengths {
b_quads: usize,
b_vertices: usize,
cover_interior_indices: usize,
cover_curve_indices: usize,
edge_bounding_box_indices: usize,
edge_upper_line_indices: usize,
edge_upper_curve_indices: usize,
edge_lower_line_indices: usize,
edge_lower_curve_indices: usize,
b_quads: u32,
b_vertices: u32,
cover_interior_indices: u32,
cover_curve_indices: u32,
edge_bounding_box_indices: u32,
edge_upper_line_indices: u32,
edge_upper_curve_indices: u32,
edge_lower_line_indices: u32,
edge_lower_curve_indices: u32,
}
pub struct MeshLibraryIndexRanges {
pub b_quads: Range<usize>,
pub b_vertices: Range<usize>,
pub cover_interior_indices: Range<usize>,
pub cover_curve_indices: Range<usize>,
pub edge_bounding_box_indices: Range<usize>,
pub edge_upper_line_indices: Range<usize>,
pub edge_upper_curve_indices: Range<usize>,
pub edge_lower_line_indices: Range<usize>,
pub edge_lower_curve_indices: Range<usize>,
#[derive(Clone, Debug)]
pub struct PathRanges {
pub b_quads: Range<u32>,
pub b_vertices: Range<u32>,
pub cover_interior_indices: Range<u32>,
pub cover_curve_indices: Range<u32>,
pub edge_bounding_box_indices: Range<u32>,
pub edge_upper_line_indices: Range<u32>,
pub edge_upper_curve_indices: Range<u32>,
pub edge_lower_line_indices: Range<u32>,
pub edge_lower_curve_indices: Range<u32>,
pub segment_lines: Range<u32>,
pub segment_curves: Range<u32>,
}
impl MeshLibraryIndexRanges {
pub(crate) fn new(start: &MeshLibraryLengths, end: &MeshLibraryLengths)
-> MeshLibraryIndexRanges {
MeshLibraryIndexRanges {
b_quads: start.b_quads..end.b_quads,
b_vertices: start.b_vertices..end.b_vertices,
cover_interior_indices: start.cover_interior_indices..end.cover_interior_indices,
cover_curve_indices: start.cover_curve_indices..end.cover_curve_indices,
edge_bounding_box_indices:
start.edge_bounding_box_indices..end.edge_bounding_box_indices,
edge_upper_line_indices: start.edge_upper_line_indices..end.edge_upper_line_indices,
edge_upper_curve_indices: start.edge_upper_curve_indices..end.edge_upper_curve_indices,
edge_lower_line_indices: start.edge_lower_line_indices..end.edge_lower_line_indices,
edge_lower_curve_indices: start.edge_lower_curve_indices..end.edge_lower_curve_indices,
impl PathRanges {
fn new() -> PathRanges {
PathRanges {
b_quads: 0..0,
b_vertices: 0..0,
cover_interior_indices: 0..0,
cover_curve_indices: 0..0,
edge_bounding_box_indices: 0..0,
edge_upper_line_indices: 0..0,
edge_upper_curve_indices: 0..0,
edge_lower_line_indices: 0..0,
edge_lower_curve_indices: 0..0,
segment_lines: 0..0,
segment_curves: 0..0,
}
}
pub(crate) fn set_partitioning_lengths(&mut self,
start: &MeshLibraryLengths,
end: &MeshLibraryLengths) {
self.b_quads = start.b_quads..end.b_quads;
self.b_vertices = start.b_vertices..end.b_vertices;
self.cover_interior_indices = start.cover_interior_indices..end.cover_interior_indices;
self.cover_curve_indices = start.cover_curve_indices..end.cover_curve_indices;
self.edge_bounding_box_indices =
start.edge_bounding_box_indices..end.edge_bounding_box_indices;
self.edge_upper_line_indices = start.edge_upper_line_indices..end.edge_upper_line_indices;
self.edge_upper_curve_indices =
start.edge_upper_curve_indices..end.edge_upper_curve_indices;
self.edge_lower_line_indices = start.edge_lower_line_indices..end.edge_lower_line_indices;
self.edge_lower_curve_indices =
start.edge_lower_curve_indices..end.edge_lower_curve_indices;
}
}
#[derive(Clone, Debug)]
@ -339,11 +411,6 @@ pub struct MeshLibraryEdgeData {
pub lower_line_vertex_positions: Vec<EdgeLineVertexPositions>,
pub upper_curve_vertex_positions: Vec<EdgeCurveVertexPositions>,
pub lower_curve_vertex_positions: Vec<EdgeCurveVertexPositions>,
pub bounding_box_path_ids: Vec<u16>,
pub upper_line_path_ids: Vec<u16>,
pub lower_line_path_ids: Vec<u16>,
pub upper_curve_path_ids: Vec<u16>,
pub lower_curve_path_ids: Vec<u16>,
}
impl MeshLibraryEdgeData {
@ -354,11 +421,6 @@ impl MeshLibraryEdgeData {
lower_line_vertex_positions: vec![],
upper_curve_vertex_positions: vec![],
lower_curve_vertex_positions: vec![],
bounding_box_path_ids: vec![],
upper_line_path_ids: vec![],
lower_line_path_ids: vec![],
upper_curve_path_ids: vec![],
lower_curve_path_ids: vec![],
}
}
@ -368,11 +430,6 @@ impl MeshLibraryEdgeData {
self.upper_curve_vertex_positions.clear();
self.lower_line_vertex_positions.clear();
self.lower_curve_vertex_positions.clear();
self.bounding_box_path_ids.clear();
self.upper_line_path_ids.clear();
self.upper_curve_path_ids.clear();
self.lower_line_path_ids.clear();
self.lower_curve_path_ids.clear();
}
}
@ -380,8 +437,6 @@ impl MeshLibraryEdgeData {
pub struct MeshLibrarySegments {
pub lines: Vec<LineSegment>,
pub curves: Vec<CurveSegment>,
pub line_path_ids: Vec<u16>,
pub curve_path_ids: Vec<u16>,
}
impl MeshLibrarySegments {
@ -389,16 +444,12 @@ impl MeshLibrarySegments {
MeshLibrarySegments {
lines: vec![],
curves: vec![],
line_path_ids: vec![],
curve_path_ids: vec![],
}
}
fn clear(&mut self) {
self.lines.clear();
self.curves.clear();
self.line_path_ids.clear();
self.curve_path_ids.clear();
}
}

View File

@ -22,7 +22,7 @@ use std::iter;
use std::ops::{Add, AddAssign};
use std::u32;
use mesh_library::{MeshLibrary, MeshLibraryIndexRanges};
use mesh_library::MeshLibrary;
use normal;
use {BQuad, BVertexLoopBlinnData, BVertexKind, Endpoint, FillRule, Subpath};
@ -103,8 +103,7 @@ impl<'a> Partitioner<'a> {
self.fill_rule = new_fill_rule
}
pub fn partition(&mut self, path_id: u16, first_subpath_index: u32, last_subpath_index: u32)
-> MeshLibraryIndexRanges {
pub fn partition(&mut self, path_id: u16, first_subpath_index: u32, last_subpath_index: u32) {
self.heap.clear();
self.active_edges.clear();
@ -118,15 +117,15 @@ impl<'a> Partitioner<'a> {
self.write_normals_to_library();
debug_assert_eq!(self.library.b_vertex_loop_blinn_data.len(),
self.library.b_vertex_path_ids.len());
debug_assert_eq!(self.library.b_vertex_loop_blinn_data.len(),
self.library.b_vertex_positions.len());
debug_assert_eq!(self.library.b_vertex_loop_blinn_data.len(),
self.library.b_vertex_normals.len());
let end_lengths = self.library.snapshot_lengths();
MeshLibraryIndexRanges::new(&start_lengths, &end_lengths)
let path_ranges = self.library.ensure_path_ranges(path_id);
path_ranges.set_partitioning_lengths(&start_lengths, &end_lengths);
}
fn process_next_point(&mut self) -> bool {
@ -219,7 +218,6 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normal
self.library.add_b_vertex(&endpoint_position,
self.path_id,
&BVertexLoopBlinnData::new(active_edge.endpoint_kind()),
0.0);
@ -263,7 +261,6 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normal
self.library.add_b_vertex(control_point_position,
self.path_id,
&control_point_b_vertex_loop_blinn_data,
0.0);
}
@ -364,7 +361,6 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normal
let position = self.endpoints[endpoint_index as usize].position;
self.library.add_b_vertex(&position,
self.path_id,
&BVertexLoopBlinnData::new(BVertexKind::Endpoint0),
0.0);
@ -417,7 +413,6 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normal
self.library.add_b_vertex(&control_point_position,
self.path_id,
&control_point_b_vertex_loop_blinn_data,
0.0)
}
@ -441,7 +436,6 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normal
self.library.add_b_vertex(&control_point_position,
self.path_id,
&control_point_b_vertex_loop_blinn_data,
0.0)
}
@ -805,8 +799,6 @@ impl<'a> Partitioner<'a> {
right_curve.control_point,
].into_iter());
self.library.b_vertex_path_ids.extend(iter::repeat(self.path_id).take(3));
// Initially, assume that the parity is false. We will modify the Loop-Blinn data later if
// that is incorrect.
self.library.b_vertex_loop_blinn_data.extend([
@ -1042,7 +1034,6 @@ impl<'a> Partitioner<'a> {
let left_curve_control_point_vertex_index;
match active_edge.control_point_vertex_index {
u32::MAX => {
let path_id = self.library.b_vertex_path_ids[left_curve_left as usize];
let right_point = self.endpoints[active_edge.right_endpoint_index as usize]
.position;
let middle_point = left_point_position.to_vector()
@ -1051,7 +1042,6 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normal
active_edge.left_vertex_index = self.library.b_vertex_loop_blinn_data.len() as u32;
self.library.add_b_vertex(&middle_point.to_point(),
path_id,
&BVertexLoopBlinnData::new(active_edge.endpoint_kind()),
0.0);
@ -1078,19 +1068,16 @@ impl<'a> Partitioner<'a> {
// FIXME(pcwalton): Normals
self.library
.add_b_vertex(&left_curve.control_point,
self.path_id,
&BVertexLoopBlinnData::control_point(&left_curve.endpoints[0],
&left_curve.control_point,
&left_curve.endpoints[1],
bottom),
0.0);
self.library.add_b_vertex(&left_curve.endpoints[1],
self.path_id,
&BVertexLoopBlinnData::new(active_edge.endpoint_kind()),
0.0);
self.library
.add_b_vertex(&right_curve.control_point,
self.path_id,
&BVertexLoopBlinnData::control_point(&right_curve.endpoints[0],
&right_curve.control_point,
&right_curve.endpoints[1],