Stub support for multiple text frames

This commit is contained in:
Patrick Walton 2017-09-07 16:13:55 -07:00
parent 3ee066bdf0
commit e34ca3d3e4
7 changed files with 224 additions and 196 deletions

View File

@ -17,7 +17,8 @@ import {PerspectiveCamera} from "./camera";
import {mat4, vec2} from "gl-matrix";
import {PathfinderMeshData} from "./meshes";
import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import {BUILTIN_FONT_URI, PathfinderGlyph, TextRun, TextLayout, GlyphStorage} from "./text";
import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStorage, PathfinderGlyph} from "./text";
import {SimpleTextLayout, TextFrame, TextRun} from "./text";
import {PathfinderError, assert, panic, unwrapNull} from "./utils";
import {PathfinderDemoView, Timings} from "./view";
import SSAAStrategy from "./ssaa-strategy";
@ -114,15 +115,18 @@ class ThreeDController extends DemoAppController<ThreeDView> {
}
}
this.glyphStorage = new GlyphStorage(this.fileData, textRuns, createGlyph, font);
// TODO(pcwalton)
const textFrame = new TextFrame(textRuns, glmatrix.vec3.create());
this.glyphStorage = new GlyphStorage(this.fileData, [textFrame], createGlyph, font);
this.glyphStorage.layoutRuns();
this.glyphStorage.partition().then((baseMeshes: PathfinderMeshData) => {
this.baseMeshes = baseMeshes;
this.expandedMeshes = this.glyphStorage.expandMeshes(baseMeshes).meshes;
this.expandedMeshes = this.glyphStorage.expandMeshes(baseMeshes);
this.view.then(view => {
view.uploadPathMetadata();
view.attachMeshes(this.expandedMeshes);
view.attachMeshes(this.expandedMeshes.map(meshes => meshes.meshes));
});
});
}
@ -144,7 +148,7 @@ class ThreeDController extends DemoAppController<ThreeDView> {
glyphStorage: GlyphStorage<ThreeDGlyph>;
private baseMeshes: PathfinderMeshData;
private expandedMeshes: PathfinderMeshData;
private expandedMeshes: ExpandedMeshData[];
private textPromise: Promise<string[][]>;
}

View File

@ -43,8 +43,8 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
}
attachMeshes(view: MonochromePathfinderView) {
const bVertexPositions = new Float32Array(view.meshData.bVertexPositions);
const bVertexPathIDs = new Uint8Array(view.meshData.bVertexPathIDs);
const bVertexPositions = new Float32Array(view.meshData[0].bVertexPositions);
const bVertexPathIDs = new Uint8Array(view.meshData[0].bVertexPathIDs);
this.bVertexPositionBufferTexture.upload(view.gl, bVertexPositions);
this.bVertexPathIDBufferTexture.upload(view.gl, bVertexPathIDs);
@ -115,7 +115,7 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
view.gl.useProgram(coverProgram.program);
view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.quadPositionsBuffer);
view.gl.vertexAttribPointer(attributes.aQuadPosition, 2, view.gl.FLOAT, false, 0, 0);
view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.meshes.bQuads);
view.gl.bindBuffer(view.gl.ARRAY_BUFFER, view.meshes[0].bQuads);
view.gl.vertexAttribPointer(attributes.aUpperPointIndices,
4,
view.gl.UNSIGNED_SHORT,
@ -148,8 +148,8 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
view.vertexArrayObjectExt.bindVertexArrayOES(vaos[direction]);
const lineIndexBuffer = {
upper: view.meshes.edgeUpperLineIndices,
lower: view.meshes.edgeLowerLineIndices,
upper: view.meshes[0].edgeUpperLineIndices,
lower: view.meshes[0].edgeLowerLineIndices,
}[direction];
view.gl.useProgram(lineProgram.program);
@ -183,8 +183,8 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
view.vertexArrayObjectExt.bindVertexArrayOES(vaos[direction]);
const curveIndexBuffer = {
upper: view.meshes.edgeUpperCurveIndices,
lower: view.meshes.edgeLowerCurveIndices,
upper: view.meshes[0].edgeUpperCurveIndices,
lower: view.meshes[0].edgeLowerCurveIndices,
}[direction];
view.gl.useProgram(curveProgram.program);
@ -310,7 +310,7 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
6,
view.gl.UNSIGNED_BYTE,
0,
view.meshData.bQuadCount);
view.meshData[0].bQuadCount);
view.vertexArrayObjectExt.bindVertexArrayOES(null);
}
@ -351,8 +351,8 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
view.vertexArrayObjectExt.bindVertexArrayOES(this.lineVAOs[direction]);
view.gl.uniform1i(uniforms.uLowerPart, direction === 'lower' ? 1 : 0);
const count = {
upper: view.meshData.edgeUpperLineIndexCount,
lower: view.meshData.edgeLowerLineIndexCount,
upper: view.meshData[0].edgeUpperLineIndexCount,
lower: view.meshData[0].edgeLowerLineIndexCount,
}[direction];
view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES,
6,
@ -376,8 +376,8 @@ export abstract class ECAAStrategy extends AntialiasingStrategy {
view.vertexArrayObjectExt.bindVertexArrayOES(this.curveVAOs[direction]);
view.gl.uniform1i(uniforms.uLowerPart, direction === 'lower' ? 1 : 0);
const count = {
upper: view.meshData.edgeUpperCurveIndexCount,
lower: view.meshData.edgeLowerCurveIndexCount,
upper: view.meshData[0].edgeUpperCurveIndexCount,
lower: view.meshData[0].edgeLowerCurveIndexCount,
}[direction];
view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES,
6,

View File

@ -17,8 +17,8 @@ import {B_QUAD_UPPER_RIGHT_VERTEX_OFFSET} from "./meshes";
import {B_QUAD_UPPER_CONTROL_POINT_VERTEX_OFFSET, B_QUAD_LOWER_LEFT_VERTEX_OFFSET} from "./meshes";
import {B_QUAD_LOWER_RIGHT_VERTEX_OFFSET} from "./meshes";
import {B_QUAD_LOWER_CONTROL_POINT_VERTEX_OFFSET, PathfinderMeshData} from "./meshes";
import { BUILTIN_FONT_URI, GlyphStorage, PathfinderGlyph, TextRun } from "./text";
import { unwrapNull, UINT32_SIZE, UINT32_MAX, assert } from "./utils";
import {BUILTIN_FONT_URI, GlyphStorage, PathfinderGlyph, TextRun, TextFrame} from "./text";
import {unwrapNull, UINT32_SIZE, UINT32_MAX, assert} from "./utils";
import {PathfinderView} from "./view";
import * as opentype from "opentype.js";
@ -45,7 +45,8 @@ class MeshDebuggerAppController extends AppController {
const createGlyph = (glyph: opentype.Glyph) => new MeshDebuggerGlyph(glyph);
const textRun = new TextRun<MeshDebuggerGlyph>(CHARACTER, [0, 0], font, createGlyph);
this.glyphStorage = new GlyphStorage(this.fileData, [textRun], createGlyph, font);
const textFrame = new TextFrame([textRun], glmatrix.vec3.create());
this.glyphStorage = new GlyphStorage(this.fileData, [textFrame], createGlyph, font);
this.glyphStorage.partition().then(meshes => {
this.meshes = meshes;

View File

@ -157,7 +157,7 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
private meshesReceived() {
this.view.then(view => {
view.uploadPathMetadata(this.pathElements);
view.attachMeshes(this.meshes);
view.attachMeshes([this.meshes]);
})
}

View File

@ -23,7 +23,7 @@ import {createFramebufferDepthTexture, QUAD_ELEMENTS, setTextureParameters} from
import {UniformMap} from './gl-utils';
import {PathfinderMeshBuffers, PathfinderMeshData} from './meshes';
import {PathfinderShaderProgram, ShaderMap, ShaderProgramSource} from './shader-loader';
import {BUILTIN_FONT_URI, PathfinderGlyph, TextLayout} from "./text";
import {BUILTIN_FONT_URI, PathfinderGlyph, SimpleTextLayout} from "./text";
import {PathfinderError, assert, expectNotNull, UINT32_SIZE, unwrapNull, panic} from './utils';
import {MonochromePathfinderView, Timings} from './view';
import PathfinderBufferTexture from './buffer-texture';
@ -162,13 +162,13 @@ class TextDemoController extends DemoAppController<TextDemoView> {
}
private recreateLayout() {
this.layout = new TextLayout(this.fileData, this.text, glyph => new GlyphInstance(glyph));
this.layout = new SimpleTextLayout(this.fileData, this.text, glyph => new GlyphInstance(glyph));
this.layout.glyphStorage.partition().then((meshes: PathfinderMeshData) => {
this.meshes = meshes;
this.view.then(view => {
view.attachText();
view.uploadPathMetadata(this.layout.glyphStorage.uniqueGlyphs.length);
view.attachMeshes(this.meshes);
view.attachMeshes([this.meshes]);
});
});
}
@ -218,7 +218,7 @@ class TextDemoController extends DemoAppController<TextDemoView> {
private text: string;
layout: TextLayout<GlyphInstance>;
layout: SimpleTextLayout<GlyphInstance>;
}
class TextDemoView extends MonochromePathfinderView {

View File

@ -21,6 +21,28 @@ export const BUILTIN_FONT_URI: string = "/otf/demo";
const PARTITION_FONT_ENDPOINT_URI: string = "/partition-font";
export interface ExpandedMeshData {
meshes: PathfinderMeshData;
}
type CreateGlyphFn<Glyph> = (glyph: opentype.Glyph) => Glyph;
export interface PixelMetrics {
left: number;
right: number;
ascent: number;
descent: number;
}
opentype.Font.prototype.isSupported = function() {
return (this as any).supported;
}
opentype.Font.prototype.lineHeight = function() {
const os2Table = this.tables.os2;
return os2Table.sTypoAscender - os2Table.sTypoDescender + os2Table.sTypoLineGap;
};
export class TextRun<Glyph extends PathfinderGlyph> {
constructor(text: string | Glyph[],
origin: number[],
@ -45,81 +67,13 @@ export class TextRun<Glyph extends PathfinderGlyph> {
readonly origin: number[];
}
export interface ExpandedMeshData {
meshes: PathfinderMeshData;
}
type CreateGlyphFn<Glyph> = (glyph: opentype.Glyph) => Glyph;
export interface PixelMetrics {
left: number;
right: number;
ascent: number;
descent: number;
}
opentype.Font.prototype.isSupported = function() {
return (this as any).supported;
}
opentype.Font.prototype.lineHeight = function() {
const os2Table = this.tables.os2;
return os2Table.sTypoAscender - os2Table.sTypoDescender + os2Table.sTypoLineGap;
};
export class GlyphStorage<Glyph extends PathfinderGlyph> {
constructor(fontData: ArrayBuffer,
textRuns: TextRun<Glyph>[],
createGlyph: CreateGlyphFn<Glyph>,
font?: Font) {
if (font == null) {
font = opentype.parse(fontData);
assert(font.isSupported(), "The font type is unsupported!");
}
this.fontData = fontData;
this.textRuns = textRuns;
this.font = font;
// Determine all glyphs potentially needed.
this.uniqueGlyphs = _.flatMap(this.textRuns, textRun => textRun.glyphs);
this.uniqueGlyphs.sort((a, b) => a.index - b.index);
this.uniqueGlyphs = _.sortedUniqBy(this.uniqueGlyphs, glyph => glyph.index);
export class TextFrame<Glyph extends PathfinderGlyph> {
constructor(runs: TextRun<Glyph>[], origin: glmatrix.vec3) {
this.runs = runs;
this.origin = origin;
}
partition(): Promise<PathfinderMeshData> {
// Build the partitioning request to the server.
//
// FIXME(pcwalton): If this is a builtin font, don't resend it to the server!
const request = {
face: {
Custom: base64js.fromByteArray(new Uint8Array(this.fontData)),
},
fontIndex: 0,
glyphs: this.uniqueGlyphs.map(glyph => {
const metrics = glyph.metrics;
return {
id: glyph.index,
transform: [1, 0, 0, 1, 0, 0],
};
}),
pointSize: this.font.unitsPerEm,
};
// Make the request.
return window.fetch(PARTITION_FONT_ENDPOINT_URI, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(request),
}).then(response => response.text()).then(responseText => {
const response = JSON.parse(responseText);
if (!('Ok' in response))
panic("Failed to partition the font!");
return new PathfinderMeshData(response.Ok.pathData);
});
}
expandMeshes(meshes: PathfinderMeshData): ExpandedMeshData {
expandMeshes(uniqueGlyphs: Glyph[], meshes: PathfinderMeshData): ExpandedMeshData {
const bQuads = _.chunk(new Uint32Array(meshes.bQuads), B_QUAD_SIZE / UINT32_SIZE);
const bVertexPositions = new Float32Array(meshes.bVertexPositions);
const bVertexPathIDs = new Uint16Array(meshes.bVertexPathIDs);
@ -133,9 +87,9 @@ export class GlyphStorage<Glyph extends PathfinderGlyph> {
const expandedCoverCurveIndices: number[] = [];
let textGlyphIndex = 0;
for (const textRun of this.textRuns) {
for (const textRun of this.runs) {
for (const textGlyph of textRun.glyphs) {
const uniqueGlyphIndex = _.sortedIndexBy(this.uniqueGlyphs, textGlyph, 'index');
const uniqueGlyphIndex = _.sortedIndexBy(uniqueGlyphs, textGlyph, 'index');
if (uniqueGlyphIndex < 0)
continue;
const firstBVertexIndex = _.sortedIndex(bVertexPathIDs, uniqueGlyphIndex + 1);
@ -208,21 +162,87 @@ export class GlyphStorage<Glyph extends PathfinderGlyph> {
}
}
get allGlyphs(): Glyph[] {
return _.flatMap(this.runs, run => run.glyphs);
}
readonly runs: TextRun<Glyph>[];
readonly origin: glmatrix.vec3;
}
export class GlyphStorage<Glyph extends PathfinderGlyph> {
constructor(fontData: ArrayBuffer,
textFrames: TextFrame<Glyph>[],
createGlyph: CreateGlyphFn<Glyph>,
font?: Font) {
if (font == null) {
font = opentype.parse(fontData);
assert(font.isSupported(), "The font type is unsupported!");
}
this.fontData = fontData;
this.textFrames = textFrames;
this.font = font;
// Determine all glyphs potentially needed.
this.uniqueGlyphs = this.allGlyphs;
this.uniqueGlyphs.sort((a, b) => a.index - b.index);
this.uniqueGlyphs = _.sortedUniqBy(this.uniqueGlyphs, glyph => glyph.index);
}
expandMeshes(meshes: PathfinderMeshData): ExpandedMeshData[] {
return this.textFrames.map(textFrame => textFrame.expandMeshes(this.uniqueGlyphs, meshes));
}
partition(): Promise<PathfinderMeshData> {
// Build the partitioning request to the server.
//
// FIXME(pcwalton): If this is a builtin font, don't resend it to the server!
const request = {
face: {
Custom: base64js.fromByteArray(new Uint8Array(this.fontData)),
},
fontIndex: 0,
glyphs: this.uniqueGlyphs.map(glyph => {
const metrics = glyph.metrics;
return {
id: glyph.index,
transform: [1, 0, 0, 1, 0, 0],
};
}),
pointSize: this.font.unitsPerEm,
};
// Make the request.
return window.fetch(PARTITION_FONT_ENDPOINT_URI, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(request),
}).then(response => response.text()).then(responseText => {
const response = JSON.parse(responseText);
if (!('Ok' in response))
panic("Failed to partition the font!");
return new PathfinderMeshData(response.Ok.pathData);
});
}
layoutRuns() {
this.textRuns.forEach(textRun => textRun.layout());
for (const textFrame of this.textFrames)
textFrame.runs.forEach(textRun => textRun.layout());
}
get allGlyphs(): Glyph[] {
return _.flatMap(this.textRuns, textRun => textRun.glyphs);
return _.flatMap(this.textFrames, textRun => textRun.allGlyphs);
}
readonly fontData: ArrayBuffer;
readonly font: Font;
readonly textRuns: TextRun<Glyph>[];
readonly textFrames: TextFrame<Glyph>[];
readonly uniqueGlyphs: Glyph[];
}
export class TextLayout<Glyph extends PathfinderGlyph> {
export class SimpleTextLayout<Glyph extends PathfinderGlyph> {
constructor(fontData: ArrayBuffer, text: string, createGlyph: CreateGlyphFn<Glyph>) {
const font = opentype.parse(fontData);
assert(font.isSupported(), "The font type is unsupported!");
@ -230,22 +250,23 @@ export class TextLayout<Glyph extends PathfinderGlyph> {
const os2Table = font.tables.os2;
const lineHeight = os2Table.sTypoAscender - os2Table.sTypoDescender +
os2Table.sTypoLineGap;
this.textRuns = text.split("\n").map((line, lineNumber) => {
const textRuns: TextRun<Glyph>[] = text.split("\n").map((line, lineNumber) => {
return new TextRun<Glyph>(line, [0.0, -lineHeight * lineNumber], font, createGlyph);
});
this.textFrame = new TextFrame(textRuns, glmatrix.vec3.create());
this.glyphStorage = new GlyphStorage(fontData, this.textRuns, createGlyph, font);
this.glyphStorage = new GlyphStorage(fontData, [this.textFrame], createGlyph, font);
}
layoutRuns() {
this.textRuns.forEach(textRun => textRun.layout());
this.textFrame.runs.forEach(textRun => textRun.layout());
}
get allGlyphs(): Glyph[] {
return _.flatMap(this.textRuns, textRun => textRun.glyphs);
return this.textFrame.allGlyphs;
}
readonly textRuns: TextRun<Glyph>[];
readonly textFrame: TextFrame<Glyph>;
readonly glyphStorage: GlyphStorage<Glyph>;
}

View File

@ -124,9 +124,9 @@ export abstract class PathfinderDemoView extends PathfinderView {
this.setDirty();
}
attachMeshes(meshes: PathfinderMeshData) {
attachMeshes(meshes: PathfinderMeshData[]) {
this.meshData = meshes;
this.meshes = new PathfinderMeshBuffers(this.gl, meshes);
this.meshes = meshes.map(meshes => new PathfinderMeshBuffers(this.gl, meshes));
unwrapNull(this.antialiasingStrategy).attachMeshes(this);
this.setDirty();
@ -274,92 +274,94 @@ export abstract class PathfinderDemoView extends PathfinderView {
}
private renderDirect() {
// Set up implicit cover state.
this.gl.depthFunc(this.gl.GREATER);
this.gl.depthMask(true);
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.disable(this.gl.BLEND);
for (const meshes of this.meshes) {
// Set up implicit cover state.
this.gl.depthFunc(this.gl.GREATER);
this.gl.depthMask(true);
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.disable(this.gl.BLEND);
// Set up the implicit cover interior VAO.
const directInteriorProgram = this.shaderPrograms[this.directInteriorProgramName];
this.gl.useProgram(directInteriorProgram.program);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.meshes.bVertexPositions);
this.gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
2,
this.gl.FLOAT,
false,
0,
0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.meshes.bVertexPathIDs);
this.gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
1,
this.gl.UNSIGNED_SHORT,
false,
0,
0);
this.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
this.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.meshes.coverInteriorIndices);
// Set up the implicit cover interior VAO.
const directInteriorProgram = this.shaderPrograms[this.directInteriorProgramName];
this.gl.useProgram(directInteriorProgram.program);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, meshes.bVertexPositions);
this.gl.vertexAttribPointer(directInteriorProgram.attributes.aPosition,
2,
this.gl.FLOAT,
false,
0,
0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
this.gl.vertexAttribPointer(directInteriorProgram.attributes.aPathID,
1,
this.gl.UNSIGNED_SHORT,
false,
0,
0);
this.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPosition);
this.gl.enableVertexAttribArray(directInteriorProgram.attributes.aPathID);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, meshes.coverInteriorIndices);
// Draw direct interior parts.
this.setTransformUniform(directInteriorProgram.uniforms);
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
this.pathColorsBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 0);
this.pathTransformBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 1);
let indexCount = this.gl.getBufferParameter(this.gl.ELEMENT_ARRAY_BUFFER,
// Draw direct interior parts.
this.setTransformUniform(directInteriorProgram.uniforms);
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
this.pathColorsBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 0);
this.pathTransformBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 1);
let indexCount = this.gl.getBufferParameter(this.gl.ELEMENT_ARRAY_BUFFER,
this.gl.BUFFER_SIZE) / UINT32_SIZE;
this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_INT, 0);
// Set up direct curve state.
this.gl.depthMask(false);
this.gl.enable(this.gl.BLEND);
this.gl.blendEquation(this.gl.FUNC_ADD);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
// Set up the direct curve VAO.
const directCurveProgram = this.shaderPrograms[this.directCurveProgramName];
this.gl.useProgram(directCurveProgram.program);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, meshes.bVertexPositions);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aPosition,
2,
this.gl.FLOAT,
false,
0,
0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, meshes.bVertexPathIDs);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
1,
this.gl.UNSIGNED_SHORT,
false,
0,
0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, meshes.bVertexLoopBlinnData);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord,
2,
this.gl.UNSIGNED_BYTE,
false,
B_LOOP_BLINN_DATA_SIZE,
B_LOOP_BLINN_DATA_TEX_COORD_OFFSET);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aSign,
1,
this.gl.BYTE,
false,
B_LOOP_BLINN_DATA_SIZE,
B_LOOP_BLINN_DATA_SIGN_OFFSET);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, meshes.coverCurveIndices);
// Draw direct curve parts.
this.setTransformUniform(directCurveProgram.uniforms);
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
this.pathColorsBufferTexture.bind(this.gl, directCurveProgram.uniforms, 0);
this.pathTransformBufferTexture.bind(this.gl, directCurveProgram.uniforms, 1);
indexCount = this.gl.getBufferParameter(this.gl.ELEMENT_ARRAY_BUFFER,
this.gl.BUFFER_SIZE) / UINT32_SIZE;
this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_INT, 0);
// Set up direct curve state.
this.gl.depthMask(false);
this.gl.enable(this.gl.BLEND);
this.gl.blendEquation(this.gl.FUNC_ADD);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
// Set up the direct curve VAO.
const directCurveProgram = this.shaderPrograms[this.directCurveProgramName];
this.gl.useProgram(directCurveProgram.program);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.meshes.bVertexPositions);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aPosition,
2,
this.gl.FLOAT,
false,
0,
0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.meshes.bVertexPathIDs);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aPathID,
1,
this.gl.UNSIGNED_SHORT,
false,
0,
0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.meshes.bVertexLoopBlinnData);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aTexCoord,
2,
this.gl.UNSIGNED_BYTE,
false,
B_LOOP_BLINN_DATA_SIZE,
B_LOOP_BLINN_DATA_TEX_COORD_OFFSET);
this.gl.vertexAttribPointer(directCurveProgram.attributes.aSign,
1,
this.gl.BYTE,
false,
B_LOOP_BLINN_DATA_SIZE,
B_LOOP_BLINN_DATA_SIGN_OFFSET);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aPosition);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aTexCoord);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aPathID);
this.gl.enableVertexAttribArray(directCurveProgram.attributes.aSign);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.meshes.coverCurveIndices);
// Draw direct curve parts.
this.setTransformUniform(directCurveProgram.uniforms);
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
this.pathColorsBufferTexture.bind(this.gl, directCurveProgram.uniforms, 0);
this.pathTransformBufferTexture.bind(this.gl, directCurveProgram.uniforms, 1);
indexCount = this.gl.getBufferParameter(this.gl.ELEMENT_ARRAY_BUFFER,
this.gl.BUFFER_SIZE) / UINT32_SIZE;
this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_INT, 0);
this.gl.drawElements(this.gl.TRIANGLES, indexCount, this.gl.UNSIGNED_INT, 0);
}
}
private finishTiming() {
@ -449,8 +451,8 @@ export abstract class PathfinderDemoView extends PathfinderView {
quadTexCoordsBuffer: WebGLBuffer;
quadElementsBuffer: WebGLBuffer;
meshes: PathfinderMeshBuffers;
meshData: PathfinderMeshData;
meshes: PathfinderMeshBuffers[];
meshData: PathfinderMeshData[];
pathTransformBufferTexture: PathfinderBufferTexture;
protected pathColorsBufferTexture: PathfinderBufferTexture;