diff --git a/Cargo.toml b/Cargo.toml index ca3bda94..789129ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,6 @@ members = [ "utils/frontend", "utils/gamma-lut", ] + +[patch.crates-io] +ring = { git = "https://github.com/SergioBenitez/ring", branch = "v0.12" } diff --git a/demo/client/src/aa-strategy.ts b/demo/client/src/aa-strategy.ts index fc098038..804ad3d9 100644 --- a/demo/client/src/aa-strategy.ts +++ b/demo/client/src/aa-strategy.ts @@ -18,7 +18,7 @@ import {DemoView} from './view'; export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa'; -export type DirectRenderingMode = 'none' | 'color'; +export type DirectRenderingMode = 'none' | 'conservative' | 'color'; export type SubpixelAAType = 'none' | 'medium'; diff --git a/demo/client/src/gl-utils.ts b/demo/client/src/gl-utils.ts index c32c1eef..735f79b2 100644 --- a/demo/client/src/gl-utils.ts +++ b/demo/client/src/gl-utils.ts @@ -44,7 +44,7 @@ export interface EXTDisjointTimerQuery { export class WebGLQuery {} -export const QUAD_ELEMENTS: Uint8Array = new Uint8Array([2, 0, 1, 1, 3, 2]); +export const QUAD_ELEMENTS: Uint8Array = new Uint8Array([0, 1, 2, 1, 3, 2]); export function createFramebufferColorTexture(gl: WebGLRenderingContext, size: glmatrix.vec2, diff --git a/demo/client/src/mesh-debugger.ts b/demo/client/src/mesh-debugger.ts index 4461046f..c793b3bb 100644 --- a/demo/client/src/mesh-debugger.ts +++ b/demo/client/src/mesh-debugger.ts @@ -268,9 +268,7 @@ class MeshDebuggerView extends PathfinderView { context.font = `12px ${POINT_LABEL_FONT}`; context.lineWidth = invScaleFactor; - const bQuads = new Uint32Array(meshes.bQuads); - const positions = new Float32Array(meshes.bVertexPositions); - const bVertexNormals = new Float32Array(meshes.bVertexNormals); + const bQuadVertexPositions = new Float32Array(meshes.bQuadVertexPositions); const normals: NormalsTable = { lowerCurve: new Float32Array(0), @@ -279,54 +277,24 @@ class MeshDebuggerView extends PathfinderView { upperLine: new Float32Array(0), }; - const drawnVertices: boolean[] = [], drawnNormals: boolean[] = []; - // Draw B-quads. - for (let bQuadIndex = 0; bQuadIndex < meshes.bQuadCount; bQuadIndex++) { + for (let bQuadIndex = 0; bQuadIndex < meshes.bQuadVertexPositionCount; bQuadIndex++) { const bQuadStartOffset = (B_QUAD_SIZE * bQuadIndex) / UINT32_SIZE; - const upperLeftIndex = bQuads[bQuadStartOffset + - B_QUAD_UPPER_LEFT_VERTEX_OFFSET / UINT32_SIZE]; - const upperRightIndex = bQuads[bQuadStartOffset + - B_QUAD_UPPER_RIGHT_VERTEX_OFFSET / UINT32_SIZE]; - const upperControlPointIndex = - bQuads[bQuadStartOffset + B_QUAD_UPPER_CONTROL_POINT_VERTEX_OFFSET / UINT32_SIZE]; - const lowerLeftIndex = bQuads[bQuadStartOffset + - B_QUAD_LOWER_LEFT_VERTEX_OFFSET / UINT32_SIZE]; - const lowerRightIndex = bQuads[bQuadStartOffset + - B_QUAD_LOWER_RIGHT_VERTEX_OFFSET / UINT32_SIZE]; - const lowerControlPointIndex = - bQuads[bQuadStartOffset + B_QUAD_LOWER_CONTROL_POINT_VERTEX_OFFSET / UINT32_SIZE]; - - const upperLeftPosition = unwrapNull(getPosition(positions, upperLeftIndex)); - const upperRightPosition = unwrapNull(getPosition(positions, upperRightIndex)); - const upperControlPointPosition = getPosition(positions, upperControlPointIndex); - const lowerLeftPosition = unwrapNull(getPosition(positions, lowerLeftIndex)); - const lowerRightPosition = unwrapNull(getPosition(positions, lowerRightIndex)); - const lowerControlPointPosition = getPosition(positions, lowerControlPointIndex); + const upperLeftPosition = getPosition(bQuadVertexPositions, bQuadIndex, 0); + const upperControlPointPosition = getPosition(bQuadVertexPositions, bQuadIndex, 1); + const upperRightPosition = getPosition(bQuadVertexPositions, bQuadIndex, 2); + const lowerRightPosition = getPosition(bQuadVertexPositions, bQuadIndex, 3); + const lowerControlPointPosition = getPosition(bQuadVertexPositions, bQuadIndex, 4); + const lowerLeftPosition = getPosition(bQuadVertexPositions, bQuadIndex, 5); if (this.drawVertices) { - drawVertexIfNecessary(context, - drawnVertices, - upperLeftIndex, - upperLeftPosition, - invScaleFactor); - drawVertexIfNecessary(context, - drawnVertices, - upperRightIndex, - upperRightPosition, - invScaleFactor); - drawVertexIfNecessary(context, - drawnVertices, - lowerLeftIndex, - lowerLeftPosition, - invScaleFactor); - drawVertexIfNecessary(context, - drawnVertices, - lowerRightIndex, - lowerRightPosition, - invScaleFactor); + drawVertexIfNecessary(context, upperLeftPosition, invScaleFactor); + drawVertexIfNecessary(context, upperRightPosition, invScaleFactor); + drawVertexIfNecessary(context, lowerLeftPosition, invScaleFactor); + drawVertexIfNecessary(context, lowerRightPosition, invScaleFactor); } + context.beginPath(); context.moveTo(upperLeftPosition[0], -upperLeftPosition[1]); if (upperControlPointPosition != null) { @@ -366,22 +334,6 @@ class MeshDebuggerView extends PathfinderView { context.moveTo(lowerLeftPosition[0], -lowerLeftPosition[1]); context.lineTo(upperLeftPosition[0], -upperLeftPosition[1]); context.stroke(); - - // Draw B-quad normals. - const lowerLeftNormal = bVertexNormals[lowerLeftIndex]; - const lowerRightNormal = bVertexNormals[lowerRightIndex]; - const upperLeftNormal = bVertexNormals[upperLeftIndex]; - const upperRightNormal = bVertexNormals[upperRightIndex]; - if (this.drawVertices && this.drawNormals) { - drawNormal(context, lowerLeftPosition, lowerLeftNormal, invScaleFactor, - 'bVertex'); - drawNormal(context, lowerRightPosition, lowerRightNormal, invScaleFactor, - 'bVertex'); - drawNormal(context, upperLeftPosition, upperLeftNormal, invScaleFactor, - 'bVertex'); - drawNormal(context, upperRightPosition, upperRightNormal, invScaleFactor, - 'bVertex'); - } } // Draw segments. @@ -429,10 +381,16 @@ class MeshDebuggerView extends PathfinderView { } } -function getPosition(positions: Float32Array, vertexIndex: number): glmatrix.vec2 | null { - if (vertexIndex === UINT32_MAX) - return null; - return glmatrix.vec2.clone([positions[vertexIndex * 2 + 0], positions[vertexIndex * 2 + 1]]); +function getPosition(positions: Float32Array, bQuadIndex: number, vertexIndex: number): + glmatrix.vec2 { + return glmatrix.vec2.clone([ + positions[(bQuadIndex * 6 + vertexIndex) * 2 + 0], + positions[(bQuadIndex * 6 + vertexIndex) * 2 + 1], + ]); +} + +function getNormal(normals: Float32Array, bQuadIndex: number, vertexIndex: number): number { + return normals[bQuadIndex * 6 + vertexIndex]; } function getNormals(normals: NormalsTable, @@ -526,25 +484,12 @@ function drawSegmentVertices(context: CanvasRenderingContext2D, } function drawVertexIfNecessary(context: CanvasRenderingContext2D, - markedVertices: boolean[], - vertexIndex: number, position: Float32Array, invScaleFactor: number) { - if (markedVertices[vertexIndex] != null) - return; - markedVertices[vertexIndex] = true; - context.beginPath(); context.moveTo(position[0], -position[1]); context.arc(position[0], -position[1], POINT_RADIUS * invScaleFactor, 0, 2.0 * Math.PI); context.fill(); - - context.save(); - context.scale(invScaleFactor, invScaleFactor); - context.fillText("" + vertexIndex, - position[0] / invScaleFactor + POINT_LABEL_OFFSET[0], - -position[1] / invScaleFactor + POINT_LABEL_OFFSET[1]); - context.restore(); } function drawSegmentVertex(context: CanvasRenderingContext2D, diff --git a/demo/client/src/meshes.ts b/demo/client/src/meshes.ts index 99214fbe..c9ba93cc 100644 --- a/demo/client/src/meshes.ts +++ b/demo/client/src/meshes.ts @@ -12,7 +12,7 @@ import * as base64js from 'base64-js'; import * as _ from 'lodash'; import {expectNotNull, FLOAT32_SIZE, panic, PathfinderError, Range, UINT16_SIZE} from './utils'; -import {UINT32_MAX, UINT32_SIZE, unwrapNull, unwrapUndef} from './utils'; +import {UINT32_MAX, UINT32_SIZE, UINT8_SIZE, unwrapNull, unwrapUndef} from './utils'; interface BufferTypeFourCCTable { [fourCC: string]: keyof Meshes; @@ -87,24 +87,9 @@ const SEGMENT_LINE_SIZE: number = 4 * 4; const SEGMENT_CURVE_SIZE: number = 4 * 6; const MESH_TYPES: Meshes = { + bQuadVertexInteriorIndices: { type: 'Uint32', size: 1 }, + bQuadVertexPositionPathIDs: { type: 'Uint16', size: 6 }, bQuadVertexPositions: { type: 'Float32', size: 12 }, - bQuads: { type: 'Uint32', size: B_QUAD_FIELD_COUNT }, - bVertexLoopBlinnData: { type: 'Uint32', size: 1 }, - bVertexNormals: { type: 'Float32', size: 1 }, - bVertexPathIDs: { type: 'Uint16', size: 1 }, - bVertexPositions: { type: 'Float32', size: 2 }, - coverCurveIndices: { type: 'Uint32', size: 1 }, - coverInteriorIndices: { type: 'Uint32', size: 1 }, - edgeBoundingBoxPathIDs: { type: 'Uint16', size: 1 }, - edgeBoundingBoxVertexPositions: { type: 'Float32', size: 4 }, - edgeLowerCurvePathIDs: { type: 'Uint16', size: 1 }, - edgeLowerCurveVertexPositions: { type: 'Float32', size: 6 }, - edgeLowerLinePathIDs: { type: 'Uint16', size: 1 }, - edgeLowerLineVertexPositions: { type: 'Float32', size: 4 }, - edgeUpperCurvePathIDs: { type: 'Uint16', size: 1 }, - edgeUpperCurveVertexPositions: { type: 'Float32', size: 6 }, - edgeUpperLinePathIDs: { type: 'Uint16', size: 1 }, - edgeUpperLineVertexPositions: { type: 'Float32', size: 4 }, segmentCurveNormals: { type: 'Float32', size: 3 }, segmentCurvePathIDs: { type: 'Uint16', size: 1 }, segmentCurves: { type: 'Float32', size: 6 }, @@ -114,24 +99,9 @@ const MESH_TYPES: Meshes = { }; const BUFFER_TYPES: Meshes = { + bQuadVertexInteriorIndices: 'ELEMENT_ARRAY_BUFFER', + bQuadVertexPositionPathIDs: 'ARRAY_BUFFER', bQuadVertexPositions: 'ARRAY_BUFFER', - bQuads: 'ARRAY_BUFFER', - bVertexLoopBlinnData: 'ARRAY_BUFFER', - bVertexNormals: 'ARRAY_BUFFER', - bVertexPathIDs: 'ARRAY_BUFFER', - bVertexPositions: 'ARRAY_BUFFER', - coverCurveIndices: 'ELEMENT_ARRAY_BUFFER', - coverInteriorIndices: 'ELEMENT_ARRAY_BUFFER', - edgeBoundingBoxPathIDs: 'ARRAY_BUFFER', - edgeBoundingBoxVertexPositions: 'ARRAY_BUFFER', - edgeLowerCurvePathIDs: 'ARRAY_BUFFER', - edgeLowerCurveVertexPositions: 'ARRAY_BUFFER', - edgeLowerLinePathIDs: 'ARRAY_BUFFER', - edgeLowerLineVertexPositions: 'ARRAY_BUFFER', - edgeUpperCurvePathIDs: 'ARRAY_BUFFER', - edgeUpperCurveVertexPositions: 'ARRAY_BUFFER', - edgeUpperLinePathIDs: 'ARRAY_BUFFER', - edgeUpperLineVertexPositions: 'ARRAY_BUFFER', segmentCurveNormals: 'ARRAY_BUFFER', segmentCurvePathIDs: 'ARRAY_BUFFER', segmentCurves: 'ARRAY_BUFFER', @@ -148,18 +118,8 @@ const MESH_LIBRARY_FOURCC: string = 'PFML'; // Must match the FourCCs in `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into()`. const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = { - bqua: 'bQuads', + bqii: 'bQuadVertexInteriorIndices', bqvp: 'bQuadVertexPositions', - bvlb: 'bVertexLoopBlinnData', - bvno: 'bVertexNormals', - bvpo: 'bVertexPositions', - cvci: 'coverCurveIndices', - cvii: 'coverInteriorIndices', - ebbv: 'edgeBoundingBoxVertexPositions', - elcv: 'edgeLowerCurveVertexPositions', - ellv: 'edgeLowerLineVertexPositions', - eucv: 'edgeUpperCurveVertexPositions', - eulv: 'edgeUpperLineVertexPositions', scur: 'segmentCurves', slin: 'segmentLines', sncu: 'segmentCurveNormals', @@ -169,57 +129,28 @@ const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = { // Must match the FourCCs in // `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`. const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = { - bqua: 'bQuadPathRanges', + bqii: 'bQuadVertexInteriorIndexPathRanges', bqvp: 'bQuadVertexPositionPathRanges', - 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', + bQuadVertexInteriorIndexPathRanges: 'bQuadVertexInteriorIndexCount', bQuadVertexPositionPathRanges: 'bQuadVertexPositionCount', - 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', + bQuadVertexPositionPathRanges: 'bQuadVertexPositionPathIDs', segmentCurveRanges: 'segmentCurvePathIDs', segmentLineRanges: 'segmentLinePathIDs', }; const RANGE_KEYS: Array = [ - 'bQuadPathRanges', 'bQuadVertexPositionPathRanges', - 'bVertexPathRanges', - 'coverInteriorIndexRanges', - 'coverCurveIndexRanges', - 'edgeBoundingBoxRanges', - 'edgeUpperLineIndexRanges', - 'edgeUpperCurveIndexRanges', - 'edgeLowerLineIndexRanges', - 'edgeLowerCurveIndexRanges', + 'bQuadVertexInteriorIndexPathRanges', 'segmentCurveRanges', 'segmentLineRanges', ]; @@ -227,113 +158,51 @@ const RANGE_KEYS: Array = [ type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER'; export interface Meshes { - readonly bQuads: T; readonly bQuadVertexPositions: T; - readonly bVertexPositions: T; - readonly bVertexLoopBlinnData: T; - readonly bVertexNormals: T; - readonly coverInteriorIndices: T; - readonly coverCurveIndices: T; - readonly edgeBoundingBoxVertexPositions: T; - readonly edgeLowerCurveVertexPositions: T; - readonly edgeLowerLineVertexPositions: T; - readonly edgeUpperCurveVertexPositions: T; - readonly edgeUpperLineVertexPositions: T; + readonly bQuadVertexInteriorIndices: T; readonly segmentLines: T; readonly segmentCurves: T; readonly segmentLineNormals: T; readonly segmentCurveNormals: T; - bVertexPathIDs: T; - edgeBoundingBoxPathIDs: T; + bQuadVertexPositionPathIDs: T; segmentLinePathIDs: T; segmentCurvePathIDs: T; - edgeLowerCurvePathIDs: T; - edgeLowerLinePathIDs: T; - edgeUpperCurvePathIDs: T; - edgeUpperLinePathIDs: T; } interface MeshDataCounts { - readonly bQuadCount: number; readonly bQuadVertexPositionCount: 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 bQuadVertexInteriorIndexCount: number; readonly segmentLineCount: number; readonly segmentCurveCount: number; } interface PathRanges { - bQuadPathRanges: Range[]; bQuadVertexPositionPathRanges: Range[]; - bVertexPathRanges: Range[]; - coverInteriorIndexRanges: Range[]; - coverCurveIndexRanges: Range[]; - edgeBoundingBoxRanges: Range[]; - edgeUpperLineIndexRanges: Range[]; - edgeUpperCurveIndexRanges: Range[]; - edgeLowerLineIndexRanges: Range[]; - edgeLowerCurveIndexRanges: Range[]; + bQuadVertexInteriorIndexPathRanges: Range[]; segmentCurveRanges: Range[]; segmentLineRanges: Range[]; } export class PathfinderMeshData implements Meshes, MeshDataCounts, PathRanges { - readonly bQuads: ArrayBuffer; readonly bQuadVertexPositions: ArrayBuffer; - readonly bVertexPositions: ArrayBuffer; - readonly bVertexLoopBlinnData: ArrayBuffer; - readonly bVertexNormals: ArrayBuffer; - readonly coverInteriorIndices: ArrayBuffer; - readonly coverCurveIndices: ArrayBuffer; - readonly edgeBoundingBoxVertexPositions: ArrayBuffer; - readonly edgeLowerCurveVertexPositions: ArrayBuffer; - readonly edgeLowerLineVertexPositions: ArrayBuffer; - readonly edgeUpperCurveVertexPositions: ArrayBuffer; - readonly edgeUpperLineVertexPositions: ArrayBuffer; + readonly bQuadVertexInteriorIndices: ArrayBuffer; readonly segmentLines: ArrayBuffer; readonly segmentCurves: ArrayBuffer; readonly segmentLineNormals: ArrayBuffer; readonly segmentCurveNormals: ArrayBuffer; - readonly bQuadCount: number; readonly bQuadVertexPositionCount: 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 bQuadVertexInteriorIndexCount: number; readonly segmentLineCount: number; readonly segmentCurveCount: number; - bVertexPathIDs: ArrayBuffer; - edgeBoundingBoxPathIDs: ArrayBuffer; - edgeLowerCurvePathIDs: ArrayBuffer; - edgeLowerLinePathIDs: ArrayBuffer; - edgeUpperCurvePathIDs: ArrayBuffer; - edgeUpperLinePathIDs: ArrayBuffer; + bQuadVertexPositionPathIDs: ArrayBuffer; segmentCurvePathIDs: ArrayBuffer; segmentLinePathIDs: ArrayBuffer; - bQuadPathRanges: Range[]; bQuadVertexPositionPathRanges: Range[]; - bVertexPathRanges: Range[]; - coverInteriorIndexRanges: Range[]; - coverCurveIndexRanges: Range[]; - edgeBoundingBoxRanges: Range[]; - edgeUpperLineIndexRanges: Range[]; - edgeUpperCurveIndexRanges: Range[]; - edgeLowerLineIndexRanges: Range[]; - edgeLowerCurveIndexRanges: Range[]; + bQuadVertexInteriorIndexPathRanges: Range[]; segmentCurveRanges: Range[]; segmentLineRanges: Range[]; @@ -368,22 +237,10 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, this[range] = ranges[range]; } - this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE; this.bQuadVertexPositionCount = this.bQuadVertexPositions.byteLength / B_QUAD_VERTEX_POSITION_SIZE; - 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.bQuadVertexInteriorIndexCount = this.bQuadVertexInteriorIndices.byteLength / + INDEX_SIZE; this.segmentCurveCount = this.segmentCurves.byteLength / SEGMENT_CURVE_SIZE; this.segmentLineCount = this.segmentLines.byteLength / SEGMENT_LINE_SIZE; @@ -418,90 +275,31 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, const expandedPathID = newPathIndex + 1; const originalPathID = pathIDs[newPathIndex]; - const bVertexCopyResult = copyVertices(['bVertexPositions', - 'bVertexLoopBlinnData', - 'bVertexNormals'], - 'bVertexPathRanges', - expandedArrays, - expandedRanges, - originalBuffers, - originalRanges, - expandedPathID, - originalPathID); + // Copy over B-quad vertex positions. + const bQuadVertexCopyResult = copyVertices(['bQuadVertexPositions'], + 'bQuadVertexPositionPathRanges', + expandedArrays, + expandedRanges, + originalBuffers, + originalRanges, + expandedPathID, + originalPathID); - if (bVertexCopyResult == null) + if (bQuadVertexCopyResult == null) continue; - const firstExpandedBVertexIndex = bVertexCopyResult.expandedStartIndex; - const firstBVertexIndex = bVertexCopyResult.originalStartIndex; - const lastBVertexIndex = bVertexCopyResult.originalEndIndex; - - // Copy over B-quad vertex positions. - copyVertices(['bQuadVertexPositions'], - 'bQuadVertexPositionPathRanges', - expandedArrays, - expandedRanges, - originalBuffers, - originalRanges, - expandedPathID, - originalPathID); - - // Copy over edge data. - copyVertices(['edgeBoundingBoxVertexPositions'], - 'edgeBoundingBoxRanges', - expandedArrays, - expandedRanges, - originalBuffers, - originalRanges, - expandedPathID, - originalPathID); - for (const edgeBufferName of EDGE_BUFFER_NAMES) { - copyVertices([`edge${edgeBufferName}VertexPositions` as keyof Meshes], - `edge${edgeBufferName}IndexRanges` as keyof PathRanges, - expandedArrays, - expandedRanges, - originalBuffers, - originalRanges, - expandedPathID, - originalPathID); - } + const firstExpandedBQuadVertexIndex = bQuadVertexCopyResult.expandedStartIndex; + const firstBQuadVertexIndex = bQuadVertexCopyResult.originalStartIndex; + const lastBQuadVertexIndex = bQuadVertexCopyResult.originalEndIndex; // Copy over indices. - copyIndices(expandedArrays.coverInteriorIndices, - expandedRanges.coverInteriorIndexRanges, - originalBuffers.coverInteriorIndices as Uint32Array, - firstExpandedBVertexIndex, - firstBVertexIndex, - lastBVertexIndex, + copyIndices(expandedArrays.bQuadVertexInteriorIndices, + expandedRanges.bQuadVertexInteriorIndexPathRanges, + originalBuffers.bQuadVertexInteriorIndices as Uint32Array, + firstExpandedBQuadVertexIndex * 6, + firstBQuadVertexIndex * 6, + lastBQuadVertexIndex * 6, expandedPathID); - copyIndices(expandedArrays.coverCurveIndices, - expandedRanges.coverCurveIndexRanges, - originalBuffers.coverCurveIndices as Uint32Array, - firstExpandedBVertexIndex, - firstBVertexIndex, - lastBVertexIndex, - expandedPathID); - - // Copy over B-quads. - const originalBQuadRange = originalRanges.bQuadPathRanges[originalPathID - 1]; - const firstExpandedBQuadIndex = expandedArrays.bQuads.length / B_QUAD_FIELD_COUNT; - expandedRanges.bQuadPathRanges[expandedPathID - 1] = - new Range(firstExpandedBQuadIndex, - firstExpandedBQuadIndex + originalBQuadRange.length); - const indexDelta = firstExpandedBVertexIndex - firstBVertexIndex; - for (let bQuadIndex = originalBQuadRange.start; - bQuadIndex < originalBQuadRange.end; - bQuadIndex++) { - const bQuad = originalBuffers.bQuads[bQuadIndex]; - for (let indexIndex = 0; indexIndex < B_QUAD_FIELD_COUNT; indexIndex++) { - const srcIndex = originalBuffers.bQuads[bQuadIndex * B_QUAD_FIELD_COUNT + - indexIndex]; - if (srcIndex === UINT32_MAX) - expandedArrays.bQuads.push(srcIndex); - else - expandedArrays.bQuads.push(srcIndex + indexDelta); - } - } // Copy over segments. copySegments(['segmentLines', 'segmentLineNormals'], @@ -560,43 +358,33 @@ export class PathfinderMeshData implements Meshes, MeshDataCounts, if (!RANGE_TO_RANGE_BUFFER_TABLE.hasOwnProperty(rangeKey)) continue; - const count = this[RANGE_TO_COUNT_TABLE[rangeKey]]; + const rangeBufferKey = RANGE_TO_RANGE_BUFFER_TABLE[rangeKey]; + + const instanceCount = this[RANGE_TO_COUNT_TABLE[rangeKey]]; + const fieldCount = MESH_TYPES[rangeBufferKey].size; const ranges = this[rangeKey as keyof PathRanges]; - const destBuffer = new Uint16Array(count); + const destBuffer = new Uint16Array(instanceCount * fieldCount); 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++; + for (let fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { + destBuffer[destIndex] = pathIndex + 1; + destIndex++; + } } } - (this as any)[RANGE_TO_RANGE_BUFFER_TABLE[rangeKey]] = destBuffer; + (this as any)[rangeBufferKey] = destBuffer.buffer as ArrayBuffer; } } } export class PathfinderMeshBuffers implements Meshes, PathRanges { - readonly bQuads: WebGLBuffer; readonly bQuadVertexPositions: WebGLBuffer; - readonly bVertexPositions: WebGLBuffer; - readonly bVertexPathIDs: WebGLBuffer; - readonly bVertexLoopBlinnData: WebGLBuffer; - readonly bVertexNormals: WebGLBuffer; - readonly coverInteriorIndices: WebGLBuffer; - readonly coverCurveIndices: WebGLBuffer; - readonly edgeBoundingBoxPathIDs: WebGLBuffer; - readonly edgeBoundingBoxVertexPositions: WebGLBuffer; - readonly edgeLowerCurvePathIDs: WebGLBuffer; - readonly edgeLowerCurveVertexPositions: WebGLBuffer; - readonly edgeLowerLinePathIDs: WebGLBuffer; - readonly edgeLowerLineVertexPositions: WebGLBuffer; - readonly edgeUpperCurvePathIDs: WebGLBuffer; - readonly edgeUpperCurveVertexPositions: WebGLBuffer; - readonly edgeUpperLinePathIDs: WebGLBuffer; - readonly edgeUpperLineVertexPositions: WebGLBuffer; + readonly bQuadVertexPositionPathIDs: WebGLBuffer; + readonly bQuadVertexInteriorIndices: WebGLBuffer; readonly segmentLines: WebGLBuffer; readonly segmentCurves: WebGLBuffer; readonly segmentLinePathIDs: WebGLBuffer; @@ -604,16 +392,8 @@ export class PathfinderMeshBuffers implements Meshes, PathRanges { readonly segmentLineNormals: WebGLBuffer; readonly segmentCurveNormals: WebGLBuffer; - readonly bQuadPathRanges: Range[]; readonly bQuadVertexPositionPathRanges: Range[]; - readonly bVertexPathRanges: Range[]; - readonly coverInteriorIndexRanges: Range[]; - readonly coverCurveIndexRanges: Range[]; - readonly edgeBoundingBoxRanges: Range[]; - readonly edgeUpperLineIndexRanges: Range[]; - readonly edgeUpperCurveIndexRanges: Range[]; - readonly edgeLowerLineIndexRanges: Range[]; - readonly edgeLowerCurveIndexRanges: Range[]; + readonly bQuadVertexInteriorIndexPathRanges: Range[]; readonly segmentCurveRanges: Range[]; readonly segmentLineRanges: Range[]; diff --git a/demo/client/src/renderer.ts b/demo/client/src/renderer.ts index b1b3ea48..8e40b178 100644 --- a/demo/client/src/renderer.ts +++ b/demo/client/src/renderer.ts @@ -11,7 +11,8 @@ import * as glmatrix from 'gl-matrix'; import * as _ from 'lodash'; -import {AntialiasingStrategy, AntialiasingStrategyName, GammaCorrectionMode} from './aa-strategy'; +import {AntialiasingStrategy, AntialiasingStrategyName, DirectRenderingMode} from './aa-strategy'; +import {GammaCorrectionMode} from './aa-strategy'; import {TileInfo} from './aa-strategy'; import {NoAAStrategy, StemDarkeningMode, SubpixelAAType} from './aa-strategy'; import {AAOptions} from './app-controller'; @@ -24,6 +25,8 @@ import {RenderContext, Timings} from "./view"; const MAX_PATHS: number = 65535; +const MAX_VERTICES: number = 4 * 1024 * 1024; + const TIME_INTERVAL_DELAY: number = 32; const B_LOOP_BLINN_DATA_SIZE: number = 4; @@ -92,6 +95,7 @@ export abstract class Renderer { private gammaLUTTexture: WebGLTexture | null; private instancedPathIDVBO: WebGLBuffer | null; + private vertexIDVBO: WebGLBuffer | null; private timerQueryPollInterval: number | null; constructor(renderContext: RenderContext) { @@ -110,6 +114,7 @@ export abstract class Renderer { if (this.pathIDsAreInstanced) this.initInstancedPathIDVBO(); + this.initVertexIDVBO(); this.initGammaLUTTexture(); this.antialiasingStrategy = new NoAAStrategy(0, 'none'); @@ -154,6 +159,17 @@ export abstract class Renderer { const objectCount = this.objectCount; for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) { + if (antialiasingStrategy.directRenderingMode !== 'none') { + // Prepare for direct rendering. + antialiasingStrategy.prepareToRenderObject(this, objectIndex); + + // Clear. + this.clearForDirectRendering(objectIndex); + + // Perform direct rendering (Loop-Blinn). + this.directlyRenderObject(pass, objectIndex); + } + // Antialias. antialiasingStrategy.antialiasObject(this, objectIndex); @@ -162,23 +178,12 @@ export abstract class Renderer { if (this.timerQueryPollInterval == null && objectIndex === objectCount - 1 && pass === passCount - 1) { renderContext.timerQueryExt - .endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT); + .endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT); renderContext.timerQueryExt .beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT, renderContext.compositingTimerQuery); } - // Perform direct rendering (Loop-Blinn). - if (antialiasingStrategy.directRenderingMode !== 'none') { - // Prepare for direct rendering. - antialiasingStrategy.prepareToRenderObject(this, objectIndex); - - // Clear. - this.clearForDirectRendering(objectIndex); - - this.directlyRenderObject(pass, objectIndex); - } - // Perform post-antialiasing tasks. antialiasingStrategy.finishAntialiasingObject(this, objectIndex); @@ -351,7 +356,7 @@ export abstract class Renderer { pathRangeForObject(objectIndex: number): Range { if (this.meshes == null) return new Range(0, 0); - const bVertexPathRanges = this.meshes[objectIndex].bVertexPathRanges; + const bVertexPathRanges = this.meshes[objectIndex].bQuadVertexPositionPathRanges; return new Range(1, bVertexPathRanges.length + 1); } @@ -382,7 +387,8 @@ export abstract class Renderer { PathTransformBuffers; protected abstract directCurveProgramName(): keyof ShaderMap; - protected abstract directInteriorProgramName(): keyof ShaderMap; + protected abstract directInteriorProgramName(renderingMode: DirectRenderingMode): + keyof ShaderMap; protected drawSceneryIfNecessary(): void {} @@ -409,17 +415,9 @@ export abstract class Renderer { return; gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - - switch (renderingMode) { - case 'color': - gl.clearDepth(0.0); - gl.depthMask(true); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - break; - case 'none': - // Nothing to do. - break; - } + gl.clearDepth(0.0); + gl.depthMask(true); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } protected getModelviewTransform(pathIndex: number): glmatrix.mat4 { @@ -460,24 +458,27 @@ export abstract class Renderer { const pathRange = this.pathRangeForObject(objectIndex); const meshIndex = this.meshIndexForObject(objectIndex); - const meshes = this.meshes[meshIndex]; - const meshData = this.meshData[meshIndex]; + const meshes = this.meshes![meshIndex]; + const meshData = this.meshData![meshIndex]; // Set up implicit cover state. gl.depthFunc(gl.GREATER); gl.depthMask(true); gl.enable(gl.DEPTH_TEST); gl.disable(gl.BLEND); + gl.cullFace(gl.BACK); + gl.frontFace(gl.CCW); + gl.enable(gl.CULL_FACE); // Set up the implicit cover interior VAO. - const directInteriorProgramName = this.directInteriorProgramName(); + const directInteriorProgramName = this.directInteriorProgramName(renderingMode); const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName]; if (this.implicitCoverInteriorVAO == null) { this.implicitCoverInteriorVAO = renderContext.vertexArrayObjectExt .createVertexArrayOES(); } renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverInteriorVAO); - this.initImplicitCoverInteriorVAO(objectIndex, instanceRange); + this.initImplicitCoverInteriorVAO(objectIndex, instanceRange, renderingMode); // Draw direct interior parts. this.setTransformUniform(directInteriorProgram.uniforms, pass, objectIndex); @@ -489,57 +490,67 @@ export abstract class Renderer { this.pathTransformBufferTextures[meshIndex] .ext .bind(gl, directInteriorProgram.uniforms, 2); - const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange); + const bQuadInteriorRange = getMeshIndexRange(meshes.bQuadVertexInteriorIndexPathRanges, + pathRange); if (!this.pathIDsAreInstanced) { gl.drawElements(gl.TRIANGLES, - coverInteriorRange.length, + bQuadInteriorRange.length, gl.UNSIGNED_INT, - coverInteriorRange.start * UINT32_SIZE); + bQuadInteriorRange.start * UINT32_SIZE); } else { renderContext.instancedArraysExt - .drawElementsInstancedANGLE(gl.TRIANGLES, - coverInteriorRange.length, - gl.UNSIGNED_INT, - 0, - instanceRange.length); + .drawElementsInstancedANGLE(gl.TRIANGLES, + bQuadInteriorRange.length, + gl.UNSIGNED_INT, + 0, + instanceRange.length); } - // Set up direct curve state. - gl.depthMask(false); - gl.enable(gl.BLEND); - gl.blendEquation(gl.FUNC_ADD); - gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); + gl.disable(gl.CULL_FACE); - // Set up the direct curve VAO. - // - // TODO(pcwalton): Cache these. - const directCurveProgramName = this.directCurveProgramName(); - const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName]; - if (this.implicitCoverCurveVAO == null) - this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES(); - renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO); - this.initImplicitCoverCurveVAO(objectIndex, instanceRange); + // Render curves, if applicable. + if (renderingMode !== 'conservative') { + // Set up direct curve state. + gl.depthMask(false); + gl.enable(gl.BLEND); + gl.blendEquation(gl.FUNC_ADD); + gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE); - // Draw direct curve parts. - this.setTransformUniform(directCurveProgram.uniforms, pass, objectIndex); - this.setFramebufferSizeUniform(directCurveProgram.uniforms); - this.setHintsUniform(directCurveProgram.uniforms); - this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0); - this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms); - this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1); - this.pathTransformBufferTextures[meshIndex].ext.bind(gl, directCurveProgram.uniforms, 2); - const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange); - if (!this.pathIDsAreInstanced) { - gl.drawElements(gl.TRIANGLES, - coverCurveRange.length, - gl.UNSIGNED_INT, - coverCurveRange.start * UINT32_SIZE); - } else { - renderContext.instancedArraysExt.drawElementsInstancedANGLE(gl.TRIANGLES, - coverCurveRange.length, - gl.UNSIGNED_INT, - 0, - instanceRange.length); + // Set up the direct curve VAO. + // + // TODO(pcwalton): Cache these. + const directCurveProgramName = this.directCurveProgramName(); + const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName]; + if (this.implicitCoverCurveVAO == null) { + this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt + .createVertexArrayOES(); + } + renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO); + this.initImplicitCoverCurveVAO(objectIndex, instanceRange); + + // Draw direct curve parts. + this.setTransformUniform(directCurveProgram.uniforms, pass, objectIndex); + this.setFramebufferSizeUniform(directCurveProgram.uniforms); + this.setHintsUniform(directCurveProgram.uniforms); + this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0); + this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms); + this.pathTransformBufferTextures[meshIndex] + .st + .bind(gl, directCurveProgram.uniforms, 1); + this.pathTransformBufferTextures[meshIndex] + .ext + .bind(gl, directCurveProgram.uniforms, 2); + const coverCurveRange = getMeshIndexRange(meshes.bQuadVertexPositionPathRanges, + pathRange); + if (!this.pathIDsAreInstanced) { + gl.drawArrays(gl.TRIANGLES, coverCurveRange.start * 6, coverCurveRange.length * 6); + } else { + renderContext.instancedArraysExt + .drawArraysInstancedANGLE(gl.TRIANGLES, + 0, + coverCurveRange.length * 6, + instanceRange.length); + } } renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); @@ -548,7 +559,7 @@ export abstract class Renderer { antialiasingStrategy.finishDirectlyRenderingObject(this, objectIndex); } - private finishTiming() { + private finishTiming(): void { const renderContext = this.renderContext; if (this.timerQueryPollInterval != null) @@ -613,17 +624,20 @@ export abstract class Renderer { const meshIndex = this.meshIndexForObject(objectIndex); const meshes = this.meshes[meshIndex]; + const meshData = unwrapNull(this.meshData)[meshIndex]; const directCurveProgramName = this.directCurveProgramName(); const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName]; gl.useProgram(directCurveProgram.program); - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions); + gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositions); gl.vertexAttribPointer(directCurveProgram.attributes.aPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexIDVBO); + gl.vertexAttribPointer(directCurveProgram.attributes.aVertexID, 1, gl.FLOAT, false, 0, 0); if (this.pathIDsAreInstanced) gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO); else - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs); + gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositionPathIDs); gl.vertexAttribPointer(directCurveProgram.attributes.aPathID, 1, gl.UNSIGNED_SHORT, @@ -635,35 +649,15 @@ export abstract class Renderer { .vertexAttribDivisorANGLE(directCurveProgram.attributes.aPathID, 1); } - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexLoopBlinnData); - gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord, - 2, - gl.UNSIGNED_BYTE, - false, - B_LOOP_BLINN_DATA_SIZE, - B_LOOP_BLINN_DATA_TEX_COORD_OFFSET); - gl.vertexAttribPointer(directCurveProgram.attributes.aSign, - 1, - gl.BYTE, - false, - B_LOOP_BLINN_DATA_SIZE, - B_LOOP_BLINN_DATA_SIGN_OFFSET); - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexNormals); - gl.vertexAttribPointer(directCurveProgram.attributes.aNormalAngle, - 1, - gl.FLOAT, - false, - FLOAT32_SIZE, - 0); gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition); - gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord); + gl.enableVertexAttribArray(directCurveProgram.attributes.aVertexID); gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID); - gl.enableVertexAttribArray(directCurveProgram.attributes.aSign); - gl.enableVertexAttribArray(directCurveProgram.attributes.aNormalAngle); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverCurveIndices); } - private initImplicitCoverInteriorVAO(objectIndex: number, instanceRange: Range): void { + private initImplicitCoverInteriorVAO(objectIndex: number, + instanceRange: Range, + renderingMode: DirectRenderingMode): + void { if (this.meshes == null) return; @@ -673,10 +667,10 @@ export abstract class Renderer { const meshIndex = this.meshIndexForObject(objectIndex); const meshes = this.meshes[meshIndex]; - const directInteriorProgramName = this.directInteriorProgramName(); + const directInteriorProgramName = this.directInteriorProgramName(renderingMode); const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName]; gl.useProgram(directInteriorProgram.program); - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions); + gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositions); gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition, 2, gl.FLOAT, @@ -687,7 +681,7 @@ export abstract class Renderer { if (this.pathIDsAreInstanced) gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO); else - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs); + gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositionPathIDs); gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID, 1, gl.UNSIGNED_SHORT, @@ -699,18 +693,21 @@ export abstract class Renderer { .vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1); } - gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexNormals); - gl.vertexAttribPointer(directInteriorProgram.attributes.aNormalAngle, - 1, - gl.FLOAT, - false, - FLOAT32_SIZE, - 0); + if (directInteriorProgramName === 'conservativeInterior') { + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexIDVBO); + gl.vertexAttribPointer(directInteriorProgram.attributes.aVertexID, + 1, + gl.FLOAT, + false, + 0, + 0); + } gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition); gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID); - gl.enableVertexAttribArray(directInteriorProgram.attributes.aNormalAngle); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverInteriorIndices); + if (directInteriorProgramName === 'conservativeInterior') + gl.enableVertexAttribArray(directInteriorProgram.attributes.aVertexID); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.bQuadVertexInteriorIndices); } private initInstancedPathIDVBO(): void { @@ -721,11 +718,25 @@ export abstract class Renderer { for (let pathIndex = 0; pathIndex < MAX_PATHS; pathIndex++) pathIDs[pathIndex] = pathIndex + 1; - this.instancedPathIDVBO = renderContext.gl.createBuffer(); + this.instancedPathIDVBO = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO); gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, null); } + + private initVertexIDVBO(): void { + const renderContext = this.renderContext; + const gl = renderContext.gl; + + const vertexIDs = new Float32Array(MAX_VERTICES); + for (let vertexID = 0; vertexID < MAX_VERTICES; vertexID++) + vertexIDs[vertexID] = vertexID; + + this.vertexIDVBO = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexIDVBO); + gl.bufferData(gl.ARRAY_BUFFER, vertexIDs, gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + } } function getMeshIndexRange(indexRanges: Range[], pathRange: Range): Range { diff --git a/demo/client/src/shader-loader.ts b/demo/client/src/shader-loader.ts index f3ef0798..cf94adea 100644 --- a/demo/client/src/shader-loader.ts +++ b/demo/client/src/shader-loader.ts @@ -14,6 +14,7 @@ import {expectNotNull, PathfinderError, unwrapNull} from './utils'; export interface ShaderMap { blitLinear: T; blitGamma: T; + conservativeInterior: T; demo3DDistantGlyph: T; demo3DMonument: T; directCurve: T; @@ -39,6 +40,7 @@ const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl'; export const SHADER_NAMES: Array> = [ 'blitLinear', 'blitGamma', + 'conservativeInterior', 'directCurve', 'directInterior', 'direct3DCurve', @@ -63,6 +65,10 @@ const SHADER_URLS: ShaderMap = { fragment: "/glsl/gles2/blit-linear.fs.glsl", vertex: "/glsl/gles2/blit.vs.glsl", }, + conservativeInterior: { + fragment: "/glsl/gles2/direct-interior.fs.glsl", + vertex: "/glsl/gles2/conservative-interior.vs.glsl", + }, demo3DDistantGlyph: { fragment: "/glsl/gles2/demo-3d-distant-glyph.fs.glsl", vertex: "/glsl/gles2/demo-3d-distant-glyph.vs.glsl", diff --git a/demo/client/src/svg-renderer.ts b/demo/client/src/svg-renderer.ts index 63f8d966..8abc069e 100644 --- a/demo/client/src/svg-renderer.ts +++ b/demo/client/src/svg-renderer.ts @@ -10,7 +10,8 @@ import * as glmatrix from 'gl-matrix'; -import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from './aa-strategy'; +import {AntialiasingStrategy, AntialiasingStrategyName, DirectRenderingMode} from './aa-strategy'; +import {NoAAStrategy} from './aa-strategy'; import {SubpixelAAType} from './aa-strategy'; import {OrthographicCamera} from "./camera"; import {UniformMap} from './gl-utils'; @@ -163,8 +164,9 @@ export abstract class SVGRenderer extends Renderer { return 'directCurve'; } - protected directInteriorProgramName(): keyof ShaderMap { - return 'directInterior'; + protected directInteriorProgramName(renderingMode: DirectRenderingMode): + keyof ShaderMap { + return renderingMode === 'conservative' ? 'conservativeInterior' : 'directInterior'; } protected pathColorsForObject(objectIndex: number): Uint8Array { diff --git a/demo/client/src/utils.ts b/demo/client/src/utils.ts index 5eb8e8f2..eda91b7b 100644 --- a/demo/client/src/utils.ts +++ b/demo/client/src/utils.ts @@ -11,8 +11,8 @@ import * as glmatrix from 'gl-matrix'; export const FLOAT32_SIZE: number = 4; - export const UINT16_SIZE: number = 2; +export const UINT8_SIZE: number = 1; export const UINT32_MAX: number = 0xffffffff; export const UINT32_SIZE: number = 4; diff --git a/demo/client/src/view.ts b/demo/client/src/view.ts index 09a59998..1595402a 100644 --- a/demo/client/src/view.ts +++ b/demo/client/src/view.ts @@ -23,17 +23,17 @@ import {ShaderProgramSource, UnlinkedShaderProgram} from './shader-loader'; import {expectNotNull, PathfinderError, UINT32_SIZE, unwrapNull} from './utils'; const QUAD_POSITIONS: Float32Array = new Float32Array([ - 0.0, 1.0, - 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, ]); const QUAD_TEX_COORDS: Float32Array = new Float32Array([ - 0.0, 1.0, - 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, ]); export const TIMINGS: {[name: string]: string} = { diff --git a/demo/client/src/xcaa-strategy.ts b/demo/client/src/xcaa-strategy.ts index 7750d8dd..9fdf01f5 100644 --- a/demo/client/src/xcaa-strategy.ts +++ b/demo/client/src/xcaa-strategy.ts @@ -33,15 +33,33 @@ type Direction = 'upper' | 'lower'; const DIRECTIONS: Direction[] = ['upper', 'lower']; +const PATCH_VERTICES: Float32Array = new Float32Array([ + 0.0, 0.0, + 0.5, 0.0, + 1.0, 0.0, + 0.0, 1.0, + 0.5, 1.0, + 1.0, 1.0, +]); + +const MCAA_PATCH_INDICES: Uint8Array = new Uint8Array([0, 1, 2, 0, 2, 3, 2, 5, 3, 3, 5, 4]); + +const ECAA_CURVE_PATCH_INDICES: Uint8Array = new Uint8Array([0, 1, 2, 0, 2, 3, 2, 5, 3]); + export abstract class XCAAStrategy extends AntialiasingStrategy { abstract readonly directRenderingMode: DirectRenderingMode; + protected patchVertexBuffer: WebGLBuffer | null; + protected patchIndexBuffer: WebGLBuffer | null; + get passCount(): number { return 1; } protected abstract get usesDilationTransforms(): boolean; + protected abstract get patchIndices(): Uint8Array; + protected pathBoundsBufferTextures: PathfinderBufferTexture[]; protected supersampledFramebufferSize: glmatrix.vec2; @@ -72,8 +90,22 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { attachMeshes(renderer: Renderer): void { const renderContext = renderer.renderContext; + const gl = renderContext.gl; + this.createResolveVAO(renderer); this.pathBoundsBufferTextures = []; + + this.patchVertexBuffer = unwrapNull(gl.createBuffer()); + gl.bindBuffer(gl.ARRAY_BUFFER, this.patchVertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, PATCH_VERTICES.buffer as ArrayBuffer, gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, null); + + this.patchIndexBuffer = unwrapNull(gl.createBuffer()); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.patchIndexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, + this.patchIndices.buffer as ArrayBuffer, + gl.STATIC_DRAW); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); } setFramebufferSize(renderer: Renderer): void { @@ -336,6 +368,10 @@ export abstract class XCAAStrategy extends AntialiasingStrategy { export class MCAAStrategy extends XCAAStrategy { protected vao: WebGLVertexArrayObject | null; + protected get patchIndices(): Uint8Array { + return MCAA_PATCH_INDICES; + } + protected get usesDilationTransforms(): boolean { return true; } @@ -348,7 +384,10 @@ export class MCAAStrategy extends XCAAStrategy { super.attachMeshes(renderer); const renderContext = renderer.renderContext; + const gl = renderContext.gl; + this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES(); + } antialiasObject(renderer: Renderer, objectIndex: number): void { @@ -372,14 +411,13 @@ export class MCAAStrategy extends XCAAStrategy { } protected clearForAA(renderer: Renderer): void { + if (!this.usesAAFramebuffer(renderer)) + return; + const renderContext = renderer.renderContext; const gl = renderContext.gl; - if (renderer.isMulticolor) - gl.clearColor(1.0, 1.0, 1.0, 1.0); - else - gl.clearColor(0.0, 0.0, 0.0, 0.0); - + gl.clearColor(0.0, 0.0, 0.0, 0.0); gl.clearDepth(0.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } @@ -388,7 +426,17 @@ export class MCAAStrategy extends XCAAStrategy { const renderContext = renderer.renderContext; const gl = renderContext.gl; - gl.disable(gl.DEPTH_TEST); + if (this.directRenderingMode !== 'conservative') { + gl.disable(gl.DEPTH_TEST); + return; + } + + gl.depthFunc(gl.GREATER); + gl.depthMask(false); + gl.enable(gl.DEPTH_TEST); + gl.frontFace(gl.CCW); + gl.cullFace(gl.BACK); + gl.enable(gl.CULL_FACE); } protected clearForResolve(renderer: Renderer): void { @@ -396,7 +444,7 @@ export class MCAAStrategy extends XCAAStrategy { const gl = renderContext.gl; if (!renderer.isMulticolor) { - gl.clearColor(1.0, 1.0, 0.0, 1.0); + gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); } } @@ -437,53 +485,80 @@ export class MCAAStrategy extends XCAAStrategy { const vao = this.vao; renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); - const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges; + const bQuadRanges = renderer.meshData[meshIndex].bQuadVertexPositionPathRanges; const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges); gl.useProgram(shaderProgram.program); - gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); - gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, this.patchVertexBuffer); + gl.vertexAttribPointer(attributes.aTessCoord, 2, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositions); - gl.vertexAttribPointer(attributes.aUpperEndpointPositions, - 4, + gl.vertexAttribPointer(attributes.aUpperLeftEndpointPosition, + 2, gl.FLOAT, false, FLOAT32_SIZE * 12, - FLOAT32_SIZE * 12 * offset); - gl.vertexAttribPointer(attributes.aLowerEndpointPositions, - 4, + FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 0); + gl.vertexAttribPointer(attributes.aUpperControlPointPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 12, + FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 2); + gl.vertexAttribPointer(attributes.aUpperRightEndpointPosition, + 2, gl.FLOAT, false, FLOAT32_SIZE * 12, FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 4); - gl.vertexAttribPointer(attributes.aControlPointPositions, - 4, + gl.vertexAttribPointer(attributes.aLowerRightEndpointPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 12, + FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 6); + gl.vertexAttribPointer(attributes.aLowerControlPointPosition, + 2, gl.FLOAT, false, FLOAT32_SIZE * 12, FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 8); + gl.vertexAttribPointer(attributes.aLowerLeftEndpointPosition, + 2, + gl.FLOAT, + false, + FLOAT32_SIZE * 12, + FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 10); renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aUpperEndpointPositions, 1); + .vertexAttribDivisorANGLE(attributes.aUpperLeftEndpointPosition, 1); renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aLowerEndpointPositions, 1); + .vertexAttribDivisorANGLE(attributes.aUpperControlPointPosition, 1); renderContext.instancedArraysExt - .vertexAttribDivisorANGLE(attributes.aControlPointPositions, 1); + .vertexAttribDivisorANGLE(attributes.aUpperRightEndpointPosition, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aLowerRightEndpointPosition, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aLowerControlPointPosition, 1); + renderContext.instancedArraysExt + .vertexAttribDivisorANGLE(attributes.aLowerLeftEndpointPosition, 1); - gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].edgeBoundingBoxPathIDs); + gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositionPathIDs); gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, - 0, + UINT16_SIZE * 6, UINT16_SIZE * offset); renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1); - gl.enableVertexAttribArray(attributes.aQuadPosition); - gl.enableVertexAttribArray(attributes.aUpperEndpointPositions); - gl.enableVertexAttribArray(attributes.aLowerEndpointPositions); - gl.enableVertexAttribArray(attributes.aControlPointPositions); + gl.enableVertexAttribArray(attributes.aTessCoord); + gl.enableVertexAttribArray(attributes.aUpperLeftEndpointPosition); + gl.enableVertexAttribArray(attributes.aUpperControlPointPosition); + gl.enableVertexAttribArray(attributes.aUpperRightEndpointPosition); + gl.enableVertexAttribArray(attributes.aLowerRightEndpointPosition); + gl.enableVertexAttribArray(attributes.aLowerControlPointPosition); + gl.enableVertexAttribArray(attributes.aLowerLeftEndpointPosition); gl.enableVertexAttribArray(attributes.aPathID); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.patchIndexBuffer); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); } @@ -516,18 +591,22 @@ export class MCAAStrategy extends XCAAStrategy { renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao); this.setBlendModeForAA(renderer); + this.setAADepthState(renderer); - const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges; + const bQuadRanges = renderer.meshData[meshIndex].bQuadVertexPositionPathRanges; const count = calculateCountFromIndexRanges(pathRange, bQuadRanges); renderContext.instancedArraysExt - .drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count); + .drawElementsInstancedANGLE(gl.TRIANGLES, 12, gl.UNSIGNED_BYTE, 0, count); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); + gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); } get directRenderingMode(): DirectRenderingMode { - return 'none'; + // FIXME(pcwalton): Only in multicolor mode? + return 'conservative'; } protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): @@ -544,6 +623,10 @@ export class MCAAStrategy extends XCAAStrategy { } export class ECAAStrategy extends XCAAStrategy { + protected get patchIndices(): Uint8Array { + return ECAA_CURVE_PATCH_INDICES; + } + protected get lineShaderProgramNames(): Array> { return ['ecaaLine']; } @@ -588,6 +671,11 @@ export class ECAAStrategy extends XCAAStrategy { objectIndex, this.curveShaderProgramNames[0], this.curveShaderProgramNames[1]); + + const renderContext = renderer.renderContext; + const gl = renderContext.gl; + + gl.disable(gl.CULL_FACE); } protected usesAAFramebuffer(): boolean { @@ -619,7 +707,13 @@ export class ECAAStrategy extends XCAAStrategy { protected setAADepthState(renderer: Renderer): void { const renderContext = renderer.renderContext; - renderContext.gl.disable(renderContext.gl.DEPTH_TEST); + const gl = renderContext.gl; + + gl.disable(gl.DEPTH_TEST); + + gl.frontFace(gl.CCW); + gl.cullFace(gl.BACK); + gl.enable(gl.CULL_FACE); } protected clearForResolve(renderer: Renderer): void { @@ -699,7 +793,7 @@ export class ECAAStrategy extends XCAAStrategy { // FIXME(pcwalton): Only render the appropriate instances. const count = renderer.meshData[meshIndex].segmentCurveCount; renderContext.instancedArraysExt - .drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count); + .drawElementsInstancedANGLE(gl.TRIANGLES, 9, gl.UNSIGNED_BYTE, 0, count); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); } @@ -735,7 +829,7 @@ export class ECAAStrategy extends XCAAStrategy { gl.useProgram(lineProgram.program); gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); - gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); + gl.vertexAttribPointer(attributes.aTessCoord, 2, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionsBuffer); gl.vertexAttribPointer(attributes.aLeftPosition, 2, @@ -752,7 +846,7 @@ export class ECAAStrategy extends XCAAStrategy { gl.bindBuffer(gl.ARRAY_BUFFER, linePathIDsBuffer); gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0); - gl.enableVertexAttribArray(attributes.aQuadPosition); + gl.enableVertexAttribArray(attributes.aTessCoord); gl.enableVertexAttribArray(attributes.aLeftPosition); gl.enableVertexAttribArray(attributes.aRightPosition); gl.enableVertexAttribArray(attributes.aPathID); @@ -805,8 +899,8 @@ export class ECAAStrategy extends XCAAStrategy { const curveNormalsBuffer = renderer.meshes[0].segmentCurveNormals; gl.useProgram(curveProgram.program); - gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer); - gl.vertexAttribPointer(attributes.aQuadPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindBuffer(gl.ARRAY_BUFFER, this.patchVertexBuffer); + gl.vertexAttribPointer(attributes.aTessCoord, 2, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer); gl.vertexAttribPointer(attributes.aLeftPosition, 2, @@ -829,7 +923,7 @@ export class ECAAStrategy extends XCAAStrategy { gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer); gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0); - gl.enableVertexAttribArray(attributes.aQuadPosition); + gl.enableVertexAttribArray(attributes.aTessCoord); gl.enableVertexAttribArray(attributes.aLeftPosition); gl.enableVertexAttribArray(attributes.aControlPointPosition); gl.enableVertexAttribArray(attributes.aRightPosition); @@ -857,7 +951,7 @@ export class ECAAStrategy extends XCAAStrategy { .vertexAttribDivisorANGLE(attributes.aNormalAngles, 1); } - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.patchIndexBuffer); renderContext.vertexArrayObjectExt.bindVertexArrayOES(null); diff --git a/demo/server/Cargo.toml b/demo/server/Cargo.toml index ea3d0f34..7358289e 100644 --- a/demo/server/Cargo.toml +++ b/demo/server/Cargo.toml @@ -17,9 +17,6 @@ image = "0.17" lazy_static = "0.2" log = "0.3" lru-cache = "0.1" -rocket = "0.3" -rocket_codegen = "0.3" -rocket_contrib = "0.3" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" @@ -36,6 +33,15 @@ optional = true [dependencies.fontsan] git = "https://github.com/servo/fontsan.git" +[dependencies.rocket] +git = "https://github.com/SergioBenitez/rocket" + +[dependencies.rocket_codegen] +git = "https://github.com/SergioBenitez/rocket" + +[dependencies.rocket_contrib] +git = "https://github.com/SergioBenitez/rocket" + [dependencies.pathfinder_font_renderer] path = "../../font-renderer" @@ -44,3 +50,6 @@ path = "../../partitioner" [dependencies.pathfinder_path_utils] path = "../../path-utils" + +[patch.crates-io] +ring = { git = "https://github.com/SergioBenitez/ring", branch = "v0.12" } diff --git a/demo/server/src/main.rs b/demo/server/src/main.rs index 4a2a9505..b1effa52 100644 --- a/demo/server/src/main.rs +++ b/demo/server/src/main.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(plugin)] +#![feature(decl_macro, plugin)] #![plugin(rocket_codegen)] extern crate app_units; diff --git a/partitioner/src/capi.rs b/partitioner/src/capi.rs index 700b456f..43660e39 100644 --- a/partitioner/src/capi.rs +++ b/partitioner/src/capi.rs @@ -112,16 +112,6 @@ pub unsafe extern fn pf_partitioner_b_vertex_loop_blinn_data<'a>( b_vertex_loop_blinn_data.as_ptr() as *const BVertexLoopBlinnData } -#[no_mangle] -pub unsafe extern fn pf_partitioner_cover_indices<'a>(partitioner: *const Partitioner<'a>, - out_cover_indices: *mut CoverIndices) { - let cover_indices = &(*partitioner).library().cover_indices; - (*out_cover_indices).interior_indices = cover_indices.interior_indices.as_ptr(); - (*out_cover_indices).interior_indices_len = cover_indices.interior_indices.len() as u32; - (*out_cover_indices).curve_indices = cover_indices.curve_indices.as_ptr(); - (*out_cover_indices).curve_indices_len = cover_indices.curve_indices.len() as u32; -} - #[no_mangle] pub unsafe extern fn pf_init_env_logger() -> u32 { env_logger::init().is_ok() as u32 diff --git a/partitioner/src/lib.rs b/partitioner/src/lib.rs index cb12f84d..16e6094c 100644 --- a/partitioner/src/lib.rs +++ b/partitioner/src/lib.rs @@ -103,9 +103,12 @@ impl BQuad { #[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)] pub struct BQuadVertexPositions { - pub upper_endpoint_positions: [Point2D; 2], - pub lower_endpoint_positions: [Point2D; 2], - pub control_point_positions: [Point2D; 2], + pub upper_left_vertex_position: Point2D, + pub upper_control_point_position: Point2D, + pub upper_right_vertex_position: Point2D, + pub lower_right_vertex_position: Point2D, + pub lower_control_point_position: Point2D, + pub lower_left_vertex_position: Point2D, } #[derive(Clone, Copy, PartialEq, Debug)] @@ -124,7 +127,7 @@ pub(crate) enum BVertexKind { ConcaveControlPoint, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug)] #[repr(C)] pub struct BVertexLoopBlinnData { pub tex_coord: [u8; 2], diff --git a/partitioner/src/mesh_library.rs b/partitioner/src/mesh_library.rs index 771ad50b..4d78610d 100644 --- a/partitioner/src/mesh_library.rs +++ b/partitioner/src/mesh_library.rs @@ -26,11 +26,10 @@ pub struct MeshLibrary { pub b_quads: Vec, // FIXME(pcwalton): Merge with `b_vertex_positions` below. pub b_quad_vertex_positions: Vec, + pub b_quad_vertex_interior_indices: Vec, pub b_vertex_positions: Vec>, pub b_vertex_loop_blinn_data: Vec, pub b_vertex_normals: Vec, - pub cover_indices: MeshLibraryCoverIndices, - pub edge_data: MeshLibraryEdgeData, pub segments: MeshLibrarySegments, pub segment_normals: MeshLibrarySegmentNormals, } @@ -42,11 +41,10 @@ impl MeshLibrary { path_ranges: vec![], b_quads: vec![], b_quad_vertex_positions: vec![], + b_quad_vertex_interior_indices: vec![], b_vertex_positions: vec![], b_vertex_loop_blinn_data: vec![], b_vertex_normals: vec![], - cover_indices: MeshLibraryCoverIndices::new(), - edge_data: MeshLibraryEdgeData::new(), segments: MeshLibrarySegments::new(), segment_normals: MeshLibrarySegmentNormals::new(), } @@ -56,11 +54,10 @@ impl MeshLibrary { self.path_ranges.clear(); self.b_quads.clear(); self.b_quad_vertex_positions.clear(); + self.b_quad_vertex_interior_indices.clear(); self.b_vertex_positions.clear(); self.b_vertex_loop_blinn_data.clear(); self.b_vertex_normals.clear(); - self.cover_indices.clear(); - self.edge_data.clear(); self.segments.clear(); self.segment_normals.clear(); } @@ -86,85 +83,99 @@ impl MeshLibrary { self.b_quads.push(*b_quad); let upper_left_position = - &self.b_vertex_positions[b_quad.upper_left_vertex_index as usize]; + self.b_vertex_positions[b_quad.upper_left_vertex_index as usize]; let upper_right_position = - &self.b_vertex_positions[b_quad.upper_right_vertex_index as usize]; + self.b_vertex_positions[b_quad.upper_right_vertex_index as usize]; let lower_left_position = - &self.b_vertex_positions[b_quad.lower_left_vertex_index as usize]; + self.b_vertex_positions[b_quad.lower_left_vertex_index as usize]; let lower_right_position = - &self.b_vertex_positions[b_quad.lower_right_vertex_index as usize]; + self.b_vertex_positions[b_quad.lower_right_vertex_index as usize]; let mut b_quad_vertex_positions = BQuadVertexPositions { - upper_endpoint_positions: [*upper_left_position, *upper_right_position], - lower_endpoint_positions: [*lower_left_position, *lower_right_position], - control_point_positions: [Point2D::zero(), Point2D::zero()], + upper_left_vertex_position: upper_left_position, + upper_control_point_position: upper_left_position, + upper_right_vertex_position: upper_right_position, + lower_left_vertex_position: lower_left_position, + lower_control_point_position: lower_right_position, + lower_right_vertex_position: lower_right_position, }; - let upper_left_bounding_box_position = - Point2D::new(upper_left_position.x, - f32::max(upper_left_position.y, upper_right_position.y)); - let lower_right_bounding_box_position = - Point2D::new(lower_right_position.x, - f32::max(lower_left_position.y, lower_right_position.y)); - - self.edge_data.bounding_box_vertex_positions.push(EdgeBoundingBoxVertexPositions { - upper_left: upper_left_bounding_box_position, - lower_right: lower_right_bounding_box_position, - }); - - 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, - }); - } else { + if b_quad.upper_control_point_vertex_index != u32::MAX { let upper_control_point_position = - &self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize]; - b_quad_vertex_positions.control_point_positions[0] = *upper_control_point_position; - self.edge_data.upper_curve_vertex_positions.push(EdgeCurveVertexPositions { - left: *upper_left_position, - control_point: *upper_control_point_position, - right: *upper_right_position, - }); + self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize]; + b_quad_vertex_positions.upper_control_point_position = upper_control_point_position; } - if b_quad.lower_control_point_vertex_index == u32::MAX { - self.edge_data.lower_line_vertex_positions.push(EdgeLineVertexPositions { - left: *lower_left_position, - right: *lower_right_position, - }); - } else { + if b_quad.lower_control_point_vertex_index != u32::MAX { let lower_control_point_position = - &self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize]; - b_quad_vertex_positions.control_point_positions[1] = *lower_control_point_position; - self.edge_data.lower_curve_vertex_positions.push(EdgeCurveVertexPositions { - left: *lower_left_position, - control_point: *lower_control_point_position, - right: *lower_right_position, - }); + self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize]; + b_quad_vertex_positions.lower_control_point_position = lower_control_point_position; } + let first_b_quad_vertex_position_index = (self.b_quad_vertex_positions.len() as u32) * 6; + self.push_b_quad_vertex_position_interior_indices(first_b_quad_vertex_position_index, + &b_quad_vertex_positions); + self.b_quad_vertex_positions.push(b_quad_vertex_positions); } + fn push_b_quad_vertex_position_interior_indices(&mut self, + first_vertex_index: u32, + b_quad: &BQuadVertexPositions) { + let upper_curve_is_concave = + (b_quad.upper_right_vertex_position - b_quad.upper_left_vertex_position).cross( + b_quad.upper_control_point_position - b_quad.upper_left_vertex_position) > 0.0; + let lower_curve_is_concave = + (b_quad.lower_left_vertex_position - b_quad.lower_right_vertex_position).cross( + b_quad.lower_control_point_position - b_quad.lower_right_vertex_position) > 0.0; + + let indices: &'static [u32] = match (upper_curve_is_concave, lower_curve_is_concave) { + (false, false) => &[UL, UR, LL, UR, LR, LL], + (true, false) => &[UL, UC, LL, UC, LR, LL, UR, LR, UC], + (false, true) => &[UL, LC, LL, UL, UR, LC, UR, LR, LC], + (true, true) => &[UL, UC, LL, UC, LC, LL, UR, LC, UC, UR, LR, LC], + }; + + self.b_quad_vertex_interior_indices + .extend(indices.into_iter().map(|index| index + first_vertex_index)); + + const UL: u32 = 0; + const UC: u32 = 1; + const UR: u32 = 2; + const LR: u32 = 3; + const LC: u32 = 4; + const LL: u32 = 5; + } + /// Reverses interior indices so that they draw front-to-back. /// /// This enables early Z optimizations. pub fn optimize(&mut self) { - let mut new_interior_indices = - Vec::with_capacity(self.cover_indices.interior_indices.len()); + reverse_indices(&mut self.path_ranges, + &mut self.b_quad_vertex_interior_indices, + |path_ranges| path_ranges.b_quad_vertex_interior_indices.clone(), + |path_ranges, new_range| { + path_ranges.b_quad_vertex_interior_indices = new_range + }); - for path_range in self.path_ranges.iter_mut().rev() { - 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; + fn reverse_indices(path_ranges: &mut [PathRanges], + indices: &mut Vec, + mut getter: G, + mut setter: S) + where G: FnMut(&PathRanges) -> Range, + S: FnMut(&mut PathRanges, Range) { + let mut new_indices = Vec::with_capacity(indices.len()); + for path_range in path_ranges.iter_mut().rev() { + let old_range = getter(path_range); + let old_range = (old_range.start as usize)..(old_range.end as usize); + let new_start_index = new_indices.len() as u32; + new_indices.extend_from_slice(&indices[old_range]); + let new_end_index = new_indices.len() as u32; + setter(path_range, new_start_index..new_end_index); + } + + *indices = new_indices } - - self.cover_indices.interior_indices = new_interior_indices } pub fn push_segments(&mut self, path_id: u16, stream: I) @@ -220,16 +231,7 @@ impl MeshLibrary { try!(write_simple_chunk(writer, b"bqua", &self.b_quads)); try!(write_simple_chunk(writer, b"bqvp", &self.b_quad_vertex_positions)); - 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"bqii", &self.b_quad_vertex_interior_indices)); 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)); @@ -274,35 +276,11 @@ impl MeshLibrary { b"bqvp", path_ranges, |ranges| &ranges.b_quad_vertex_positions)); + try!(write_path_range(writer, + b"bqii", + path_ranges, + |ranges| &ranges.b_quad_vertex_interior_indices)); 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(()) @@ -329,14 +307,8 @@ impl MeshLibrary { MeshLibraryLengths { b_quads: self.b_quads.len() as u32, b_quad_vertex_positions: self.b_quad_vertex_positions.len() as u32, + b_quad_vertex_interior_indices: self.b_quad_vertex_interior_indices.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, } } } @@ -347,46 +319,19 @@ pub struct MeshLibraryCoverIndices { pub curve_indices: Vec, } -impl MeshLibraryCoverIndices { - #[inline] - fn new() -> MeshLibraryCoverIndices { - MeshLibraryCoverIndices { - interior_indices: vec![], - curve_indices: vec![], - } - } - - fn clear(&mut self) { - self.interior_indices.clear(); - self.curve_indices.clear(); - } -} - pub(crate) struct MeshLibraryLengths { - b_quads: u32, + pub(crate) b_quads: u32, b_quad_vertex_positions: u32, + b_quad_vertex_interior_indices: 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, } #[derive(Clone, Debug)] pub struct PathRanges { pub b_quads: Range, pub b_quad_vertex_positions: Range, + pub b_quad_vertex_interior_indices: 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, } @@ -396,14 +341,8 @@ impl PathRanges { PathRanges { b_quads: 0..0, b_quad_vertex_positions: 0..0, + b_quad_vertex_interior_indices: 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, } @@ -414,46 +353,9 @@ impl PathRanges { end: &MeshLibraryLengths) { self.b_quads = start.b_quads..end.b_quads; self.b_quad_vertex_positions = start.b_quad_vertex_positions..end.b_quad_vertex_positions; + self.b_quad_vertex_interior_indices = + start.b_quad_vertex_interior_indices..end.b_quad_vertex_interior_indices; 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)] -pub struct MeshLibraryEdgeData { - pub bounding_box_vertex_positions: Vec, - pub upper_line_vertex_positions: Vec, - pub lower_line_vertex_positions: Vec, - pub upper_curve_vertex_positions: Vec, - pub lower_curve_vertex_positions: Vec, -} - -impl MeshLibraryEdgeData { - fn new() -> MeshLibraryEdgeData { - MeshLibraryEdgeData { - bounding_box_vertex_positions: vec![], - upper_line_vertex_positions: vec![], - lower_line_vertex_positions: vec![], - upper_curve_vertex_positions: vec![], - lower_curve_vertex_positions: vec![], - } - } - - fn clear(&mut self) { - self.bounding_box_vertex_positions.clear(); - self.upper_line_vertex_positions.clear(); - self.upper_curve_vertex_positions.clear(); - self.lower_line_vertex_positions.clear(); - self.lower_curve_vertex_positions.clear(); } } @@ -497,25 +399,6 @@ impl MeshLibrarySegmentNormals { } } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct EdgeBoundingBoxVertexPositions { - pub upper_left: Point2D, - pub lower_right: Point2D, -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct EdgeLineVertexPositions { - pub left: Point2D, - pub right: Point2D, -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct EdgeCurveVertexPositions { - pub left: Point2D, - pub control_point: Point2D, - pub right: Point2D, -} - #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct LineSegment { pub endpoint_0: Point2D, diff --git a/partitioner/src/partitioner.rs b/partitioner/src/partitioner.rs index cda9b1a2..93a52e38 100644 --- a/partitioner/src/partitioner.rs +++ b/partitioner/src/partitioner.rs @@ -177,24 +177,10 @@ impl<'a> Partitioner<'a> { let next_active_edge_index = self.find_point_between_active_edges(endpoint_index); let endpoint = &self.endpoints[endpoint_index as usize]; - let emission_result = self.emit_b_quads_around_active_edge(next_active_edge_index, - endpoint.position.x); + self.emit_b_quads_around_active_edge(next_active_edge_index, endpoint.position.x); self.add_new_edges_for_min_point(endpoint_index, next_active_edge_index); - // Add supporting interior triangles if necessary. - match emission_result { - BQuadEmissionResult::BQuadEmittedAbove | BQuadEmissionResult::BQuadEmittedAround => { - self.add_supporting_interior_triangle(next_active_edge_index, - next_active_edge_index - 1, - next_active_edge_index + 2); - self.add_supporting_interior_triangle(next_active_edge_index + 1, - next_active_edge_index - 1, - next_active_edge_index + 2); - } - _ => {} - } - let prev_endpoint_index = self.prev_endpoint_of(endpoint_index); let next_endpoint_index = self.next_endpoint_of(endpoint_index); let new_point = self.create_point_from_endpoint(next_endpoint_index); @@ -291,29 +277,10 @@ impl<'a> Partitioner<'a> { // TODO(pcwalton): Collapse the two duplicate endpoints that this will create together if // possible (i.e. if they have the same parity). - let b_quad_emission_results = [ - self.emit_b_quads_around_active_edge(active_edge_indices[0], endpoint.position.x), - self.emit_b_quads_around_active_edge(active_edge_indices[1], endpoint.position.x), - ]; + self.emit_b_quads_around_active_edge(active_edge_indices[0], endpoint.position.x); + self.emit_b_quads_around_active_edge(active_edge_indices[1], endpoint.position.x); // Add supporting interior triangles if necessary. - match b_quad_emission_results[0] { - BQuadEmissionResult::BQuadEmittedAbove | BQuadEmissionResult::BQuadEmittedAround => { - self.add_supporting_interior_triangle(active_edge_indices[0], - active_edge_indices[0] - 1, - active_edge_indices[0] + 2) - } - _ => {} - } - match b_quad_emission_results[1] { - BQuadEmissionResult::BQuadEmittedBelow | BQuadEmissionResult::BQuadEmittedAround => { - self.add_supporting_interior_triangle(active_edge_indices[1], - active_edge_indices[1] - 2, - active_edge_indices[1] + 1) - } - _ => {} - } - self.heap.pop(); // FIXME(pcwalton): This is twice as slow as it needs to be. @@ -360,6 +327,7 @@ impl<'a> Partitioner<'a> { } fn write_normals_to_library(&mut self) { + // Write B-vertex normals. for (b_vertex_index, vertex_normal) in self.vertex_normals.iter().enumerate() { debug_assert!(b_vertex_index <= self.library.b_vertex_normals.len()); @@ -695,115 +663,6 @@ impl<'a> Partitioner<'a> { lower_active_edge.toggle_parity(); } - match (upper_shape, lower_shape) { - (Shape::Flat, Shape::Flat) | - (Shape::Flat, Shape::Convex) | - (Shape::Convex, Shape::Flat) | - (Shape::Convex, Shape::Convex) => { - self.library.cover_indices.interior_indices.extend([ - upper_subdivision.left_curve_left, - upper_subdivision.middle_point, - lower_subdivision.left_curve_left, - lower_subdivision.middle_point, - lower_subdivision.left_curve_left, - upper_subdivision.middle_point, - ].into_iter()); - if upper_shape != Shape::Flat { - self.library.cover_indices.curve_indices.extend([ - upper_subdivision.left_curve_control_point, - upper_subdivision.middle_point, - upper_subdivision.left_curve_left, - ].into_iter()) - } - if lower_shape != Shape::Flat { - self.library.cover_indices.curve_indices.extend([ - lower_subdivision.left_curve_control_point, - lower_subdivision.left_curve_left, - lower_subdivision.middle_point, - ].into_iter()) - } - } - - (Shape::Concave, Shape::Flat) | - (Shape::Concave, Shape::Convex) => { - self.library.cover_indices.interior_indices.extend([ - upper_subdivision.left_curve_left, - upper_subdivision.left_curve_control_point, - lower_subdivision.left_curve_left, - upper_subdivision.middle_point, - lower_subdivision.middle_point, - upper_subdivision.left_curve_control_point, - lower_subdivision.middle_point, - lower_subdivision.left_curve_left, - upper_subdivision.left_curve_control_point, - ].into_iter()); - self.library.cover_indices.curve_indices.extend([ - upper_subdivision.left_curve_control_point, - upper_subdivision.left_curve_left, - upper_subdivision.middle_point, - ].into_iter()); - if lower_shape != Shape::Flat { - self.library.cover_indices.curve_indices.extend([ - lower_subdivision.left_curve_control_point, - lower_subdivision.left_curve_left, - lower_subdivision.middle_point, - ].into_iter()) - } - } - - (Shape::Flat, Shape::Concave) | - (Shape::Convex, Shape::Concave) => { - self.library.cover_indices.interior_indices.extend([ - upper_subdivision.left_curve_left, - upper_subdivision.middle_point, - lower_subdivision.left_curve_control_point, - upper_subdivision.middle_point, - lower_subdivision.middle_point, - lower_subdivision.left_curve_control_point, - upper_subdivision.left_curve_left, - lower_subdivision.left_curve_control_point, - lower_subdivision.left_curve_left, - ].into_iter()); - self.library.cover_indices.curve_indices.extend([ - lower_subdivision.left_curve_control_point, - lower_subdivision.middle_point, - lower_subdivision.left_curve_left, - ].into_iter()); - if upper_shape != Shape::Flat { - self.library.cover_indices.curve_indices.extend([ - upper_subdivision.left_curve_control_point, - upper_subdivision.middle_point, - upper_subdivision.left_curve_left, - ].into_iter()) - } - } - - (Shape::Concave, Shape::Concave) => { - self.library.cover_indices.interior_indices.extend([ - upper_subdivision.left_curve_left, - upper_subdivision.left_curve_control_point, - lower_subdivision.left_curve_left, - lower_subdivision.left_curve_left, - upper_subdivision.left_curve_control_point, - lower_subdivision.left_curve_control_point, - upper_subdivision.middle_point, - lower_subdivision.left_curve_control_point, - upper_subdivision.left_curve_control_point, - upper_subdivision.middle_point, - lower_subdivision.middle_point, - lower_subdivision.left_curve_control_point, - ].into_iter()); - self.library.cover_indices.curve_indices.extend([ - upper_subdivision.left_curve_control_point, - upper_subdivision.left_curve_left, - upper_subdivision.middle_point, - lower_subdivision.left_curve_control_point, - lower_subdivision.middle_point, - lower_subdivision.left_curve_left, - ].into_iter()); - } - } - let b_quad = BQuad::new(upper_subdivision.left_curve_left, upper_subdivision.left_curve_control_point, upper_subdivision.middle_point, @@ -872,17 +731,6 @@ impl<'a> Partitioner<'a> { self.subdivide_active_edge_again_at_t(subdivision, t, bottom) } - fn add_supporting_interior_triangle(&mut self, - active_edge_index: u32, - upper_active_edge_index: u32, - lower_active_edge_index: u32) { - self.library.cover_indices.interior_indices.extend([ - self.active_edges[active_edge_index as usize].left_vertex_index, - self.active_edges[upper_active_edge_index as usize].left_vertex_index, - self.active_edges[lower_active_edge_index as usize].left_vertex_index, - ].into_iter()); - } - fn already_visited_point(&self, point: &Point) -> bool { // FIXME(pcwalton): This makes the visited vector too big. let index = point.endpoint_index as usize; diff --git a/shaders/gles2/common.inc.glsl b/shaders/gles2/common.inc.glsl index a9035667..58278be5 100644 --- a/shaders/gles2/common.inc.glsl +++ b/shaders/gles2/common.inc.glsl @@ -117,6 +117,12 @@ vec2 dilatePosition(vec2 position, float normalAngle, vec2 amount) { return position + vec2(cos(normalAngle), -sin(normalAngle)) * amount; } +vec2 offsetPositionVertically(vec2 position, ivec2 framebufferSize, bool roundUp) { + position = convertClipToScreenSpace(position, framebufferSize); + position.y = roundUp ? ceil(position.y + 1.0) : floor(position.y - 1.0); + return convertScreenToClipSpace(position, framebufferSize); +} + vec2 computeMCAAPosition(vec2 position, vec4 hints, vec4 localTransformST, diff --git a/shaders/gles2/conservative-interior.vs.glsl b/shaders/gles2/conservative-interior.vs.glsl new file mode 100644 index 00000000..be76e8b7 --- /dev/null +++ b/shaders/gles2/conservative-interior.vs.glsl @@ -0,0 +1,72 @@ +// pathfinder/shaders/gles2/direct-interior.vs.glsl +// +// Copyright (c) 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Renders polygonal portions of a mesh, only filling pixels that are fully +//! covered. +//! +//! Typically, you will run this shader before running XCAA. +//! Remember to enable the depth test with a `GREATER` depth function for optimal +//! performance. + +precision highp float; + +/// A 3D transform to be applied to all points. +uniform mat4 uTransform; +/// Vertical snapping positions. +uniform vec4 uHints; +/// The framebuffer size in pixels. +uniform ivec2 uFramebufferSize; +/// The size of the path colors texture in texels. +uniform ivec2 uPathColorsDimensions; +/// The fill color for each path. +uniform sampler2D uPathColors; +/// The size of the path transform buffer texture in texels. +uniform ivec2 uPathTransformSTDimensions; +/// The path transform buffer texture, one path dilation per texel. +uniform sampler2D uPathTransformST; +/// The size of the extra path transform factors buffer texture in texels. +uniform ivec2 uPathTransformExtDimensions; +/// The extra path transform factors buffer texture, packed two path transforms per texel. +uniform sampler2D uPathTransformExt; +/// The amount of faux-bold to apply, in local path units. +uniform vec2 uEmboldenAmount; + +/// The 2D position of this point. +attribute vec2 aPosition; +/// The path ID, starting from 1. +attribute float aPathID; +/// The vertex ID. In OpenGL 3.0+, this can be omitted in favor of `gl_VertexID`. +attribute float aVertexID; + +/// The color of this path. +varying vec4 vColor; + +void main() { + int pathID = int(aPathID); + int vertexID = int(aVertexID); + + vec2 pathTransformExt; + vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, + uPathTransformST, + uPathTransformSTDimensions, + uPathTransformExt, + uPathTransformExtDimensions, + pathID); + + vec2 position = hintPosition(aPosition, uHints); + position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt); + position = transformVertexPosition(position, uTransform); + position = offsetPositionVertically(position, uFramebufferSize, imod(vertexID, 6) < 3); + + float depth = convertPathIndexToViewportDepthValue(pathID); + gl_Position = vec4(position, depth, 1.0); + + vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); +} diff --git a/shaders/gles2/direct-3d-curve.vs.glsl b/shaders/gles2/direct-3d-curve.vs.glsl index 1e10446d..8ff41fd7 100644 --- a/shaders/gles2/direct-3d-curve.vs.glsl +++ b/shaders/gles2/direct-3d-curve.vs.glsl @@ -35,24 +35,21 @@ uniform vec2 uEmboldenAmount; /// The 2D position of this point. attribute vec2 aPosition; -/// The abstract Loop-Blinn texture coordinate for this point. -attribute vec2 aTexCoord; -/// The path ID, starting from 1. -attribute float aPathID; -/// Specifies whether this is a concave or convex curve. -attribute float aSign; /// The angle of the 2D normal for this point. attribute float aNormalAngle; +/// The vertex ID. In OpenGL 3.0+, this can be omitted in favor of `gl_VertexID`. +attribute float aVertexID; +/// The path ID, starting from 1. +attribute float aPathID; /// The fill color of this path. varying vec4 vColor; /// The outgoing abstract Loop-Blinn texture coordinate. varying vec2 vTexCoord; -/// Specifies whether this is a concave or convex curve. -varying float vSign; void main() { int pathID = int(aPathID); + int vertexID = int(aVertexID); vec2 pathTransformExt; vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, @@ -67,7 +64,9 @@ void main() { gl_Position = uTransform * vec4(position, 0.0, 1.0); + int vertexIndex = imod(vertexID, 3); + vec2 texCoord = vec2(float(vertexIndex) * 0.5, float(vertexIndex == 2)); + vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); - vTexCoord = vec2(aTexCoord) / 2.0; - vSign = aSign; + vTexCoord = texCoord; } diff --git a/shaders/gles2/direct-curve.fs.glsl b/shaders/gles2/direct-curve.fs.glsl index ab0f67f6..4517930f 100644 --- a/shaders/gles2/direct-curve.fs.glsl +++ b/shaders/gles2/direct-curve.fs.glsl @@ -25,11 +25,11 @@ precision highp float; varying vec4 vColor; /// The abstract Loop-Blinn texture coordinate. varying vec2 vTexCoord; -/// Specifies whether this is a concave or convex curve. -varying float vSign; void main() { - float side = vTexCoord.x * vTexCoord.x - vTexCoord.y; - float alpha = float(sign(side) == sign(vSign)); + float side = sign(vTexCoord.x * vTexCoord.x - vTexCoord.y); + float winding = gl_FrontFacing ? -1.0 : 1.0; + float alpha = float(side == winding); + //float alpha = mod(gl_FragCoord.x, 2.0) < 1.0 ? 1.0 : 0.0; gl_FragColor = alpha * vColor; } diff --git a/shaders/gles2/direct-curve.vs.glsl b/shaders/gles2/direct-curve.vs.glsl index c0d62363..bf9deb96 100644 --- a/shaders/gles2/direct-curve.vs.glsl +++ b/shaders/gles2/direct-curve.vs.glsl @@ -37,29 +37,22 @@ uniform sampler2D uPathTransformST; uniform ivec2 uPathTransformExtDimensions; /// The extra path transform factors buffer texture, packed two path transforms per texel. uniform sampler2D uPathTransformExt; -/// The amount of faux-bold to apply, in local path units. -uniform vec2 uEmboldenAmount; /// The 2D position of this point. attribute vec2 aPosition; -/// The abstract Loop-Blinn texture coordinate for this point. -attribute vec2 aTexCoord; +/// The vertex ID. In OpenGL 3.0+, this can be omitted in favor of `gl_VertexID`. +attribute float aVertexID; /// The path ID, starting from 1. attribute float aPathID; -/// Specifies whether this is a concave or convex curve. -attribute float aSign; -/// The angle of the 2D normal for this point. -attribute float aNormalAngle; /// The fill color of this path. varying vec4 vColor; /// The outgoing abstract Loop-Blinn texture coordinate. varying vec2 vTexCoord; -/// Specifies whether this is a concave or convex curve. -varying float vSign; void main() { int pathID = int(aPathID); + int vertexID = int(aVertexID); vec2 pathTransformExt; vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt, @@ -69,15 +62,16 @@ void main() { uPathTransformExtDimensions, pathID); - vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); - position = hintPosition(position, uHints); + vec2 position = hintPosition(aPosition, uHints); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt); position = transformVertexPosition(position, uTransform); float depth = convertPathIndexToViewportDepthValue(pathID); gl_Position = vec4(position, depth, 1.0); + int vertexIndex = imod(vertexID, 3); + vec2 texCoord = vec2(float(vertexIndex) * 0.5, float(vertexIndex == 2)); + vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions); - vTexCoord = vec2(aTexCoord) / 2.0; - vSign = aSign; + vTexCoord = texCoord; } diff --git a/shaders/gles2/direct-interior.vs.glsl b/shaders/gles2/direct-interior.vs.glsl index 3f7de525..d62c73d3 100644 --- a/shaders/gles2/direct-interior.vs.glsl +++ b/shaders/gles2/direct-interior.vs.glsl @@ -32,12 +32,11 @@ uniform sampler2D uPathTransformST; uniform ivec2 uPathTransformExtDimensions; /// The extra path transform factors buffer texture, packed two path transforms per texel. uniform sampler2D uPathTransformExt; -/// The amount of faux-bold to apply, in local path units. -uniform vec2 uEmboldenAmount; +/// The 2D position of this point. attribute vec2 aPosition; +/// The path ID, starting from 1. attribute float aPathID; -attribute float aNormalAngle; /// The color of this path. varying vec4 vColor; @@ -53,8 +52,7 @@ void main() { uPathTransformExtDimensions, pathID); - vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount); - position = hintPosition(position, uHints); + vec2 position = hintPosition(aPosition, uHints); position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt); position = transformVertexPosition(position, uTransform); diff --git a/shaders/gles2/ecaa-curve.vs.glsl b/shaders/gles2/ecaa-curve.vs.glsl index 9daaeae4..98a750a1 100644 --- a/shaders/gles2/ecaa-curve.vs.glsl +++ b/shaders/gles2/ecaa-curve.vs.glsl @@ -47,8 +47,8 @@ uniform sampler2D uPathTransformExt; /// The amount of faux-bold to apply, in local path units. uniform vec2 uEmboldenAmount; -/// The abstract quad position: (0.0, 0.0) to (1.0, 1.0). -attribute vec2 aQuadPosition; +/// The abstract position within the quad: (0.0, 0.0) to (1.0, 1.0). +attribute vec2 aTessCoord; /// The position of the left endpoint. attribute vec2 aLeftPosition; /// The position of the control point. @@ -82,31 +82,63 @@ void main() { vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions); // Transform the points, and compute the position of this vertex. - vec2 position; - float winding; - if (computeECAAQuadPosition(position, - winding, - leftPosition, - rightPosition, - aQuadPosition, - uFramebufferSize, - pathTransformST, - pathTransformExt, - uTransform, - uHints, - bounds, - leftRightNormalAngles, - uEmboldenAmount)) { - controlPointPosition = computeECAAPosition(controlPointPosition, - controlPointNormalAngle, - uEmboldenAmount, - uHints, - pathTransformST, - pathTransformExt, - uTransform, - uFramebufferSize); + leftPosition = computeECAAPosition(leftPosition, + aNormalAngles.x, + uEmboldenAmount, + uHints, + pathTransformST, + pathTransformExt, + uTransform, + uFramebufferSize); + rightPosition = computeECAAPosition(rightPosition, + aNormalAngles.z, + uEmboldenAmount, + uHints, + pathTransformST, + pathTransformExt, + uTransform, + uFramebufferSize); + controlPointPosition = computeECAAPosition(controlPointPosition, + aNormalAngles.y, + uEmboldenAmount, + uHints, + pathTransformST, + pathTransformExt, + uTransform, + uFramebufferSize); + float winding = computeECAAWinding(leftPosition, rightPosition); + if (winding == 0.0) { + gl_Position = vec4(0.0); + return; } + vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy; + edgeBL = transformECAAPosition(edgeBL, pathTransformST, pathTransformExt, uTransform); + edgeBR = transformECAAPosition(edgeBR, pathTransformST, pathTransformExt, uTransform); + edgeTL = transformECAAPosition(edgeTL, pathTransformST, pathTransformExt, uTransform); + edgeTR = transformECAAPosition(edgeTR, pathTransformST, pathTransformExt, uTransform); + + // Find the bottom of the path, and convert to clip space. + // + // FIXME(pcwalton): Speed this up somehow? + float pathBottomY = max(max(edgeBL.y, edgeBR.y), max(edgeTL.y, edgeTR.y)); + pathBottomY = (pathBottomY + 1.0) * 0.5 * float(uFramebufferSize.y); + + vec2 position; + if (aTessCoord.x < 0.25) + position = vec2(floor(leftPosition.x), leftPosition.y); + else if (aTessCoord.x < 0.75) + position = controlPointPosition; + else + position = vec2(ceil(rightPosition.x), rightPosition.y); + + // FIXME(pcwalton): Only compute path bottom Y if necessary. + if (aTessCoord.y < 0.5) + position.y = floor(position.y - 1.0); + else + position.y = pathBottomY; + + position = convertScreenToClipSpace(position, uFramebufferSize); float depth = convertPathIndexToViewportDepthValue(pathID); gl_Position = vec4(position, depth, 1.0); diff --git a/shaders/gles2/ecaa-line.vs.glsl b/shaders/gles2/ecaa-line.vs.glsl index cb0ee5a5..4334f239 100644 --- a/shaders/gles2/ecaa-line.vs.glsl +++ b/shaders/gles2/ecaa-line.vs.glsl @@ -46,7 +46,7 @@ uniform sampler2D uPathTransformExt; uniform vec2 uEmboldenAmount; /// The abstract quad position: (0.0, 0.0) to (1.0, 1.0). -attribute vec2 aQuadPosition; +attribute vec2 aTessCoord; /// The position of the left endpoint. attribute vec2 aLeftPosition; /// The position of the right endpoint. @@ -75,22 +75,53 @@ void main() { vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions); // Transform the points, and compute the position of this vertex. - vec2 position; - float winding; - computeECAAQuadPosition(position, - winding, - leftPosition, - rightPosition, - aQuadPosition, - uFramebufferSize, - pathTransformST, - pathTransformExt, - uTransform, - uHints, - bounds, - leftRightNormalAngles, - uEmboldenAmount); + leftPosition = computeECAAPosition(leftPosition, + aNormalAngles.x, + uEmboldenAmount, + uHints, + pathTransformST, + pathTransformExt, + uTransform, + uFramebufferSize); + rightPosition = computeECAAPosition(rightPosition, + aNormalAngles.y, + uEmboldenAmount, + uHints, + pathTransformST, + pathTransformExt, + uTransform, + uFramebufferSize); + float winding = computeECAAWinding(leftPosition, rightPosition); + if (winding == 0.0) { + gl_Position = vec4(0.0); + return; + } + vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy; + edgeBL = transformECAAPosition(edgeBL, pathTransformST, pathTransformExt, uTransform); + edgeBR = transformECAAPosition(edgeBR, pathTransformST, pathTransformExt, uTransform); + edgeTL = transformECAAPosition(edgeTL, pathTransformST, pathTransformExt, uTransform); + edgeTR = transformECAAPosition(edgeTR, pathTransformST, pathTransformExt, uTransform); + + // Find the bottom of the path, and convert to clip space. + // + // FIXME(pcwalton): Speed this up somehow? + float pathBottomY = max(max(edgeBL.y, edgeBR.y), max(edgeTL.y, edgeTR.y)); + pathBottomY = (pathBottomY + 1.0) * 0.5 * float(uFramebufferSize.y); + + vec2 position; + if (aTessCoord.x < 0.5) + position = vec2(floor(leftPosition.x), leftPosition.y); + else + position = vec2(ceil(rightPosition.x), rightPosition.y); + + // FIXME(pcwalton): Only compute path bottom Y if necessary. + if (aTessCoord.y < 0.5) + position.y = floor(position.y - 1.0); + else + position.y = pathBottomY; + + position = convertScreenToClipSpace(position, uFramebufferSize); float depth = convertPathIndexToViewportDepthValue(pathID); gl_Position = vec4(position, depth, 1.0); diff --git a/shaders/gles2/ecaa-transformed-curve.vs.glsl b/shaders/gles2/ecaa-transformed-curve.vs.glsl index 5ecf6807..9a5f03e3 100644 --- a/shaders/gles2/ecaa-transformed-curve.vs.glsl +++ b/shaders/gles2/ecaa-transformed-curve.vs.glsl @@ -57,7 +57,7 @@ uniform vec2 uEmboldenAmount; uniform int uPassIndex; /// The abstract quad position: (0.0, 0.0) to (1.0, 1.0). -attribute vec2 aQuadPosition; +attribute vec2 aTessCoord; /// The position of the left endpoint. attribute vec2 aLeftPosition; /// The position of the control point. @@ -126,16 +126,33 @@ void main() { return; } - vec2 position = computeECAAQuadPositionFromTransformedPositions(leftPosition, - rightPosition, - aQuadPosition, - uFramebufferSize, - pathTransformST, - pathTransformExt, - uTransform, - bounds, - leftTopRightEdges); + vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy; + edgeBL = transformECAAPosition(edgeBL, pathTransformST, pathTransformExt, uTransform); + edgeBR = transformECAAPosition(edgeBR, pathTransformST, pathTransformExt, uTransform); + edgeTL = transformECAAPosition(edgeTL, pathTransformST, pathTransformExt, uTransform); + edgeTR = transformECAAPosition(edgeTR, pathTransformST, pathTransformExt, uTransform); + // Find the bottom of the path, and convert to clip space. + // + // FIXME(pcwalton): Speed this up somehow? + float pathBottomY = max(max(edgeBL.y, edgeBR.y), max(edgeTL.y, edgeTR.y)); + pathBottomY = (pathBottomY + 1.0) * 0.5 * float(uFramebufferSize.y); + + vec2 position; + if (aTessCoord.x < 0.25) + position = vec2(floor(leftPosition.x), leftPosition.y); + else if (aTessCoord.x < 0.75) + position = controlPointPosition; + else + position = vec2(ceil(rightPosition.x), rightPosition.y); + + // FIXME(pcwalton): Only compute path bottom Y if necessary. + if (aTessCoord.y < 0.5) + position.y = floor(position.y - 1.0); + else + position.y = pathBottomY; + + position = convertScreenToClipSpace(position, uFramebufferSize); float depth = convertPathIndexToViewportDepthValue(pathID); gl_Position = vec4(position, depth, 1.0); diff --git a/shaders/gles2/mcaa.vs.glsl b/shaders/gles2/mcaa.vs.glsl index 2aeaa42c..79cc0c0e 100644 --- a/shaders/gles2/mcaa.vs.glsl +++ b/shaders/gles2/mcaa.vs.glsl @@ -53,10 +53,13 @@ uniform sampler2D uPathColors; /// If this is true, then points will be snapped to the nearest pixel. uniform bool uMulticolor; -attribute vec2 aQuadPosition; -attribute vec4 aUpperEndpointPositions; -attribute vec4 aLowerEndpointPositions; -attribute vec4 aControlPointPositions; +attribute vec2 aTessCoord; +attribute vec2 aUpperLeftEndpointPosition; +attribute vec2 aUpperControlPointPosition; +attribute vec2 aUpperRightEndpointPosition; +attribute vec2 aLowerRightEndpointPosition; +attribute vec2 aLowerControlPointPosition; +attribute vec2 aLowerLeftEndpointPosition; attribute float aPathID; varying vec4 vUpperEndpoints; @@ -65,13 +68,13 @@ varying vec4 vControlPoints; varying vec4 vColor; void main() { - vec2 tlPosition = aUpperEndpointPositions.xy; - vec2 tcPosition = aControlPointPositions.xy; - vec2 trPosition = aUpperEndpointPositions.zw; - vec2 blPosition = aLowerEndpointPositions.xy; - vec2 bcPosition = aControlPointPositions.zw; - vec2 brPosition = aLowerEndpointPositions.zw; - vec2 quadPosition = aQuadPosition; + vec2 tlPosition = aUpperLeftEndpointPosition; + vec2 tcPosition = aUpperControlPointPosition; + vec2 trPosition = aUpperRightEndpointPosition; + vec2 blPosition = aLowerLeftEndpointPosition; + vec2 bcPosition = aLowerControlPointPosition; + vec2 brPosition = aLowerRightEndpointPosition; + vec2 tessCoord = aTessCoord; int pathID = int(floor(aPathID)); vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions); @@ -129,19 +132,33 @@ void main() { float depth = convertPathIndexToViewportDepthValue(pathID); - // Use the same side--in this case, the top--or else floating point error during partitioning - // can occasionally cause inconsistent rounding, resulting in cracks. + // Use the same side--in this case, the top--or else floating point error during + // partitioning can occasionally cause inconsistent rounding, resulting in cracks. vec2 position; + if (tessCoord.y < 0.5) { + if (tessCoord.x < 0.25) + position = tlPosition; + else if (tessCoord.x < 0.75) + position = tcPosition; + else + position = trPosition; + position.y = floor(position.y - 0.5); + } else { + if (tessCoord.x < 0.25) + position = blPosition; + else if (tessCoord.x < 0.75) + position = bcPosition; + else + position = brPosition; + position.y = ceil(position.y + 0.5); + } - if (uMulticolor) - position.x = quadPosition.x < 0.5 ? tlPosition.x : trPosition.x; - else - position.x = quadPosition.x < 0.5 ? floor(tlPosition.x) : ceil(trPosition.x); - - if (quadPosition.y < 0.5) - position.y = floor(min(tlPosition.y, trPosition.y)); - else - position.y = ceil(max(blPosition.y, brPosition.y)); + if (!uMulticolor) { + if (tessCoord.x < 0.25) + position.x = floor(position.x); + else if (tessCoord.x >= 0.75) + position.x = ceil(position.x); + } position = convertScreenToClipSpace(position, uFramebufferSize);