react-three-game 0.0.100 → 0.0.101
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.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/tools/assetviewer/page.js +70 -58
- package/dist/tools/dragdrop/DragDropLoader.d.ts +3 -0
- package/dist/tools/dragdrop/DragDropLoader.js +183 -44
- package/dist/tools/dragdrop/index.d.ts +1 -1
- package/dist/tools/dragdrop/index.js +1 -1
- package/dist/tools/dragdrop/modelLoader.js +2 -0
- package/dist/tools/prefabeditor/EditorUI.js +7 -8
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +3 -0
- package/dist/tools/prefabeditor/PrefabEditor.js +28 -11
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +2 -0
- package/dist/tools/prefabeditor/PrefabRoot.js +51 -35
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +20 -0
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +5 -0
- package/dist/tools/prefabeditor/components/ComponentRegistry.js +31 -0
- package/dist/tools/prefabeditor/components/DataComponent.js +1 -0
- package/dist/tools/prefabeditor/components/EnvironmentComponent.js +1 -0
- package/dist/tools/prefabeditor/components/GeometryComponent.js +1 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.d.ts +1 -0
- package/dist/tools/prefabeditor/components/MaterialComponent.js +89 -52
- package/dist/tools/prefabeditor/components/ModelComponent.js +45 -3
- package/dist/tools/prefabeditor/components/SpriteComponent.js +1 -0
- package/dist/tools/prefabeditor/components/TransformComponent.js +1 -0
- package/dist/tools/prefabeditor/modelPrefab.d.ts +16 -0
- package/dist/tools/prefabeditor/modelPrefab.js +180 -0
- package/dist/tools/prefabeditor/prefabStore.d.ts +1 -0
- package/dist/tools/prefabeditor/prefabStore.js +75 -42
- package/package.json +1 -1
|
@@ -17,7 +17,7 @@ import { PrefabEditorMode, PrefabRoot } from "./PrefabRoot";
|
|
|
17
17
|
import EditorUI from "./EditorUI";
|
|
18
18
|
import { base, toolbar } from "./styles";
|
|
19
19
|
import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, exportGLBData, focusCameraOnObject, regenerateIds } from "./utils";
|
|
20
|
-
import {
|
|
20
|
+
import { loadDroppedAssets } from "../dragdrop";
|
|
21
21
|
import { denormalizePrefab, createImageNode, createModelNode, createNode } from './prefab';
|
|
22
22
|
import { createPrefabStore, PrefabStoreProvider } from "./prefabStore";
|
|
23
23
|
function isObjectAttachedToRoot(root, object) {
|
|
@@ -31,6 +31,19 @@ function isObjectAttachedToRoot(root, object) {
|
|
|
31
31
|
}
|
|
32
32
|
return false;
|
|
33
33
|
}
|
|
34
|
+
export function isAbsoluteAssetPath(path) {
|
|
35
|
+
return (path.startsWith("data:") ||
|
|
36
|
+
path.startsWith("http://") ||
|
|
37
|
+
path.startsWith("https://"));
|
|
38
|
+
}
|
|
39
|
+
export function resolvePrefabAssetPath(basePath, file) {
|
|
40
|
+
if (isAbsoluteAssetPath(file))
|
|
41
|
+
return file;
|
|
42
|
+
return file.startsWith("/") ? `${basePath}${file}` : `${basePath}/${file}`;
|
|
43
|
+
}
|
|
44
|
+
export function getPrefabAssetRef(assetRef, folder) {
|
|
45
|
+
return isAbsoluteAssetPath(assetRef) ? assetRef : `${folder}/${assetRef}`;
|
|
46
|
+
}
|
|
34
47
|
function SelectionHelper({ object }) {
|
|
35
48
|
const objectRef = useRef(null);
|
|
36
49
|
objectRef.current = object;
|
|
@@ -91,6 +104,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
91
104
|
const getRoot = useCallback(() => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null; }, []);
|
|
92
105
|
const getObject = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
93
106
|
const getHandle = useCallback((nodeId, kind) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getHandle(nodeId, kind)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
107
|
+
const getModel = useCallback((path) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getModel(path)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
94
108
|
const scheduleHistory = useCallback((nextPrefab) => {
|
|
95
109
|
if (historyTimeoutRef.current) {
|
|
96
110
|
clearTimeout(historyTimeoutRef.current);
|
|
@@ -124,6 +138,9 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
124
138
|
const update = useCallback((id, fn) => {
|
|
125
139
|
mutate(s => s.updateNode(id, fn));
|
|
126
140
|
}, [mutate]);
|
|
141
|
+
const replaceNode = useCallback((id, node) => {
|
|
142
|
+
mutate(s => s.replaceNode(id, node));
|
|
143
|
+
}, [mutate]);
|
|
127
144
|
const remove = useCallback((id) => {
|
|
128
145
|
mutate(s => s.deleteNode(id));
|
|
129
146
|
}, [mutate]);
|
|
@@ -320,21 +337,19 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
320
337
|
e.stopPropagation();
|
|
321
338
|
}
|
|
322
339
|
function handleDrop(e) {
|
|
323
|
-
var _a;
|
|
324
340
|
e.preventDefault();
|
|
325
341
|
e.stopPropagation();
|
|
326
|
-
const files = ((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) ? Array.from(e.dataTransfer.files) : [];
|
|
327
342
|
const scene = prefabRootRef.current;
|
|
328
|
-
void
|
|
329
|
-
onModelLoaded: (model, filename) => {
|
|
330
|
-
const path =
|
|
343
|
+
void loadDroppedAssets(e.dataTransfer, {
|
|
344
|
+
onModelLoaded: (model, filename, file) => {
|
|
345
|
+
const path = getPrefabAssetRef(filename, 'models');
|
|
331
346
|
scene === null || scene === void 0 ? void 0 : scene.addModel(path, model);
|
|
332
|
-
add(createModelNode(path,
|
|
347
|
+
add(createModelNode(path, file.name.replace(/\.[^.]+$/, '')));
|
|
333
348
|
},
|
|
334
|
-
onTextureLoaded: (texture, filename) => {
|
|
335
|
-
const path =
|
|
349
|
+
onTextureLoaded: (texture, filename, file) => {
|
|
350
|
+
const path = getPrefabAssetRef(filename, 'textures');
|
|
336
351
|
scene === null || scene === void 0 ? void 0 : scene.addTexture(path, texture);
|
|
337
|
-
add(createImageNode(path,
|
|
352
|
+
add(createImageNode(path, file.name.replace(/\.[^.]+$/, '')));
|
|
338
353
|
},
|
|
339
354
|
onLoadError: error => {
|
|
340
355
|
console.error('Drop asset error:', error);
|
|
@@ -356,8 +371,10 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
356
371
|
get: getNode,
|
|
357
372
|
getObject,
|
|
358
373
|
getHandle,
|
|
374
|
+
getModel,
|
|
359
375
|
add,
|
|
360
376
|
update,
|
|
377
|
+
replaceNode,
|
|
361
378
|
remove,
|
|
362
379
|
duplicate,
|
|
363
380
|
move,
|
|
@@ -365,7 +382,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode =
|
|
|
365
382
|
addModel: (path, model) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model); },
|
|
366
383
|
addTexture: (path, texture) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture); },
|
|
367
384
|
addSound: (path, sound) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addSound(path, sound); },
|
|
368
|
-
}), [add, duplicate, getHandle, getNode, getObject, getRoot, mode, move, remove, replace, update]);
|
|
385
|
+
}), [add, duplicate, getHandle, getModel, getNode, getObject, getRoot, mode, move, remove, replace, replaceNode, update]);
|
|
369
386
|
const editorRefValue = useMemo(() => (Object.assign(Object.assign({}, sceneValue), { save: getPrefab, load: loadPrefab, undo,
|
|
370
387
|
redo, screenshot: handleScreenshot, exportGLB: handleExportGLB, exportGLBData: handleExportGLBData, clearSelection })), [clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, redo, sceneValue, undo]);
|
|
371
388
|
useImperativeHandle(ref, () => editorRefValue, [editorRefValue]);
|
|
@@ -15,8 +15,10 @@ export interface Scene {
|
|
|
15
15
|
get(id: string): GameObjectType | null;
|
|
16
16
|
getObject(id: string): Object3D | null;
|
|
17
17
|
getHandle<T = unknown>(id: string, kind: string): T | null;
|
|
18
|
+
getModel(path: string): Object3D | null;
|
|
18
19
|
add(node: GameObjectType, parentId?: string): GameObjectType;
|
|
19
20
|
update(id: string, fn: (node: PrefabNode) => PrefabNode): void;
|
|
21
|
+
replaceNode(id: string, node: GameObjectType): void;
|
|
20
22
|
remove(id: string): void;
|
|
21
23
|
duplicate(id: string): string | null;
|
|
22
24
|
move(draggedId: string, targetId: string, position: "before" | "inside"): void;
|
|
@@ -31,14 +31,16 @@ const EMPTY_TEXTURES = {};
|
|
|
31
31
|
const EMPTY_SOUNDS = {};
|
|
32
32
|
const EMPTY_NODE_COMPONENTS = {
|
|
33
33
|
geometry: undefined,
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
materials: [],
|
|
35
|
+
models: [],
|
|
36
36
|
sprite: undefined,
|
|
37
37
|
clickEventName: null,
|
|
38
38
|
composition: [],
|
|
39
39
|
};
|
|
40
40
|
/** Resolve a relative or absolute asset file path against a base path. */
|
|
41
41
|
function resolveAssetPath(basePath, file) {
|
|
42
|
+
if (file.startsWith("data:"))
|
|
43
|
+
return file;
|
|
42
44
|
if (file.startsWith("http://") || file.startsWith("https://"))
|
|
43
45
|
return file;
|
|
44
46
|
return file.startsWith("/") ? `${basePath}${file}` : `${basePath}/${file}`;
|
|
@@ -101,6 +103,9 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
101
103
|
const availableModels = useMemo(() => (Object.assign(Object.assign({}, models), injectedModels)), [models, injectedModels]);
|
|
102
104
|
const availableTextures = useMemo(() => (Object.assign(Object.assign({}, textures), injectedTextures)), [textures, injectedTextures]);
|
|
103
105
|
const availableSounds = useMemo(() => (Object.assign(Object.assign({}, sounds), injectedSounds)), [sounds, injectedSounds]);
|
|
106
|
+
const getModel = useCallback((path) => { var _a; return (_a = availableModels[path]) !== null && _a !== void 0 ? _a : null; }, [availableModels]);
|
|
107
|
+
const getTexture = useCallback((path) => { var _a; return (_a = availableTextures[path]) !== null && _a !== void 0 ? _a : null; }, [availableTextures]);
|
|
108
|
+
const getSound = useCallback((path) => { var _a; return (_a = availableSounds[path]) !== null && _a !== void 0 ? _a : null; }, [availableSounds]);
|
|
104
109
|
const getObject = useCallback((id) => {
|
|
105
110
|
var _a;
|
|
106
111
|
return (_a = objectRefs.current[id]) !== null && _a !== void 0 ? _a : null;
|
|
@@ -139,12 +144,14 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
139
144
|
get: getNode,
|
|
140
145
|
getObject,
|
|
141
146
|
getHandle,
|
|
147
|
+
getModel,
|
|
142
148
|
add: (node, parentId) => {
|
|
143
149
|
const state = resolvedStore.getState();
|
|
144
150
|
state.addChild(parentId !== null && parentId !== void 0 ? parentId : state.rootId, node);
|
|
145
151
|
return node;
|
|
146
152
|
},
|
|
147
153
|
update: (id, fn) => resolvedStore.getState().updateNode(id, fn),
|
|
154
|
+
replaceNode: (id, node) => resolvedStore.getState().replaceNode(id, node),
|
|
148
155
|
remove: (id) => resolvedStore.getState().deleteNode(id),
|
|
149
156
|
duplicate: (id) => resolvedStore.getState().duplicateNode(id),
|
|
150
157
|
move: (draggedId, targetId, position) => resolvedStore.getState().moveNode(draggedId, targetId, position),
|
|
@@ -155,7 +162,7 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
155
162
|
soundManager.setBuffer(path, sound);
|
|
156
163
|
setInjectedSounds(prev => (Object.assign(Object.assign({}, prev), { [path]: sound })));
|
|
157
164
|
},
|
|
158
|
-
}), [editMode, getHandle, getNode, getObject, resolvedStore, rootId]);
|
|
165
|
+
}), [editMode, getHandle, getModel, getNode, getObject, resolvedStore, rootId]);
|
|
159
166
|
useImperativeHandle(ref, () => sceneValue, [sceneValue]);
|
|
160
167
|
const registerRef = useCallback((id, obj) => {
|
|
161
168
|
objectRefs.current[id] = obj;
|
|
@@ -234,11 +241,11 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
234
241
|
registerHandle,
|
|
235
242
|
getHandle,
|
|
236
243
|
getObject,
|
|
237
|
-
getModel
|
|
238
|
-
getTexture
|
|
239
|
-
getSound
|
|
244
|
+
getModel,
|
|
245
|
+
getTexture,
|
|
246
|
+
getSound,
|
|
240
247
|
getAssetRevision: () => `${Object.keys(availableTextures).sort().join('|')}::${Object.keys(availableModels).sort().join('|')}`,
|
|
241
|
-
}), [registerHandle, getHandle, getObject, availableModels, availableTextures
|
|
248
|
+
}), [registerHandle, getHandle, getObject, getModel, getTexture, getSound, availableModels, availableTextures]);
|
|
242
249
|
const handleNodeClick = useCallback((event, nodeId, fallbackObject) => {
|
|
243
250
|
const node = resolvedStore.getState().nodesById[nodeId];
|
|
244
251
|
if (!node)
|
|
@@ -266,8 +273,8 @@ function analyzeNodeComponents(node) {
|
|
|
266
273
|
var _a, _b, _c, _d;
|
|
267
274
|
let bufferGeometry;
|
|
268
275
|
let geometry;
|
|
269
|
-
|
|
270
|
-
|
|
276
|
+
const materials = [];
|
|
277
|
+
const models = [];
|
|
271
278
|
let sprite;
|
|
272
279
|
const composition = [];
|
|
273
280
|
for (const [key, component] of Object.entries((_a = node.components) !== null && _a !== void 0 ? _a : {})) {
|
|
@@ -283,10 +290,10 @@ function analyzeNodeComponents(node) {
|
|
|
283
290
|
geometry = component;
|
|
284
291
|
break;
|
|
285
292
|
case "Material":
|
|
286
|
-
|
|
293
|
+
materials.push({ key, component });
|
|
287
294
|
break;
|
|
288
295
|
case "Model":
|
|
289
|
-
|
|
296
|
+
models.push({ key, component });
|
|
290
297
|
break;
|
|
291
298
|
case "Sprite":
|
|
292
299
|
sprite = component;
|
|
@@ -306,10 +313,10 @@ function analyzeNodeComponents(node) {
|
|
|
306
313
|
}
|
|
307
314
|
return {
|
|
308
315
|
geometry: bufferGeometry !== null && bufferGeometry !== void 0 ? bufferGeometry : geometry,
|
|
309
|
-
|
|
310
|
-
|
|
316
|
+
materials,
|
|
317
|
+
models,
|
|
311
318
|
sprite,
|
|
312
|
-
clickEventName: (_d = (_c = (_b = getClickEventName(bufferGeometry)) !== null && _b !== void 0 ? _b : getClickEventName(geometry)) !== null && _c !== void 0 ? _c : getClickEventName(
|
|
319
|
+
clickEventName: (_d = (_c = (_b = getClickEventName(bufferGeometry)) !== null && _b !== void 0 ? _b : getClickEventName(geometry)) !== null && _c !== void 0 ? _c : models.map(({ component }) => getClickEventName(component)).find(Boolean)) !== null && _d !== void 0 ? _d : getClickEventName(sprite),
|
|
313
320
|
composition,
|
|
314
321
|
};
|
|
315
322
|
}
|
|
@@ -361,7 +368,7 @@ function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef,
|
|
|
361
368
|
const analyzedComponents = useMemo(() => gameObject ? analyzeNodeComponents(gameObject) : EMPTY_NODE_COMPONENTS, [gameObject]);
|
|
362
369
|
const localTransform = getNodeTransformProps(gameObject);
|
|
363
370
|
const isLocked = Boolean(gameObject === null || gameObject === void 0 ? void 0 : gameObject.locked);
|
|
364
|
-
const modelUrl = (_b = (_a = analyzedComponents.
|
|
371
|
+
const modelUrl = (_b = (_a = analyzedComponents.models[0]) === null || _a === void 0 ? void 0 : _a.component.properties) === null || _b === void 0 ? void 0 : _b.filename;
|
|
365
372
|
const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl), [gameObject, modelUrl, parentMatrix]);
|
|
366
373
|
const groupRef = useRef(null);
|
|
367
374
|
const handleGroupRef = useCallback((object) => {
|
|
@@ -498,35 +505,47 @@ function getNodeTransformProps(node) {
|
|
|
498
505
|
};
|
|
499
506
|
}
|
|
500
507
|
function renderNodeContent(analyzedComponents, loadedModels, primaryClickHandlers, childNodes) {
|
|
501
|
-
var _a, _b, _c, _d;
|
|
508
|
+
var _a, _b, _c, _d, _e, _f;
|
|
502
509
|
const geometry = analyzedComponents.geometry;
|
|
503
|
-
const
|
|
504
|
-
const
|
|
510
|
+
const models = analyzedComponents.models;
|
|
511
|
+
const materials = analyzedComponents.materials;
|
|
512
|
+
const primaryMaterial = (_a = materials[0]) === null || _a === void 0 ? void 0 : _a.component;
|
|
505
513
|
const sprite = analyzedComponents.sprite;
|
|
506
|
-
const shapeKind = (sprite === null || sprite === void 0 ? void 0 : sprite.type) ? 'sprite' : (geometry === null || geometry === void 0 ? void 0 : geometry.type) ? 'mesh' :
|
|
514
|
+
const shapeKind = (sprite === null || sprite === void 0 ? void 0 : sprite.type) ? 'sprite' : (geometry === null || geometry === void 0 ? void 0 : geometry.type) ? 'mesh' : models.length > 0 ? 'model' : 'none';
|
|
507
515
|
let materialContent = null;
|
|
508
516
|
switch (shapeKind) {
|
|
509
517
|
case 'sprite': {
|
|
510
|
-
const materialDef = (
|
|
511
|
-
if ((
|
|
512
|
-
const materialIsSprite =
|
|
513
|
-
materialContent = (_jsx(materialDef.View, { properties: Object.assign(Object.assign({},
|
|
518
|
+
const materialDef = (primaryMaterial === null || primaryMaterial === void 0 ? void 0 : primaryMaterial.type) ? getComponentDef(primaryMaterial.type) : undefined;
|
|
519
|
+
if ((primaryMaterial === null || primaryMaterial === void 0 ? void 0 : primaryMaterial.properties) && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View)) {
|
|
520
|
+
const materialIsSprite = primaryMaterial.properties.materialType === 'sprite';
|
|
521
|
+
materialContent = (_jsx(materialDef.View, { properties: Object.assign(Object.assign({}, primaryMaterial.properties), { materialType: 'sprite', attach: 'material', transparent: materialIsSprite ? primaryMaterial.properties.transparent : true, depthTest: materialIsSprite ? primaryMaterial.properties.depthTest : false, depthWrite: materialIsSprite ? primaryMaterial.properties.depthWrite : false }) }, (_c = (_b = materials[0]) === null || _b === void 0 ? void 0 : _b.key) !== null && _c !== void 0 ? _c : 'material'));
|
|
514
522
|
}
|
|
515
523
|
break;
|
|
516
524
|
}
|
|
517
525
|
case 'mesh': {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
526
|
+
materialContent = materials.map(({ key, component }) => {
|
|
527
|
+
const materialDef = component.type ? getComponentDef(component.type) : undefined;
|
|
528
|
+
if (!component.properties || !(materialDef === null || materialDef === void 0 ? void 0 : materialDef.View))
|
|
529
|
+
return null;
|
|
530
|
+
return _jsx(materialDef.View, { properties: component.properties }, key);
|
|
531
|
+
});
|
|
522
532
|
break;
|
|
523
533
|
}
|
|
524
534
|
}
|
|
525
535
|
let primaryContent = null;
|
|
526
536
|
let contentChildren = childNodes;
|
|
537
|
+
const modelContent = models.map(({ key, component }) => {
|
|
538
|
+
var _a;
|
|
539
|
+
if (!component.type || ((_a = component.properties) === null || _a === void 0 ? void 0 : _a.instanced) || !isNodeReady(component, loadedModels))
|
|
540
|
+
return null;
|
|
541
|
+
const modelDef = getComponentDef(component.type);
|
|
542
|
+
if (!(modelDef === null || modelDef === void 0 ? void 0 : modelDef.View))
|
|
543
|
+
return null;
|
|
544
|
+
return _jsx(modelDef.View, { properties: component.properties }, key);
|
|
545
|
+
});
|
|
527
546
|
switch (shapeKind) {
|
|
528
547
|
case 'sprite': {
|
|
529
|
-
primaryContent = (_jsxs("sprite", Object.assign({ center: (
|
|
548
|
+
primaryContent = (_jsxs("sprite", Object.assign({ center: (_e = (_d = sprite === null || sprite === void 0 ? void 0 : sprite.properties) === null || _d === void 0 ? void 0 : _d.center) !== null && _e !== void 0 ? _e : [0.5, 0.5] }, primaryClickHandlers, { children: [materialContent, childNodes] })));
|
|
530
549
|
contentChildren = null;
|
|
531
550
|
break;
|
|
532
551
|
}
|
|
@@ -535,22 +554,19 @@ function renderNodeContent(analyzedComponents, loadedModels, primaryClickHandler
|
|
|
535
554
|
if (!(geometry === null || geometry === void 0 ? void 0 : geometry.properties) || !(geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View))
|
|
536
555
|
break;
|
|
537
556
|
const GeometryView = geometryDef.View;
|
|
538
|
-
const geometryProperties = (
|
|
557
|
+
const geometryProperties = (_f = geometry.properties) !== null && _f !== void 0 ? _f : {};
|
|
539
558
|
const visible = geometryProperties.visible !== false;
|
|
540
559
|
primaryContent = (_jsxs("mesh", Object.assign({ visible: visible, castShadow: visible && geometryProperties.castShadow !== false, receiveShadow: visible && geometryProperties.receiveShadow !== false }, primaryClickHandlers, { children: [_jsx(GeometryView, { properties: geometry.properties }), materialContent] })));
|
|
541
560
|
break;
|
|
542
561
|
}
|
|
543
562
|
case 'model': {
|
|
544
|
-
if (!(model === null || model === void 0 ? void 0 : model.type) || ((_d = model.properties) === null || _d === void 0 ? void 0 : _d.instanced) || !isNodeReady(model, loadedModels))
|
|
545
|
-
break;
|
|
546
|
-
const modelDef = getComponentDef(model.type);
|
|
547
|
-
if (!(modelDef === null || modelDef === void 0 ? void 0 : modelDef.View))
|
|
548
|
-
break;
|
|
549
|
-
const modelContent = _jsx(modelDef.View, { properties: model.properties });
|
|
550
563
|
primaryContent = primaryClickHandlers ? _jsx("group", Object.assign({}, primaryClickHandlers, { children: modelContent })) : modelContent;
|
|
551
564
|
break;
|
|
552
565
|
}
|
|
553
566
|
}
|
|
567
|
+
if (shapeKind !== 'model' && modelContent.some(Boolean)) {
|
|
568
|
+
primaryContent = _jsxs(_Fragment, { children: [primaryContent, modelContent] });
|
|
569
|
+
}
|
|
554
570
|
let content = _jsxs(_Fragment, { children: [primaryContent, contentChildren] });
|
|
555
571
|
for (const { key, View, properties } of analyzedComponents.composition) {
|
|
556
572
|
content = (_jsx(View, { properties: properties, children: content }, key));
|
|
@@ -15,6 +15,18 @@ const DEFAULT_TRIANGLE_UVS = [
|
|
|
15
15
|
function isFiniteNumberArray(value) {
|
|
16
16
|
return Array.isArray(value) && value.every(entry => typeof entry === 'number' && Number.isFinite(entry));
|
|
17
17
|
}
|
|
18
|
+
function isGeometryGroupArray(value) {
|
|
19
|
+
return Array.isArray(value) && value.every(group => {
|
|
20
|
+
if (!group || typeof group !== 'object' || Array.isArray(group))
|
|
21
|
+
return false;
|
|
22
|
+
const entry = group;
|
|
23
|
+
return typeof entry.start === 'number'
|
|
24
|
+
&& Number.isFinite(entry.start)
|
|
25
|
+
&& typeof entry.count === 'number'
|
|
26
|
+
&& Number.isFinite(entry.count)
|
|
27
|
+
&& (entry.materialIndex === undefined || typeof entry.materialIndex === 'number');
|
|
28
|
+
});
|
|
29
|
+
}
|
|
18
30
|
function normalizeNumberArray(value, fallback) {
|
|
19
31
|
return isFiniteNumberArray(value) ? value : fallback;
|
|
20
32
|
}
|
|
@@ -62,7 +74,13 @@ function BufferGeometryComponentView({ properties }) {
|
|
|
62
74
|
const indexArray = getIndexArray(indices);
|
|
63
75
|
const hasNormals = normals.length >= 3 && normals.length % 3 === 0;
|
|
64
76
|
const hasUvs = uvs.length >= 2 && uvs.length % 2 === 0;
|
|
77
|
+
const groups = isGeometryGroupArray(properties.groups) ? properties.groups : [];
|
|
65
78
|
return (_jsxs("bufferGeometry", { onUpdate: (geometry) => {
|
|
79
|
+
geometry.clearGroups();
|
|
80
|
+
groups.forEach(group => {
|
|
81
|
+
var _a;
|
|
82
|
+
geometry.addGroup(group.start, group.count, (_a = group.materialIndex) !== null && _a !== void 0 ? _a : 0);
|
|
83
|
+
});
|
|
66
84
|
if (properties.computeVertexNormals !== false && !hasNormals) {
|
|
67
85
|
geometry.computeVertexNormals();
|
|
68
86
|
}
|
|
@@ -72,6 +90,7 @@ function BufferGeometryComponentView({ properties }) {
|
|
|
72
90
|
}
|
|
73
91
|
const BufferGeometryComponent = {
|
|
74
92
|
name: 'BufferGeometry',
|
|
93
|
+
disableSiblingComposition: 'geometry',
|
|
75
94
|
Editor: BufferGeometryComponentEditor,
|
|
76
95
|
View: BufferGeometryComponentView,
|
|
77
96
|
defaultProperties: {
|
|
@@ -79,6 +98,7 @@ const BufferGeometryComponent = {
|
|
|
79
98
|
indices: DEFAULT_TRIANGLE_INDICES,
|
|
80
99
|
normals: [],
|
|
81
100
|
uvs: DEFAULT_TRIANGLE_UVS,
|
|
101
|
+
groups: [],
|
|
82
102
|
computeVertexNormals: true,
|
|
83
103
|
emitClickEvent: false,
|
|
84
104
|
clickEventName: '',
|
|
@@ -21,6 +21,8 @@ export interface ComponentViewProps<P = Record<string, unknown>> {
|
|
|
21
21
|
}
|
|
22
22
|
export interface Component {
|
|
23
23
|
name: string;
|
|
24
|
+
/** Set when this component occupies a single slot on a node. Use a string to share a slot across component types. */
|
|
25
|
+
disableSiblingComposition?: boolean | string;
|
|
24
26
|
Editor: FC<{
|
|
25
27
|
node?: GameObject;
|
|
26
28
|
component: ComponentData;
|
|
@@ -35,4 +37,7 @@ export interface Component {
|
|
|
35
37
|
export declare function registerComponent(component: Component): void;
|
|
36
38
|
export declare function getComponentDef(name: string): Component | undefined;
|
|
37
39
|
export declare function getAllComponentDefs(): Record<string, Component>;
|
|
40
|
+
export declare function getSiblingCompositionSlot(componentName: string, disableSiblingComposition: boolean | string | undefined): string | null;
|
|
41
|
+
export declare function canAddComponentToNode(node: GameObject, component: Component | undefined, allComponents?: Record<string, Component>): boolean;
|
|
42
|
+
export declare function getNextComponentKey(node: GameObject, componentName: string): string;
|
|
38
43
|
export declare function getComponentAssetRefs(componentType: string, properties: Record<string, unknown>): AssetRef[];
|
|
@@ -14,6 +14,37 @@ export function getComponentDef(name) {
|
|
|
14
14
|
export function getAllComponentDefs() {
|
|
15
15
|
return Object.assign({}, REGISTRY);
|
|
16
16
|
}
|
|
17
|
+
export function getSiblingCompositionSlot(componentName, disableSiblingComposition) {
|
|
18
|
+
if (!disableSiblingComposition)
|
|
19
|
+
return null;
|
|
20
|
+
return typeof disableSiblingComposition === "string" ? disableSiblingComposition : componentName;
|
|
21
|
+
}
|
|
22
|
+
export function canAddComponentToNode(node, component, allComponents = REGISTRY) {
|
|
23
|
+
var _a;
|
|
24
|
+
if (!component)
|
|
25
|
+
return false;
|
|
26
|
+
const slot = getSiblingCompositionSlot(component.name, component.disableSiblingComposition);
|
|
27
|
+
if (!slot)
|
|
28
|
+
return true;
|
|
29
|
+
return !Object.values((_a = node.components) !== null && _a !== void 0 ? _a : {}).some(entry => {
|
|
30
|
+
if (!(entry === null || entry === void 0 ? void 0 : entry.type))
|
|
31
|
+
return false;
|
|
32
|
+
const sibling = allComponents[entry.type];
|
|
33
|
+
return getSiblingCompositionSlot(entry.type, sibling === null || sibling === void 0 ? void 0 : sibling.disableSiblingComposition) === slot;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function getNextComponentKey(node, componentName) {
|
|
37
|
+
var _a;
|
|
38
|
+
const baseKey = componentName.toLowerCase();
|
|
39
|
+
const existingKeys = new Set(Object.keys((_a = node.components) !== null && _a !== void 0 ? _a : {}));
|
|
40
|
+
let nextKey = baseKey;
|
|
41
|
+
let index = 1;
|
|
42
|
+
while (existingKeys.has(nextKey)) {
|
|
43
|
+
nextKey = `${baseKey}_${index}`;
|
|
44
|
+
index += 1;
|
|
45
|
+
}
|
|
46
|
+
return nextKey;
|
|
47
|
+
}
|
|
17
48
|
export function getComponentAssetRefs(componentType, properties) {
|
|
18
49
|
var _a, _b;
|
|
19
50
|
const component = REGISTRY[componentType];
|
|
@@ -10,6 +10,7 @@ function EnvironmentView({ properties, children, }) {
|
|
|
10
10
|
}
|
|
11
11
|
const EnvironmentComponent = {
|
|
12
12
|
name: 'Environment',
|
|
13
|
+
disableSiblingComposition: true,
|
|
13
14
|
Editor: ({ component, onUpdate }) => (_jsxs(FieldGroup, { children: [_jsx(NumberField, { name: "intensity", label: "Intensity", values: component.properties, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 }), _jsx(NumberField, { name: "resolution", label: "Resolution", values: component.properties, onChange: onUpdate, min: 64, step: 64, fallback: 256 })] })),
|
|
14
15
|
View: EnvironmentView,
|
|
15
16
|
defaultProperties: {},
|
|
@@ -11,6 +11,7 @@ declare module '@react-three/fiber' {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
export interface MaterialProps extends Omit<MeshStandardMaterialProperties & MeshBasicMaterialProperties, 'args' | 'normalScale' | 'side'> {
|
|
14
|
+
attach?: string;
|
|
14
15
|
materialType?: 'standard' | 'basic' | 'sprite';
|
|
15
16
|
transmission?: number;
|
|
16
17
|
thickness?: number;
|