@quake2ts/test-utils 0.0.819 → 0.0.824
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/index.cjs +139 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -22
- package/dist/index.d.ts +53 -22
- package/dist/index.js +137 -0
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/src/engine/mocks/renderer.ts +1 -0
- package/src/shared/bsp.ts +181 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quake2ts/test-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.824",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"serve-handler": "^6.1.6",
|
|
56
56
|
"vitest": "^1.6.0",
|
|
57
57
|
"webgpu": "^0.3.8",
|
|
58
|
-
"@quake2ts/engine": "^0.0.
|
|
59
|
-
"@quake2ts/
|
|
60
|
-
"@quake2ts/
|
|
61
|
-
"@quake2ts/
|
|
58
|
+
"@quake2ts/engine": "^0.0.824",
|
|
59
|
+
"@quake2ts/server": "0.0.824",
|
|
60
|
+
"@quake2ts/shared": "0.0.824",
|
|
61
|
+
"@quake2ts/game": "0.0.824"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|
|
64
64
|
"@quake2ts/engine": {
|
|
@@ -104,20 +104,20 @@
|
|
|
104
104
|
"@types/upng-js": "^2.1.5",
|
|
105
105
|
"@webgpu/types": "^0.1.68",
|
|
106
106
|
"fake-indexeddb": "^6.0.0",
|
|
107
|
-
"jsdom": "^27.4.0",
|
|
108
107
|
"gl-matrix": "^3.4.4",
|
|
108
|
+
"jsdom": "^27.4.0",
|
|
109
109
|
"pixelmatch": "^7.1.0",
|
|
110
110
|
"playwright": "^1.57.0",
|
|
111
111
|
"pngjs": "^7.0.0",
|
|
112
|
+
"serve-handler": "^6.1.6",
|
|
112
113
|
"tsup": "^8.5.1",
|
|
113
114
|
"typescript": "^5.9.3",
|
|
114
115
|
"vitest": "^4.0.16",
|
|
115
|
-
"serve-handler": "^6.1.6",
|
|
116
116
|
"webgpu": "^0.3.8",
|
|
117
|
-
"@quake2ts/
|
|
118
|
-
"@quake2ts/
|
|
119
|
-
"@quake2ts/
|
|
120
|
-
"@quake2ts/shared": "0.0.
|
|
117
|
+
"@quake2ts/game": "0.0.824",
|
|
118
|
+
"@quake2ts/engine": "^0.0.824",
|
|
119
|
+
"@quake2ts/server": "0.0.824",
|
|
120
|
+
"@quake2ts/shared": "0.0.824"
|
|
121
121
|
},
|
|
122
122
|
"dependencies": {
|
|
123
123
|
"upng-js": "^2.1.0"
|
|
@@ -77,6 +77,7 @@ export function createMockRenderer(overrides?: Partial<Renderer>): Renderer {
|
|
|
77
77
|
setLodBias: vi.fn(),
|
|
78
78
|
setAreaPortalState: vi.fn(),
|
|
79
79
|
renderInstanced: vi.fn(),
|
|
80
|
+
uploadBspGeometry: vi.fn().mockReturnValue({ surfaces: [], lightmaps: [] }),
|
|
80
81
|
dispose: vi.fn(),
|
|
81
82
|
...overrides,
|
|
82
83
|
};
|
package/src/shared/bsp.ts
CHANGED
|
@@ -5,9 +5,27 @@ import {
|
|
|
5
5
|
type CollisionPlane,
|
|
6
6
|
type CollisionNode,
|
|
7
7
|
type CollisionLeaf,
|
|
8
|
-
CONTENTS_SOLID
|
|
9
|
-
type Vec3
|
|
8
|
+
CONTENTS_SOLID
|
|
10
9
|
} from '@quake2ts/shared';
|
|
10
|
+
// Avoid named imports for Vec3 from shared to avoid conflict with engine tuple type
|
|
11
|
+
import * as SharedMath from '@quake2ts/shared';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type BspMap,
|
|
15
|
+
type BspFace,
|
|
16
|
+
type BspTexInfo,
|
|
17
|
+
type BspNode,
|
|
18
|
+
type BspLeaf,
|
|
19
|
+
type BspModel,
|
|
20
|
+
type BspEdge,
|
|
21
|
+
type BspEntity,
|
|
22
|
+
type BspHeader,
|
|
23
|
+
type BspEntities,
|
|
24
|
+
type BspPlane,
|
|
25
|
+
type BspLightmapInfo,
|
|
26
|
+
type BspLeafLists,
|
|
27
|
+
type BspData
|
|
28
|
+
} from '@quake2ts/engine';
|
|
11
29
|
|
|
12
30
|
/**
|
|
13
31
|
* Creates a collision plane with the specified normal and distance.
|
|
@@ -17,7 +35,7 @@ import {
|
|
|
17
35
|
* @param dist - The distance from the origin.
|
|
18
36
|
* @returns A CollisionPlane object.
|
|
19
37
|
*/
|
|
20
|
-
export function makePlane(normal: Vec3, dist: number): CollisionPlane {
|
|
38
|
+
export function makePlane(normal: SharedMath.Vec3, dist: number): CollisionPlane {
|
|
21
39
|
return {
|
|
22
40
|
normal,
|
|
23
41
|
dist,
|
|
@@ -128,7 +146,7 @@ export function makeLeafModel(brushes: CollisionBrush[]): CollisionModel {
|
|
|
128
146
|
* @param contents - Content flags (default: CONTENTS_SOLID).
|
|
129
147
|
* @returns A CollisionBrush object.
|
|
130
148
|
*/
|
|
131
|
-
export function makeBrushFromMinsMaxs(mins: Vec3, maxs: Vec3, contents = CONTENTS_SOLID): CollisionBrush {
|
|
149
|
+
export function makeBrushFromMinsMaxs(mins: SharedMath.Vec3, maxs: SharedMath.Vec3, contents = CONTENTS_SOLID): CollisionBrush {
|
|
132
150
|
const planes = [
|
|
133
151
|
makePlane({ x: 1, y: 0, z: 0 }, maxs.x),
|
|
134
152
|
makePlane({ x: -1, y: 0, z: 0 }, -mins.x),
|
|
@@ -143,3 +161,162 @@ export function makeBrushFromMinsMaxs(mins: Vec3, maxs: Vec3, contents = CONTENT
|
|
|
143
161
|
sides: planes.map((plane) => ({ plane, surfaceFlags: 0 })),
|
|
144
162
|
};
|
|
145
163
|
}
|
|
164
|
+
|
|
165
|
+
// --- Visual Test Helpers ---
|
|
166
|
+
|
|
167
|
+
// BspVec3 matches the tuple type used in engine assets
|
|
168
|
+
export type BspVec3 = [number, number, number];
|
|
169
|
+
|
|
170
|
+
export interface TestBspSurface {
|
|
171
|
+
vertices: BspVec3[];
|
|
172
|
+
texInfo?: Partial<BspTexInfo>;
|
|
173
|
+
lightmap?: Uint8Array;
|
|
174
|
+
lightmapInfo?: BspLightmapInfo;
|
|
175
|
+
styles?: [number, number, number, number];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface TestBspMapOptions {
|
|
179
|
+
surfaces?: TestBspSurface[];
|
|
180
|
+
entities?: BspEntity[];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Creates a minimal valid BspMap for testing rendering.
|
|
185
|
+
*
|
|
186
|
+
* @param options - Configuration for the test BSP map.
|
|
187
|
+
* @returns A BspMap object populated with the requested surfaces.
|
|
188
|
+
*/
|
|
189
|
+
export function createTestBspMap(options: TestBspMapOptions = {}): BspMap {
|
|
190
|
+
const vertices: BspVec3[] = [];
|
|
191
|
+
const edges: BspEdge[] = [];
|
|
192
|
+
const surfEdges: number[] = []; // Using number[] to match push usage, converted to Int32Array later
|
|
193
|
+
const faces: BspFace[] = [];
|
|
194
|
+
const texInfos: BspTexInfo[] = [];
|
|
195
|
+
const lightMapInfo: (BspLightmapInfo | undefined)[] = [];
|
|
196
|
+
|
|
197
|
+
// Aggregate lightmap data
|
|
198
|
+
let lightMapDataSize = 0;
|
|
199
|
+
if (options.surfaces) {
|
|
200
|
+
for (const surface of options.surfaces) {
|
|
201
|
+
if (surface.lightmap) {
|
|
202
|
+
lightMapDataSize += surface.lightmap.length;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const lightMaps = new Uint8Array(lightMapDataSize);
|
|
207
|
+
let currentLightMapOffset = 0;
|
|
208
|
+
|
|
209
|
+
if (options.surfaces) {
|
|
210
|
+
for (const surface of options.surfaces) {
|
|
211
|
+
// Add vertices and create edges
|
|
212
|
+
const firstEdge = surfEdges.length;
|
|
213
|
+
const startVertexIndex = vertices.length;
|
|
214
|
+
|
|
215
|
+
for (const v of surface.vertices) {
|
|
216
|
+
vertices.push(v);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (let i = 0; i < surface.vertices.length; i++) {
|
|
220
|
+
const v1 = startVertexIndex + i;
|
|
221
|
+
const v2 = startVertexIndex + ((i + 1) % surface.vertices.length);
|
|
222
|
+
edges.push({ vertices: [v1, v2] });
|
|
223
|
+
surfEdges.push(edges.length - 1); // Positive index for standard winding
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Add TexInfo
|
|
227
|
+
const defaultTexInfo: BspTexInfo = {
|
|
228
|
+
s: [1, 0, 0], sOffset: 0,
|
|
229
|
+
t: [0, 1, 0], tOffset: 0,
|
|
230
|
+
flags: 0, value: 0,
|
|
231
|
+
texture: 'test_texture',
|
|
232
|
+
nextTexInfo: -1
|
|
233
|
+
};
|
|
234
|
+
const texInfo: BspTexInfo = { ...defaultTexInfo, ...surface.texInfo };
|
|
235
|
+
texInfos.push(texInfo);
|
|
236
|
+
|
|
237
|
+
// Handle Lightmap
|
|
238
|
+
let lightOffset = -1;
|
|
239
|
+
let info: BspLightmapInfo | undefined = undefined;
|
|
240
|
+
|
|
241
|
+
if (surface.lightmap) {
|
|
242
|
+
lightOffset = currentLightMapOffset;
|
|
243
|
+
lightMaps.set(surface.lightmap, lightOffset);
|
|
244
|
+
info = { offset: lightOffset, length: surface.lightmap.length };
|
|
245
|
+
currentLightMapOffset += surface.lightmap.length;
|
|
246
|
+
}
|
|
247
|
+
lightMapInfo.push(info);
|
|
248
|
+
|
|
249
|
+
faces.push({
|
|
250
|
+
planeIndex: 0, // Dummy plane
|
|
251
|
+
side: 0,
|
|
252
|
+
firstEdge,
|
|
253
|
+
numEdges: surface.vertices.length,
|
|
254
|
+
texInfo: texInfos.length - 1,
|
|
255
|
+
styles: surface.styles ?? [255, 255, 255, 255], // Default styles
|
|
256
|
+
lightOffset
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Minimal valid BSP structure
|
|
262
|
+
const header: BspHeader = { version: 38, lumps: new Map() };
|
|
263
|
+
const entities: BspEntities = {
|
|
264
|
+
raw: '',
|
|
265
|
+
entities: options.entities || [],
|
|
266
|
+
worldspawn: undefined,
|
|
267
|
+
getUniqueClassnames: () => []
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const planes: BspPlane[] = [{ normal: [0, 0, 1], dist: 0, type: 0 }]; // Dummy plane
|
|
271
|
+
const nodes: BspNode[] = [];
|
|
272
|
+
const leafs: BspLeaf[] = [{
|
|
273
|
+
contents: 0, cluster: 0, area: 0,
|
|
274
|
+
mins: [-1000, -1000, -1000], maxs: [1000, 1000, 1000],
|
|
275
|
+
firstLeafFace: 0, numLeafFaces: faces.length,
|
|
276
|
+
firstLeafBrush: 0, numLeafBrushes: 0
|
|
277
|
+
}];
|
|
278
|
+
const leafLists: BspLeafLists = {
|
|
279
|
+
leafFaces: [faces.map((_, i) => i)],
|
|
280
|
+
leafBrushes: [[]]
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const models: BspModel[] = [{
|
|
284
|
+
mins: [-1000, -1000, -1000], maxs: [1000, 1000, 1000], origin: [0,0,0],
|
|
285
|
+
headNode: 0, firstFace: 0, numFaces: faces.length
|
|
286
|
+
}];
|
|
287
|
+
|
|
288
|
+
const data: BspData = {
|
|
289
|
+
header, entities, planes, vertices, nodes, texInfo: texInfos, faces,
|
|
290
|
+
lightMaps, lightMapInfo, leafs, leafLists, edges, surfEdges: Int32Array.from(surfEdges),
|
|
291
|
+
models, brushes: [], brushSides: [], visibility: undefined, areas: [], areaPortals: []
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// Create the BspMap with methods
|
|
295
|
+
return {
|
|
296
|
+
...data,
|
|
297
|
+
pickEntity: () => null,
|
|
298
|
+
findLeaf: () => leafs[0],
|
|
299
|
+
calculatePVS: () => undefined
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Creates a simple solid color lightmap of specified dimensions.
|
|
305
|
+
*
|
|
306
|
+
* @param width - Width of the lightmap (usually small, e.g. 16x16)
|
|
307
|
+
* @param height - Height of the lightmap
|
|
308
|
+
* @param r - Red component (0-255)
|
|
309
|
+
* @param g - Green component (0-255)
|
|
310
|
+
* @param b - Blue component (0-255)
|
|
311
|
+
* @returns Uint8Array containing RGB data
|
|
312
|
+
*/
|
|
313
|
+
export function createTestLightmap(width: number, height: number, r: number, g: number, b: number): Uint8Array {
|
|
314
|
+
const size = width * height * 3;
|
|
315
|
+
const data = new Uint8Array(size);
|
|
316
|
+
for (let i = 0; i < size; i+=3) {
|
|
317
|
+
data[i] = r;
|
|
318
|
+
data[i+1] = g;
|
|
319
|
+
data[i+2] = b;
|
|
320
|
+
}
|
|
321
|
+
return data;
|
|
322
|
+
}
|