This commit is contained in:
Tony Garnock-Jones 2023-02-14 09:27:25 +01:00
parent a12209cdec
commit 90d57ccc58
3 changed files with 115 additions and 45 deletions

View File

@ -105,45 +105,52 @@
; ]>
; >>>>>
; <sprite "tt" []
; <move <v 0.0 1.6 0.0>
; <turtle [
; 1 to slen
; 0.025 to dlen
; 90 U
; dlen 10 * F
; PenDown
; 90 L
; [12 L dlen 2 * F] 30 times
; 90 R
; slen F
; SetPen
; Home
; PenDown
; [6 CW dlen F] 240 times
; PenUp
; ]>>>
<sprite "tt2" []
<move <v 0.0 1.6 3.0>
<color 0.5 0.0 1.0
<turtle [
1 to slen
0.025 to dlen
90 U
dlen 10 * F
PenDown
90 L
[12 L dlen 2 * F] 30 times
90 R
slen F
SetPen
Home
PenDown
[6 CW dlen F] 240 times
PenUp
]>>>>
<sprite "tt" []
<move <v 0.0 0.01 0.75>
<turtle [
1.0 to wallHeight
0.1 to wallDepth
<rotate <v -0.125 0.0 0.0>
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
<v 3.0 3.0>
<v 0.0 0.0>
1.0]
<turtle [
1.0 to wallHeight
0.1 to wallDepth
90 U
PenDown
[wallHeight F 90 L wallDepth F 90 L] 2 times
SetPen
Home
90 U
PenDown
[wallHeight F 90 L wallDepth F 90 L] 2 times
SetPen
Home
[ 10 to k k / [dup F] k times drop ] to ff
[ 1.414 1 1 PenScale ] to big
[ 1 1 1 PenScale ] to normal
[ 1 to k k / [dup F] k times drop ] to ff
[ 2 / dup R big 0 F R normal 0 F ] to rr
1 CornerDivisions
1 1 1 PenScale
PenDown
1 ff 90 R 1 ff 90 R 1 ff 90 R 1 ff 90 R
PenUp
]>>>
PenDown
1 ff 90 rr 1 ff 90 rr 1 ff 90 rr 1 ff 90 rr
PenUp
]>>>>>
; <Exit "y" "lobby">
; <sprite "y" []

View File

@ -265,7 +265,10 @@ export function buildMesh(
const t = new TurtleVM(name, scene, meshSpec.value.program.map(fromJS));
t.debug = true;
t.exec();
return { rootnode: t.container };
return {
rootnode: t.container,
subnodes: Promise.resolve(t.meshes),
};
}
}
}

View File

@ -1,7 +1,9 @@
import {
Mesh,
MeshBuilder,
Plane,
Quaternion,
Ray,
Scene,
Vector3,
} from '@babylonjs/core/Legacy/legacy';
@ -47,13 +49,15 @@ const D2R = Math.PI / 180;
export class TurtleVM extends BaseVM<TurtleVM> {
container: Mesh;
meshes: Mesh[] = [];
counter = 0;
sideOrientation = Mesh.BACKSIDE; // TODO: see SideOrientation primitive below
pen = new PenState();
pos = new Vector3();
q = new Quaternion();
cornerDivisions = 0;
prevQ = this.q;
get euler(): Vector3 {
return this.q.toEulerAngles();
@ -76,12 +80,11 @@ export class TurtleVM extends BaseVM<TurtleVM> {
}
setQ(newQ: Quaternion) {
if (this.cornerDivisions === 0) {
this.q = newQ;
} else {
this.q = newQ;
this.pen.push(this.pos, this.q);
}
this.q = newQ;
}
resetQ(newQ: Quaternion) {
this.q = this.prevQ = newQ;
}
rotate(y: number, x: number, z: number) {
@ -111,11 +114,12 @@ export class TurtleVM extends BaseVM<TurtleVM> {
sideOrientation: this.sideOrientation,
});
m.parent = this.container;
this.meshes.push(m);
}
}
export const TurtlePrimitives: Environment<TurtleVM> = Object.assign({}, Primitives, {
'Home'() { this.pos = new Vector3(); this.q = new Quaternion(); return []; },
'Home'() { this.pos = new Vector3(); this.resetQ(new Quaternion()); return []; },
'GetPos'() { return [this.pos.asArray()]; },
'GetX'() { return [this.pos.x]; },
@ -137,7 +141,7 @@ export const TurtlePrimitives: Environment<TurtleVM> = Object.assign({}, Primiti
'SetRY'(v) { this.q.y = v as number * D2R; return []; },
'SetRZ'(v) { this.q.z = v as number * D2R; return []; },
'SetHeading'(x, y, z) {
this.q = Quaternion.FromEulerAngles(x as number * D2R, y as number * D2R, z as number * D2R);
this.resetQ(Quaternion.FromEulerAngles(x as number * D2R, y as number * D2R, z as number * D2R));
return [];
},
@ -178,6 +182,62 @@ export const TurtlePrimitives: Environment<TurtleVM> = Object.assign({}, Primiti
}
return [];
},
'CornerDivisions'(n) { this.cornerDivisions = n as number; return []; },
} satisfies Environment<TurtleVM>);
function mitredExtrude(
name: string,
options: { shape: Vector3[], path: Vector3[], close?: boolean },
scene: Scene,
): Mesh {
const shape = options.shape;
const path = options.path;
const closed = options.close ?? false;
function miterNormal(v1: Vector3, v2: Vector3): Vector3 {
return Vector3.Cross(Vector3.Cross(v2, v1), v2.subtract(v1));
}
var allPaths = [];
for (var s = 0; s < shape.length; s++) {
let axisZ = path[1].subtract(path[0]).normalize();
const axisX = Vector3.Cross(scene.activeCamera!.position, axisZ).normalize();
const axisY = Vector3.Cross(axisZ, axisX);
let startPoint = path[0].add(axisX.scale(shape[s].x)).add(axisY.scale(shape[s].y));
const ribbonPath = [startPoint];
for (var p = 0; p < path.length - 2; p++) {
const nextAxisZ = path[p + 2].subtract(path[p + 1]).normalize();
startPoint = startPoint.add(axisZ.scale(new Ray(startPoint, axisZ).intersectsPlane(Plane.FromPositionAndNormal(path[p + 1], miterNormal(axisZ, nextAxisZ)))!));
ribbonPath.push(startPoint);
axisZ = nextAxisZ;
}
// Last Point
if (closed) {
let nextAxisZ = path[0].subtract(path[path.length - 1]).normalize();
startPoint = startPoint.add(axisZ.scale(new Ray(startPoint, axisZ).intersectsPlane(Plane.FromPositionAndNormal(path[path.length - 1], miterNormal(axisZ, nextAxisZ)))!));
ribbonPath.push(startPoint);
axisZ = nextAxisZ;
nextAxisZ = path[1].subtract(path[0]).normalize();
startPoint = startPoint.add(axisZ.scale(new Ray(startPoint, axisZ).intersectsPlane(Plane.FromPositionAndNormal(path[0], miterNormal(axisZ, nextAxisZ)))!));
ribbonPath.shift();
ribbonPath.unshift(startPoint);
} else {
startPoint = startPoint.add(axisZ.scale(new Ray(startPoint, axisZ).intersectsPlane(Plane.FromPositionAndNormal(path[path.length - 1], axisZ))!));
ribbonPath.push(startPoint);
}
allPaths.push(ribbonPath);
}
return MeshBuilder.CreateRibbon(name, {
pathArray: allPaths,
sideOrientation: Mesh.DOUBLESIDE,
closeArray: true,
closePath: closed,
}, scene);
}