@drawcall/charta 0.1.9 → 0.1.11
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.js +24 -24
- package/dist/locations.js +1 -1
- package/dist/pillars/index.js +2 -2
- package/dist/place/index.js +12 -12
- package/dist/tiles/geometry.d.ts +5 -5
- package/dist/tiles/geometry.d.ts.map +1 -1
- package/dist/tiles/geometry.js +48 -48
- package/dist/tiles/index.d.ts +3 -4
- package/dist/tiles/index.d.ts.map +1 -1
- package/dist/tiles/index.js +11 -12
- package/dist/walls/index.js +2 -2
- package/dist/water/index.js +7 -7
- package/package.json +1 -1
package/dist/grass/index.js
CHANGED
|
@@ -19,10 +19,10 @@ export class GrassMesh extends InstancedMesh {
|
|
|
19
19
|
.fill(undefined)
|
|
20
20
|
.map(() => new Array(cols).fill(null));
|
|
21
21
|
let maxBlades = 0;
|
|
22
|
-
for (let
|
|
23
|
-
for (let
|
|
22
|
+
for (let row = 0; row < rows; row++) {
|
|
23
|
+
for (let col = 0; col < cols; col++) {
|
|
24
24
|
const grassParsed = interpreter
|
|
25
|
-
.getCalls([
|
|
25
|
+
.getCalls([row, col], { grass: grassSchema })
|
|
26
26
|
.at(-1)?.[1];
|
|
27
27
|
if (!grassParsed)
|
|
28
28
|
continue;
|
|
@@ -33,8 +33,8 @@ export class GrassMesh extends InstancedMesh {
|
|
|
33
33
|
const step = cellSize / subN;
|
|
34
34
|
const jitterAmp = step * 0.35;
|
|
35
35
|
// top surface stack index = total number of ground/ceiling - 1
|
|
36
|
-
const topStackIndex = Math.max(0, interpreter.countCalls([
|
|
37
|
-
perCell[
|
|
36
|
+
const topStackIndex = Math.max(0, interpreter.countCalls([row, col], (c) => c.name === "ground" || c.name === "ceiling") - 1);
|
|
37
|
+
perCell[row][col] = {
|
|
38
38
|
subN,
|
|
39
39
|
jitterAmp,
|
|
40
40
|
height,
|
|
@@ -46,23 +46,23 @@ export class GrassMesh extends InstancedMesh {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
// Compute neighbor flags
|
|
49
|
-
function hasGrassCell(
|
|
50
|
-
return (!(
|
|
49
|
+
function hasGrassCell(row, col) {
|
|
50
|
+
return (!(row < 0 || col < 0 || row >= rows || col >= cols) && perCell[row][col] != null);
|
|
51
51
|
}
|
|
52
|
-
for (let
|
|
53
|
-
for (let
|
|
54
|
-
const cell = perCell[
|
|
52
|
+
for (let row = 0; row < rows; row++) {
|
|
53
|
+
for (let col = 0; col < cols; col++) {
|
|
54
|
+
const cell = perCell[row][col];
|
|
55
55
|
if (!cell)
|
|
56
56
|
continue;
|
|
57
57
|
cell.neighbors = {
|
|
58
|
-
top: !hasGrassCell(
|
|
59
|
-
right: !hasGrassCell(
|
|
60
|
-
bottom: !hasGrassCell(
|
|
61
|
-
left: !hasGrassCell(
|
|
62
|
-
topLeft: !hasGrassCell(
|
|
63
|
-
topRight: !hasGrassCell(
|
|
64
|
-
bottomRight: !hasGrassCell(
|
|
65
|
-
bottomLeft: !hasGrassCell(
|
|
58
|
+
top: !hasGrassCell(row - 1, col), // north
|
|
59
|
+
right: !hasGrassCell(row, col + 1), // east
|
|
60
|
+
bottom: !hasGrassCell(row + 1, col), // south
|
|
61
|
+
left: !hasGrassCell(row, col - 1), // west
|
|
62
|
+
topLeft: !hasGrassCell(row - 1, col - 1),
|
|
63
|
+
topRight: !hasGrassCell(row - 1, col + 1),
|
|
64
|
+
bottomRight: !hasGrassCell(row + 1, col + 1),
|
|
65
|
+
bottomLeft: !hasGrassCell(row + 1, col - 1),
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -83,17 +83,17 @@ export class GrassMesh extends InstancedMesh {
|
|
|
83
83
|
const scale = new Vector3(1, 1, 1);
|
|
84
84
|
const tilesGeometry = interpreter.getAsset(TilesGeometry, "tilesGeometry");
|
|
85
85
|
// Single pass generation
|
|
86
|
-
for (let
|
|
87
|
-
for (let
|
|
88
|
-
const cell = perCell[
|
|
86
|
+
for (let row = 0; row < rows; row++) {
|
|
87
|
+
for (let col = 0; col < cols; col++) {
|
|
88
|
+
const cell = perCell[row][col];
|
|
89
89
|
if (!cell)
|
|
90
90
|
continue;
|
|
91
91
|
const { subN, jitterAmp, height, width, topStackIndex, neighbors } = cell;
|
|
92
92
|
const nb = neighbors;
|
|
93
93
|
const step = cellSize / subN;
|
|
94
94
|
// Cell center
|
|
95
|
-
const cx = (
|
|
96
|
-
const cz = (
|
|
95
|
+
const cx = (col - cols / 2 + 0.5) * cellSize;
|
|
96
|
+
const cz = (row - rows / 2 + 0.5) * cellSize;
|
|
97
97
|
for (let gz = 0; gz < subN; gz++) {
|
|
98
98
|
for (let gx = 0; gx < subN; gx++) {
|
|
99
99
|
// Optimization: Check stochastic rejection early using simplified fade check
|
|
@@ -144,7 +144,7 @@ export class GrassMesh extends InstancedMesh {
|
|
|
144
144
|
const pz = cz + oz + jz;
|
|
145
145
|
let baseY = 0;
|
|
146
146
|
if (tilesGeometry) {
|
|
147
|
-
baseY = tilesGeometry.getHeight(
|
|
147
|
+
baseY = tilesGeometry.getHeight(row, col, topStackIndex, px - cx, pz - cz);
|
|
148
148
|
}
|
|
149
149
|
tmpPos.set(px, baseY, pz);
|
|
150
150
|
// Scale
|
package/dist/locations.js
CHANGED
|
@@ -51,7 +51,7 @@ export class Locations {
|
|
|
51
51
|
stackIndex = layersAfter > 0 ? 0 : 0;
|
|
52
52
|
}
|
|
53
53
|
const tilesGeometry = this.interpreter.getAsset(TilesGeometry, 'tilesGeometry');
|
|
54
|
-
const y = tilesGeometry?.getHeight(
|
|
54
|
+
const y = tilesGeometry?.getHeight(row, col, stackIndex, 0, 0) ?? 0;
|
|
55
55
|
target.set(x, y, z);
|
|
56
56
|
return target;
|
|
57
57
|
}
|
package/dist/pillars/index.js
CHANGED
|
@@ -86,7 +86,7 @@ export class PillarMesh extends InstancedMesh {
|
|
|
86
86
|
const tilesGeometry = interpreter.getAsset(TilesGeometry, 'tilesGeometry', loc);
|
|
87
87
|
if (!tilesGeometry)
|
|
88
88
|
continue;
|
|
89
|
-
bottomY = tilesGeometry.getHeight(
|
|
89
|
+
bottomY = tilesGeometry.getHeight(row, col, bottomStackIndex, offsetX, offsetZ);
|
|
90
90
|
}
|
|
91
91
|
let topStackIndex;
|
|
92
92
|
if (topY == null) {
|
|
@@ -100,7 +100,7 @@ export class PillarMesh extends InstancedMesh {
|
|
|
100
100
|
const tilesGeometry = interpreter.getAsset(TilesGeometry, 'tilesGeometry', loc);
|
|
101
101
|
if (!tilesGeometry)
|
|
102
102
|
continue;
|
|
103
|
-
topY = tilesGeometry.getHeight(
|
|
103
|
+
topY = tilesGeometry.getHeight(row, col, topStackIndex, offsetX, offsetZ);
|
|
104
104
|
}
|
|
105
105
|
// Support "negative pillars" by swapping
|
|
106
106
|
if (topY < bottomY) {
|
package/dist/place/index.js
CHANGED
|
@@ -77,7 +77,7 @@ export class PlaceGroup extends Group {
|
|
|
77
77
|
py = opts.fixedY;
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
py = tilesGeometry.getHeight(cell.
|
|
80
|
+
py = tilesGeometry.getHeight(cell.row, cell.col, opts.layerIndex, offsetX, offsetZ, normal);
|
|
81
81
|
}
|
|
82
82
|
const pos = new Vector3(px, py, pz);
|
|
83
83
|
const quat = new Quaternion();
|
|
@@ -111,22 +111,22 @@ export class PlaceGroup extends Group {
|
|
|
111
111
|
const scale = Math.min(sFactorX ?? sFactorZ ?? 1, sFactorZ ?? sFactorX ?? 1);
|
|
112
112
|
return new Vector3(scale, scale, scale);
|
|
113
113
|
};
|
|
114
|
-
for (let
|
|
115
|
-
for (let
|
|
116
|
-
const scatterEntries = interpreter.getCalls([
|
|
114
|
+
for (let row = 0; row < rows; row++) {
|
|
115
|
+
for (let col = 0; col < cols; col++) {
|
|
116
|
+
const scatterEntries = interpreter.getCalls([row, col], {
|
|
117
117
|
scatter: scatterSchema,
|
|
118
118
|
});
|
|
119
|
-
const placeEntries = interpreter.getCalls([
|
|
119
|
+
const placeEntries = interpreter.getCalls([row, col], {
|
|
120
120
|
place: placeSchema,
|
|
121
121
|
});
|
|
122
122
|
if (scatterEntries.length === 0 && placeEntries.length === 0)
|
|
123
123
|
continue;
|
|
124
|
-
const cx = (
|
|
125
|
-
const cz = (
|
|
124
|
+
const cx = (col - cols / 2 + 0.5) * cellSize;
|
|
125
|
+
const cz = (row - rows / 2 + 0.5) * cellSize;
|
|
126
126
|
const half = cellSize * 0.5;
|
|
127
127
|
// scatter: randomized distribution, density is count for now
|
|
128
128
|
for (const [, parsed, callIdx, loc] of scatterEntries) {
|
|
129
|
-
const layerIndex = interpreter.countCalls([
|
|
129
|
+
const layerIndex = interpreter.countCalls([row, col], (c) => c.name === 'ground' || c.name === 'ceiling', 0, callIdx) - 1;
|
|
130
130
|
const prefabName = `${parsed.model}Prefab`;
|
|
131
131
|
const batchBuilder = interpreter.getAsset(PrefabBatchBuilder, prefabName, loc);
|
|
132
132
|
if (!batchBuilder)
|
|
@@ -135,7 +135,7 @@ export class PlaceGroup extends Group {
|
|
|
135
135
|
const usualSize = new Vector3();
|
|
136
136
|
usualSize.copy(batchBuilder.prefabSize);
|
|
137
137
|
const base = hashStringToUint32(parsed.model);
|
|
138
|
-
const seed = hashNumbersToUint32(base,
|
|
138
|
+
const seed = hashNumbersToUint32(base, row, col);
|
|
139
139
|
const rng = createRng(seed);
|
|
140
140
|
// area-based density: items per m^2
|
|
141
141
|
// expected = density * area; stochastic rounding using seeded rng
|
|
@@ -161,7 +161,7 @@ export class PlaceGroup extends Group {
|
|
|
161
161
|
const px = cx + ox;
|
|
162
162
|
const pz = cz + oz;
|
|
163
163
|
const yaw = yawMin === yawMax ? yawMin : yawMin + (yawMax - yawMin) * rng();
|
|
164
|
-
const { pos, quat, scl } = computeTransform(px, pz, { row
|
|
164
|
+
const { pos, quat, scl } = computeTransform(px, pz, { row, col, center: [cx, cz] }, {
|
|
165
165
|
alignMode,
|
|
166
166
|
yaw,
|
|
167
167
|
useFixedY: useFixedY,
|
|
@@ -181,13 +181,13 @@ export class PlaceGroup extends Group {
|
|
|
181
181
|
}
|
|
182
182
|
// place: exact in-cell placement
|
|
183
183
|
for (const [, parsed, callIdx, loc] of placeEntries) {
|
|
184
|
-
const layerIndex = interpreter.countCalls([
|
|
184
|
+
const layerIndex = interpreter.countCalls([row, col], (c) => c.name === 'ground' || c.name === 'ceiling', 0, callIdx) - 1;
|
|
185
185
|
const px = cx + (parsed.offsetX ?? 0);
|
|
186
186
|
const pz = cz + (parsed.offsetZ ?? 0);
|
|
187
187
|
// In place command, yaw is exact, no min/max range
|
|
188
188
|
const yaw = parsed.yaw ?? 0;
|
|
189
189
|
const alignMode = (parsed.align ?? 'up').toLowerCase();
|
|
190
|
-
const { pos, quat, scl } = computeTransform(px, pz, { row
|
|
190
|
+
const { pos, quat, scl } = computeTransform(px, pz, { row, col, center: [cx, cz] }, {
|
|
191
191
|
alignMode,
|
|
192
192
|
yaw,
|
|
193
193
|
useFixedY: parsed.bottomY != null,
|
package/dist/tiles/geometry.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ export type Tile = {
|
|
|
3
3
|
type: string;
|
|
4
4
|
y: number;
|
|
5
5
|
textureId: number;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
row: number;
|
|
7
|
+
col: number;
|
|
8
8
|
};
|
|
9
9
|
export type WallData = {
|
|
10
10
|
topY: number;
|
|
@@ -31,14 +31,14 @@ export declare class TilesGeometry extends BufferGeometry {
|
|
|
31
31
|
left: Array<WallData>;
|
|
32
32
|
}>>, mapSizeX: number, mapSizeZ: number);
|
|
33
33
|
/**
|
|
34
|
-
* @param
|
|
35
|
-
* @param
|
|
34
|
+
* @param row tile grid row index (Z direction)
|
|
35
|
+
* @param col tile grid column index (X direction)
|
|
36
36
|
* @param stackIndex index in the tile stack
|
|
37
37
|
* @param offsetX world unit offset from tile center X
|
|
38
38
|
* @param offsetZ world unit offset from tile center Z
|
|
39
39
|
* @param normalTarget optional target vector that will receive the interpolated face normal at the queried point
|
|
40
40
|
*/
|
|
41
|
-
getHeight(
|
|
41
|
+
getHeight(row: number, col: number, stackIndex?: number, offsetX?: number, offsetZ?: number, normalTarget?: Vector3): number;
|
|
42
42
|
private addVertex;
|
|
43
43
|
private getVertices;
|
|
44
44
|
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,
|
|
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;IA0ElC;;;;;;;OAOG;IACI,SAAS,CACd,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,MAAU,EACnB,OAAO,GAAE,MAAU,EACnB,YAAY,CAAC,EAAE,OAAO;IAqFxB,OAAO,CAAC,SAAS;IAoGjB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,qBAAqB;CAiB9B"}
|
package/dist/tiles/geometry.js
CHANGED
|
@@ -67,8 +67,8 @@ function isBlockingWall(wall, tile, tileSize) {
|
|
|
67
67
|
return isLayerConnectedToWall(wall.topY, wall.bottomY, tile.y, tileSize);
|
|
68
68
|
}
|
|
69
69
|
function getRelevantWallIndices(tile, vertexX, vertexZ, cellSizeX, cellSizeZ) {
|
|
70
|
-
const centerX = computeMeter('x', tile.
|
|
71
|
-
const centerZ = computeMeter('z', tile.
|
|
70
|
+
const centerX = computeMeter('x', tile.col, cellSizeX);
|
|
71
|
+
const centerZ = computeMeter('z', tile.row, cellSizeZ);
|
|
72
72
|
const dx = vertexX - centerX;
|
|
73
73
|
const dz = vertexZ - centerZ;
|
|
74
74
|
const eps = 1e-3;
|
|
@@ -266,17 +266,17 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
266
266
|
.fill(undefined)
|
|
267
267
|
.map(() => new Array(tiles[0].length * 2 + 1).fill(undefined).map(() => []));
|
|
268
268
|
const indices = [];
|
|
269
|
-
for (let
|
|
270
|
-
const tileRow = tiles[
|
|
271
|
-
for (let
|
|
272
|
-
const tileStack = tileRow[
|
|
273
|
-
for (let
|
|
274
|
-
const centerVertexId = this.addVertex(
|
|
269
|
+
for (let row = 0; row < tiles.length; row++) {
|
|
270
|
+
const tileRow = tiles[row];
|
|
271
|
+
for (let col = 0; col < tileRow.length; col++) {
|
|
272
|
+
const tileStack = tileRow[col];
|
|
273
|
+
for (let stackIdx = 0; stackIdx < tileStack.length; stackIdx++) {
|
|
274
|
+
const centerVertexId = this.addVertex(col, row, undefined, tileStack[stackIdx]);
|
|
275
275
|
for (let i = 0; i < 8; i += 2) {
|
|
276
276
|
const a = centerVertexId;
|
|
277
|
-
const b = this.getConnectionVertexId(
|
|
278
|
-
const c = this.getConnectionVertexId(
|
|
279
|
-
const d = this.getConnectionVertexId(
|
|
277
|
+
const b = this.getConnectionVertexId(col, stackIdx, row, (i + 0));
|
|
278
|
+
const c = this.getConnectionVertexId(col, stackIdx, row, (i + 1));
|
|
279
|
+
const d = this.getConnectionVertexId(col, stackIdx, row, ((i + 2) % 8));
|
|
280
280
|
// First triangle
|
|
281
281
|
indices.push(a, c, b);
|
|
282
282
|
// Second triangle
|
|
@@ -294,24 +294,24 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
294
294
|
this.computeTangents();
|
|
295
295
|
}
|
|
296
296
|
/**
|
|
297
|
-
* @param
|
|
298
|
-
* @param
|
|
297
|
+
* @param row tile grid row index (Z direction)
|
|
298
|
+
* @param col tile grid column index (X direction)
|
|
299
299
|
* @param stackIndex index in the tile stack
|
|
300
300
|
* @param offsetX world unit offset from tile center X
|
|
301
301
|
* @param offsetZ world unit offset from tile center Z
|
|
302
302
|
* @param normalTarget optional target vector that will receive the interpolated face normal at the queried point
|
|
303
303
|
*/
|
|
304
|
-
getHeight(
|
|
305
|
-
if (
|
|
306
|
-
throw new Error(`Tile index out of bounds: (
|
|
304
|
+
getHeight(row, col, stackIndex, offsetX = 0, offsetZ = 0, normalTarget) {
|
|
305
|
+
if (col < 0 || col >= this.tiles[0].length || row < 0 || row >= this.tiles.length) {
|
|
306
|
+
throw new Error(`Tile index out of bounds: (row=${row}, col=${col}). Grid size: ${this.tiles.length}x${this.tiles[0].length}`);
|
|
307
307
|
}
|
|
308
|
-
const vertices = this.getVertices(
|
|
309
|
-
const vertex1 = vertices[stackIndex];
|
|
308
|
+
const vertices = this.getVertices(col, row);
|
|
309
|
+
const vertex1 = vertices[stackIndex ?? vertices.length - 1];
|
|
310
310
|
if (vertex1 == null) {
|
|
311
|
-
throw new Error(`No vertex found at stack index ${stackIndex} for tile (
|
|
311
|
+
throw new Error(`No vertex found at stack index "${stackIndex ?? 'any'}" for tile (row=${row}, col=${col}).`);
|
|
312
312
|
}
|
|
313
|
-
const centerX = computeMeter('x',
|
|
314
|
-
const centerZ = computeMeter('z',
|
|
313
|
+
const centerX = computeMeter('x', col, this.cellSizeX) - this.mapSizeX / 2;
|
|
314
|
+
const centerZ = computeMeter('z', row, this.cellSizeZ) - this.mapSizeZ / 2;
|
|
315
315
|
const worldX = centerX + offsetX;
|
|
316
316
|
const worldZ = centerZ + offsetZ;
|
|
317
317
|
let tileOffsetX = offsetX;
|
|
@@ -331,10 +331,10 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
331
331
|
const directionVertex2 = triangleIndex;
|
|
332
332
|
const directionVertex3 = ((triangleIndex + 1) % 8);
|
|
333
333
|
const tile = vertex1.relatedTiles[0];
|
|
334
|
-
const vertex2 = this.getVertices(
|
|
335
|
-
const vertex3 = this.getVertices(
|
|
334
|
+
const vertex2 = this.getVertices(col, row, directionVertex2).find((vertex) => vertex.relatedTiles.includes(tile));
|
|
335
|
+
const vertex3 = this.getVertices(col, row, directionVertex3).find((vertex) => vertex.relatedTiles.includes(tile));
|
|
336
336
|
if (vertex2 == null || vertex3 == null) {
|
|
337
|
-
throw new Error(`Failed to find vertices for triangle at tile (
|
|
337
|
+
throw new Error(`Failed to find vertices for triangle at tile (row=${row}, col=${col}) stack "${stackIndex ?? 'any'}" direction ${triangleIndex}.`);
|
|
338
338
|
}
|
|
339
339
|
const [x1, y1_pos, z1] = vertex1.position;
|
|
340
340
|
const [x2, y2_pos, z2] = vertex2.position;
|
|
@@ -365,10 +365,10 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
365
365
|
}
|
|
366
366
|
return w1 * y1_pos + w2 * y2_pos + w3 * y3_pos;
|
|
367
367
|
}
|
|
368
|
-
addVertex(
|
|
368
|
+
addVertex(col, row, direction, tile, connections) {
|
|
369
369
|
const id = this.idCounter++;
|
|
370
|
-
const xMeter = computeMeter('x',
|
|
371
|
-
const zMeter = computeMeter('z',
|
|
370
|
+
const xMeter = computeMeter('x', col, this.cellSizeX, direction);
|
|
371
|
+
const zMeter = computeMeter('z', row, this.cellSizeZ, direction);
|
|
372
372
|
let filteredRelatedTiles;
|
|
373
373
|
let relatedTiles;
|
|
374
374
|
if (connections == null) {
|
|
@@ -380,7 +380,7 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
380
380
|
const removeCoordinateSet = new Set();
|
|
381
381
|
let blockingTile;
|
|
382
382
|
for (const relatedTile of relatedTiles) {
|
|
383
|
-
const tileWalls = this.walls[relatedTile.
|
|
383
|
+
const tileWalls = this.walls[relatedTile.row]?.[relatedTile.col];
|
|
384
384
|
if (!tileWalls)
|
|
385
385
|
continue;
|
|
386
386
|
const relevantIndices = getRelevantWallIndices(relatedTile, xMeter, zMeter, this.cellSizeX, this.cellSizeZ);
|
|
@@ -392,9 +392,9 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
392
392
|
if (hasBlockingWall) {
|
|
393
393
|
causesBlocking = true;
|
|
394
394
|
// Remove neighbor in direction i
|
|
395
|
-
const
|
|
396
|
-
const
|
|
397
|
-
removeCoordinateSet.add(`${
|
|
395
|
+
const nc = relatedTile.col + directionXOffsetMap[(i * 2)] * 2;
|
|
396
|
+
const nr = relatedTile.row + directionZOffsetMap[(i * 2)] * 2;
|
|
397
|
+
removeCoordinateSet.add(`${nr},${nc}`);
|
|
398
398
|
// Check secondary blocking (diagonal)
|
|
399
399
|
const nextI = (i + 1) % 4;
|
|
400
400
|
const nextDir = wallDirections[nextI];
|
|
@@ -402,9 +402,9 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
402
402
|
const hasNextBlockingWall = tileWalls[nextDir].some((wall) => isBlockingWall(wall, relatedTile, nextWallSize));
|
|
403
403
|
if (hasNextBlockingWall) {
|
|
404
404
|
const diagDir = (i * 2 + 1);
|
|
405
|
-
const
|
|
406
|
-
const
|
|
407
|
-
removeCoordinateSet.add(`${
|
|
405
|
+
const ndc = relatedTile.col + directionXOffsetMap[diagDir] * 2;
|
|
406
|
+
const ndr = relatedTile.row + directionZOffsetMap[diagDir] * 2;
|
|
407
|
+
removeCoordinateSet.add(`${ndr},${ndc}`);
|
|
408
408
|
}
|
|
409
409
|
}
|
|
410
410
|
}
|
|
@@ -412,7 +412,7 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
412
412
|
blockingTile = relatedTile;
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
|
-
filteredRelatedTiles = computeConnectedTiles(blockingTile ?? tile, connections, (newTile) => !removeCoordinateSet.has(`${newTile.
|
|
415
|
+
filteredRelatedTiles = computeConnectedTiles(blockingTile ?? tile, connections, (newTile) => !removeCoordinateSet.has(`${newTile.row},${newTile.col}`));
|
|
416
416
|
}
|
|
417
417
|
const yMeter = filteredRelatedTiles.length === 0
|
|
418
418
|
? tile.y
|
|
@@ -427,7 +427,7 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
427
427
|
this.positions.push(...position);
|
|
428
428
|
const uv = [xMeter, zMeter];
|
|
429
429
|
this.uvs.push(...uv);
|
|
430
|
-
this.getVertices(
|
|
430
|
+
this.getVertices(col, row, direction).push({
|
|
431
431
|
position,
|
|
432
432
|
textureStrength,
|
|
433
433
|
uv,
|
|
@@ -436,27 +436,27 @@ export class TilesGeometry extends BufferGeometry {
|
|
|
436
436
|
});
|
|
437
437
|
return id;
|
|
438
438
|
}
|
|
439
|
-
getVertices(
|
|
440
|
-
let
|
|
441
|
-
let
|
|
439
|
+
getVertices(col, row, direction) {
|
|
440
|
+
let vertexCol = col * 2 + 1;
|
|
441
|
+
let vertexRow = row * 2 + 1;
|
|
442
442
|
if (direction != null) {
|
|
443
|
-
|
|
444
|
-
|
|
443
|
+
vertexCol += directionXOffsetMap[direction] * 2;
|
|
444
|
+
vertexRow += directionZOffsetMap[direction] * 2;
|
|
445
445
|
}
|
|
446
|
-
return this.vertices[
|
|
446
|
+
return this.vertices[vertexRow][vertexCol];
|
|
447
447
|
}
|
|
448
|
-
getConnectionVertexId(
|
|
449
|
-
const tile = this.tiles[
|
|
450
|
-
let vertexId = this.getVertices(
|
|
448
|
+
getConnectionVertexId(col, stackIndex, row, direction) {
|
|
449
|
+
const tile = this.tiles[row][col][stackIndex];
|
|
450
|
+
let vertexId = this.getVertices(col, row, direction).find(({ relatedTiles: connectedTiles }) => connectedTiles.includes(tile))?.id;
|
|
451
451
|
if (vertexId == null) {
|
|
452
452
|
const connections = [];
|
|
453
453
|
for (const [xOffset, zOffset] of directionXConnectionIndexOffsetMap[direction]) {
|
|
454
|
-
connections.push(...(this.xConnections[zOffset +
|
|
454
|
+
connections.push(...(this.xConnections[zOffset + row]?.[xOffset + col] ?? []));
|
|
455
455
|
}
|
|
456
456
|
for (const [xOffset, zOffset] of directionZConnectionIndexOffsetMap[direction]) {
|
|
457
|
-
connections.push(...(this.zConnections[zOffset +
|
|
457
|
+
connections.push(...(this.zConnections[zOffset + row]?.[xOffset + col] ?? []));
|
|
458
458
|
}
|
|
459
|
-
vertexId = this.addVertex(
|
|
459
|
+
vertexId = this.addVertex(col, row, direction, tile, connections);
|
|
460
460
|
}
|
|
461
461
|
return vertexId;
|
|
462
462
|
}
|
package/dist/tiles/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Material, Mesh } from 'three';
|
|
2
2
|
import { Interpreter } from '../interpreter.js';
|
|
3
3
|
import { coerce } from 'zod';
|
|
4
|
+
import { TilesGeometry } from './geometry.js';
|
|
4
5
|
export declare const groundSchema: import("zod").ZodObject<{
|
|
5
6
|
texture: import("zod").ZodString;
|
|
6
7
|
y: coerce.ZodCoercedNumber<unknown>;
|
|
@@ -9,10 +10,8 @@ export declare const ceilingSchema: import("zod").ZodObject<{
|
|
|
9
10
|
texture: import("zod").ZodString;
|
|
10
11
|
y: coerce.ZodCoercedNumber<unknown>;
|
|
11
12
|
}, import("zod/v4/core").$strip>;
|
|
12
|
-
export type TilesMeshOptions = {
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
export declare class TilesMesh extends Mesh {
|
|
13
|
+
export type TilesMeshOptions = {};
|
|
14
|
+
export declare class TilesMesh extends Mesh<TilesGeometry> {
|
|
16
15
|
constructor(interpreter: Interpreter, material?: Material, options?: TilesMeshOptions);
|
|
17
16
|
}
|
|
18
17
|
//# 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,MAAM,EAAkB,MAAM,KAAK,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,MAAM,EAAkB,MAAM,KAAK,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAA;AAMlE,eAAO,MAAM,YAAY;;;gCAAoD,CAAA;AAC7E,eAAO,MAAM,aAAa;;;gCAAoD,CAAA;AAE9E,MAAM,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAyCjC,qBAAa,SAAU,SAAQ,IAAI,CAAC,aAAa,CAAC;gBACpC,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAkC,EAAE,OAAO,GAAE,gBAAqB;CA4GnH"}
|
package/dist/tiles/index.js
CHANGED
|
@@ -34,7 +34,6 @@ function resolveHeights(position, items, interpreter, reverse) {
|
|
|
34
34
|
}
|
|
35
35
|
export class TilesMesh extends Mesh {
|
|
36
36
|
constructor(interpreter, material = new MeshBasicMaterial(), options = {}) {
|
|
37
|
-
super();
|
|
38
37
|
const rows = interpreter.getRows();
|
|
39
38
|
const cols = interpreter.getCols();
|
|
40
39
|
// Helper to manage texture indices on the fly
|
|
@@ -58,21 +57,21 @@ export class TilesMesh extends Mesh {
|
|
|
58
57
|
left: [],
|
|
59
58
|
right: [],
|
|
60
59
|
})));
|
|
61
|
-
for (let
|
|
62
|
-
for (let
|
|
60
|
+
for (let row = 0; row < rows; row++) {
|
|
61
|
+
for (let col = 0; col < cols; col++) {
|
|
63
62
|
// 1. Collect all entries for this cell
|
|
64
|
-
const calls = Array.from(interpreter.getCalls([
|
|
63
|
+
const calls = Array.from(interpreter.getCalls([row, col], {
|
|
65
64
|
ground: groundSchema,
|
|
66
65
|
ceiling: ceilingSchema,
|
|
67
66
|
wall: wallSchema,
|
|
68
67
|
}));
|
|
69
68
|
// 2. Compute wall heights using the helper
|
|
70
|
-
const bottomYs = resolveHeights([
|
|
69
|
+
const bottomYs = resolveHeights([row, col], calls.map(([_1, parsed, _2, loc]) => ({
|
|
71
70
|
loc,
|
|
72
71
|
layerY: 'y' in parsed ? parsed.y : undefined,
|
|
73
72
|
explicitWallY: 'bottomY' in parsed ? parsed.bottomY : undefined,
|
|
74
73
|
})), interpreter, false);
|
|
75
|
-
const topYs = resolveHeights([
|
|
74
|
+
const topYs = resolveHeights([row, col], calls.map(([_1, parsed, _2, loc]) => ({
|
|
76
75
|
loc,
|
|
77
76
|
layerY: 'y' in parsed ? parsed.y : undefined,
|
|
78
77
|
explicitWallY: 'topY' in parsed ? parsed.topY : undefined,
|
|
@@ -91,18 +90,18 @@ export class TilesMesh extends Mesh {
|
|
|
91
90
|
[bottomY, topY] = [topY, bottomY];
|
|
92
91
|
}
|
|
93
92
|
const dir = parsed.dir;
|
|
94
|
-
if (walls[
|
|
95
|
-
walls[
|
|
93
|
+
if (walls[row][col][dir]) {
|
|
94
|
+
walls[row][col][dir].push({ bottomY, topY });
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
else {
|
|
99
98
|
// Ground or Ceiling
|
|
100
|
-
tiles[
|
|
99
|
+
tiles[row][col].push({
|
|
101
100
|
type: name,
|
|
102
101
|
y: parsed.y,
|
|
103
102
|
textureId: getTextureIndex(parsed.texture, loc),
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
row,
|
|
104
|
+
col,
|
|
106
105
|
});
|
|
107
106
|
}
|
|
108
107
|
}
|
|
@@ -110,7 +109,7 @@ export class TilesMesh extends Mesh {
|
|
|
110
109
|
}
|
|
111
110
|
const cellSize = interpreter.getCellSize();
|
|
112
111
|
const geometry = new TilesGeometry(tiles, walls, cols * cellSize, rows * cellSize);
|
|
113
|
-
|
|
112
|
+
super(geometry);
|
|
114
113
|
interpreter.setAsset('tilesGeometry', geometry);
|
|
115
114
|
// Build texture array from interpreter assets using encountered material names in insertion order
|
|
116
115
|
const texturesInOrder = Array.from(textureIndex.keys()).sort((a, b) => textureIndex.get(a) - textureIndex.get(b));
|
package/dist/walls/index.js
CHANGED
|
@@ -129,7 +129,7 @@ export function computeWallVerticalBounds(interpreter, tilesGeometry, row, col,
|
|
|
129
129
|
if (bottomLayer) {
|
|
130
130
|
const offX = sX + (col - bottomLayer.col) * cellSize;
|
|
131
131
|
const offZ = sZ + (row - bottomLayer.row) * cellSize;
|
|
132
|
-
yStart[k] = tilesGeometry.getHeight(bottomLayer.
|
|
132
|
+
yStart[k] = tilesGeometry.getHeight(bottomLayer.row, bottomLayer.col, bottomLayer.layerIdx, offX, offZ);
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
135
|
yStart[k] = parsed.bottomY;
|
|
@@ -138,7 +138,7 @@ export function computeWallVerticalBounds(interpreter, tilesGeometry, row, col,
|
|
|
138
138
|
if (topLayer) {
|
|
139
139
|
const offX = sX + (col - topLayer.col) * cellSize;
|
|
140
140
|
const offZ = sZ + (row - topLayer.row) * cellSize;
|
|
141
|
-
yEnd[k] = tilesGeometry.getHeight(topLayer.
|
|
141
|
+
yEnd[k] = tilesGeometry.getHeight(topLayer.row, topLayer.col, topLayer.layerIdx, offX, offZ);
|
|
142
142
|
}
|
|
143
143
|
else {
|
|
144
144
|
yEnd[k] = parsed.topY;
|
package/dist/water/index.js
CHANGED
|
@@ -6,24 +6,24 @@ export class WaterMesh extends Mesh {
|
|
|
6
6
|
constructor(interpreter, options = {}) {
|
|
7
7
|
const rows = interpreter.getRows();
|
|
8
8
|
const cols = interpreter.getCols();
|
|
9
|
-
// Build tiles[
|
|
9
|
+
// Build tiles[row][col] => Array<Tile>, containing only water tiles
|
|
10
10
|
const tiles = new Array(rows)
|
|
11
11
|
.fill(undefined)
|
|
12
12
|
.map(() => new Array(cols).fill(undefined).map(() => []));
|
|
13
|
-
for (let
|
|
14
|
-
for (let
|
|
15
|
-
const entries = interpreter.getCalls([
|
|
13
|
+
for (let row = 0; row < rows; row++) {
|
|
14
|
+
for (let col = 0; col < cols; col++) {
|
|
15
|
+
const entries = interpreter.getCalls([row, col], { water: waterSchema });
|
|
16
16
|
const stack = [];
|
|
17
17
|
for (const [, parsed] of entries) {
|
|
18
18
|
stack.push({
|
|
19
19
|
type: "water",
|
|
20
20
|
y: parsed.y,
|
|
21
21
|
textureId: 0,
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
row,
|
|
23
|
+
col,
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
-
tiles[
|
|
26
|
+
tiles[row][col] = stack;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
const cellSize = interpreter.getCellSize();
|