diff --git a/demo/client/src/app-controller.ts b/demo/client/src/app-controller.ts new file mode 100644 index 00000000..665f2b13 --- /dev/null +++ b/demo/client/src/app-controller.ts @@ -0,0 +1,33 @@ +// pathfinder/client/src/app-controller.ts +// +// Copyright © 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +import {ShaderLoader, ShaderMap, ShaderProgramSource} from './shader-loader'; + +export default abstract class AppController { + constructor() {} + + start() { + const canvas = document.getElementById('pf-canvas') as HTMLCanvasElement; + + const shaderLoader = new ShaderLoader; + shaderLoader.load(); + + this.view = Promise.all([shaderLoader.common, shaderLoader.shaders]).then(allShaders => { + return this.createView(canvas, allShaders[0], allShaders[1]); + }); + } + + protected abstract createView(canvas: HTMLCanvasElement, + commonShaderSource: string, + shaderSources: ShaderMap): + View; + + view: Promise; +} diff --git a/demo/client/src/shader-loader.ts b/demo/client/src/shader-loader.ts new file mode 100644 index 00000000..3d28e159 --- /dev/null +++ b/demo/client/src/shader-loader.ts @@ -0,0 +1,109 @@ +// pathfinder/client/src/shader-loader.ts +// +// Copyright © 2017 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl'; + +export const SHADER_NAMES: Array> = [ + 'blit', + 'directCurve', + 'directInterior', + 'ecaaEdgeDetect', + 'ecaaCover', + 'ecaaLine', + 'ecaaCurve', + 'ecaaMonoResolve', + 'ecaaMultiResolve', +]; + +const SHADER_URLS: ShaderMap = { + blit: { + vertex: "/glsl/gles2/blit.vs.glsl", + fragment: "/glsl/gles2/blit.fs.glsl", + }, + directCurve: { + vertex: "/glsl/gles2/direct-curve.vs.glsl", + fragment: "/glsl/gles2/direct-curve.fs.glsl", + }, + directInterior: { + vertex: "/glsl/gles2/direct-interior.vs.glsl", + fragment: "/glsl/gles2/direct-interior.fs.glsl", + }, + ecaaEdgeDetect: { + vertex: "/glsl/gles2/ecaa-edge-detect.vs.glsl", + fragment: "/glsl/gles2/ecaa-edge-detect.fs.glsl", + }, + ecaaCover: { + vertex: "/glsl/gles2/ecaa-cover.vs.glsl", + fragment: "/glsl/gles2/ecaa-cover.fs.glsl", + }, + ecaaLine: { + vertex: "/glsl/gles2/ecaa-line.vs.glsl", + fragment: "/glsl/gles2/ecaa-line.fs.glsl", + }, + ecaaCurve: { + vertex: "/glsl/gles2/ecaa-curve.vs.glsl", + fragment: "/glsl/gles2/ecaa-curve.fs.glsl", + }, + ecaaMonoResolve: { + vertex: "/glsl/gles2/ecaa-mono-resolve.vs.glsl", + fragment: "/glsl/gles2/ecaa-mono-resolve.fs.glsl", + }, + ecaaMultiResolve: { + vertex: "/glsl/gles2/ecaa-multi-resolve.vs.glsl", + fragment: "/glsl/gles2/ecaa-multi-resolve.fs.glsl", + }, +}; + +export interface ShaderMap { + blit: T; + directCurve: T; + directInterior: T; + ecaaEdgeDetect: T; + ecaaCover: T; + ecaaLine: T; + ecaaCurve: T; + ecaaMonoResolve: T; + ecaaMultiResolve: T; +} + +export interface ShaderProgramSource { + vertex: string; + fragment: string; +} + +interface ShaderProgramURLs { + vertex: string; + fragment: string; +} + +export class ShaderLoader { + load() { + this.common = window.fetch(COMMON_SHADER_URL).then(response => response.text()); + + const shaderKeys = Object.keys(SHADER_URLS) as Array>; + let promises = []; + for (const shaderKey of shaderKeys) { + promises.push(Promise.all([ + window.fetch(SHADER_URLS[shaderKey].vertex).then(response => response.text()), + window.fetch(SHADER_URLS[shaderKey].fragment).then(response => response.text()), + ]).then(results => { return { vertex: results[0], fragment: results[1] } })); + } + + this.shaders = Promise.all(promises).then(promises => { + let shaderMap: Partial> = {}; + for (let keyIndex = 0; keyIndex < shaderKeys.length; keyIndex++) + shaderMap[shaderKeys[keyIndex]] = promises[keyIndex]; + return shaderMap as ShaderMap; + }); + } + + common: Promise; + shaders: Promise>; +} diff --git a/demo/client/src/text.ts b/demo/client/src/text.ts index e668e3a2..b0c606b5 100644 --- a/demo/client/src/text.ts +++ b/demo/client/src/text.ts @@ -13,6 +13,9 @@ import * as base64js from 'base64-js'; import * as glmatrix from 'gl-matrix'; import * as opentype from 'opentype.js'; +import AppController from './app-controller'; +import {SHADER_NAMES, ShaderMap, ShaderProgramSource} from './shader-loader'; + const TEXT: string = `’Twas brillig, and the slithy toves Did gyre and gimble in the wabe; @@ -57,8 +60,6 @@ const TIME_INTERVAL_DELAY: number = 32; const PARTITION_FONT_ENDPOINT_URL: string = "/partition-font"; -const COMMON_SHADER_URL: string = '/glsl/gles2/common.inc.glsl'; - const UINT32_SIZE: number = 4; const B_POSITION_SIZE: number = 8; @@ -75,45 +76,6 @@ const B_QUAD_LOWER_INDICES_OFFSET: number = 4 * 4; const ATLAS_SIZE: glmatrix.vec2 = glmatrix.vec2.fromValues(3072, 3072); -const SHADER_URLS: ShaderMap = { - blit: { - vertex: "/glsl/gles2/blit.vs.glsl", - fragment: "/glsl/gles2/blit.fs.glsl", - }, - directCurve: { - vertex: "/glsl/gles2/direct-curve.vs.glsl", - fragment: "/glsl/gles2/direct-curve.fs.glsl", - }, - directInterior: { - vertex: "/glsl/gles2/direct-interior.vs.glsl", - fragment: "/glsl/gles2/direct-interior.fs.glsl", - }, - ecaaEdgeDetect: { - vertex: "/glsl/gles2/ecaa-edge-detect.vs.glsl", - fragment: "/glsl/gles2/ecaa-edge-detect.fs.glsl", - }, - ecaaCover: { - vertex: "/glsl/gles2/ecaa-cover.vs.glsl", - fragment: "/glsl/gles2/ecaa-cover.fs.glsl", - }, - ecaaLine: { - vertex: "/glsl/gles2/ecaa-line.vs.glsl", - fragment: "/glsl/gles2/ecaa-line.fs.glsl", - }, - ecaaCurve: { - vertex: "/glsl/gles2/ecaa-curve.vs.glsl", - fragment: "/glsl/gles2/ecaa-curve.fs.glsl", - }, - ecaaMonoResolve: { - vertex: "/glsl/gles2/ecaa-mono-resolve.vs.glsl", - fragment: "/glsl/gles2/ecaa-mono-resolve.fs.glsl", - }, - ecaaMultiResolve: { - vertex: "/glsl/gles2/ecaa-multi-resolve.vs.glsl", - fragment: "/glsl/gles2/ecaa-multi-resolve.fs.glsl", - }, -}; - interface UnlinkedShaderProgram { vertex: WebGLShader; fragment: WebGLShader; @@ -130,28 +92,6 @@ interface Point2D { type Size2D = glmatrix.vec2; -interface ShaderProgramSource { - vertex: string; - fragment: string; -} - -interface ShaderProgramURLs { - vertex: string; - fragment: string; -} - -interface ShaderMap { - blit: T; - directCurve: T; - directInterior: T; - ecaaEdgeDetect: T; - ecaaCover: T; - ecaaLine: T; - ecaaCurve: T; - ecaaMonoResolve: T; - ecaaMultiResolve: T; -} - interface UniformMap { [uniformName: string]: WebGLUniformLocation; } @@ -443,23 +383,20 @@ class PathfinderMeshBuffers implements Meshes { readonly edgeLowerCurveIndices: WebGLBuffer; } -class AppController { +class TextDemoController extends AppController { constructor() { + super(); this._atlas = new Atlas; } start() { + super.start(); + this.fontSize = INITIAL_FONT_SIZE; this.fpsLabel = unwrapNull(document.getElementById('pf-fps-label')); const canvas = document.getElementById('pf-canvas') as HTMLCanvasElement; - const shaderLoader = new PathfinderShaderLoader; - shaderLoader.load(); - this.view = Promise.all([shaderLoader.common, shaderLoader.shaders]).then(allShaders => { - return new PathfinderView(this, canvas, allShaders[0], allShaders[1]); - }); - this.loadFontButton = document.getElementById('pf-load-font-button') as HTMLInputElement; this.loadFontButton.addEventListener('change', () => this.loadFont(), false); @@ -468,6 +405,12 @@ class AppController { this.updateAALevel(); } + protected createView(canvas: HTMLCanvasElement, + commonShaderSource: string, + shaderSources: ShaderMap) { + return new PathfinderView(this, canvas, commonShaderSource, shaderSources); + } + private loadFont() { const file = expectNotNull(this.loadFontButton.files, "No file selected!")[0]; const reader = new FileReader; @@ -552,7 +495,6 @@ class AppController { return this._atlas; } - private view: Promise; private loadFontButton: HTMLInputElement; private aaLevelSelect: HTMLSelectElement; private fpsLabel: HTMLElement; @@ -572,33 +514,8 @@ class AppController { fontSize: number; } -class PathfinderShaderLoader { - load() { - this.common = window.fetch(COMMON_SHADER_URL).then(response => response.text()); - - const shaderKeys = Object.keys(SHADER_URLS) as Array>; - let promises = []; - for (const shaderKey of shaderKeys) { - promises.push(Promise.all([ - window.fetch(SHADER_URLS[shaderKey].vertex).then(response => response.text()), - window.fetch(SHADER_URLS[shaderKey].fragment).then(response => response.text()), - ]).then(results => { return { vertex: results[0], fragment: results[1] } })); - } - - this.shaders = Promise.all(promises).then(promises => { - let shaderMap: Partial> = {}; - for (let keyIndex = 0; keyIndex < shaderKeys.length; keyIndex++) - shaderMap[shaderKeys[keyIndex]] = promises[keyIndex]; - return shaderMap as ShaderMap; - }); - } - - common: Promise; - shaders: Promise>; -} - class PathfinderView { - constructor(appController: AppController, + constructor(appController: TextDemoController, canvas: HTMLCanvasElement, commonShaderSource: string, shaderSources: ShaderMap) { @@ -669,9 +586,8 @@ class PathfinderView { private compileShaders(commonSource: string, shaderSources: ShaderMap): ShaderMap { let shaders: Partial>> = {}; - const shaderKeys = Object.keys(SHADER_URLS) as Array>; - for (const shaderKey of shaderKeys) { + for (const shaderKey of SHADER_NAMES) { for (const typeName of ['vertex', 'fragment'] as Array) { const type = { vertex: this.gl.VERTEX_SHADER, @@ -1263,7 +1179,7 @@ class PathfinderView { atlasTransformBuffer: PathfinderBufferTexture; - appController: AppController; + appController: TextDemoController; private dirty: boolean; } @@ -2250,7 +2166,7 @@ const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = { }; function main() { - const controller = new AppController; + const controller = new TextDemoController; window.addEventListener('load', () => controller.start(), false); }