Get the SVG demo rendering something

This commit is contained in:
Patrick Walton 2017-08-29 12:29:16 -07:00
parent 8e2172f06f
commit c47aa5c4d0
6 changed files with 71 additions and 43 deletions

View File

@ -14,47 +14,48 @@ import {PathfinderView} from './view';
export type AntialiasingStrategyName = 'none' | 'ssaa' | 'ecaa';
export interface AntialiasingStrategy {
export abstract class AntialiasingStrategy {
// Prepares any OpenGL data. This is only called on startup and canvas resize.
init(view: PathfinderView): void;
init(view: PathfinderView): void {
this.setFramebufferSize(view);
}
// Uploads any mesh data. This is called whenever a new set of meshes is supplied.
attachMeshes(view: PathfinderView): void;
abstract attachMeshes(view: PathfinderView): void;
// This is called whenever the framebuffer has changed.
setFramebufferSize(view: PathfinderView, framebufferSize: glmatrix.vec2): void;
abstract setFramebufferSize(view: PathfinderView): void;
// Returns the transformation matrix that should be applied when directly rendering.
transform(): glmatrix.mat4;
abstract get transform(): glmatrix.mat4;
// Called before direct rendering.
//
// Typically, this redirects direct rendering to a framebuffer of some sort.
prepare(view: PathfinderView): void;
abstract prepare(view: PathfinderView): void;
// Called after direct rendering.
//
// This usually performs the actual antialiasing and blits to the real framebuffer.
resolve(view: PathfinderView): void;
abstract resolve(view: PathfinderView): void;
// True if direct rendering should occur.
shouldRenderDirect: boolean;
}
export class NoAAStrategy implements AntialiasingStrategy {
export class NoAAStrategy extends AntialiasingStrategy {
constructor(level: number) {
super();
this.framebufferSize = glmatrix.vec2.create();
}
init(view: PathfinderView) {}
attachMeshes(view: PathfinderView) {}
setFramebufferSize(view: PathfinderView, framebufferSize: glmatrix.vec2) {
this.framebufferSize = framebufferSize;
setFramebufferSize(view: PathfinderView) {
this.framebufferSize = view.destAllocatedSize;
}
transform(): glmatrix.mat4 {
get transform(): glmatrix.mat4 {
return glmatrix.mat4.create();
}

View File

@ -25,12 +25,14 @@ interface UpperAndLower<T> {
lower: T;
}
export abstract class ECAAStrategy implements AntialiasingStrategy {
export abstract class ECAAStrategy extends AntialiasingStrategy {
constructor(level: number) {
super();
this.framebufferSize = glmatrix.vec2.create();
}
init(view: MonochromePathfinderView) {
super.init(view);
this.bVertexPositionBufferTexture = new PathfinderBufferTexture(view.gl,
'uBVertexPosition');
this.bVertexPathIDBufferTexture = new PathfinderBufferTexture(view.gl, 'uBVertexPathID');
@ -49,8 +51,8 @@ export abstract class ECAAStrategy implements AntialiasingStrategy {
this.createResolveVAO(view);
}
setFramebufferSize(view: MonochromePathfinderView, framebufferSize: glmatrix.vec2) {
this.framebufferSize = framebufferSize;
setFramebufferSize(view: MonochromePathfinderView) {
this.framebufferSize = view.destAllocatedSize;
this.initDirectFramebuffer(view);
this.initEdgeDetectFramebuffer(view);
@ -58,7 +60,7 @@ export abstract class ECAAStrategy implements AntialiasingStrategy {
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null);
}
transform(): glmatrix.mat4 {
get transform(): glmatrix.mat4 {
return glmatrix.mat4.create();
}
@ -288,7 +290,7 @@ export abstract class ECAAStrategy implements AntialiasingStrategy {
view.setFramebufferSizeUniform(uniforms);
this.bVertexPositionBufferTexture.bind(view.gl, uniforms, 0);
this.bVertexPathIDBufferTexture.bind(view.gl, uniforms, 1);
view.atlasTransformBuffer.bind(view.gl, uniforms, 2);
view.pathTransformBufferTexture.bind(view.gl, uniforms, 2);
view.instancedArraysExt.drawElementsInstancedANGLE(view.gl.TRIANGLES,
6,
view.gl.UNSIGNED_BYTE,
@ -315,7 +317,7 @@ export abstract class ECAAStrategy implements AntialiasingStrategy {
view.setFramebufferSizeUniform(uniforms);
this.bVertexPositionBufferTexture.bind(view.gl, uniforms, 0);
this.bVertexPathIDBufferTexture.bind(view.gl, uniforms, 1);
view.atlasTransformBuffer.bind(view.gl, uniforms, 2);
view.pathTransformBufferTexture.bind(view.gl, uniforms, 2);
}
private antialiasLines(view: MonochromePathfinderView) {

View File

@ -15,23 +15,22 @@ import {createFramebufferDepthTexture, createFramebuffer, setTextureParameters}
import {unwrapNull} from './utils';
import {PathfinderView} from './view';
export default class SSAAStrategy implements AntialiasingStrategy {
export default class SSAAStrategy extends AntialiasingStrategy {
constructor(level: number) {
super();
this.level = level;
this.destFramebufferSize = glmatrix.vec2.create();
this.supersampledFramebufferSize = glmatrix.vec2.create();
}
init(view: PathfinderView) {}
attachMeshes(view: PathfinderView) {}
setFramebufferSize(view: PathfinderView, framebufferSize: glmatrix.vec2) {
this.destFramebufferSize = framebufferSize;
setFramebufferSize(view: PathfinderView) {
this.destFramebufferSize = view.destAllocatedSize;
this.supersampledFramebufferSize = glmatrix.vec2.create();
glmatrix.vec2.mul(this.supersampledFramebufferSize,
framebufferSize,
this.destFramebufferSize,
this.supersampleScale);
this.supersampledColorTexture = unwrapNull(view.gl.createTexture());
@ -59,7 +58,7 @@ export default class SSAAStrategy implements AntialiasingStrategy {
view.gl.bindFramebuffer(view.gl.FRAMEBUFFER, null);
}
transform(): glmatrix.mat4 {
get transform(): glmatrix.mat4 {
const scale = glmatrix.vec2.create();
glmatrix.vec2.div(scale, this.supersampledFramebufferSize, this.destFramebufferSize);

View File

@ -143,7 +143,10 @@ class SVGDemoView extends PathfinderView {
this._scale = 1.0;
}
protected resized(initialSize: boolean) {}
protected resized(initialSize: boolean) {
this.antialiasingStrategy.init(this);
this.setDirty();
}
get destAllocatedSize(): glmatrix.vec2 {
return glmatrix.vec2.fromValues(this.canvas.width, this.canvas.height);
@ -157,17 +160,29 @@ class SVGDemoView extends PathfinderView {
return this.destAllocatedSize;
}
protected panned(): void {}
protected panned(): void {
this.setDirty();
}
uploadPathData(elements: SVGPathElement[]) {
const pathColors = new Uint8Array(4 * (elements.length + 1));
const pathTransforms = new Float32Array(4 * (elements.length + 1));
for (let pathIndex = 0; pathIndex < elements.length; pathIndex++) {
const startOffset = (pathIndex + 1) * 4;
// Set color.
const style = window.getComputedStyle(elements[pathIndex]);
const fillColor = style.fill === 'none' ? [0, 0, 0, 0] : parseColor(style.fill).rgba;
pathColors.set(fillColor, (pathIndex + 1) * 4);
const fillColor: number[] =
style.fill === 'none' ? [0, 0, 0, 0] : parseColor(style.fill).rgba;
pathColors.set(fillColor.slice(0, 3), startOffset);
pathColors[startOffset + 3] = fillColor[3] * 255;
// TODO(pcwalton): Set transform.
pathTransforms.set([1, 1, 0, 0], startOffset);
}
this.pathColorsBufferTexture.upload(this.gl, pathColors);
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
}
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
@ -182,7 +197,7 @@ class SVGDemoView extends PathfinderView {
}
protected get usedSizeFactor(): glmatrix.vec2 {
return glmatrix.vec2.create();
return glmatrix.vec2.fromValues(1.0, 1.0);
}
protected get scale(): number {
@ -194,6 +209,13 @@ class SVGDemoView extends PathfinderView {
this.setDirty();
}
protected get worldTransform() {
const transform = glmatrix.mat4.create();
glmatrix.mat4.fromTranslation(transform, [this.translation[0], this.translation[1], 0]);
glmatrix.mat4.scale(transform, transform, [this.scale, this.scale, 1.0]);
return transform;
}
private _scale: number;
private appController: SVGDemoController;

View File

@ -380,7 +380,7 @@ class TextDemoView extends MonochromePathfinderView {
transforms[pathID * 4 + 3] = atlasLocation[1] - bottom;
}
this.atlasTransformBuffer.upload(this.gl, transforms);
this.pathTransformBufferTexture.upload(this.gl, transforms);
}
private createAtlasFramebuffer() {
@ -392,7 +392,7 @@ class TextDemoView extends MonochromePathfinderView {
this.atlasDepthTexture);
// Allow the antialiasing strategy to set up framebuffers as necessary.
this.antialiasingStrategy.setFramebufferSize(this, ATLAS_SIZE);
this.antialiasingStrategy.setFramebufferSize(this);
}
private setGlyphTexCoords() {
@ -551,6 +551,10 @@ class TextDemoView extends MonochromePathfinderView {
this.appController.updateTimings(timings);
}
protected get worldTransform() {
return glmatrix.mat4.create();
}
atlasFramebuffer: WebGLFramebuffer;
atlasDepthTexture: WebGLTexture;
@ -560,8 +564,6 @@ class TextDemoView extends MonochromePathfinderView {
glyphTexCoordsBuffer: WebGLBuffer;
glyphElementsBuffer: WebGLBuffer;
atlasTransformBuffer: PathfinderBufferTexture;
appController: TextDemoController;
}

View File

@ -60,7 +60,7 @@ export abstract class PathfinderView {
const shaderSource = this.compileShaders(commonShaderSource, shaderSources);
this.shaderPrograms = this.linkShaders(shaderSource);
this.atlasTransformBuffer = new PathfinderBufferTexture(this.gl, 'uPathTransform');
this.pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform');
this.pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
this.antialiasingStrategy = new NoAAStrategy(0);
@ -77,7 +77,6 @@ export abstract class PathfinderView {
let canvas = this.canvas;
this.antialiasingStrategy.init(this);
this.antialiasingStrategy.setFramebufferSize(this, this.destAllocatedSize);
if (this.meshData != null)
this.antialiasingStrategy.attachMeshes(this);
@ -233,14 +232,15 @@ export abstract class PathfinderView {
// Draw the glyphs with the resolved atlas to the default framebuffer.
this.compositeIfNecessary();
// Finish timing, clear dirty bit and finish.
// Finish timing, clear dirty bit, and finish.
this.finishTiming();
this.dirty = false;
}
private setTransformUniform(uniforms: UniformMap) {
const transform = this.antialiasingStrategy.transform();
this.gl.uniformMatrix4fv(uniforms.uTransform, false, this.antialiasingStrategy.transform());
const transform = glmatrix.mat4.create();
glmatrix.mat4.mul(transform, this.worldTransform, this.antialiasingStrategy.transform);
this.gl.uniformMatrix4fv(uniforms.uTransform, false, transform);
}
private renderDirect() {
@ -275,7 +275,7 @@ export abstract class PathfinderView {
this.setTransformUniform(directInteriorProgram.uniforms);
this.setFramebufferSizeUniform(directInteriorProgram.uniforms);
this.pathColorsBufferTexture.bind(this.gl, directInteriorProgram.uniforms, 0);
this.atlasTransformBuffer.bind(this.gl, directInteriorProgram.uniforms, 1);
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);
@ -326,7 +326,7 @@ export abstract class PathfinderView {
this.setTransformUniform(directCurveProgram.uniforms);
this.setFramebufferSizeUniform(directCurveProgram.uniforms);
this.pathColorsBufferTexture.bind(this.gl, directCurveProgram.uniforms, 0);
this.atlasTransformBuffer.bind(this.gl, directCurveProgram.uniforms, 1);
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);
@ -437,6 +437,8 @@ export abstract class PathfinderView {
protected abstract get scale(): number;
protected abstract set scale(newScale: number);
protected abstract get worldTransform(): glmatrix.mat4;
protected antialiasingStrategy: AntialiasingStrategy;
protected translation: glmatrix.vec2;
@ -461,7 +463,7 @@ export abstract class PathfinderView {
meshes: PathfinderMeshBuffers;
meshData: PathfinderMeshData;
atlasTransformBuffer: PathfinderBufferTexture;
pathTransformBufferTexture: PathfinderBufferTexture;
protected pathColorsBufferTexture: PathfinderBufferTexture;
private atlasRenderingTimerQuery: WebGLQuery;