diff --git a/src/graphics/rendering/renderer/context-aware-renderer.ts b/src/graphics/rendering/renderer/context-aware-renderer.ts index 80d17d5..accde78 100644 --- a/src/graphics/rendering/renderer/context-aware-renderer.ts +++ b/src/graphics/rendering/renderer/context-aware-renderer.ts @@ -143,6 +143,13 @@ export class ContextAwareRenderer implements Renderer { ); } + public worldToDisplayCoordinates(worldCoordinates: vec2): vec2 { + return this.handle( + () => this.renderer.worldToDisplayCoordinates(worldCoordinates), + vec2.create() + ); + } + public renderDrawables(): void { return this.handle(() => this.renderer.renderDrawables(), undefined); } diff --git a/src/graphics/rendering/renderer/renderer-implementation.ts b/src/graphics/rendering/renderer/renderer-implementation.ts index f21e8a0..425a9dc 100644 --- a/src/graphics/rendering/renderer/renderer-implementation.ts +++ b/src/graphics/rendering/renderer/renderer-implementation.ts @@ -242,6 +242,10 @@ export class RendererImplementation implements Renderer { return this.uniformsProvider.screenToWorldPosition(displayCoordinates); } + public worldToDisplayCoordinates(worldCoordinates: vec2): vec2 { + return this.uniformsProvider.worldToDisplayCoordinates(worldCoordinates); + } + public setViewArea(topLeft: vec2, size: vec2) { this.uniformsProvider.setViewArea(topLeft, size); } diff --git a/src/graphics/rendering/renderer/renderer.ts b/src/graphics/rendering/renderer/renderer.ts index 9c54685..b038238 100644 --- a/src/graphics/rendering/renderer/renderer.ts +++ b/src/graphics/rendering/renderer/renderer.ts @@ -30,7 +30,8 @@ export interface Renderer { setViewArea(topLeft: vec2, size: vec2): void; /** - * Return the world coordinates from a pixel's position. + * The inverse of `worldToDisplayCoordinates`, returns the world coordinates + * from a pixel's position. * * The view area coordinates are also given in world coordinates. * @@ -41,6 +42,17 @@ export interface Renderer { */ displayToWorldCoordinates(displayCoordinates: vec2): vec2; + /** + * The inverse of `displayToWorldCoordinates`, returns the screen space position + * of a point given in world space cooridnates. + * + * While the origin for worldCoordinates resides in the bottom-left corner, + * the origin of the returned display coordinates is placed in the top left. + * + * @param worldCoordinates Coordinates used when drawing objects. + */ + worldToDisplayCoordinates(worldCoordinates: vec2): vec2; + /** * Patch the current runtime settings with new values. * @param overrides diff --git a/src/graphics/rendering/uniforms-provider.ts b/src/graphics/rendering/uniforms-provider.ts index c85b308..62e4044 100644 --- a/src/graphics/rendering/uniforms-provider.ts +++ b/src/graphics/rendering/uniforms-provider.ts @@ -71,21 +71,28 @@ export class UniformsProvider { } 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 position = vec2.fromValues(screenPosition.x, height - screenPosition.y); 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, 0.5)); - - return vec2.transformMat2d(vec2.create(), position, transform); + mat2d.translate(transform, transform, vec2.fromValues(0.5, height - 0.5)); + return mat2d.scale(transform, transform, vec2.fromValues(1, -1)); } }