diff --git a/demo/client/src/meshes.ts b/demo/client/src/meshes.ts index f8701679..a8d2cb59 100644 --- a/demo/client/src/meshes.ts +++ b/demo/client/src/meshes.ts @@ -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; } +interface PathRangeTypeFourCCTable { + [fourCC: string]: keyof PathRanges; +} + +interface RangeToCountTable { + [rangeKey: string]: keyof MeshDataCounts; +} + +interface RangeToRangeBufferTable { + [rangeKey: string]: keyof Meshes; +} + interface ArrayLike { [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 = { 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 { 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 { +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, 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 { readonly segmentLineCount: number; readonly segmentCurveCount: number; - constructor(meshes: ArrayBuffer | Meshes) { + 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, optionalRanges?: PathRanges) { if (meshes instanceof ArrayBuffer) { // RIFF encoded data. if (toFourCC(meshes, 0) !== RIFF_FOURCC) @@ -219,26 +321,44 @@ export class PathfinderMeshData implements Meshes { 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>) this[bufferName] = meshes[bufferName]; + + const ranges = unwrapUndef(optionalRanges); + for (const range of Object.keys(RANGE_TO_COUNT_TABLE) as Array) + 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 { tempExpandedArrays[key] = []; } + const tempOriginalRanges: Partial = {}; + const tempExpandedRanges: Partial = {}; + for (const key of Object.keys(RANGE_TO_COUNT_TABLE) as Array) { + tempOriginalRanges[key] = this[key]; + + const newExpandedRanges = []; + for (const newPathID of pathIDs) + newExpandedRanges.push(new Range(0, 0)); + tempExpandedRanges[key] = newExpandedRanges; + } + const originalBuffers: Meshes = tempOriginalBuffers; + const originalRanges: PathRanges = tempOriginalRanges as PathRanges; const expandedArrays: Meshes = 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 { // 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], - `edge${edgeBufferName}PathIDs` as keyof Meshes, + `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 { // 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 { } const expandedBuffers = tempExpandedBuffers as Meshes; - 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) { + 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 { readonly segmentCurveNormals: WebGLBuffer; constructor(gl: WebGLRenderingContext, meshData: PathfinderMeshData) { - for (const bufferName of Object.keys(BUFFER_TYPES) as Array) { + for (const bufferName of Object.keys(BUFFER_TYPES) as Array>) { 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 { } function copyVertices(vertexBufferNames: Array>, - pathIDBufferName: keyof Meshes, + rangesName: keyof PathRanges, expandedMeshes: Meshes, + expandedRanges: PathRanges, originalMeshes: Meshes, + 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>, - pathIDBufferName: keyof Meshes, + rangesName: keyof PathRanges, expandedMeshes: Meshes, + expandedRanges: PathRanges, originalMeshes: Meshes, + 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]; +} diff --git a/demo/client/src/text-demo.ts b/demo/client/src/text-demo.ts index f5b4d393..72518a7a 100644 --- a/demo/client/src/text-demo.ts +++ b/demo/client/src/text-demo.ts @@ -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 { diff --git a/partitioner/src/capi.rs b/partitioner/src/capi.rs index bdfb8e32..700b456f 100644 --- a/partitioner/src/capi.rs +++ b/partitioner/src/capi.rs @@ -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 } -#[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>, diff --git a/partitioner/src/mesh_library.rs b/partitioner/src/mesh_library.rs index 233f5d7c..4f882455 100644 --- a/partitioner/src/mesh_library.rs +++ b/partitioner/src/mesh_library.rs @@ -22,9 +22,9 @@ use {BQuad, BVertexLoopBlinnData}; #[derive(Debug, Clone)] pub struct MeshLibrary { + pub path_ranges: Vec, pub b_quads: Vec, pub b_vertex_positions: Vec>, - pub b_vertex_path_ids: Vec, pub b_vertex_loop_blinn_data: Vec, pub b_vertex_normals: Vec, 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, - 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(&mut self, path_id: u16, stream: I) where I: Iterator { + 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::((total_length - 8) as u32)); return Ok(()); - fn write_chunk(writer: &mut W, tag: &[u8; 4], data: &[T]) -> io::Result<()> - where W: Write + Seek, T: Serialize { + fn write_chunk(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(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(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(writer: &mut W, + tag: &[u8; 4], + all_path_ranges: &[PathRanges], + mut get_range: F) + -> io::Result<()> + where W: Write + Seek, F: FnMut(&PathRanges) -> &Range { + write_chunk(writer, tag, |writer| { + for path_ranges in all_path_ranges { + let range = get_range(path_ranges); + try!(writer.write_u32::(range.start)); + try!(writer.write_u32::(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, - pub b_vertices: Range, - pub cover_interior_indices: Range, - pub cover_curve_indices: Range, - pub edge_bounding_box_indices: Range, - pub edge_upper_line_indices: Range, - pub edge_upper_curve_indices: Range, - pub edge_lower_line_indices: Range, - pub edge_lower_curve_indices: Range, +#[derive(Clone, Debug)] +pub struct PathRanges { + pub b_quads: Range, + pub b_vertices: Range, + pub cover_interior_indices: Range, + pub cover_curve_indices: Range, + pub edge_bounding_box_indices: Range, + pub edge_upper_line_indices: Range, + pub edge_upper_curve_indices: Range, + pub edge_lower_line_indices: Range, + pub edge_lower_curve_indices: Range, + pub segment_lines: Range, + pub segment_curves: Range, } -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, pub upper_curve_vertex_positions: Vec, pub lower_curve_vertex_positions: Vec, - pub bounding_box_path_ids: Vec, - pub upper_line_path_ids: Vec, - pub lower_line_path_ids: Vec, - pub upper_curve_path_ids: Vec, - pub lower_curve_path_ids: Vec, } 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, pub curves: Vec, - pub line_path_ids: Vec, - pub curve_path_ids: Vec, } 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(); } } diff --git a/partitioner/src/partitioner.rs b/partitioner/src/partitioner.rs index 09ffb2cb..802df4bf 100644 --- a/partitioner/src/partitioner.rs +++ b/partitioner/src/partitioner.rs @@ -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],