Simplify the B-quad vertex position VBO to have a uniform format, and
enable early Z for SVG. Additionally, this switches the B-quad patches for XCAA to be convex hulls instead of bounding boxes, reducing fragment shader load. This is a large speedup for the Ghostscript tiger demo: 5x or more. Closes #33.
This commit is contained in:
parent
67dd6cd8ed
commit
6a640eca74
|
@ -7,3 +7,6 @@ members = [
|
||||||
"utils/frontend",
|
"utils/frontend",
|
||||||
"utils/gamma-lut",
|
"utils/gamma-lut",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
ring = { git = "https://github.com/SergioBenitez/ring", branch = "v0.12" }
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {DemoView} from './view';
|
||||||
|
|
||||||
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'xcaa';
|
||||||
|
|
||||||
export type DirectRenderingMode = 'none' | 'color';
|
export type DirectRenderingMode = 'none' | 'conservative' | 'color';
|
||||||
|
|
||||||
export type SubpixelAAType = 'none' | 'medium';
|
export type SubpixelAAType = 'none' | 'medium';
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ export interface EXTDisjointTimerQuery {
|
||||||
|
|
||||||
export class WebGLQuery {}
|
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,
|
export function createFramebufferColorTexture(gl: WebGLRenderingContext,
|
||||||
size: glmatrix.vec2,
|
size: glmatrix.vec2,
|
||||||
|
|
|
@ -268,9 +268,7 @@ class MeshDebuggerView extends PathfinderView {
|
||||||
context.font = `12px ${POINT_LABEL_FONT}`;
|
context.font = `12px ${POINT_LABEL_FONT}`;
|
||||||
context.lineWidth = invScaleFactor;
|
context.lineWidth = invScaleFactor;
|
||||||
|
|
||||||
const bQuads = new Uint32Array(meshes.bQuads);
|
const bQuadVertexPositions = new Float32Array(meshes.bQuadVertexPositions);
|
||||||
const positions = new Float32Array(meshes.bVertexPositions);
|
|
||||||
const bVertexNormals = new Float32Array(meshes.bVertexNormals);
|
|
||||||
|
|
||||||
const normals: NormalsTable<Float32Array> = {
|
const normals: NormalsTable<Float32Array> = {
|
||||||
lowerCurve: new Float32Array(0),
|
lowerCurve: new Float32Array(0),
|
||||||
|
@ -279,54 +277,24 @@ class MeshDebuggerView extends PathfinderView {
|
||||||
upperLine: new Float32Array(0),
|
upperLine: new Float32Array(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawnVertices: boolean[] = [], drawnNormals: boolean[] = [];
|
|
||||||
|
|
||||||
// Draw B-quads.
|
// 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 bQuadStartOffset = (B_QUAD_SIZE * bQuadIndex) / UINT32_SIZE;
|
||||||
|
|
||||||
const upperLeftIndex = bQuads[bQuadStartOffset +
|
const upperLeftPosition = getPosition(bQuadVertexPositions, bQuadIndex, 0);
|
||||||
B_QUAD_UPPER_LEFT_VERTEX_OFFSET / UINT32_SIZE];
|
const upperControlPointPosition = getPosition(bQuadVertexPositions, bQuadIndex, 1);
|
||||||
const upperRightIndex = bQuads[bQuadStartOffset +
|
const upperRightPosition = getPosition(bQuadVertexPositions, bQuadIndex, 2);
|
||||||
B_QUAD_UPPER_RIGHT_VERTEX_OFFSET / UINT32_SIZE];
|
const lowerRightPosition = getPosition(bQuadVertexPositions, bQuadIndex, 3);
|
||||||
const upperControlPointIndex =
|
const lowerControlPointPosition = getPosition(bQuadVertexPositions, bQuadIndex, 4);
|
||||||
bQuads[bQuadStartOffset + B_QUAD_UPPER_CONTROL_POINT_VERTEX_OFFSET / UINT32_SIZE];
|
const lowerLeftPosition = getPosition(bQuadVertexPositions, bQuadIndex, 5);
|
||||||
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);
|
|
||||||
|
|
||||||
if (this.drawVertices) {
|
if (this.drawVertices) {
|
||||||
drawVertexIfNecessary(context,
|
drawVertexIfNecessary(context, upperLeftPosition, invScaleFactor);
|
||||||
drawnVertices,
|
drawVertexIfNecessary(context, upperRightPosition, invScaleFactor);
|
||||||
upperLeftIndex,
|
drawVertexIfNecessary(context, lowerLeftPosition, invScaleFactor);
|
||||||
upperLeftPosition,
|
drawVertexIfNecessary(context, lowerRightPosition, invScaleFactor);
|
||||||
invScaleFactor);
|
|
||||||
drawVertexIfNecessary(context,
|
|
||||||
drawnVertices,
|
|
||||||
upperRightIndex,
|
|
||||||
upperRightPosition,
|
|
||||||
invScaleFactor);
|
|
||||||
drawVertexIfNecessary(context,
|
|
||||||
drawnVertices,
|
|
||||||
lowerLeftIndex,
|
|
||||||
lowerLeftPosition,
|
|
||||||
invScaleFactor);
|
|
||||||
drawVertexIfNecessary(context,
|
|
||||||
drawnVertices,
|
|
||||||
lowerRightIndex,
|
|
||||||
lowerRightPosition,
|
|
||||||
invScaleFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.moveTo(upperLeftPosition[0], -upperLeftPosition[1]);
|
context.moveTo(upperLeftPosition[0], -upperLeftPosition[1]);
|
||||||
if (upperControlPointPosition != null) {
|
if (upperControlPointPosition != null) {
|
||||||
|
@ -366,22 +334,6 @@ class MeshDebuggerView extends PathfinderView {
|
||||||
context.moveTo(lowerLeftPosition[0], -lowerLeftPosition[1]);
|
context.moveTo(lowerLeftPosition[0], -lowerLeftPosition[1]);
|
||||||
context.lineTo(upperLeftPosition[0], -upperLeftPosition[1]);
|
context.lineTo(upperLeftPosition[0], -upperLeftPosition[1]);
|
||||||
context.stroke();
|
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.
|
// Draw segments.
|
||||||
|
@ -429,10 +381,16 @@ class MeshDebuggerView extends PathfinderView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPosition(positions: Float32Array, vertexIndex: number): glmatrix.vec2 | null {
|
function getPosition(positions: Float32Array, bQuadIndex: number, vertexIndex: number):
|
||||||
if (vertexIndex === UINT32_MAX)
|
glmatrix.vec2 {
|
||||||
return null;
|
return glmatrix.vec2.clone([
|
||||||
return glmatrix.vec2.clone([positions[vertexIndex * 2 + 0], positions[vertexIndex * 2 + 1]]);
|
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<Float32Array>,
|
function getNormals(normals: NormalsTable<Float32Array>,
|
||||||
|
@ -526,25 +484,12 @@ function drawSegmentVertices(context: CanvasRenderingContext2D,
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawVertexIfNecessary(context: CanvasRenderingContext2D,
|
function drawVertexIfNecessary(context: CanvasRenderingContext2D,
|
||||||
markedVertices: boolean[],
|
|
||||||
vertexIndex: number,
|
|
||||||
position: Float32Array,
|
position: Float32Array,
|
||||||
invScaleFactor: number) {
|
invScaleFactor: number) {
|
||||||
if (markedVertices[vertexIndex] != null)
|
|
||||||
return;
|
|
||||||
markedVertices[vertexIndex] = true;
|
|
||||||
|
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.moveTo(position[0], -position[1]);
|
context.moveTo(position[0], -position[1]);
|
||||||
context.arc(position[0], -position[1], POINT_RADIUS * invScaleFactor, 0, 2.0 * Math.PI);
|
context.arc(position[0], -position[1], POINT_RADIUS * invScaleFactor, 0, 2.0 * Math.PI);
|
||||||
context.fill();
|
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,
|
function drawSegmentVertex(context: CanvasRenderingContext2D,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import * as base64js from 'base64-js';
|
||||||
|
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import {expectNotNull, FLOAT32_SIZE, panic, PathfinderError, Range, UINT16_SIZE} from './utils';
|
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 {
|
interface BufferTypeFourCCTable {
|
||||||
[fourCC: string]: keyof Meshes<void>;
|
[fourCC: string]: keyof Meshes<void>;
|
||||||
|
@ -87,24 +87,9 @@ const SEGMENT_LINE_SIZE: number = 4 * 4;
|
||||||
const SEGMENT_CURVE_SIZE: number = 4 * 6;
|
const SEGMENT_CURVE_SIZE: number = 4 * 6;
|
||||||
|
|
||||||
const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
||||||
|
bQuadVertexInteriorIndices: { type: 'Uint32', size: 1 },
|
||||||
|
bQuadVertexPositionPathIDs: { type: 'Uint16', size: 6 },
|
||||||
bQuadVertexPositions: { type: 'Float32', size: 12 },
|
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 },
|
segmentCurveNormals: { type: 'Float32', size: 3 },
|
||||||
segmentCurvePathIDs: { type: 'Uint16', size: 1 },
|
segmentCurvePathIDs: { type: 'Uint16', size: 1 },
|
||||||
segmentCurves: { type: 'Float32', size: 6 },
|
segmentCurves: { type: 'Float32', size: 6 },
|
||||||
|
@ -114,24 +99,9 @@ const MESH_TYPES: Meshes<MeshBufferTypeDescriptor> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const BUFFER_TYPES: Meshes<BufferType> = {
|
const BUFFER_TYPES: Meshes<BufferType> = {
|
||||||
|
bQuadVertexInteriorIndices: 'ELEMENT_ARRAY_BUFFER',
|
||||||
|
bQuadVertexPositionPathIDs: 'ARRAY_BUFFER',
|
||||||
bQuadVertexPositions: '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',
|
segmentCurveNormals: 'ARRAY_BUFFER',
|
||||||
segmentCurvePathIDs: 'ARRAY_BUFFER',
|
segmentCurvePathIDs: 'ARRAY_BUFFER',
|
||||||
segmentCurves: '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()`.
|
// Must match the FourCCs in `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into()`.
|
||||||
const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
||||||
bqua: 'bQuads',
|
bqii: 'bQuadVertexInteriorIndices',
|
||||||
bqvp: 'bQuadVertexPositions',
|
bqvp: 'bQuadVertexPositions',
|
||||||
bvlb: 'bVertexLoopBlinnData',
|
|
||||||
bvno: 'bVertexNormals',
|
|
||||||
bvpo: 'bVertexPositions',
|
|
||||||
cvci: 'coverCurveIndices',
|
|
||||||
cvii: 'coverInteriorIndices',
|
|
||||||
ebbv: 'edgeBoundingBoxVertexPositions',
|
|
||||||
elcv: 'edgeLowerCurveVertexPositions',
|
|
||||||
ellv: 'edgeLowerLineVertexPositions',
|
|
||||||
eucv: 'edgeUpperCurveVertexPositions',
|
|
||||||
eulv: 'edgeUpperLineVertexPositions',
|
|
||||||
scur: 'segmentCurves',
|
scur: 'segmentCurves',
|
||||||
slin: 'segmentLines',
|
slin: 'segmentLines',
|
||||||
sncu: 'segmentCurveNormals',
|
sncu: 'segmentCurveNormals',
|
||||||
|
@ -169,57 +129,28 @@ const BUFFER_TYPE_FOURCCS: BufferTypeFourCCTable = {
|
||||||
// Must match the FourCCs in
|
// Must match the FourCCs in
|
||||||
// `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`.
|
// `pathfinder_partitioner::mesh_library::MeshLibrary::serialize_into::write_path_ranges()`.
|
||||||
const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
const PATH_RANGE_TYPE_FOURCCS: PathRangeTypeFourCCTable = {
|
||||||
bqua: 'bQuadPathRanges',
|
bqii: 'bQuadVertexInteriorIndexPathRanges',
|
||||||
bqvp: 'bQuadVertexPositionPathRanges',
|
bqvp: 'bQuadVertexPositionPathRanges',
|
||||||
bver: 'bVertexPathRanges',
|
|
||||||
cvci: 'coverCurveIndexRanges',
|
|
||||||
cvii: 'coverInteriorIndexRanges',
|
|
||||||
ebbo: 'edgeBoundingBoxRanges',
|
|
||||||
elci: 'edgeLowerCurveIndexRanges',
|
|
||||||
elli: 'edgeLowerLineIndexRanges',
|
|
||||||
euci: 'edgeUpperCurveIndexRanges',
|
|
||||||
euli: 'edgeUpperLineIndexRanges',
|
|
||||||
scur: 'segmentCurveRanges',
|
scur: 'segmentCurveRanges',
|
||||||
slin: 'segmentLineRanges',
|
slin: 'segmentLineRanges',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RANGE_TO_COUNT_TABLE: RangeToCountTable = {
|
const RANGE_TO_COUNT_TABLE: RangeToCountTable = {
|
||||||
bQuadPathRanges: 'bQuadCount',
|
bQuadVertexInteriorIndexPathRanges: 'bQuadVertexInteriorIndexCount',
|
||||||
bQuadVertexPositionPathRanges: 'bQuadVertexPositionCount',
|
bQuadVertexPositionPathRanges: 'bQuadVertexPositionCount',
|
||||||
bVertexPathRanges: 'bVertexCount',
|
|
||||||
coverCurveIndexRanges: 'coverCurveCount',
|
|
||||||
coverInteriorIndexRanges: 'coverInteriorCount',
|
|
||||||
edgeBoundingBoxRanges: 'edgeBoundingBoxCount',
|
|
||||||
edgeLowerCurveIndexRanges: 'edgeLowerCurveCount',
|
|
||||||
edgeLowerLineIndexRanges: 'edgeLowerLineCount',
|
|
||||||
edgeUpperCurveIndexRanges: 'edgeUpperCurveCount',
|
|
||||||
edgeUpperLineIndexRanges: 'edgeUpperLineCount',
|
|
||||||
segmentCurveRanges: 'segmentCurveCount',
|
segmentCurveRanges: 'segmentCurveCount',
|
||||||
segmentLineRanges: 'segmentLineCount',
|
segmentLineRanges: 'segmentLineCount',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RANGE_TO_RANGE_BUFFER_TABLE: RangeToRangeBufferTable = {
|
const RANGE_TO_RANGE_BUFFER_TABLE: RangeToRangeBufferTable = {
|
||||||
bVertexPathRanges: 'bVertexPathIDs',
|
bQuadVertexPositionPathRanges: 'bQuadVertexPositionPathIDs',
|
||||||
edgeBoundingBoxRanges: 'edgeBoundingBoxPathIDs',
|
|
||||||
edgeLowerCurveIndexRanges: 'edgeLowerCurvePathIDs',
|
|
||||||
edgeLowerLineIndexRanges: 'edgeLowerLinePathIDs',
|
|
||||||
edgeUpperCurveIndexRanges: 'edgeUpperCurvePathIDs',
|
|
||||||
edgeUpperLineIndexRanges: 'edgeUpperLinePathIDs',
|
|
||||||
segmentCurveRanges: 'segmentCurvePathIDs',
|
segmentCurveRanges: 'segmentCurvePathIDs',
|
||||||
segmentLineRanges: 'segmentLinePathIDs',
|
segmentLineRanges: 'segmentLinePathIDs',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RANGE_KEYS: Array<keyof PathRanges> = [
|
const RANGE_KEYS: Array<keyof PathRanges> = [
|
||||||
'bQuadPathRanges',
|
|
||||||
'bQuadVertexPositionPathRanges',
|
'bQuadVertexPositionPathRanges',
|
||||||
'bVertexPathRanges',
|
'bQuadVertexInteriorIndexPathRanges',
|
||||||
'coverInteriorIndexRanges',
|
|
||||||
'coverCurveIndexRanges',
|
|
||||||
'edgeBoundingBoxRanges',
|
|
||||||
'edgeUpperLineIndexRanges',
|
|
||||||
'edgeUpperCurveIndexRanges',
|
|
||||||
'edgeLowerLineIndexRanges',
|
|
||||||
'edgeLowerCurveIndexRanges',
|
|
||||||
'segmentCurveRanges',
|
'segmentCurveRanges',
|
||||||
'segmentLineRanges',
|
'segmentLineRanges',
|
||||||
];
|
];
|
||||||
|
@ -227,113 +158,51 @@ const RANGE_KEYS: Array<keyof PathRanges> = [
|
||||||
type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
||||||
|
|
||||||
export interface Meshes<T> {
|
export interface Meshes<T> {
|
||||||
readonly bQuads: T;
|
|
||||||
readonly bQuadVertexPositions: T;
|
readonly bQuadVertexPositions: T;
|
||||||
readonly bVertexPositions: T;
|
readonly bQuadVertexInteriorIndices: 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 segmentLines: T;
|
readonly segmentLines: T;
|
||||||
readonly segmentCurves: T;
|
readonly segmentCurves: T;
|
||||||
readonly segmentLineNormals: T;
|
readonly segmentLineNormals: T;
|
||||||
readonly segmentCurveNormals: T;
|
readonly segmentCurveNormals: T;
|
||||||
|
|
||||||
bVertexPathIDs: T;
|
bQuadVertexPositionPathIDs: T;
|
||||||
edgeBoundingBoxPathIDs: T;
|
|
||||||
segmentLinePathIDs: T;
|
segmentLinePathIDs: T;
|
||||||
segmentCurvePathIDs: T;
|
segmentCurvePathIDs: T;
|
||||||
edgeLowerCurvePathIDs: T;
|
|
||||||
edgeLowerLinePathIDs: T;
|
|
||||||
edgeUpperCurvePathIDs: T;
|
|
||||||
edgeUpperLinePathIDs: T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MeshDataCounts {
|
interface MeshDataCounts {
|
||||||
readonly bQuadCount: number;
|
|
||||||
readonly bQuadVertexPositionCount: number;
|
readonly bQuadVertexPositionCount: number;
|
||||||
readonly bVertexCount: number;
|
readonly bQuadVertexInteriorIndexCount: number;
|
||||||
readonly coverCurveCount: number;
|
|
||||||
readonly coverInteriorCount: number;
|
|
||||||
readonly edgeBoundingBoxCount: number;
|
|
||||||
readonly edgeLowerCurveCount: number;
|
|
||||||
readonly edgeUpperCurveCount: number;
|
|
||||||
readonly edgeLowerLineCount: number;
|
|
||||||
readonly edgeUpperLineCount: number;
|
|
||||||
readonly segmentLineCount: number;
|
readonly segmentLineCount: number;
|
||||||
readonly segmentCurveCount: number;
|
readonly segmentCurveCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PathRanges {
|
interface PathRanges {
|
||||||
bQuadPathRanges: Range[];
|
|
||||||
bQuadVertexPositionPathRanges: Range[];
|
bQuadVertexPositionPathRanges: Range[];
|
||||||
bVertexPathRanges: Range[];
|
bQuadVertexInteriorIndexPathRanges: Range[];
|
||||||
coverInteriorIndexRanges: Range[];
|
|
||||||
coverCurveIndexRanges: Range[];
|
|
||||||
edgeBoundingBoxRanges: Range[];
|
|
||||||
edgeUpperLineIndexRanges: Range[];
|
|
||||||
edgeUpperCurveIndexRanges: Range[];
|
|
||||||
edgeLowerLineIndexRanges: Range[];
|
|
||||||
edgeLowerCurveIndexRanges: Range[];
|
|
||||||
segmentCurveRanges: Range[];
|
segmentCurveRanges: Range[];
|
||||||
segmentLineRanges: Range[];
|
segmentLineRanges: Range[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts, PathRanges {
|
export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts, PathRanges {
|
||||||
readonly bQuads: ArrayBuffer;
|
|
||||||
readonly bQuadVertexPositions: ArrayBuffer;
|
readonly bQuadVertexPositions: ArrayBuffer;
|
||||||
readonly bVertexPositions: ArrayBuffer;
|
readonly bQuadVertexInteriorIndices: 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 segmentLines: ArrayBuffer;
|
readonly segmentLines: ArrayBuffer;
|
||||||
readonly segmentCurves: ArrayBuffer;
|
readonly segmentCurves: ArrayBuffer;
|
||||||
readonly segmentLineNormals: ArrayBuffer;
|
readonly segmentLineNormals: ArrayBuffer;
|
||||||
readonly segmentCurveNormals: ArrayBuffer;
|
readonly segmentCurveNormals: ArrayBuffer;
|
||||||
|
|
||||||
readonly bQuadCount: number;
|
|
||||||
readonly bQuadVertexPositionCount: number;
|
readonly bQuadVertexPositionCount: number;
|
||||||
readonly bVertexCount: number;
|
readonly bQuadVertexInteriorIndexCount: number;
|
||||||
readonly coverCurveCount: number;
|
|
||||||
readonly coverInteriorCount: number;
|
|
||||||
readonly edgeBoundingBoxCount: number;
|
|
||||||
readonly edgeLowerCurveCount: number;
|
|
||||||
readonly edgeUpperCurveCount: number;
|
|
||||||
readonly edgeLowerLineCount: number;
|
|
||||||
readonly edgeUpperLineCount: number;
|
|
||||||
readonly segmentLineCount: number;
|
readonly segmentLineCount: number;
|
||||||
readonly segmentCurveCount: number;
|
readonly segmentCurveCount: number;
|
||||||
|
|
||||||
bVertexPathIDs: ArrayBuffer;
|
bQuadVertexPositionPathIDs: ArrayBuffer;
|
||||||
edgeBoundingBoxPathIDs: ArrayBuffer;
|
|
||||||
edgeLowerCurvePathIDs: ArrayBuffer;
|
|
||||||
edgeLowerLinePathIDs: ArrayBuffer;
|
|
||||||
edgeUpperCurvePathIDs: ArrayBuffer;
|
|
||||||
edgeUpperLinePathIDs: ArrayBuffer;
|
|
||||||
segmentCurvePathIDs: ArrayBuffer;
|
segmentCurvePathIDs: ArrayBuffer;
|
||||||
segmentLinePathIDs: ArrayBuffer;
|
segmentLinePathIDs: ArrayBuffer;
|
||||||
|
|
||||||
bQuadPathRanges: Range[];
|
|
||||||
bQuadVertexPositionPathRanges: Range[];
|
bQuadVertexPositionPathRanges: Range[];
|
||||||
bVertexPathRanges: Range[];
|
bQuadVertexInteriorIndexPathRanges: Range[];
|
||||||
coverInteriorIndexRanges: Range[];
|
|
||||||
coverCurveIndexRanges: Range[];
|
|
||||||
edgeBoundingBoxRanges: Range[];
|
|
||||||
edgeUpperLineIndexRanges: Range[];
|
|
||||||
edgeUpperCurveIndexRanges: Range[];
|
|
||||||
edgeLowerLineIndexRanges: Range[];
|
|
||||||
edgeLowerCurveIndexRanges: Range[];
|
|
||||||
segmentCurveRanges: Range[];
|
segmentCurveRanges: Range[];
|
||||||
segmentLineRanges: Range[];
|
segmentLineRanges: Range[];
|
||||||
|
|
||||||
|
@ -368,22 +237,10 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
this[range] = ranges[range];
|
this[range] = ranges[range];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bQuadCount = this.bQuads.byteLength / B_QUAD_SIZE;
|
|
||||||
this.bQuadVertexPositionCount = this.bQuadVertexPositions.byteLength /
|
this.bQuadVertexPositionCount = this.bQuadVertexPositions.byteLength /
|
||||||
B_QUAD_VERTEX_POSITION_SIZE;
|
B_QUAD_VERTEX_POSITION_SIZE;
|
||||||
this.bVertexCount = this.bVertexPositions.byteLength / B_VERTEX_POSITION_SIZE;
|
this.bQuadVertexInteriorIndexCount = this.bQuadVertexInteriorIndices.byteLength /
|
||||||
this.coverCurveCount = this.coverCurveIndices.byteLength / INDEX_SIZE;
|
INDEX_SIZE;
|
||||||
this.coverInteriorCount = this.coverInteriorIndices.byteLength / INDEX_SIZE;
|
|
||||||
this.edgeBoundingBoxCount = this.edgeBoundingBoxVertexPositions.byteLength /
|
|
||||||
EDGE_BOUNDING_BOX_VERTEX_POSITION_SIZE;
|
|
||||||
this.edgeUpperLineCount = this.edgeUpperLineVertexPositions.byteLength /
|
|
||||||
EDGE_UPPER_LINE_VERTEX_POSITION_SIZE;
|
|
||||||
this.edgeLowerLineCount = this.edgeLowerLineVertexPositions.byteLength /
|
|
||||||
EDGE_LOWER_LINE_VERTEX_POSITION_SIZE;
|
|
||||||
this.edgeUpperCurveCount = this.edgeUpperCurveVertexPositions.byteLength /
|
|
||||||
EDGE_UPPER_CURVE_VERTEX_POSITION_SIZE;
|
|
||||||
this.edgeLowerCurveCount = this.edgeLowerCurveVertexPositions.byteLength /
|
|
||||||
EDGE_LOWER_CURVE_VERTEX_POSITION_SIZE;
|
|
||||||
this.segmentCurveCount = this.segmentCurves.byteLength / SEGMENT_CURVE_SIZE;
|
this.segmentCurveCount = this.segmentCurves.byteLength / SEGMENT_CURVE_SIZE;
|
||||||
this.segmentLineCount = this.segmentLines.byteLength / SEGMENT_LINE_SIZE;
|
this.segmentLineCount = this.segmentLines.byteLength / SEGMENT_LINE_SIZE;
|
||||||
|
|
||||||
|
@ -418,90 +275,31 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
const expandedPathID = newPathIndex + 1;
|
const expandedPathID = newPathIndex + 1;
|
||||||
const originalPathID = pathIDs[newPathIndex];
|
const originalPathID = pathIDs[newPathIndex];
|
||||||
|
|
||||||
const bVertexCopyResult = copyVertices(['bVertexPositions',
|
// Copy over B-quad vertex positions.
|
||||||
'bVertexLoopBlinnData',
|
const bQuadVertexCopyResult = copyVertices(['bQuadVertexPositions'],
|
||||||
'bVertexNormals'],
|
'bQuadVertexPositionPathRanges',
|
||||||
'bVertexPathRanges',
|
expandedArrays,
|
||||||
expandedArrays,
|
expandedRanges,
|
||||||
expandedRanges,
|
originalBuffers,
|
||||||
originalBuffers,
|
originalRanges,
|
||||||
originalRanges,
|
expandedPathID,
|
||||||
expandedPathID,
|
originalPathID);
|
||||||
originalPathID);
|
|
||||||
|
|
||||||
if (bVertexCopyResult == null)
|
if (bQuadVertexCopyResult == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const firstExpandedBVertexIndex = bVertexCopyResult.expandedStartIndex;
|
const firstExpandedBQuadVertexIndex = bQuadVertexCopyResult.expandedStartIndex;
|
||||||
const firstBVertexIndex = bVertexCopyResult.originalStartIndex;
|
const firstBQuadVertexIndex = bQuadVertexCopyResult.originalStartIndex;
|
||||||
const lastBVertexIndex = bVertexCopyResult.originalEndIndex;
|
const lastBQuadVertexIndex = bQuadVertexCopyResult.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<void>],
|
|
||||||
`edge${edgeBufferName}IndexRanges` as keyof PathRanges,
|
|
||||||
expandedArrays,
|
|
||||||
expandedRanges,
|
|
||||||
originalBuffers,
|
|
||||||
originalRanges,
|
|
||||||
expandedPathID,
|
|
||||||
originalPathID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy over indices.
|
// Copy over indices.
|
||||||
copyIndices(expandedArrays.coverInteriorIndices,
|
copyIndices(expandedArrays.bQuadVertexInteriorIndices,
|
||||||
expandedRanges.coverInteriorIndexRanges,
|
expandedRanges.bQuadVertexInteriorIndexPathRanges,
|
||||||
originalBuffers.coverInteriorIndices as Uint32Array,
|
originalBuffers.bQuadVertexInteriorIndices as Uint32Array,
|
||||||
firstExpandedBVertexIndex,
|
firstExpandedBQuadVertexIndex * 6,
|
||||||
firstBVertexIndex,
|
firstBQuadVertexIndex * 6,
|
||||||
lastBVertexIndex,
|
lastBQuadVertexIndex * 6,
|
||||||
expandedPathID);
|
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.
|
// Copy over segments.
|
||||||
copySegments(['segmentLines', 'segmentLineNormals'],
|
copySegments(['segmentLines', 'segmentLineNormals'],
|
||||||
|
@ -560,43 +358,33 @@ export class PathfinderMeshData implements Meshes<ArrayBuffer>, MeshDataCounts,
|
||||||
if (!RANGE_TO_RANGE_BUFFER_TABLE.hasOwnProperty(rangeKey))
|
if (!RANGE_TO_RANGE_BUFFER_TABLE.hasOwnProperty(rangeKey))
|
||||||
continue;
|
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 ranges = this[rangeKey as keyof PathRanges];
|
||||||
|
|
||||||
const destBuffer = new Uint16Array(count);
|
const destBuffer = new Uint16Array(instanceCount * fieldCount);
|
||||||
let destIndex = 0;
|
let destIndex = 0;
|
||||||
for (let pathIndex = 0; pathIndex < ranges.length; pathIndex++) {
|
for (let pathIndex = 0; pathIndex < ranges.length; pathIndex++) {
|
||||||
const range = ranges[pathIndex];
|
const range = ranges[pathIndex];
|
||||||
for (let subindex = range.start; subindex < range.end; subindex++) {
|
for (let subindex = range.start; subindex < range.end; subindex++) {
|
||||||
destBuffer[destIndex] = pathIndex + 1;
|
for (let fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
|
||||||
destIndex++;
|
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<WebGLBuffer>, PathRanges {
|
export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
||||||
readonly bQuads: WebGLBuffer;
|
|
||||||
readonly bQuadVertexPositions: WebGLBuffer;
|
readonly bQuadVertexPositions: WebGLBuffer;
|
||||||
readonly bVertexPositions: WebGLBuffer;
|
readonly bQuadVertexPositionPathIDs: WebGLBuffer;
|
||||||
readonly bVertexPathIDs: WebGLBuffer;
|
readonly bQuadVertexInteriorIndices: 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 segmentLines: WebGLBuffer;
|
readonly segmentLines: WebGLBuffer;
|
||||||
readonly segmentCurves: WebGLBuffer;
|
readonly segmentCurves: WebGLBuffer;
|
||||||
readonly segmentLinePathIDs: WebGLBuffer;
|
readonly segmentLinePathIDs: WebGLBuffer;
|
||||||
|
@ -604,16 +392,8 @@ export class PathfinderMeshBuffers implements Meshes<WebGLBuffer>, PathRanges {
|
||||||
readonly segmentLineNormals: WebGLBuffer;
|
readonly segmentLineNormals: WebGLBuffer;
|
||||||
readonly segmentCurveNormals: WebGLBuffer;
|
readonly segmentCurveNormals: WebGLBuffer;
|
||||||
|
|
||||||
readonly bQuadPathRanges: Range[];
|
|
||||||
readonly bQuadVertexPositionPathRanges: Range[];
|
readonly bQuadVertexPositionPathRanges: Range[];
|
||||||
readonly bVertexPathRanges: Range[];
|
readonly bQuadVertexInteriorIndexPathRanges: Range[];
|
||||||
readonly coverInteriorIndexRanges: Range[];
|
|
||||||
readonly coverCurveIndexRanges: Range[];
|
|
||||||
readonly edgeBoundingBoxRanges: Range[];
|
|
||||||
readonly edgeUpperLineIndexRanges: Range[];
|
|
||||||
readonly edgeUpperCurveIndexRanges: Range[];
|
|
||||||
readonly edgeLowerLineIndexRanges: Range[];
|
|
||||||
readonly edgeLowerCurveIndexRanges: Range[];
|
|
||||||
readonly segmentCurveRanges: Range[];
|
readonly segmentCurveRanges: Range[];
|
||||||
readonly segmentLineRanges: Range[];
|
readonly segmentLineRanges: Range[];
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
import * as glmatrix from 'gl-matrix';
|
import * as glmatrix from 'gl-matrix';
|
||||||
import * as _ from 'lodash';
|
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 {TileInfo} from './aa-strategy';
|
||||||
import {NoAAStrategy, StemDarkeningMode, SubpixelAAType} from './aa-strategy';
|
import {NoAAStrategy, StemDarkeningMode, SubpixelAAType} from './aa-strategy';
|
||||||
import {AAOptions} from './app-controller';
|
import {AAOptions} from './app-controller';
|
||||||
|
@ -24,6 +25,8 @@ import {RenderContext, Timings} from "./view";
|
||||||
|
|
||||||
const MAX_PATHS: number = 65535;
|
const MAX_PATHS: number = 65535;
|
||||||
|
|
||||||
|
const MAX_VERTICES: number = 4 * 1024 * 1024;
|
||||||
|
|
||||||
const TIME_INTERVAL_DELAY: number = 32;
|
const TIME_INTERVAL_DELAY: number = 32;
|
||||||
|
|
||||||
const B_LOOP_BLINN_DATA_SIZE: number = 4;
|
const B_LOOP_BLINN_DATA_SIZE: number = 4;
|
||||||
|
@ -92,6 +95,7 @@ export abstract class Renderer {
|
||||||
private gammaLUTTexture: WebGLTexture | null;
|
private gammaLUTTexture: WebGLTexture | null;
|
||||||
|
|
||||||
private instancedPathIDVBO: WebGLBuffer | null;
|
private instancedPathIDVBO: WebGLBuffer | null;
|
||||||
|
private vertexIDVBO: WebGLBuffer | null;
|
||||||
private timerQueryPollInterval: number | null;
|
private timerQueryPollInterval: number | null;
|
||||||
|
|
||||||
constructor(renderContext: RenderContext) {
|
constructor(renderContext: RenderContext) {
|
||||||
|
@ -110,6 +114,7 @@ export abstract class Renderer {
|
||||||
if (this.pathIDsAreInstanced)
|
if (this.pathIDsAreInstanced)
|
||||||
this.initInstancedPathIDVBO();
|
this.initInstancedPathIDVBO();
|
||||||
|
|
||||||
|
this.initVertexIDVBO();
|
||||||
this.initGammaLUTTexture();
|
this.initGammaLUTTexture();
|
||||||
|
|
||||||
this.antialiasingStrategy = new NoAAStrategy(0, 'none');
|
this.antialiasingStrategy = new NoAAStrategy(0, 'none');
|
||||||
|
@ -154,6 +159,17 @@ export abstract class Renderer {
|
||||||
|
|
||||||
const objectCount = this.objectCount;
|
const objectCount = this.objectCount;
|
||||||
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
|
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.
|
// Antialias.
|
||||||
antialiasingStrategy.antialiasObject(this, objectIndex);
|
antialiasingStrategy.antialiasObject(this, objectIndex);
|
||||||
|
|
||||||
|
@ -162,23 +178,12 @@ export abstract class Renderer {
|
||||||
if (this.timerQueryPollInterval == null && objectIndex === objectCount - 1 &&
|
if (this.timerQueryPollInterval == null && objectIndex === objectCount - 1 &&
|
||||||
pass === passCount - 1) {
|
pass === passCount - 1) {
|
||||||
renderContext.timerQueryExt
|
renderContext.timerQueryExt
|
||||||
.endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT);
|
.endQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT);
|
||||||
renderContext.timerQueryExt
|
renderContext.timerQueryExt
|
||||||
.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
.beginQueryEXT(renderContext.timerQueryExt.TIME_ELAPSED_EXT,
|
||||||
renderContext.compositingTimerQuery);
|
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.
|
// Perform post-antialiasing tasks.
|
||||||
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
antialiasingStrategy.finishAntialiasingObject(this, objectIndex);
|
||||||
|
|
||||||
|
@ -351,7 +356,7 @@ export abstract class Renderer {
|
||||||
pathRangeForObject(objectIndex: number): Range {
|
pathRangeForObject(objectIndex: number): Range {
|
||||||
if (this.meshes == null)
|
if (this.meshes == null)
|
||||||
return new Range(0, 0);
|
return new Range(0, 0);
|
||||||
const bVertexPathRanges = this.meshes[objectIndex].bVertexPathRanges;
|
const bVertexPathRanges = this.meshes[objectIndex].bQuadVertexPositionPathRanges;
|
||||||
return new Range(1, bVertexPathRanges.length + 1);
|
return new Range(1, bVertexPathRanges.length + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +387,8 @@ export abstract class Renderer {
|
||||||
PathTransformBuffers<Float32Array>;
|
PathTransformBuffers<Float32Array>;
|
||||||
|
|
||||||
protected abstract directCurveProgramName(): keyof ShaderMap<void>;
|
protected abstract directCurveProgramName(): keyof ShaderMap<void>;
|
||||||
protected abstract directInteriorProgramName(): keyof ShaderMap<void>;
|
protected abstract directInteriorProgramName(renderingMode: DirectRenderingMode):
|
||||||
|
keyof ShaderMap<void>;
|
||||||
|
|
||||||
protected drawSceneryIfNecessary(): void {}
|
protected drawSceneryIfNecessary(): void {}
|
||||||
|
|
||||||
|
@ -409,17 +415,9 @@ export abstract class Renderer {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
||||||
|
gl.clearDepth(0.0);
|
||||||
switch (renderingMode) {
|
gl.depthMask(true);
|
||||||
case 'color':
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
gl.clearDepth(0.0);
|
|
||||||
gl.depthMask(true);
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
||||||
break;
|
|
||||||
case 'none':
|
|
||||||
// Nothing to do.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getModelviewTransform(pathIndex: number): glmatrix.mat4 {
|
protected getModelviewTransform(pathIndex: number): glmatrix.mat4 {
|
||||||
|
@ -460,24 +458,27 @@ export abstract class Renderer {
|
||||||
const pathRange = this.pathRangeForObject(objectIndex);
|
const pathRange = this.pathRangeForObject(objectIndex);
|
||||||
const meshIndex = this.meshIndexForObject(objectIndex);
|
const meshIndex = this.meshIndexForObject(objectIndex);
|
||||||
|
|
||||||
const meshes = this.meshes[meshIndex];
|
const meshes = this.meshes![meshIndex];
|
||||||
const meshData = this.meshData[meshIndex];
|
const meshData = this.meshData![meshIndex];
|
||||||
|
|
||||||
// Set up implicit cover state.
|
// Set up implicit cover state.
|
||||||
gl.depthFunc(gl.GREATER);
|
gl.depthFunc(gl.GREATER);
|
||||||
gl.depthMask(true);
|
gl.depthMask(true);
|
||||||
gl.enable(gl.DEPTH_TEST);
|
gl.enable(gl.DEPTH_TEST);
|
||||||
gl.disable(gl.BLEND);
|
gl.disable(gl.BLEND);
|
||||||
|
gl.cullFace(gl.BACK);
|
||||||
|
gl.frontFace(gl.CCW);
|
||||||
|
gl.enable(gl.CULL_FACE);
|
||||||
|
|
||||||
// Set up the implicit cover interior VAO.
|
// Set up the implicit cover interior VAO.
|
||||||
const directInteriorProgramName = this.directInteriorProgramName();
|
const directInteriorProgramName = this.directInteriorProgramName(renderingMode);
|
||||||
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
||||||
if (this.implicitCoverInteriorVAO == null) {
|
if (this.implicitCoverInteriorVAO == null) {
|
||||||
this.implicitCoverInteriorVAO = renderContext.vertexArrayObjectExt
|
this.implicitCoverInteriorVAO = renderContext.vertexArrayObjectExt
|
||||||
.createVertexArrayOES();
|
.createVertexArrayOES();
|
||||||
}
|
}
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverInteriorVAO);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverInteriorVAO);
|
||||||
this.initImplicitCoverInteriorVAO(objectIndex, instanceRange);
|
this.initImplicitCoverInteriorVAO(objectIndex, instanceRange, renderingMode);
|
||||||
|
|
||||||
// Draw direct interior parts.
|
// Draw direct interior parts.
|
||||||
this.setTransformUniform(directInteriorProgram.uniforms, pass, objectIndex);
|
this.setTransformUniform(directInteriorProgram.uniforms, pass, objectIndex);
|
||||||
|
@ -489,57 +490,67 @@ export abstract class Renderer {
|
||||||
this.pathTransformBufferTextures[meshIndex]
|
this.pathTransformBufferTextures[meshIndex]
|
||||||
.ext
|
.ext
|
||||||
.bind(gl, directInteriorProgram.uniforms, 2);
|
.bind(gl, directInteriorProgram.uniforms, 2);
|
||||||
const coverInteriorRange = getMeshIndexRange(meshes.coverInteriorIndexRanges, pathRange);
|
const bQuadInteriorRange = getMeshIndexRange(meshes.bQuadVertexInteriorIndexPathRanges,
|
||||||
|
pathRange);
|
||||||
if (!this.pathIDsAreInstanced) {
|
if (!this.pathIDsAreInstanced) {
|
||||||
gl.drawElements(gl.TRIANGLES,
|
gl.drawElements(gl.TRIANGLES,
|
||||||
coverInteriorRange.length,
|
bQuadInteriorRange.length,
|
||||||
gl.UNSIGNED_INT,
|
gl.UNSIGNED_INT,
|
||||||
coverInteriorRange.start * UINT32_SIZE);
|
bQuadInteriorRange.start * UINT32_SIZE);
|
||||||
} else {
|
} else {
|
||||||
renderContext.instancedArraysExt
|
renderContext.instancedArraysExt
|
||||||
.drawElementsInstancedANGLE(gl.TRIANGLES,
|
.drawElementsInstancedANGLE(gl.TRIANGLES,
|
||||||
coverInteriorRange.length,
|
bQuadInteriorRange.length,
|
||||||
gl.UNSIGNED_INT,
|
gl.UNSIGNED_INT,
|
||||||
0,
|
0,
|
||||||
instanceRange.length);
|
instanceRange.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up direct curve state.
|
gl.disable(gl.CULL_FACE);
|
||||||
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);
|
|
||||||
|
|
||||||
// Set up the direct curve VAO.
|
// Render curves, if applicable.
|
||||||
//
|
if (renderingMode !== 'conservative') {
|
||||||
// TODO(pcwalton): Cache these.
|
// Set up direct curve state.
|
||||||
const directCurveProgramName = this.directCurveProgramName();
|
gl.depthMask(false);
|
||||||
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
gl.enable(gl.BLEND);
|
||||||
if (this.implicitCoverCurveVAO == null)
|
gl.blendEquation(gl.FUNC_ADD);
|
||||||
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO);
|
|
||||||
this.initImplicitCoverCurveVAO(objectIndex, instanceRange);
|
|
||||||
|
|
||||||
// Draw direct curve parts.
|
// Set up the direct curve VAO.
|
||||||
this.setTransformUniform(directCurveProgram.uniforms, pass, objectIndex);
|
//
|
||||||
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
|
// TODO(pcwalton): Cache these.
|
||||||
this.setHintsUniform(directCurveProgram.uniforms);
|
const directCurveProgramName = this.directCurveProgramName();
|
||||||
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
|
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
||||||
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
|
if (this.implicitCoverCurveVAO == null) {
|
||||||
this.pathTransformBufferTextures[meshIndex].st.bind(gl, directCurveProgram.uniforms, 1);
|
this.implicitCoverCurveVAO = renderContext.vertexArrayObjectExt
|
||||||
this.pathTransformBufferTextures[meshIndex].ext.bind(gl, directCurveProgram.uniforms, 2);
|
.createVertexArrayOES();
|
||||||
const coverCurveRange = getMeshIndexRange(meshes.coverCurveIndexRanges, pathRange);
|
}
|
||||||
if (!this.pathIDsAreInstanced) {
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(this.implicitCoverCurveVAO);
|
||||||
gl.drawElements(gl.TRIANGLES,
|
this.initImplicitCoverCurveVAO(objectIndex, instanceRange);
|
||||||
coverCurveRange.length,
|
|
||||||
gl.UNSIGNED_INT,
|
// Draw direct curve parts.
|
||||||
coverCurveRange.start * UINT32_SIZE);
|
this.setTransformUniform(directCurveProgram.uniforms, pass, objectIndex);
|
||||||
} else {
|
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
|
||||||
renderContext.instancedArraysExt.drawElementsInstancedANGLE(gl.TRIANGLES,
|
this.setHintsUniform(directCurveProgram.uniforms);
|
||||||
coverCurveRange.length,
|
this.setPathColorsUniform(objectIndex, directCurveProgram.uniforms, 0);
|
||||||
gl.UNSIGNED_INT,
|
this.setEmboldenAmountUniform(objectIndex, directCurveProgram.uniforms);
|
||||||
0,
|
this.pathTransformBufferTextures[meshIndex]
|
||||||
instanceRange.length);
|
.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);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
|
@ -548,7 +559,7 @@ export abstract class Renderer {
|
||||||
antialiasingStrategy.finishDirectlyRenderingObject(this, objectIndex);
|
antialiasingStrategy.finishDirectlyRenderingObject(this, objectIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private finishTiming() {
|
private finishTiming(): void {
|
||||||
const renderContext = this.renderContext;
|
const renderContext = this.renderContext;
|
||||||
|
|
||||||
if (this.timerQueryPollInterval != null)
|
if (this.timerQueryPollInterval != null)
|
||||||
|
@ -613,17 +624,20 @@ export abstract class Renderer {
|
||||||
|
|
||||||
const meshIndex = this.meshIndexForObject(objectIndex);
|
const meshIndex = this.meshIndexForObject(objectIndex);
|
||||||
const meshes = this.meshes[meshIndex];
|
const meshes = this.meshes[meshIndex];
|
||||||
|
const meshData = unwrapNull(this.meshData)[meshIndex];
|
||||||
|
|
||||||
const directCurveProgramName = this.directCurveProgramName();
|
const directCurveProgramName = this.directCurveProgramName();
|
||||||
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
const directCurveProgram = renderContext.shaderPrograms[directCurveProgramName];
|
||||||
gl.useProgram(directCurveProgram.program);
|
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.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)
|
if (this.pathIDsAreInstanced)
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||||
else
|
else
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositionPathIDs);
|
||||||
gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
|
gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
|
||||||
1,
|
1,
|
||||||
gl.UNSIGNED_SHORT,
|
gl.UNSIGNED_SHORT,
|
||||||
|
@ -635,35 +649,15 @@ export abstract class Renderer {
|
||||||
.vertexAttribDivisorANGLE(directCurveProgram.attributes.aPathID, 1);
|
.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.aPosition);
|
||||||
gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
|
gl.enableVertexAttribArray(directCurveProgram.attributes.aVertexID);
|
||||||
gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
|
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)
|
if (this.meshes == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -673,10 +667,10 @@ export abstract class Renderer {
|
||||||
const meshIndex = this.meshIndexForObject(objectIndex);
|
const meshIndex = this.meshIndexForObject(objectIndex);
|
||||||
const meshes = this.meshes[meshIndex];
|
const meshes = this.meshes[meshIndex];
|
||||||
|
|
||||||
const directInteriorProgramName = this.directInteriorProgramName();
|
const directInteriorProgramName = this.directInteriorProgramName(renderingMode);
|
||||||
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
const directInteriorProgram = renderContext.shaderPrograms[directInteriorProgramName];
|
||||||
gl.useProgram(directInteriorProgram.program);
|
gl.useProgram(directInteriorProgram.program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPositions);
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositions);
|
||||||
gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
|
gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
|
||||||
2,
|
2,
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
|
@ -687,7 +681,7 @@ export abstract class Renderer {
|
||||||
if (this.pathIDsAreInstanced)
|
if (this.pathIDsAreInstanced)
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||||
else
|
else
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
|
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bQuadVertexPositionPathIDs);
|
||||||
gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
|
gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
|
||||||
1,
|
1,
|
||||||
gl.UNSIGNED_SHORT,
|
gl.UNSIGNED_SHORT,
|
||||||
|
@ -699,18 +693,21 @@ export abstract class Renderer {
|
||||||
.vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1);
|
.vertexAttribDivisorANGLE(directInteriorProgram.attributes.aPathID, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, meshes.bVertexNormals);
|
if (directInteriorProgramName === 'conservativeInterior') {
|
||||||
gl.vertexAttribPointer(directInteriorProgram.attributes.aNormalAngle,
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexIDVBO);
|
||||||
1,
|
gl.vertexAttribPointer(directInteriorProgram.attributes.aVertexID,
|
||||||
gl.FLOAT,
|
1,
|
||||||
false,
|
gl.FLOAT,
|
||||||
FLOAT32_SIZE,
|
false,
|
||||||
0);
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
|
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
|
||||||
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
|
gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
|
||||||
gl.enableVertexAttribArray(directInteriorProgram.attributes.aNormalAngle);
|
if (directInteriorProgramName === 'conservativeInterior')
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.coverInteriorIndices);
|
gl.enableVertexAttribArray(directInteriorProgram.attributes.aVertexID);
|
||||||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, meshes.bQuadVertexInteriorIndices);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initInstancedPathIDVBO(): void {
|
private initInstancedPathIDVBO(): void {
|
||||||
|
@ -721,11 +718,25 @@ export abstract class Renderer {
|
||||||
for (let pathIndex = 0; pathIndex < MAX_PATHS; pathIndex++)
|
for (let pathIndex = 0; pathIndex < MAX_PATHS; pathIndex++)
|
||||||
pathIDs[pathIndex] = pathIndex + 1;
|
pathIDs[pathIndex] = pathIndex + 1;
|
||||||
|
|
||||||
this.instancedPathIDVBO = renderContext.gl.createBuffer();
|
this.instancedPathIDVBO = gl.createBuffer();
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancedPathIDVBO);
|
||||||
gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW);
|
gl.bufferData(gl.ARRAY_BUFFER, pathIDs, gl.STATIC_DRAW);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
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 {
|
function getMeshIndexRange(indexRanges: Range[], pathRange: Range): Range {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {expectNotNull, PathfinderError, unwrapNull} from './utils';
|
||||||
export interface ShaderMap<T> {
|
export interface ShaderMap<T> {
|
||||||
blitLinear: T;
|
blitLinear: T;
|
||||||
blitGamma: T;
|
blitGamma: T;
|
||||||
|
conservativeInterior: T;
|
||||||
demo3DDistantGlyph: T;
|
demo3DDistantGlyph: T;
|
||||||
demo3DMonument: T;
|
demo3DMonument: T;
|
||||||
directCurve: T;
|
directCurve: T;
|
||||||
|
@ -39,6 +40,7 @@ const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl';
|
||||||
export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
export const SHADER_NAMES: Array<keyof ShaderMap<void>> = [
|
||||||
'blitLinear',
|
'blitLinear',
|
||||||
'blitGamma',
|
'blitGamma',
|
||||||
|
'conservativeInterior',
|
||||||
'directCurve',
|
'directCurve',
|
||||||
'directInterior',
|
'directInterior',
|
||||||
'direct3DCurve',
|
'direct3DCurve',
|
||||||
|
@ -63,6 +65,10 @@ const SHADER_URLS: ShaderMap<ShaderProgramURLs> = {
|
||||||
fragment: "/glsl/gles2/blit-linear.fs.glsl",
|
fragment: "/glsl/gles2/blit-linear.fs.glsl",
|
||||||
vertex: "/glsl/gles2/blit.vs.glsl",
|
vertex: "/glsl/gles2/blit.vs.glsl",
|
||||||
},
|
},
|
||||||
|
conservativeInterior: {
|
||||||
|
fragment: "/glsl/gles2/direct-interior.fs.glsl",
|
||||||
|
vertex: "/glsl/gles2/conservative-interior.vs.glsl",
|
||||||
|
},
|
||||||
demo3DDistantGlyph: {
|
demo3DDistantGlyph: {
|
||||||
fragment: "/glsl/gles2/demo-3d-distant-glyph.fs.glsl",
|
fragment: "/glsl/gles2/demo-3d-distant-glyph.fs.glsl",
|
||||||
vertex: "/glsl/gles2/demo-3d-distant-glyph.vs.glsl",
|
vertex: "/glsl/gles2/demo-3d-distant-glyph.vs.glsl",
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
import * as glmatrix from 'gl-matrix';
|
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 {SubpixelAAType} from './aa-strategy';
|
||||||
import {OrthographicCamera} from "./camera";
|
import {OrthographicCamera} from "./camera";
|
||||||
import {UniformMap} from './gl-utils';
|
import {UniformMap} from './gl-utils';
|
||||||
|
@ -163,8 +164,9 @@ export abstract class SVGRenderer extends Renderer {
|
||||||
return 'directCurve';
|
return 'directCurve';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected directInteriorProgramName(): keyof ShaderMap<void> {
|
protected directInteriorProgramName(renderingMode: DirectRenderingMode):
|
||||||
return 'directInterior';
|
keyof ShaderMap<void> {
|
||||||
|
return renderingMode === 'conservative' ? 'conservativeInterior' : 'directInterior';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected pathColorsForObject(objectIndex: number): Uint8Array {
|
protected pathColorsForObject(objectIndex: number): Uint8Array {
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
import * as glmatrix from 'gl-matrix';
|
import * as glmatrix from 'gl-matrix';
|
||||||
|
|
||||||
export const FLOAT32_SIZE: number = 4;
|
export const FLOAT32_SIZE: number = 4;
|
||||||
|
|
||||||
export const UINT16_SIZE: number = 2;
|
export const UINT16_SIZE: number = 2;
|
||||||
|
export const UINT8_SIZE: number = 1;
|
||||||
|
|
||||||
export const UINT32_MAX: number = 0xffffffff;
|
export const UINT32_MAX: number = 0xffffffff;
|
||||||
export const UINT32_SIZE: number = 4;
|
export const UINT32_SIZE: number = 4;
|
||||||
|
|
|
@ -23,17 +23,17 @@ import {ShaderProgramSource, UnlinkedShaderProgram} from './shader-loader';
|
||||||
import {expectNotNull, PathfinderError, UINT32_SIZE, unwrapNull} from './utils';
|
import {expectNotNull, PathfinderError, UINT32_SIZE, unwrapNull} from './utils';
|
||||||
|
|
||||||
const QUAD_POSITIONS: Float32Array = new Float32Array([
|
const QUAD_POSITIONS: Float32Array = new Float32Array([
|
||||||
0.0, 1.0,
|
|
||||||
1.0, 1.0,
|
|
||||||
0.0, 0.0,
|
0.0, 0.0,
|
||||||
1.0, 0.0,
|
1.0, 0.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 1.0,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const QUAD_TEX_COORDS: Float32Array = new Float32Array([
|
const QUAD_TEX_COORDS: Float32Array = new Float32Array([
|
||||||
0.0, 1.0,
|
|
||||||
1.0, 1.0,
|
|
||||||
0.0, 0.0,
|
0.0, 0.0,
|
||||||
1.0, 0.0,
|
1.0, 0.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 1.0,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const TIMINGS: {[name: string]: string} = {
|
export const TIMINGS: {[name: string]: string} = {
|
||||||
|
|
|
@ -33,15 +33,33 @@ type Direction = 'upper' | 'lower';
|
||||||
|
|
||||||
const DIRECTIONS: 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 {
|
export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
abstract readonly directRenderingMode: DirectRenderingMode;
|
abstract readonly directRenderingMode: DirectRenderingMode;
|
||||||
|
|
||||||
|
protected patchVertexBuffer: WebGLBuffer | null;
|
||||||
|
protected patchIndexBuffer: WebGLBuffer | null;
|
||||||
|
|
||||||
get passCount(): number {
|
get passCount(): number {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract get usesDilationTransforms(): boolean;
|
protected abstract get usesDilationTransforms(): boolean;
|
||||||
|
|
||||||
|
protected abstract get patchIndices(): Uint8Array;
|
||||||
|
|
||||||
protected pathBoundsBufferTextures: PathfinderBufferTexture[];
|
protected pathBoundsBufferTextures: PathfinderBufferTexture[];
|
||||||
|
|
||||||
protected supersampledFramebufferSize: glmatrix.vec2;
|
protected supersampledFramebufferSize: glmatrix.vec2;
|
||||||
|
@ -72,8 +90,22 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
|
|
||||||
attachMeshes(renderer: Renderer): void {
|
attachMeshes(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
this.createResolveVAO(renderer);
|
this.createResolveVAO(renderer);
|
||||||
this.pathBoundsBufferTextures = [];
|
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 {
|
setFramebufferSize(renderer: Renderer): void {
|
||||||
|
@ -336,6 +368,10 @@ export abstract class XCAAStrategy extends AntialiasingStrategy {
|
||||||
export class MCAAStrategy extends XCAAStrategy {
|
export class MCAAStrategy extends XCAAStrategy {
|
||||||
protected vao: WebGLVertexArrayObject | null;
|
protected vao: WebGLVertexArrayObject | null;
|
||||||
|
|
||||||
|
protected get patchIndices(): Uint8Array {
|
||||||
|
return MCAA_PATCH_INDICES;
|
||||||
|
}
|
||||||
|
|
||||||
protected get usesDilationTransforms(): boolean {
|
protected get usesDilationTransforms(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +384,10 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
super.attachMeshes(renderer);
|
super.attachMeshes(renderer);
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
this.vao = renderContext.vertexArrayObjectExt.createVertexArrayOES();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
antialiasObject(renderer: Renderer, objectIndex: number): void {
|
||||||
|
@ -372,14 +411,13 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected clearForAA(renderer: Renderer): void {
|
protected clearForAA(renderer: Renderer): void {
|
||||||
|
if (!this.usesAAFramebuffer(renderer))
|
||||||
|
return;
|
||||||
|
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
if (renderer.isMulticolor)
|
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
gl.clearColor(1.0, 1.0, 1.0, 1.0);
|
|
||||||
else
|
|
||||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
gl.clearDepth(0.0);
|
gl.clearDepth(0.0);
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
@ -388,7 +426,17 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
const renderContext = renderer.renderContext;
|
const renderContext = renderer.renderContext;
|
||||||
const gl = renderContext.gl;
|
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 {
|
protected clearForResolve(renderer: Renderer): void {
|
||||||
|
@ -396,7 +444,7 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
const gl = renderContext.gl;
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
if (!renderer.isMulticolor) {
|
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);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,53 +485,80 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
const vao = this.vao;
|
const vao = this.vao;
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
const bQuadRanges = renderer.meshData[meshIndex].bQuadVertexPositionPathRanges;
|
||||||
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
const offset = calculateStartFromIndexRanges(pathRange, bQuadRanges);
|
||||||
|
|
||||||
gl.useProgram(shaderProgram.program);
|
gl.useProgram(shaderProgram.program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.patchVertexBuffer);
|
||||||
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, renderer.meshes[meshIndex].bQuadVertexPositions);
|
gl.bindBuffer(gl.ARRAY_BUFFER, renderer.meshes[meshIndex].bQuadVertexPositions);
|
||||||
gl.vertexAttribPointer(attributes.aUpperEndpointPositions,
|
gl.vertexAttribPointer(attributes.aUpperLeftEndpointPosition,
|
||||||
4,
|
2,
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
FLOAT32_SIZE * 12,
|
FLOAT32_SIZE * 12,
|
||||||
FLOAT32_SIZE * 12 * offset);
|
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 0);
|
||||||
gl.vertexAttribPointer(attributes.aLowerEndpointPositions,
|
gl.vertexAttribPointer(attributes.aUpperControlPointPosition,
|
||||||
4,
|
2,
|
||||||
|
gl.FLOAT,
|
||||||
|
false,
|
||||||
|
FLOAT32_SIZE * 12,
|
||||||
|
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 2);
|
||||||
|
gl.vertexAttribPointer(attributes.aUpperRightEndpointPosition,
|
||||||
|
2,
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
FLOAT32_SIZE * 12,
|
FLOAT32_SIZE * 12,
|
||||||
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 4);
|
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 4);
|
||||||
gl.vertexAttribPointer(attributes.aControlPointPositions,
|
gl.vertexAttribPointer(attributes.aLowerRightEndpointPosition,
|
||||||
4,
|
2,
|
||||||
|
gl.FLOAT,
|
||||||
|
false,
|
||||||
|
FLOAT32_SIZE * 12,
|
||||||
|
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 6);
|
||||||
|
gl.vertexAttribPointer(attributes.aLowerControlPointPosition,
|
||||||
|
2,
|
||||||
gl.FLOAT,
|
gl.FLOAT,
|
||||||
false,
|
false,
|
||||||
FLOAT32_SIZE * 12,
|
FLOAT32_SIZE * 12,
|
||||||
FLOAT32_SIZE * 12 * offset + FLOAT32_SIZE * 8);
|
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
|
renderContext.instancedArraysExt
|
||||||
.vertexAttribDivisorANGLE(attributes.aUpperEndpointPositions, 1);
|
.vertexAttribDivisorANGLE(attributes.aUpperLeftEndpointPosition, 1);
|
||||||
renderContext.instancedArraysExt
|
renderContext.instancedArraysExt
|
||||||
.vertexAttribDivisorANGLE(attributes.aLowerEndpointPositions, 1);
|
.vertexAttribDivisorANGLE(attributes.aUpperControlPointPosition, 1);
|
||||||
renderContext.instancedArraysExt
|
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,
|
gl.vertexAttribPointer(attributes.aPathID,
|
||||||
1,
|
1,
|
||||||
gl.UNSIGNED_SHORT,
|
gl.UNSIGNED_SHORT,
|
||||||
false,
|
false,
|
||||||
0,
|
UINT16_SIZE * 6,
|
||||||
UINT16_SIZE * offset);
|
UINT16_SIZE * offset);
|
||||||
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
renderContext.instancedArraysExt.vertexAttribDivisorANGLE(attributes.aPathID, 1);
|
||||||
|
|
||||||
gl.enableVertexAttribArray(attributes.aQuadPosition);
|
gl.enableVertexAttribArray(attributes.aTessCoord);
|
||||||
gl.enableVertexAttribArray(attributes.aUpperEndpointPositions);
|
gl.enableVertexAttribArray(attributes.aUpperLeftEndpointPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aLowerEndpointPositions);
|
gl.enableVertexAttribArray(attributes.aUpperControlPointPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aControlPointPositions);
|
gl.enableVertexAttribArray(attributes.aUpperRightEndpointPosition);
|
||||||
|
gl.enableVertexAttribArray(attributes.aLowerRightEndpointPosition);
|
||||||
|
gl.enableVertexAttribArray(attributes.aLowerControlPointPosition);
|
||||||
|
gl.enableVertexAttribArray(attributes.aLowerLeftEndpointPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aPathID);
|
gl.enableVertexAttribArray(attributes.aPathID);
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.patchIndexBuffer);
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
}
|
}
|
||||||
|
@ -516,18 +591,22 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(vao);
|
||||||
|
|
||||||
this.setBlendModeForAA(renderer);
|
this.setBlendModeForAA(renderer);
|
||||||
|
this.setAADepthState(renderer);
|
||||||
|
|
||||||
const bQuadRanges = renderer.meshData[meshIndex].bQuadPathRanges;
|
const bQuadRanges = renderer.meshData[meshIndex].bQuadVertexPositionPathRanges;
|
||||||
const count = calculateCountFromIndexRanges(pathRange, bQuadRanges);
|
const count = calculateCountFromIndexRanges(pathRange, bQuadRanges);
|
||||||
|
|
||||||
renderContext.instancedArraysExt
|
renderContext.instancedArraysExt
|
||||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
.drawElementsInstancedANGLE(gl.TRIANGLES, 12, gl.UNSIGNED_BYTE, 0, count);
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
|
gl.disable(gl.DEPTH_TEST);
|
||||||
|
gl.disable(gl.CULL_FACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
get directRenderingMode(): DirectRenderingMode {
|
get directRenderingMode(): DirectRenderingMode {
|
||||||
return 'none';
|
// FIXME(pcwalton): Only in multicolor mode?
|
||||||
|
return 'conservative';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
|
||||||
|
@ -544,6 +623,10 @@ export class MCAAStrategy extends XCAAStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ECAAStrategy extends XCAAStrategy {
|
export class ECAAStrategy extends XCAAStrategy {
|
||||||
|
protected get patchIndices(): Uint8Array {
|
||||||
|
return ECAA_CURVE_PATCH_INDICES;
|
||||||
|
}
|
||||||
|
|
||||||
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
protected get lineShaderProgramNames(): Array<keyof ShaderMap<void>> {
|
||||||
return ['ecaaLine'];
|
return ['ecaaLine'];
|
||||||
}
|
}
|
||||||
|
@ -588,6 +671,11 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
objectIndex,
|
objectIndex,
|
||||||
this.curveShaderProgramNames[0],
|
this.curveShaderProgramNames[0],
|
||||||
this.curveShaderProgramNames[1]);
|
this.curveShaderProgramNames[1]);
|
||||||
|
|
||||||
|
const renderContext = renderer.renderContext;
|
||||||
|
const gl = renderContext.gl;
|
||||||
|
|
||||||
|
gl.disable(gl.CULL_FACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected usesAAFramebuffer(): boolean {
|
protected usesAAFramebuffer(): boolean {
|
||||||
|
@ -619,7 +707,13 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
|
|
||||||
protected setAADepthState(renderer: Renderer): void {
|
protected setAADepthState(renderer: Renderer): void {
|
||||||
const renderContext = renderer.renderContext;
|
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 {
|
protected clearForResolve(renderer: Renderer): void {
|
||||||
|
@ -699,7 +793,7 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
// FIXME(pcwalton): Only render the appropriate instances.
|
// FIXME(pcwalton): Only render the appropriate instances.
|
||||||
const count = renderer.meshData[meshIndex].segmentCurveCount;
|
const count = renderer.meshData[meshIndex].segmentCurveCount;
|
||||||
renderContext.instancedArraysExt
|
renderContext.instancedArraysExt
|
||||||
.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, count);
|
.drawElementsInstancedANGLE(gl.TRIANGLES, 9, gl.UNSIGNED_BYTE, 0, count);
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
}
|
}
|
||||||
|
@ -735,7 +829,7 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
|
|
||||||
gl.useProgram(lineProgram.program);
|
gl.useProgram(lineProgram.program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
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.bindBuffer(gl.ARRAY_BUFFER, lineVertexPositionsBuffer);
|
||||||
gl.vertexAttribPointer(attributes.aLeftPosition,
|
gl.vertexAttribPointer(attributes.aLeftPosition,
|
||||||
2,
|
2,
|
||||||
|
@ -752,7 +846,7 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, linePathIDsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, linePathIDsBuffer);
|
||||||
gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0);
|
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.aLeftPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aRightPosition);
|
gl.enableVertexAttribArray(attributes.aRightPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aPathID);
|
gl.enableVertexAttribArray(attributes.aPathID);
|
||||||
|
@ -805,8 +899,8 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
const curveNormalsBuffer = renderer.meshes[0].segmentCurveNormals;
|
const curveNormalsBuffer = renderer.meshes[0].segmentCurveNormals;
|
||||||
|
|
||||||
gl.useProgram(curveProgram.program);
|
gl.useProgram(curveProgram.program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, renderContext.quadPositionsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.patchVertexBuffer);
|
||||||
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, curveVertexPositionsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, curveVertexPositionsBuffer);
|
||||||
gl.vertexAttribPointer(attributes.aLeftPosition,
|
gl.vertexAttribPointer(attributes.aLeftPosition,
|
||||||
2,
|
2,
|
||||||
|
@ -829,7 +923,7 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, curvePathIDsBuffer);
|
||||||
gl.vertexAttribPointer(attributes.aPathID, 1, gl.UNSIGNED_SHORT, false, 0, 0);
|
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.aLeftPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aControlPointPosition);
|
gl.enableVertexAttribArray(attributes.aControlPointPosition);
|
||||||
gl.enableVertexAttribArray(attributes.aRightPosition);
|
gl.enableVertexAttribArray(attributes.aRightPosition);
|
||||||
|
@ -857,7 +951,7 @@ export class ECAAStrategy extends XCAAStrategy {
|
||||||
.vertexAttribDivisorANGLE(attributes.aNormalAngles, 1);
|
.vertexAttribDivisorANGLE(attributes.aNormalAngles, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, renderContext.quadElementsBuffer);
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.patchIndexBuffer);
|
||||||
|
|
||||||
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
renderContext.vertexArrayObjectExt.bindVertexArrayOES(null);
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,6 @@ image = "0.17"
|
||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
lru-cache = "0.1"
|
lru-cache = "0.1"
|
||||||
rocket = "0.3"
|
|
||||||
rocket_codegen = "0.3"
|
|
||||||
rocket_contrib = "0.3"
|
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -36,6 +33,15 @@ optional = true
|
||||||
[dependencies.fontsan]
|
[dependencies.fontsan]
|
||||||
git = "https://github.com/servo/fontsan.git"
|
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]
|
[dependencies.pathfinder_font_renderer]
|
||||||
path = "../../font-renderer"
|
path = "../../font-renderer"
|
||||||
|
|
||||||
|
@ -44,3 +50,6 @@ path = "../../partitioner"
|
||||||
|
|
||||||
[dependencies.pathfinder_path_utils]
|
[dependencies.pathfinder_path_utils]
|
||||||
path = "../../path-utils"
|
path = "../../path-utils"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
ring = { git = "https://github.com/SergioBenitez/ring", branch = "v0.12" }
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
#![feature(plugin)]
|
#![feature(decl_macro, plugin)]
|
||||||
#![plugin(rocket_codegen)]
|
#![plugin(rocket_codegen)]
|
||||||
|
|
||||||
extern crate app_units;
|
extern crate app_units;
|
||||||
|
|
|
@ -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
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern fn pf_init_env_logger() -> u32 {
|
pub unsafe extern fn pf_init_env_logger() -> u32 {
|
||||||
env_logger::init().is_ok() as u32
|
env_logger::init().is_ok() as u32
|
||||||
|
|
|
@ -103,9 +103,12 @@ impl BQuad {
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
pub struct BQuadVertexPositions {
|
pub struct BQuadVertexPositions {
|
||||||
pub upper_endpoint_positions: [Point2D<f32>; 2],
|
pub upper_left_vertex_position: Point2D<f32>,
|
||||||
pub lower_endpoint_positions: [Point2D<f32>; 2],
|
pub upper_control_point_position: Point2D<f32>,
|
||||||
pub control_point_positions: [Point2D<f32>; 2],
|
pub upper_right_vertex_position: Point2D<f32>,
|
||||||
|
pub lower_right_vertex_position: Point2D<f32>,
|
||||||
|
pub lower_control_point_position: Point2D<f32>,
|
||||||
|
pub lower_left_vertex_position: Point2D<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
@ -124,7 +127,7 @@ pub(crate) enum BVertexKind {
|
||||||
ConcaveControlPoint,
|
ConcaveControlPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct BVertexLoopBlinnData {
|
pub struct BVertexLoopBlinnData {
|
||||||
pub tex_coord: [u8; 2],
|
pub tex_coord: [u8; 2],
|
||||||
|
|
|
@ -26,11 +26,10 @@ pub struct MeshLibrary {
|
||||||
pub b_quads: Vec<BQuad>,
|
pub b_quads: Vec<BQuad>,
|
||||||
// FIXME(pcwalton): Merge with `b_vertex_positions` below.
|
// FIXME(pcwalton): Merge with `b_vertex_positions` below.
|
||||||
pub b_quad_vertex_positions: Vec<BQuadVertexPositions>,
|
pub b_quad_vertex_positions: Vec<BQuadVertexPositions>,
|
||||||
|
pub b_quad_vertex_interior_indices: Vec<u32>,
|
||||||
pub b_vertex_positions: Vec<Point2D<f32>>,
|
pub b_vertex_positions: Vec<Point2D<f32>>,
|
||||||
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
|
pub b_vertex_loop_blinn_data: Vec<BVertexLoopBlinnData>,
|
||||||
pub b_vertex_normals: Vec<f32>,
|
pub b_vertex_normals: Vec<f32>,
|
||||||
pub cover_indices: MeshLibraryCoverIndices,
|
|
||||||
pub edge_data: MeshLibraryEdgeData,
|
|
||||||
pub segments: MeshLibrarySegments,
|
pub segments: MeshLibrarySegments,
|
||||||
pub segment_normals: MeshLibrarySegmentNormals,
|
pub segment_normals: MeshLibrarySegmentNormals,
|
||||||
}
|
}
|
||||||
|
@ -42,11 +41,10 @@ impl MeshLibrary {
|
||||||
path_ranges: vec![],
|
path_ranges: vec![],
|
||||||
b_quads: vec![],
|
b_quads: vec![],
|
||||||
b_quad_vertex_positions: vec![],
|
b_quad_vertex_positions: vec![],
|
||||||
|
b_quad_vertex_interior_indices: vec![],
|
||||||
b_vertex_positions: vec![],
|
b_vertex_positions: vec![],
|
||||||
b_vertex_loop_blinn_data: vec![],
|
b_vertex_loop_blinn_data: vec![],
|
||||||
b_vertex_normals: vec![],
|
b_vertex_normals: vec![],
|
||||||
cover_indices: MeshLibraryCoverIndices::new(),
|
|
||||||
edge_data: MeshLibraryEdgeData::new(),
|
|
||||||
segments: MeshLibrarySegments::new(),
|
segments: MeshLibrarySegments::new(),
|
||||||
segment_normals: MeshLibrarySegmentNormals::new(),
|
segment_normals: MeshLibrarySegmentNormals::new(),
|
||||||
}
|
}
|
||||||
|
@ -56,11 +54,10 @@ impl MeshLibrary {
|
||||||
self.path_ranges.clear();
|
self.path_ranges.clear();
|
||||||
self.b_quads.clear();
|
self.b_quads.clear();
|
||||||
self.b_quad_vertex_positions.clear();
|
self.b_quad_vertex_positions.clear();
|
||||||
|
self.b_quad_vertex_interior_indices.clear();
|
||||||
self.b_vertex_positions.clear();
|
self.b_vertex_positions.clear();
|
||||||
self.b_vertex_loop_blinn_data.clear();
|
self.b_vertex_loop_blinn_data.clear();
|
||||||
self.b_vertex_normals.clear();
|
self.b_vertex_normals.clear();
|
||||||
self.cover_indices.clear();
|
|
||||||
self.edge_data.clear();
|
|
||||||
self.segments.clear();
|
self.segments.clear();
|
||||||
self.segment_normals.clear();
|
self.segment_normals.clear();
|
||||||
}
|
}
|
||||||
|
@ -86,85 +83,99 @@ impl MeshLibrary {
|
||||||
self.b_quads.push(*b_quad);
|
self.b_quads.push(*b_quad);
|
||||||
|
|
||||||
let upper_left_position =
|
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 =
|
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 =
|
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 =
|
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 {
|
let mut b_quad_vertex_positions = BQuadVertexPositions {
|
||||||
upper_endpoint_positions: [*upper_left_position, *upper_right_position],
|
upper_left_vertex_position: upper_left_position,
|
||||||
lower_endpoint_positions: [*lower_left_position, *lower_right_position],
|
upper_control_point_position: upper_left_position,
|
||||||
control_point_positions: [Point2D::zero(), Point2D::zero()],
|
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 =
|
if b_quad.upper_control_point_vertex_index != u32::MAX {
|
||||||
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 {
|
|
||||||
let upper_control_point_position =
|
let upper_control_point_position =
|
||||||
&self.b_vertex_positions[b_quad.upper_control_point_vertex_index as usize];
|
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;
|
b_quad_vertex_positions.upper_control_point_position = 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,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if b_quad.lower_control_point_vertex_index == u32::MAX {
|
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 {
|
|
||||||
let lower_control_point_position =
|
let lower_control_point_position =
|
||||||
&self.b_vertex_positions[b_quad.lower_control_point_vertex_index as usize];
|
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;
|
b_quad_vertex_positions.lower_control_point_position = 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,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
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.
|
/// Reverses interior indices so that they draw front-to-back.
|
||||||
///
|
///
|
||||||
/// This enables early Z optimizations.
|
/// This enables early Z optimizations.
|
||||||
pub fn optimize(&mut self) {
|
pub fn optimize(&mut self) {
|
||||||
let mut new_interior_indices =
|
reverse_indices(&mut self.path_ranges,
|
||||||
Vec::with_capacity(self.cover_indices.interior_indices.len());
|
&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() {
|
fn reverse_indices<G, S>(path_ranges: &mut [PathRanges],
|
||||||
let old_interior_indices = &self.cover_indices.interior_indices[..];
|
indices: &mut Vec<u32>,
|
||||||
let old_range = path_range.cover_interior_indices.clone();
|
mut getter: G,
|
||||||
let old_range = (old_range.start as usize)..(old_range.end as usize);
|
mut setter: S)
|
||||||
let new_start_index = new_interior_indices.len() as u32;
|
where G: FnMut(&PathRanges) -> Range<u32>,
|
||||||
new_interior_indices.extend_from_slice(&old_interior_indices[old_range]);
|
S: FnMut(&mut PathRanges, Range<u32>) {
|
||||||
let new_end_index = new_interior_indices.len() as u32;
|
let mut new_indices = Vec::with_capacity(indices.len());
|
||||||
path_range.cover_interior_indices = new_start_index..new_end_index;
|
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<I>(&mut self, path_id: u16, stream: I)
|
pub fn push_segments<I>(&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"bqua", &self.b_quads));
|
||||||
try!(write_simple_chunk(writer, b"bqvp", &self.b_quad_vertex_positions));
|
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"bqii", &self.b_quad_vertex_interior_indices));
|
||||||
try!(write_simple_chunk(writer, b"bvlb", &self.b_vertex_loop_blinn_data));
|
|
||||||
try!(write_simple_chunk(writer, b"bvno", &self.b_vertex_normals));
|
|
||||||
try!(write_simple_chunk(writer, b"cvii", &self.cover_indices.interior_indices));
|
|
||||||
try!(write_simple_chunk(writer, b"cvci", &self.cover_indices.curve_indices));
|
|
||||||
try!(write_simple_chunk(writer, b"ebbv", &self.edge_data.bounding_box_vertex_positions));
|
|
||||||
try!(write_simple_chunk(writer, b"eulv", &self.edge_data.upper_line_vertex_positions));
|
|
||||||
try!(write_simple_chunk(writer, b"ellv", &self.edge_data.lower_line_vertex_positions));
|
|
||||||
try!(write_simple_chunk(writer, b"eucv", &self.edge_data.upper_curve_vertex_positions));
|
|
||||||
try!(write_simple_chunk(writer, b"elcv", &self.edge_data.lower_curve_vertex_positions));
|
|
||||||
try!(write_simple_chunk(writer, b"slin", &self.segments.lines));
|
try!(write_simple_chunk(writer, b"slin", &self.segments.lines));
|
||||||
try!(write_simple_chunk(writer, b"scur", &self.segments.curves));
|
try!(write_simple_chunk(writer, b"scur", &self.segments.curves));
|
||||||
try!(write_simple_chunk(writer, b"snli", &self.segment_normals.line_normals));
|
try!(write_simple_chunk(writer, b"snli", &self.segment_normals.line_normals));
|
||||||
|
@ -274,35 +276,11 @@ impl MeshLibrary {
|
||||||
b"bqvp",
|
b"bqvp",
|
||||||
path_ranges,
|
path_ranges,
|
||||||
|ranges| &ranges.b_quad_vertex_positions));
|
|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"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"slin", path_ranges, |ranges| &ranges.segment_lines));
|
||||||
try!(write_path_range(writer, b"scur", path_ranges, |ranges| &ranges.segment_curves));
|
try!(write_path_range(writer, b"scur", path_ranges, |ranges| &ranges.segment_curves));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -329,14 +307,8 @@ impl MeshLibrary {
|
||||||
MeshLibraryLengths {
|
MeshLibraryLengths {
|
||||||
b_quads: self.b_quads.len() as u32,
|
b_quads: self.b_quads.len() as u32,
|
||||||
b_quad_vertex_positions: self.b_quad_vertex_positions.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,
|
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<u32>,
|
pub curve_indices: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
pub(crate) struct MeshLibraryLengths {
|
||||||
b_quads: u32,
|
pub(crate) b_quads: u32,
|
||||||
b_quad_vertex_positions: u32,
|
b_quad_vertex_positions: u32,
|
||||||
|
b_quad_vertex_interior_indices: u32,
|
||||||
b_vertices: 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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PathRanges {
|
pub struct PathRanges {
|
||||||
pub b_quads: Range<u32>,
|
pub b_quads: Range<u32>,
|
||||||
pub b_quad_vertex_positions: Range<u32>,
|
pub b_quad_vertex_positions: Range<u32>,
|
||||||
|
pub b_quad_vertex_interior_indices: Range<u32>,
|
||||||
pub b_vertices: Range<u32>,
|
pub b_vertices: Range<u32>,
|
||||||
pub cover_interior_indices: Range<u32>,
|
|
||||||
pub cover_curve_indices: Range<u32>,
|
|
||||||
pub edge_bounding_box_indices: Range<u32>,
|
|
||||||
pub edge_upper_line_indices: Range<u32>,
|
|
||||||
pub edge_upper_curve_indices: Range<u32>,
|
|
||||||
pub edge_lower_line_indices: Range<u32>,
|
|
||||||
pub edge_lower_curve_indices: Range<u32>,
|
|
||||||
pub segment_lines: Range<u32>,
|
pub segment_lines: Range<u32>,
|
||||||
pub segment_curves: Range<u32>,
|
pub segment_curves: Range<u32>,
|
||||||
}
|
}
|
||||||
|
@ -396,14 +341,8 @@ impl PathRanges {
|
||||||
PathRanges {
|
PathRanges {
|
||||||
b_quads: 0..0,
|
b_quads: 0..0,
|
||||||
b_quad_vertex_positions: 0..0,
|
b_quad_vertex_positions: 0..0,
|
||||||
|
b_quad_vertex_interior_indices: 0..0,
|
||||||
b_vertices: 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_lines: 0..0,
|
||||||
segment_curves: 0..0,
|
segment_curves: 0..0,
|
||||||
}
|
}
|
||||||
|
@ -414,46 +353,9 @@ impl PathRanges {
|
||||||
end: &MeshLibraryLengths) {
|
end: &MeshLibraryLengths) {
|
||||||
self.b_quads = start.b_quads..end.b_quads;
|
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_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.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<EdgeBoundingBoxVertexPositions>,
|
|
||||||
pub upper_line_vertex_positions: Vec<EdgeLineVertexPositions>,
|
|
||||||
pub lower_line_vertex_positions: Vec<EdgeLineVertexPositions>,
|
|
||||||
pub upper_curve_vertex_positions: Vec<EdgeCurveVertexPositions>,
|
|
||||||
pub lower_curve_vertex_positions: Vec<EdgeCurveVertexPositions>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<f32>,
|
|
||||||
pub lower_right: Point2D<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct EdgeLineVertexPositions {
|
|
||||||
pub left: Point2D<f32>,
|
|
||||||
pub right: Point2D<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct EdgeCurveVertexPositions {
|
|
||||||
pub left: Point2D<f32>,
|
|
||||||
pub control_point: Point2D<f32>,
|
|
||||||
pub right: Point2D<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub struct LineSegment {
|
pub struct LineSegment {
|
||||||
pub endpoint_0: Point2D<f32>,
|
pub endpoint_0: Point2D<f32>,
|
||||||
|
|
|
@ -177,24 +177,10 @@ impl<'a> Partitioner<'a> {
|
||||||
let next_active_edge_index = self.find_point_between_active_edges(endpoint_index);
|
let next_active_edge_index = self.find_point_between_active_edges(endpoint_index);
|
||||||
|
|
||||||
let endpoint = &self.endpoints[endpoint_index as usize];
|
let endpoint = &self.endpoints[endpoint_index as usize];
|
||||||
let emission_result = self.emit_b_quads_around_active_edge(next_active_edge_index,
|
self.emit_b_quads_around_active_edge(next_active_edge_index, endpoint.position.x);
|
||||||
endpoint.position.x);
|
|
||||||
|
|
||||||
self.add_new_edges_for_min_point(endpoint_index, next_active_edge_index);
|
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 prev_endpoint_index = self.prev_endpoint_of(endpoint_index);
|
||||||
let next_endpoint_index = self.next_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);
|
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
|
// TODO(pcwalton): Collapse the two duplicate endpoints that this will create together if
|
||||||
// possible (i.e. if they have the same parity).
|
// 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[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[1], endpoint.position.x),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Add supporting interior triangles if necessary.
|
// 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();
|
self.heap.pop();
|
||||||
|
|
||||||
// FIXME(pcwalton): This is twice as slow as it needs to be.
|
// 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) {
|
fn write_normals_to_library(&mut self) {
|
||||||
|
// Write B-vertex normals.
|
||||||
for (b_vertex_index, vertex_normal) in self.vertex_normals.iter().enumerate() {
|
for (b_vertex_index, vertex_normal) in self.vertex_normals.iter().enumerate() {
|
||||||
debug_assert!(b_vertex_index <= self.library.b_vertex_normals.len());
|
debug_assert!(b_vertex_index <= self.library.b_vertex_normals.len());
|
||||||
|
|
||||||
|
@ -695,115 +663,6 @@ impl<'a> Partitioner<'a> {
|
||||||
lower_active_edge.toggle_parity();
|
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,
|
let b_quad = BQuad::new(upper_subdivision.left_curve_left,
|
||||||
upper_subdivision.left_curve_control_point,
|
upper_subdivision.left_curve_control_point,
|
||||||
upper_subdivision.middle_point,
|
upper_subdivision.middle_point,
|
||||||
|
@ -872,17 +731,6 @@ impl<'a> Partitioner<'a> {
|
||||||
self.subdivide_active_edge_again_at_t(subdivision, t, bottom)
|
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 {
|
fn already_visited_point(&self, point: &Point) -> bool {
|
||||||
// FIXME(pcwalton): This makes the visited vector too big.
|
// FIXME(pcwalton): This makes the visited vector too big.
|
||||||
let index = point.endpoint_index as usize;
|
let index = point.endpoint_index as usize;
|
||||||
|
|
|
@ -117,6 +117,12 @@ vec2 dilatePosition(vec2 position, float normalAngle, vec2 amount) {
|
||||||
return position + vec2(cos(normalAngle), -sin(normalAngle)) * 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,
|
vec2 computeMCAAPosition(vec2 position,
|
||||||
vec4 hints,
|
vec4 hints,
|
||||||
vec4 localTransformST,
|
vec4 localTransformST,
|
||||||
|
|
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
|
||||||
|
}
|
|
@ -35,24 +35,21 @@ uniform vec2 uEmboldenAmount;
|
||||||
|
|
||||||
/// The 2D position of this point.
|
/// The 2D position of this point.
|
||||||
attribute vec2 aPosition;
|
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.
|
/// The angle of the 2D normal for this point.
|
||||||
attribute float aNormalAngle;
|
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.
|
/// The fill color of this path.
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
/// The outgoing abstract Loop-Blinn texture coordinate.
|
/// The outgoing abstract Loop-Blinn texture coordinate.
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
/// Specifies whether this is a concave or convex curve.
|
|
||||||
varying float vSign;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
int pathID = int(aPathID);
|
int pathID = int(aPathID);
|
||||||
|
int vertexID = int(aVertexID);
|
||||||
|
|
||||||
vec2 pathTransformExt;
|
vec2 pathTransformExt;
|
||||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||||
|
@ -67,7 +64,9 @@ void main() {
|
||||||
|
|
||||||
gl_Position = uTransform * vec4(position, 0.0, 1.0);
|
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);
|
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||||
vTexCoord = vec2(aTexCoord) / 2.0;
|
vTexCoord = texCoord;
|
||||||
vSign = aSign;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,11 @@ precision highp float;
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
/// The abstract Loop-Blinn texture coordinate.
|
/// The abstract Loop-Blinn texture coordinate.
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
/// Specifies whether this is a concave or convex curve.
|
|
||||||
varying float vSign;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float side = vTexCoord.x * vTexCoord.x - vTexCoord.y;
|
float side = sign(vTexCoord.x * vTexCoord.x - vTexCoord.y);
|
||||||
float alpha = float(sign(side) == sign(vSign));
|
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;
|
gl_FragColor = alpha * vColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,29 +37,22 @@ uniform sampler2D uPathTransformST;
|
||||||
uniform ivec2 uPathTransformExtDimensions;
|
uniform ivec2 uPathTransformExtDimensions;
|
||||||
/// The extra path transform factors buffer texture, packed two path transforms per texel.
|
/// The extra path transform factors buffer texture, packed two path transforms per texel.
|
||||||
uniform sampler2D uPathTransformExt;
|
uniform sampler2D uPathTransformExt;
|
||||||
/// The amount of faux-bold to apply, in local path units.
|
|
||||||
uniform vec2 uEmboldenAmount;
|
|
||||||
|
|
||||||
/// The 2D position of this point.
|
/// The 2D position of this point.
|
||||||
attribute vec2 aPosition;
|
attribute vec2 aPosition;
|
||||||
/// The abstract Loop-Blinn texture coordinate for this point.
|
/// The vertex ID. In OpenGL 3.0+, this can be omitted in favor of `gl_VertexID`.
|
||||||
attribute vec2 aTexCoord;
|
attribute float aVertexID;
|
||||||
/// The path ID, starting from 1.
|
/// The path ID, starting from 1.
|
||||||
attribute float aPathID;
|
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.
|
/// The fill color of this path.
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
/// The outgoing abstract Loop-Blinn texture coordinate.
|
/// The outgoing abstract Loop-Blinn texture coordinate.
|
||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
/// Specifies whether this is a concave or convex curve.
|
|
||||||
varying float vSign;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
int pathID = int(aPathID);
|
int pathID = int(aPathID);
|
||||||
|
int vertexID = int(aVertexID);
|
||||||
|
|
||||||
vec2 pathTransformExt;
|
vec2 pathTransformExt;
|
||||||
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
vec4 pathTransformST = fetchPathAffineTransform(pathTransformExt,
|
||||||
|
@ -69,15 +62,16 @@ void main() {
|
||||||
uPathTransformExtDimensions,
|
uPathTransformExtDimensions,
|
||||||
pathID);
|
pathID);
|
||||||
|
|
||||||
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
|
vec2 position = hintPosition(aPosition, uHints);
|
||||||
position = hintPosition(position, uHints);
|
|
||||||
position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
|
position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
|
||||||
position = transformVertexPosition(position, uTransform);
|
position = transformVertexPosition(position, uTransform);
|
||||||
|
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
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);
|
vColor = fetchFloat4Data(uPathColors, pathID, uPathColorsDimensions);
|
||||||
vTexCoord = vec2(aTexCoord) / 2.0;
|
vTexCoord = texCoord;
|
||||||
vSign = aSign;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,11 @@ uniform sampler2D uPathTransformST;
|
||||||
uniform ivec2 uPathTransformExtDimensions;
|
uniform ivec2 uPathTransformExtDimensions;
|
||||||
/// The extra path transform factors buffer texture, packed two path transforms per texel.
|
/// The extra path transform factors buffer texture, packed two path transforms per texel.
|
||||||
uniform sampler2D uPathTransformExt;
|
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;
|
attribute vec2 aPosition;
|
||||||
|
/// The path ID, starting from 1.
|
||||||
attribute float aPathID;
|
attribute float aPathID;
|
||||||
attribute float aNormalAngle;
|
|
||||||
|
|
||||||
/// The color of this path.
|
/// The color of this path.
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
|
@ -53,8 +52,7 @@ void main() {
|
||||||
uPathTransformExtDimensions,
|
uPathTransformExtDimensions,
|
||||||
pathID);
|
pathID);
|
||||||
|
|
||||||
vec2 position = dilatePosition(aPosition, aNormalAngle, uEmboldenAmount);
|
vec2 position = hintPosition(aPosition, uHints);
|
||||||
position = hintPosition(position, uHints);
|
|
||||||
position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
|
position = transformVertexPositionAffine(position, pathTransformST, pathTransformExt);
|
||||||
position = transformVertexPosition(position, uTransform);
|
position = transformVertexPosition(position, uTransform);
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,8 @@ uniform sampler2D uPathTransformExt;
|
||||||
/// The amount of faux-bold to apply, in local path units.
|
/// The amount of faux-bold to apply, in local path units.
|
||||||
uniform vec2 uEmboldenAmount;
|
uniform vec2 uEmboldenAmount;
|
||||||
|
|
||||||
/// The abstract quad position: (0.0, 0.0) to (1.0, 1.0).
|
/// The abstract position within the quad: (0.0, 0.0) to (1.0, 1.0).
|
||||||
attribute vec2 aQuadPosition;
|
attribute vec2 aTessCoord;
|
||||||
/// The position of the left endpoint.
|
/// The position of the left endpoint.
|
||||||
attribute vec2 aLeftPosition;
|
attribute vec2 aLeftPosition;
|
||||||
/// The position of the control point.
|
/// The position of the control point.
|
||||||
|
@ -82,31 +82,63 @@ void main() {
|
||||||
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
|
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
|
||||||
|
|
||||||
// Transform the points, and compute the position of this vertex.
|
// Transform the points, and compute the position of this vertex.
|
||||||
vec2 position;
|
leftPosition = computeECAAPosition(leftPosition,
|
||||||
float winding;
|
aNormalAngles.x,
|
||||||
if (computeECAAQuadPosition(position,
|
uEmboldenAmount,
|
||||||
winding,
|
uHints,
|
||||||
leftPosition,
|
pathTransformST,
|
||||||
rightPosition,
|
pathTransformExt,
|
||||||
aQuadPosition,
|
uTransform,
|
||||||
uFramebufferSize,
|
uFramebufferSize);
|
||||||
pathTransformST,
|
rightPosition = computeECAAPosition(rightPosition,
|
||||||
pathTransformExt,
|
aNormalAngles.z,
|
||||||
uTransform,
|
uEmboldenAmount,
|
||||||
uHints,
|
uHints,
|
||||||
bounds,
|
pathTransformST,
|
||||||
leftRightNormalAngles,
|
pathTransformExt,
|
||||||
uEmboldenAmount)) {
|
uTransform,
|
||||||
controlPointPosition = computeECAAPosition(controlPointPosition,
|
uFramebufferSize);
|
||||||
controlPointNormalAngle,
|
controlPointPosition = computeECAAPosition(controlPointPosition,
|
||||||
uEmboldenAmount,
|
aNormalAngles.y,
|
||||||
uHints,
|
uEmboldenAmount,
|
||||||
pathTransformST,
|
uHints,
|
||||||
pathTransformExt,
|
pathTransformST,
|
||||||
uTransform,
|
pathTransformExt,
|
||||||
uFramebufferSize);
|
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);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
|
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
gl_Position = vec4(position, depth, 1.0);
|
||||||
|
|
|
@ -46,7 +46,7 @@ uniform sampler2D uPathTransformExt;
|
||||||
uniform vec2 uEmboldenAmount;
|
uniform vec2 uEmboldenAmount;
|
||||||
|
|
||||||
/// The abstract quad position: (0.0, 0.0) to (1.0, 1.0).
|
/// 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.
|
/// The position of the left endpoint.
|
||||||
attribute vec2 aLeftPosition;
|
attribute vec2 aLeftPosition;
|
||||||
/// The position of the right endpoint.
|
/// The position of the right endpoint.
|
||||||
|
@ -75,22 +75,53 @@ void main() {
|
||||||
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
|
vec4 bounds = fetchFloat4Data(uPathBounds, pathID, uPathBoundsDimensions);
|
||||||
|
|
||||||
// Transform the points, and compute the position of this vertex.
|
// Transform the points, and compute the position of this vertex.
|
||||||
vec2 position;
|
leftPosition = computeECAAPosition(leftPosition,
|
||||||
float winding;
|
aNormalAngles.x,
|
||||||
computeECAAQuadPosition(position,
|
uEmboldenAmount,
|
||||||
winding,
|
uHints,
|
||||||
leftPosition,
|
pathTransformST,
|
||||||
rightPosition,
|
pathTransformExt,
|
||||||
aQuadPosition,
|
uTransform,
|
||||||
uFramebufferSize,
|
uFramebufferSize);
|
||||||
pathTransformST,
|
rightPosition = computeECAAPosition(rightPosition,
|
||||||
pathTransformExt,
|
aNormalAngles.y,
|
||||||
uTransform,
|
uEmboldenAmount,
|
||||||
uHints,
|
uHints,
|
||||||
bounds,
|
pathTransformST,
|
||||||
leftRightNormalAngles,
|
pathTransformExt,
|
||||||
uEmboldenAmount);
|
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);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
|
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
gl_Position = vec4(position, depth, 1.0);
|
||||||
|
|
|
@ -57,7 +57,7 @@ uniform vec2 uEmboldenAmount;
|
||||||
uniform int uPassIndex;
|
uniform int uPassIndex;
|
||||||
|
|
||||||
/// The abstract quad position: (0.0, 0.0) to (1.0, 1.0).
|
/// 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.
|
/// The position of the left endpoint.
|
||||||
attribute vec2 aLeftPosition;
|
attribute vec2 aLeftPosition;
|
||||||
/// The position of the control point.
|
/// The position of the control point.
|
||||||
|
@ -126,16 +126,33 @@ void main() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 position = computeECAAQuadPositionFromTransformedPositions(leftPosition,
|
vec2 edgeBL = bounds.xy, edgeTL = bounds.xw, edgeTR = bounds.zw, edgeBR = bounds.zy;
|
||||||
rightPosition,
|
edgeBL = transformECAAPosition(edgeBL, pathTransformST, pathTransformExt, uTransform);
|
||||||
aQuadPosition,
|
edgeBR = transformECAAPosition(edgeBR, pathTransformST, pathTransformExt, uTransform);
|
||||||
uFramebufferSize,
|
edgeTL = transformECAAPosition(edgeTL, pathTransformST, pathTransformExt, uTransform);
|
||||||
pathTransformST,
|
edgeTR = transformECAAPosition(edgeTR, pathTransformST, pathTransformExt, uTransform);
|
||||||
pathTransformExt,
|
|
||||||
uTransform,
|
|
||||||
bounds,
|
|
||||||
leftTopRightEdges);
|
|
||||||
|
|
||||||
|
// 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);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
|
|
||||||
gl_Position = vec4(position, depth, 1.0);
|
gl_Position = vec4(position, depth, 1.0);
|
||||||
|
|
|
@ -53,10 +53,13 @@ uniform sampler2D uPathColors;
|
||||||
/// If this is true, then points will be snapped to the nearest pixel.
|
/// If this is true, then points will be snapped to the nearest pixel.
|
||||||
uniform bool uMulticolor;
|
uniform bool uMulticolor;
|
||||||
|
|
||||||
attribute vec2 aQuadPosition;
|
attribute vec2 aTessCoord;
|
||||||
attribute vec4 aUpperEndpointPositions;
|
attribute vec2 aUpperLeftEndpointPosition;
|
||||||
attribute vec4 aLowerEndpointPositions;
|
attribute vec2 aUpperControlPointPosition;
|
||||||
attribute vec4 aControlPointPositions;
|
attribute vec2 aUpperRightEndpointPosition;
|
||||||
|
attribute vec2 aLowerRightEndpointPosition;
|
||||||
|
attribute vec2 aLowerControlPointPosition;
|
||||||
|
attribute vec2 aLowerLeftEndpointPosition;
|
||||||
attribute float aPathID;
|
attribute float aPathID;
|
||||||
|
|
||||||
varying vec4 vUpperEndpoints;
|
varying vec4 vUpperEndpoints;
|
||||||
|
@ -65,13 +68,13 @@ varying vec4 vControlPoints;
|
||||||
varying vec4 vColor;
|
varying vec4 vColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 tlPosition = aUpperEndpointPositions.xy;
|
vec2 tlPosition = aUpperLeftEndpointPosition;
|
||||||
vec2 tcPosition = aControlPointPositions.xy;
|
vec2 tcPosition = aUpperControlPointPosition;
|
||||||
vec2 trPosition = aUpperEndpointPositions.zw;
|
vec2 trPosition = aUpperRightEndpointPosition;
|
||||||
vec2 blPosition = aLowerEndpointPositions.xy;
|
vec2 blPosition = aLowerLeftEndpointPosition;
|
||||||
vec2 bcPosition = aControlPointPositions.zw;
|
vec2 bcPosition = aLowerControlPointPosition;
|
||||||
vec2 brPosition = aLowerEndpointPositions.zw;
|
vec2 brPosition = aLowerRightEndpointPosition;
|
||||||
vec2 quadPosition = aQuadPosition;
|
vec2 tessCoord = aTessCoord;
|
||||||
int pathID = int(floor(aPathID));
|
int pathID = int(floor(aPathID));
|
||||||
|
|
||||||
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
vec4 transformST = fetchFloat4Data(uPathTransformST, pathID, uPathTransformSTDimensions);
|
||||||
|
@ -129,19 +132,33 @@ void main() {
|
||||||
|
|
||||||
float depth = convertPathIndexToViewportDepthValue(pathID);
|
float depth = convertPathIndexToViewportDepthValue(pathID);
|
||||||
|
|
||||||
// Use the same side--in this case, the top--or else floating point error during partitioning
|
// Use the same side--in this case, the top--or else floating point error during
|
||||||
// can occasionally cause inconsistent rounding, resulting in cracks.
|
// partitioning can occasionally cause inconsistent rounding, resulting in cracks.
|
||||||
vec2 position;
|
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)
|
if (!uMulticolor) {
|
||||||
position.x = quadPosition.x < 0.5 ? tlPosition.x : trPosition.x;
|
if (tessCoord.x < 0.25)
|
||||||
else
|
position.x = floor(position.x);
|
||||||
position.x = quadPosition.x < 0.5 ? floor(tlPosition.x) : ceil(trPosition.x);
|
else if (tessCoord.x >= 0.75)
|
||||||
|
position.x = ceil(position.x);
|
||||||
if (quadPosition.y < 0.5)
|
}
|
||||||
position.y = floor(min(tlPosition.y, trPosition.y));
|
|
||||||
else
|
|
||||||
position.y = ceil(max(blPosition.y, brPosition.y));
|
|
||||||
|
|
||||||
position = convertScreenToClipSpace(position, uFramebufferSize);
|
position = convertScreenToClipSpace(position, uFramebufferSize);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue