Skip to content

Commit 00534a7

Browse files
Yuri Pourreyuripourre
authored andcommitted
Export particles and sounds
1 parent bbd1579 commit 00534a7

File tree

2 files changed

+169
-25
lines changed

2 files changed

+169
-25
lines changed

editor/src/editor/layout/graph/export.ts

Lines changed: 168 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -72,33 +72,21 @@ export async function exportNode(editor: Editor, node: Node): Promise<void> {
7272
// Store original doNotSerialize values
7373
const originalDoNotSerialize = new Map<Node, boolean>();
7474

75-
// Temporarily set doNotSerialize = true for all nodes except the ones we want to include
76-
scene.meshes.forEach((mesh) => {
77-
originalDoNotSerialize.set(mesh, mesh.doNotSerialize);
78-
mesh.doNotSerialize = !nodesToInclude.has(mesh);
79-
});
80-
81-
scene.lights.forEach((light) => {
82-
originalDoNotSerialize.set(light, light.doNotSerialize);
83-
light.doNotSerialize = !nodesToInclude.has(light);
84-
});
75+
exportMeshes(scene, nodesToInclude, originalDoNotSerialize);
76+
exportLights(scene, nodesToInclude, originalDoNotSerialize);
77+
exportCameras(scene, nodesToInclude, originalDoNotSerialize);
78+
exportTransformNodes(scene, nodesToInclude, originalDoNotSerialize);
8579

86-
scene.cameras.forEach((camera) => {
87-
originalDoNotSerialize.set(camera, camera.doNotSerialize);
88-
camera.doNotSerialize = !nodesToInclude.has(camera);
89-
});
90-
91-
scene.transformNodes.forEach((transformNode) => {
92-
originalDoNotSerialize.set(transformNode, transformNode.doNotSerialize);
93-
transformNode.doNotSerialize = !nodesToInclude.has(transformNode);
94-
});
80+
const originalParticleSystems = exportParticleSystems(scene, nodesToInclude);
81+
const originalSoundTracks = exportSounds(scene, nodesToInclude);
9582

9683
// Serialize the filtered scene
9784
const data = await SceneSerializer.SerializeAsync(scene);
9885

99-
// Restore original doNotSerialize values
100-
originalDoNotSerialize.forEach((value, node) => {
101-
node.doNotSerialize = value;
86+
// Restore original scene state
87+
restoreSceneState(scene, originalDoNotSerialize, {
88+
originalParticleSystems,
89+
originalSoundTracks
10290
});
10391

10492
await writeJSON(filePath, data, JSON_CONFIG);
@@ -112,3 +100,161 @@ export async function exportNode(editor: Editor, node: Node): Promise<void> {
112100
}
113101
}
114102
}
103+
104+
/**
105+
* Restores the original scene state after export.
106+
* @param scene The scene to restore
107+
* @param originalDoNotSerialize Map containing original serialization states
108+
* @param exportData Data needed for restoration
109+
*/
110+
function restoreSceneState(
111+
scene: any,
112+
originalDoNotSerialize: Map<Node, boolean>,
113+
exportData: { originalParticleSystems: any[]; originalSoundTracks: any[] }
114+
): void {
115+
// Restore original doNotSerialize values
116+
originalDoNotSerialize.forEach((value, node) => {
117+
node.doNotSerialize = value;
118+
});
119+
120+
// Restore particle systems
121+
scene.particleSystems.length = 0;
122+
exportData.originalParticleSystems.forEach((ps: any) =>
123+
scene.particleSystems.push(ps)
124+
);
125+
126+
// Restore soundtracks
127+
scene.soundTracks = exportData.originalSoundTracks;
128+
}
129+
130+
/**
131+
* Configures mesh nodes for export.
132+
* @param scene The scene containing the meshes
133+
* @param nodesToInclude Set of nodes to include in the export
134+
* @param originalDoNotSerialize Map to store original serialization state
135+
*/
136+
function exportMeshes(
137+
scene: any,
138+
nodesToInclude: Set<Node>,
139+
originalDoNotSerialize: Map<Node, boolean>
140+
): void {
141+
scene.meshes.forEach((mesh: Node) => {
142+
originalDoNotSerialize.set(mesh, mesh.doNotSerialize);
143+
mesh.doNotSerialize = !nodesToInclude.has(mesh);
144+
});
145+
}
146+
147+
/**
148+
* Configures light nodes for export.
149+
* @param scene The scene containing the lights
150+
* @param nodesToInclude Set of nodes to include in the export
151+
* @param originalDoNotSerialize Map to store original serialization state
152+
*/
153+
function exportLights(
154+
scene: any,
155+
nodesToInclude: Set<Node>,
156+
originalDoNotSerialize: Map<Node, boolean>
157+
): void {
158+
scene.lights.forEach((light: Node) => {
159+
originalDoNotSerialize.set(light, light.doNotSerialize);
160+
light.doNotSerialize = !nodesToInclude.has(light);
161+
});
162+
}
163+
164+
/**
165+
* Configures camera nodes for export.
166+
* @param scene The scene containing the cameras
167+
* @param nodesToInclude Set of nodes to include in the export
168+
* @param originalDoNotSerialize Map to store original serialization state
169+
*/
170+
function exportCameras(
171+
scene: any,
172+
nodesToInclude: Set<Node>,
173+
originalDoNotSerialize: Map<Node, boolean>
174+
): void {
175+
scene.cameras.forEach((camera: Node) => {
176+
originalDoNotSerialize.set(camera, camera.doNotSerialize);
177+
camera.doNotSerialize = !nodesToInclude.has(camera);
178+
});
179+
}
180+
181+
/**
182+
* Configures transform nodes for export.
183+
* @param scene The scene containing the transform nodes
184+
* @param nodesToInclude Set of nodes to include in the export
185+
* @param originalDoNotSerialize Map to store original serialization state
186+
*/
187+
function exportTransformNodes(
188+
scene: any,
189+
nodesToInclude: Set<Node>,
190+
originalDoNotSerialize: Map<Node, boolean>
191+
): void {
192+
scene.transformNodes.forEach((transformNode: Node) => {
193+
originalDoNotSerialize.set(transformNode, transformNode.doNotSerialize);
194+
transformNode.doNotSerialize = !nodesToInclude.has(transformNode);
195+
});
196+
}
197+
198+
/**
199+
* Filters particle systems for export based on their attached nodes.
200+
* @param scene The scene containing the particle systems
201+
* @param nodesToInclude Set of nodes to include in the export
202+
* @returns The original array of particle systems (for restoration)
203+
*/
204+
function exportParticleSystems(scene: any, nodesToInclude: Set<Node>): Array<any> {
205+
// Save original particle systems
206+
const originalParticleSystems = scene.particleSystems.slice();
207+
208+
// Filter particle systems to only include those attached to our nodes
209+
const particlesToKeep = originalParticleSystems.filter((ps: any) => {
210+
const emitter = ps.emitter;
211+
return emitter && nodesToInclude.has(emitter as Node);
212+
});
213+
214+
// Replace the scene's particle systems with only those we want to include
215+
scene.particleSystems.length = 0;
216+
particlesToKeep.forEach((ps: any) => scene.particleSystems.push(ps));
217+
218+
return originalParticleSystems;
219+
}
220+
221+
/**
222+
* Filters sounds for export based on their attached nodes.
223+
* @param scene The scene containing the sounds
224+
* @param nodesToInclude Set of nodes to include in the export
225+
* @returns The original array of soundtracks (for restoration)
226+
*/
227+
function exportSounds(scene: any, nodesToInclude: Set<Node>): Array<any> {
228+
// Handle sounds - filter out sounds not attached to our nodes
229+
let originalSoundTracks: any[] = [];
230+
231+
if (scene.soundTracks) {
232+
// Store original soundtracks to restore later
233+
originalSoundTracks = scene.soundTracks.slice();
234+
235+
// Filter each soundtrack to only include sounds attached to our nodes
236+
const filteredSoundTracks = scene.soundTracks.map((soundtrack: any) => {
237+
// Create a new sound collection with only the sounds attached to our nodes
238+
const filteredSoundCollection = soundtrack.soundCollection.filter((sound: any) => {
239+
if (sound.spatialSound && sound.metadata && sound.metadata.connectedMeshName) {
240+
// Check if the connected mesh name matches any of our nodes
241+
for (const meshNode of nodesToInclude) {
242+
if (meshNode.name === sound.metadata.connectedMeshName) {
243+
return true;
244+
}
245+
}
246+
}
247+
return false;
248+
});
249+
250+
// Replace the original sound collection with our filtered one
251+
soundtrack.soundCollection = filteredSoundCollection;
252+
return soundtrack;
253+
}).filter((st: any) => st.soundCollection.length > 0); // Remove empty soundtracks
254+
255+
// Replace scene soundtracks with our filtered ones
256+
scene.soundTracks = filteredSoundTracks;
257+
}
258+
259+
return originalSoundTracks;
260+
}

editor/src/editor/layout/graph/graph.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export class EditorGraphContextMenu extends Component<IEditorGraphContextMenuPro
8686
<ContextMenuItem onClick={() => this.props.editor.layout.graph.copySelectedNodes()}>
8787
Copy <ContextMenuShortcut>{platform() === "darwin" ? "⌘+C" : "CTRL+C"}</ContextMenuShortcut>
8888
</ContextMenuItem>
89+
8990
{isNode(this.props.object) && (
9091
<ContextMenuItem onClick={() => this.props.editor.layout.graph.pasteSelectedNodes(this.props.object)}>
9192
Paste <ContextMenuShortcut>{platform() === "darwin" ? "⌘+V" : "CTRL+V"}</ContextMenuShortcut>
@@ -98,14 +99,11 @@ export class EditorGraphContextMenu extends Component<IEditorGraphContextMenuPro
9899

99100
<ContextMenuSeparator />
100101

101-
<ContextMenuItem onClick={() => this._cloneNode(this.props.object)}>Clone</ContextMenuItem>
102-
103102
{isNode(this.props.object) && !isScene(this.props.object) && (
104103
<ContextMenuItem onClick={() => exportNode(this.props.editor, this.props.object)}>Export Node (.babylon)</ContextMenuItem>
105104
)}
106105

107106
<ContextMenuSeparator />
108-
>>>>>>> 616af57c (Add menu item to export .babylon)
109107
</>
110108
)}
111109

0 commit comments

Comments
 (0)