Build the ribbon ourselves for great justice
This commit is contained in:
parent
ce9c15836b
commit
6fd5e65376
|
@ -120,16 +120,18 @@
|
|||
slen F
|
||||
SetPen
|
||||
Home
|
||||
"double" SetSideOrientation
|
||||
#t SetSmooth
|
||||
PenDown
|
||||
[6 CW dlen F] 240 times
|
||||
PenUp
|
||||
]>>>>
|
||||
|
||||
<sprite "tt" []
|
||||
<move <v 0.0 0.01 0.75>
|
||||
<move <v 1.0 0.01 0.75>
|
||||
<rotate <v -0.125 0.0 0.0>
|
||||
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||
<v 3.0 3.0>
|
||||
<v 2.0 1.0>
|
||||
<v 0.0 0.0>
|
||||
1.0]
|
||||
<turtle [
|
||||
|
|
115
src/turtle.ts
115
src/turtle.ts
|
@ -6,9 +6,10 @@ import {
|
|||
Ray,
|
||||
Scene,
|
||||
Vector3,
|
||||
VertexData,
|
||||
} from '@babylonjs/core/Legacy/legacy';
|
||||
|
||||
import { VM as BaseVM, Input, Primitives, Environment } from './cat.js';
|
||||
import * as Cat from './cat.js';
|
||||
|
||||
export class PenState {
|
||||
templatePath: Vector3[] = [new Vector3()];
|
||||
|
@ -47,17 +48,18 @@ export class PenState {
|
|||
|
||||
const D2R = Math.PI / 180;
|
||||
|
||||
export class TurtleVM extends BaseVM<TurtleVM> {
|
||||
export class TurtleVM extends Cat.VM<TurtleVM> {
|
||||
container: Mesh;
|
||||
meshes: Mesh[] = [];
|
||||
|
||||
counter = 0;
|
||||
sideOrientation = Mesh.BACKSIDE; // TODO: see SideOrientation primitive below
|
||||
sideOrientation = Mesh.DEFAULTSIDE;
|
||||
|
||||
pen = new PenState();
|
||||
pos = new Vector3();
|
||||
q = new Quaternion();
|
||||
prevQ = this.q;
|
||||
smooth = false;
|
||||
|
||||
get euler(): Vector3 {
|
||||
return this.q.toEulerAngles();
|
||||
|
@ -66,7 +68,7 @@ export class TurtleVM extends BaseVM<TurtleVM> {
|
|||
constructor(
|
||||
name: string,
|
||||
scene: Scene | null,
|
||||
program: Input,
|
||||
program: Cat.Input,
|
||||
) {
|
||||
super(program, TurtlePrimitives);
|
||||
this.container = new Mesh(name, scene);
|
||||
|
@ -109,16 +111,96 @@ export class TurtleVM extends BaseVM<TurtleVM> {
|
|||
throw new Error('todo');
|
||||
}
|
||||
|
||||
const m = MeshBuilder.CreateRibbon(this.container.name + this.counter++, {
|
||||
pathArray: this.pen.paths!,
|
||||
sideOrientation: this.sideOrientation,
|
||||
});
|
||||
const m = new Mesh(this.container.name + this.counter++);
|
||||
// TODO: this.sideOrientation
|
||||
|
||||
const vertexData = new VertexData();
|
||||
const positions: number[] = [];
|
||||
const indices: number[] = [];
|
||||
const normals: number[] = [];
|
||||
const uvs: number[] = [];
|
||||
|
||||
const paths = this.pen.paths!;
|
||||
const pathCount = paths.length;
|
||||
const stepCount = paths[0].length;
|
||||
|
||||
const us: number[][] = [];
|
||||
const vs: number[][] = [];
|
||||
const uTotal: number[] = [];
|
||||
const vTotal: number[] = [];
|
||||
|
||||
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
|
||||
uTotal.push(0);
|
||||
us.push([]);
|
||||
let prev = paths[pathIndex][0];
|
||||
for (let stepIndex = 0; stepIndex < stepCount; stepIndex++) {
|
||||
const curr = paths[pathIndex][stepIndex];
|
||||
uTotal[pathIndex] += curr.subtract(prev).length();
|
||||
us[pathIndex][stepIndex] = uTotal[pathIndex];
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
for (let stepIndex = 0; stepIndex < stepCount; stepIndex++) {
|
||||
vTotal.push(0);
|
||||
vs.push([]);
|
||||
let prev = paths[0][stepIndex];
|
||||
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
|
||||
const curr = paths[pathIndex][stepIndex];
|
||||
vTotal[stepIndex] += curr.subtract(prev).length();
|
||||
vs[stepIndex][pathIndex] = vTotal[stepIndex];
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
function pushPoint(pathIndex: number, stepIndex: number): number {
|
||||
const pointIndex = positions.length / 3;
|
||||
positions.push(... paths[pathIndex][stepIndex].asArray());
|
||||
uvs.push(us[pathIndex][stepIndex] / uTotal[pathIndex],
|
||||
vs[stepIndex][pathIndex] / vTotal[stepIndex]);
|
||||
return pointIndex;
|
||||
}
|
||||
|
||||
const cachedIndices: { [key: string]: number } = {};
|
||||
function cachedPoint(pathIndex: number, stepIndex: number): number {
|
||||
const v = paths[pathIndex][stepIndex].asArray().map(n => n.toFixed(3)).toString();
|
||||
if (!(v in cachedIndices)) cachedIndices[v] = pushPoint(pathIndex, stepIndex);
|
||||
return cachedIndices[v];
|
||||
}
|
||||
|
||||
const computePointIndex = this.smooth ? cachedPoint : pushPoint;
|
||||
for (let pathIndex = 1; pathIndex < pathCount; pathIndex++) {
|
||||
for (let stepIndex = 1; stepIndex < stepCount; stepIndex++) {
|
||||
indices.push(computePointIndex(pathIndex - 1, stepIndex - 1),
|
||||
computePointIndex(pathIndex - 1, stepIndex),
|
||||
computePointIndex(pathIndex, stepIndex - 1));
|
||||
|
||||
indices.push(computePointIndex(pathIndex - 1, stepIndex),
|
||||
computePointIndex(pathIndex, stepIndex),
|
||||
computePointIndex(pathIndex, stepIndex - 1));
|
||||
}
|
||||
}
|
||||
|
||||
VertexData.ComputeNormals(positions, indices, normals);
|
||||
VertexData._ComputeSides(this.sideOrientation, positions, indices, normals, uvs);
|
||||
vertexData.positions = new Float32Array(positions);
|
||||
vertexData.indices = new Int32Array(indices);
|
||||
vertexData.normals = new Float32Array(normals);
|
||||
vertexData.uvs = new Float32Array(uvs);
|
||||
|
||||
vertexData.applyToMesh(m);
|
||||
|
||||
// const m = MeshBuilder.CreateRibbon(this.container.name + this.counter++, {
|
||||
// pathArray: this.pen.paths!,
|
||||
// sideOrientation: this.sideOrientation,
|
||||
// });
|
||||
|
||||
m.parent = this.container;
|
||||
this.meshes.push(m);
|
||||
}
|
||||
}
|
||||
|
||||
export const TurtlePrimitives: Environment<TurtleVM> = Object.assign({}, Primitives, {
|
||||
export const TurtlePrimitives: Cat.Environment<TurtleVM> = Object.assign({}, Cat.Primitives, {
|
||||
'Home'() { this.pos = new Vector3(); this.resetQ(new Quaternion()); return []; },
|
||||
|
||||
'GetPos'() { return [this.pos.asArray()]; },
|
||||
|
@ -166,19 +248,18 @@ export const TurtlePrimitives: Environment<TurtleVM> = Object.assign({}, Primiti
|
|||
'PenUp'() { this.penUp(false); return []; },
|
||||
'Close'() { this.penUp(true); return []; },
|
||||
|
||||
'SideOrientation'(s) {
|
||||
// TODO: why is this back to front?? argh
|
||||
'SetSmooth'(b) { this.smooth = b as boolean; return []; },
|
||||
'SetSideOrientation'(s) {
|
||||
switch (s) {
|
||||
case "default": this.sideOrientation = Mesh.BACKSIDE; break;
|
||||
case "front": this.sideOrientation = Mesh.BACKSIDE; break;
|
||||
case "back": this.sideOrientation = Mesh.FRONTSIDE; break;
|
||||
case "default": this.sideOrientation = Mesh.DEFAULTSIDE; break;
|
||||
case "front": this.sideOrientation = Mesh.FRONTSIDE; break;
|
||||
case "back": this.sideOrientation = Mesh.BACKSIDE; break;
|
||||
case "double": this.sideOrientation = Mesh.DOUBLESIDE; break;
|
||||
default:
|
||||
break;
|
||||
default: throw new TypeError("Invalid SideOrientation: " + s);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
} satisfies Environment<TurtleVM>);
|
||||
} satisfies Cat.Environment<TurtleVM>);
|
||||
|
||||
function mitredExtrude(
|
||||
name: string,
|
||||
|
|
Loading…
Reference in New Issue