From a03269603a4641257877fd72185fef7700a77e73 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 10 Jan 2023 22:04:38 +0100 Subject: [PATCH] CSG --- protocols/schemas/shapes.prs | 11 ++-- scene/lobby.pr | 29 +++++++++-- scene/other.pr | 13 +++++ src/shapes.ts | 99 +++++++++++++++++++++++++++--------- 4 files changed, 120 insertions(+), 32 deletions(-) diff --git a/protocols/schemas/shapes.prs b/protocols/schemas/shapes.prs index 25eec13..65c0460 100644 --- a/protocols/schemas/shapes.prs +++ b/protocols/schemas/shapes.prs @@ -42,10 +42,13 @@ Touchable = . CSG = . CSGExpr = -/ -/ -/ -/ +/ +/ +/ +/ +/ +/ +/ / . diff --git a/scene/lobby.pr b/scene/lobby.pr index f871f4f..95961cb 100644 --- a/scene/lobby.pr +++ b/scene/lobby.pr @@ -66,7 +66,28 @@ >>>>>> - - >>>> + + + ] + >>> + >>> + ]> + > + >>> + + + + ] + >> + > + ]> + > + >>> diff --git a/scene/other.pr b/scene/other.pr index d62339b..06b5332 100644 --- a/scene/other.pr +++ b/scene/other.pr @@ -17,3 +17,16 @@ >>>> >> ]>>> + + + + ] + >>> + >>> + ]> + > + >>> diff --git a/src/shapes.ts b/src/shapes.ts index 79430af..a449b34 100644 --- a/src/shapes.ts +++ b/src/shapes.ts @@ -4,6 +4,7 @@ import { CSG, HemisphericLight, Material, + Matrix, Mesh, MeshBuilder, Node, @@ -177,32 +178,22 @@ function releaseTexture(entry: CachedTexture) { } } +export function buildMesh(name: string, scene: Scene | null, meshSpec: Shapes.Mesh): Mesh { + switch (meshSpec._variant) { + case "Sphere": return MeshBuilder.CreateSphere(name, {}, scene); + case "Box": return MeshBuilder.CreateBox(name, {}, scene); + case "Ground": { + const v = v2(meshSpec.value.size); + return MeshBuilder.CreateGround(name, { width: v.x, height: v.y }, scene ?? void 0); + } + case "Plane": return MeshBuilder.CreatePlane(name, {}, scene); + } +} + export function build(name: string, scene: Scene, shape: Shapes.Shape, customize: MeshCustomizer): ShapeTree { switch (shape._variant) { case "Mesh": { - const mesh = shape.value; - let t: ShapeTree; - switch (mesh._variant) { - case "Sphere": - t = new ShapeTree(scene, shape, MeshBuilder.CreateSphere(name, {}, scene)); - break; - case "Box": - t = new ShapeTree(scene, shape, MeshBuilder.CreateBox(name, {}, scene)); - break; - - case "Ground": { - const v = v2(mesh.value.size); - t = new ShapeTree( - scene, - shape, - MeshBuilder.CreateGround(name, { width: v.x, height: v.y }, scene)); - break; - } - - case "Plane": - t = new ShapeTree(scene, shape, MeshBuilder.CreatePlane(name, {}, scene)); - break; - } + const t = new ShapeTree(scene, shape, buildMesh(name, scene, shape.value)); applyCustomizer(t, customize); return t; } @@ -307,7 +298,10 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize }); case "CSG": { - throw new Error("unimplemented"); + const t = new ShapeTree( + scene, shape, buildCSG(shape.value.expr).toMesh(name, null, scene)); + applyCustomizer(t, customize); + return t; } case "Skybox": { @@ -331,6 +325,63 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize } } +function emptyCSG(): CSG { + const c = new CSG(); + c.matrix = Matrix.Identity(); + c.position = Vector3.Zero(); + c.rotation = Vector3.Zero(); + c.scaling = Vector3.Zero(); + c.rotationQuaternion = null; + return c; +} + +export function buildCSG(expr: Shapes.CSGExpr): CSG { + function walk(expr: Shapes.CSGExpr, matrix: Matrix): CSG { + switch (expr._variant) { + case "mesh": { + const mesh = buildMesh("", null, expr.shape); + mesh.freezeWorldMatrix(matrix, true); + mesh.unfreezeWorldMatrix(); + const c = CSG.FromMesh(mesh); + mesh.dispose(); + return c; + } + case "scale": + return walk(expr.shape, matrix.multiply( + Matrix.Scaling(expr.v.x, expr.v.y, expr.v.z))); + case "move": + return walk(expr.shape, matrix.multiply( + Matrix.Translation(expr.v.x, expr.v.y, expr.v.z))); + case "rotate": + return walk(expr.shape, matrix.multiply( + Matrix.RotationYawPitchRoll(expr.v.y * 2 * Math.PI, + expr.v.x * 2 * Math.PI, + expr.v.z * 2 * Math.PI))); + case "subtract": { + let c = walk(expr.base, matrix); + expr.more.forEach(d => c.subtractInPlace(walk(d, matrix))); + return c; + } + case "union": { + let c = walk(expr.base, matrix); + expr.more.forEach(d => c.unionInPlace(walk(d, matrix))); + return c; + } + case "intersect": { + let c = walk(expr.base, matrix); + expr.more.forEach(d => c.intersectInPlace(walk(d, matrix))); + return c; + } + case "invert": { + let c = walk(expr.shape, matrix); + c.inverseInPlace(); + return c; + } + } + } + return walk(expr, Matrix.Identity()); +} + export const builder: { [key: string]: (... args: any[]) => Shapes.Shape } = { sphere: () => Shapes.Shape.Mesh(Shapes.Mesh.Sphere(Shapes.Sphere())), box: () => Shapes.Shape.Mesh(Shapes.Mesh.Box(Shapes.Box())),