diff --git a/src/drawables/shapes/circle.ts b/src/drawables/shapes/circle.ts index f38f8a3..4e713bb 100644 --- a/src/drawables/shapes/circle.ts +++ b/src/drawables/shapes/circle.ts @@ -31,7 +31,7 @@ export class Circle extends Drawable { }, uniformCountMacroName: 'CIRCLE_COUNT', shaderCombinationSteps: [0, 1, 2, 3, 8, 16], - empty: new Circle(vec2.fromValues(0, 0), 0), + empty: new Circle(vec2.create(), 0), }; constructor(public center: vec2, public radius: number) { diff --git a/src/drawables/shapes/rotated-rectangle.ts b/src/drawables/shapes/rotated-rectangle.ts new file mode 100644 index 0000000..b5cc75d --- /dev/null +++ b/src/drawables/shapes/rotated-rectangle.ts @@ -0,0 +1,78 @@ +import { mat2d, vec2 } from 'gl-matrix'; +import { Drawable } from '../drawable'; +import { DrawableDescriptor } from '../drawable-descriptor'; + +/** + * @category Drawable + */ +export class RotatedRectangle extends Drawable { + public static descriptor: DrawableDescriptor = { + sdf: { + // Source: https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm + shader: ` + uniform vec2 rotatedRectangleTopCenters[ROTATED_RECTANGLE_COUNT]; + uniform vec2 rotatedRectangleBottomCenters[ROTATED_RECTANGLE_COUNT]; + uniform float rotatedRectangleWidths[ROTATED_RECTANGLE_COUNT]; + + float rotatedRectangleMinDistance(vec2 target, out float colorIndex) { + colorIndex = 4.0; + float minDistance = 1000.0; + for (int i = 0; i < ROTATED_RECTANGLE_COUNT; i++) { + vec2 top = rotatedRectangleTopCenters[i]; + vec2 bottom = rotatedRectangleBottomCenters[i]; + float height = length(bottom - top); + vec2 d = (bottom - top) / height; + + vec2 q = (target - (top + bottom) * 0.5); + q = mat2(d.x, -d.y, d.y, d.x) * q; + q = abs(q) - vec2(height, rotatedRectangleWidths[i]) * 0.5; + float dist = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0); + minDistance = min(minDistance, dist); + } + + return minDistance; + } + `, + distanceFunctionName: 'rotatedRectangleMinDistance', + }, + propertyUniformMapping: { + topCenter: 'rotatedRectangleTopCenters', + bottomCenter: 'rotatedRectangleBottomCenters', + width: 'rotatedRectangleWidths', + }, + uniformCountMacroName: 'ROTATED_RECTANGLE_COUNT', + shaderCombinationSteps: [0, 1, 2, 3, 8, 16], + empty: new RotatedRectangle(vec2.create(), vec2.create(), 0), + }; + + constructor(public center: vec2, public size: vec2, public rotation: number) { + super(); + } + + /** + * It is just an estimate by calculating a bounding circle + * @param target + */ + public minDistance(target: vec2): number { + return vec2.distance(this.center, target) - vec2.length(this.size) / 2; + } + + protected getObjectToSerialize(transform2d: mat2d, transform1d: number): any { + const rotation = mat2d.fromRotation(mat2d.create(), this.rotation); + + const halfHeight = vec2.fromValues(0, this.size.y / 2); + vec2.transformMat2d(halfHeight, halfHeight, rotation); + + const topCenter = vec2.add(vec2.create(), this.center, halfHeight); + vec2.transformMat2d(topCenter, topCenter, transform2d); + + const bottomCenter = vec2.subtract(vec2.create(), this.center, halfHeight); + vec2.transformMat2d(bottomCenter, bottomCenter, transform2d); + + return { + topCenter, + bottomCenter, + width: this.size.x * transform1d, + }; + } +} diff --git a/src/main.ts b/src/main.ts index 556d0cf..55be0ec 100644 --- a/src/main.ts +++ b/src/main.ts @@ -69,5 +69,6 @@ export * from './drawables/lights/circle-light'; export * from './drawables/lights/flashlight'; export * from './drawables/shapes/circle'; export * from './drawables/shapes/inverted-tunnel'; +export * from './drawables/shapes/rotated-rectangle'; export * from './drawables/shapes/tunnel'; export * from './graphics/rendering/renderer/renderer';