@drawcall/charta 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/grass/index.d.ts.map +1 -1
- package/dist/grass/index.js +12 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/interpreter.d.ts +6 -4
- package/dist/interpreter.d.ts.map +1 -1
- package/dist/interpreter.js +32 -12
- package/dist/locations.d.ts.map +1 -1
- package/dist/locations.js +4 -6
- package/dist/pillars/index.d.ts.map +1 -1
- package/dist/pillars/index.js +28 -27
- package/dist/place/index.d.ts.map +1 -1
- package/dist/place/index.js +22 -20
- package/dist/schemas.d.ts +18 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/tiles/geometry.d.ts +14 -9
- package/dist/tiles/geometry.d.ts.map +1 -1
- package/dist/tiles/geometry.js +3 -10
- package/dist/tiles/index.d.ts +4 -2
- package/dist/tiles/index.d.ts.map +1 -1
- package/dist/tiles/index.js +15 -2
- package/dist/utils/bvh.d.ts +11 -0
- package/dist/utils/bvh.d.ts.map +1 -0
- package/dist/utils/bvh.js +20 -0
- package/dist/utils/instanced-mesh-group.d.ts.map +1 -1
- package/dist/utils/instanced-mesh-group.js +6 -0
- package/dist/walls/index.d.ts.map +1 -1
- package/dist/walls/index.js +16 -9
- package/dist/water/index.d.ts +8 -5
- package/dist/water/index.d.ts.map +1 -1
- package/dist/water/index.js +16 -11
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grass/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACb,QAAQ,EAMT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAO9E,MAAM,MAAM,YAAY,GAAG,oBAAoB,GAAG;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,qBAAa,SAAU,SAAQ,aAAa;gBAExC,WAAW,EAAE,WAAW,EACxB,QAAQ,GAAE,QAAkC,EAC5C,IAAI,GAAE,YAAiB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grass/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,aAAa,EACb,QAAQ,EAMT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAO9E,MAAM,MAAM,YAAY,GAAG,oBAAoB,GAAG;IAChD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,qBAAa,SAAU,SAAQ,aAAa;gBAExC,WAAW,EAAE,WAAW,EACxB,QAAQ,GAAE,QAAkC,EAC5C,IAAI,GAAE,YAAiB;CAyP1B"}
|
package/dist/grass/index.js
CHANGED
|
@@ -15,7 +15,7 @@ export class GrassMesh extends InstancedMesh {
|
|
|
15
15
|
for (let row = 0; row < rows; row++) {
|
|
16
16
|
for (let col = 0; col < cols; col++) {
|
|
17
17
|
// getCalls validates the schema and reports errors
|
|
18
|
-
interpreter.getCalls(
|
|
18
|
+
interpreter.getCalls({ row, col }, { grass: grassSchema });
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
return;
|
|
@@ -31,7 +31,7 @@ export class GrassMesh extends InstancedMesh {
|
|
|
31
31
|
for (let row = 0; row < rows; row++) {
|
|
32
32
|
for (let col = 0; col < cols; col++) {
|
|
33
33
|
const grassParsed = interpreter
|
|
34
|
-
.getCalls(
|
|
34
|
+
.getCalls({ row, col }, { grass: grassSchema })
|
|
35
35
|
.at(-1)?.[1];
|
|
36
36
|
if (!grassParsed)
|
|
37
37
|
continue;
|
|
@@ -42,7 +42,7 @@ export class GrassMesh extends InstancedMesh {
|
|
|
42
42
|
const step = cellSize / subN;
|
|
43
43
|
const jitterAmp = step * 0.35;
|
|
44
44
|
// top surface stack index = total number of ground/ceiling - 1
|
|
45
|
-
const topStackIndex = Math.max(0, interpreter.countCalls(
|
|
45
|
+
const topStackIndex = Math.max(0, interpreter.countCalls({ row, col }, (c) => c.name === "ground" || c.name === "ceiling") - 1);
|
|
46
46
|
perCell[row][col] = {
|
|
47
47
|
subN,
|
|
48
48
|
jitterAmp,
|
|
@@ -101,8 +101,7 @@ export class GrassMesh extends InstancedMesh {
|
|
|
101
101
|
const nb = neighbors;
|
|
102
102
|
const step = cellSize / subN;
|
|
103
103
|
// Cell center
|
|
104
|
-
const cx
|
|
105
|
-
const cz = (row - rows / 2 + 0.5) * cellSize;
|
|
104
|
+
const { x: cx, z: cz } = interpreter.gridToWorld({ row, col });
|
|
106
105
|
for (let gz = 0; gz < subN; gz++) {
|
|
107
106
|
for (let gx = 0; gx < subN; gx++) {
|
|
108
107
|
// Optimization: Check stochastic rejection early using simplified fade check
|
|
@@ -144,16 +143,16 @@ export class GrassMesh extends InstancedMesh {
|
|
|
144
143
|
if (Math.random() >= f)
|
|
145
144
|
continue;
|
|
146
145
|
// --- Instance is accepted ---
|
|
147
|
-
// Position
|
|
148
|
-
const
|
|
149
|
-
const
|
|
146
|
+
// Position (offset from cell center)
|
|
147
|
+
const offsetX = -cellSize * 0.5 + (gx + 0.5) * step;
|
|
148
|
+
const offsetZ = -cellSize * 0.5 + (gz + 0.5) * step;
|
|
150
149
|
const jx = (Math.random() * 2 - 1) * jitterAmp;
|
|
151
150
|
const jz = (Math.random() * 2 - 1) * jitterAmp;
|
|
152
|
-
const px = cx +
|
|
153
|
-
const pz = cz +
|
|
151
|
+
const px = cx + offsetX + jx;
|
|
152
|
+
const pz = cz + offsetZ + jz;
|
|
154
153
|
let baseY = 0;
|
|
155
154
|
if (tilesGeometry) {
|
|
156
|
-
baseY = tilesGeometry.
|
|
155
|
+
baseY = tilesGeometry.getHeightAt({ row, col, offsetX: offsetX + jx, offsetZ: offsetZ + jz }, { stackIndex: topStackIndex });
|
|
157
156
|
}
|
|
158
157
|
tmpPos.set(px, baseY, pz);
|
|
159
158
|
// Scale
|
|
@@ -182,5 +181,7 @@ export class GrassMesh extends InstancedMesh {
|
|
|
182
181
|
this.instanceMatrix.needsUpdate = true;
|
|
183
182
|
if (this.instanceColor)
|
|
184
183
|
this.instanceColor.needsUpdate = true;
|
|
184
|
+
// Disable raycasting entirely for grass (no-op)
|
|
185
|
+
this.raycast = () => { };
|
|
185
186
|
}
|
|
186
187
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,6 @@ export * from "./pillars/index.js";
|
|
|
10
10
|
export * from "./water/index.js";
|
|
11
11
|
export * from "./locations.js";
|
|
12
12
|
export * from "./utils/instanced-mesh-group.js";
|
|
13
|
+
export * from "./utils/bvh.js";
|
|
13
14
|
export * from "./assets/loader.js";
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iCAAiC,CAAA;AAC/C,cAAc,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/interpreter.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { output, ZodObject } from 'zod';
|
|
2
2
|
import { Call } from './parser.js';
|
|
3
3
|
import { ChartaError, ErrorLocation } from './errors.js';
|
|
4
|
-
import { cellSizeSchema } from './schemas.js';
|
|
4
|
+
import { cellSizeSchema, GridCoord, WorldCoord } from './schemas.js';
|
|
5
|
+
export type { GridCoord, WorldCoord };
|
|
5
6
|
export { cellSizeSchema as cellSizeFunctionParams };
|
|
6
7
|
export type InterpreterOptions = {
|
|
7
8
|
throwOnError?: boolean;
|
|
@@ -19,13 +20,14 @@ export declare class Interpreter {
|
|
|
19
20
|
private readonly sourceLines;
|
|
20
21
|
getSource(): string;
|
|
21
22
|
getLineTextForRow(row: number): string;
|
|
22
|
-
|
|
23
|
+
gridToWorld(coord: GridCoord): WorldCoord;
|
|
24
|
+
worldToGrid(coord: WorldCoord): GridCoord;
|
|
23
25
|
getRows(): number;
|
|
24
26
|
getCols(): number;
|
|
25
|
-
countCalls(
|
|
27
|
+
countCalls(coord: GridCoord | undefined, filter: string | ((call: Call) => boolean), startAt?: number, endAtExcl?: number): number;
|
|
26
28
|
getCalls<T extends {
|
|
27
29
|
[Key in string]: ZodObject<any>;
|
|
28
|
-
}>(
|
|
30
|
+
}>(coord: GridCoord | undefined, callSchemas: T): Array<{
|
|
29
31
|
[Key in keyof T]: [Key, output<T[Key]>, number, {
|
|
30
32
|
line: number;
|
|
31
33
|
column: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../src/interpreter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAa,MAAM,KAAK,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../src/interpreter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAa,MAAM,KAAK,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEpE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,CAAA;AAErC,OAAO,EAAE,cAAc,IAAI,sBAAsB,EAAE,CAAA;AAEnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,qBAAa,WAAW;IAKpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAS;gBAGV,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,YAAK,EAChC,MAAM,EAAE,MAAM,EAC/B,OAAO,GAAE,kBAAuB;IAelC,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAOrC,SAAS,IAAI,WAAW,EAAE;IAI1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IAEtC,SAAS,IAAI,MAAM;IAInB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAMtC,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU;IAUzC,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS;IAsBzC,OAAO,IAAI,MAAM;IAKjB,OAAO,IAAI,MAAM;IAKjB,UAAU,CACR,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,EAC1C,OAAO,GAAE,MAAU,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM;IAgBT,QAAQ,CAAC,CAAC,SAAS;SAAG,GAAG,IAAI,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC;KAAE,EACpD,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,WAAW,EAAE,CAAC,GACb,KAAK,CACN;SACG,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KACpG,CAAC,MAAM,CAAC,CAAC,CACX;IA0GD,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,uBAAuB;IAa/B,gBAAgB,CAAC,CAAC,EAAE,WAAW,EAAE;QAAE,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;KAAE,EAAE,IAAI,GAAE,MAAyB,GAAG,CAAC,GAAG,SAAS;IAWlH,QAAQ,CAAC,CAAC,EACR,WAAW,EAAE;QAAE,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;KAAE,EAC7C,IAAI,GAAE,MAAyB,EAC/B,GAAG,CAAC,EAAE,aAAa,GAClB,CAAC,GAAG,SAAS;IAmBhB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAIxC,WAAW,IAAI,MAAM;CAStB"}
|
package/dist/interpreter.js
CHANGED
|
@@ -40,11 +40,31 @@ export class Interpreter {
|
|
|
40
40
|
const lineNumber = row + 2;
|
|
41
41
|
return this.sourceLines[lineNumber - 1] ?? '';
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
gridToWorld(coord) {
|
|
44
44
|
const cellSize = this.getCellSize();
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
return
|
|
45
|
+
const cx = (coord.col - this.getCols() / 2 + 0.5) * cellSize;
|
|
46
|
+
const cz = (coord.row - this.getRows() / 2 + 0.5) * cellSize;
|
|
47
|
+
return {
|
|
48
|
+
x: cx + (coord.offsetX ?? 0),
|
|
49
|
+
z: cz + (coord.offsetZ ?? 0),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
worldToGrid(coord) {
|
|
53
|
+
const cellSize = this.getCellSize();
|
|
54
|
+
const cols = this.getCols();
|
|
55
|
+
const rows = this.getRows();
|
|
56
|
+
const rawCol = coord.x / cellSize + cols / 2 - 0.5;
|
|
57
|
+
const rawRow = coord.z / cellSize + rows / 2 - 0.5;
|
|
58
|
+
const col = Math.floor(rawCol);
|
|
59
|
+
const row = Math.floor(rawRow);
|
|
60
|
+
const cellCenterX = (col - cols / 2 + 0.5) * cellSize;
|
|
61
|
+
const cellCenterZ = (row - rows / 2 + 0.5) * cellSize;
|
|
62
|
+
return {
|
|
63
|
+
row,
|
|
64
|
+
col,
|
|
65
|
+
offsetX: coord.x - cellCenterX,
|
|
66
|
+
offsetZ: coord.z - cellCenterZ,
|
|
67
|
+
};
|
|
48
68
|
}
|
|
49
69
|
getRows() {
|
|
50
70
|
// Exclude meta row
|
|
@@ -54,9 +74,9 @@ export class Interpreter {
|
|
|
54
74
|
// Use first grid row, if present
|
|
55
75
|
return this.ast.length > 1 ? this.ast[1].length : 0;
|
|
56
76
|
}
|
|
57
|
-
countCalls(
|
|
77
|
+
countCalls(coord, filter, startAt = 0, endAtExcl) {
|
|
58
78
|
let sum = 0;
|
|
59
|
-
const calls =
|
|
79
|
+
const calls = coord == null ? this.ast[0][0] : this.ast[coord.row + 1][coord.col];
|
|
60
80
|
const length = Math.min(endAtExcl ?? Infinity, calls.length);
|
|
61
81
|
for (let i = startAt; i < length; i++) {
|
|
62
82
|
if (typeof filter === 'string' && calls[i].name != filter) {
|
|
@@ -69,28 +89,28 @@ export class Interpreter {
|
|
|
69
89
|
}
|
|
70
90
|
return sum;
|
|
71
91
|
}
|
|
72
|
-
getCalls(
|
|
92
|
+
getCalls(coord, callSchemas) {
|
|
73
93
|
let calls;
|
|
74
94
|
const normalizedSource = this.normalizedSource;
|
|
75
95
|
const sourceLines = this.sourceLines;
|
|
76
96
|
let lineNumber = 1;
|
|
77
97
|
let lineText = sourceLines[0] ?? '';
|
|
78
98
|
let callStartColumns = [];
|
|
79
|
-
if (
|
|
99
|
+
if (coord == null) {
|
|
80
100
|
calls = this.ast[0][0];
|
|
81
101
|
callStartColumns = this.computeCallStartColumns(lineText);
|
|
82
102
|
}
|
|
83
103
|
else {
|
|
84
|
-
const row =
|
|
85
|
-
const col =
|
|
104
|
+
const row = coord.row + 1;
|
|
105
|
+
const col = coord.col;
|
|
86
106
|
if (row >= this.ast.length || col >= this.ast[row].length) {
|
|
87
|
-
const lineNumber =
|
|
107
|
+
const lineNumber = coord.row + 2;
|
|
88
108
|
const lineText = sourceLines[lineNumber - 1] ?? '';
|
|
89
109
|
this.reportError(new ChartaError(`index ${col}/${row} cannot be used to index the ast (${this.ast.length}/${this.ast[Math.min(1, this.ast.length - 1)].length})`, normalizedSource, { line: lineNumber, column: 1, lineText }));
|
|
90
110
|
return []; // Return empty if index invalid
|
|
91
111
|
}
|
|
92
112
|
calls = this.ast[row][col];
|
|
93
|
-
lineNumber =
|
|
113
|
+
lineNumber = coord.row + 2;
|
|
94
114
|
lineText = sourceLines[lineNumber - 1] ?? '';
|
|
95
115
|
const [cellStart, cellEnd] = this.getCellBounds(lineText, col);
|
|
96
116
|
const cellText = lineText.slice(cellStart, cellEnd);
|
package/dist/locations.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locations.d.ts","sourceRoot":"","sources":["../src/locations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB,qBAAa,SAAS;IACpB,SAAgB,cAAc,uBAA6B;gBAE/C,WAAW,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"locations.d.ts","sourceRoot":"","sources":["../src/locations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAG9C,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB,qBAAa,SAAS;IACpB,SAAgB,cAAc,uBAA6B;gBAE/C,WAAW,EAAE,WAAW;IA8BpC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO;CAOzD"}
|
package/dist/locations.js
CHANGED
|
@@ -12,7 +12,7 @@ export class Locations {
|
|
|
12
12
|
const isLayer = (c) => c.name === 'ground' || c.name === 'ceiling';
|
|
13
13
|
for (let row = 0; row < rows; row++) {
|
|
14
14
|
for (let col = 0; col < cols; col++) {
|
|
15
|
-
const entries = interpreter.getCalls(
|
|
15
|
+
const entries = interpreter.getCalls({ row, col }, { location: locationSchema });
|
|
16
16
|
for (const [, parsed, callIdx, loc] of entries) {
|
|
17
17
|
const name = parsed.name;
|
|
18
18
|
if (this.worldPositions.has(name)) {
|
|
@@ -21,12 +21,10 @@ export class Locations {
|
|
|
21
21
|
}
|
|
22
22
|
const offsetX = parsed.offsetX ?? 0;
|
|
23
23
|
const offsetZ = parsed.offsetZ ?? 0;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const z = cz + offsetZ;
|
|
27
|
-
const layersBefore = interpreter.countCalls([row, col], isLayer, 0, callIdx);
|
|
24
|
+
const { x, z } = interpreter.gridToWorld({ row, col, offsetX, offsetZ });
|
|
25
|
+
const layersBefore = interpreter.countCalls({ row, col }, isLayer, 0, callIdx);
|
|
28
26
|
const stackIndex = layersBefore > 0 ? layersBefore - 1 : 0;
|
|
29
|
-
const y = tilesGeometry?.
|
|
27
|
+
const y = tilesGeometry?.getHeightAt({ row, col, offsetX, offsetZ }, { stackIndex }) ?? 0;
|
|
30
28
|
this.worldPositions.set(name, new Vector3(x, y, z));
|
|
31
29
|
}
|
|
32
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pillars/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEb,QAAQ,EAMT,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pillars/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEb,QAAQ,EAMT,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAQ/C,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,YAAY,CAAA;AAYhF,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,qBAAa,UAAW,SAAQ,aAAa;gBAC/B,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAkC,EAAE,OAAO,GAAE,iBAAsB;CA+LpH"}
|
package/dist/pillars/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { buildTextureArrayFromAssets } from '../utils/texture.js';
|
|
|
4
4
|
import { buildPillarMeshMaterial } from './material.js';
|
|
5
5
|
import { ChartaError } from '../errors.js';
|
|
6
6
|
import { pillarSchema } from '../schemas.js';
|
|
7
|
+
import { setupBVH, acceleratedRaycast } from '../utils/bvh.js';
|
|
7
8
|
export class PillarMesh extends InstancedMesh {
|
|
8
9
|
constructor(interpreter, material = new MeshBasicMaterial(), options = {}) {
|
|
9
10
|
const rows = interpreter.getRows();
|
|
@@ -27,31 +28,30 @@ export class PillarMesh extends InstancedMesh {
|
|
|
27
28
|
return idx;
|
|
28
29
|
};
|
|
29
30
|
function resolveCornerPosition(row, col, corner) {
|
|
30
|
-
const [cx, cz] = interpreter.getWorldCellCenter(row, col);
|
|
31
31
|
const half = cellSize * 0.5;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const lineNumber = row + 2;
|
|
43
|
-
const lineText = interpreter.getLineTextForRow(row);
|
|
44
|
-
const pos = lineText.indexOf('pillar(');
|
|
45
|
-
const columnNumber = pos >= 0 ? pos + 1 : 1;
|
|
46
|
-
interpreter.reportError(new ChartaError(`pillar at ${row}/${col}: invalid corner "${corner}", expected one of topleft, topright, bottomright, bottomleft`, interpreter.getSource(), { line: lineNumber, column: columnNumber, lineText }));
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
32
|
+
const offsets = {
|
|
33
|
+
topleft: [-half, -half],
|
|
34
|
+
topright: [half, -half],
|
|
35
|
+
bottomright: [half, half],
|
|
36
|
+
bottomleft: [-half, half],
|
|
37
|
+
};
|
|
38
|
+
const offset = offsets[corner];
|
|
39
|
+
if (offset) {
|
|
40
|
+
const { x, z } = interpreter.gridToWorld({ row, col, offsetX: offset[0], offsetZ: offset[1] });
|
|
41
|
+
return [x, z];
|
|
49
42
|
}
|
|
43
|
+
// Invalid corner
|
|
44
|
+
const lineNumber = row + 2;
|
|
45
|
+
const lineText = interpreter.getLineTextForRow(row);
|
|
46
|
+
const pos = lineText.indexOf('pillar(');
|
|
47
|
+
const columnNumber = pos >= 0 ? pos + 1 : 1;
|
|
48
|
+
interpreter.reportError(new ChartaError(`pillar at ${row}/${col}: invalid corner "${corner}", expected one of topleft, topright, bottomright, bottomleft`, interpreter.getSource(), { line: lineNumber, column: columnNumber, lineText }));
|
|
49
|
+
return undefined;
|
|
50
50
|
}
|
|
51
51
|
// Validation loop runs in both modes
|
|
52
52
|
for (let row = 0; row < rows; row++) {
|
|
53
53
|
for (let col = 0; col < cols; col++) {
|
|
54
|
-
const entries = interpreter.getCalls(
|
|
54
|
+
const entries = interpreter.getCalls({ row, col }, {
|
|
55
55
|
pillar: pillarSchema,
|
|
56
56
|
});
|
|
57
57
|
for (const [, parsed, idx, loc] of entries) {
|
|
@@ -61,9 +61,7 @@ export class PillarMesh extends InstancedMesh {
|
|
|
61
61
|
if (!cornerPos)
|
|
62
62
|
continue;
|
|
63
63
|
const [px, pz] = cornerPos;
|
|
64
|
-
const
|
|
65
|
-
const offsetX = px - cx;
|
|
66
|
-
const offsetZ = pz - cz;
|
|
64
|
+
const { offsetX, offsetZ } = interpreter.worldToGrid({ x: px, z: pz });
|
|
67
65
|
// Validate texture reference (runs in both modes)
|
|
68
66
|
const textureId = getTextureId(parsed.texture, loc);
|
|
69
67
|
// Derive default layers relative to call position (like walls)
|
|
@@ -73,7 +71,7 @@ export class PillarMesh extends InstancedMesh {
|
|
|
73
71
|
// Validate layer existence (runs in both modes)
|
|
74
72
|
let bottomStackIndex;
|
|
75
73
|
if (bottomY == null) {
|
|
76
|
-
const layersBefore = interpreter.countCalls(
|
|
74
|
+
const layersBefore = interpreter.countCalls({ row, col }, isLayer, 0, idx);
|
|
77
75
|
bottomStackIndex = layersBefore - 1;
|
|
78
76
|
if (bottomStackIndex < 0) {
|
|
79
77
|
interpreter.reportError(new ChartaError(`pillar at ${row}/${col}: missing bottomY and no preceding layer`, interpreter.getSource(), loc));
|
|
@@ -84,24 +82,24 @@ export class PillarMesh extends InstancedMesh {
|
|
|
84
82
|
const tilesGeometry = interpreter.getAsset(TilesGeometry, 'tilesGeometry', loc);
|
|
85
83
|
if (!tilesGeometry)
|
|
86
84
|
continue;
|
|
87
|
-
bottomY = tilesGeometry.
|
|
85
|
+
bottomY = tilesGeometry.getHeightAt({ row, col, offsetX, offsetZ }, { stackIndex: bottomStackIndex });
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
let topStackIndex;
|
|
91
89
|
if (topY == null) {
|
|
92
|
-
const layersAfter = interpreter.countCalls(
|
|
90
|
+
const layersAfter = interpreter.countCalls({ row, col }, isLayer, idx + 1);
|
|
93
91
|
if (layersAfter <= 0) {
|
|
94
92
|
interpreter.reportError(new ChartaError(`pillar at ${row}/${col}: missing topY and no subsequent layer`, interpreter.getSource(), loc));
|
|
95
93
|
continue;
|
|
96
94
|
}
|
|
97
95
|
// Height sampling only in non-validateOnly mode
|
|
98
96
|
if (!options.validateOnly) {
|
|
99
|
-
const layersBefore = interpreter.countCalls(
|
|
97
|
+
const layersBefore = interpreter.countCalls({ row, col }, isLayer, 0, idx);
|
|
100
98
|
topStackIndex = layersBefore;
|
|
101
99
|
const tilesGeometry = interpreter.getAsset(TilesGeometry, 'tilesGeometry', loc);
|
|
102
100
|
if (!tilesGeometry)
|
|
103
101
|
continue;
|
|
104
|
-
topY = tilesGeometry.
|
|
102
|
+
topY = tilesGeometry.getHeightAt({ row, col, offsetX, offsetZ }, { stackIndex: topStackIndex });
|
|
105
103
|
}
|
|
106
104
|
}
|
|
107
105
|
// Only collect pillar data in non-validateOnly mode
|
|
@@ -160,5 +158,8 @@ export class PillarMesh extends InstancedMesh {
|
|
|
160
158
|
const textureArray = buildTextureArrayFromAssets(usedTextures);
|
|
161
159
|
buildPillarMeshMaterial(this.material, textureArray);
|
|
162
160
|
}
|
|
161
|
+
// Setup BVH for accelerated raycasting
|
|
162
|
+
setupBVH(this.geometry);
|
|
163
|
+
this.raycast = acceleratedRaycast;
|
|
163
164
|
}
|
|
164
165
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/place/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAQ,MAAM,OAAO,CAAA;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAO/C,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;AAEvD,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE;IACvC,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,WAAW,CAAA;IACxB,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;IAC5D,IAAI,EAAE,MAAM,CAAA;CACb,KAAK,IAAI,CAAA;AAKV,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAOvD;AAED,qBAAa,kBAAkB;aAIX,UAAU,EAAE,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAJpC,SAAgB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAK;gBAG3B,UAAU,EAAE,OAAO,EAClB,iBAAiB,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ;IAG5E,GAAG,CAAC,MAAM,EAAE,OAAO;IAKZ,KAAK,IAAI,QAAQ;CAGzB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC,CAAA;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,aAAa,kCAAwC;gBAEzD,WAAW,EAAE,WAAW,EAAE,iBAAiB,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAE,iBAAsB;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/place/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAQ,MAAM,OAAO,CAAA;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAO/C,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;AAEvD,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE;IACvC,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,WAAW,CAAA;IACxB,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;IAC5D,IAAI,EAAE,MAAM,CAAA;CACb,KAAK,IAAI,CAAA;AAKV,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAOvD;AAED,qBAAa,kBAAkB;aAIX,UAAU,EAAE,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAJpC,SAAgB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAK;gBAG3B,UAAU,EAAE,OAAO,EAClB,iBAAiB,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ;IAG5E,GAAG,CAAC,MAAM,EAAE,OAAO;IAKZ,KAAK,IAAI,QAAQ;CAGzB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC,CAAA;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,aAAa,kCAAwC;gBAEzD,WAAW,EAAE,WAAW,EAAE,iBAAiB,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAE,iBAAsB;IAkPhG,OAAO;CAOR"}
|
package/dist/place/index.js
CHANGED
|
@@ -61,18 +61,17 @@ export class PlaceGroup extends Group {
|
|
|
61
61
|
const scale = Math.min(sFactorX ?? sFactorZ ?? 1, sFactorZ ?? sFactorX ?? 1);
|
|
62
62
|
return new Vector3(scale, scale, scale);
|
|
63
63
|
};
|
|
64
|
-
const computeTransform = (
|
|
64
|
+
const computeTransform = (worldX, worldZ, cell, transformOpts) => {
|
|
65
65
|
const normal = new Vector3();
|
|
66
|
-
const offsetX =
|
|
67
|
-
const offsetZ = pz - cell.center[1];
|
|
66
|
+
const { offsetX, offsetZ } = interpreter.worldToGrid({ x: worldX, z: worldZ });
|
|
68
67
|
let py = 0;
|
|
69
68
|
if (transformOpts.useFixedY) {
|
|
70
69
|
py = transformOpts.fixedY;
|
|
71
70
|
}
|
|
72
71
|
else {
|
|
73
|
-
py = tilesGeometry.
|
|
72
|
+
py = tilesGeometry.getHeightAt({ row: cell.row, col: cell.col, offsetX, offsetZ }, { stackIndex: transformOpts.layerIndex, normalTarget: normal });
|
|
74
73
|
}
|
|
75
|
-
const pos = new Vector3(
|
|
74
|
+
const pos = new Vector3(worldX, py, worldZ);
|
|
76
75
|
const quat = new Quaternion();
|
|
77
76
|
if (transformOpts.alignMode === 'normal' && !transformOpts.useFixedY) {
|
|
78
77
|
const qAlign = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), normal);
|
|
@@ -90,19 +89,18 @@ export class PlaceGroup extends Group {
|
|
|
90
89
|
for (let row = 0; row < rows; row++) {
|
|
91
90
|
for (let col = 0; col < cols; col++) {
|
|
92
91
|
// getCalls validates the schema and reports errors
|
|
93
|
-
const scatterEntries = interpreter.getCalls(
|
|
94
|
-
const placeEntries = interpreter.getCalls(
|
|
92
|
+
const scatterEntries = interpreter.getCalls({ row, col }, { scatter: scatterSchema });
|
|
93
|
+
const placeEntries = interpreter.getCalls({ row, col }, { place: placeSchema });
|
|
95
94
|
if (scatterEntries.length === 0 && placeEntries.length === 0)
|
|
96
95
|
continue;
|
|
97
|
-
const cx
|
|
98
|
-
const cz = (row - rows / 2 + 0.5) * cellSize;
|
|
96
|
+
const { x: cx, z: cz } = interpreter.gridToWorld({ row, col });
|
|
99
97
|
const half = cellSize * 0.5;
|
|
100
98
|
// Collect location points in this cell for collision/footprint validation
|
|
101
|
-
const locationEntries = interpreter.getCalls(
|
|
102
|
-
const locationPoints = locationEntries.map(([, parsed]) =>
|
|
103
|
-
x
|
|
104
|
-
|
|
105
|
-
})
|
|
99
|
+
const locationEntries = interpreter.getCalls({ row, col }, { location: locationSchema });
|
|
100
|
+
const locationPoints = locationEntries.map(([, parsed]) => {
|
|
101
|
+
const { x, z } = interpreter.gridToWorld({ row, col, offsetX: parsed.offsetX, offsetZ: parsed.offsetZ });
|
|
102
|
+
return { x, z };
|
|
103
|
+
});
|
|
106
104
|
// scatter: randomized distribution
|
|
107
105
|
for (const [, parsed, callIdx, loc] of scatterEntries) {
|
|
108
106
|
const prefabName = `${parsed.model}Prefab`;
|
|
@@ -115,7 +113,7 @@ export class PlaceGroup extends Group {
|
|
|
115
113
|
this.batchBuilders.set(parsed.model, batchBuilder);
|
|
116
114
|
const usualSize = new Vector3();
|
|
117
115
|
usualSize.copy(batchBuilder.prefabSize);
|
|
118
|
-
const layerIndex = interpreter.countCalls(
|
|
116
|
+
const layerIndex = interpreter.countCalls({ row, col }, (c) => c.name === 'ground' || c.name === 'ceiling', 0, callIdx) - 1;
|
|
119
117
|
const base = hashStringToUint32(parsed.model);
|
|
120
118
|
const seed = hashNumbersToUint32(base, row, col);
|
|
121
119
|
const rng = createRng(seed);
|
|
@@ -143,7 +141,7 @@ export class PlaceGroup extends Group {
|
|
|
143
141
|
const px = cx + ox;
|
|
144
142
|
const pz = cz + oz;
|
|
145
143
|
const yaw = yawMin === yawMax ? yawMin : yawMin + (yawMax - yawMin) * rng();
|
|
146
|
-
const { pos, quat, scl } = computeTransform(px, pz, { row, col
|
|
144
|
+
const { pos, quat, scl } = computeTransform(px, pz, { row, col }, {
|
|
147
145
|
alignMode,
|
|
148
146
|
yaw,
|
|
149
147
|
useFixedY: useFixedY,
|
|
@@ -174,8 +172,12 @@ export class PlaceGroup extends Group {
|
|
|
174
172
|
if (!batchBuilder)
|
|
175
173
|
continue;
|
|
176
174
|
const usualSize = batchBuilder.prefabSize;
|
|
177
|
-
const px
|
|
178
|
-
|
|
175
|
+
const { x: px, z: pz } = interpreter.gridToWorld({
|
|
176
|
+
row,
|
|
177
|
+
col,
|
|
178
|
+
offsetX: parsed.offsetX,
|
|
179
|
+
offsetZ: parsed.offsetZ,
|
|
180
|
+
});
|
|
179
181
|
// Compute scale for footprint validation (needed for both validateOnly and normal mode)
|
|
180
182
|
const scale = computeScale(usualSize, parsed.sizeX, parsed.sizeZ);
|
|
181
183
|
const halfX = (usualSize.x * scale.x) / 2;
|
|
@@ -190,10 +192,10 @@ export class PlaceGroup extends Group {
|
|
|
190
192
|
if (validateOnly)
|
|
191
193
|
continue;
|
|
192
194
|
this.batchBuilders.set(parsed.model, batchBuilder);
|
|
193
|
-
const layerIndex = interpreter.countCalls(
|
|
195
|
+
const layerIndex = interpreter.countCalls({ row, col }, (c) => c.name === 'ground' || c.name === 'ceiling', 0, callIdx) - 1;
|
|
194
196
|
const yaw = parsed.yaw ?? 0;
|
|
195
197
|
const alignMode = (parsed.align ?? 'up').toLowerCase();
|
|
196
|
-
const { pos, quat, scl } = computeTransform(px, pz, { row, col
|
|
198
|
+
const { pos, quat, scl } = computeTransform(px, pz, { row, col }, {
|
|
197
199
|
alignMode,
|
|
198
200
|
yaw,
|
|
199
201
|
useFixedY: parsed.bottomY != null,
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { coerce } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Grid coordinate with optional offset from cell center.
|
|
4
|
+
* row/col are integer indices into the grid.
|
|
5
|
+
* offsetX/offsetZ are in meters from the cell center.
|
|
6
|
+
*/
|
|
7
|
+
export type GridCoord = {
|
|
8
|
+
row: number;
|
|
9
|
+
col: number;
|
|
10
|
+
offsetX?: number;
|
|
11
|
+
offsetZ?: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* World coordinate in meters (top-down X/Z plane).
|
|
15
|
+
*/
|
|
16
|
+
export type WorldCoord = {
|
|
17
|
+
x: number;
|
|
18
|
+
z: number;
|
|
19
|
+
};
|
|
2
20
|
export declare const alignEnum: import("zod").ZodEnum<{
|
|
3
21
|
up: "up";
|
|
4
22
|
normal: "normal";
|
package/dist/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,KAAK,CAAA;AAM7D,eAAO,MAAM,SAAS;;;EAA4B,CAAA;AAClD,eAAO,MAAM,UAAU;;;;;EAAgE,CAAA;AACvF,eAAO,MAAM,WAAW;;;;;EAA8C,CAAA;AAMtE,eAAO,MAAM,cAAc;;gCAAoC,CAAA;AAC/D,eAAO,MAAM,cAAc;;gCAA6B,CAAA;AACxD,eAAO,MAAM,iBAAiB;;;gCAA6C,CAAA;AAC3E,eAAO,MAAM,eAAe;;;gCAA6C,CAAA;AAMzE,eAAO,MAAM,YAAY;;;gCAAoD,CAAA;AAC7E,eAAO,MAAM,aAAa;;;gCAAoD,CAAA;AAC9E,eAAO,MAAM,WAAW;;gCAAiC,CAAA;AAMzD,eAAO,MAAM,UAAU;;;;;;;;;;gCAKrB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;gCAKvB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;gCAMrB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;gCAOvB,CAAA;AAMF,eAAO,MAAM,cAAc;;;;gCAIzB,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;;;;;;;;gCAStB,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;gCAcxB,CAAA;AAMF,eAAO,MAAM,WAAW;;;;gCAItB,CAAA;AAMF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAET"}
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,KAAK,CAAA;AAM7D;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV,CAAA;AAMD,eAAO,MAAM,SAAS;;;EAA4B,CAAA;AAClD,eAAO,MAAM,UAAU;;;;;EAAgE,CAAA;AACvF,eAAO,MAAM,WAAW;;;;;EAA8C,CAAA;AAMtE,eAAO,MAAM,cAAc;;gCAAoC,CAAA;AAC/D,eAAO,MAAM,cAAc;;gCAA6B,CAAA;AACxD,eAAO,MAAM,iBAAiB;;;gCAA6C,CAAA;AAC3E,eAAO,MAAM,eAAe;;;gCAA6C,CAAA;AAMzE,eAAO,MAAM,YAAY;;;gCAAoD,CAAA;AAC7E,eAAO,MAAM,aAAa;;;gCAAoD,CAAA;AAC9E,eAAO,MAAM,WAAW;;gCAAiC,CAAA;AAMzD,eAAO,MAAM,UAAU;;;;;;;;;;gCAKrB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;gCAKvB,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;gCAMrB,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;gCAOvB,CAAA;AAMF,eAAO,MAAM,cAAc;;;;gCAIzB,CAAA;AAEF,eAAO,MAAM,WAAW;;;;;;;;;;;;gCAStB,CAAA;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;gCAcxB,CAAA;AAMF,eAAO,MAAM,WAAW;;;;gCAItB,CAAA;AAMF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAET"}
|
package/dist/tiles/geometry.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { BufferGeometry, Vector3 } from 'three';
|
|
2
|
+
import type { GridCoord } from '../schemas.js';
|
|
3
|
+
export type GetHeightAtOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* index in the tile stack
|
|
6
|
+
* use 0 for the lowest and Infinity for the highest
|
|
7
|
+
* @default infinity
|
|
8
|
+
*/
|
|
9
|
+
stackIndex?: number;
|
|
10
|
+
/**
|
|
11
|
+
* optional target vector that will receive the interpolated face normal at the queried point
|
|
12
|
+
*/
|
|
13
|
+
normalTarget?: Vector3;
|
|
14
|
+
};
|
|
2
15
|
export type Tile = {
|
|
3
16
|
type: string;
|
|
4
17
|
y: number;
|
|
@@ -30,15 +43,7 @@ export declare class TilesGeometry extends BufferGeometry {
|
|
|
30
43
|
bottom: Array<WallData>;
|
|
31
44
|
left: Array<WallData>;
|
|
32
45
|
}>>, mapSizeX: number, mapSizeZ: number);
|
|
33
|
-
|
|
34
|
-
* @param row tile grid row index (Z direction)
|
|
35
|
-
* @param col tile grid column index (X direction)
|
|
36
|
-
* @param stackIndex index in the tile stack
|
|
37
|
-
* @param offsetX world unit offset from tile center X
|
|
38
|
-
* @param offsetZ world unit offset from tile center Z
|
|
39
|
-
* @param normalTarget optional target vector that will receive the interpolated face normal at the queried point
|
|
40
|
-
*/
|
|
41
|
-
getHeight(row: number, col: number, stackIndex?: number, offsetX?: number, offsetZ?: number, normalTarget?: Vector3): number;
|
|
46
|
+
getHeightAt({ row, col, offsetX, offsetZ }: GridCoord, { normalTarget, stackIndex }?: GetHeightAtOptions): number;
|
|
42
47
|
private addVertex;
|
|
43
48
|
private getVertices;
|
|
44
49
|
private getConnectionVertexId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/tiles/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAMd,OAAO,EACR,MAAM,OAAO,CAAA;AAGd,MAAM,MAAM,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAoB3F,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAkQxD,qBAAa,aAAc,SAAQ,cAAc;IAe7C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;aAQN,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,MAAM;IAxBlC,SAAgB,SAAS,EAAE,MAAM,CAAA;IACjC,SAAgB,SAAS,EAAE,MAAM,CAAA;IAEjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IAErD,OAAO,CAAC,SAAS,CAAI;IAErB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;gBAG7C,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAChC,KAAK,EAAE,KAAK,CAC3B,KAAK,CAAC;QACJ,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACpB,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACtB,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACvB,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;KACtB,CAAC,CACH,EACe,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/tiles/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAMd,OAAO,EACR,MAAM,OAAO,CAAA;AAGd,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAE9C,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAoB3F,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAkQxD,qBAAa,aAAc,SAAQ,cAAc;IAe7C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;aAQN,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,MAAM;IAxBlC,SAAgB,SAAS,EAAE,MAAM,CAAA;IACjC,SAAgB,SAAS,EAAE,MAAM,CAAA;IAEjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IAErD,OAAO,CAAC,SAAS,CAAI;IAErB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;gBAG7C,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAChC,KAAK,EAAE,KAAK,CAC3B,KAAK,CAAC;QACJ,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACpB,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACtB,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;QACvB,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;KACtB,CAAC,CACH,EACe,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IA0E3B,WAAW,CAChB,EAAE,GAAG,EAAE,GAAG,EAAE,OAAW,EAAE,OAAW,EAAE,EAAE,SAAS,EACjD,EAAE,YAAY,EAAE,UAAqB,EAAE,GAAE,kBAAuB;IAiFlE,OAAO,CAAC,SAAS;IAoGjB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,qBAAqB;CAiB9B"}
|
package/dist/tiles/geometry.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BufferGeometry, Float32BufferAttribute, Uint16BufferAttribute, } from 'three';
|
|
2
2
|
import { isLayerConnectedToWall } from '../walls/index.js';
|
|
3
|
+
import { clamp } from 'three/src/math/MathUtils.js';
|
|
3
4
|
const MAX_AUTO_CONNECT_HEIGHT_DIFF_RATIO = 1 / 4;
|
|
4
5
|
const MAX_CONNECTION_HEIGHT_DIFF_RATIO = 8;
|
|
5
6
|
function isBetterConnection(newConnection, oldConnection, tileSize) {
|
|
@@ -293,20 +294,12 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
293
294
|
this.computeVertexNormals();
|
|
294
295
|
this.computeTangents();
|
|
295
296
|
}
|
|
296
|
-
|
|
297
|
-
* @param row tile grid row index (Z direction)
|
|
298
|
-
* @param col tile grid column index (X direction)
|
|
299
|
-
* @param stackIndex index in the tile stack
|
|
300
|
-
* @param offsetX world unit offset from tile center X
|
|
301
|
-
* @param offsetZ world unit offset from tile center Z
|
|
302
|
-
* @param normalTarget optional target vector that will receive the interpolated face normal at the queried point
|
|
303
|
-
*/
|
|
304
|
-
getHeight(row, col, stackIndex, offsetX = 0, offsetZ = 0, normalTarget) {
|
|
297
|
+
getHeightAt({ row, col, offsetX = 0, offsetZ = 0 }, { normalTarget, stackIndex = Infinity } = {}) {
|
|
305
298
|
if (col < 0 || col >= this.tiles[0].length || row < 0 || row >= this.tiles.length) {
|
|
306
299
|
throw new Error(`Tile index out of bounds: (row=${row}, col=${col}). Grid size: ${this.tiles.length}x${this.tiles[0].length}`);
|
|
307
300
|
}
|
|
308
301
|
const vertices = this.getVertices(col, row);
|
|
309
|
-
const vertex1 = vertices[stackIndex
|
|
302
|
+
const vertex1 = vertices[clamp(stackIndex, 0, vertices.length - 1)];
|
|
310
303
|
if (vertex1 == null) {
|
|
311
304
|
throw new Error(`No vertex found at stack index "${stackIndex ?? 'any'}" for tile (row=${row}, col=${col}).`);
|
|
312
305
|
}
|
package/dist/tiles/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Material, Mesh } from 'three';
|
|
2
2
|
import { Interpreter } from '../interpreter.js';
|
|
3
|
-
import { TilesGeometry } from './geometry.js';
|
|
4
|
-
import { groundSchema, ceilingSchema } from '../schemas.js';
|
|
3
|
+
import { GetHeightAtOptions, TilesGeometry } from './geometry.js';
|
|
4
|
+
import { groundSchema, ceilingSchema, GridCoord } from '../schemas.js';
|
|
5
5
|
export { groundSchema, ceilingSchema };
|
|
6
6
|
export type TilesMeshOptions = {
|
|
7
7
|
/**
|
|
@@ -13,5 +13,7 @@ export type TilesMeshOptions = {
|
|
|
13
13
|
};
|
|
14
14
|
export declare class TilesMesh extends Mesh<TilesGeometry> {
|
|
15
15
|
constructor(interpreter: Interpreter, material?: Material, options?: TilesMeshOptions);
|
|
16
|
+
getHeightAt(coord: GridCoord, options?: GetHeightAtOptions): number;
|
|
17
|
+
dispose(): void;
|
|
16
18
|
}
|
|
17
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tiles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,IAAI,EAOL,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tiles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,IAAI,EAOL,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAA;AAItF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAc,SAAS,EAAE,MAAM,eAAe,CAAA;AAGlF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAA;AAEtC,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAyCD,qBAAa,SAAU,SAAQ,IAAI,CAAC,aAAa,CAAC;gBACpC,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAkC,EAAE,OAAO,GAAE,gBAAqB;IAyIlH,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,kBAAkB;IAI1D,OAAO,IAAI,IAAI;CAMhB"}
|
package/dist/tiles/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Mesh, Texture, MeshBasicMaterial, } from 'three';
|
|
1
|
+
import { Material, Mesh, Texture, MeshBasicMaterial, } from 'three';
|
|
2
2
|
import { TilesGeometry } from './geometry.js';
|
|
3
3
|
import { buildTilesMaterial } from './material.js';
|
|
4
4
|
import { ChartaError } from '../errors.js';
|
|
5
5
|
import { buildTextureArrayFromAssets } from '../utils/texture.js';
|
|
6
6
|
import { groundSchema, ceilingSchema, wallSchema } from '../schemas.js';
|
|
7
|
+
import { setupBVH, acceleratedRaycast } from '../utils/bvh.js';
|
|
7
8
|
export { groundSchema, ceilingSchema };
|
|
8
9
|
function resolveHeights(position, items, interpreter, reverse) {
|
|
9
10
|
items = [...items];
|
|
@@ -65,7 +66,7 @@ export class TilesMesh extends Mesh {
|
|
|
65
66
|
for (let row = 0; row < rows; row++) {
|
|
66
67
|
for (let col = 0; col < cols; col++) {
|
|
67
68
|
// Collect and validate all entries for this cell
|
|
68
|
-
const calls = Array.from(interpreter.getCalls(
|
|
69
|
+
const calls = Array.from(interpreter.getCalls({ row, col }, {
|
|
69
70
|
ground: groundSchema,
|
|
70
71
|
ceiling: ceilingSchema,
|
|
71
72
|
wall: wallSchema,
|
|
@@ -133,5 +134,17 @@ export class TilesMesh extends Mesh {
|
|
|
133
134
|
this.material = buildTilesMaterial(material, buildTextureArrayFromAssets(texturesInOrder));
|
|
134
135
|
}
|
|
135
136
|
}
|
|
137
|
+
// Setup BVH for accelerated raycasting
|
|
138
|
+
setupBVH(this.geometry);
|
|
139
|
+
this.raycast = acceleratedRaycast;
|
|
140
|
+
}
|
|
141
|
+
getHeightAt(coord, options) {
|
|
142
|
+
return this.geometry.getHeightAt(coord, options);
|
|
143
|
+
}
|
|
144
|
+
dispose() {
|
|
145
|
+
this.geometry.dispose();
|
|
146
|
+
if (this.material instanceof Material) {
|
|
147
|
+
this.material.dispose();
|
|
148
|
+
}
|
|
136
149
|
}
|
|
137
150
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { acceleratedRaycast } from 'three-mesh-bvh';
|
|
2
|
+
import type { BufferGeometry } from 'three';
|
|
3
|
+
/**
|
|
4
|
+
* Sets up BVH (Bounding Volume Hierarchy) on a geometry for accelerated raycasting.
|
|
5
|
+
* Call this after geometry is created, then assign acceleratedRaycast to the mesh's raycast method.
|
|
6
|
+
*
|
|
7
|
+
* @param geometry - The BufferGeometry to compute BVH for. If undefined or empty, this is a no-op.
|
|
8
|
+
*/
|
|
9
|
+
export declare function setupBVH(geometry: BufferGeometry | undefined): void;
|
|
10
|
+
export { acceleratedRaycast };
|
|
11
|
+
//# sourceMappingURL=bvh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bvh.d.ts","sourceRoot":"","sources":["../../src/utils/bvh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAwC,MAAM,gBAAgB,CAAA;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,CAWnE;AAED,OAAO,EAAE,kBAAkB,EAAE,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh';
|
|
2
|
+
/**
|
|
3
|
+
* Sets up BVH (Bounding Volume Hierarchy) on a geometry for accelerated raycasting.
|
|
4
|
+
* Call this after geometry is created, then assign acceleratedRaycast to the mesh's raycast method.
|
|
5
|
+
*
|
|
6
|
+
* @param geometry - The BufferGeometry to compute BVH for. If undefined or empty, this is a no-op.
|
|
7
|
+
*/
|
|
8
|
+
export function setupBVH(geometry) {
|
|
9
|
+
if (!geometry)
|
|
10
|
+
return;
|
|
11
|
+
// Skip BVH for empty geometries (no index or no position attribute)
|
|
12
|
+
const index = geometry.getIndex();
|
|
13
|
+
const position = geometry.getAttribute('position');
|
|
14
|
+
if (!index || index.count === 0 || !position || position.count === 0)
|
|
15
|
+
return;
|
|
16
|
+
geometry.computeBoundsTree = computeBoundsTree;
|
|
17
|
+
geometry.disposeBoundsTree = disposeBoundsTree;
|
|
18
|
+
geometry.computeBoundsTree();
|
|
19
|
+
}
|
|
20
|
+
export { acceleratedRaycast };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instanced-mesh-group.d.ts","sourceRoot":"","sources":["../../src/utils/instanced-mesh-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAQ,QAAQ,EAAS,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"instanced-mesh-group.d.ts","sourceRoot":"","sources":["../../src/utils/instanced-mesh-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAQ,QAAQ,EAAS,MAAM,OAAO,CAAC;AAG7E,UAAU,kBAAkB;IAC1B,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,OAAO,EAAE,kBAAkB,EAAE,CAAM;gBAEvB,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;IAmDtE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;IAiB1C;;;OAGG;IACH,OAAO;CAOR"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Group, InstancedMesh, Matrix4 } from "three";
|
|
2
|
+
import { setupBVH, acceleratedRaycast } from "./bvh.js";
|
|
2
3
|
export class InstancedMeshGroup extends Group {
|
|
3
4
|
entries = [];
|
|
4
5
|
constructor(object, count, matrices) {
|
|
@@ -29,6 +30,11 @@ export class InstancedMeshGroup extends Group {
|
|
|
29
30
|
this.setMatrixAt(i, matrices[i]);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
33
|
+
// Setup BVH for accelerated raycasting on all child InstancedMeshes
|
|
34
|
+
for (const entry of this.entries) {
|
|
35
|
+
setupBVH(entry.mesh.geometry);
|
|
36
|
+
entry.mesh.raycast = acceleratedRaycast;
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
setMatrixAt(index, matrix) {
|
|
34
40
|
const instanceMatrix = new Matrix4();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/walls/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAER,IAAI,EAGJ,YAAY,EAEZ,YAAY,EAOb,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpD,OAAO,EAAe,aAAa,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAGL,UAAU,EACV,YAAY,EACZ,UAAU,EACX,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/walls/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EAER,IAAI,EAGJ,YAAY,EAEZ,YAAY,EAOb,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpD,OAAO,EAAe,aAAa,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAGL,UAAU,EACV,YAAY,EACZ,UAAU,EACX,MAAM,eAAe,CAAA;AAGtB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,CAAA;AAK/C,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,MAAM,EAAE,YAAY,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,YAAY,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,UAAU,EAAE,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;CAed,CAAA;AAEV,eAAO,MAAM,+BAA+B,QAAQ,CAAA;AAEpD,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACxD,MAAM,EAAE,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,EACtD,GAAG,EAAE,aAAa;YAwFO,YAAY;UACd,YAAY;;;cA8DpC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,qBAAa,QAAS,SAAQ,IAAI;gBACpB,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAkC,EAAE,OAAO,GAAE,eAAoB;CAkTlH;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,WAGrG"}
|
package/dist/walls/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { buildTextureArrayFromAssets } from '../utils/texture.js';
|
|
|
5
5
|
import { buildWallMeshMaterial } from './material.js';
|
|
6
6
|
import { ChartaError } from '../errors.js';
|
|
7
7
|
import { groundSchema, ceilingSchema, wallSchema, windowSchema, doorSchema, } from '../schemas.js';
|
|
8
|
+
import { setupBVH, acceleratedRaycast } from '../utils/bvh.js';
|
|
8
9
|
export { wallSchema, windowSchema, doorSchema };
|
|
9
10
|
const eulerHelper = new Euler();
|
|
10
11
|
const scaleHelper = new Vector3(1, 1, 1);
|
|
@@ -42,14 +43,17 @@ export function computeWallVerticalBounds(interpreter, tilesGeometry, row, col,
|
|
|
42
43
|
neighborCol--;
|
|
43
44
|
else if (parsed.dir === 'right')
|
|
44
45
|
neighborCol++;
|
|
45
|
-
const [worldCellCenterX, worldCellCenterZ] = interpreter.getWorldCellCenter(row, col);
|
|
46
46
|
const localWallX = ('xOffset' in config ? config.xOffset : 0) * cellSize;
|
|
47
47
|
const localWallZ = ('zOffset' in config ? config.zOffset : 0) * cellSize;
|
|
48
|
-
const worldWallX
|
|
49
|
-
|
|
48
|
+
const { x: worldWallX, z: worldWallZ } = interpreter.gridToWorld({
|
|
49
|
+
row,
|
|
50
|
+
col,
|
|
51
|
+
offsetX: localWallX,
|
|
52
|
+
offsetZ: localWallZ,
|
|
53
|
+
});
|
|
50
54
|
// Determine layer context
|
|
51
|
-
const layersBefore = interpreter.countCalls(
|
|
52
|
-
const layersAfter = interpreter.countCalls(
|
|
55
|
+
const layersBefore = interpreter.countCalls({ row, col }, isLayer, 0, wallIdx);
|
|
56
|
+
const layersAfter = interpreter.countCalls({ row, col }, isLayer, wallIdx + 1);
|
|
53
57
|
const resolveLayer = (explicitY, isTop) => {
|
|
54
58
|
// Case 1: No explicit height -> connect to adjacent layer in current cell
|
|
55
59
|
if (explicitY === undefined) {
|
|
@@ -72,7 +76,7 @@ export function computeWallVerticalBounds(interpreter, tilesGeometry, row, col,
|
|
|
72
76
|
const checkCell = (r, c) => {
|
|
73
77
|
if (r < 0 || r >= rows || c < 0 || c >= cols)
|
|
74
78
|
return;
|
|
75
|
-
const calls = interpreter.getCalls(
|
|
79
|
+
const calls = interpreter.getCalls({ row: r, col: c }, { ground: groundSchema, ceiling: ceilingSchema });
|
|
76
80
|
for (let i = 0; i < calls.length; i++) {
|
|
77
81
|
const [, { y: layerY }] = calls[i];
|
|
78
82
|
const diff = Math.abs(layerY - explicitY);
|
|
@@ -119,7 +123,7 @@ export function computeWallVerticalBounds(interpreter, tilesGeometry, row, col,
|
|
|
119
123
|
if (bottomLayer) {
|
|
120
124
|
const offX = sX + (col - bottomLayer.col) * cellSize;
|
|
121
125
|
const offZ = sZ + (row - bottomLayer.row) * cellSize;
|
|
122
|
-
yStart[k] = tilesGeometry.
|
|
126
|
+
yStart[k] = tilesGeometry.getHeightAt({ row: bottomLayer.row, col: bottomLayer.col, offsetX: offX, offsetZ: offZ }, { stackIndex: bottomLayer.layerIdx });
|
|
123
127
|
}
|
|
124
128
|
else {
|
|
125
129
|
yStart[k] = parsed.bottomY;
|
|
@@ -128,7 +132,7 @@ export function computeWallVerticalBounds(interpreter, tilesGeometry, row, col,
|
|
|
128
132
|
if (topLayer) {
|
|
129
133
|
const offX = sX + (col - topLayer.col) * cellSize;
|
|
130
134
|
const offZ = sZ + (row - topLayer.row) * cellSize;
|
|
131
|
-
yEnd[k] = tilesGeometry.
|
|
135
|
+
yEnd[k] = tilesGeometry.getHeightAt({ row: topLayer.row, col: topLayer.col, offsetX: offX, offsetZ: offZ }, { stackIndex: topLayer.layerIdx });
|
|
132
136
|
}
|
|
133
137
|
else {
|
|
134
138
|
yEnd[k] = parsed.topY;
|
|
@@ -175,7 +179,7 @@ export class WallMesh extends Mesh {
|
|
|
175
179
|
// Validation loop runs in both modes
|
|
176
180
|
for (let row = 0; row < rows; row++) {
|
|
177
181
|
for (let col = 0; col < cols; col++) {
|
|
178
|
-
const entries = interpreter.getCalls(
|
|
182
|
+
const entries = interpreter.getCalls({ row, col }, {
|
|
179
183
|
wall: wallSchema,
|
|
180
184
|
window: windowSchema,
|
|
181
185
|
door: doorSchema,
|
|
@@ -385,6 +389,9 @@ export class WallMesh extends Mesh {
|
|
|
385
389
|
const textureArray = buildTextureArrayFromAssets(usedTextures);
|
|
386
390
|
buildWallMeshMaterial(this.material, textureArray);
|
|
387
391
|
}
|
|
392
|
+
// Setup BVH for accelerated raycasting
|
|
393
|
+
setupBVH(this.geometry);
|
|
394
|
+
this.raycast = acceleratedRaycast;
|
|
388
395
|
}
|
|
389
396
|
}
|
|
390
397
|
export function isLayerConnectedToWall(wallTopY, wallBotY, y, tileSize) {
|
package/dist/water/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { Mesh } from
|
|
2
|
-
import { Interpreter } from
|
|
1
|
+
import { Mesh } from 'three';
|
|
2
|
+
import { Interpreter } from '../interpreter.js';
|
|
3
|
+
import { GetHeightAtOptions, TilesGeometry } from '../tiles/geometry.js';
|
|
4
|
+
import { GridCoord } from '../schemas.js';
|
|
3
5
|
export type WaterMeshOptions = {
|
|
4
6
|
/**
|
|
5
7
|
* Validate-only mode: validates water calls but skips geometry creation.
|
|
@@ -7,10 +9,11 @@ export type WaterMeshOptions = {
|
|
|
7
9
|
*/
|
|
8
10
|
validateOnly?: boolean;
|
|
9
11
|
};
|
|
10
|
-
export declare class WaterMesh extends Mesh {
|
|
12
|
+
export declare class WaterMesh extends Mesh<TilesGeometry> {
|
|
11
13
|
constructor(interpreter: Interpreter, options?: WaterMeshOptions);
|
|
14
|
+
getHeightAt(coord: GridCoord, options?: GetHeightAtOptions): number;
|
|
12
15
|
dispose(): void;
|
|
13
16
|
}
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
17
|
+
export * from './texture.js';
|
|
18
|
+
export * from './material.js';
|
|
16
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/water/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAY,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/water/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAY,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAa,MAAM,sBAAsB,CAAA;AACnF,OAAO,EAAE,SAAS,EAAe,MAAM,eAAe,CAAA;AAGtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,qBAAa,SAAU,SAAQ,IAAI,CAAC,aAAa,CAAC;gBACpC,WAAW,EAAE,WAAW,EAAE,OAAO,GAAE,gBAAqB;IAsDpE,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,kBAAkB;IAI1D,OAAO,IAAI,IAAI;CAMhB;AAED,cAAc,cAAc,CAAA;AAC5B,cAAc,eAAe,CAAA"}
|
package/dist/water/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Mesh, Material } from
|
|
2
|
-
import { TilesGeometry } from
|
|
3
|
-
import { waterSchema } from
|
|
1
|
+
import { Mesh, Material } from 'three';
|
|
2
|
+
import { TilesGeometry } from '../tiles/geometry.js';
|
|
3
|
+
import { waterSchema } from '../schemas.js';
|
|
4
|
+
import { setupBVH, acceleratedRaycast } from '../utils/bvh.js';
|
|
4
5
|
export class WaterMesh extends Mesh {
|
|
5
6
|
constructor(interpreter, options = {}) {
|
|
6
7
|
const rows = interpreter.getRows();
|
|
@@ -8,20 +9,18 @@ export class WaterMesh extends Mesh {
|
|
|
8
9
|
// Build tiles only in non-validateOnly mode (expensive allocation)
|
|
9
10
|
let tiles;
|
|
10
11
|
if (!options.validateOnly) {
|
|
11
|
-
tiles = new Array(rows)
|
|
12
|
-
.fill(undefined)
|
|
13
|
-
.map(() => new Array(cols).fill(undefined).map(() => []));
|
|
12
|
+
tiles = new Array(rows).fill(undefined).map(() => new Array(cols).fill(undefined).map(() => []));
|
|
14
13
|
}
|
|
15
14
|
// Validation loop runs in both modes
|
|
16
15
|
for (let row = 0; row < rows; row++) {
|
|
17
16
|
for (let col = 0; col < cols; col++) {
|
|
18
|
-
const entries = interpreter.getCalls(
|
|
17
|
+
const entries = interpreter.getCalls({ row, col }, { water: waterSchema });
|
|
19
18
|
// Only build tile stack in non-validateOnly mode
|
|
20
19
|
if (!options.validateOnly) {
|
|
21
20
|
const stack = [];
|
|
22
21
|
for (const [, parsed] of entries) {
|
|
23
22
|
stack.push({
|
|
24
|
-
type:
|
|
23
|
+
type: 'water',
|
|
25
24
|
y: parsed.y,
|
|
26
25
|
textureId: 0,
|
|
27
26
|
row,
|
|
@@ -41,10 +40,16 @@ export class WaterMesh extends Mesh {
|
|
|
41
40
|
const mapSizeX = cols * cellSize;
|
|
42
41
|
const mapSizeZ = rows * cellSize;
|
|
43
42
|
const geometry = new TilesGeometry(tiles, [], mapSizeX, mapSizeZ);
|
|
44
|
-
interpreter.setAsset(
|
|
43
|
+
interpreter.setAsset('waterGeometry', geometry);
|
|
45
44
|
super(geometry);
|
|
46
45
|
this.renderOrder = 1;
|
|
47
46
|
this.frustumCulled = true;
|
|
47
|
+
// Setup BVH for accelerated raycasting
|
|
48
|
+
setupBVH(this.geometry);
|
|
49
|
+
this.raycast = acceleratedRaycast;
|
|
50
|
+
}
|
|
51
|
+
getHeightAt(coord, options) {
|
|
52
|
+
return this.geometry.getHeightAt(coord, options);
|
|
48
53
|
}
|
|
49
54
|
dispose() {
|
|
50
55
|
this.geometry.dispose();
|
|
@@ -53,5 +58,5 @@ export class WaterMesh extends Mesh {
|
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
|
-
export * from
|
|
57
|
-
export * from
|
|
61
|
+
export * from './texture.js';
|
|
62
|
+
export * from './material.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drawcall/charta",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"author": "Bela Bohlender",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://drawcall.ai",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"fft.js": "^4.0.4",
|
|
26
26
|
"imurmurhash": "^0.1.4",
|
|
27
27
|
"seedrandom": "^3.0.5",
|
|
28
|
+
"three-mesh-bvh": "^0.8.0",
|
|
28
29
|
"zod": "^4.1.12"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|