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:
parent
c767141169
commit
572b7cdd4a
|
@ -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 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,18 +369,32 @@ 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',
|
||||
const bVertexCopyResult = copyVertices(['bVertexPositions', 'bVertexLoopBlinnData'],
|
||||
'bVertexPathRanges',
|
||||
expandedArrays,
|
||||
expandedRanges,
|
||||
originalBuffers,
|
||||
originalRanges,
|
||||
expandedPathID,
|
||||
originalPathID);
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in New Issue