This commit is contained in:
Tony Garnock-Jones 2023-01-10 22:04:38 +01:00
parent b82fdea3c4
commit a03269603a
4 changed files with 120 additions and 32 deletions

View File

@ -42,10 +42,13 @@ Touchable = <touchable @shape Shape> .
CSG = <csg @expr CSGExpr> . CSG = <csg @expr CSGExpr> .
CSGExpr = CSGExpr =
/ <mesh @shape Shape> / <mesh @shape Mesh>
/ <subtract @base CSGExpr @more [CSGExpr ...]> / <scale @v Vector3 @shape CSGExpr>
/ <union @shapes [CSGExpr ...]> / <move @v Vector3 @shape CSGExpr>
/ <intersect @shapes [CSGExpr ...]> / <rotate @v Vector3 @shape CSGExpr>
/ <subtract [@base CSGExpr @more CSGExpr ...]>
/ <union [@base CSGExpr @more CSGExpr ...]>
/ <intersect [@base CSGExpr @more CSGExpr ...]>
/ <invert @shape CSGExpr> / <invert @shape CSGExpr>
. .

View File

@ -66,7 +66,28 @@
<color 0.5 0.5 0.0 <color 0.5 0.5 0.0
<box>>>>>>> <box>>>>>>>
<sprite "house" <sprite "x"
<scale <v 10.0 4.0 15.0> <move <v 10.0 1.6 -5.0>
<floor <texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<move <v 1.5 0.5 -0.5> <box>>>>> <v 1.0 3.0 1.0>
<v 0.0 0.0 0.0>]
<csg
<subtract [
<move <v 0.0 0.0 0.5> <scale <v 1.1 3.1 1.1> <mesh <box>>>>
<move <v 0.0 0.0 0.5> <scale <v 1.0 3.0 1.0> <mesh <box>>>>
]>
>
>>>
<sprite "y"
<move <v 12.0 0.75 -5.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 1.0 1.0 1.0>
<v 0.0 0.0 0.0>]
<csg
<intersect [
<scale <v 0.5 1.0 0.5> <mesh <box>>>
<mesh <sphere>>
]>
>
>>>

View File

@ -17,3 +17,16 @@
<touchable <move <v 0.0 0.5 0.0> <plane>>>>> <touchable <move <v 0.0 0.5 0.0> <plane>>>>>
<scale <v 1.0 2.11 0.1> <move <v 0.0 0.5 0.6> <box>>> <scale <v 1.0 2.11 0.1> <move <v 0.0 0.5 0.6> <box>>>
]>>> ]>>>
<sprite "x"
<move <v 0.0 0.0 10.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 1.0 3.0 1.0>
<v 0.0 0.0 0.0>]
<csg
<subtract [
<move <v 0.0 0.0 0.5> <scale <v 1.1 3.1 1.1> <mesh <box>>>>
<move <v 0.0 0.0 0.5> <scale <v 1.0 3.0 1.0> <mesh <box>>>>
]>
>
>>>

View File

@ -4,6 +4,7 @@ import {
CSG, CSG,
HemisphericLight, HemisphericLight,
Material, Material,
Matrix,
Mesh, Mesh,
MeshBuilder, MeshBuilder,
Node, 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 { export function build(name: string, scene: Scene, shape: Shapes.Shape, customize: MeshCustomizer): ShapeTree {
switch (shape._variant) { switch (shape._variant) {
case "Mesh": { case "Mesh": {
const mesh = shape.value; const t = new ShapeTree<Mesh>(scene, shape, buildMesh(name, scene, shape.value));
let t: ShapeTree<Mesh>;
switch (mesh._variant) {
case "Sphere":
t = new ShapeTree<Mesh>(scene, shape, MeshBuilder.CreateSphere(name, {}, scene));
break;
case "Box":
t = new ShapeTree<Mesh>(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<Mesh>(scene, shape, MeshBuilder.CreatePlane(name, {}, scene));
break;
}
applyCustomizer(t, customize); applyCustomizer(t, customize);
return t; return t;
} }
@ -307,7 +298,10 @@ export function build(name: string, scene: Scene, shape: Shapes.Shape, customize
}); });
case "CSG": { case "CSG": {
throw new Error("unimplemented"); const t = new ShapeTree<Mesh>(
scene, shape, buildCSG(shape.value.expr).toMesh(name, null, scene));
applyCustomizer(t, customize);
return t;
} }
case "Skybox": { 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 } = { export const builder: { [key: string]: (... args: any[]) => Shapes.Shape } = {
sphere: () => Shapes.Shape.Mesh(Shapes.Mesh.Sphere(Shapes.Sphere())), sphere: () => Shapes.Shape.Mesh(Shapes.Mesh.Sphere(Shapes.Sphere())),
box: () => Shapes.Shape.Mesh(Shapes.Mesh.Box(Shapes.Box())), box: () => Shapes.Shape.Mesh(Shapes.Mesh.Box(Shapes.Box())),