123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- import { SceneSerializer } from "./sceneSerializer.js";
- import { Mesh } from "../Meshes/mesh.js";
- import { Light } from "../Lights/light.js";
- import { Camera } from "../Cameras/camera.js";
- import { Skeleton } from "../Bones/skeleton.js";
- import { Material } from "../Materials/material.js";
- import { MultiMaterial } from "../Materials/multiMaterial.js";
- import { TransformNode } from "../Meshes/transformNode.js";
- import { ParticleSystem } from "../Particles/particleSystem.js";
- import { MorphTargetManager } from "../Morph/morphTargetManager.js";
- import { ShadowGenerator } from "../Lights/Shadows/shadowGenerator.js";
- import { PostProcess } from "../PostProcesses/postProcess.js";
- import { Texture } from "../Materials/Textures/texture.js";
- import { SerializationHelper } from "./decorators.serialization.js";
- /**
- * Class used to record delta files between 2 scene states
- */
- export class SceneRecorder {
- constructor() {
- this._trackedScene = null;
- }
- /**
- * Track a given scene. This means the current scene state will be considered the original state
- * @param scene defines the scene to track
- */
- track(scene) {
- this._trackedScene = scene;
- SerializationHelper.AllowLoadingUniqueId = true;
- this._savedJSON = SceneSerializer.Serialize(scene);
- SerializationHelper.AllowLoadingUniqueId = false;
- }
- /**
- * Get the delta between current state and original state
- * @returns a any containing the delta
- */
- getDelta() {
- if (!this._trackedScene) {
- return null;
- }
- const currentForceSerializeBuffers = Texture.ForceSerializeBuffers;
- Texture.ForceSerializeBuffers = false;
- SerializationHelper.AllowLoadingUniqueId = true;
- const newJSON = SceneSerializer.Serialize(this._trackedScene);
- SerializationHelper.AllowLoadingUniqueId = false;
- const deltaJSON = {};
- for (const node in newJSON) {
- this._compareCollections(node, this._savedJSON[node], newJSON[node], deltaJSON);
- }
- Texture.ForceSerializeBuffers = currentForceSerializeBuffers;
- return deltaJSON;
- }
- _compareArray(key, original, current, deltaJSON) {
- if (original.length === 0 && current.length === 0) {
- return true;
- }
- // Numbers?
- if ((original.length && !isNaN(original[0])) || (current.length && !isNaN(current[0]))) {
- if (original.length !== current.length) {
- return false;
- }
- if (original.length === 0) {
- return true;
- }
- for (let index = 0; index < original.length; index++) {
- if (original[index] !== current[index]) {
- deltaJSON[key] = current;
- return false;
- }
- }
- return true;
- }
- // let's use uniqueId to find similar objects
- const originalUniqueIds = [];
- for (let index = 0; index < original.length; index++) {
- const originalObject = original[index];
- const originalUniqueId = originalObject.uniqueId;
- originalUniqueIds.push(originalUniqueId);
- // Look for that object in current state
- const currentObjects = current.filter((c) => c.uniqueId === originalUniqueId);
- if (currentObjects.length) {
- // We have a candidate
- const currentObject = currentObjects[0];
- const newObject = {};
- if (!this._compareObjects(originalObject, currentObject, newObject)) {
- if (!deltaJSON[key]) {
- deltaJSON[key] = [];
- }
- newObject.__state = {
- id: currentObject.id || currentObject.name,
- };
- deltaJSON[key].push(newObject);
- }
- }
- else {
- // We need to delete
- const newObject = {
- __state: {
- deleteId: originalObject.id || originalObject.name,
- },
- };
- if (!deltaJSON[key]) {
- deltaJSON[key] = [];
- }
- deltaJSON[key].push(newObject);
- }
- }
- // Checking for new objects
- for (let index = 0; index < current.length; index++) {
- const currentObject = current[index];
- const currentUniqueId = currentObject.uniqueId;
- // Object was added
- if (originalUniqueIds.indexOf(currentUniqueId) === -1) {
- if (!deltaJSON[key]) {
- deltaJSON[key] = [];
- }
- deltaJSON[key].push(currentObject);
- }
- }
- return true;
- }
- _compareObjects(originalObjet, currentObject, deltaJSON) {
- let aDifferenceWasFound = false;
- for (const prop in originalObjet) {
- if (!Object.prototype.hasOwnProperty.call(originalObjet, prop)) {
- continue;
- }
- const originalValue = originalObjet[prop];
- const currentValue = currentObject[prop];
- let diffFound = false;
- if (Array.isArray(originalValue)) {
- diffFound = JSON.stringify(originalValue) !== JSON.stringify(currentValue);
- }
- else if (!isNaN(originalValue) || Object.prototype.toString.call(originalValue) == "[object String]") {
- diffFound = originalValue !== currentValue;
- }
- else if (typeof originalValue === "object" && typeof currentValue === "object") {
- const newObject = {};
- if (!this._compareObjects(originalValue, currentValue, newObject)) {
- deltaJSON[prop] = newObject;
- aDifferenceWasFound = true;
- }
- }
- if (diffFound) {
- aDifferenceWasFound = true;
- deltaJSON[prop] = currentValue;
- }
- }
- return !aDifferenceWasFound;
- }
- _compareCollections(key, original, current, deltaJSON) {
- // Same ?
- if (original === current) {
- return;
- }
- if (original && current) {
- // Array?
- if (Array.isArray(original) && Array.isArray(current)) {
- if (this._compareArray(key, original, current, deltaJSON)) {
- return;
- }
- }
- else if (typeof original === "object" && typeof current === "object") {
- // Object
- const newObject = {};
- if (!this._compareObjects(original, current, newObject)) {
- deltaJSON[key] = newObject;
- }
- return;
- }
- }
- }
- static GetShadowGeneratorById(scene, id) {
- const allGenerators = scene.lights.map((l) => l.getShadowGenerators());
- for (const generators of allGenerators) {
- if (generators) {
- const iterator = generators.values();
- for (let key = iterator.next(); key.done !== true; key = iterator.next()) {
- const generator = key.value;
- if (generator && generator.id === id) {
- return generator;
- }
- }
- }
- }
- return null;
- }
- /**
- * Apply a given delta to a given scene
- * @param deltaJSON defines the JSON containing the delta
- * @param scene defines the scene to apply the delta to
- */
- static ApplyDelta(deltaJSON, scene) {
- if (typeof deltaJSON === "string") {
- deltaJSON = JSON.parse(deltaJSON);
- }
- // Scene
- const anyScene = scene;
- for (const prop in deltaJSON) {
- const source = deltaJSON[prop];
- const property = anyScene[prop];
- if (Array.isArray(property) || prop === "shadowGenerators") {
- // Restore array
- switch (prop) {
- case "cameras":
- this._ApplyDeltaForEntity(source, scene, scene.getCameraById.bind(scene), (data) => Camera.Parse(data, scene));
- break;
- case "lights":
- this._ApplyDeltaForEntity(source, scene, scene.getLightById.bind(scene), (data) => Light.Parse(data, scene));
- break;
- case "shadowGenerators":
- this._ApplyDeltaForEntity(source, scene, (id) => this.GetShadowGeneratorById(scene, id), (data) => ShadowGenerator.Parse(data, scene));
- break;
- case "meshes":
- this._ApplyDeltaForEntity(source, scene, scene.getMeshById.bind(scene), (data) => Mesh.Parse(data, scene, ""));
- break;
- case "skeletons":
- this._ApplyDeltaForEntity(source, scene, scene.getSkeletonById.bind(scene), (data) => Skeleton.Parse(data, scene));
- break;
- case "materials":
- this._ApplyDeltaForEntity(source, scene, scene.getMaterialById.bind(scene), (data) => Material.Parse(data, scene, ""));
- break;
- case "multiMaterials":
- this._ApplyDeltaForEntity(source, scene, scene.getMaterialById.bind(scene), (data) => MultiMaterial.Parse(data, scene, ""));
- break;
- case "transformNodes":
- this._ApplyDeltaForEntity(source, scene, scene.getTransformNodeById.bind(scene), (data) => TransformNode.Parse(data, scene, ""));
- break;
- case "particleSystems":
- this._ApplyDeltaForEntity(source, scene, scene.getParticleSystemById.bind(scene), (data) => ParticleSystem.Parse(data, scene, ""));
- break;
- case "morphTargetManagers":
- this._ApplyDeltaForEntity(source, scene, scene.getMorphTargetById.bind(scene), (data) => MorphTargetManager.Parse(data, scene));
- break;
- case "postProcesses":
- this._ApplyDeltaForEntity(source, scene, scene.getPostProcessByName.bind(scene), (data) => PostProcess.Parse(data, scene, ""));
- break;
- }
- }
- else if (!isNaN(property)) {
- anyScene[prop] = source;
- }
- else if (property.fromArray) {
- property.fromArray(source);
- }
- }
- }
- static _ApplyPropertiesToEntity(deltaJSON, entity) {
- for (const prop in deltaJSON) {
- const source = deltaJSON[prop];
- const property = entity[prop];
- if (property === undefined) {
- continue;
- }
- if (!isNaN(property) || Array.isArray(property)) {
- entity[prop] = source;
- }
- else if (property.fromArray) {
- property.fromArray(source);
- }
- else if (typeof property === "object" && property !== null) {
- this._ApplyPropertiesToEntity(source, property);
- }
- }
- }
- static _ApplyDeltaForEntity(sources, scene, finder, addNew) {
- for (const source of sources) {
- // Update
- if (source.__state && source.__state.id !== undefined) {
- const targetEntity = finder(source.__state.id);
- if (targetEntity) {
- // This first pass applies properties that aren't on the serialization list
- this._ApplyPropertiesToEntity(source, targetEntity);
- // The second pass applies the serializable properties
- SerializationHelper.ParseProperties(source, targetEntity, scene, null);
- }
- }
- else if (source.__state && source.__state.deleteId !== undefined) {
- const target = finder(source.__state.deleteId);
- target?.dispose();
- }
- else {
- // New
- addNew(source);
- }
- }
- }
- }
- //# sourceMappingURL=sceneRecorder.js.map
|