import { ImageWrapType, ImageMappingType, ImageFilterType, InheritType } from '../const';
import { Utils } from '../common/Utils';
import { CubeTexture } from '../resources/CubeTexture';
import { ImageTexture } from '../resources/ImageTexture';
import { Style } from '../resources/Style';
var _registeredResolvers = [];
const cCanIgnoreKeys = {
'relationships': false,
'blueprints': false,
'selections': false,
'plugins': false,
'files': false,
'predownloads': false,
'actions': false,
'renderSettings': true,
'viewPoint': true,
};
const __ = {
private: Symbol('private'),
}
function _initPrivateMembers(that, param) {
that[__.private] = {};
const _private = that[__.private];
_private.checkIgnore = (key) => {
if (!cCanIgnoreKeys.hasOwnProperty(key)) {
return false;
}
if (_private.ignore.hasOwnProperty(key)) {
return _private.ignore[key];
}
else {
return cCanIgnoreKeys[key];
}
}
_private.checkAndConcat = (target, memberName, memberData) => {
let ignore = _private.checkIgnore(memberName);
if (!ignore) {
_private.concatArrayMember(target, memberName, memberData)
}
}
_private.concatArrayMember = (target, memberName, memberData) => {
if (!target || !memberName || !memberData) {
return;
}
let data = memberData;
if (!Array.isArray(memberData)) {
data = [memberData];
}
target[memberName] = target[memberName].concat(data);
}
_private.checkAndSet = (target, memberName, memberData) => {
let ignore = _private.checkIgnore(memberName);
if (!ignore) {
_private.setArrayMember(target, memberName, memberData)
}
}
_private.setArrayMember = (target, memberName, memberData) => {
if (!target || !memberName || !memberData) {
return;
}
let data = memberData;
if (!Array.isArray(memberData)) {
data = [memberData];
}
if (data.length > 0) {
target[memberName] = data;
}
}
// #region processResolvers
_private.processResolvers = () => {
_registeredResolvers.forEach(item => {
let type = item.type;
let resolver = new item.resolver({
app: _private.app,
toolkit: _private.toolkit,
});
_private.resolvers.set(type, resolver);
});
}
// #region processObjects
_private.resolveURL = (url) => {
let baseURL = _private.getBaseURL();
if (url.startsWith(baseURL)) {
url = url.replace(baseURL, '');
}
let workPath = _private.getWorkPath();
if (workPath && url.startsWith(workPath)) {
url = url.replace(workPath, '');
if (_private.workPathPrefix) {
url = _private.workPathPrefix + url;
}
else {
url = "/" + url;
}
}
return url;
}
_private.processURI = (oriURI) => {
let retURI = null;
if (Array.isArray(oriURI)) {
retURI = oriURI.map(uri => {
uri = _private.resolveURL(uri);
return uri;
});
}
else {
retURI = _private.resolveURL(oriURI);
}
return retURI;
}
// collect resource
_private.getIndexByURI = (uri) => {
let index = null;
if (Array.isArray(uri)) {
index = uri.map(url => {
return _private.getIndexByURI(url);
});
}
else {
index = _private.URIs.indexOf(uri);
if (index == -1) {
index = _private.URIs.push(uri) - 1;
}
}
return index;
}
_private.getURIByIndex = (index) => {
let uri = null;
if (Array.isArray(index)) {
uri = index.map(i => {
return _private.getURIByIndex(i);
});
}
else {
uri = _private.URIs[index];
}
return uri;
}
_private.collectResource = (resource) => {
if (!resource) {
return
}
const data = {}
if (resource.isSceneRoot) {
data['isSceneRoot'] = resource.isSceneRoot;
}
if (resource.isSceneNode) {
data['isSceneNode'] = resource.isSceneNode;
}
if (resource.nodeName) {
data['nodeName'] = resource.nodeName;
}
if (resource.inverseRotationMode) {
data['inverseRotationMode'] = resource.inverseRotationMode;
}
if (resource.excludeNodeNames) {
data['excludeNodeNames'] = resource.excludeNodeNames;
}
if (resource.instanceCount) {
data['instanceCount'] = resource.instanceCount;
}
if (resource.instanceId) {
data['instanceId'] = resource.instanceId;
}
if (resource.instanceStyle) {
data['instanceStyle'] = Object.assign({}, resource.instanceStyle);
if (data.instanceStyle.map && data.instanceStyle.map.url) {
data.instanceStyle.map = Object.assign({}, resource.instanceStyle.map);
data.instanceStyle.map.url = _private.processURI(data.instanceStyle.map.url);
}
}
if (resource.url) {
let uri = _private.processURI(resource.url);
data['uri'] = uri;
}
return Object.keys(data).length ? data : null;
};
// collect body
_private.collectBody = (object) => {
// If there are no children, "node" and "bodynode" are the same
if (object.node === object.bodyNode) {
return
}
const body = object.body
let localPosition = body.localPosition;
let localQuaternion = body.localQuaternion;
let localScale = body.localScale;
let halfSize = body.getLocalBoundingBox().halfSize;
return { localPosition, localQuaternion, localScale, halfSize };
};
// collect tags
_private.collectTags = (tags) => {
let ret = [];
tags.forEach(tag => {
let index = _private.tags.indexOf(tag);
if (index == -1) {
ret.push(_private.tags.push(tag) - 1);
}
else {
ret.push(index);
}
})
return ret;
};
// collect image
_private.collectImage = (image) => {
if (Utils.isNull(image)) {
return null;
}
else if (Array.isArray(image)) {
return {
type: 'NumberArray',
value: image
}
}
let imageData = null;
if (Utils.isNull(image.url)) {
return null;
}
else if (image instanceof ImageTexture) {
let url = _private.processURI(image.url);
imageData = {
type: 'ImageTexture',
value: _private.getIndexByURI(url),
}
image.flipY == false || (imageData.flipY = image.flipY);
let defaultMinFilterType = image.generateMipmaps ? ImageFilterType.LinearMipmapLinearFilter : ImageFilterType.LinearFilter
image.minFilterType == defaultMinFilterType || (imageData.minFilterType = image.minFilterType);
image.magFilterType == ImageFilterType.LinearFilter || (imageData.magFilterType = image.magFilterType);
image.mappingType == ImageMappingType.UV || (imageData.mappingType = image.mappingType);
image.wrapTypeT == ImageWrapType.Repeat || (imageData.wrapTypeT = image.wrapType);
image.wrapTypeS == ImageWrapType.Repeat || (imageData.wrapTypeS = image.wrapType);
}
else if (image instanceof CubeTexture) {
let url = _private.processURI(image.url);
imageData = {
type: 'CubeTexture',
value: _private.getIndexByURI(url),
}
image.flipY == false || (imageData.flipY = image.flipY);
let defaultMinFilterType = image.generateMipmaps ? ImageFilterType.LinearMipmapLinearFilter : ImageFilterType.LinearFilter
image.minFilterType == defaultMinFilterType || (imageData.minFilterType = image.minFilterType);
image.magFilterType == ImageFilterType.LinearFilter || (imageData.magFilterType = image.magFilterType);
image.mappingType == ImageMappingType.CubeReflection || (imageData.mappingType = image.mappingType);
image.wrapTypeT == ImageWrapType.ClampToEdge || (imageData.wrapTypeT = image.wrapType);
image.wrapTypeS == ImageWrapType.ClampToEdge || (imageData.wrapTypeS = image.wrapType);
}
return imageData;
}
// collect style.
_private.collectStyle = (style) => {
let styleData = Object.assign({}, style);
let images = styleData.images;
if (images) {
for (let key in images) {
let image = _private.collectImage(images[key]);
if (Utils.isNull(image)) {
delete images[key];
}
else {
styleData[key] = image;
}
}
delete styleData.images;
}
let mark = JSON.stringify(styleData);
let data = _private.stylesData.get(mark);
if (!data) {
data = {
index: _private.stylesData.size,
data: styleData
}
_private.stylesData.set(mark, data);
}
return data.index;
}
// collect children
_private.collectChildren = (object) => {
let children = []
object.children.forEach(child => {
let objectData = _private.collectObject(child);
if (objectData) {
children.push(objectData.index);
}
})
return children;
}
_private.processObjectData = (data) => {
// _customObjectProcessCallback
if (_private._customObjectProcessCallback) {
data = _private._customObjectProcessCallback(data);
}
// process resolvers
_private.resolvers.forEach(resolver => {
resolver.resolveExportObject(data);
});
// process uri
if (data.resource) {
if (data.resource.uri) {
let index = _private.getIndexByURI(data.resource.uri)
if (index >= 0) {
data.resource.uri = index;
}
}
let style = data.resource.instanceStyle;
if (style && style.map && style.map.url) {
style.map.url = _private.getIndexByURI(style.map.url);
}
}
// process tags
if (data.tags) {
let tags = _private.collectTags(data.tags);
if (tags.length) {
data.tags = tags;
}
}
// process style
if (data.style) {
let styleIndex = _private.collectStyle(data.style);
if (styleIndex >= 0) {
data.styleIndex = styleIndex;
}
delete data.style;
}
return data;
}
_private.isPrefabRoot = (object) => {
if (_private.rootObjects.includes(object) && _private.extensions.isPrefab) {
return true;
}
return false;
}
_private.needCollectChildren = (object) => {
if (!object || !object.children || object.children.length == 0) {
return false;
}
// if (object.type == 'Map') {
// return false;
// }
if (_private.isPrefabRoot(object)) {
return true;
}
return (!object.isPrefabObject);
}
_private.needCollect = (object) => {
if (!object) {
return false;
}
if (object.isPrivateObject) {
return false;
}
// do not collect subobject which maybe the child of prefab or gltf scene
if (object.isSubObject && !_private.extensions.isPrefab) {
return false;
}
if (_private.onFilterObject) {
return _private.onFilterObject(object);
}
return true;
}
_private.getChangedData = (curData, defaultData) => {
let equals = (v1, v2) => {
if (v1 == v2) {
return true;
}
if (Utils.isArray(v1) && Utils.isArray(v2)) {
return JSON.stringify(v1) === JSON.stringify(v2);
}
if (Utils.isObject(v1) && Utils.isObject(v2)) {
return Utils.equalsObject(v1, v2);
}
return false;
}
let data = {};
for (let key in curData) {
if (!equals(curData[key], defaultData[key])) {
data[key] = curData[key];
}
}
return data;
}
_private.getStyleChangedData = (style) => {
let changedStyle = {};
if (!style || !style.data) {
return changedStyle;
}
const styleData = style.getValues()
let data = _private.getChangedData(styleData.data, Style.cDefaultValues);
if (!Utils.isEmptyObject(data)) {
changedStyle = Object.assign(changedStyle, data);
}
let edge = _private.getChangedData(styleData.edge, Style.cEdgeDefaultValues);
if (!Utils.isEmptyObject(edge)) {
changedStyle.edge = edge;
}
let effect = _private.getChangedData(styleData.effect, Style.cEffectDefaultValues);
if (!Utils.isEmptyObject(effect)) {
changedStyle.effect = effect;
}
let images = _private.getChangedData(styleData.images, Style.cImagesDefaultValues);
if (!Utils.isEmptyObject(images)) {
changedStyle.images = images;
}
if (styleData.attributes && !Utils.isEmptyObject(styleData.attributes)) {
changedStyle.attributes = styleData.attributes;
}
// cUVMatrixDefaultValues is default value for every prop of uvData
if (styleData.uvData) {
let uvData = {};
for (let key in styleData.uvData) {
let uvDataItem = _private.getChangedData(styleData.uvData[key], Style.cUVMatrixDefaultValues);
if (!Utils.isEmptyObject(uvDataItem)) {
uvData[key] = uvDataItem;
}
}
if (!Utils.isEmptyObject(uvData)) {
changedStyle.uvData = uvData;
}
}
return changedStyle;
}
_private.collectProperty = (data, propKey, object, callback) => {
if (_private.onHookProperty) {
let succ = _private.onHookProperty(data, propKey, object);
if (succ) {
return;
}
}
if (callback) {
callback();
}
}
_private.collectObject = (object) => {
if (!_private.needCollect(object)) {
return null;
}
let objectData = _private.objectsData.get(object.uuid);
if (objectData) {
return objectData;
}
let data = {};
_private.objects.push(object);
_private.collectProperty(data, 'id', object, () => {
Utils.setAttributeIfExist(data, 'id', object);
})
_private.collectProperty(data, 'uuid', object, () => {
Utils.setAttributeIfExist(data, 'uuid', object);
})
_private.collectProperty(data, 'type', object, () => {
Utils.setAttributeIfExist(data, 'type', object);
})
_private.collectProperty(data, 'dtType', object, () => {
Utils.setAttributeIfExist(data, 'dtType', object);
})
_private.collectProperty(data, 'visible', object, () => {
Utils.setAttributeIfExist(data, 'visible', object, (v) => { return !v; });
})
_private.collectProperty(data, 'active', object, () => {
Utils.setAttributeIfExist(data, 'active', object, (v) => { return !v; });
})
_private.collectProperty(data, 'queryable', object, () => {
Utils.setAttributeIfExist(data, 'queryable', object, (v) => { return !v; });
})
_private.collectProperty(data, 'destroyable', object, () => {
Utils.setAttributeIfExist(data, 'destroyable', object, (v) => { return !v; });
})
_private.collectProperty(data, 'renderOrder', object, () => {
Utils.setAttributeIfExist(data, 'renderOrder', object, (v) => { return v != 0; });
})
_private.collectProperty(data, 'castShadow', object, () => {
Utils.setAttributeIfExist(data, 'castShadow', object, (v) => { return !v; });
})
_private.collectProperty(data, 'receiveShadow', object, () => {
Utils.setAttributeIfExist(data, 'receiveShadow', object, (v) => { return !v; });
})
_private.collectProperty(data, 'alwaysOnTop', object, () => {
Utils.setAttributeIfExist(data, 'alwaysOnTop', object, (v) => { return !v; });
})
_private.collectProperty(data, 'pickable', object, () => {
Utils.setAttributeIfExist(data, 'pickable', object, (v) => { return v; });
})
_private.collectProperty(data, 'pivot', object, () => {
Utils.setAttributeIfExist(data, 'pivot', object);
})
_private.collectProperty(data, 'name', object, () => {
Utils.setAttributeIfExist(data, 'name', object, (v) => { return v != ''; });
})
_private.collectProperty(data, 'styleTag', object, () => {
Utils.setAttributeIfExist(data, 'styleTag', object, (v) => { return v != ''; });
})
_private.collectProperty(data, 'position', object, () => {
Utils.setAttributeIfExist(data, 'position', object, (v) => { return v[0] != 0 || v[1] != 0 || v[2] != 0; }, 'localPosition');
})
_private.collectProperty(data, 'scale', object, () => {
Utils.setAttributeIfExist(data, 'scale', object, (v) => { return v[0] != 1 || v[1] != 1 || v[2] != 1; }, 'localScale');
})
_private.collectProperty(data, 'rotation', object, () => {
Utils.setAttributeIfExist(data, 'rotation', object, (v) => { return v[0] != 0 || v[1] != 0 || v[2] != 0 || v[3] != 1; }, 'localQuaternion');
})
_private.collectProperty(data, 'userData', object, () => {
Utils.setAttributeIfExist(data, 'userData', object, (v) => { return !!Object.keys(v).length; });
})
_private.collectProperty(data, 'internalData', object, () => {
Utils.setAttributeIfExist(data, 'internalData', object, (v) => { return !!Object.keys(v).length; });
})
_private.collectProperty(data, 'layerMask', object, () => {
Utils.setAttributeIfExist(data, 'layerMask', object, (v) => { return v != 1; });
})
_private.collectProperty(data, 'tags', object, () => {
if (object.tags && object.tags.size) {
data.tags = object.tags;
}
})
_private.collectProperty(data, 'extras', object, () => {
if (!Utils.isFunction(object.onExportExternalData)) {
return;
}
let externalData = object.onExportExternalData();
if (externalData) {
data.extras = externalData;
}
})
_private.collectProperty(data, 'inherit', object, () => {
if (!object.inherit) {
return;
}
let inherit = {};
object.inherit._keys.forEach(key => {
let value = object.inherit[key];
if (value != InheritType.Normal) {
inherit[key] = value;
}
})
if (!Utils.isEmptyObject(inherit)) {
data.inherit = inherit;
}
})
if (object.resource) {
let resData = _private.collectResource(object.resource);
if (resData) {
data.resource = resData;
}
}
// instanceGroupName属性非必须,可以理解为配置信息,因此存在extras里
if (object.instanceGroupName) {
data.extras = data.extras || {}
data.extras.instanceGroupName = object.instanceGroupName;
}
if (object.body) {
let body = _private.collectBody(object);
if (body) {
data.body = {};
Utils.setAttributeIfExist(data.body, 'position', body, (v) => { return v[0] != 0 || v[1] != 0 || v[2] != 0; }, 'localPosition');
Utils.setAttributeIfExist(data.body, 'scale', body, (v) => { return v[0] != 1 || v[1] != 1 || v[2] != 1; }, 'localScale');
Utils.setAttributeIfExist(data.body, 'rotation', body, (v) => { return v[0] != 0 || v[1] != 0 || v[2] != 0 || v[3] != 1; }, 'localQuaternion');
Utils.setAttributeIfExist(data.body, 'halfSize', body);
}
let style = _private.getStyleChangedData(object.body.style)
if (!Utils.isEmptyObject(style)) {
data.style = style;
}
}
let options = Object.assign(_private.toolkit, _private.options);
let components = object.onExportComponents(options);
if (object.isPrefabObject) {
components = components.filter(item => {
let componentClass = Utils.getRegisteredClass(item.type);
return !Utils.isNull(componentClass);
});
}
if (components.length) {
data.components = components;
}
// process data
objectData = {
data: _private.processObjectData(data),
index: _private.objectsData.size
}
_private.objectsData.set(data.uuid, objectData);
// collect children
if (_private.needCollectChildren(object)) {
data.children = _private.collectChildren(object);
}
return objectData;
}
_private.processObjects = () => {
_private.rootObjects.forEach(object => {
_private.collectObject(object);
})
let app = Utils.getCurrentApp();
let roots = Utils.uniqueObjects(_private.rootObjects);
roots.forEach(root => {
let objectData = _private.objectsData.get(root.uuid);
let data = objectData ? objectData.data : null;
if (data) {
// prefab's parent must be null
if (_private.extensions.isPrefab) {
data.parent = null;
}
else if (root.parent) {
// if the object's parent is app.root the save as null
if (app && app.root && app.root.uuid == root.parent.uuid) {
data.parent = null;
}
else {
data.parent = { uuid: root.parent.uuid };
}
// set indexOfParent
let object = app.queryByUUID(data.uuid)[0];
if (object) {
data.indexOfParent = object.indexOfParent;
}
}
}
})
}
// #endregion
// #region processRelationships
_private.arrayFromMap = (data, map, callback) => {
let ret = [];
if (!data) {
return ret;
}
else if (Utils.isArray(data)) {
data.forEach(item => {
let index = callback(item.uuid, map);
if (index >= 0) {
ret.push(index);
}
});
}
else {
let index = callback(data.uuid, map);
if (index >= 0) {
ret.push(index);
}
}
return ret;
}
_private.collectRelationship = (relationship) => {
let data = {
uuid: relationship.uuid,
name: relationship.name,
type: relationship.type,
queryDirection: relationship.queryDirection,
tags: relationship.tags
};
let callback = (uuid, map) => {
let object = map.get(uuid);
if (object) {
return object.index;
}
return { uuid: uuid };
}
let source = _private.arrayFromMap(relationship.source, _private.objectsData, callback);
if (source.length > 0) {
data.source = source;
}
let target = _private.arrayFromMap(relationship.target, _private.objectsData, callback);
if (target.length > 0) {
data.target = target;
}
_private.relationshipsData.push(data);
}
_private.processRelationships = () => {
if (!_private.checkIgnore('relationships')) {
_private.relationships.forEach(relationship => {
_private.collectRelationship(relationship);
})
}
}
// #endregion
// #region processSelections
_private.processSelections = () => {
if (_private.checkIgnore('selections')) {
return;
}
_private.selections.forEach(selection => {
let objects = selection.objects;
if (objects) {
selection.objects = [];
if (Array.isArray(objects)) {
objects.forEach(object => {
// if we can not find the object, we ignore it
let data = _private.objectsData.get(object.uuid);
if (data) {
selection.objects.push(data.index);
}
})
}
else {
let data = _private.objectsData.get(objects.uuid);
if (data) {
selection.objects.push(data.index);
}
}
}
let style = selection.style?.modifier;
if (style) {
let styleIndex = _private.collectStyle(style);
if (styleIndex >= 0) {
selection.style = styleIndex;
}
}
});
}
// #endregion
// #region processRenderSettings
_private.processBackground = () => {
let background = _private.collectImage(_private.renderSettings.background);
if (Utils.isNull(background)) {
_private.renderSettings.background = null;
}
else {
_private.renderSettings.background = background;
}
}
_private.processEnvMap = () => {
let environment = _private.renderSettings.environment;
if (Utils.isNull(environment)) {
delete _private.renderSettings.environment;
return;
}
// 特殊处理: 如果envMap为null,仍需设置,目的为清空环境图
if (environment.envMap != null) {
let envMap = _private.collectImage(environment.envMap);
if (Utils.isNull(envMap)) {
delete environment.envMap;
}
else {
environment.envMap = envMap;
}
}
}
_private.processRenderSettings = () => {
if (!_private.checkIgnore('renderSettings')) {
let app = Utils.getCurrentApp();
_private.renderSettings = app ? Object.assign({}, app.renderSettings) : {};
_private.processBackground();
_private.processEnvMap();
}
}
// #endregion
_private.process = () => {
_private.processResolvers();
_private.processObjects();
_private.processRelationships();
_private.processSelections();
_private.processRenderSettings();
}
_private.exportStyles = () => {
let stylesData = Array.from(_private.stylesData.values());
stylesData.sort(function (a, b) { return a.index - b.index });
let styles = stylesData.map(style => { return style.data });
return styles;
}
_private.exportObjects = () => {
let objectsData = Array.from(_private.objectsData.values());
objectsData.sort(function (a, b) { return a.index - b.index });
let objects = objectsData.map(object => {
let data = Object.assign({}, object.data);
if ('styleIndex' in data) {
data.style = data.styleIndex;
delete data.styleIndex;
}
return data;
});
return objects;
}
_private.exportResolvers = () => {
let resolvers = [];
for (let [key, value] of _private.resolvers) {
let resolver = {};
resolver.type = key;
resolver.data = value.onExport();
if (resolver.data) {
resolvers.push(resolver);
}
}
return resolvers;
}
_private.exportInstanceObjects = () => {
let instanceObjects = []
for (let index = 0; index < _private.objects.length; index++) {
let object = _private.objects[index];
// check valid
if (!object.scale || object.scale[0] <= 0 || object.scale[1] <= 0 || object.scale[2] <= 0) {
continue;
}
if (object.isInstancedDrawing) {
instanceObjects.push(index);
}
}
return instanceObjects;
}
_private.exportComponentsOfRoot = () => {
let data = {};
let app = Utils.getCurrentApp();
if (!app) {
return data;
}
for (const [key, value] of app.components) {
let param = value.onExport ? value.onExport() : null;
if (param) {
data[key] = {
name: key,
type: value.constructor.className,
param
}
}
}
return data;
}
_private.exportExtensions = () => {
let extensions = Object.assign({}, _private.extensions);
let instances = _private.exportInstanceObjects();
if (instances.length > 0) {
extensions.instances = instances;
}
let componentsOfRoot = _private.exportComponentsOfRoot()
if (!Utils.isEmptyObject(componentsOfRoot)) {
extensions.componentsOfRoot = componentsOfRoot;
}
return extensions;
}
_private.exportViewpoint = () => {
let viewpoint = {};
if (!_private.checkIgnore('viewPoint')) {
viewpoint.position = _private.viewpoint.position
viewpoint.target = _private.viewpoint.target
let app = Utils.getCurrentApp();
if (app && app.camera) {
viewpoint.position = viewpoint.position || app.camera.position
viewpoint.target = viewpoint.target || app.camera.target
}
}
return viewpoint;
}
_private.export = () => {
let data = {};
data.baseURL = _private.getBaseURL();
data.$schema = _private.schemaURL;
data.version = "2.0.0";
data.description = "ThingJS Scene Format";
data.author = "uino";
let styles = _private.exportStyles();
if (!Utils.isEmptyObject(styles)) {
data.styles = styles;
}
let objects = _private.exportObjects();
if (!Utils.isEmptyObject(objects)) {
data.objects = objects;
}
let resolvers = _private.exportResolvers();
if (!Utils.isEmptyObject(resolvers)) {
data.resolvers = resolvers;
}
let extensions = _private.exportExtensions();
if (!Utils.isEmptyObject(extensions)) {
data.extensions = extensions;
}
let viewpoint = _private.exportViewpoint();
if (!Utils.isEmptyObject(viewpoint)) {
data.viewpoint = viewpoint;
}
let renderSettings = Object.assign({}, _private.renderSettings);
if (!Utils.isEmptyObject(renderSettings) && !_private.checkIgnore('renderSettings')) {
data.renderSettings = renderSettings;
}
_private.checkAndSet(data, 'tags', _private.tags);
_private.checkAndSet(data, 'URIs', _private.URIs);
_private.checkAndSet(data, 'blueprints', _private.blueprints);
_private.checkAndSet(data, 'selections', _private.selections);
_private.checkAndSet(data, 'files', _private.files);
_private.checkAndSet(data, 'scripts', _private.scripts);
_private.checkAndSet(data, 'preDownloads', _private.preDownloads);
_private.checkAndSet(data, 'plugins', _private.plugins);
_private.checkAndSet(data, 'relationships', _private.relationshipsData);
_private.checkAndSet(data, 'actions', _private.actions);
return data;
}
_private.getWorkPath = () => {
let app = Utils.getCurrentApp();
let workPath = '';
if (_private.workPath) {
workPath = _private.workPath;
}
else if (_private.options.workPath) {
workPath = _private.options.workPath
}
else if (app && app.workPath) {
workPath = app.workPath;
}
else {
workPath = Utils.workPath;
}
workPath = workPath.replaceAll('\\', '/');
if (!workPath.endsWith('/')) {
workPath = workPath + '/';
}
return workPath;
}
_private.getBaseURL = () => {
let baseURL = _private.baseURL;
baseURL = baseURL.replaceAll('\\', '/');
if (!baseURL.endsWith('/')) {
baseURL = baseURL + '/';
}
return baseURL;
}
_private.reset = (options = {}) => {
_private.baseURL = options.baseURL || _private.baseURL;
_private.schemaURL = options.schemaURL || _private.schemaURL;
_private.onFilterObject = Utils.isFunction(options.onFilterObject) ? param.onFilterObject : _private.onFilterObject;
_private.onHookProperty = Utils.isFunction(param.onHookProperty) ? param.onHookProperty : _private.onHookProperty;
_private.tags.length = 0;
_private.URIs.length = 0;
_private.objects.length = 0;
_private.rootObjects.length = 0;
_private.selections.length = 0;
_private.blueprints.length = 0;
_private.files.length = 0;
_private.scripts.length = 0;
_private.preDownloads.length = 0;
_private.plugins.length = 0;
_private.relationships.length = 0;
_private.actions.length = 0;
_private.objectsData.clear();
_private.stylesData.clear();
_private.relationshipsData.length = 0;
_private.renderSettings = {};
_private.extensions = {};
_private.viewpoint = {};
_private.resolvers.clear();
_private.ignore = options.ignore || _private.ignore;
_private.options = Object.assign({}, options);
_private._customObjectProcessCallback = null;
}
_private.init = (param) => {
_private.baseURL = param.baseURL || 'https://model.3dmomoda.com/';
_private.schemaURL = param.schemaURL || "https://raw.githubusercontent.com/UINOSOFT/thingjs/master/docs/tsf/schema/tsf.schema.json";
_private.onFilterObject = Utils.isFunction(param.onFilterObject) ? param.onFilterObject : null;
_private.onHookProperty = Utils.isFunction(param.onHookProperty) ? param.onHookProperty : null;
_private.tags = [];
_private.URIs = [];
_private.objects = [];
_private.rootObjects = [];
_private.selections = [];
_private.blueprints = [];
_private.files = [];
_private.scripts = [];
_private.preDownloads = [];
_private.plugins = [];
_private.relationships = [];
_private.actions = [];
_private.objectsData = new Map();
_private.stylesData = new Map();
_private.relationshipsData = [];
_private.renderSettings = {};
_private.extensions = {};
_private.viewpoint = {};
_private.resolvers = new Map();
_private.options = Object.assign({}, param);
_private.ignore = _private.options.ignore || {};
_private.toolkit = {
getURIByIndex: _private.getURIByIndex,
getIndexByURI: _private.getIndexByURI,
resolveURL: _private.resolveURL
}
_private._customObjectProcessCallback = null;
}
_private.init(param);
}
/**
* SceneExporter - 场景导出器
*
* 用于导出场景数据,支持多种格式的场景导出。
*
* @class SceneExporter
* @memberof THING
* @public
*
**/
class SceneExporter {
constructor(param = {}) {
_initPrivateMembers(this, param);
}
/**
* reset.
* @param {object} options The options.
* @private
*/
reset(options = {}) {
let _private = this[__.private];
_private.reset(options);
}
/**
* add the objects to be exporter.
* @param {Array|BaseObject} objects The objects which will be export.
*/
addObjects(objects) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'rootObjects', objects);
}
/**
* add the selections to the exporter
* @param {Array|object} selections The selections which will be export.
*/
addSelections(selections) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'selections', selections);
}
/**
* add the blueprints to the exporter
* @param {Array|object} blueprints The blueprints which will be export.
*/
addBlueprints(blueprints) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'blueprints', blueprints);
}
/**
* add files to the exporter
* @param {Array|string} files The files which will be export.
*/
addFiles(files) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'files', files);
}
/**
* add the scripts to the exporter
* @param {Array|string} scripts The scripts which will be export.
*/
addScripts(scripts) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'scripts', scripts);
}
/**
* add the preDownloads to the exporter
* @param {Array|string} preDownloads The preDownloads which will be export.
*/
addPreDownloads(preDownloads) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'preDownloads', preDownloads);
}
/**
* add the plugins to the exporter
* @param {Array|object} plugins The plugins which will be export.
*/
addPlugins(plugins) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'plugins', plugins);
}
/**
* add the relationships to the exporter
* @param {Array|object} relationships The relationships which will be export.
*/
addRelationships(relationships) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'relationships', relationships);
}
/**
* add extensions to the exporter
* @param {object} extensions The extension which will be export.
*/
addExtensions(extensions) {
let _private = this[__.private];
for (let key in extensions) {
_private.extensions[key] = extensions[key];
}
}
/**
* add actions to the exporter
* @param {object} action The action data.
*/
addAction(actions) {
let _private = this[__.private];
_private.checkAndConcat(_private, 'actions', actions);
}
/**
* add viewpoint to the exporter
* @param {object} viewpoint The viewpoint of the scene which will be export.
*/
addViewpoint(viewpoint = {}) {
let _private = this[__.private];
if (viewpoint.position) {
_private.viewpoint.position = viewpoint.position;
}
if (viewpoint.target) {
_private.viewpoint.target = viewpoint.target;
}
}
/**
* add work path to the exporter
* @param {string} workPath The Work Path that the uri should be cutted
*/
setWorkPath(workPath, prefix = null) {
let _private = this[__.private];
if (!workPath) {
return;
}
_private.workPath = workPath;
_private.workPathPrefix = prefix;
}
/**
* ouput scene file.
* @returns {object} scene data.
* @private
*/
export() {
let _private = this[__.private];
_private.process();
return _private.export();
}
set CustomObjectProcessCallback(callback) {
let _private = this[__.private];
_private._customObjectProcessCallback = callback;
}
get CustomObjectProcessCallback() {
let _private = this[__.private];
return _private._customObjectProcessCallback;
}
// 注册解析器;
// type:解析器类型名称,必须对应解析器类名
// resolver:解析器类型
static registerResolver(type, resolver) {
let item = {
type: type,
resolver: resolver
}
if (!_registeredResolvers.includes(item)) {
_registeredResolvers.push(item);
}
}
}
export { SceneExporter }