sdf-2d/src/graphics/rendering/uniforms-provider.ts
2020-10-18 15:42:38 +02:00

98 lines
3.2 KiB
TypeScript

import { mat2d, vec2, vec3 } from 'gl-matrix';
import { UniversalRenderingContext } from '../graphics-library/universal-rendering-context';
/** @internal */
export class UniformsProvider {
public ambientLight!: vec3;
public textures: { [textureName: string]: number } = {};
private scaleWorldLengthToNDC = 1;
private transformWorldToNDC = mat2d.create();
private viewAreaBottomLeft = vec2.create();
private worldAreaInView = vec2.create();
private squareToAspectRatio = vec2.create();
private uvToWorld = mat2d.create();
public constructor(private readonly gl: UniversalRenderingContext) {}
public getUniforms(uniforms: any): any {
return {
...uniforms,
...this.textures,
ambientLight: this.ambientLight,
uvToWorld: this.uvToWorld,
worldAreaInView: this.worldAreaInView,
squareToAspectRatio: this.squareToAspectRatio,
squareToAspectRatioTimes2: vec2.scale(vec2.create(), this.squareToAspectRatio, 2),
scaleWorldLengthToNDC: this.scaleWorldLengthToNDC,
transformWorldToNDC: this.transformWorldToNDC,
};
}
public getViewArea(): vec2 {
return this.worldAreaInView;
}
public setViewArea(topLeft: vec2, size: vec2) {
this.worldAreaInView = size;
// world coordinates
this.viewAreaBottomLeft = vec2.add(
vec2.create(),
topLeft,
vec2.fromValues(0, -size.y)
);
const scaleLongerEdgeTo1 =
1 / Math.max(this.worldAreaInView.x, this.worldAreaInView.y);
this.squareToAspectRatio = vec2.fromValues(
this.worldAreaInView.x * scaleLongerEdgeTo1,
this.worldAreaInView.y * scaleLongerEdgeTo1
);
this.scaleWorldLengthToNDC = scaleLongerEdgeTo1 * 2;
mat2d.fromScaling(
this.transformWorldToNDC,
vec2.fromValues(this.scaleWorldLengthToNDC, this.scaleWorldLengthToNDC)
);
mat2d.translate(
this.transformWorldToNDC,
this.transformWorldToNDC,
vec2.fromValues(
-this.viewAreaBottomLeft.x - 0.5 * this.worldAreaInView.x,
-this.viewAreaBottomLeft.y - 0.5 * this.worldAreaInView.y
)
);
this.uvToWorld = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft);
mat2d.scale(this.uvToWorld, this.uvToWorld, this.worldAreaInView);
}
public screenToWorldPosition(screenPosition: vec2): vec2 {
const transform = this.calculateScreenToWorldTransformation();
return vec2.transformMat2d(vec2.create(), screenPosition, transform);
}
public worldToDisplayCoordinates(worldCoordinates: vec2): vec2 {
const transform = this.calculateScreenToWorldTransformation();
mat2d.invert(transform, transform);
return vec2.transformMat2d(vec2.create(), worldCoordinates, transform);
}
private calculateScreenToWorldTransformation(): mat2d {
const { width, height } = (this.gl
.canvas as HTMLCanvasElement).getBoundingClientRect();
const resolution = vec2.fromValues(width, height);
const transform = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft);
mat2d.scale(
transform,
transform,
vec2.divide(vec2.create(), this.worldAreaInView, resolution)
);
mat2d.translate(transform, transform, vec2.fromValues(0.5, height - 0.5));
return mat2d.scale(transform, transform, vec2.fromValues(1, -1));
}
}