98 lines
3.2 KiB
TypeScript
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));
|
|
}
|
|
}
|