pathfinder/demo/client/src/3d-demo.ts

185 lines
6.0 KiB
TypeScript
Raw Normal View History

2017-08-29 22:46:18 -04:00
// pathfinder/client/src/3d-demo.ts
//
// Copyright © 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.
import * as glmatrix from 'gl-matrix';
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
2017-09-01 21:11:44 -04:00
import {DemoAppController} from "./app-controller";
import {PerspectiveCamera} from "./camera";
import {mat4, vec2} from "gl-matrix";
import {PathfinderMeshData} from "./meshes";
import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import {BUILTIN_FONT_URI, TextLayout, PathfinderGlyph} from "./text";
2017-09-01 21:11:44 -04:00
import {PathfinderError, panic, unwrapNull} from "./utils";
2017-09-02 01:29:05 -04:00
import {PathfinderDemoView, Timings} from "./view";
import SSAAStrategy from "./ssaa-strategy";
const TEXT: string = "Lorem ipsum dolor sit amet";
const FONT: string = 'open-sans';
2017-08-31 22:19:26 -04:00
const PIXELS_PER_UNIT: number = 1.0;
const FOV: number = 45.0;
const NEAR_CLIP_PLANE: number = 0.01;
const FAR_CLIP_PLANE: number = 1000.0;
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
none: NoAAStrategy,
ssaa: SSAAStrategy,
};
interface AntialiasingStrategyTable {
none: typeof NoAAStrategy;
ssaa: typeof SSAAStrategy;
}
2017-09-01 21:11:44 -04:00
class ThreeDController extends DemoAppController<ThreeDView> {
2017-08-31 22:19:26 -04:00
start() {
super.start();
this.loadInitialFile();
}
protected fileLoaded(): void {
2017-08-31 22:19:26 -04:00
this.layout = new TextLayout(this.fileData, TEXT, glyph => new ThreeDGlyph(glyph));
this.layout.layoutText();
2017-09-02 01:29:05 -04:00
this.layout.glyphStorage.partition().then((meshes: PathfinderMeshData) => {
this.meshes = meshes;
this.view.then(view => {
2017-09-02 01:29:05 -04:00
view.uploadPathMetadata(this.layout.glyphStorage.textGlyphs.length);
view.attachMeshes(this.meshes);
});
});
}
2017-09-01 21:11:44 -04:00
protected createView(): ThreeDView {
return new ThreeDView(this,
unwrapNull(this.commonShaderSource),
unwrapNull(this.shaderSources));
}
protected get builtinFileURI(): string {
return BUILTIN_FONT_URI;
}
protected get defaultFile(): string {
return FONT;
}
2017-08-31 22:19:26 -04:00
layout: TextLayout<ThreeDGlyph>;
private meshes: PathfinderMeshData;
}
2017-09-02 01:29:05 -04:00
class ThreeDView extends PathfinderDemoView {
constructor(appController: ThreeDController,
commonShaderSource: string,
shaderSources: ShaderMap<ShaderProgramSource>) {
2017-09-02 01:29:05 -04:00
super(commonShaderSource, shaderSources);
this.appController = appController;
this.camera = new PerspectiveCamera(this.canvas);
this.camera.onChange = () => this.setDirty();
}
uploadPathMetadata(pathCount: number) {
2017-09-02 01:29:05 -04:00
const textGlyphs = this.appController.layout.glyphStorage.textGlyphs;
2017-08-31 22:19:26 -04:00
const pathColors = new Uint8Array(4 * (pathCount + 1));
2017-08-31 22:19:26 -04:00
const pathTransforms = new Float32Array(4 * (pathCount + 1));
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
2017-08-31 22:19:26 -04:00
const startOffset = (pathIndex + 1) * 4;
for (let channel = 0; channel < 3; channel++)
2017-08-31 22:19:26 -04:00
pathColors[startOffset + channel] = 0x00; // RGB
pathColors[startOffset + 3] = 0xff; // alpha
const textGlyph = textGlyphs[pathIndex];
const glyphRect = textGlyph.getRect(PIXELS_PER_UNIT);
pathTransforms.set([1, 1, glyphRect[0], glyphRect[1]], startOffset);
}
this.pathColorsBufferTexture.upload(this.gl, pathColors);
2017-08-31 22:19:26 -04:00
this.pathTransformBufferTexture.upload(this.gl, pathTransforms);
}
protected createAAStrategy(aaType: AntialiasingStrategyName, aaLevel: number):
AntialiasingStrategy {
if (aaType != 'ecaa')
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel);
throw new PathfinderError("Unsupported antialiasing type!");
}
protected compositeIfNecessary(): void {}
protected updateTimings(timings: Timings) {
// TODO(pcwalton)
}
get destAllocatedSize(): glmatrix.vec2 {
return glmatrix.vec2.fromValues(this.canvas.width, this.canvas.height);
}
get destFramebuffer(): WebGLFramebuffer | null {
return null;
}
get destUsedSize(): glmatrix.vec2 {
return this.destAllocatedSize;
}
protected get usedSizeFactor(): glmatrix.vec2 {
return glmatrix.vec2.fromValues(1.0, 1.0);
}
protected get worldTransform() {
const transform = glmatrix.mat4.create();
glmatrix.mat4.perspective(transform,
FOV / 180.0 * Math.PI,
this.canvas.width / this.canvas.height,
NEAR_CLIP_PLANE,
FAR_CLIP_PLANE);
glmatrix.mat4.translate(transform, transform, this.camera.translation);
glmatrix.mat4.mul(transform, transform, this.camera.rotationMatrix);
return transform;
}
private _scale: number;
private appController: ThreeDController;
camera: PerspectiveCamera;
}
2017-08-31 22:19:26 -04:00
class ThreeDGlyph extends PathfinderGlyph {
constructor(glyph: opentype.Glyph) {
super(glyph);
}
getRect(pixelsPerUnit: number): glmatrix.vec4 {
2017-08-31 22:19:26 -04:00
const rect =
glmatrix.vec4.fromValues(this.position[0],
this.position[1],
this.position[0] + this.metrics.xMax - this.metrics.xMin,
this.position[1] + this.metrics.yMax - this.metrics.yMin);
glmatrix.vec4.scale(rect, rect, pixelsPerUnit);
return rect;
}
}
function main() {
const controller = new ThreeDController;
window.addEventListener('load', () => controller.start(), false);
}
main();