diff --git a/ShadowEditor.Web/dist/ShadowEditor.js b/ShadowEditor.Web/dist/ShadowEditor.js
index 14c8bce4..e6ddccd9 100644
--- a/ShadowEditor.Web/dist/ShadowEditor.js
+++ b/ShadowEditor.Web/dist/ShadowEditor.js
@@ -35486,11 +35486,11 @@
}
/**
- * 判断对象或字符串是否满足转换条件,满足返回true,不满足返回false
+ * 判断对象是否满足转换条件,满足返回true,不满足返回false
* @param {*} obj
*/
BaseSerializer.prototype.filter = function (obj) {
-
+ return false;
};
/**
@@ -35498,14 +35498,21 @@
* @param {*} obj 对象
*/
BaseSerializer.prototype.toJSON = function (obj) {
- return {};
+ var json = {};
+ Object.assign(json, this.metadata);
+ return json;
};
/**
* json转对象
- * @param {*} json json字符串
+ * @param {*} json json对象
+ * @param {*} parent 父对象
*/
- BaseSerializer.prototype.fromJSON = function (json) {
+ BaseSerializer.prototype.fromJSON = function (json, parent) {
+ if (parent) {
+ return parent;
+ }
+
return null;
};
@@ -35519,13 +35526,23 @@
Object3DSerializer.prototype = Object.create(BaseSerializer.prototype);
Object3DSerializer.prototype.constructor = Object3DSerializer;
+ Object3DSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.Object3D) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
Object3DSerializer.prototype.toJSON = function (obj) {
var json = BaseSerializer.prototype.toJSON(obj);
json.type = obj.type;
json.uuid = obj.uuid;
json.castShadow = obj.castShadow;
- json.children = obj.children.map(function (child) {
+ json.children = obj.children.map(child => {
return child.uuid;
});
json.frustumCulled = obj.frustumCulled;
@@ -35555,8 +35572,12 @@
return json;
};
- Object3DSerializer.prototype.fromJSON = function (json) {
+ Object3DSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? THREE.Object3D : parent;
+ // TODO: Object3D反序列化
+
+ return obj;
};
/**
@@ -35608,7 +35629,5599 @@
};
/**
- * Object3D序列化器
+ * 配置选项
+ * @param {*} options 配置选项
+ */
+ function Options(options) {
+ options = options || {};
+ this.server = options.server || location.origin;
+
+ this.gravityConstant = -9.8; // 重力加速度
+ }
+
+ /**
+ * Logo标志
+ * @param {*} options
+ */
+ function Logo(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ Logo.prototype = Object.create(UI$1.Control.prototype);
+ Logo.prototype.constructor = Logo;
+
+ Logo.prototype.render = function () {
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'logo',
+ html: ''
+ });
+
+ container.render();
+ };
+
+ /**
+ * 场景菜单
+ * @param {*} options
+ */
+ function SceneMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ SceneMenu.prototype = Object.create(UI$1.Control.prototype);
+ SceneMenu.prototype.constructor = SceneMenu;
+
+ SceneMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '场景'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ xtype: 'div',
+ id: 'mNewScene',
+ html: '新建',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mNewScene');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mLoadScene',
+ html: '载入',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mLoadScene');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mSaveScene',
+ html: '保存',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mSaveScene');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mPublishScene',
+ html: '发布',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mPublishScene');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 编辑菜单
+ * @param {*} options
+ */
+ function EditMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ EditMenu.prototype = Object.create(UI$1.Control.prototype);
+ EditMenu.prototype.constructor = EditMenu;
+
+ EditMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '编辑'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ xtype: 'div',
+ id: 'mUndo',
+ html: '撤销(Ctrl+Z)',
+ cls: 'option inactive',
+ onClick: function () {
+ _this.app.call('mUndo');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mRedo',
+ html: '重做(Ctrl+Shift+Z)',
+ cls: 'option inactive',
+ onClick: function () {
+ _this.app.call('mRedo');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mClearHistory',
+ html: '清空历史记录',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mClearHistory');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mClone',
+ html: '复制',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mClone');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mDelete',
+ html: '删除(Del)',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mDelete');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mMinifyShader',
+ html: '压缩着色器程序',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mMinifyShader');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 添加菜单
+ * @param {*} options
+ */
+ function AddMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ AddMenu.prototype = Object.create(UI$1.Control.prototype);
+ AddMenu.prototype.constructor = AddMenu;
+
+ AddMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '添加'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ xtype: 'div',
+ id: 'mAddGroup',
+ html: '组',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddGroup');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mAddPlane',
+ html: '平板',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddPlane');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddBox',
+ html: '正方体',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddBox');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddCircle',
+ html: '圆',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddCircle');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddCylinder',
+ html: '圆柱体',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddCylinder');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddSphere',
+ html: '球体',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddSphere');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddIcosahedron',
+ html: '二十面体',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddIcosahedron');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddTorus',
+ html: '轮胎',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddTorus');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddTorusKnot',
+ html: '扭结',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddTorusKnot');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddTeaport',
+ html: '茶壶',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddTeaport');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddLathe',
+ html: '花瓶',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddLathe');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddSprite',
+ html: '精灵',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddSprite');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddText',
+ html: '文本',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddText');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mAddPointLight',
+ html: '点光源',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddPointLight');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddSpotLight',
+ html: '聚光灯',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddSpotLight');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddDirectionalLight',
+ html: '平行光源',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddDirectionalLight');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddHemisphereLight',
+ html: '半球光',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddHemisphereLight');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mAddAmbientLight',
+ html: '环境光',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddAmbientLight');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mAddPerspectiveCamera',
+ html: '透视相机',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddPerspectiveCamera');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 资源菜单
+ * @param {*} options
+ */
+ function AssetMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ AssetMenu.prototype = Object.create(UI$1.Control.prototype);
+ AssetMenu.prototype.constructor = AssetMenu;
+
+ AssetMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '资源'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ xtype: 'div',
+ id: 'mAddAsset',
+ html: '添加模型',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddAsset');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mImportAsset',
+ html: '导入模型',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mImportAsset');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mExportGeometry',
+ html: '导出几何体',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportGeometry');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportObject',
+ html: '导出物体',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportObject');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportScene',
+ html: '导出场景',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportScene');
+ }
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'div',
+ id: 'mExportGLTF',
+ html: '导出gltf文件',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportGLTF');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportMMD',
+ html: '导出mmd文件',
+ cls: 'option inactive',
+ onClick: function () {
+ _this.app.call('mExportMMD');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportOBJ',
+ html: '导出obj文件',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportOBJ');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportPLY',
+ html: '导出ply文件',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportPLY');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportSTLB',
+ html: '导出stl二进制文件',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportSTLB');
+ }
+ }, {
+ xtype: 'div',
+ id: 'mExportSTL',
+ html: '导出stl文件',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mExportSTL');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 动画菜单
+ * @param {*} options
+ */
+ function AnimationMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ AnimationMenu.prototype = Object.create(UI$1.Control.prototype);
+ AnimationMenu.prototype.constructor = AnimationMenu;
+
+ AnimationMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '动画'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ id: 'mPerson',
+ xtype: 'div',
+ cls: 'option',
+ html: '人',
+ onClick: function () {
+ _this.app.call('mAddPerson', _this);
+ }
+ }, {
+ id: 'mFire',
+ xtype: 'div',
+ cls: 'option',
+ html: '火焰',
+ onClick: function () {
+ _this.app.call('mAddFire', _this);
+ }
+ }, {
+ id: 'mSmoke',
+ xtype: 'div',
+ cls: 'option',
+ html: '烟',
+ onClick: function () {
+ _this.app.call('mAddSmoke', _this);
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 物体菜单
+ * @param {*} options
+ */
+ function PhysicsMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ PhysicsMenu.prototype = Object.create(UI$1.Control.prototype);
+ PhysicsMenu.prototype.constructor = PhysicsMenu;
+
+ PhysicsMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '物理'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ xtype: 'div',
+ id: 'mAddCloth',
+ html: '添加布料',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mAddCloth', _this);
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 组件菜单
+ * @param {*} options
+ */
+ function ComponentMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ ComponentMenu.prototype = Object.create(UI$1.Control.prototype);
+ ComponentMenu.prototype.constructor = ComponentMenu;
+
+ ComponentMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '组件'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ xtype: 'div',
+ id: 'mParticleEmitter',
+ html: '粒子发射器',
+ cls: 'option',
+ onClick: function () {
+ _this.app.call('mParticleEmitter');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 启动菜单
+ * @param {*} options
+ */
+ function PlayMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ PlayMenu.prototype = Object.create(UI$1.Control.prototype);
+ PlayMenu.prototype.constructor = PlayMenu;
+
+ PlayMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ id: 'mPlay',
+ xtype: 'div',
+ cls: 'title',
+ html: '启动',
+ onClick: function () {
+ _this.app.call('mPlay');
+ }
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 视图菜单
+ * @param {*} options
+ */
+ function ViewMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ ViewMenu.prototype = Object.create(UI$1.Control.prototype);
+ ViewMenu.prototype.constructor = ViewMenu;
+
+ ViewMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '视图'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ id: 'mVRMode',
+ xtype: 'div',
+ cls: 'option',
+ html: 'VR模式',
+ onClick: function () {
+ _this.app.call('mVRMode');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 示例菜单
+ * @param {*} options
+ */
+ function ExampleMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ ExampleMenu.prototype = Object.create(UI$1.Control.prototype);
+ ExampleMenu.prototype.constructor = ExampleMenu;
+
+ ExampleMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '示例'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ id: 'mArkanoid',
+ xtype: 'div',
+ cls: 'option',
+ html: '打砖块',
+ onClick: function () {
+ _this.app.call('mArkanoid');
+ }
+ }, {
+ id: 'mCamera',
+ xtype: 'div',
+ cls: 'option',
+ html: '相机',
+ onClick: function () {
+ _this.app.call('mCamera');
+ }
+ }, {
+ id: 'mParticles',
+ xtype: 'div',
+ cls: 'option',
+ html: '粒子',
+ onClick: function () {
+ _this.app.call('mParticles');
+ }
+ }, {
+ id: 'mPong',
+ xtype: 'div',
+ cls: 'option',
+ html: '乒乓球',
+ onClick: function () {
+ _this.app.call('mPong');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 帮助菜单
+ * @param {*} options
+ */
+ function HelpMenu(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+
+ HelpMenu.prototype = Object.create(UI$1.Control.prototype);
+ HelpMenu.prototype.constructor = HelpMenu;
+
+ HelpMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'menu',
+ children: [{
+ xtype: 'div',
+ cls: 'title',
+ html: '帮助'
+ }, {
+ xtype: 'div',
+ cls: 'options',
+ children: [{
+ id: 'mSourceCode',
+ xtype: 'div',
+ cls: 'option',
+ html: '源码',
+ onClick: function () {
+ _this.app.call('mSourceCode');
+ }
+ }, {
+ id: 'mAbout',
+ xtype: 'div',
+ cls: 'option',
+ html: '关于',
+ onClick: function () {
+ _this.app.call('mAbout');
+ }
+ }]
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 状态菜单(菜单栏右侧)
+ * @param {*} options
+ */
+ function StatusMenu(options) {
+ UI$1.Control.call(this, options);
+ options = options || {};
+
+ this.app = options.app;
+ }
+
+ StatusMenu.prototype = Object.create(UI$1.Control.prototype);
+ StatusMenu.prototype.constructor = StatusMenu;
+
+ StatusMenu.prototype.render = function () {
+ var _this = this;
+
+ var container = UI$1.create({
+ xtype: 'div',
+ id: 'mStatus',
+ parent: this.parent,
+ cls: 'menu right',
+ children: [{
+ id: 'bAutoSave',
+ xtype: 'boolean',
+ text: '自动保存',
+ value: true,
+ style: {
+ color: '#888 !important;'
+ },
+ onChange: function (e) {
+ _this.app.editor.config.setKey('autosave', e.target.checked);
+ _this.app.call('sceneGraphChanged', _this);
+ }
+ }, {
+ xtype: 'text',
+ text: 'r' + THREE.REVISION,
+ cls: 'title version'
+ }]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 菜单栏
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Menubar(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ Menubar.prototype = Object.create(UI$1.Control.prototype);
+ Menubar.prototype.constructor = Menubar;
+
+ Menubar.prototype.render = function () {
+ var params = { app: this.app };
+
+ var container = UI$1.create({
+ xtype: 'div',
+ id: 'menubar',
+ cls: 'menubar',
+ parent: this.parent,
+ children: [
+ // Logo
+ new Logo(params),
+
+ // 左侧
+ new SceneMenu(params),
+ new EditMenu(params),
+ new AddMenu(params),
+ new AssetMenu(params),
+ new AnimationMenu(params),
+ new PhysicsMenu(params),
+ new ComponentMenu(params),
+ new PlayMenu(params),
+ new ViewMenu(params),
+ new ExampleMenu(params),
+ new HelpMenu(params),
+
+ // 右侧
+ new StatusMenu(params)
+ ]
+ });
+
+ container.render();
+ };
+
+ /**
+ * 工具栏
+ */
+ function Toolbar(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ Toolbar.prototype = Object.create(UI$1.Control.prototype);
+ Toolbar.prototype.constructor = Toolbar;
+
+ Toolbar.prototype.render = function () {
+
+ var data = {
+ xtype: 'div',
+ id: 'toolbar',
+ parent: this.app.container,
+ cls: 'toolbar',
+ children: [{
+ xtype: 'iconbutton',
+ id: 'selectBtn',
+ icon: 'icon-select',
+ cls: 'Button IconButton selected',
+ title: '选择'
+ }, {
+ xtype: 'iconbutton',
+ id: 'translateBtn',
+ icon: 'icon-translate',
+ title: '平移(W)'
+ }, {
+ xtype: 'iconbutton',
+ id: 'rotateBtn',
+ icon: 'icon-rotate',
+ title: '旋转(E)'
+ }, {
+ xtype: 'iconbutton',
+ id: 'scaleBtn',
+ icon: 'icon-scale',
+ title: '缩放(R)'
+ }, {
+ xtype: 'hr'
+ }, {
+ xtype: 'iconbutton',
+ id: 'modelBtn',
+ icon: 'icon-model-view',
+ title: '模型'
+ }
+ // , {
+ // xtype: 'iconbutton',
+ // id: 'handBtn',
+ // icon: 'icon-hand',
+ // title: '抓手'
+ // }, {
+ // xtype: 'iconbutton',
+ // id: 'anchorPointBtn',
+ // icon: 'icon-anchor-point',
+ // title: '添加锚点'
+ // }, {
+ // xtype: 'iconbutton',
+ // id: 'pathBtn',
+ // icon: 'icon-path',
+ // title: '绘制路径'
+ // }
+ ]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 场景编辑区
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Viewport(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ Viewport.prototype = Object.create(UI$1.Control.prototype);
+ Viewport.prototype.constructor = Viewport;
+
+ Viewport.prototype.render = function () {
+ this.container = UI$1.create({
+ xtype: 'div',
+ id: 'viewport',
+ parent: this.app.container,
+ cls: 'viewport'
+ });
+ this.container.render();
+ };
+
+ /**
+ * 场景面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function ScenePanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ ScenePanel.prototype = Object.create(UI$1.Control.prototype);
+ ScenePanel.prototype.constructor = ScenePanel;
+
+ ScenePanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ var _this = this;
+
+ var onFogChanged = function () {
+ var fogType = UI$1.get('fogType');
+ var fogColor = UI$1.get('fogColor');
+ var fogNear = UI$1.get('fogNear');
+ var fogFar = UI$1.get('fogFar');
+ var fogDensity = UI$1.get('fogDensity');
+
+ _this.app.call('sceneFogChanged',
+ _this,
+ fogType.getValue(),
+ fogColor.getHexValue(),
+ fogNear.getValue(),
+ fogFar.getValue(),
+ fogDensity.getValue()
+ );
+ };
+
+ var refreshFogUI = function () {
+ _this.app.call('updateScenePanelFog', _this);
+ };
+
+ var data = {
+ xtype: 'div',
+ id: 'scenePanel',
+ parent: this.parent,
+ cls: 'Panel',
+ children: [{ // outliner
+ xtype: 'outliner',
+ id: 'outliner',
+ editor: editor,
+ onChange: function () {
+ _this.app.call('outlinerChange', _this, this);
+ },
+ onDblClick: function () {
+ editor.focusById(parseInt(this.getValue()));
+ }
+ }, {
+ xtype: 'br'
+ }, { // background
+ xtype: 'row',
+ id: 'backgroundRow',
+ children: [{
+ xtype: 'label',
+ text: '背景',
+ style: {
+ width: '90px'
+ }
+ }, {
+ xtype: 'color',
+ id: 'backgroundColor',
+ value: '#aaaaaa',
+ onChange: function () {
+ _this.app.call('sceneBackgroundChanged', _this, this.getHexValue());
+ }
+ }]
+ }, { // fog
+ xtype: 'row',
+ id: 'fogTypeRow',
+ children: [{
+ xtype: 'label',
+ text: '雾',
+ style: {
+ width: '90px'
+ }
+ }, {
+ xtype: 'select',
+ id: 'fogType',
+ options: {
+ 'None': '无',
+ 'Fog': '线性',
+ 'FogExp2': '指数型'
+ },
+ style: {
+ width: '150px'
+ },
+ onChange: function () {
+ onFogChanged();
+ refreshFogUI();
+ }
+ }]
+ }, {
+ xtype: 'row',
+ id: 'fogPropertiesRow',
+ children: [{ // fog color
+ xtype: 'color',
+ id: 'fogColor',
+ value: '#aaaaaa',
+ onChange: onFogChanged
+ }, { // fog near
+ xtype: 'number',
+ id: 'fogNear',
+ value: 0.1,
+ style: {
+ width: '40px'
+ },
+ range: [0, Infinity],
+ onChange: onFogChanged
+ }, { // fog far
+ xtype: 'number',
+ id: 'fogFar',
+ value: 50,
+ style: {
+ width: '40px'
+ },
+ range: [0, Infinity],
+ onChange: onFogChanged
+ }, { // fog density
+ xtype: 'number',
+ id: 'fogDensity',
+ value: 0.05,
+ style: {
+ width: '40px'
+ },
+ range: [0, 0.1],
+ precision: 3,
+ onChange: onFogChanged
+ }]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param newUuid string
+ * @constructor
+ */
+
+ function SetUuidCommand(object, newUuid) {
+
+ Command.call(this);
+
+ this.type = 'SetUuidCommand';
+ this.name = 'Update UUID';
+
+ this.object = object;
+
+ this.oldUuid = (object !== undefined) ? object.uuid : undefined;
+ this.newUuid = newUuid;
+
+ }
+ SetUuidCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetUuidCommand.prototype, {
+
+ constructor: SetUuidCommand,
+
+ execute: function () {
+
+ this.object.uuid = this.newUuid;
+ this.editor.app.call('objectChanged', this, this.object);
+ this.editor.app.call('sceneGraphChanged', this);
+
+ },
+
+ undo: function () {
+
+ this.object.uuid = this.oldUuid;
+ this.editor.app.call('objectChanged', this, this.object);
+ this.editor.app.call('sceneGraphChanged', this);
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.oldUuid = this.oldUuid;
+ output.newUuid = this.newUuid;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.oldUuid = json.oldUuid;
+ this.newUuid = json.newUuid;
+ this.object = this.editor.objectByUuid(json.oldUuid);
+
+ if (this.object === undefined) {
+
+ this.object = this.editor.objectByUuid(json.newUuid);
+
+ }
+
+ }
+
+ });
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param attributeName string
+ * @param newValue number, string, boolean or object
+ * @constructor
+ */
+
+ function SetValueCommand(object, attributeName, newValue) {
+
+ Command.call(this);
+
+ this.type = 'SetValueCommand';
+ this.name = 'Set ' + attributeName;
+ this.updatable = true;
+
+ this.object = object;
+ this.attributeName = attributeName;
+ this.oldValue = (object !== undefined) ? object[attributeName] : undefined;
+ this.newValue = newValue;
+
+ }
+ SetValueCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetValueCommand.prototype, {
+
+ constructor: SetValueCommand,
+
+ execute: function () {
+ this.object[this.attributeName] = this.newValue;
+ this.editor.app.call('objectChanged', this, this.object);
+ },
+
+ undo: function () {
+ this.object[this.attributeName] = this.oldValue;
+ this.editor.app.call('objectChanged', this, this.object);
+ },
+
+ update: function (cmd) {
+
+ this.newValue = cmd.newValue;
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.objectUuid = this.object.uuid;
+ output.attributeName = this.attributeName;
+ output.oldValue = this.oldValue;
+ output.newValue = this.newValue;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.attributeName = json.attributeName;
+ this.oldValue = json.oldValue;
+ this.newValue = json.newValue;
+ this.object = this.editor.objectByUuid(json.objectUuid);
+
+ }
+
+ });
+
+ /**
+ * 物体面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function ObjectPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ ObjectPanel.prototype = Object.create(UI$1.Control.prototype);
+ ObjectPanel.prototype.constructor = ObjectPanel;
+
+ ObjectPanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ var _this = this;
+
+ var update = function () {
+ _this.app.call('updateObject', _this);
+ };
+
+ var data = {
+ xtype: 'div',
+ id: 'objectPanel',
+ parent: this.parent,
+ cls: 'Panel',
+ style: {
+ borderTop: 0,
+ paddingTop: '20px',
+ display: 'none'
+ },
+ children: [{ // type
+ xtype: 'row',
+ id: 'objectTypeRow',
+ children: [{
+ xtype: 'label',
+ text: '类型'
+ }, {
+ xtype: 'text',
+ id: 'objectType'
+ }]
+ }, { // uuid
+ xtype: 'row',
+ id: 'objectUUIDRow',
+ children: [{
+ xtype: 'label',
+ text: 'UUID'
+ }, {
+ xtype: 'input',
+ id: 'objectUUID',
+ style: {
+ width: '102px',
+ fontSize: '12px'
+ },
+ disabled: true
+ }, {
+ xtype: 'button',
+ id: 'objectUUIDRenew',
+ text: '新建',
+ style: {
+ marginLeft: '7px'
+ },
+ onClick: function () {
+ var objectUUID = UI$1.get('objectUUID');
+ objectUUID.setValue(THREE.Math.generateUUID());
+ editor.execute(new SetUuidCommand(editor.selected, objectUUID.getValue()));
+ }
+ }]
+ }, { // name
+ xtype: 'row',
+ id: 'objectNameRow',
+ children: [{
+ xtype: 'label',
+ text: '名称'
+ }, {
+ xtype: 'input',
+ id: 'objectName',
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: function () {
+ editor.execute(new SetValueCommand(editor.selected, 'name', this.getValue()));
+ }
+ }]
+ }, { // position
+ xtype: 'row',
+ id: 'objectPositionRow',
+ children: [{
+ xtype: 'label',
+ text: '位置'
+ }, {
+ xtype: 'number',
+ id: 'objectPositionX',
+ style: {
+ width: '50px'
+ },
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'objectPositionY',
+ style: {
+ width: '50px'
+ },
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'objectPositionZ',
+ style: {
+ width: '50px'
+ },
+ onChange: update
+ }]
+ }, { // rotation
+ xtype: 'row',
+ id: 'objectRotationRow',
+ children: [{
+ xtype: 'label',
+ text: '旋转'
+ }, {
+ xtype: 'number',
+ id: 'objectRotationX',
+ step: 10,
+ unit: '°',
+ style: {
+ width: '50px'
+ },
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'objectRotationY',
+ step: 10,
+ unit: '°',
+ style: {
+ width: '50px'
+ },
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'objectRotationZ',
+ step: 10,
+ unit: '°',
+ style: {
+ width: '50px'
+ },
+ onChange: update
+ }]
+ }, { // scale
+ xtype: 'row',
+ id: 'objectScaleRow',
+ children: [{
+ xtype: 'label',
+ text: '尺寸'
+ }, {
+ xtype: 'checkbox',
+ id: 'objectScaleLock',
+ value: true,
+ style: {
+ position: 'absolute',
+ left: '75px'
+ }
+ }, {
+ xtype: 'number',
+ id: 'objectScaleX',
+ value: 1,
+ range: [0.01, Infinity],
+ style: {
+ width: '50px'
+ },
+ onChange: function () {
+ _this.app.call('updateScaleX', _this);
+ }
+ }, {
+ xtype: 'number',
+ id: 'objectScaleY',
+ value: 1,
+ range: [0.01, Infinity],
+ style: {
+ width: '50px'
+ },
+ onChange: function () {
+ _this.app.call('updateScaleY', _this);
+ }
+ }, {
+ xtype: 'number',
+ id: 'objectScaleZ',
+ value: 1,
+ range: [0.01, Infinity],
+ style: {
+ width: '50px'
+ },
+ onChange: function () {
+ _this.app.call('updateScaleZ', _this);
+ }
+ }]
+ }, { // fov
+ xtype: 'row',
+ id: 'objectFovRow',
+ children: [{
+ xtype: 'label',
+ text: '视场'
+ }, {
+ xtype: 'number',
+ id: 'objectFov',
+ onChange: update
+ }]
+ }, { // near
+ xtype: 'row',
+ id: 'objectNearRow',
+ children: [{
+ xtype: 'label',
+ text: '近点'
+ }, {
+ xtype: 'number',
+ id: 'objectNear',
+ onChange: update
+ }]
+ }, { // far
+ xtype: 'row',
+ id: 'objectFarRow',
+ children: [{
+ xtype: 'label',
+ text: '远点'
+ }, {
+ xtype: 'number',
+ id: 'objectFar',
+ onChange: update
+ }]
+ }, { // intensity
+ xtype: 'row',
+ id: 'objectIntensityRow',
+ children: [{
+ xtype: 'label',
+ text: '强度'
+ }, {
+ xtype: 'number',
+ id: 'objectIntensity',
+ range: [0, Infinity],
+ onChange: update
+ }]
+ }, { // color
+ xtype: 'row',
+ id: 'objectColorRow',
+ children: [{
+ xtype: 'label',
+ text: '颜色'
+ }, {
+ xtype: 'color',
+ id: 'objectColor',
+ onChange: update
+ }]
+ }, { // ground color
+ xtype: 'row',
+ id: 'objectGroundColorRow',
+ children: [{
+ xtype: 'label',
+ text: '地面颜色'
+ }, {
+ xtype: 'color',
+ id: 'objectGroundColor',
+ onChange: update
+ }]
+ }, { // distance
+ xtype: 'row',
+ id: 'objectDistanceRow',
+ children: [{
+ xtype: 'label',
+ text: '距离'
+ }, {
+ xtype: 'number',
+ id: 'objectDistance',
+ range: [0, Infinity],
+ onChange: update
+ }]
+ }, { // angle
+ xtype: 'row',
+ id: 'objectAngleRow',
+ children: [{
+ xtype: 'label',
+ text: '角度'
+ }, {
+ xtype: 'number',
+ id: 'objectAngle',
+ precision: 3,
+ range: [0, Math.PI / 2],
+ onChange: update
+ }]
+ }, { // penumbra
+ xtype: 'row',
+ id: 'objectPenumbraRow',
+ children: [{
+ xtype: 'label',
+ text: '边缘'
+ }, {
+ xtype: 'number',
+ id: 'objectPenumbra',
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // decay
+ xtype: 'row',
+ id: 'objectDecayRow',
+ children: [{
+ xtype: 'label',
+ text: '衰变'
+ }, {
+ xtype: 'number',
+ id: 'objectDecay',
+ range: [0, Infinity],
+ onChange: update
+ }]
+ }, { // shadow
+ xtype: 'row',
+ id: 'objectShadowRow',
+ children: [{
+ xtype: 'label',
+ text: '阴影'
+ }, {
+ xtype: 'boolean',
+ id: 'objectCastShadow',
+ value: false,
+ text: '产生',
+ onChange: update
+ }, {
+ xtype: 'boolean',
+ id: 'objectReceiveShadow',
+ value: false,
+ text: '接收',
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'objectShadowRadius',
+ value: 1,
+ onChange: update
+ }]
+ }, { // visible
+ xtype: 'row',
+ id: 'objectVisibleRow',
+ children: [{
+ xtype: 'label',
+ text: '可见性'
+ }, {
+ xtype: 'checkbox',
+ id: 'objectVisible',
+ onChange: update
+ }]
+ }, { // user data
+ xtype: 'row',
+ id: 'objectUserDataRow',
+ children: [{
+ xtype: 'label',
+ text: '用户数据'
+ }, {
+ xtype: 'textarea',
+ id: 'objectUserData',
+ style: {
+ width: '150px',
+ height: '40px',
+ fontSize: '12px'
+ },
+ onChange: update,
+ onKeyUp: function () {
+ try {
+ JSON.parse(this.getValue());
+ this.dom.classList.add('success');
+ this.dom.classList.remove('fail');
+ } catch (error) {
+ this.dom.classList.remove('success');
+ this.dom.classList.add('fail');
+ }
+ }
+ }]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param attributeName string
+ * @param newValue number, string, boolean or object
+ * @constructor
+ */
+
+ function SetGeometryValueCommand(object, attributeName, newValue) {
+
+ Command.call(this);
+
+ this.type = 'SetGeometryValueCommand';
+ this.name = 'Set Geometry.' + attributeName;
+
+ this.object = object;
+ this.attributeName = attributeName;
+ this.oldValue = (object !== undefined) ? object.geometry[attributeName] : undefined;
+ this.newValue = newValue;
+
+ }
+ SetGeometryValueCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetGeometryValueCommand.prototype, {
+
+ constructor: SetGeometryValueCommand,
+
+ execute: function () {
+
+ this.object.geometry[this.attributeName] = this.newValue;
+ this.editor.app.call('objectChanged', this, this.object);
+ this.editor.app.call('geometryChanged', this);
+ this.editor.app.call('sceneGraphChanged', this);
+
+ },
+
+ undo: function () {
+
+ this.object.geometry[this.attributeName] = this.oldValue;
+ this.editor.app.call('objectChanged', this, this.object);
+ this.editor.app.call('geometryChanged', this);
+ this.editor.app.call('sceneGraphChanged', this);
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.objectUuid = this.object.uuid;
+ output.attributeName = this.attributeName;
+ output.oldValue = this.oldValue;
+ output.newValue = this.newValue;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.object = this.editor.objectByUuid(json.objectUuid);
+ this.attributeName = json.attributeName;
+ this.oldValue = json.oldValue;
+ this.newValue = json.newValue;
+
+ }
+
+ });
+
+ /**
+ * 几何体信息面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function GeometryInfoPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ GeometryInfoPanel.prototype = Object.create(UI$1.Control.prototype);
+ GeometryInfoPanel.prototype.constructor = GeometryInfoPanel;
+
+ GeometryInfoPanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ this.children = {
+ 'xtype': 'row',
+ parent: this.parent,
+ children: [{ // vertices
+ xtype: 'row',
+ children: [{
+ xtype: 'label',
+ text: '顶点'
+ }, {
+ xtype: 'text',
+ id: 'geometryInfoVertices'
+ }]
+ }, { // faces
+ xtype: 'row',
+ children: [{
+ xtype: 'label',
+ text: '面'
+ }, {
+ xtype: 'text',
+ id: 'geometryInfoFaces',
+ }]
+ }]
+ };
+
+ var container = UI$1.create(this.children);
+ container.render();
+
+ function update(object) {
+ var vertices = UI$1.get('geometryInfoVertices');
+ var faces = UI$1.get('geometryInfoFaces');
+
+ if (object === null) return; // objectSelected.dispatch( null )
+ if (object === undefined) return;
+
+ var geometry = object.geometry;
+
+ if (geometry instanceof THREE.Geometry) {
+ container.dom.style.display = 'block';
+
+ vertices.setValue((geometry.vertices.length).format());
+ faces.setValue((geometry.faces.length).format());
+ } else {
+ container.dom.style.display = 'none';
+ }
+ }
+
+ this.app.on('objectSelected.GeometryInfoPanel', function (mesh) {
+ update(mesh);
+ });
+
+ this.app.on('geometryChanged.GeometryInfoPanel', function (mesh) {
+ update(mesh);
+ });
+ };
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param newGeometry THREE.Geometry
+ * @constructor
+ */
+
+ function SetGeometryCommand(object, newGeometry) {
+
+ Command.call(this);
+
+ this.type = 'SetGeometryCommand';
+ this.name = 'Set Geometry';
+ this.updatable = true;
+
+ this.object = object;
+ this.oldGeometry = (object !== undefined) ? object.geometry : undefined;
+ this.newGeometry = newGeometry;
+
+ }
+ SetGeometryCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetGeometryCommand.prototype, {
+
+ constructor: SetGeometryCommand,
+
+ execute: function () {
+
+ this.object.geometry.dispose();
+ this.object.geometry = this.newGeometry;
+ this.object.geometry.computeBoundingSphere();
+
+ this.editor.app.call('geometryChanged', this, this.object);
+ this.editor.app.call('sceneGraphChanged', this);
+
+ },
+
+ undo: function () {
+
+ this.object.geometry.dispose();
+ this.object.geometry = this.oldGeometry;
+ this.object.geometry.computeBoundingSphere();
+
+ this.editor.app.call('geometryChanged', this, this.object);
+ this.editor.app.call('sceneGraphChanged', this);
+
+ },
+
+ update: function (cmd) {
+
+ this.newGeometry = cmd.newGeometry;
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.objectUuid = this.object.uuid;
+ output.oldGeometry = this.object.geometry.toJSON();
+ output.newGeometry = this.newGeometry.toJSON();
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.object = this.editor.objectByUuid(json.objectUuid);
+
+ this.oldGeometry = parseGeometry(json.oldGeometry);
+ this.newGeometry = parseGeometry(json.newGeometry);
+
+ function parseGeometry(data) {
+
+ var loader = new THREE.ObjectLoader();
+ return loader.parseGeometries([data])[data.uuid];
+
+ }
+
+ }
+
+ });
+
+ /**
+ * 缓冲几何体面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function BufferGeometryPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ BufferGeometryPanel.prototype = Object.create(UI$1.Control.prototype);
+ BufferGeometryPanel.prototype.constructor = BufferGeometryPanel;
+
+ BufferGeometryPanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ var data = {
+ xtype: 'row',
+ id: 'bufferGeometryPanel',
+ parent: this.parent
+ };
+
+ var container = UI$1.create(data);
+ container.render();
+
+ function update(object) {
+ if (object === null) return; // objectSelected.dispatch( null )
+ if (object === undefined) return;
+
+ var geometry = object.geometry;
+
+ if (geometry instanceof THREE.BufferGeometry) {
+ container.dom.innerHTML = '';
+ container.dom.style.display = 'block';
+
+ var index = geometry.index;
+
+ if (index !== null) {
+ var panel = UI$1.create({
+ xtype: 'row',
+ parent: container.dom,
+ children: [{
+ xtype: 'label',
+ text: '索引数'
+ }, {
+ xtype: 'text',
+ text: (index.count).format(),
+ style: {
+ fontSize: '12px'
+ }
+ }]
+ });
+
+ panel.render();
+ }
+
+ var attributes = geometry.attributes;
+
+ for (var name in attributes) {
+
+ var attribute = attributes[name];
+
+ var panel = UI$1.create({
+ xtype: 'row',
+ parent: container.dom,
+ children: [{
+ xtype: 'label',
+ text: name
+ }, {
+ xtype: 'text',
+ text: (attribute.count).format() + ' (' + attribute.itemSize + ')',
+ style: {
+ fontSize: '12px'
+ }
+ }]
+ });
+
+ panel.render();
+ }
+ } else {
+ container.dom.style.display = 'none';
+ }
+ }
+
+ this.app.on('objectSelected.BufferGeometryPanel', function (mesh) {
+ update(mesh);
+ });
+
+ this.app.on('geometryChanged.BufferGeometryPanel', function (mesh) {
+ update(mesh);
+ });
+ };
+
+ /**
+ * 几何体面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function GeometryPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ GeometryPanel.prototype = Object.create(UI$1.Control.prototype);
+ GeometryPanel.prototype.constructor = GeometryPanel;
+
+ GeometryPanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ this.children = [{
+ xtype: 'div',
+ id: 'geometryPanel',
+ parent: this.parent,
+ cls: 'Panel',
+ style: {
+ borderTop: 0,
+ paddingTop: '20px',
+ display: 'none'
+ },
+ children: [{ // type
+ xtype: 'row',
+ id: 'geometryTypeRow',
+ children: [{
+ xtype: 'label',
+ text: '类型'
+ }, {
+ xtype: 'text',
+ id: 'geometryType'
+ }]
+ }, { // uuid
+ xtype: 'row',
+ id: 'geometryUUIDRow',
+ children: [{
+ xtype: 'label',
+ text: 'UUID'
+ }, {
+ xtype: 'input',
+ id: 'geometryUUID',
+ style: {
+ width: '102px',
+ fontSize: '12px'
+ },
+ disabled: true
+ }, {
+ xtype: 'button',
+ id: 'geometryUUIDRenew',
+ text: '新建',
+ style: {
+ marginLeft: '7px'
+ },
+ onClick: function () {
+ geometryUUID.setValue(THREE.Math.generateUUID());
+ editor.execute(new SetGeometryValueCommand(editor.selected, 'uuid', geometryUUID.getValue()));
+ }
+ }]
+ }, { // name
+ xtype: 'row',
+ id: 'geometryNameRow',
+ children: [{
+ xtype: 'label',
+ text: '名称'
+ }, {
+ xtype: 'input',
+ id: 'geometryName',
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: function () {
+ editor.execute(new SetGeometryValueCommand(editor.selected, 'name', this.getValue()));
+ }
+ }]
+ }, {
+ xtype: 'row',
+ id: 'geometryParameters',
+ children: [
+ new BufferGeometryPanel({ app: this.app })
+ ]
+ },
+ new GeometryInfoPanel({ app: this.app, id: 'geometryInfoPanel' })
+ ]
+ }];
+
+ var container = UI$1.create(this.children[0]);
+ container.render();
+ };
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param attributeName string
+ * @param newValue number, string, boolean or object
+ * @constructor
+ */
+
+ function SetMaterialValueCommand(object, attributeName, newValue) {
+
+ Command.call(this);
+
+ this.type = 'SetMaterialValueCommand';
+ this.name = 'Set Material.' + attributeName;
+ this.updatable = true;
+
+ this.object = object;
+ this.oldValue = (object !== undefined) ? object.material[attributeName] : undefined;
+ this.newValue = newValue;
+ this.attributeName = attributeName;
+
+ }
+ SetMaterialValueCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetMaterialValueCommand.prototype, {
+
+ constructor: SetMaterialValueCommand,
+
+ execute: function () {
+ this.object.material[this.attributeName] = this.newValue;
+ this.object.material.needsUpdate = true;
+ this.editor.app.call('objectChanged', this, this.object);
+ this.editor.app.call('materialChanged', this, this.object.material);
+ },
+
+ undo: function () {
+ this.object.material[this.attributeName] = this.oldValue;
+ this.object.material.needsUpdate = true;
+ this.editor.app.call('objectChanged', this, this.object);
+ this.editor.app.call('materialChanged', this, this.object.material);
+ },
+
+ update: function (cmd) {
+
+ this.newValue = cmd.newValue;
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.objectUuid = this.object.uuid;
+ output.attributeName = this.attributeName;
+ output.oldValue = this.oldValue;
+ output.newValue = this.newValue;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.attributeName = json.attributeName;
+ this.oldValue = json.oldValue;
+ this.newValue = json.newValue;
+ this.object = this.editor.objectByUuid(json.objectUuid);
+
+ }
+
+ });
+
+ /**
+ * 材质面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function MaterialPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ MaterialPanel.prototype = Object.create(UI$1.Control.prototype);
+ MaterialPanel.prototype.constructor = MaterialPanel;
+
+ MaterialPanel.prototype.render = function () {
+ var _this = this;
+ var editor = this.app.editor;
+
+ var update = function () {
+ _this.app.call('updateMaterial', _this);
+ };
+
+ var data = {
+ xtype: 'div',
+ parent: this.parent,
+ id: 'materialPanel',
+ cls: 'Panel',
+ style: {
+ borderTop: 0,
+ paddingTop: '20px',
+ display: 'none'
+ },
+ children: [{ // New Copy Paste
+ xtype: 'row',
+ children: [{
+ xtype: 'label',
+ text: ''
+ }, {
+ xtype: 'button',
+ id: 'btnNewMaterial',
+ text: '新建',
+ onClick: function () {
+ this.app.call('newMaterial', this);
+ }
+ }, {
+ xtype: 'button',
+ id: 'btnCopyMaterial',
+ text: '复制',
+ style: {
+ marginLeft: '4px'
+ },
+ onClick: function () {
+ this.app.call('copyMaterial', this);
+ }
+ }, {
+ xtype: 'button',
+ text: '粘贴',
+ id: 'btnPasteMaterial',
+ style: {
+ marginLeft: '4px'
+ },
+ onClick: function () {
+ this.app.call('pasteMaterial', this);
+ }
+ }]
+ }, { // type
+ xtype: 'row',
+ children: [{
+ xtype: 'label',
+ text: '类型'
+ }, {
+ xtype: 'select',
+ id: 'materialClass',
+ options: {
+ 'LineBasicMaterial': '线条材质',
+ 'LineDashedMaterial': '虚线材质',
+ 'MeshBasicMaterial': '基本材质',
+ 'MeshDepthMaterial': '深度材质',
+ 'MeshNormalMaterial': '法向量材质',
+ 'MeshLambertMaterial': '兰伯特材质',
+ 'MeshPhongMaterial': '冯氏材质',
+ 'PointCloudMaterial': '点云材质',
+ 'MeshStandardMaterial': '标准材质',
+ 'MeshPhysicalMaterial': '物理材质',
+ 'ShaderMaterial': '着色器材质',
+ 'SpriteMaterial': '精灵材质',
+ 'RawShaderMaterial': '原始着色器材质'
+ },
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: function () {
+ _this.app.call('updateMaterial');
+ }
+ }]
+ }, { // uuid
+ xtype: 'row',
+ children: [{
+ xtype: 'label',
+ text: 'UUID'
+ }, {
+ xtype: 'input',
+ id: 'materialUUID',
+ style: {
+ width: '102px',
+ fontSize: '12px'
+ },
+ disabled: true
+ }, {
+ xtype: 'button',
+ text: '新建',
+ style: {
+ marginLeft: '7px'
+ },
+ onClick: function () {
+ var materialUUID = UI$1.get('materialUUID');
+ materialUUID.setValue(THREE.Math.generateUUID());
+ _this.app.call('updateMaterial');
+ }
+ }]
+ }, { // name
+ xtype: 'row',
+ id: 'materialNameRow',
+ children: [{
+ xtype: 'label',
+ text: '名称'
+ }, {
+ xtype: 'input',
+ id: 'materialName',
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: function () {
+ editor.execute(new SetMaterialValueCommand(editor.selected, 'name', this.getValue()));
+ }
+ }]
+ }, { // program
+ xtype: 'row',
+ id: 'materialProgramRow',
+ children: [{
+ xtype: 'label',
+ text: '着色器程序'
+ }, {
+ xtype: 'button',
+ text: '信息',
+ style: {
+ marginLeft: '4px'
+ },
+ onClick: function () {
+ _this.app.call('editScript', _this, currentObject, 'programInfo');
+ }
+ }, {
+ xtype: 'button',
+ text: '顶点着色器',
+ style: {
+ marginLeft: '4px'
+ },
+ onClick: function () {
+ _this.app.call('editScript', _this, currentObject, 'vertexShader');
+ }
+ }, {
+ xtype: 'button',
+ text: '片源着色器',
+ style: {
+ marginLeft: '4px'
+ },
+ onClick: function () {
+ _this.app.call('editScript', _this, currentObject, 'fragmentShader');
+ }
+ }]
+ }, { // color
+ xtype: 'row',
+ id: 'materialColorRow',
+ children: [{
+ xtype: 'label',
+ text: '颜色'
+ }, {
+ xtype: 'color',
+ id: 'materialColor',
+ onChange: update
+ }]
+ }, { // roughness
+ xtype: 'row',
+ id: 'materialRoughnessRow',
+ children: [{
+ xtype: 'label',
+ text: '粗糙度'
+ }, {
+ xtype: 'number',
+ id: 'materialRoughness',
+ value: 0.5,
+ style: {
+ width: '60px'
+ },
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // metalness
+ xtype: 'row',
+ id: 'materialMetalnessRow',
+ children: [{
+ xtype: 'label',
+ text: '金属度'
+ }, {
+ xtype: 'number',
+ id: 'materialMetalness',
+ value: 0.5,
+ style: {
+ width: '60px'
+ },
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // emissive
+ xtype: 'row',
+ id: 'materialEmissiveRow',
+ children: [{
+ xtype: 'label',
+ text: '发光'
+ }, {
+ xtype: 'color',
+ id: 'materialEmissive',
+ value: 0x000000,
+ onChange: update
+ }]
+ }, { // specular
+ xtype: 'row',
+ id: 'materialSpecularRow',
+ children: [{
+ xtype: 'label',
+ text: '镜面度'
+ }, {
+ xtype: 'color',
+ id: 'materialSpecular',
+ value: 0x111111,
+ onChange: update
+ }]
+ }, { // shininess
+ xtype: 'row',
+ id: 'materialShininessRow',
+ children: [{
+ xtype: 'label',
+ text: '光亮度'
+ }, {
+ xtype: 'number',
+ id: 'materialShininess',
+ value: 30,
+ onChange: update
+ }]
+ }, { // clearCoat
+ xtype: 'row',
+ id: 'materialClearCoatRow',
+ children: [{
+ xtype: 'label',
+ text: '透明度'
+ }, {
+ xtype: 'number',
+ id: 'materialClearCoat',
+ value: 1,
+ style: {
+ width: '60px'
+ },
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // clearCoatRoughness
+ xtype: 'row',
+ id: 'materialClearCoatRoughnessRow',
+ children: [{
+ xtype: 'label',
+ text: '透明粗糙度'
+ }, {
+ xtype: 'number',
+ id: 'materialClearCoatRoughness',
+ value: 1,
+ style: {
+ width: '60px'
+ },
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // vertex colors
+ xtype: 'row',
+ id: 'materialVertexColorsRow',
+ children: [{
+ xtype: 'label',
+ text: '顶点颜色'
+ }, {
+ xtype: 'select',
+ id: 'materialVertexColors',
+ options: {
+ 0: '无',
+ 1: '面',
+ 2: '顶点'
+ },
+ onChange: update
+ }]
+ }, { // skinning
+ xtype: 'row',
+ id: 'materialSkinningRow',
+ children: [{
+ xtype: 'label',
+ text: '皮肤'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialSkinning',
+ value: false,
+ onChange: update
+ }]
+ }, { // map
+ xtype: 'row',
+ id: 'materialMapRow',
+ children: [{
+ xtype: 'label',
+ text: '纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialMap',
+ onChange: update
+ }]
+ }, { // alpha map
+ xtype: 'row',
+ id: 'materialAlphaMapRow',
+ children: [{
+ xtype: 'label',
+ text: '透明纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialAlphaMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialAlphaMap',
+ onChange: update
+ }]
+ }, { // bump map
+ xtype: 'row',
+ id: 'materialBumpMapRow',
+ children: [{
+ xtype: 'label',
+ text: '凹凸纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialBumpMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialBumpMap',
+ value: 1,
+ style: {
+ width: '30px'
+ },
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'materialBumpScale',
+ value: 1,
+ style: {
+ width: '30px'
+ },
+ onChange: update
+ }]
+ }, { // normal map
+ xtype: 'row',
+ id: 'materialNormalMapRow',
+ children: [{
+ xtype: 'label',
+ text: '法线纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialNormalMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialNormalMap',
+ onChange: update
+ }]
+ }, { // displacement map
+ xtype: 'row',
+ id: 'materialDisplacementMapRow',
+ children: [{
+ xtype: 'label',
+ text: '位移纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialDisplacementMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialDisplacementMap',
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'materialDisplacementScale',
+ value: 1,
+ style: {
+ width: '30px'
+ },
+ onChange: update
+ }]
+ }, { // roughness map
+ xtype: 'row',
+ id: 'materialRoughnessMapRow',
+ children: [{
+ xtype: 'label',
+ text: '粗糙纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialRoughnessMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialRoughnessMap',
+ onChange: update
+ }]
+ }, { // metalness map
+ xtype: 'row',
+ id: 'materialMetalnessMapRow',
+ children: [{
+ xtype: 'label',
+ text: '金属纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialMetalnessMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialMetalnessMap',
+ onChange: update
+ }]
+ }, { // specular map
+ xtype: 'row',
+ id: 'materialSpecularMapRow',
+ children: [{
+ xtype: 'label',
+ text: '镜面纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialSpecularMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialSpecularMap',
+ onChange: update
+ }]
+ }, { // env map
+ xtype: 'row',
+ id: 'materialEnvMapRow',
+ children: [{
+ xtype: 'label',
+ text: '环境纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialEnvMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialEnvMap',
+ mapping: THREE.SphericalReflectionMapping,
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'materialReflectivity',
+ value: 1,
+ style: {
+ width: '30px'
+ },
+ onChange: update
+ }]
+ }, { // light map
+ xtype: 'row',
+ id: 'materialLightMapRow',
+ children: [{
+ xtype: 'label',
+ text: '光照纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialLightMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialLightMap',
+ onChange: update
+ }]
+ }, { // ambient occlusion map
+ xtype: 'row',
+ id: 'materialAOMapRow',
+ children: [{
+ xtype: 'label',
+ text: '遮挡纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialAOMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialAOMap',
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'materialAOScale',
+ value: 1,
+ range: [0, 1],
+ style: {
+ width: '30px'
+ },
+ onChange: update
+ }]
+ }, { // emissive map
+ xtype: 'row',
+ id: 'materialEmissiveMapRow',
+ children: [{
+ xtype: 'label',
+ text: '放射纹理'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialEmissiveMapEnabled',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'texture',
+ id: 'materialEmissiveMap',
+ onChange: update
+ }]
+ }, { // side
+ xtype: 'row',
+ id: 'materialSideRow',
+ children: [{
+ xtype: 'label',
+ text: '剔除'
+ }, {
+ xtype: 'select',
+ id: 'materialSide',
+ options: {
+ 0: '正面',
+ 1: '反面',
+ 2: '双面'
+ },
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: update
+ }]
+ }, { // shading
+ xtype: 'row',
+ id: 'materialShadingRow',
+ children: [{
+ xtype: 'label',
+ text: '着色'
+ }, {
+ xtype: 'select',
+ id: 'materialShading',
+ options: {
+ 0: '无',
+ 1: '平坦',
+ 2: '光滑'
+ },
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: update
+ }]
+ }, { // blending
+ xtype: 'row',
+ id: 'materialBlendingRow',
+ children: [{
+ xtype: 'label',
+ text: '混合'
+ }, {
+ xtype: 'select',
+ id: 'materialBlending',
+ options: {
+ 0: '不混合',
+ 1: '一般混合',
+ 2: '和混合',
+ 3: '差混合',
+ 4: '积混合',
+ 5: '自定义混合'
+ },
+ style: {
+ width: '150px',
+ fontSize: '12px'
+ },
+ onChange: update
+ }]
+ }, { // opacity
+ xtype: 'row',
+ id: 'materialOpacityRow',
+ children: [{
+ xtype: 'label',
+ text: '不透明度'
+ }, {
+ xtype: 'number',
+ id: 'materialOpacity',
+ value: 1,
+ style: {
+ width: '60px'
+ },
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // transparent
+ xtype: 'row',
+ id: 'materialTransparentRow',
+ children: [{
+ xtype: 'label',
+ text: '透明'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialTransparent',
+ style: {
+ left: '100px'
+ },
+ onChange: update
+ }]
+ }, { // alpha test
+ xtype: 'row',
+ id: 'materialAlphaTestRow',
+ children: [{
+ xtype: 'label',
+ text: 'α测试'
+ }, {
+ xtype: 'number',
+ id: 'materialAlphaTest',
+ style: {
+ width: '60px'
+ },
+ range: [0, 1],
+ onChange: update
+ }]
+ }, { // wireframe
+ xtype: 'row',
+ id: 'materialWireframeRow',
+ children: [{
+ xtype: 'label',
+ text: '线框'
+ }, {
+ xtype: 'checkbox',
+ id: 'materialWireframe',
+ value: false,
+ onChange: update
+ }, {
+ xtype: 'number',
+ id: 'materialWireframeLinewidth',
+ value: 1,
+ style: {
+ width: '60px'
+ },
+ range: [0, 100],
+ onChange: update
+ }]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 属性面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function PropertyPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ PropertyPanel.prototype = Object.create(UI$1.Control.prototype);
+ PropertyPanel.prototype.constructor = PropertyPanel;
+
+ PropertyPanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ var _this = this;
+
+ var onClick = function (event) {
+ _this.app.call('selectPropertyTab', _this, event.target.textContent);
+ };
+
+ var data = {
+ xtype: 'div',
+ id: 'propertyPanel',
+ parent: this.parent,
+ children: [{
+ xtype: 'div',
+ cls: 'tabs',
+ children: [{
+ xtype: 'text',
+ id: 'objectTab',
+ text: '物体',
+ onClick: onClick
+ }, {
+ xtype: 'text',
+ id: 'geometryTab',
+ text: '几何',
+ onClick: onClick
+ }, {
+ xtype: 'text',
+ id: 'materialTab',
+ text: '材质',
+ onClick: onClick
+ }]
+ }, {
+ xtype: 'div',
+ children: [
+ new ObjectPanel({ app: this.app, id: 'object' })
+ ]
+ }, {
+ xtype: 'div',
+ children: [
+ new GeometryPanel({ app: this.app, id: 'geometry' })
+ ]
+ }, {
+ xtype: 'div',
+ children: [
+ new MaterialPanel({ app: this.app, id: 'material' })
+ ]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param script javascript object
+ * @constructor
+ */
+
+ var AddScriptCommand = function (object, script) {
+
+ Command.call(this);
+
+ this.type = 'AddScriptCommand';
+ this.name = 'Add Script';
+
+ this.object = object;
+ this.script = script;
+
+ };
+
+ AddScriptCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(AddScriptCommand.prototype, {
+
+ constructor: AddScriptCommand,
+
+ execute: function () {
+ if (this.editor.scripts[this.object.uuid] === undefined) {
+ this.editor.scripts[this.object.uuid] = [];
+ }
+
+ this.editor.scripts[this.object.uuid].push(this.script);
+ this.editor.app.call('scriptAdded', this, this.script);
+ },
+
+ undo: function () {
+
+ if (this.editor.scripts[this.object.uuid] === undefined) return;
+
+ var index = this.editor.scripts[this.object.uuid].indexOf(this.script);
+
+ if (index !== - 1) {
+
+ this.editor.scripts[this.object.uuid].splice(index, 1);
+
+ }
+
+ this.editor.app.call('scriptRemoved', this, this.script);
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.objectUuid = this.object.uuid;
+ output.script = this.script;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.script = json.script;
+ this.object = this.editor.objectByUuid(json.objectUuid);
+
+ }
+
+ });
+
+ /**
+ * 脚本面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function ScriptPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ ScriptPanel.prototype = Object.create(UI$1.Control.prototype);
+ ScriptPanel.prototype.constructor = ScriptPanel;
+
+ ScriptPanel.prototype.render = function () {
+ var editor = this.app.editor;
+
+ var data = {
+ xtype: 'div',
+ id: 'scriptPanel',
+ parent: this.parent,
+ cls: 'Panel scriptPanel',
+ style: {
+ display: 'none'
+ },
+ children: [{
+ xtype: 'label',
+ text: '脚本'
+ }, {
+ xtype: 'br'
+ }, {
+ xtype: 'br'
+ }, {
+ xtype: 'row',
+ id: 'scriptsContainer'
+ }, {
+ xtype: 'button',
+ id: 'newScript',
+ text: '新建',
+ onClick: function () {
+ var script = { name: '', source: 'function update( event ) {}' };
+ editor.execute(new AddScriptCommand(editor.selected, script));
+ }
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 工程面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function ProjectPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ ProjectPanel.prototype = Object.create(UI$1.Control.prototype);
+ ProjectPanel.prototype.constructor = ProjectPanel;
+
+ ProjectPanel.prototype.render = function () {
+ var editor = this.app.editor;
+ var config = editor.config;
+
+ var rendererTypes = {
+ 'WebGLRenderer': THREE.WebGLRenderer,
+ 'CanvasRenderer': THREE.CanvasRenderer,
+ 'SVGRenderer': THREE.SVGRenderer,
+ 'SoftwareRenderer': THREE.SoftwareRenderer,
+ 'RaytracingRenderer': THREE.RaytracingRenderer
+ };
+
+ var options = {};
+
+ for (var key in rendererTypes) {
+ if (key.indexOf('WebGL') >= 0 && System.support.webgl === false) continue;
+ options[key] = key;
+ }
+
+ var _this = this;
+
+ var updateRenderer = function () {
+ _this.app.call('updateRenderer', _this);
+ };
+
+ var data = {
+ xtype: 'div',
+ id: 'projectPanel',
+ parent: this.parent,
+ style: {
+ borderTop: 0,
+ paddingTop: '20px'
+ },
+ cls: 'Panel',
+ children: [{ // class
+ xtype: 'row',
+ id: 'rendererTypeRow',
+ children: [{
+ xtype: 'label',
+ text: '渲染器',
+ style: {
+ width: '90px'
+ }
+ }, {
+ xtype: 'select',
+ id: 'rendererType',
+ options: options,
+ value: config.getKey('project/renderer'),
+ style: {
+ width: '150px'
+ },
+ onChange: function () {
+ var value = this.getValue();
+ config.setKey('project/renderer', value);
+ updateRenderer();
+ }
+ }]
+ }, {
+ xtype: 'row',
+ id: 'rendererPropertiesRow',
+ style: {
+ marginLeft: '90px'
+ },
+ children: [{ // antialiasing
+ xtype: 'boolean',
+ id: 'rendererAntialias',
+ value: config.getKey('project/renderer/antialias'),
+ text: '抗锯齿',
+ onChange: function () {
+ config.setKey('project/renderer/antialias', this.getValue());
+ updateRenderer();
+ }
+ }, { // shadow
+ xtype: 'boolean',
+ id: 'rendererShadows',
+ value: config.getKey('project/renderer/shadows'),
+ text: '阴影',
+ onChange: function () {
+ config.setKey('project/renderer/shadows', this.getValue());
+ updateRenderer();
+ }
+ }, {
+ xtype: 'br'
+ }, { // gamma input
+ xtype: 'boolean',
+ id: 'rendererGammaInput',
+ value: config.getKey('project/renderer/gammaInput'),
+ text: 'γ输入',
+ onChange: function () {
+ config.setKey('project/renderer/gammaInput', this.getValue());
+ updateRenderer();
+ }
+ }, { // gamma output
+ xtype: 'boolean',
+ id: 'rendererGammaOutput',
+ value: config.getKey('project/renderer/gammaOutput'),
+ text: 'γ输出',
+ onChange: function () {
+ config.setKey('project/renderer/gammaOutput', this.getValue());
+ updateRenderer();
+ }
+ }]
+ }, { // VR
+ xtype: 'row',
+ id: 'vrRow',
+ children: [{
+ xtype: 'label',
+ text: '虚拟现实',
+ style: {
+ width: '90px'
+ }
+ }, {
+ xtype: 'checkbox',
+ id: 'vr',
+ value: config.getKey('project/vr'),
+ style: {
+ left: '100px'
+ },
+ onChange: function () {
+ config.setKey('project/vr', this.getValue());
+ // updateRenderer();
+ }
+ }]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 设置面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function SettingPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ SettingPanel.prototype = Object.create(UI$1.Control.prototype);
+ SettingPanel.prototype.constructor = SettingPanel;
+
+ SettingPanel.prototype.render = function () {
+ var editor = this.app.editor;
+ var config = editor.config;
+
+ var data = {
+ xtype: 'div',
+ id: 'settingPanel',
+ parent: this.parent,
+ cls: 'Panel',
+ style: {
+ borderTop: 0,
+ paddingTop: '20px'
+ },
+ children: [{
+ xtype: 'row',
+ id: 'themeRow',
+ children: [{
+ xtype: 'label',
+ text: '主题'
+ }, { // class
+ xtype: 'select',
+ options: {
+ 'assets/css/light.css': '浅色',
+ 'assets/css/dark.css': '深色'
+ },
+ value: config.getKey('theme'),
+ style: {
+ width: '150px'
+ },
+ onChange: function () {
+ var value = this.getValue();
+ editor.setTheme(value);
+ editor.config.setKey('theme', value);
+ }
+ }]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 历史记录面板
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+ function HistoryPanel(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ HistoryPanel.prototype = Object.create(UI$1.Control.prototype);
+ HistoryPanel.prototype.constructor = HistoryPanel;
+
+ HistoryPanel.prototype.render = function () {
+ var editor = this.app.editor;
+ var config = editor.config;
+ var history = editor.history;
+
+ var _this = this;
+
+ var data = {
+ xtype: 'div',
+ parent: this.parent,
+ cls: 'Panel',
+ children: [{
+ xtype: 'label',
+ text: '历史记录'
+ }, {
+ xtype: 'boolean',
+ text: '永久',
+ style: {
+ position: 'absolute',
+ right: '8px'
+ },
+ onChange: function () {
+ var value = this.getValue();
+ config.setKey('settings/history', value);
+ if (value) {
+ UI$1.msg('历史记录将被保存在会话中。\n这会对使用材质的性能产生影响。');
+ var lastUndoCmd = history.undos[history.undos.length - 1];
+ var lastUndoId = (lastUndoCmd !== undefined) ? lastUndoCmd.id : 0;
+ editor.history.enableSerialization(lastUndoId);
+ } else {
+ _this.app.call('historyChanged');
+ }
+ }
+ }, {
+ xtype: 'br'
+ }, {
+ xtype: 'br'
+ }, {
+ xtype: 'outliner',
+ id: 'historyOutlinear',
+ editor: editor,
+ onChange: function () {
+ history.goToState(parseInt(this.getValue()));
+ }
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 侧边栏
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Sidebar(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ Sidebar.prototype = Object.create(UI$1.Control.prototype);
+ Sidebar.prototype.constructor = Sidebar;
+
+ Sidebar.prototype.render = function () {
+ var editor = this.app.editor;
+ var _this = this;
+
+ function onClick(event) {
+ _this.app.call('selectTab', _this, event.target.textContent);
+ }
+
+ var data = {
+ xtype: 'div',
+ id: 'sidebar',
+ cls: 'sidebar',
+ parent: this.app.container,
+ children: [{
+ xtype: 'div',
+ cls: 'tabs',
+ children: [{
+ xtype: 'text',
+ id: 'sceneTab',
+ text: '场景',
+ onClick: onClick
+ }, {
+ xtype: 'text',
+ id: 'projectTab',
+ text: '工程',
+ onClick: onClick
+ }, {
+ xtype: 'text',
+ id: 'settingsTab',
+ text: '设置',
+ onClick: onClick
+ }]
+ }, { // scene
+ xtype: 'div',
+ id: 'scene',
+ children: [
+ new ScenePanel({ app: this.app }),
+ new PropertyPanel({ app: this.app }),
+ new ScriptPanel({ app: this.app })
+ ]
+ }, { // project
+ xtype: 'div',
+ id: 'project',
+ children: [
+ new ProjectPanel({ app: this.app })
+ ]
+ }, {
+ xtype: 'div',
+ id: 'settings',
+ children: [
+ new SettingPanel({ app: this.app }),
+ new HistoryPanel({ app: this.app })
+ ]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * 状态栏
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function StatusBar(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ StatusBar.prototype = Object.create(UI$1.Control.prototype);
+ StatusBar.prototype.constructor = StatusBar;
+
+ StatusBar.prototype.render = function () {
+
+ var data = {
+ xtype: 'div',
+ id: 'statusBar',
+ parent: this.app.container,
+ cls: 'statusBar',
+ children: [{
+ xtype: 'row',
+ children: [{
+ xtype: 'label',
+ text: '物体'
+ }, {
+ xtype: 'text',
+ id: 'objectsText',
+ text: '0' // 物体数
+ }, {
+ xtype: 'label',
+ text: '顶点'
+ }, {
+ xtype: 'text',
+ id: 'verticesText',
+ text: '0' // 顶点数
+ }, {
+ xtype: 'label',
+ text: '三角形'
+ }, {
+ xtype: 'text',
+ id: 'trianglesText',
+ text: '0' // 三角形数
+ }]
+ }]
+ };
+
+ var control = UI$1.create(data);
+ control.render();
+ };
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @param script javascript object
+ * @param attributeName string
+ * @param newValue string, object
+ * @param cursorPosition javascript object with format {line: 2, ch: 3}
+ * @param scrollInfo javascript object with values {left, top, width, height, clientWidth, clientHeight}
+ * @constructor
+ */
+
+ function SetScriptValueCommand(object, script, attributeName, newValue, cursorPosition, scrollInfo) {
+
+ Command.call(this);
+
+ this.type = 'SetScriptValueCommand';
+ this.name = 'Set Script.' + attributeName;
+ this.updatable = true;
+
+ this.object = object;
+ this.script = script;
+
+ this.attributeName = attributeName;
+ this.oldValue = (script !== undefined) ? script[this.attributeName] : undefined;
+ this.newValue = newValue;
+ this.cursorPosition = cursorPosition;
+ this.scrollInfo = scrollInfo;
+
+ }
+ SetScriptValueCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetScriptValueCommand.prototype, {
+
+ constructor: SetScriptValueCommand,
+
+ execute: function () {
+
+ this.script[this.attributeName] = this.newValue;
+
+ this.editor.app.call('scriptChanged', this);
+ this.editor.app.call('refreshScriptEditor', this, this.object, this.script, this.cursorPosition, this.scrollInfo);
+
+ },
+
+ undo: function () {
+
+ this.script[this.attributeName] = this.oldValue;
+
+ this.editor.app.call('scriptChanged', this);
+ this.editor.app.call('refreshScriptEditor', this, this.object, this.script, this.cursorPosition, this.scrollInfo);
+
+ },
+
+ update: function (cmd) {
+
+ this.cursorPosition = cmd.cursorPosition;
+ this.scrollInfo = cmd.scrollInfo;
+ this.newValue = cmd.newValue;
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ output.objectUuid = this.object.uuid;
+ output.index = this.editor.scripts[this.object.uuid].indexOf(this.script);
+ output.attributeName = this.attributeName;
+ output.oldValue = this.oldValue;
+ output.newValue = this.newValue;
+ output.cursorPosition = this.cursorPosition;
+ output.scrollInfo = this.scrollInfo;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.oldValue = json.oldValue;
+ this.newValue = json.newValue;
+ this.attributeName = json.attributeName;
+ this.object = this.editor.objectByUuid(json.objectUuid);
+ this.script = this.editor.scripts[json.objectUuid][json.index];
+ this.cursorPosition = json.cursorPosition;
+ this.scrollInfo = json.scrollInfo;
+
+ }
+
+ });
+
+ /**
+ * 脚本编辑面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Script(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ Script.prototype = Object.create(UI$1.Control.prototype);
+ Script.prototype.constructor = Script;
+
+ Script.prototype.render = function () {
+ var container;
+
+ var data = {
+ xtype: 'div',
+ parent: this.app.container,
+ id: 'script',
+ cls: 'script',
+ style: {
+ backgroundColor: '#272822',
+ display: 'none'
+ },
+ children: [{
+ xtype: 'div',
+ style: {
+ padding: '10px'
+ },
+ children: [{
+ id: 'scriptTitle',
+ xtype: 'text',
+ style: {
+ color: '#fff'
+ }
+ }, {
+ xtype: 'closebutton',
+ style: {
+ position: 'absolute',
+ top: '3px',
+ right: '1px',
+ cursor: 'pointer'
+ },
+ onClick: function () {
+ if (container) {
+ container.dom.style.display = 'none';
+ }
+ }
+ }]
+ }]
+ };
+
+ container = UI$1.create(data);
+ container.render();
+
+ var title = UI$1.get('scriptTitle');
+
+ // 业务逻辑
+ var currentMode;
+ var currentScript;
+ var currentObject;
+
+ var _this = this;
+
+ var codemirror = CodeMirror(container.dom, {
+ value: '',
+ lineNumbers: true,
+ matchBrackets: true,
+ indentWithTabs: true,
+ tabSize: 4,
+ indentUnit: 4,
+ hintOptions: {
+ completeSingle: false
+ }
+ });
+ codemirror.setOption('theme', 'monokai');
+ codemirror.on('change', function () {
+ _this.app.call('codeMirrorChange', _this, codemirror, currentMode, currentScript, currentObject);
+ });
+
+ // 防止回退键删除物体
+ var wrapper = codemirror.getWrapperElement();
+ wrapper.addEventListener('keydown', function (event) {
+ event.stopPropagation();
+ });
+
+ // tern js 自动完成
+ var server = new CodeMirror.TernServer({
+ caseInsensitive: true,
+ plugins: { threejs: null }
+ });
+
+ codemirror.setOption('extraKeys', {
+ 'Ctrl-Space': function (cm) { server.complete(cm); },
+ 'Ctrl-I': function (cm) { server.showType(cm); },
+ 'Ctrl-O': function (cm) { server.showDocs(cm); },
+ 'Alt-.': function (cm) { server.jumpToDef(cm); },
+ 'Alt-,': function (cm) { server.jumpBack(cm); },
+ 'Ctrl-Q': function (cm) { server.rename(cm); },
+ 'Ctrl-.': function (cm) { server.selectName(cm); }
+ });
+
+ codemirror.on('cursorActivity', function (cm) {
+ if (currentMode !== 'javascript') {
+ return;
+ }
+ server.updateArgHints(cm);
+ });
+
+ codemirror.on('keypress', function (cm, kb) {
+ if (currentMode !== 'javascript') {
+ return;
+ }
+ var typed = String.fromCharCode(kb.which || kb.keyCode);
+ if (/[\w\.]/.exec(typed)) {
+ server.complete(cm);
+ }
+ });
+
+ //
+ this.app.on('editorCleared.Script', function () {
+ container.dom.style.display = 'none';
+ });
+
+ this.app.on('editScript.Script', function (object, script) {
+ var mode, name, source;
+
+ if (typeof (script) === 'object') {
+ mode = 'javascript';
+ name = script.name;
+ source = script.source;
+ title.setValue(object.name + ' / ' + name);
+ } else {
+ switch (script) {
+ case 'vertexShader':
+ mode = 'glsl';
+ name = 'Vertex Shader';
+ source = object.material.vertexShader || "";
+ break;
+ case 'fragmentShader':
+ mode = 'glsl';
+ name = 'Fragment Shader';
+ source = object.material.fragmentShader || "";
+ break;
+ case 'programInfo':
+ mode = 'json';
+ name = 'Program Properties';
+ var json = {
+ defines: object.material.defines,
+ uniforms: object.material.uniforms,
+ attributes: object.material.attributes
+ };
+ source = JSON.stringify(json, null, '\t');
+ }
+ title.setValue(object.material.name + ' / ' + name);
+ }
+
+ currentMode = mode;
+ currentScript = script;
+ currentObject = object;
+
+ container.dom.style.display = 'block';
+ codemirror.setValue(source);
+ if (mode === 'json') mode = { name: 'javascript', json: true };
+ codemirror.setOption('mode', mode);
+ });
+
+ this.app.on('scriptRemoved.Script', function (script) {
+ if (currentScript === script) {
+ container.dom.style.display = 'none';
+ }
+ });
+
+ this.app.on('refreshScriptEditor.Script', function (object, script, cursorPosition, scrollInfo) {
+ if (currentScript !== script) return;
+
+ // copying the codemirror history because "codemirror.setValue(...)" alters its history
+
+ var history = codemirror.getHistory();
+ title.setValue(object.name + ' / ' + script.name);
+ codemirror.setValue(script.source);
+
+ if (cursorPosition !== undefined) {
+
+ codemirror.setCursor(cursorPosition);
+ codemirror.scrollTo(scrollInfo.left, scrollInfo.top);
+
+ }
+ codemirror.setHistory(history); // setting the history to previous state
+ });
+ };
+
+ /**
+ * 播放器
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function AppPlayer() {
+ var loader = new THREE.ObjectLoader();
+ var camera, scene, renderer;
+
+ var events = {};
+
+ var dom = document.createElement('div');
+
+ this.dom = dom;
+
+ this.width = 500;
+ this.height = 500;
+
+ this.load = function (json) {
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setClearColor(0x000000);
+ renderer.setPixelRatio(window.devicePixelRatio);
+
+ var project = json.project;
+
+ if (project.gammaInput) renderer.gammaInput = true;
+ if (project.gammaOutput) renderer.gammaOutput = true;
+ if (project.shadows) renderer.shadowMap.enabled = true;
+ if (project.vr) renderer.vr.enabled = true;
+
+ dom.appendChild(renderer.domElement);
+
+ this.setScene(loader.parse(json.scene));
+ this.setCamera(loader.parse(json.camera));
+
+ events = {
+ init: [],
+ start: [],
+ stop: [],
+ keydown: [],
+ keyup: [],
+ mousedown: [],
+ mouseup: [],
+ mousemove: [],
+ touchstart: [],
+ touchend: [],
+ touchmove: [],
+ update: []
+ };
+
+ var scriptWrapParams = 'player,renderer,scene,camera';
+ var scriptWrapResultObj = {};
+
+ for (var eventKey in events) {
+ scriptWrapParams += ',' + eventKey;
+ scriptWrapResultObj[eventKey] = eventKey;
+ }
+
+ var scriptWrapResult = JSON.stringify(scriptWrapResultObj).replace(/\"/g, '');
+
+ for (var uuid in json.scripts) {
+ var object = scene.getObjectByProperty('uuid', uuid, true);
+
+ if (object === undefined) {
+ console.warn('APP.Player: Script without object.', uuid);
+ continue;
+ }
+
+ var scripts = json.scripts[uuid];
+
+ for (var i = 0; i < scripts.length; i++) {
+ var script = scripts[i];
+
+ var functions = (new Function(scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';').bind(object))(this, renderer, scene, camera);
+
+ for (var name in functions) {
+
+ if (functions[name] === undefined) continue;
+
+ if (events[name] === undefined) {
+ console.warn('APP.Player: Event type not supported (', name, ')');
+ continue;
+ }
+
+ events[name].push(functions[name].bind(object));
+ }
+
+ }
+
+ }
+
+ dispatch$$1(events.init, arguments);
+
+ };
+
+ this.setCamera = function (value) {
+ camera = value;
+ camera.aspect = this.width / this.height;
+ camera.updateProjectionMatrix();
+
+ if (renderer.vr.enabled) {
+ dom.appendChild(WEBVR.createButton(renderer));
+ }
+ };
+
+ this.setScene = function (value) {
+ scene = value;
+ };
+
+ this.setSize = function (width, height) {
+ this.width = width;
+ this.height = height;
+
+ if (camera) {
+ camera.aspect = this.width / this.height;
+ camera.updateProjectionMatrix();
+ }
+
+ if (renderer) {
+ renderer.setSize(width, height);
+ }
+ };
+
+ function dispatch$$1(array, event) {
+ for (var i = 0, l = array.length; i < l; i++) {
+ array[i](event);
+ }
+ }
+
+ var prevTime;
+
+ function animate() {
+ var time = performance.now();
+
+ try {
+ dispatch$$1(events.update, { time: time, delta: time - prevTime });
+ } catch (e) {
+ console.error((e.message || e), (e.stack || ""));
+ }
+
+ renderer.render(scene, camera);
+ prevTime = time;
+ }
+
+ this.play = function () {
+ prevTime = performance.now();
+
+ document.addEventListener('keydown', onDocumentKeyDown);
+ document.addEventListener('keyup', onDocumentKeyUp);
+ document.addEventListener('mousedown', onDocumentMouseDown);
+ document.addEventListener('mouseup', onDocumentMouseUp);
+ document.addEventListener('mousemove', onDocumentMouseMove);
+ document.addEventListener('touchstart', onDocumentTouchStart);
+ document.addEventListener('touchend', onDocumentTouchEnd);
+ document.addEventListener('touchmove', onDocumentTouchMove);
+
+ dispatch$$1(events.start, arguments);
+
+ renderer.setAnimationLoop(animate);
+ };
+
+ this.stop = function () {
+ document.removeEventListener('keydown', onDocumentKeyDown);
+ document.removeEventListener('keyup', onDocumentKeyUp);
+ document.removeEventListener('mousedown', onDocumentMouseDown);
+ document.removeEventListener('mouseup', onDocumentMouseUp);
+ document.removeEventListener('mousemove', onDocumentMouseMove);
+ document.removeEventListener('touchstart', onDocumentTouchStart);
+ document.removeEventListener('touchend', onDocumentTouchEnd);
+ document.removeEventListener('touchmove', onDocumentTouchMove);
+
+ dispatch$$1(events.stop, arguments);
+
+ renderer.setAnimationLoop(null);
+ };
+
+ this.dispose = function () {
+ while (dom.children.length) {
+ dom.removeChild(dom.firstChild);
+ }
+
+ renderer.dispose();
+
+ camera = undefined;
+ scene = undefined;
+ renderer = undefined;
+ };
+
+ //
+
+ function onDocumentKeyDown(event) {
+ dispatch$$1(events.keydown, event);
+ }
+
+ function onDocumentKeyUp(event) {
+ dispatch$$1(events.keyup, event);
+ }
+
+ function onDocumentMouseDown(event) {
+ dispatch$$1(events.mousedown, event);
+ }
+
+ function onDocumentMouseUp(event) {
+ dispatch$$1(events.mouseup, event);
+ }
+
+ function onDocumentMouseMove(event) {
+ dispatch$$1(events.mousemove, event);
+ }
+
+ function onDocumentTouchStart(event) {
+ dispatch$$1(events.touchstart, event);
+ }
+
+ function onDocumentTouchEnd(event) {
+ dispatch$$1(events.touchend, event);
+ }
+
+ function onDocumentTouchMove(event) {
+ dispatch$$1(events.touchmove, event);
+ }
+ }
+
+ /**
+ * 播放器面板
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Player(options) {
+ UI$1.Control.call(this, options);
+ this.app = options.app;
+ }
+ Player.prototype = Object.create(UI$1.Control.prototype);
+ Player.prototype.constructor = Player;
+
+ Player.prototype.render = function () {
+ this.container = UI$1.create({
+ xtype: 'div',
+ parent: this.parent,
+ id: 'player',
+ cls: 'Panel player',
+ style: {
+ position: 'absolute',
+ display: 'none'
+ }
+ });
+
+ this.container.render();
+
+ this.player = new AppPlayer();
+ this.container.dom.appendChild(this.player.dom);
+ };
+
+ /**
+ * 时间线窗口
+ * @param {*} options
+ */
+ function TimePanel(options) {
+ Control.call(this, options);
+ }
+
+ TimePanel.prototype = Object.create(Control.prototype);
+ TimePanel.prototype.constructor = TimePanel;
+
+ TimePanel.prototype.render = function () {
+ return;
+ var target = {
+ x: 0,
+ y: 0,
+ rotate: 0
+ };
+
+ var timeliner = new Timeliner(target, {
+ position: 'absolute',
+ left: '48px',
+ right: '300px',
+ bottom: '32px'
+ });
+
+ timeliner.load({
+ 'version': '1.2.0',
+ 'modified': 'Mon Dec 08 2014 10:41:11 GMT+0800 (SGT)',
+ 'title': 'Untitled',
+ 'layers': [{
+ 'name': 'x',
+ 'values': [{
+ 'time': 0.1,
+ 'value': 0,
+ '_color': '#893c0f',
+ 'tween': 'quadEaseIn'
+ }, {
+ 'time': 3,
+ 'value': 3.500023,
+ '_color': '#b074a0'
+ }],
+ 'tmpValue': 3.500023,
+ '_color': '#6ee167'
+ }, {
+ 'name': 'y',
+ 'values': [{
+ 'time': 0.1,
+ 'value': 0,
+ '_color':
+ '#abac31',
+ 'tween': 'quadEaseOut'
+ }, {
+ 'time': 0.5,
+ 'value': -1.000001,
+ '_color': '#355ce8',
+ 'tween': 'quadEaseIn'
+ }, {
+ 'time': 1.1,
+ 'value': 0,
+ '_color': '#47e90',
+ 'tween': 'quadEaseOut'
+ }, {
+ 'time': 1.7,
+ 'value': -0.5,
+ '_color':
+ '#f76bca',
+ 'tween': 'quadEaseOut'
+ }, {
+ 'time': 2.3,
+ 'value': 0,
+ '_color': '#d59cfd'
+ }],
+ 'tmpValue': -0.5,
+ '_color': '#8bd589'
+ }, {
+ 'name': 'rotate',
+ 'values': [{
+ 'time': 0.1,
+ 'value': -25.700014000000003,
+ '_color': '#f50ae9',
+ 'tween': 'quadEaseInOut'
+ }, {
+ 'time': 2.8,
+ 'value': 0,
+ '_color': '#2e3712'
+ }],
+ 'tmpValue': -25.700014000000003,
+ '_color': '#2d9f57'
+ }]
+ });
+ };
+
+ /**
+ * 系统配置
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Config(name) {
+ var storage = {
+ 'autosave': true,
+ 'theme': 'assets/css/light.css',
+
+ 'project/renderer': 'WebGLRenderer',
+ 'project/renderer/antialias': true,
+ 'project/renderer/gammaInput': false,
+ 'project/renderer/gammaOutput': false,
+ 'project/renderer/shadows': true,
+ 'project/vr': false,
+
+ 'settings/history': false
+ };
+
+ if (window.localStorage[name] === undefined) {
+ window.localStorage[name] = JSON.stringify(storage);
+ } else {
+ var data = JSON.parse(window.localStorage[name]);
+
+ for (var key in data) {
+ storage[key] = data[key];
+ }
+ }
+
+ return {
+ getKey: function (key) {
+ return storage[key];
+ },
+
+ setKey: function () { // key, value, key, value ...
+ for (var i = 0, l = arguments.length; i < l; i += 2) {
+ storage[arguments[i]] = arguments[i + 1];
+ }
+
+ window.localStorage[name] = JSON.stringify(storage);
+
+ console.log('[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']', '保存配置到LocalStorage。');
+ },
+
+ clear: function () {
+ delete window.localStorage[name];
+ },
+
+ toJSON: function () {
+ return storage;
+ }
+ };
+ }
+
+ /**
+ * 历史记录
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+ function History(editor) {
+ this.app = editor.app;
+
+ this.editor = editor;
+ this.undos = [];
+ this.redos = [];
+ this.lastCmdTime = new Date();
+ this.idCounter = 0;
+
+ this.historyDisabled = false;
+ this.config = editor.config;
+
+ //Set editor-reference in Command
+
+ Command.call(this, editor);
+
+ var scope = this;
+
+ this.app.on('startPlayer.History', function () {
+ scope.historyDisabled = true;
+ });
+
+ this.app.on('stopPlayer.History', function () {
+ scope.historyDisabled = false;
+ });
+ }
+ History.prototype = Object.create(Command.prototype);
+
+ Object.assign(History.prototype, {
+
+ constructor: History,
+
+ execute: function (cmd, optionalName) {
+
+ var lastCmd = this.undos[this.undos.length - 1];
+ var timeDifference = new Date().getTime() - this.lastCmdTime.getTime();
+
+ var isUpdatableCmd = lastCmd &&
+ lastCmd.updatable &&
+ cmd.updatable &&
+ lastCmd.object === cmd.object &&
+ lastCmd.type === cmd.type &&
+ lastCmd.script === cmd.script &&
+ lastCmd.attributeName === cmd.attributeName;
+
+ if (isUpdatableCmd && cmd.type === "SetScriptValueCommand") {
+
+ // When the cmd.type is "SetScriptValueCommand" the timeDifference is ignored
+
+ lastCmd.update(cmd);
+ cmd = lastCmd;
+
+ } else if (isUpdatableCmd && timeDifference < 500) {
+
+ lastCmd.update(cmd);
+ cmd = lastCmd;
+
+ } else {
+
+ // the command is not updatable and is added as a new part of the history
+
+ this.undos.push(cmd);
+ cmd.id = ++this.idCounter;
+
+ }
+ cmd.name = (optionalName !== undefined) ? optionalName : cmd.name;
+ cmd.execute();
+ cmd.inMemory = true;
+
+ if (this.config.getKey('settings/history')) {
+
+ cmd.json = cmd.toJSON(); // serialize the cmd immediately after execution and append the json to the cmd
+
+ }
+ this.lastCmdTime = new Date();
+
+ // clearing all the redo-commands
+
+ this.redos = [];
+ this.app.call('historyChanged', this, cmd);
+
+ },
+
+ undo: function () {
+ if (this.historyDisabled) {
+ UI$1.msg("场景启动时撤销/重做将被禁用。");
+ return;
+ }
+
+ var cmd = undefined;
+
+ if (this.undos.length > 0) {
+ cmd = this.undos.pop();
+
+ if (cmd.inMemory === false) {
+ cmd.fromJSON(cmd.json);
+ }
+ }
+
+ if (cmd !== undefined) {
+ cmd.undo();
+ this.redos.push(cmd);
+ this.app.call('historyChanged', this, cmd);
+ }
+
+ return cmd;
+ },
+
+ redo: function () {
+ if (this.historyDisabled) {
+ UI$1.msg("场景启动时撤销/重做将被禁用。");
+ return;
+ }
+
+ var cmd = undefined;
+
+ if (this.redos.length > 0) {
+ cmd = this.redos.pop();
+
+ if (cmd.inMemory === false) {
+ cmd.fromJSON(cmd.json);
+ }
+ }
+
+ if (cmd !== undefined) {
+ cmd.execute();
+ this.undos.push(cmd);
+ this.app.call('historyChanged', this, cmd);
+ }
+
+ return cmd;
+ },
+
+ toJSON: function () {
+ var history = {};
+ history.undos = [];
+ history.redos = [];
+
+ if (!this.config.getKey('settings/history')) {
+ return history;
+ }
+
+ // Append Undos to History
+ for (var i = 0; i < this.undos.length; i++) {
+ if (this.undos[i].hasOwnProperty("json")) {
+ history.undos.push(this.undos[i].json);
+ }
+ }
+
+ // Append Redos to History
+ for (var i = 0; i < this.redos.length; i++) {
+ if (this.redos[i].hasOwnProperty("json")) {
+ history.redos.push(this.redos[i].json);
+ }
+ }
+
+ return history;
+ },
+
+ fromJSON: function (json) {
+ if (json === undefined) return;
+
+ for (var i = 0; i < json.undos.length; i++) {
+ var cmdJSON = json.undos[i];
+ var cmd = new window[cmdJSON.type](); // creates a new object of type "json.type"
+ cmd.json = cmdJSON;
+ cmd.id = cmdJSON.id;
+ cmd.name = cmdJSON.name;
+ this.undos.push(cmd);
+ this.idCounter = (cmdJSON.id > this.idCounter) ? cmdJSON.id : this.idCounter; // set last used idCounter
+ }
+
+ for (var i = 0; i < json.redos.length; i++) {
+ var cmdJSON = json.redos[i];
+ var cmd = new window[cmdJSON.type](); // creates a new object of type "json.type"
+ cmd.json = cmdJSON;
+ cmd.id = cmdJSON.id;
+ cmd.name = cmdJSON.name;
+ this.redos.push(cmd);
+ this.idCounter = (cmdJSON.id > this.idCounter) ? cmdJSON.id : this.idCounter; // set last used idCounter
+ }
+
+ // Select the last executed undo-command
+ this.app.call('historyChanged', this, this.undos[this.undos.length - 1]);
+ },
+
+ clear: function () {
+ this.undos = [];
+ this.redos = [];
+ this.idCounter = 0;
+
+ this.app.call('historyChanged', this);
+ },
+
+ goToState: function (id) {
+ if (this.historyDisabled) {
+ UI$1.msg("场景启动时撤销/重做将被禁用。");
+ return;
+ }
+
+ var cmd = this.undos.length > 0 ? this.undos[this.undos.length - 1] : undefined; // next cmd to pop
+
+ if (cmd === undefined || id > cmd.id) {
+ cmd = this.redo();
+ while (cmd !== undefined && id > cmd.id) {
+ cmd = this.redo();
+ }
+ } else {
+ while (true) {
+ cmd = this.undos[this.undos.length - 1]; // next cmd to pop
+ if (cmd === undefined || id === cmd.id) break;
+ cmd = this.undo();
+ }
+ }
+
+ this.editor.app.call('sceneGraphChanged', this);
+ this.editor.app.call('historyChanged', this, cmd);
+ },
+
+ enableSerialization: function (id) {
+
+ /**
+ * because there might be commands in this.undos and this.redos
+ * which have not been serialized with .toJSON() we go back
+ * to the oldest command and redo one command after the other
+ * while also calling .toJSON() on them.
+ */
+
+ this.goToState(-1);
+
+ var cmd = this.redo();
+ while (cmd !== undefined) {
+ if (!cmd.hasOwnProperty("json")) {
+ cmd.json = cmd.toJSON();
+ }
+ cmd = this.redo();
+ }
+
+ this.goToState(id);
+ }
+ });
+
+ /**
+ * 本地存储
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Storage() {
+ var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+
+ if (indexedDB === undefined) {
+ console.warn('Storage: IndexedDB不可用。');
+ return { init: function () { }, get: function () { }, set: function () { }, clear: function () { } };
+ }
+
+ var name = 'threejs-editor';
+ var version = 1;
+
+ var database;
+
+ return {
+ init: function (callback) {
+ var request = indexedDB.open(name, version);
+ request.onupgradeneeded = function (event) {
+ var db = event.target.result;
+
+ if (db.objectStoreNames.contains('states') === false) {
+
+ db.createObjectStore('states');
+
+ }
+ };
+ request.onsuccess = function (event) {
+ database = event.target.result;
+
+ callback();
+ };
+ request.onerror = function (event) {
+ console.error('IndexedDB', event);
+ };
+ },
+
+ get: function (callback) {
+ var transaction = database.transaction(['states'], 'readwrite');
+ var objectStore = transaction.objectStore('states');
+ var request = objectStore.get(0);
+ request.onsuccess = function (event) {
+ callback(event.target.result);
+ };
+
+ },
+
+ set: function (data, callback) {
+ var start = performance.now();
+
+ var transaction = database.transaction(['states'], 'readwrite');
+ var objectStore = transaction.objectStore('states');
+ var request = objectStore.put(data, 0);
+ request.onsuccess = function (event) {
+ console.log('[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']', '保存到IndexedDB中。 ' + (performance.now() - start).toFixed(2) + 'ms');
+ };
+
+ },
+
+ clear: function () {
+ if (database === undefined) return;
+
+ var transaction = database.transaction(['states'], 'readwrite');
+ var objectStore = transaction.objectStore('states');
+ var request = objectStore.clear();
+ request.onsuccess = function (event) {
+ console.log('[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']', '清空IndexedDB。');
+ };
+ }
+ };
+ }
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param object THREE.Object3D
+ * @constructor
+ */
+
+ function AddObjectCommand(object) {
+
+ Command.call(this);
+
+ this.type = 'AddObjectCommand';
+
+ this.object = object;
+ if (object !== undefined) {
+
+ this.name = 'Add Object: ' + object.name;
+
+ }
+
+ }
+ AddObjectCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(AddObjectCommand.prototype, {
+
+ constructor: AddObjectCommand,
+
+ execute: function () {
+
+ this.editor.addObject(this.object);
+ this.editor.select(this.object);
+
+ },
+
+ undo: function () {
+
+ this.editor.removeObject(this.object);
+ this.editor.deselect();
+
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+ output.object = this.object.toJSON();
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+
+ Command.prototype.fromJSON.call(this, json);
+
+ this.object = this.editor.objectByUuid(json.object.object.uuid);
+
+ if (this.object === undefined) {
+
+ var loader = new THREE.ObjectLoader();
+ this.object = loader.parse(json.object);
+
+ }
+
+ }
+
+ });
+
+ /**
+ * @author dforrer / https://github.com/dforrer
+ * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
+ */
+
+ /**
+ * @param scene containing children to import
+ * @constructor
+ */
+
+ function SetSceneCommand(scene) {
+
+ Command.call(this);
+
+ this.type = 'SetSceneCommand';
+ this.name = 'Set Scene';
+
+ this.cmdArray = [];
+
+ if (scene !== undefined) {
+
+ this.cmdArray.push(new SetUuidCommand(this.editor.scene, scene.uuid));
+ this.cmdArray.push(new SetValueCommand(this.editor.scene, 'name', scene.name));
+ this.cmdArray.push(new SetValueCommand(this.editor.scene, 'userData', JSON.parse(JSON.stringify(scene.userData))));
+
+ while (scene.children.length > 0) {
+
+ var child = scene.children.pop();
+ this.cmdArray.push(new AddObjectCommand(child));
+
+ }
+
+ }
+
+ }
+ SetSceneCommand.prototype = Object.create(Command.prototype);
+
+ Object.assign(SetSceneCommand.prototype, {
+
+ constructor: SetSceneCommand,
+
+ execute: function () {
+ for (var i = 0; i < this.cmdArray.length; i++) {
+
+ this.cmdArray[i].execute();
+
+ }
+ this.editor.app.call('sceneGraphChanged', this);
+ },
+
+ undo: function () {
+ for (var i = this.cmdArray.length - 1; i >= 0; i--) {
+
+ this.cmdArray[i].undo();
+
+ }
+ this.editor.app.call('sceneGraphChanged', this);
+ },
+
+ toJSON: function () {
+
+ var output = Command.prototype.toJSON.call(this);
+
+ var cmds = [];
+ for (var i = 0; i < this.cmdArray.length; i++) {
+
+ cmds.push(this.cmdArray[i].toJSON());
+
+ }
+ output.cmds = cmds;
+
+ return output;
+
+ },
+
+ fromJSON: function (json) {
+ Command.prototype.fromJSON.call(this, json);
+
+ var cmds = json.cmds;
+ for (var i = 0; i < cmds.length; i++) {
+ var cmd = new window[cmds[i].type](); // creates a new object of type "json.type"
+ cmd.fromJSON(cmds[i]);
+ this.cmdArray.push(cmd);
+ }
+ }
+ });
+
+ /**
+ * 模型加载
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Loader(editor) {
+
+ var scope = this;
+
+ this.texturePath = '';
+
+ this.loadFile = function (file) {
+
+ var filename = file.name;
+ var extension = filename.split('.').pop().toLowerCase();
+
+ var reader = new FileReader();
+ reader.addEventListener('progress', function (event) {
+
+ var size = '(' + Math.floor(event.total / 1000).format() + ' KB)';
+ var progress = Math.floor((event.loaded / event.total) * 100) + '%';
+ console.log('加载中', filename, size, progress);
+
+ });
+
+ switch (extension) {
+
+ case 'amf':
+
+ reader.addEventListener('load', function (event) {
+
+ var loader = new THREE.AMFLoader();
+ var amfobject = loader.parse(event.target.result);
+
+ editor.execute(new AddObjectCommand(amfobject));
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'awd':
+
+ reader.addEventListener('load', function (event) {
+
+ var loader = new THREE.AWDLoader();
+ var scene = loader.parse(event.target.result);
+
+ editor.execute(new SetSceneCommand(scene));
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'babylon':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+ var json = JSON.parse(contents);
+
+ var loader = new THREE.BabylonLoader();
+ var scene = loader.parse(json);
+
+ editor.execute(new SetSceneCommand(scene));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'babylonmeshdata':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+ var json = JSON.parse(contents);
+
+ var loader = new THREE.BabylonLoader();
+
+ var geometry = loader.parseGeometry(json);
+ var material = new THREE.MeshStandardMaterial();
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'ctm':
+
+ reader.addEventListener('load', function (event) {
+
+ var data = new Uint8Array(event.target.result);
+
+ var stream = new CTM.Stream(data);
+ stream.offset = 0;
+
+ var loader = new THREE.CTMLoader();
+ loader.createModel(new CTM.File(stream), function (geometry) {
+
+ geometry.sourceType = "ctm";
+ geometry.sourceFile = file.name;
+
+ var material = new THREE.MeshStandardMaterial();
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ });
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'dae':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var loader = new THREE.ColladaLoader();
+ var collada = loader.parse(contents);
+
+ collada.scene.name = filename;
+
+ editor.execute(new AddObjectCommand(collada.scene));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'fbx':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var loader = new THREE.FBXLoader();
+ var object = loader.parse(contents);
+
+ editor.execute(new AddObjectCommand(object));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'glb':
+ case 'gltf':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var loader = new THREE.GLTFLoader();
+ loader.parse(contents, function (result) {
+
+ result.scene.name = filename;
+ editor.execute(new AddObjectCommand(result.scene));
+
+ });
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'js':
+ case 'json':
+
+ case '3geo':
+ case '3mat':
+ case '3obj':
+ case '3scn':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ // 2.0
+
+ if (contents.indexOf('postMessage') !== -1) {
+
+ var blob = new Blob([contents], { type: 'text/javascript' });
+ var url = URL.createObjectURL(blob);
+
+ var worker = new Worker(url);
+
+ worker.onmessage = function (event) {
+
+ event.data.metadata = { version: 2 };
+ handleJSON(event.data, file, filename);
+
+ };
+
+ worker.postMessage(Date.now());
+
+ return;
+
+ }
+
+ // >= 3.0
+
+ var data;
+
+ try {
+
+ data = JSON.parse(contents);
+
+ } catch (error) {
+
+ UI$1.msg(error);
+ return;
+
+ }
+
+ handleJSON(data, file, filename);
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+
+ case 'kmz':
+
+ reader.addEventListener('load', function (event) {
+
+ var loader = new THREE.KMZLoader();
+ var collada = loader.parse(event.target.result);
+
+ collada.scene.name = filename;
+
+ editor.execute(new AddObjectCommand(collada.scene));
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'md2':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var geometry = new THREE.MD2Loader().parse(contents);
+ var material = new THREE.MeshStandardMaterial({
+ morphTargets: true,
+ morphNormals: true
+ });
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.mixer = new THREE.AnimationMixer(mesh);
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'obj':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var object = new THREE.OBJLoader().parse(contents);
+ object.name = filename;
+
+ editor.execute(new AddObjectCommand(object));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'playcanvas':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+ var json = JSON.parse(contents);
+
+ var loader = new THREE.PlayCanvasLoader();
+ var object = loader.parse(json);
+
+ editor.execute(new AddObjectCommand(object));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'ply':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var geometry = new THREE.PLYLoader().parse(contents);
+ geometry.sourceType = "ply";
+ geometry.sourceFile = file.name;
+
+ var material = new THREE.MeshStandardMaterial();
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ }, false);
+ reader.readAsArrayBuffer(file);
+
+ break;
+
+ case 'stl':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var geometry = new THREE.STLLoader().parse(contents);
+ geometry.sourceType = "stl";
+ geometry.sourceFile = file.name;
+
+ var material = new THREE.MeshStandardMaterial();
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ }, false);
+
+ if (reader.readAsBinaryString !== undefined) {
+
+ reader.readAsBinaryString(file);
+
+ } else {
+
+ reader.readAsArrayBuffer(file);
+
+ }
+
+ break;
+
+ /*
+ case 'utf8':
+
+ reader.addEventListener( 'load', function ( event ) {
+
+ var contents = event.target.result;
+
+ var geometry = new THREE.UTF8Loader().parse( contents );
+ var material = new THREE.MeshLambertMaterial();
+
+ var mesh = new THREE.Mesh( geometry, material );
+
+ editor.execute( new AddObjectCommand( mesh ) );
+
+ }, false );
+ reader.readAsBinaryString( file );
+
+ break;
+ */
+
+ case 'vtk':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var geometry = new THREE.VTKLoader().parse(contents);
+ geometry.sourceType = "vtk";
+ geometry.sourceFile = file.name;
+
+ var material = new THREE.MeshStandardMaterial();
+
+ var mesh = new THREE.Mesh(geometry, material);
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ case 'wrl':
+
+ reader.addEventListener('load', function (event) {
+
+ var contents = event.target.result;
+
+ var result = new THREE.VRMLLoader().parse(contents);
+
+ editor.execute(new SetSceneCommand(result));
+
+ }, false);
+ reader.readAsText(file);
+
+ break;
+
+ default:
+
+ UI$1.msg('不支持的文件类型(' + extension + ').');
+
+ break;
+
+ }
+
+ };
+
+ function handleJSON(data, file, filename) {
+
+ if (data.metadata === undefined) { // 2.0
+
+ data.metadata = { type: 'Geometry' };
+
+ }
+
+ if (data.metadata.type === undefined) { // 3.0
+
+ data.metadata.type = 'Geometry';
+
+ }
+
+ if (data.metadata.formatVersion !== undefined) {
+
+ data.metadata.version = data.metadata.formatVersion;
+
+ }
+
+ switch (data.metadata.type.toLowerCase()) {
+
+ case 'buffergeometry':
+
+ var loader = new THREE.BufferGeometryLoader();
+ var result = loader.parse(data);
+
+ var mesh = new THREE.Mesh(result);
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ break;
+
+ case 'geometry':
+
+ var loader = new THREE.JSONLoader();
+ loader.setTexturePath(scope.texturePath);
+
+ var result = loader.parse(data);
+
+ var geometry = result.geometry;
+ var material;
+
+ if (result.materials !== undefined) {
+
+ if (result.materials.length > 1) {
+
+ material = new THREE.MultiMaterial(result.materials);
+
+ } else {
+
+ material = result.materials[0];
+
+ }
+
+ } else {
+
+ material = new THREE.MeshStandardMaterial();
+
+ }
+
+ geometry.sourceType = "ascii";
+ geometry.sourceFile = file.name;
+
+ var mesh;
+
+ if (geometry.animation && geometry.animation.hierarchy) {
+
+ mesh = new THREE.SkinnedMesh(geometry, material);
+
+ } else {
+
+ mesh = new THREE.Mesh(geometry, material);
+
+ }
+
+ mesh.name = filename;
+
+ editor.execute(new AddObjectCommand(mesh));
+
+ break;
+
+ case 'object':
+
+ var loader = new THREE.ObjectLoader();
+ loader.setTexturePath(scope.texturePath);
+
+ var result = loader.parse(data);
+
+ if (result instanceof THREE.Scene) {
+
+ editor.execute(new SetSceneCommand(result));
+
+ } else {
+
+ editor.execute(new AddObjectCommand(result));
+
+ }
+
+ break;
+
+ case 'scene':
+
+ // DEPRECATED
+
+ var loader = new THREE.SceneLoader();
+ loader.parse(data, function (result) {
+
+ editor.execute(new SetSceneCommand(result.scene));
+
+ }, '');
+
+ break;
+
+ case 'app':
+
+ editor.fromJSON(data);
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ /**
+ * 渲染器改变事件
+ * @param {*} app
+ */
+ function RendererChangedEvent(app) {
+ BaseEvent.call(this, app);
+
+ this.vrControls = null;
+ this.vrCamera = null;
+ this.vrEffect = null;
+ }
+
+ RendererChangedEvent.prototype = Object.create(BaseEvent.prototype);
+ RendererChangedEvent.prototype.constructor = RendererChangedEvent;
+
+ RendererChangedEvent.prototype.start = function () {
+ this.app.on('rendererChanged.' + this.id, this.onRendererChanged.bind(this));
+ };
+
+ RendererChangedEvent.prototype.stop = function () {
+ this.app.on('rendererChanged.' + this.id, null);
+ };
+
+ RendererChangedEvent.prototype.onRendererChanged = function (newRenderer) {
+ var editor = this.app.editor;
+ var renderer = this.app.editor.renderer;
+ var container = this.app.viewport.container;
+
+ if (renderer != null) {
+ container.dom.removeChild(renderer.domElement);
+ }
+
+ renderer = newRenderer;
+ this.app.editor.renderer = renderer;
+
+ renderer.autoClear = false;
+ renderer.autoUpdateScene = false;
+ renderer.setPixelRatio(window.devicePixelRatio);
+ renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight);
+
+ container.dom.appendChild(renderer.domElement);
+
+ if (renderer.vr && renderer.vr.enabled) {
+ this.vrCamera = new THREE.PerspectiveCamera();
+ this.vrCamera.projectionMatrix = editor.camera.projectionMatrix;
+ editor.camera.add(this.vrCamera);
+ editor.vrCamera = this.vrCamera;
+
+ this.vrControls = new THREE.VRControls(this.vrCamera);
+ editor.vrControls = this.vrControls;
+
+ this.vrEffect = new THREE.VREffect(renderer);
+ editor.vrEffect = this.vrEffect;
+
+ var _this = this;
+
+ window.addEventListener('vrdisplaypresentchange', function (event) {
+ _this.vrEffect.isPresenting ? _this.app.call('enteredVR', _this) : _this.app.call('exitedVR', _this);
+ }, false);
+ }
+
+ this.app.call('render');
+ };
+
+ /**
+ * 编辑器
+ * @author mrdoob / http://mrdoob.com/
+ */
+ function Editor(app) {
+ this.app = app;
+ this.app.editor = this;
+
+ // 基础
+ this.config = new Config('threejs-editor');
+ this.history = new History(this);
+ this.storage = new Storage();
+ this.loader = new Loader(this);
+
+ // 场景
+ this.scene = new THREE.Scene();
+ this.scene.name = '场景';
+ this.scene.background = new THREE.Color(0xaaaaaa);
+
+ this.sceneHelpers = new THREE.Scene();
+
+ this.sceneName = null; // 当前场景名称
+
+ // 相机
+ this.DEFAULT_CAMERA = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);
+ this.DEFAULT_CAMERA.name = '默认相机';
+ this.DEFAULT_CAMERA.position.set(20, 10, 20);
+ this.DEFAULT_CAMERA.lookAt(new THREE.Vector3());
+
+ this.camera = this.DEFAULT_CAMERA.clone();
+
+ // 渲染器
+ this.rendererTypes = {
+ 'WebGLRenderer': THREE.WebGLRenderer,
+ 'CanvasRenderer': THREE.CanvasRenderer,
+ 'SVGRenderer': THREE.SVGRenderer,
+ 'SoftwareRenderer': THREE.SoftwareRenderer,
+ 'RaytracingRenderer': THREE.RaytracingRenderer
+ };
+
+ this.renderer = this.createRendererFromConfig();
+ this.app.viewport.container.dom.appendChild(this.renderer.domElement);
+ (new RendererChangedEvent(this.app)).onRendererChanged(this.renderer);
+
+ // 缓存
+ this.object = {};
+ this.objects = [];
+ this.geometries = {};
+ this.materials = {};
+ this.textures = {};
+ this.scripts = {};
+ this.helpers = {};
+
+ // 当前选中物体
+ this.selected = null;
+
+ // 网格
+ this.grid = new THREE.GridHelper(30, 30, 0x444444, 0x888888);
+ this.sceneHelpers.add(this.grid);
+
+ // 选中包围盒(当mesh.useSelectionBox === false时,不使用包围盒)
+ this.selectionBox = new THREE.BoxHelper();
+ this.selectionBox.material.depthTest = false;
+ this.selectionBox.material.transparent = true;
+ this.selectionBox.visible = false;
+ this.sceneHelpers.add(this.selectionBox);
+
+ // 平移旋转缩放控件
+ this.transformControls = new THREE.TransformControls(this.camera, this.app.viewport.container.dom);
+ this.sceneHelpers.add(this.transformControls);
+
+ // 编辑器控件
+ this.controls = new THREE.EditorControls(this.camera, this.app.viewport.container.dom);
+
+ // 性能控件
+ this.stats = new Stats();
+ this.stats.dom.style.position = 'absolute';
+ this.stats.dom.style.left = '8px';
+ this.stats.dom.style.top = '8px';
+ this.stats.dom.style.zIndex = 'initial';
+ this.app.viewport.container.dom.appendChild(this.stats.dom);
+ }
+ // ---------------------- 渲染器 ---------------------------
+
+ Editor.prototype.createRenderer = function (options) { // 创建渲染器
+ var rendererType = options.rendererType === undefined ? 'WebGLRenderer' : options.rendererType;
+ var antialias = options.antialias === undefined ? true : options.antialias;
+ var shadows = options.shadows === undefined ? true : options.shadows;
+ var gammaIn = options.gammaIn === undefined ? false : options.gammaIn;
+ var gammaOut = options.gammaOut === undefined ? false : options.gammaOut;
+ var rendererTypes = this.rendererTypes;
+
+ var renderer = new rendererTypes[rendererType]({ antialias: antialias });
+ renderer.gammaInput = gammaIn;
+ renderer.gammaOutput = gammaOut;
+ if (shadows && renderer.shadowMap) {
+ renderer.shadowMap.enabled = true;
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
+ }
+ return renderer;
+ };
+
+ Editor.prototype.createRendererFromConfig = function () { // 从配置创建渲染器
+ var rendererType = this.config.getKey('project/renderer');
+ var antialias = this.config.getKey('project/renderer/antialias');
+ var shadows = this.config.getKey('project/renderer/shadows');
+ var gammaIn = this.config.getKey('project/renderer/gammaInput');
+ var gammaOut = this.config.getKey('project/renderer/gammaOutput');
+
+ return this.createRenderer({
+ rendererType: rendererType,
+ antialias: antialias,
+ shadows: shadows,
+ gammaIn: gammaIn,
+ gammaOut: gammaOut
+ });
+ };
+
+ // -------------------- 编辑器 --------------------------
+
+ Editor.prototype.setTheme = function (value) { // 设置主题
+ this.app.call('setTheme', this, value);
+ };
+
+ Editor.prototype.setScene = function (scene) { // 设置场景
+ this.app.call('setScene', this, scene);
+ };
+
+ // ---------------------- 物体 ---------------------------
+
+ Editor.prototype.objectByUuid = function (uuid) { // 根据uuid获取物体
+ return this.scene.getObjectByProperty('uuid', uuid, true);
+ };
+
+ Editor.prototype.addObject = function (object) { // 添加物体
+ this.app.call('addObject', this, object);
+ };
+
+ Editor.prototype.moveObject = function (object, parent, before) { // 移动物体
+ this.app.call('moveObject', this, object, parent, before);
+ };
+
+ Editor.prototype.nameObject = function (object, name) { // 重命名物体
+ this.app.call('nameObject', this, object, name);
+ };
+
+ Editor.prototype.removeObject = function (object) { // 移除物体
+ this.app.call('removeObject', this, object);
+ };
+
+ Editor.prototype.addGeometry = function (geometry) { // 添加几何体
+ this.app.call('addGeometry', this, geometry);
+ };
+
+ Editor.prototype.setGeometryName = function (geometry, name) { // 设置几何体名称
+ this.app.call('setGeometryName', this, geometry, name);
+ };
+
+ Editor.prototype.addMaterial = function (material) { // 添加材质
+ this.app.call('addMaterial', this, material);
+ };
+
+ Editor.prototype.setMaterialName = function (material, name) { // 设置材质名称事件
+ this.app.call('setMaterialName', this, material, name);
+ };
+
+ Editor.prototype.addTexture = function (texture) { // 添加纹理事件
+ this.app.call('addTexture', this, texture);
+ };
+
+ // ------------------------- 帮助 ------------------------------
+
+ Editor.prototype.addHelper = function (object) { // 添加物体帮助
+ this.app.call('addHelper', this, object);
+ };
+
+ Editor.prototype.removeHelper = function (object) { // 移除物体帮助
+ this.app.call('removeHelper', this, object);
+ };
+
+ // ------------------------ 脚本 ----------------------------
+
+ Editor.prototype.addScript = function (object, script) { // 添加脚本
+ this.app.call('addScript', this, object, script);
+ };
+
+ Editor.prototype.removeScript = function (object, script) { // 移除脚本
+ this.app.call('removeScript', this, object, script);
+ };
+
+ // ------------------------ 选中事件 --------------------------------
+
+ Editor.prototype.select = function (object) { // 选中物体
+ this.app.call('select', this, object);
+ };
+
+ Editor.prototype.selectById = function (id) { // 根据id选中物体
+ if (id === this.camera.id) {
+ this.select(this.camera);
+ return;
+ }
+
+ this.select(this.scene.getObjectById(id, true));
+ };
+
+ Editor.prototype.selectByUuid = function (uuid) { // 根据uuid选中物体
+ var _this = this;
+ this.scene.traverse(function (child) {
+ if (child.uuid === uuid) {
+ _this.select(child);
+ }
+ });
+ };
+
+ Editor.prototype.deselect = function () { // 取消选中物体
+ this.select(null);
+ };
+
+ // ---------------------- 焦点事件 --------------------------
+
+ Editor.prototype.focus = function (object) { // 设置焦点
+ this.app.call('objectFocused', this, object);
+ };
+
+ Editor.prototype.focusById = function (id) { // 根据id设置交点
+ this.focus(this.scene.getObjectById(id, true));
+ };
+
+ // ----------------------- 场景事件 ----------------------------
+
+ Editor.prototype.clear = function () { // 清空场景
+ this.app.call('clear', this);
+ };
+
+ Editor.prototype.load = function () { // 加载场景
+ this.app.call('load', this);
+ };
+
+ Editor.prototype.save = function () { // 保存场景
+ this.app.call('save', this);
+ };
+
+ // --------------------- 命令事件 ------------------------
+
+ Editor.prototype.execute = function (cmd, optionalName) { // 执行事件
+ this.history.execute(cmd, optionalName);
+ };
+
+ Editor.prototype.undo = function () { // 撤销事件
+ this.history.undo();
+ };
+
+ Editor.prototype.redo = function () { // 重做事件
+ this.history.redo();
+ };
+
+ // ------------------------- 序列化 ----------------------------
+
+ Editor.prototype.fromJSON = function (json) { // 根据json创建场景
+ var loader = new THREE.ObjectLoader();
+
+ // backwards
+
+ if (json.scene === undefined) {
+ this.setScene(loader.parse(json));
+ return;
+ }
+
+ var camera = loader.parse(json.camera);
+
+ this.camera.copy(camera);
+ this.camera.aspect = this.DEFAULT_CAMERA.aspect;
+ this.camera.updateProjectionMatrix();
+
+ this.history.fromJSON(json.history);
+ this.scripts = json.scripts;
+
+ this.setScene(loader.parse(json.scene));
+ };
+
+ Editor.prototype.toJSON = function () { // 将场景转换为json
+ // scripts clean up
+ var scene = this.scene;
+ var scripts = this.scripts;
+
+ for (var key in scripts) {
+ var script = scripts[key];
+
+ if (script.length === 0 || scene.getObjectByProperty('uuid', key) === undefined) {
+ delete scripts[key];
+ }
+ }
+
+ return {
+ metadata: {},
+ project: {
+ gammaInput: this.config.getKey('project/renderer/gammaInput'),
+ gammaOutput: this.config.getKey('project/renderer/gammaOutput'),
+ shadows: this.config.getKey('project/renderer/shadows'),
+ vr: this.config.getKey('project/vr')
+ },
+ camera: this.camera.toJSON(),
+ scene: this.scene.toJSON(),
+ scripts: this.scripts,
+ history: this.history.toJSON()
+ };
+ };
+
+ function Physics(options) {
+ this.app = options.app;
+
+ // Physics configuration
+ this.collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration();
+ this.dispatcher = new Ammo.btCollisionDispatcher(this.collisionConfiguration);
+ this.broadphase = new Ammo.btDbvtBroadphase();
+ this.solver = new Ammo.btSequentialImpulseConstraintSolver();
+ this.softBodySolver = new Ammo.btDefaultSoftBodySolver();
+
+ this.physicsWorld = new Ammo.btSoftRigidDynamicsWorld(this.dispatcher, this.broadphase, this.solver, this.collisionConfiguration, this.softBodySolver);
+ this.physicsWorld.setGravity(new Ammo.btVector3(0, this.app.options.gravityConstant, 0));
+ this.physicsWorld.getWorldInfo().set_m_gravity(new Ammo.btVector3(0, this.app.options.gravityConstant, 0));
+ }
+
+ Physics.prototype.init = function () {
+
+ };
+
+ /**
+ * 应用程序
+ */
+ function Application(container, options) {
+
+ // 容器
+ this.container = container;
+ this.width = this.container.clientWidth;
+ this.height = this.container.clientHeight;
+
+ // 配置
+ this.options = new Options(options);
+
+ // 事件
+ this.event = new EventDispatcher(this);
+ this.call = this.event.call.bind(this.event);
+ this.on = this.event.on.bind(this.event);
+
+ var params = { app: this, parent: this.container };
+
+ // 用户界面
+ this.ui = UI$1;
+
+ this.menubar = new Menubar(params); // 菜单栏
+ this.menubar.render();
+
+ this.toolbar = new Toolbar(params); // 工具栏
+ this.toolbar.render();
+
+ this.viewport = new Viewport(params); // 场景编辑区
+ this.viewport.render();
+
+ this.editor = new Editor(this); // 编辑器
+
+ this.sidebar = new Sidebar(params); // 侧边栏
+ this.sidebar.render();
+
+ this.statusBar = new StatusBar(params); // 状态栏
+ this.statusBar.render();
+
+ this.script = new Script(params); // 脚本编辑面板
+ this.script.render();
+
+ this.player = new Player(params); // 播放器面板
+ this.player.render();
+
+ this.timePanel = new TimePanel(params); // 时间面板
+ this.timePanel.render();
+
+ // 物理引擎
+ this.physics = new Physics(params);
+ this.physics.init();
+
+ this.running = false;
+
+ // 是否从文件中加载场景,从文件中加载场景的url格式是index.html#file=xxx
+ this.isLoadingFromHash = false;
+ }
+
+ Application.prototype.start = function () {
+ this.running = true;
+
+ // 启动事件 - 事件要在ui创建完成后启动
+ this.event.start();
+
+ this.call('appStart', this);
+ this.call('resize', this);
+ this.call('initApp', this);
+ this.call('appStarted', this);
+ };
+
+ Application.prototype.stop = function () {
+ this.running = false;
+
+ this.call('appStop', this);
+ this.call('appStoped', this);
+
+ this.event.stop();
+ };
+
+ /**
+ * 配置序列化器
*/
function ConfigSerializer() {
BaseSerializer.call(this);
@@ -35617,13 +41230,26 @@
ConfigSerializer.prototype = Object.create(BaseSerializer.prototype);
ConfigSerializer.prototype.constructor = ConfigSerializer;
- ConfigSerializer.prototype.toJSON = function (obj) {
- var json = obj.toJSON();
+ ConfigSerializer.prototype.filter = function (obj) {
+ if (obj instanceof Application) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ ConfigSerializer.prototype.toJSON = function (app) {
+ var json = BaseSerializer.prototype.toJSON(app);
+ Object.assign(json, app.editor.config.toJSON());
return json;
};
- ConfigSerializer.prototype.fromJSON = function (json) {
-
+ ConfigSerializer.prototype.fromJSON = function (app, json) {
+ Object.keys(json).forEach(key => {
+ app.editor.config.setKey(key, json[key]);
+ });
};
/**
@@ -35636,12 +41262,46 @@
ScriptSerializer.prototype = Object.create(BaseSerializer.prototype);
ScriptSerializer.prototype.constructor = ScriptSerializer;
- ScriptSerializer.prototype.toJSON = function (obj) {
- return obj;
+ ScriptSerializer.prototype.filter = function (obj) {
+ if (obj instanceof Application) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
};
- ScriptSerializer.prototype.fromJSON = function (json) {
+ ScriptSerializer.prototype.toJSON = function (app) {
+ var list = [];
+ Object.keys(app.editor.scripts).forEach(id => {
+ var json = BaseSerializer.prototype.toJSON(app);
+
+ var name = app.editor.scripts[id].name;
+ var source = app.editor.scripts[id].source;
+
+ Object.assign(json, {
+ id: id,
+ name: name,
+ source: source
+ });
+
+ list.push(json);
+ });
+
+ return list;
+ };
+
+ ScriptSerializer.prototype.fromJSON = function (app, json) {
+ app.editor.scripts = {};
+
+ json.forEach(n => {
+ app.editor.scripts[id] = {
+ name: n.name,
+ source: n.source
+ };
+ });
};
/**
@@ -35654,6 +41314,16 @@
CameraSerializer$1.prototype = Object.create(BaseSerializer.prototype);
CameraSerializer$1.prototype.constructor = CameraSerializer$1;
+ CameraSerializer$1.prototype.filter = function (obj) {
+ if (obj instanceof THREE.Camera) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
CameraSerializer$1.prototype.toJSON = function (obj) {
var json = Object3DSerializer.prototype.toJSON(obj);
@@ -35663,8 +41333,12 @@
return json;
};
- CameraSerializer$1.prototype.fromJSON = function (json) {
+ CameraSerializer$1.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? new THREE.Camera() : parent;
+ // TODO: Three.Camera反序列化
+
+ return obj;
};
/**
@@ -35677,6 +41351,16 @@
OrthographicCameraSerializer.prototype = Object.create(BaseSerializer.prototype);
OrthographicCameraSerializer.prototype.constructor = OrthographicCameraSerializer;
+ OrthographicCameraSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.OrthographicCamera) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
OrthographicCameraSerializer.prototype.toJSON = function (obj) {
var json = CameraSerializer$1.prototype.toJSON(obj);
@@ -35692,8 +41376,12 @@
return json;
};
- OrthographicCameraSerializer.prototype.fromJSON = function (json) {
+ OrthographicCameraSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? new THREE.OrthographicCamera() : parent;
+ // TODO: THREE.OrthographicCamera反序列化
+
+ return obj;
};
/**
@@ -35706,6 +41394,16 @@
PerspectiveCameraSerializer.prototype = Object.create(BaseSerializer.prototype);
PerspectiveCameraSerializer.prototype.constructor = PerspectiveCameraSerializer;
+ PerspectiveCameraSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.PerspectiveCamera) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
PerspectiveCameraSerializer.prototype.toJSON = function (obj) {
var json = CameraSerializer$1.prototype.toJSON(obj);
@@ -35722,8 +41420,12 @@
return json;
};
- PerspectiveCameraSerializer.prototype.fromJSON = function (json) {
+ PerspectiveCameraSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? new THREE.PerspectiveCamera() : parent;
+ // TODO: THREE.PerspectiveCamera 反序列化
+
+ return obj;
};
/**
@@ -35876,25 +41578,23 @@
Converter.prototype.constructor = Converter;
Converter.prototype.filter = function (obj) {
- return true;
+ return false;
};
Converter.prototype.toJSON = function (app) {
var list = [];
// 配置
- var config = {
- Metadata: Serializers.Config.Metadata,
- Object: Serializers.Config.Serializer.toJSON(app.editor.config),
- };
+ var config = (new ConfigSerializer()).toJSON(app);
list.push(config);
// 相机
- var camera = {
- Metadata: Serializers.PerspectiveCamera.Metadata,
- Object: Serializers.PerspectiveCamera.Serializer.toJSON(app.editor.camera)
- };
- list.push(camera);
+ var camera;
+ if (app.editor.camera instanceof THREE.OrthographicCamera) {
+ camera = (new OrthographicCameraSerializer()).toJSON(app.editor.camera);
+ } else {
+ camera = (new PerspectiveCameraSerializer()).toJSON(app.editor.camera);
+ }
// 脚本
Object.keys(app.editor.scripts).forEach(function (id) {
@@ -35912,17 +41612,17 @@
});
// 场景
- app.editor.scene.traverse(function (obj) {
- if (Serializers[obj.constructor.name] != null) {
- var json = {
- Metadata: Serializers[obj.constructor.name].Metadata,
- Object: Serializers[obj.constructor.name].Serializer.toJSON(obj)
- };
- list.push(json);
- } else {
- console.log(`There is no serializer to serialize ${obj.name}`);
- }
- });
+ // app.editor.scene.traverse(function (obj) {
+ // if (Serializers[obj.constructor.name] != null) {
+ // var json = {
+ // Metadata: Serializers[obj.constructor.name].Metadata,
+ // Object: Serializers[obj.constructor.name].Serializer.toJSON(obj)
+ // };
+ // list.push(json);
+ // } else {
+ // console.log(`There is no serializer to serialize ${obj.name}`);
+ // }
+ // });
return list;
};
@@ -36252,76 +41952,6 @@
};
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @constructor
- */
-
- function AddObjectCommand(object) {
-
- Command.call(this);
-
- this.type = 'AddObjectCommand';
-
- this.object = object;
- if (object !== undefined) {
-
- this.name = 'Add Object: ' + object.name;
-
- }
-
- }
- AddObjectCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(AddObjectCommand.prototype, {
-
- constructor: AddObjectCommand,
-
- execute: function () {
-
- this.editor.addObject(this.object);
- this.editor.select(this.object);
-
- },
-
- undo: function () {
-
- this.editor.removeObject(this.object);
- this.editor.deselect();
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
- output.object = this.object.toJSON();
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.object = this.editor.objectByUuid(json.object.object.uuid);
-
- if (this.object === undefined) {
-
- var loader = new THREE.ObjectLoader();
- this.object = loader.parse(json.object);
-
- }
-
- }
-
- });
-
/**
* 文件上传器
*/
@@ -37130,84 +42760,6 @@
});
};
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param attributeName string
- * @param newValue number, string, boolean or object
- * @constructor
- */
-
- function SetMaterialValueCommand(object, attributeName, newValue) {
-
- Command.call(this);
-
- this.type = 'SetMaterialValueCommand';
- this.name = 'Set Material.' + attributeName;
- this.updatable = true;
-
- this.object = object;
- this.oldValue = (object !== undefined) ? object.material[attributeName] : undefined;
- this.newValue = newValue;
- this.attributeName = attributeName;
-
- }
- SetMaterialValueCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetMaterialValueCommand.prototype, {
-
- constructor: SetMaterialValueCommand,
-
- execute: function () {
- this.object.material[this.attributeName] = this.newValue;
- this.object.material.needsUpdate = true;
- this.editor.app.call('objectChanged', this, this.object);
- this.editor.app.call('materialChanged', this, this.object.material);
- },
-
- undo: function () {
- this.object.material[this.attributeName] = this.oldValue;
- this.object.material.needsUpdate = true;
- this.editor.app.call('objectChanged', this, this.object);
- this.editor.app.call('materialChanged', this, this.object.material);
- },
-
- update: function (cmd) {
-
- this.newValue = cmd.newValue;
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.objectUuid = this.object.uuid;
- output.attributeName = this.attributeName;
- output.oldValue = this.oldValue;
- output.newValue = this.newValue;
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.attributeName = json.attributeName;
- this.oldValue = json.oldValue;
- this.newValue = json.newValue;
- this.object = this.editor.objectByUuid(json.objectUuid);
-
- }
-
- });
-
/**
* @author dforrer / https://github.com/dforrer
* Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
@@ -39536,155 +45088,6 @@
});
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param newUuid string
- * @constructor
- */
-
- function SetUuidCommand(object, newUuid) {
-
- Command.call(this);
-
- this.type = 'SetUuidCommand';
- this.name = 'Update UUID';
-
- this.object = object;
-
- this.oldUuid = (object !== undefined) ? object.uuid : undefined;
- this.newUuid = newUuid;
-
- }
- SetUuidCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetUuidCommand.prototype, {
-
- constructor: SetUuidCommand,
-
- execute: function () {
-
- this.object.uuid = this.newUuid;
- this.editor.app.call('objectChanged', this, this.object);
- this.editor.app.call('sceneGraphChanged', this);
-
- },
-
- undo: function () {
-
- this.object.uuid = this.oldUuid;
- this.editor.app.call('objectChanged', this, this.object);
- this.editor.app.call('sceneGraphChanged', this);
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.oldUuid = this.oldUuid;
- output.newUuid = this.newUuid;
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.oldUuid = json.oldUuid;
- this.newUuid = json.newUuid;
- this.object = this.editor.objectByUuid(json.oldUuid);
-
- if (this.object === undefined) {
-
- this.object = this.editor.objectByUuid(json.newUuid);
-
- }
-
- }
-
- });
-
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param attributeName string
- * @param newValue number, string, boolean or object
- * @constructor
- */
-
- function SetValueCommand(object, attributeName, newValue) {
-
- Command.call(this);
-
- this.type = 'SetValueCommand';
- this.name = 'Set ' + attributeName;
- this.updatable = true;
-
- this.object = object;
- this.attributeName = attributeName;
- this.oldValue = (object !== undefined) ? object[attributeName] : undefined;
- this.newValue = newValue;
-
- }
- SetValueCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetValueCommand.prototype, {
-
- constructor: SetValueCommand,
-
- execute: function () {
- this.object[this.attributeName] = this.newValue;
- this.editor.app.call('objectChanged', this, this.object);
- },
-
- undo: function () {
- this.object[this.attributeName] = this.oldValue;
- this.editor.app.call('objectChanged', this, this.object);
- },
-
- update: function (cmd) {
-
- this.newValue = cmd.newValue;
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.objectUuid = this.object.uuid;
- output.attributeName = this.attributeName;
- output.oldValue = this.oldValue;
- output.newValue = this.newValue;
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.attributeName = json.attributeName;
- this.oldValue = json.oldValue;
- this.newValue = json.newValue;
- this.object = this.editor.objectByUuid(json.objectUuid);
-
- }
-
- });
-
/**
* @author dforrer / https://github.com/dforrer
* Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
@@ -40214,96 +45617,6 @@
this.updateTransformRows(object);
};
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param newGeometry THREE.Geometry
- * @constructor
- */
-
- function SetGeometryCommand(object, newGeometry) {
-
- Command.call(this);
-
- this.type = 'SetGeometryCommand';
- this.name = 'Set Geometry';
- this.updatable = true;
-
- this.object = object;
- this.oldGeometry = (object !== undefined) ? object.geometry : undefined;
- this.newGeometry = newGeometry;
-
- }
- SetGeometryCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetGeometryCommand.prototype, {
-
- constructor: SetGeometryCommand,
-
- execute: function () {
-
- this.object.geometry.dispose();
- this.object.geometry = this.newGeometry;
- this.object.geometry.computeBoundingSphere();
-
- this.editor.app.call('geometryChanged', this, this.object);
- this.editor.app.call('sceneGraphChanged', this);
-
- },
-
- undo: function () {
-
- this.object.geometry.dispose();
- this.object.geometry = this.oldGeometry;
- this.object.geometry.computeBoundingSphere();
-
- this.editor.app.call('geometryChanged', this, this.object);
- this.editor.app.call('sceneGraphChanged', this);
-
- },
-
- update: function (cmd) {
-
- this.newGeometry = cmd.newGeometry;
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.objectUuid = this.object.uuid;
- output.oldGeometry = this.object.geometry.toJSON();
- output.newGeometry = this.newGeometry.toJSON();
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.object = this.editor.objectByUuid(json.objectUuid);
-
- this.oldGeometry = parseGeometry(json.oldGeometry);
- this.newGeometry = parseGeometry(json.newGeometry);
-
- function parseGeometry(data) {
-
- var loader = new THREE.ObjectLoader();
- return loader.parseGeometries([data])[data.uuid];
-
- }
-
- }
-
- });
-
/**
* 正方体几何体
* @author mrdoob / http://mrdoob.com/
@@ -42788,103 +48101,6 @@
fogDensity.dom.style.display = type === 'FogExp2' ? '' : 'none';
};
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param script javascript object
- * @param attributeName string
- * @param newValue string, object
- * @param cursorPosition javascript object with format {line: 2, ch: 3}
- * @param scrollInfo javascript object with values {left, top, width, height, clientWidth, clientHeight}
- * @constructor
- */
-
- function SetScriptValueCommand(object, script, attributeName, newValue, cursorPosition, scrollInfo) {
-
- Command.call(this);
-
- this.type = 'SetScriptValueCommand';
- this.name = 'Set Script.' + attributeName;
- this.updatable = true;
-
- this.object = object;
- this.script = script;
-
- this.attributeName = attributeName;
- this.oldValue = (script !== undefined) ? script[this.attributeName] : undefined;
- this.newValue = newValue;
- this.cursorPosition = cursorPosition;
- this.scrollInfo = scrollInfo;
-
- }
- SetScriptValueCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetScriptValueCommand.prototype, {
-
- constructor: SetScriptValueCommand,
-
- execute: function () {
-
- this.script[this.attributeName] = this.newValue;
-
- this.editor.app.call('scriptChanged', this);
- this.editor.app.call('refreshScriptEditor', this, this.object, this.script, this.cursorPosition, this.scrollInfo);
-
- },
-
- undo: function () {
-
- this.script[this.attributeName] = this.oldValue;
-
- this.editor.app.call('scriptChanged', this);
- this.editor.app.call('refreshScriptEditor', this, this.object, this.script, this.cursorPosition, this.scrollInfo);
-
- },
-
- update: function (cmd) {
-
- this.cursorPosition = cmd.cursorPosition;
- this.scrollInfo = cmd.scrollInfo;
- this.newValue = cmd.newValue;
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.objectUuid = this.object.uuid;
- output.index = this.editor.scripts[this.object.uuid].indexOf(this.script);
- output.attributeName = this.attributeName;
- output.oldValue = this.oldValue;
- output.newValue = this.newValue;
- output.cursorPosition = this.cursorPosition;
- output.scrollInfo = this.scrollInfo;
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.oldValue = json.oldValue;
- this.newValue = json.newValue;
- this.attributeName = json.attributeName;
- this.object = this.editor.objectByUuid(json.objectUuid);
- this.script = this.editor.scripts[json.objectUuid][json.index];
- this.cursorPosition = json.cursorPosition;
- this.scrollInfo = json.scrollInfo;
-
- }
-
- });
-
/**
* @author dforrer / https://github.com/dforrer
* Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
@@ -43830,70 +49046,6 @@
}
};
- /**
- * 渲染器改变事件
- * @param {*} app
- */
- function RendererChangedEvent(app) {
- BaseEvent.call(this, app);
-
- this.vrControls = null;
- this.vrCamera = null;
- this.vrEffect = null;
- }
-
- RendererChangedEvent.prototype = Object.create(BaseEvent.prototype);
- RendererChangedEvent.prototype.constructor = RendererChangedEvent;
-
- RendererChangedEvent.prototype.start = function () {
- this.app.on('rendererChanged.' + this.id, this.onRendererChanged.bind(this));
- };
-
- RendererChangedEvent.prototype.stop = function () {
- this.app.on('rendererChanged.' + this.id, null);
- };
-
- RendererChangedEvent.prototype.onRendererChanged = function (newRenderer) {
- var editor = this.app.editor;
- var renderer = this.app.editor.renderer;
- var container = this.app.viewport.container;
-
- if (renderer != null) {
- container.dom.removeChild(renderer.domElement);
- }
-
- renderer = newRenderer;
- this.app.editor.renderer = renderer;
-
- renderer.autoClear = false;
- renderer.autoUpdateScene = false;
- renderer.setPixelRatio(window.devicePixelRatio);
- renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight);
-
- container.dom.appendChild(renderer.domElement);
-
- if (renderer.vr && renderer.vr.enabled) {
- this.vrCamera = new THREE.PerspectiveCamera();
- this.vrCamera.projectionMatrix = editor.camera.projectionMatrix;
- editor.camera.add(this.vrCamera);
- editor.vrCamera = this.vrCamera;
-
- this.vrControls = new THREE.VRControls(this.vrCamera);
- editor.vrControls = this.vrControls;
-
- this.vrEffect = new THREE.VREffect(renderer);
- editor.vrEffect = this.vrEffect;
-
- var _this = this;
-
- window.addEventListener('vrdisplaypresentchange', function (event) {
- _this.vrEffect.isPresenting ? _this.app.call('enteredVR', _this) : _this.app.call('exitedVR', _this);
- }, false);
- }
-
- this.app.call('render');
- };
-
/**
* 渲染事件
* @param {*} app
@@ -44558,4778 +49710,6 @@
});
};
- /**
- * 系统配置
- * @author mrdoob / http://mrdoob.com/
- */
- function Config(name) {
- var storage = {
- 'autosave': true,
- 'theme': 'assets/css/light.css',
-
- 'project/renderer': 'WebGLRenderer',
- 'project/renderer/antialias': true,
- 'project/renderer/gammaInput': false,
- 'project/renderer/gammaOutput': false,
- 'project/renderer/shadows': true,
- 'project/vr': false,
-
- 'settings/history': false
- };
-
- if (window.localStorage[name] === undefined) {
- window.localStorage[name] = JSON.stringify(storage);
- } else {
- var data = JSON.parse(window.localStorage[name]);
-
- for (var key in data) {
- storage[key] = data[key];
- }
- }
-
- return {
- getKey: function (key) {
- return storage[key];
- },
-
- setKey: function () { // key, value, key, value ...
- for (var i = 0, l = arguments.length; i < l; i += 2) {
- storage[arguments[i]] = arguments[i + 1];
- }
-
- window.localStorage[name] = JSON.stringify(storage);
-
- console.log('[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']', '保存配置到LocalStorage。');
- },
-
- clear: function () {
- delete window.localStorage[name];
- },
-
- toJSON: function () {
- return storage;
- }
- };
- }
-
- /**
- * 历史记录
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
- function History(editor) {
- this.app = editor.app;
-
- this.editor = editor;
- this.undos = [];
- this.redos = [];
- this.lastCmdTime = new Date();
- this.idCounter = 0;
-
- this.historyDisabled = false;
- this.config = editor.config;
-
- //Set editor-reference in Command
-
- Command.call(this, editor);
-
- var scope = this;
-
- this.app.on('startPlayer.History', function () {
- scope.historyDisabled = true;
- });
-
- this.app.on('stopPlayer.History', function () {
- scope.historyDisabled = false;
- });
- }
- History.prototype = Object.create(Command.prototype);
-
- Object.assign(History.prototype, {
-
- constructor: History,
-
- execute: function (cmd, optionalName) {
-
- var lastCmd = this.undos[this.undos.length - 1];
- var timeDifference = new Date().getTime() - this.lastCmdTime.getTime();
-
- var isUpdatableCmd = lastCmd &&
- lastCmd.updatable &&
- cmd.updatable &&
- lastCmd.object === cmd.object &&
- lastCmd.type === cmd.type &&
- lastCmd.script === cmd.script &&
- lastCmd.attributeName === cmd.attributeName;
-
- if (isUpdatableCmd && cmd.type === "SetScriptValueCommand") {
-
- // When the cmd.type is "SetScriptValueCommand" the timeDifference is ignored
-
- lastCmd.update(cmd);
- cmd = lastCmd;
-
- } else if (isUpdatableCmd && timeDifference < 500) {
-
- lastCmd.update(cmd);
- cmd = lastCmd;
-
- } else {
-
- // the command is not updatable and is added as a new part of the history
-
- this.undos.push(cmd);
- cmd.id = ++this.idCounter;
-
- }
- cmd.name = (optionalName !== undefined) ? optionalName : cmd.name;
- cmd.execute();
- cmd.inMemory = true;
-
- if (this.config.getKey('settings/history')) {
-
- cmd.json = cmd.toJSON(); // serialize the cmd immediately after execution and append the json to the cmd
-
- }
- this.lastCmdTime = new Date();
-
- // clearing all the redo-commands
-
- this.redos = [];
- this.app.call('historyChanged', this, cmd);
-
- },
-
- undo: function () {
- if (this.historyDisabled) {
- UI$1.msg("场景启动时撤销/重做将被禁用。");
- return;
- }
-
- var cmd = undefined;
-
- if (this.undos.length > 0) {
- cmd = this.undos.pop();
-
- if (cmd.inMemory === false) {
- cmd.fromJSON(cmd.json);
- }
- }
-
- if (cmd !== undefined) {
- cmd.undo();
- this.redos.push(cmd);
- this.app.call('historyChanged', this, cmd);
- }
-
- return cmd;
- },
-
- redo: function () {
- if (this.historyDisabled) {
- UI$1.msg("场景启动时撤销/重做将被禁用。");
- return;
- }
-
- var cmd = undefined;
-
- if (this.redos.length > 0) {
- cmd = this.redos.pop();
-
- if (cmd.inMemory === false) {
- cmd.fromJSON(cmd.json);
- }
- }
-
- if (cmd !== undefined) {
- cmd.execute();
- this.undos.push(cmd);
- this.app.call('historyChanged', this, cmd);
- }
-
- return cmd;
- },
-
- toJSON: function () {
- var history = {};
- history.undos = [];
- history.redos = [];
-
- if (!this.config.getKey('settings/history')) {
- return history;
- }
-
- // Append Undos to History
- for (var i = 0; i < this.undos.length; i++) {
- if (this.undos[i].hasOwnProperty("json")) {
- history.undos.push(this.undos[i].json);
- }
- }
-
- // Append Redos to History
- for (var i = 0; i < this.redos.length; i++) {
- if (this.redos[i].hasOwnProperty("json")) {
- history.redos.push(this.redos[i].json);
- }
- }
-
- return history;
- },
-
- fromJSON: function (json) {
- if (json === undefined) return;
-
- for (var i = 0; i < json.undos.length; i++) {
- var cmdJSON = json.undos[i];
- var cmd = new window[cmdJSON.type](); // creates a new object of type "json.type"
- cmd.json = cmdJSON;
- cmd.id = cmdJSON.id;
- cmd.name = cmdJSON.name;
- this.undos.push(cmd);
- this.idCounter = (cmdJSON.id > this.idCounter) ? cmdJSON.id : this.idCounter; // set last used idCounter
- }
-
- for (var i = 0; i < json.redos.length; i++) {
- var cmdJSON = json.redos[i];
- var cmd = new window[cmdJSON.type](); // creates a new object of type "json.type"
- cmd.json = cmdJSON;
- cmd.id = cmdJSON.id;
- cmd.name = cmdJSON.name;
- this.redos.push(cmd);
- this.idCounter = (cmdJSON.id > this.idCounter) ? cmdJSON.id : this.idCounter; // set last used idCounter
- }
-
- // Select the last executed undo-command
- this.app.call('historyChanged', this, this.undos[this.undos.length - 1]);
- },
-
- clear: function () {
- this.undos = [];
- this.redos = [];
- this.idCounter = 0;
-
- this.app.call('historyChanged', this);
- },
-
- goToState: function (id) {
- if (this.historyDisabled) {
- UI$1.msg("场景启动时撤销/重做将被禁用。");
- return;
- }
-
- var cmd = this.undos.length > 0 ? this.undos[this.undos.length - 1] : undefined; // next cmd to pop
-
- if (cmd === undefined || id > cmd.id) {
- cmd = this.redo();
- while (cmd !== undefined && id > cmd.id) {
- cmd = this.redo();
- }
- } else {
- while (true) {
- cmd = this.undos[this.undos.length - 1]; // next cmd to pop
- if (cmd === undefined || id === cmd.id) break;
- cmd = this.undo();
- }
- }
-
- this.editor.app.call('sceneGraphChanged', this);
- this.editor.app.call('historyChanged', this, cmd);
- },
-
- enableSerialization: function (id) {
-
- /**
- * because there might be commands in this.undos and this.redos
- * which have not been serialized with .toJSON() we go back
- * to the oldest command and redo one command after the other
- * while also calling .toJSON() on them.
- */
-
- this.goToState(-1);
-
- var cmd = this.redo();
- while (cmd !== undefined) {
- if (!cmd.hasOwnProperty("json")) {
- cmd.json = cmd.toJSON();
- }
- cmd = this.redo();
- }
-
- this.goToState(id);
- }
- });
-
- /**
- * 本地存储
- * @author mrdoob / http://mrdoob.com/
- */
- function Storage() {
- var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
-
- if (indexedDB === undefined) {
- console.warn('Storage: IndexedDB不可用。');
- return { init: function () { }, get: function () { }, set: function () { }, clear: function () { } };
- }
-
- var name = 'threejs-editor';
- var version = 1;
-
- var database;
-
- return {
- init: function (callback) {
- var request = indexedDB.open(name, version);
- request.onupgradeneeded = function (event) {
- var db = event.target.result;
-
- if (db.objectStoreNames.contains('states') === false) {
-
- db.createObjectStore('states');
-
- }
- };
- request.onsuccess = function (event) {
- database = event.target.result;
-
- callback();
- };
- request.onerror = function (event) {
- console.error('IndexedDB', event);
- };
- },
-
- get: function (callback) {
- var transaction = database.transaction(['states'], 'readwrite');
- var objectStore = transaction.objectStore('states');
- var request = objectStore.get(0);
- request.onsuccess = function (event) {
- callback(event.target.result);
- };
-
- },
-
- set: function (data, callback) {
- var start = performance.now();
-
- var transaction = database.transaction(['states'], 'readwrite');
- var objectStore = transaction.objectStore('states');
- var request = objectStore.put(data, 0);
- request.onsuccess = function (event) {
- console.log('[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']', '保存到IndexedDB中。 ' + (performance.now() - start).toFixed(2) + 'ms');
- };
-
- },
-
- clear: function () {
- if (database === undefined) return;
-
- var transaction = database.transaction(['states'], 'readwrite');
- var objectStore = transaction.objectStore('states');
- var request = objectStore.clear();
- request.onsuccess = function (event) {
- console.log('[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']', '清空IndexedDB。');
- };
- }
- };
- }
-
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param scene containing children to import
- * @constructor
- */
-
- function SetSceneCommand(scene) {
-
- Command.call(this);
-
- this.type = 'SetSceneCommand';
- this.name = 'Set Scene';
-
- this.cmdArray = [];
-
- if (scene !== undefined) {
-
- this.cmdArray.push(new SetUuidCommand(this.editor.scene, scene.uuid));
- this.cmdArray.push(new SetValueCommand(this.editor.scene, 'name', scene.name));
- this.cmdArray.push(new SetValueCommand(this.editor.scene, 'userData', JSON.parse(JSON.stringify(scene.userData))));
-
- while (scene.children.length > 0) {
-
- var child = scene.children.pop();
- this.cmdArray.push(new AddObjectCommand(child));
-
- }
-
- }
-
- }
- SetSceneCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetSceneCommand.prototype, {
-
- constructor: SetSceneCommand,
-
- execute: function () {
- for (var i = 0; i < this.cmdArray.length; i++) {
-
- this.cmdArray[i].execute();
-
- }
- this.editor.app.call('sceneGraphChanged', this);
- },
-
- undo: function () {
- for (var i = this.cmdArray.length - 1; i >= 0; i--) {
-
- this.cmdArray[i].undo();
-
- }
- this.editor.app.call('sceneGraphChanged', this);
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- var cmds = [];
- for (var i = 0; i < this.cmdArray.length; i++) {
-
- cmds.push(this.cmdArray[i].toJSON());
-
- }
- output.cmds = cmds;
-
- return output;
-
- },
-
- fromJSON: function (json) {
- Command.prototype.fromJSON.call(this, json);
-
- var cmds = json.cmds;
- for (var i = 0; i < cmds.length; i++) {
- var cmd = new window[cmds[i].type](); // creates a new object of type "json.type"
- cmd.fromJSON(cmds[i]);
- this.cmdArray.push(cmd);
- }
- }
- });
-
- /**
- * 模型加载
- * @author mrdoob / http://mrdoob.com/
- */
- function Loader(editor) {
-
- var scope = this;
-
- this.texturePath = '';
-
- this.loadFile = function (file) {
-
- var filename = file.name;
- var extension = filename.split('.').pop().toLowerCase();
-
- var reader = new FileReader();
- reader.addEventListener('progress', function (event) {
-
- var size = '(' + Math.floor(event.total / 1000).format() + ' KB)';
- var progress = Math.floor((event.loaded / event.total) * 100) + '%';
- console.log('加载中', filename, size, progress);
-
- });
-
- switch (extension) {
-
- case 'amf':
-
- reader.addEventListener('load', function (event) {
-
- var loader = new THREE.AMFLoader();
- var amfobject = loader.parse(event.target.result);
-
- editor.execute(new AddObjectCommand(amfobject));
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'awd':
-
- reader.addEventListener('load', function (event) {
-
- var loader = new THREE.AWDLoader();
- var scene = loader.parse(event.target.result);
-
- editor.execute(new SetSceneCommand(scene));
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'babylon':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
- var json = JSON.parse(contents);
-
- var loader = new THREE.BabylonLoader();
- var scene = loader.parse(json);
-
- editor.execute(new SetSceneCommand(scene));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'babylonmeshdata':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
- var json = JSON.parse(contents);
-
- var loader = new THREE.BabylonLoader();
-
- var geometry = loader.parseGeometry(json);
- var material = new THREE.MeshStandardMaterial();
-
- var mesh = new THREE.Mesh(geometry, material);
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'ctm':
-
- reader.addEventListener('load', function (event) {
-
- var data = new Uint8Array(event.target.result);
-
- var stream = new CTM.Stream(data);
- stream.offset = 0;
-
- var loader = new THREE.CTMLoader();
- loader.createModel(new CTM.File(stream), function (geometry) {
-
- geometry.sourceType = "ctm";
- geometry.sourceFile = file.name;
-
- var material = new THREE.MeshStandardMaterial();
-
- var mesh = new THREE.Mesh(geometry, material);
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- });
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'dae':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var loader = new THREE.ColladaLoader();
- var collada = loader.parse(contents);
-
- collada.scene.name = filename;
-
- editor.execute(new AddObjectCommand(collada.scene));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'fbx':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var loader = new THREE.FBXLoader();
- var object = loader.parse(contents);
-
- editor.execute(new AddObjectCommand(object));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'glb':
- case 'gltf':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var loader = new THREE.GLTFLoader();
- loader.parse(contents, function (result) {
-
- result.scene.name = filename;
- editor.execute(new AddObjectCommand(result.scene));
-
- });
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'js':
- case 'json':
-
- case '3geo':
- case '3mat':
- case '3obj':
- case '3scn':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- // 2.0
-
- if (contents.indexOf('postMessage') !== -1) {
-
- var blob = new Blob([contents], { type: 'text/javascript' });
- var url = URL.createObjectURL(blob);
-
- var worker = new Worker(url);
-
- worker.onmessage = function (event) {
-
- event.data.metadata = { version: 2 };
- handleJSON(event.data, file, filename);
-
- };
-
- worker.postMessage(Date.now());
-
- return;
-
- }
-
- // >= 3.0
-
- var data;
-
- try {
-
- data = JSON.parse(contents);
-
- } catch (error) {
-
- UI$1.msg(error);
- return;
-
- }
-
- handleJSON(data, file, filename);
-
- }, false);
- reader.readAsText(file);
-
- break;
-
-
- case 'kmz':
-
- reader.addEventListener('load', function (event) {
-
- var loader = new THREE.KMZLoader();
- var collada = loader.parse(event.target.result);
-
- collada.scene.name = filename;
-
- editor.execute(new AddObjectCommand(collada.scene));
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'md2':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var geometry = new THREE.MD2Loader().parse(contents);
- var material = new THREE.MeshStandardMaterial({
- morphTargets: true,
- morphNormals: true
- });
-
- var mesh = new THREE.Mesh(geometry, material);
- mesh.mixer = new THREE.AnimationMixer(mesh);
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'obj':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var object = new THREE.OBJLoader().parse(contents);
- object.name = filename;
-
- editor.execute(new AddObjectCommand(object));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'playcanvas':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
- var json = JSON.parse(contents);
-
- var loader = new THREE.PlayCanvasLoader();
- var object = loader.parse(json);
-
- editor.execute(new AddObjectCommand(object));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'ply':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var geometry = new THREE.PLYLoader().parse(contents);
- geometry.sourceType = "ply";
- geometry.sourceFile = file.name;
-
- var material = new THREE.MeshStandardMaterial();
-
- var mesh = new THREE.Mesh(geometry, material);
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- }, false);
- reader.readAsArrayBuffer(file);
-
- break;
-
- case 'stl':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var geometry = new THREE.STLLoader().parse(contents);
- geometry.sourceType = "stl";
- geometry.sourceFile = file.name;
-
- var material = new THREE.MeshStandardMaterial();
-
- var mesh = new THREE.Mesh(geometry, material);
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- }, false);
-
- if (reader.readAsBinaryString !== undefined) {
-
- reader.readAsBinaryString(file);
-
- } else {
-
- reader.readAsArrayBuffer(file);
-
- }
-
- break;
-
- /*
- case 'utf8':
-
- reader.addEventListener( 'load', function ( event ) {
-
- var contents = event.target.result;
-
- var geometry = new THREE.UTF8Loader().parse( contents );
- var material = new THREE.MeshLambertMaterial();
-
- var mesh = new THREE.Mesh( geometry, material );
-
- editor.execute( new AddObjectCommand( mesh ) );
-
- }, false );
- reader.readAsBinaryString( file );
-
- break;
- */
-
- case 'vtk':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var geometry = new THREE.VTKLoader().parse(contents);
- geometry.sourceType = "vtk";
- geometry.sourceFile = file.name;
-
- var material = new THREE.MeshStandardMaterial();
-
- var mesh = new THREE.Mesh(geometry, material);
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- case 'wrl':
-
- reader.addEventListener('load', function (event) {
-
- var contents = event.target.result;
-
- var result = new THREE.VRMLLoader().parse(contents);
-
- editor.execute(new SetSceneCommand(result));
-
- }, false);
- reader.readAsText(file);
-
- break;
-
- default:
-
- UI$1.msg('不支持的文件类型(' + extension + ').');
-
- break;
-
- }
-
- };
-
- function handleJSON(data, file, filename) {
-
- if (data.metadata === undefined) { // 2.0
-
- data.metadata = { type: 'Geometry' };
-
- }
-
- if (data.metadata.type === undefined) { // 3.0
-
- data.metadata.type = 'Geometry';
-
- }
-
- if (data.metadata.formatVersion !== undefined) {
-
- data.metadata.version = data.metadata.formatVersion;
-
- }
-
- switch (data.metadata.type.toLowerCase()) {
-
- case 'buffergeometry':
-
- var loader = new THREE.BufferGeometryLoader();
- var result = loader.parse(data);
-
- var mesh = new THREE.Mesh(result);
-
- editor.execute(new AddObjectCommand(mesh));
-
- break;
-
- case 'geometry':
-
- var loader = new THREE.JSONLoader();
- loader.setTexturePath(scope.texturePath);
-
- var result = loader.parse(data);
-
- var geometry = result.geometry;
- var material;
-
- if (result.materials !== undefined) {
-
- if (result.materials.length > 1) {
-
- material = new THREE.MultiMaterial(result.materials);
-
- } else {
-
- material = result.materials[0];
-
- }
-
- } else {
-
- material = new THREE.MeshStandardMaterial();
-
- }
-
- geometry.sourceType = "ascii";
- geometry.sourceFile = file.name;
-
- var mesh;
-
- if (geometry.animation && geometry.animation.hierarchy) {
-
- mesh = new THREE.SkinnedMesh(geometry, material);
-
- } else {
-
- mesh = new THREE.Mesh(geometry, material);
-
- }
-
- mesh.name = filename;
-
- editor.execute(new AddObjectCommand(mesh));
-
- break;
-
- case 'object':
-
- var loader = new THREE.ObjectLoader();
- loader.setTexturePath(scope.texturePath);
-
- var result = loader.parse(data);
-
- if (result instanceof THREE.Scene) {
-
- editor.execute(new SetSceneCommand(result));
-
- } else {
-
- editor.execute(new AddObjectCommand(result));
-
- }
-
- break;
-
- case 'scene':
-
- // DEPRECATED
-
- var loader = new THREE.SceneLoader();
- loader.parse(data, function (result) {
-
- editor.execute(new SetSceneCommand(result.scene));
-
- }, '');
-
- break;
-
- case 'app':
-
- editor.fromJSON(data);
-
- break;
-
- }
-
- }
-
- }
-
- /**
- * 播放器
- * @author mrdoob / http://mrdoob.com/
- */
- function AppPlayer() {
- var loader = new THREE.ObjectLoader();
- var camera, scene, renderer;
-
- var events = {};
-
- var dom = document.createElement('div');
-
- this.dom = dom;
-
- this.width = 500;
- this.height = 500;
-
- this.load = function (json) {
- renderer = new THREE.WebGLRenderer({ antialias: true });
- renderer.setClearColor(0x000000);
- renderer.setPixelRatio(window.devicePixelRatio);
-
- var project = json.project;
-
- if (project.gammaInput) renderer.gammaInput = true;
- if (project.gammaOutput) renderer.gammaOutput = true;
- if (project.shadows) renderer.shadowMap.enabled = true;
- if (project.vr) renderer.vr.enabled = true;
-
- dom.appendChild(renderer.domElement);
-
- this.setScene(loader.parse(json.scene));
- this.setCamera(loader.parse(json.camera));
-
- events = {
- init: [],
- start: [],
- stop: [],
- keydown: [],
- keyup: [],
- mousedown: [],
- mouseup: [],
- mousemove: [],
- touchstart: [],
- touchend: [],
- touchmove: [],
- update: []
- };
-
- var scriptWrapParams = 'player,renderer,scene,camera';
- var scriptWrapResultObj = {};
-
- for (var eventKey in events) {
- scriptWrapParams += ',' + eventKey;
- scriptWrapResultObj[eventKey] = eventKey;
- }
-
- var scriptWrapResult = JSON.stringify(scriptWrapResultObj).replace(/\"/g, '');
-
- for (var uuid in json.scripts) {
- var object = scene.getObjectByProperty('uuid', uuid, true);
-
- if (object === undefined) {
- console.warn('APP.Player: Script without object.', uuid);
- continue;
- }
-
- var scripts = json.scripts[uuid];
-
- for (var i = 0; i < scripts.length; i++) {
- var script = scripts[i];
-
- var functions = (new Function(scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';').bind(object))(this, renderer, scene, camera);
-
- for (var name in functions) {
-
- if (functions[name] === undefined) continue;
-
- if (events[name] === undefined) {
- console.warn('APP.Player: Event type not supported (', name, ')');
- continue;
- }
-
- events[name].push(functions[name].bind(object));
- }
-
- }
-
- }
-
- dispatch$$1(events.init, arguments);
-
- };
-
- this.setCamera = function (value) {
- camera = value;
- camera.aspect = this.width / this.height;
- camera.updateProjectionMatrix();
-
- if (renderer.vr.enabled) {
- dom.appendChild(WEBVR.createButton(renderer));
- }
- };
-
- this.setScene = function (value) {
- scene = value;
- };
-
- this.setSize = function (width, height) {
- this.width = width;
- this.height = height;
-
- if (camera) {
- camera.aspect = this.width / this.height;
- camera.updateProjectionMatrix();
- }
-
- if (renderer) {
- renderer.setSize(width, height);
- }
- };
-
- function dispatch$$1(array, event) {
- for (var i = 0, l = array.length; i < l; i++) {
- array[i](event);
- }
- }
-
- var prevTime;
-
- function animate() {
- var time = performance.now();
-
- try {
- dispatch$$1(events.update, { time: time, delta: time - prevTime });
- } catch (e) {
- console.error((e.message || e), (e.stack || ""));
- }
-
- renderer.render(scene, camera);
- prevTime = time;
- }
-
- this.play = function () {
- prevTime = performance.now();
-
- document.addEventListener('keydown', onDocumentKeyDown);
- document.addEventListener('keyup', onDocumentKeyUp);
- document.addEventListener('mousedown', onDocumentMouseDown);
- document.addEventListener('mouseup', onDocumentMouseUp);
- document.addEventListener('mousemove', onDocumentMouseMove);
- document.addEventListener('touchstart', onDocumentTouchStart);
- document.addEventListener('touchend', onDocumentTouchEnd);
- document.addEventListener('touchmove', onDocumentTouchMove);
-
- dispatch$$1(events.start, arguments);
-
- renderer.setAnimationLoop(animate);
- };
-
- this.stop = function () {
- document.removeEventListener('keydown', onDocumentKeyDown);
- document.removeEventListener('keyup', onDocumentKeyUp);
- document.removeEventListener('mousedown', onDocumentMouseDown);
- document.removeEventListener('mouseup', onDocumentMouseUp);
- document.removeEventListener('mousemove', onDocumentMouseMove);
- document.removeEventListener('touchstart', onDocumentTouchStart);
- document.removeEventListener('touchend', onDocumentTouchEnd);
- document.removeEventListener('touchmove', onDocumentTouchMove);
-
- dispatch$$1(events.stop, arguments);
-
- renderer.setAnimationLoop(null);
- };
-
- this.dispose = function () {
- while (dom.children.length) {
- dom.removeChild(dom.firstChild);
- }
-
- renderer.dispose();
-
- camera = undefined;
- scene = undefined;
- renderer = undefined;
- };
-
- //
-
- function onDocumentKeyDown(event) {
- dispatch$$1(events.keydown, event);
- }
-
- function onDocumentKeyUp(event) {
- dispatch$$1(events.keyup, event);
- }
-
- function onDocumentMouseDown(event) {
- dispatch$$1(events.mousedown, event);
- }
-
- function onDocumentMouseUp(event) {
- dispatch$$1(events.mouseup, event);
- }
-
- function onDocumentMouseMove(event) {
- dispatch$$1(events.mousemove, event);
- }
-
- function onDocumentTouchStart(event) {
- dispatch$$1(events.touchstart, event);
- }
-
- function onDocumentTouchEnd(event) {
- dispatch$$1(events.touchend, event);
- }
-
- function onDocumentTouchMove(event) {
- dispatch$$1(events.touchmove, event);
- }
- }
-
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param script javascript object
- * @constructor
- */
-
- var AddScriptCommand = function (object, script) {
-
- Command.call(this);
-
- this.type = 'AddScriptCommand';
- this.name = 'Add Script';
-
- this.object = object;
- this.script = script;
-
- };
-
- AddScriptCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(AddScriptCommand.prototype, {
-
- constructor: AddScriptCommand,
-
- execute: function () {
- if (this.editor.scripts[this.object.uuid] === undefined) {
- this.editor.scripts[this.object.uuid] = [];
- }
-
- this.editor.scripts[this.object.uuid].push(this.script);
- this.editor.app.call('scriptAdded', this, this.script);
- },
-
- undo: function () {
-
- if (this.editor.scripts[this.object.uuid] === undefined) return;
-
- var index = this.editor.scripts[this.object.uuid].indexOf(this.script);
-
- if (index !== - 1) {
-
- this.editor.scripts[this.object.uuid].splice(index, 1);
-
- }
-
- this.editor.app.call('scriptRemoved', this, this.script);
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.objectUuid = this.object.uuid;
- output.script = this.script;
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.script = json.script;
- this.object = this.editor.objectByUuid(json.objectUuid);
-
- }
-
- });
-
- /**
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
-
- /**
- * @param object THREE.Object3D
- * @param attributeName string
- * @param newValue number, string, boolean or object
- * @constructor
- */
-
- function SetGeometryValueCommand(object, attributeName, newValue) {
-
- Command.call(this);
-
- this.type = 'SetGeometryValueCommand';
- this.name = 'Set Geometry.' + attributeName;
-
- this.object = object;
- this.attributeName = attributeName;
- this.oldValue = (object !== undefined) ? object.geometry[attributeName] : undefined;
- this.newValue = newValue;
-
- }
- SetGeometryValueCommand.prototype = Object.create(Command.prototype);
-
- Object.assign(SetGeometryValueCommand.prototype, {
-
- constructor: SetGeometryValueCommand,
-
- execute: function () {
-
- this.object.geometry[this.attributeName] = this.newValue;
- this.editor.app.call('objectChanged', this, this.object);
- this.editor.app.call('geometryChanged', this);
- this.editor.app.call('sceneGraphChanged', this);
-
- },
-
- undo: function () {
-
- this.object.geometry[this.attributeName] = this.oldValue;
- this.editor.app.call('objectChanged', this, this.object);
- this.editor.app.call('geometryChanged', this);
- this.editor.app.call('sceneGraphChanged', this);
-
- },
-
- toJSON: function () {
-
- var output = Command.prototype.toJSON.call(this);
-
- output.objectUuid = this.object.uuid;
- output.attributeName = this.attributeName;
- output.oldValue = this.oldValue;
- output.newValue = this.newValue;
-
- return output;
-
- },
-
- fromJSON: function (json) {
-
- Command.prototype.fromJSON.call(this, json);
-
- this.object = this.editor.objectByUuid(json.objectUuid);
- this.attributeName = json.attributeName;
- this.oldValue = json.oldValue;
- this.newValue = json.newValue;
-
- }
-
- });
-
- /**
- * 场景编辑区
- * @author mrdoob / http://mrdoob.com/
- */
- function Viewport(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- Viewport.prototype = Object.create(UI$1.Control.prototype);
- Viewport.prototype.constructor = Viewport;
-
- Viewport.prototype.render = function () {
- this.container = UI$1.create({
- xtype: 'div',
- id: 'viewport',
- parent: this.app.container,
- cls: 'viewport'
- });
- this.container.render();
- };
-
- /**
- * Logo标志
- * @param {*} options
- */
- function Logo(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- Logo.prototype = Object.create(UI$1.Control.prototype);
- Logo.prototype.constructor = Logo;
-
- Logo.prototype.render = function () {
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'logo',
- html: ''
- });
-
- container.render();
- };
-
- /**
- * 场景菜单
- * @param {*} options
- */
- function SceneMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- SceneMenu.prototype = Object.create(UI$1.Control.prototype);
- SceneMenu.prototype.constructor = SceneMenu;
-
- SceneMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '场景'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- xtype: 'div',
- id: 'mNewScene',
- html: '新建',
- cls: 'option',
- onClick: function () {
- _this.app.call('mNewScene');
- }
- }, {
- xtype: 'div',
- id: 'mLoadScene',
- html: '载入',
- cls: 'option',
- onClick: function () {
- _this.app.call('mLoadScene');
- }
- }, {
- xtype: 'div',
- id: 'mSaveScene',
- html: '保存',
- cls: 'option',
- onClick: function () {
- _this.app.call('mSaveScene');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mPublishScene',
- html: '发布',
- cls: 'option',
- onClick: function () {
- _this.app.call('mPublishScene');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 编辑菜单
- * @param {*} options
- */
- function EditMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- EditMenu.prototype = Object.create(UI$1.Control.prototype);
- EditMenu.prototype.constructor = EditMenu;
-
- EditMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '编辑'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- xtype: 'div',
- id: 'mUndo',
- html: '撤销(Ctrl+Z)',
- cls: 'option inactive',
- onClick: function () {
- _this.app.call('mUndo');
- }
- }, {
- xtype: 'div',
- id: 'mRedo',
- html: '重做(Ctrl+Shift+Z)',
- cls: 'option inactive',
- onClick: function () {
- _this.app.call('mRedo');
- }
- }, {
- xtype: 'div',
- id: 'mClearHistory',
- html: '清空历史记录',
- cls: 'option',
- onClick: function () {
- _this.app.call('mClearHistory');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mClone',
- html: '复制',
- cls: 'option',
- onClick: function () {
- _this.app.call('mClone');
- }
- }, {
- xtype: 'div',
- id: 'mDelete',
- html: '删除(Del)',
- cls: 'option',
- onClick: function () {
- _this.app.call('mDelete');
- }
- }, {
- xtype: 'div',
- id: 'mMinifyShader',
- html: '压缩着色器程序',
- cls: 'option',
- onClick: function () {
- _this.app.call('mMinifyShader');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 添加菜单
- * @param {*} options
- */
- function AddMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- AddMenu.prototype = Object.create(UI$1.Control.prototype);
- AddMenu.prototype.constructor = AddMenu;
-
- AddMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '添加'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- xtype: 'div',
- id: 'mAddGroup',
- html: '组',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddGroup');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mAddPlane',
- html: '平板',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddPlane');
- }
- }, {
- xtype: 'div',
- id: 'mAddBox',
- html: '正方体',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddBox');
- }
- }, {
- xtype: 'div',
- id: 'mAddCircle',
- html: '圆',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddCircle');
- }
- }, {
- xtype: 'div',
- id: 'mAddCylinder',
- html: '圆柱体',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddCylinder');
- }
- }, {
- xtype: 'div',
- id: 'mAddSphere',
- html: '球体',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddSphere');
- }
- }, {
- xtype: 'div',
- id: 'mAddIcosahedron',
- html: '二十面体',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddIcosahedron');
- }
- }, {
- xtype: 'div',
- id: 'mAddTorus',
- html: '轮胎',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddTorus');
- }
- }, {
- xtype: 'div',
- id: 'mAddTorusKnot',
- html: '扭结',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddTorusKnot');
- }
- }, {
- xtype: 'div',
- id: 'mAddTeaport',
- html: '茶壶',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddTeaport');
- }
- }, {
- xtype: 'div',
- id: 'mAddLathe',
- html: '花瓶',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddLathe');
- }
- }, {
- xtype: 'div',
- id: 'mAddSprite',
- html: '精灵',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddSprite');
- }
- }, {
- xtype: 'div',
- id: 'mAddText',
- html: '文本',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddText');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mAddPointLight',
- html: '点光源',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddPointLight');
- }
- }, {
- xtype: 'div',
- id: 'mAddSpotLight',
- html: '聚光灯',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddSpotLight');
- }
- }, {
- xtype: 'div',
- id: 'mAddDirectionalLight',
- html: '平行光源',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddDirectionalLight');
- }
- }, {
- xtype: 'div',
- id: 'mAddHemisphereLight',
- html: '半球光',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddHemisphereLight');
- }
- }, {
- xtype: 'div',
- id: 'mAddAmbientLight',
- html: '环境光',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddAmbientLight');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mAddPerspectiveCamera',
- html: '透视相机',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddPerspectiveCamera');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 资源菜单
- * @param {*} options
- */
- function AssetMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- AssetMenu.prototype = Object.create(UI$1.Control.prototype);
- AssetMenu.prototype.constructor = AssetMenu;
-
- AssetMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '资源'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- xtype: 'div',
- id: 'mAddAsset',
- html: '添加模型',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddAsset');
- }
- }, {
- xtype: 'div',
- id: 'mImportAsset',
- html: '导入模型',
- cls: 'option',
- onClick: function () {
- _this.app.call('mImportAsset');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mExportGeometry',
- html: '导出几何体',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportGeometry');
- }
- }, {
- xtype: 'div',
- id: 'mExportObject',
- html: '导出物体',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportObject');
- }
- }, {
- xtype: 'div',
- id: 'mExportScene',
- html: '导出场景',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportScene');
- }
- }, {
- xtype: 'hr'
- }, {
- xtype: 'div',
- id: 'mExportGLTF',
- html: '导出gltf文件',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportGLTF');
- }
- }, {
- xtype: 'div',
- id: 'mExportMMD',
- html: '导出mmd文件',
- cls: 'option inactive',
- onClick: function () {
- _this.app.call('mExportMMD');
- }
- }, {
- xtype: 'div',
- id: 'mExportOBJ',
- html: '导出obj文件',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportOBJ');
- }
- }, {
- xtype: 'div',
- id: 'mExportPLY',
- html: '导出ply文件',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportPLY');
- }
- }, {
- xtype: 'div',
- id: 'mExportSTLB',
- html: '导出stl二进制文件',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportSTLB');
- }
- }, {
- xtype: 'div',
- id: 'mExportSTL',
- html: '导出stl文件',
- cls: 'option',
- onClick: function () {
- _this.app.call('mExportSTL');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 动画菜单
- * @param {*} options
- */
- function AnimationMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- AnimationMenu.prototype = Object.create(UI$1.Control.prototype);
- AnimationMenu.prototype.constructor = AnimationMenu;
-
- AnimationMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '动画'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- id: 'mPerson',
- xtype: 'div',
- cls: 'option',
- html: '人',
- onClick: function () {
- _this.app.call('mAddPerson', _this);
- }
- }, {
- id: 'mFire',
- xtype: 'div',
- cls: 'option',
- html: '火焰',
- onClick: function () {
- _this.app.call('mAddFire', _this);
- }
- }, {
- id: 'mSmoke',
- xtype: 'div',
- cls: 'option',
- html: '烟',
- onClick: function () {
- _this.app.call('mAddSmoke', _this);
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 物体菜单
- * @param {*} options
- */
- function PhysicsMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- PhysicsMenu.prototype = Object.create(UI$1.Control.prototype);
- PhysicsMenu.prototype.constructor = PhysicsMenu;
-
- PhysicsMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '物理'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- xtype: 'div',
- id: 'mAddCloth',
- html: '添加布料',
- cls: 'option',
- onClick: function () {
- _this.app.call('mAddCloth', _this);
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 组件菜单
- * @param {*} options
- */
- function ComponentMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- ComponentMenu.prototype = Object.create(UI$1.Control.prototype);
- ComponentMenu.prototype.constructor = ComponentMenu;
-
- ComponentMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '组件'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- xtype: 'div',
- id: 'mParticleEmitter',
- html: '粒子发射器',
- cls: 'option',
- onClick: function () {
- _this.app.call('mParticleEmitter');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 启动菜单
- * @param {*} options
- */
- function PlayMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- PlayMenu.prototype = Object.create(UI$1.Control.prototype);
- PlayMenu.prototype.constructor = PlayMenu;
-
- PlayMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- id: 'mPlay',
- xtype: 'div',
- cls: 'title',
- html: '启动',
- onClick: function () {
- _this.app.call('mPlay');
- }
- }]
- });
-
- container.render();
- };
-
- /**
- * 视图菜单
- * @param {*} options
- */
- function ViewMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- ViewMenu.prototype = Object.create(UI$1.Control.prototype);
- ViewMenu.prototype.constructor = ViewMenu;
-
- ViewMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '视图'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- id: 'mVRMode',
- xtype: 'div',
- cls: 'option',
- html: 'VR模式',
- onClick: function () {
- _this.app.call('mVRMode');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 示例菜单
- * @param {*} options
- */
- function ExampleMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- ExampleMenu.prototype = Object.create(UI$1.Control.prototype);
- ExampleMenu.prototype.constructor = ExampleMenu;
-
- ExampleMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '示例'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- id: 'mArkanoid',
- xtype: 'div',
- cls: 'option',
- html: '打砖块',
- onClick: function () {
- _this.app.call('mArkanoid');
- }
- }, {
- id: 'mCamera',
- xtype: 'div',
- cls: 'option',
- html: '相机',
- onClick: function () {
- _this.app.call('mCamera');
- }
- }, {
- id: 'mParticles',
- xtype: 'div',
- cls: 'option',
- html: '粒子',
- onClick: function () {
- _this.app.call('mParticles');
- }
- }, {
- id: 'mPong',
- xtype: 'div',
- cls: 'option',
- html: '乒乓球',
- onClick: function () {
- _this.app.call('mPong');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 帮助菜单
- * @param {*} options
- */
- function HelpMenu(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
-
- HelpMenu.prototype = Object.create(UI$1.Control.prototype);
- HelpMenu.prototype.constructor = HelpMenu;
-
- HelpMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- cls: 'menu',
- children: [{
- xtype: 'div',
- cls: 'title',
- html: '帮助'
- }, {
- xtype: 'div',
- cls: 'options',
- children: [{
- id: 'mSourceCode',
- xtype: 'div',
- cls: 'option',
- html: '源码',
- onClick: function () {
- _this.app.call('mSourceCode');
- }
- }, {
- id: 'mAbout',
- xtype: 'div',
- cls: 'option',
- html: '关于',
- onClick: function () {
- _this.app.call('mAbout');
- }
- }]
- }]
- });
-
- container.render();
- };
-
- /**
- * 状态菜单(菜单栏右侧)
- * @param {*} options
- */
- function StatusMenu(options) {
- UI$1.Control.call(this, options);
- options = options || {};
-
- this.app = options.app;
- }
-
- StatusMenu.prototype = Object.create(UI$1.Control.prototype);
- StatusMenu.prototype.constructor = StatusMenu;
-
- StatusMenu.prototype.render = function () {
- var _this = this;
-
- var container = UI$1.create({
- xtype: 'div',
- id: 'mStatus',
- parent: this.parent,
- cls: 'menu right',
- children: [{
- id: 'bAutoSave',
- xtype: 'boolean',
- text: '自动保存',
- value: true,
- style: {
- color: '#888 !important;'
- },
- onChange: function (e) {
- _this.app.editor.config.setKey('autosave', e.target.checked);
- _this.app.call('sceneGraphChanged', _this);
- }
- }, {
- xtype: 'text',
- text: 'r' + THREE.REVISION,
- cls: 'title version'
- }]
- });
-
- container.render();
- };
-
- /**
- * 菜单栏
- * @author mrdoob / http://mrdoob.com/
- */
- function Menubar(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- Menubar.prototype = Object.create(UI$1.Control.prototype);
- Menubar.prototype.constructor = Menubar;
-
- Menubar.prototype.render = function () {
- var params = { app: this.app };
-
- var container = UI$1.create({
- xtype: 'div',
- id: 'menubar',
- cls: 'menubar',
- parent: this.parent,
- children: [
- // Logo
- new Logo(params),
-
- // 左侧
- new SceneMenu(params),
- new EditMenu(params),
- new AddMenu(params),
- new AssetMenu(params),
- new AnimationMenu(params),
- new PhysicsMenu(params),
- new ComponentMenu(params),
- new PlayMenu(params),
- new ViewMenu(params),
- new ExampleMenu(params),
- new HelpMenu(params),
-
- // 右侧
- new StatusMenu(params)
- ]
- });
-
- container.render();
- };
-
- /**
- * 状态栏
- * @author mrdoob / http://mrdoob.com/
- */
- function StatusBar(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- StatusBar.prototype = Object.create(UI$1.Control.prototype);
- StatusBar.prototype.constructor = StatusBar;
-
- StatusBar.prototype.render = function () {
-
- var data = {
- xtype: 'div',
- id: 'statusBar',
- parent: this.app.container,
- cls: 'statusBar',
- children: [{
- xtype: 'row',
- children: [{
- xtype: 'label',
- text: '物体'
- }, {
- xtype: 'text',
- id: 'objectsText',
- text: '0' // 物体数
- }, {
- xtype: 'label',
- text: '顶点'
- }, {
- xtype: 'text',
- id: 'verticesText',
- text: '0' // 顶点数
- }, {
- xtype: 'label',
- text: '三角形'
- }, {
- xtype: 'text',
- id: 'trianglesText',
- text: '0' // 三角形数
- }]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 编辑器
- * @author mrdoob / http://mrdoob.com/
- */
- function Editor(app) {
- this.app = app;
- this.app.editor = this;
-
- // 基础
- this.config = new Config('threejs-editor');
- this.history = new History(this);
- this.storage = new Storage();
- this.loader = new Loader(this);
-
- // 场景
- this.scene = new THREE.Scene();
- this.scene.name = '场景';
- this.scene.background = new THREE.Color(0xaaaaaa);
-
- this.sceneHelpers = new THREE.Scene();
-
- this.sceneName = null; // 当前场景名称
-
- // 相机
- this.DEFAULT_CAMERA = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);
- this.DEFAULT_CAMERA.name = '默认相机';
- this.DEFAULT_CAMERA.position.set(20, 10, 20);
- this.DEFAULT_CAMERA.lookAt(new THREE.Vector3());
-
- this.camera = this.DEFAULT_CAMERA.clone();
-
- // 渲染器
- this.rendererTypes = {
- 'WebGLRenderer': THREE.WebGLRenderer,
- 'CanvasRenderer': THREE.CanvasRenderer,
- 'SVGRenderer': THREE.SVGRenderer,
- 'SoftwareRenderer': THREE.SoftwareRenderer,
- 'RaytracingRenderer': THREE.RaytracingRenderer
- };
-
- this.renderer = this.createRendererFromConfig();
- this.app.viewport.container.dom.appendChild(this.renderer.domElement);
- (new RendererChangedEvent(this.app)).onRendererChanged(this.renderer);
-
- // 缓存
- this.object = {};
- this.objects = [];
- this.geometries = {};
- this.materials = {};
- this.textures = {};
- this.scripts = {};
- this.helpers = {};
-
- // 当前选中物体
- this.selected = null;
-
- // 网格
- this.grid = new THREE.GridHelper(30, 30, 0x444444, 0x888888);
- this.sceneHelpers.add(this.grid);
-
- // 选中包围盒(当mesh.useSelectionBox === false时,不使用包围盒)
- this.selectionBox = new THREE.BoxHelper();
- this.selectionBox.material.depthTest = false;
- this.selectionBox.material.transparent = true;
- this.selectionBox.visible = false;
- this.sceneHelpers.add(this.selectionBox);
-
- // 平移旋转缩放控件
- this.transformControls = new THREE.TransformControls(this.camera, this.app.viewport.container.dom);
- this.sceneHelpers.add(this.transformControls);
-
- // 编辑器控件
- this.controls = new THREE.EditorControls(this.camera, this.app.viewport.container.dom);
-
- // 性能控件
- this.stats = new Stats();
- this.stats.dom.style.position = 'absolute';
- this.stats.dom.style.left = '8px';
- this.stats.dom.style.top = '8px';
- this.stats.dom.style.zIndex = 'initial';
- this.app.viewport.container.dom.appendChild(this.stats.dom);
- }
- // ---------------------- 渲染器 ---------------------------
-
- Editor.prototype.createRenderer = function (options) { // 创建渲染器
- var rendererType = options.rendererType === undefined ? 'WebGLRenderer' : options.rendererType;
- var antialias = options.antialias === undefined ? true : options.antialias;
- var shadows = options.shadows === undefined ? true : options.shadows;
- var gammaIn = options.gammaIn === undefined ? false : options.gammaIn;
- var gammaOut = options.gammaOut === undefined ? false : options.gammaOut;
- var rendererTypes = this.rendererTypes;
-
- var renderer = new rendererTypes[rendererType]({ antialias: antialias });
- renderer.gammaInput = gammaIn;
- renderer.gammaOutput = gammaOut;
- if (shadows && renderer.shadowMap) {
- renderer.shadowMap.enabled = true;
- renderer.shadowMap.type = THREE.PCFSoftShadowMap;
- }
- return renderer;
- };
-
- Editor.prototype.createRendererFromConfig = function () { // 从配置创建渲染器
- var rendererType = this.config.getKey('project/renderer');
- var antialias = this.config.getKey('project/renderer/antialias');
- var shadows = this.config.getKey('project/renderer/shadows');
- var gammaIn = this.config.getKey('project/renderer/gammaInput');
- var gammaOut = this.config.getKey('project/renderer/gammaOutput');
-
- return this.createRenderer({
- rendererType: rendererType,
- antialias: antialias,
- shadows: shadows,
- gammaIn: gammaIn,
- gammaOut: gammaOut
- });
- };
-
- // -------------------- 编辑器 --------------------------
-
- Editor.prototype.setTheme = function (value) { // 设置主题
- this.app.call('setTheme', this, value);
- };
-
- Editor.prototype.setScene = function (scene) { // 设置场景
- this.app.call('setScene', this, scene);
- };
-
- // ---------------------- 物体 ---------------------------
-
- Editor.prototype.objectByUuid = function (uuid) { // 根据uuid获取物体
- return this.scene.getObjectByProperty('uuid', uuid, true);
- };
-
- Editor.prototype.addObject = function (object) { // 添加物体
- this.app.call('addObject', this, object);
- };
-
- Editor.prototype.moveObject = function (object, parent, before) { // 移动物体
- this.app.call('moveObject', this, object, parent, before);
- };
-
- Editor.prototype.nameObject = function (object, name) { // 重命名物体
- this.app.call('nameObject', this, object, name);
- };
-
- Editor.prototype.removeObject = function (object) { // 移除物体
- this.app.call('removeObject', this, object);
- };
-
- Editor.prototype.addGeometry = function (geometry) { // 添加几何体
- this.app.call('addGeometry', this, geometry);
- };
-
- Editor.prototype.setGeometryName = function (geometry, name) { // 设置几何体名称
- this.app.call('setGeometryName', this, geometry, name);
- };
-
- Editor.prototype.addMaterial = function (material) { // 添加材质
- this.app.call('addMaterial', this, material);
- };
-
- Editor.prototype.setMaterialName = function (material, name) { // 设置材质名称事件
- this.app.call('setMaterialName', this, material, name);
- };
-
- Editor.prototype.addTexture = function (texture) { // 添加纹理事件
- this.app.call('addTexture', this, texture);
- };
-
- // ------------------------- 帮助 ------------------------------
-
- Editor.prototype.addHelper = function (object) { // 添加物体帮助
- this.app.call('addHelper', this, object);
- };
-
- Editor.prototype.removeHelper = function (object) { // 移除物体帮助
- this.app.call('removeHelper', this, object);
- };
-
- // ------------------------ 脚本 ----------------------------
-
- Editor.prototype.addScript = function (object, script) { // 添加脚本
- this.app.call('addScript', this, object, script);
- };
-
- Editor.prototype.removeScript = function (object, script) { // 移除脚本
- this.app.call('removeScript', this, object, script);
- };
-
- // ------------------------ 选中事件 --------------------------------
-
- Editor.prototype.select = function (object) { // 选中物体
- this.app.call('select', this, object);
- };
-
- Editor.prototype.selectById = function (id) { // 根据id选中物体
- if (id === this.camera.id) {
- this.select(this.camera);
- return;
- }
-
- this.select(this.scene.getObjectById(id, true));
- };
-
- Editor.prototype.selectByUuid = function (uuid) { // 根据uuid选中物体
- var _this = this;
- this.scene.traverse(function (child) {
- if (child.uuid === uuid) {
- _this.select(child);
- }
- });
- };
-
- Editor.prototype.deselect = function () { // 取消选中物体
- this.select(null);
- };
-
- // ---------------------- 焦点事件 --------------------------
-
- Editor.prototype.focus = function (object) { // 设置焦点
- this.app.call('objectFocused', this, object);
- };
-
- Editor.prototype.focusById = function (id) { // 根据id设置交点
- this.focus(this.scene.getObjectById(id, true));
- };
-
- // ----------------------- 场景事件 ----------------------------
-
- Editor.prototype.clear = function () { // 清空场景
- this.app.call('clear', this);
- };
-
- Editor.prototype.load = function () { // 加载场景
- this.app.call('load', this);
- };
-
- Editor.prototype.save = function () { // 保存场景
- this.app.call('save', this);
- };
-
- // --------------------- 命令事件 ------------------------
-
- Editor.prototype.execute = function (cmd, optionalName) { // 执行事件
- this.history.execute(cmd, optionalName);
- };
-
- Editor.prototype.undo = function () { // 撤销事件
- this.history.undo();
- };
-
- Editor.prototype.redo = function () { // 重做事件
- this.history.redo();
- };
-
- // ------------------------- 序列化 ----------------------------
-
- Editor.prototype.fromJSON = function (json) { // 根据json创建场景
- var loader = new THREE.ObjectLoader();
-
- // backwards
-
- if (json.scene === undefined) {
- this.setScene(loader.parse(json));
- return;
- }
-
- var camera = loader.parse(json.camera);
-
- this.camera.copy(camera);
- this.camera.aspect = this.DEFAULT_CAMERA.aspect;
- this.camera.updateProjectionMatrix();
-
- this.history.fromJSON(json.history);
- this.scripts = json.scripts;
-
- this.setScene(loader.parse(json.scene));
- };
-
- Editor.prototype.toJSON = function () { // 将场景转换为json
- // scripts clean up
- var scene = this.scene;
- var scripts = this.scripts;
-
- for (var key in scripts) {
- var script = scripts[key];
-
- if (script.length === 0 || scene.getObjectByProperty('uuid', key) === undefined) {
- delete scripts[key];
- }
- }
-
- return {
- metadata: {},
- project: {
- gammaInput: this.config.getKey('project/renderer/gammaInput'),
- gammaOutput: this.config.getKey('project/renderer/gammaOutput'),
- shadows: this.config.getKey('project/renderer/shadows'),
- vr: this.config.getKey('project/vr')
- },
- camera: this.camera.toJSON(),
- scene: this.scene.toJSON(),
- scripts: this.scripts,
- history: this.history.toJSON()
- };
- };
-
- /**
- * 脚本编辑面板
- * @author mrdoob / http://mrdoob.com/
- */
- function Script(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- Script.prototype = Object.create(UI$1.Control.prototype);
- Script.prototype.constructor = Script;
-
- Script.prototype.render = function () {
- var container;
-
- var data = {
- xtype: 'div',
- parent: this.app.container,
- id: 'script',
- cls: 'script',
- style: {
- backgroundColor: '#272822',
- display: 'none'
- },
- children: [{
- xtype: 'div',
- style: {
- padding: '10px'
- },
- children: [{
- id: 'scriptTitle',
- xtype: 'text',
- style: {
- color: '#fff'
- }
- }, {
- xtype: 'closebutton',
- style: {
- position: 'absolute',
- top: '3px',
- right: '1px',
- cursor: 'pointer'
- },
- onClick: function () {
- if (container) {
- container.dom.style.display = 'none';
- }
- }
- }]
- }]
- };
-
- container = UI$1.create(data);
- container.render();
-
- var title = UI$1.get('scriptTitle');
-
- // 业务逻辑
- var currentMode;
- var currentScript;
- var currentObject;
-
- var _this = this;
-
- var codemirror = CodeMirror(container.dom, {
- value: '',
- lineNumbers: true,
- matchBrackets: true,
- indentWithTabs: true,
- tabSize: 4,
- indentUnit: 4,
- hintOptions: {
- completeSingle: false
- }
- });
- codemirror.setOption('theme', 'monokai');
- codemirror.on('change', function () {
- _this.app.call('codeMirrorChange', _this, codemirror, currentMode, currentScript, currentObject);
- });
-
- // 防止回退键删除物体
- var wrapper = codemirror.getWrapperElement();
- wrapper.addEventListener('keydown', function (event) {
- event.stopPropagation();
- });
-
- // tern js 自动完成
- var server = new CodeMirror.TernServer({
- caseInsensitive: true,
- plugins: { threejs: null }
- });
-
- codemirror.setOption('extraKeys', {
- 'Ctrl-Space': function (cm) { server.complete(cm); },
- 'Ctrl-I': function (cm) { server.showType(cm); },
- 'Ctrl-O': function (cm) { server.showDocs(cm); },
- 'Alt-.': function (cm) { server.jumpToDef(cm); },
- 'Alt-,': function (cm) { server.jumpBack(cm); },
- 'Ctrl-Q': function (cm) { server.rename(cm); },
- 'Ctrl-.': function (cm) { server.selectName(cm); }
- });
-
- codemirror.on('cursorActivity', function (cm) {
- if (currentMode !== 'javascript') {
- return;
- }
- server.updateArgHints(cm);
- });
-
- codemirror.on('keypress', function (cm, kb) {
- if (currentMode !== 'javascript') {
- return;
- }
- var typed = String.fromCharCode(kb.which || kb.keyCode);
- if (/[\w\.]/.exec(typed)) {
- server.complete(cm);
- }
- });
-
- //
- this.app.on('editorCleared.Script', function () {
- container.dom.style.display = 'none';
- });
-
- this.app.on('editScript.Script', function (object, script) {
- var mode, name, source;
-
- if (typeof (script) === 'object') {
- mode = 'javascript';
- name = script.name;
- source = script.source;
- title.setValue(object.name + ' / ' + name);
- } else {
- switch (script) {
- case 'vertexShader':
- mode = 'glsl';
- name = 'Vertex Shader';
- source = object.material.vertexShader || "";
- break;
- case 'fragmentShader':
- mode = 'glsl';
- name = 'Fragment Shader';
- source = object.material.fragmentShader || "";
- break;
- case 'programInfo':
- mode = 'json';
- name = 'Program Properties';
- var json = {
- defines: object.material.defines,
- uniforms: object.material.uniforms,
- attributes: object.material.attributes
- };
- source = JSON.stringify(json, null, '\t');
- }
- title.setValue(object.material.name + ' / ' + name);
- }
-
- currentMode = mode;
- currentScript = script;
- currentObject = object;
-
- container.dom.style.display = 'block';
- codemirror.setValue(source);
- if (mode === 'json') mode = { name: 'javascript', json: true };
- codemirror.setOption('mode', mode);
- });
-
- this.app.on('scriptRemoved.Script', function (script) {
- if (currentScript === script) {
- container.dom.style.display = 'none';
- }
- });
-
- this.app.on('refreshScriptEditor.Script', function (object, script, cursorPosition, scrollInfo) {
- if (currentScript !== script) return;
-
- // copying the codemirror history because "codemirror.setValue(...)" alters its history
-
- var history = codemirror.getHistory();
- title.setValue(object.name + ' / ' + script.name);
- codemirror.setValue(script.source);
-
- if (cursorPosition !== undefined) {
-
- codemirror.setCursor(cursorPosition);
- codemirror.scrollTo(scrollInfo.left, scrollInfo.top);
-
- }
- codemirror.setHistory(history); // setting the history to previous state
- });
- };
-
- /**
- * 播放器面板
- * @author mrdoob / http://mrdoob.com/
- */
- function Player(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- Player.prototype = Object.create(UI$1.Control.prototype);
- Player.prototype.constructor = Player;
-
- Player.prototype.render = function () {
- this.container = UI$1.create({
- xtype: 'div',
- parent: this.parent,
- id: 'player',
- cls: 'Panel player',
- style: {
- position: 'absolute',
- display: 'none'
- }
- });
-
- this.container.render();
-
- this.player = new AppPlayer();
- this.container.dom.appendChild(this.player.dom);
- };
-
- /**
- * 历史记录面板
- * @author dforrer / https://github.com/dforrer
- * Developed as part of a project at University of Applied Sciences and Arts Northwestern Switzerland (www.fhnw.ch)
- */
- function HistoryPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- HistoryPanel.prototype = Object.create(UI$1.Control.prototype);
- HistoryPanel.prototype.constructor = HistoryPanel;
-
- HistoryPanel.prototype.render = function () {
- var editor = this.app.editor;
- var config = editor.config;
- var history = editor.history;
-
- var _this = this;
-
- var data = {
- xtype: 'div',
- parent: this.parent,
- cls: 'Panel',
- children: [{
- xtype: 'label',
- text: '历史记录'
- }, {
- xtype: 'boolean',
- text: '永久',
- style: {
- position: 'absolute',
- right: '8px'
- },
- onChange: function () {
- var value = this.getValue();
- config.setKey('settings/history', value);
- if (value) {
- UI$1.msg('历史记录将被保存在会话中。\n这会对使用材质的性能产生影响。');
- var lastUndoCmd = history.undos[history.undos.length - 1];
- var lastUndoId = (lastUndoCmd !== undefined) ? lastUndoCmd.id : 0;
- editor.history.enableSerialization(lastUndoId);
- } else {
- _this.app.call('historyChanged');
- }
- }
- }, {
- xtype: 'br'
- }, {
- xtype: 'br'
- }, {
- xtype: 'outliner',
- id: 'historyOutlinear',
- editor: editor,
- onChange: function () {
- history.goToState(parseInt(this.getValue()));
- }
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 材质面板
- * @author mrdoob / http://mrdoob.com/
- */
- function MaterialPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- MaterialPanel.prototype = Object.create(UI$1.Control.prototype);
- MaterialPanel.prototype.constructor = MaterialPanel;
-
- MaterialPanel.prototype.render = function () {
- var _this = this;
- var editor = this.app.editor;
-
- var update = function () {
- _this.app.call('updateMaterial', _this);
- };
-
- var data = {
- xtype: 'div',
- parent: this.parent,
- id: 'materialPanel',
- cls: 'Panel',
- style: {
- borderTop: 0,
- paddingTop: '20px',
- display: 'none'
- },
- children: [{ // New Copy Paste
- xtype: 'row',
- children: [{
- xtype: 'label',
- text: ''
- }, {
- xtype: 'button',
- id: 'btnNewMaterial',
- text: '新建',
- onClick: function () {
- this.app.call('newMaterial', this);
- }
- }, {
- xtype: 'button',
- id: 'btnCopyMaterial',
- text: '复制',
- style: {
- marginLeft: '4px'
- },
- onClick: function () {
- this.app.call('copyMaterial', this);
- }
- }, {
- xtype: 'button',
- text: '粘贴',
- id: 'btnPasteMaterial',
- style: {
- marginLeft: '4px'
- },
- onClick: function () {
- this.app.call('pasteMaterial', this);
- }
- }]
- }, { // type
- xtype: 'row',
- children: [{
- xtype: 'label',
- text: '类型'
- }, {
- xtype: 'select',
- id: 'materialClass',
- options: {
- 'LineBasicMaterial': '线条材质',
- 'LineDashedMaterial': '虚线材质',
- 'MeshBasicMaterial': '基本材质',
- 'MeshDepthMaterial': '深度材质',
- 'MeshNormalMaterial': '法向量材质',
- 'MeshLambertMaterial': '兰伯特材质',
- 'MeshPhongMaterial': '冯氏材质',
- 'PointCloudMaterial': '点云材质',
- 'MeshStandardMaterial': '标准材质',
- 'MeshPhysicalMaterial': '物理材质',
- 'ShaderMaterial': '着色器材质',
- 'SpriteMaterial': '精灵材质',
- 'RawShaderMaterial': '原始着色器材质'
- },
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: function () {
- _this.app.call('updateMaterial');
- }
- }]
- }, { // uuid
- xtype: 'row',
- children: [{
- xtype: 'label',
- text: 'UUID'
- }, {
- xtype: 'input',
- id: 'materialUUID',
- style: {
- width: '102px',
- fontSize: '12px'
- },
- disabled: true
- }, {
- xtype: 'button',
- text: '新建',
- style: {
- marginLeft: '7px'
- },
- onClick: function () {
- var materialUUID = UI$1.get('materialUUID');
- materialUUID.setValue(THREE.Math.generateUUID());
- _this.app.call('updateMaterial');
- }
- }]
- }, { // name
- xtype: 'row',
- id: 'materialNameRow',
- children: [{
- xtype: 'label',
- text: '名称'
- }, {
- xtype: 'input',
- id: 'materialName',
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: function () {
- editor.execute(new SetMaterialValueCommand(editor.selected, 'name', this.getValue()));
- }
- }]
- }, { // program
- xtype: 'row',
- id: 'materialProgramRow',
- children: [{
- xtype: 'label',
- text: '着色器程序'
- }, {
- xtype: 'button',
- text: '信息',
- style: {
- marginLeft: '4px'
- },
- onClick: function () {
- _this.app.call('editScript', _this, currentObject, 'programInfo');
- }
- }, {
- xtype: 'button',
- text: '顶点着色器',
- style: {
- marginLeft: '4px'
- },
- onClick: function () {
- _this.app.call('editScript', _this, currentObject, 'vertexShader');
- }
- }, {
- xtype: 'button',
- text: '片源着色器',
- style: {
- marginLeft: '4px'
- },
- onClick: function () {
- _this.app.call('editScript', _this, currentObject, 'fragmentShader');
- }
- }]
- }, { // color
- xtype: 'row',
- id: 'materialColorRow',
- children: [{
- xtype: 'label',
- text: '颜色'
- }, {
- xtype: 'color',
- id: 'materialColor',
- onChange: update
- }]
- }, { // roughness
- xtype: 'row',
- id: 'materialRoughnessRow',
- children: [{
- xtype: 'label',
- text: '粗糙度'
- }, {
- xtype: 'number',
- id: 'materialRoughness',
- value: 0.5,
- style: {
- width: '60px'
- },
- range: [0, 1],
- onChange: update
- }]
- }, { // metalness
- xtype: 'row',
- id: 'materialMetalnessRow',
- children: [{
- xtype: 'label',
- text: '金属度'
- }, {
- xtype: 'number',
- id: 'materialMetalness',
- value: 0.5,
- style: {
- width: '60px'
- },
- range: [0, 1],
- onChange: update
- }]
- }, { // emissive
- xtype: 'row',
- id: 'materialEmissiveRow',
- children: [{
- xtype: 'label',
- text: '发光'
- }, {
- xtype: 'color',
- id: 'materialEmissive',
- value: 0x000000,
- onChange: update
- }]
- }, { // specular
- xtype: 'row',
- id: 'materialSpecularRow',
- children: [{
- xtype: 'label',
- text: '镜面度'
- }, {
- xtype: 'color',
- id: 'materialSpecular',
- value: 0x111111,
- onChange: update
- }]
- }, { // shininess
- xtype: 'row',
- id: 'materialShininessRow',
- children: [{
- xtype: 'label',
- text: '光亮度'
- }, {
- xtype: 'number',
- id: 'materialShininess',
- value: 30,
- onChange: update
- }]
- }, { // clearCoat
- xtype: 'row',
- id: 'materialClearCoatRow',
- children: [{
- xtype: 'label',
- text: '透明度'
- }, {
- xtype: 'number',
- id: 'materialClearCoat',
- value: 1,
- style: {
- width: '60px'
- },
- range: [0, 1],
- onChange: update
- }]
- }, { // clearCoatRoughness
- xtype: 'row',
- id: 'materialClearCoatRoughnessRow',
- children: [{
- xtype: 'label',
- text: '透明粗糙度'
- }, {
- xtype: 'number',
- id: 'materialClearCoatRoughness',
- value: 1,
- style: {
- width: '60px'
- },
- range: [0, 1],
- onChange: update
- }]
- }, { // vertex colors
- xtype: 'row',
- id: 'materialVertexColorsRow',
- children: [{
- xtype: 'label',
- text: '顶点颜色'
- }, {
- xtype: 'select',
- id: 'materialVertexColors',
- options: {
- 0: '无',
- 1: '面',
- 2: '顶点'
- },
- onChange: update
- }]
- }, { // skinning
- xtype: 'row',
- id: 'materialSkinningRow',
- children: [{
- xtype: 'label',
- text: '皮肤'
- }, {
- xtype: 'checkbox',
- id: 'materialSkinning',
- value: false,
- onChange: update
- }]
- }, { // map
- xtype: 'row',
- id: 'materialMapRow',
- children: [{
- xtype: 'label',
- text: '纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialMap',
- onChange: update
- }]
- }, { // alpha map
- xtype: 'row',
- id: 'materialAlphaMapRow',
- children: [{
- xtype: 'label',
- text: '透明纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialAlphaMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialAlphaMap',
- onChange: update
- }]
- }, { // bump map
- xtype: 'row',
- id: 'materialBumpMapRow',
- children: [{
- xtype: 'label',
- text: '凹凸纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialBumpMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialBumpMap',
- value: 1,
- style: {
- width: '30px'
- },
- onChange: update
- }, {
- xtype: 'number',
- id: 'materialBumpScale',
- value: 1,
- style: {
- width: '30px'
- },
- onChange: update
- }]
- }, { // normal map
- xtype: 'row',
- id: 'materialNormalMapRow',
- children: [{
- xtype: 'label',
- text: '法线纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialNormalMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialNormalMap',
- onChange: update
- }]
- }, { // displacement map
- xtype: 'row',
- id: 'materialDisplacementMapRow',
- children: [{
- xtype: 'label',
- text: '位移纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialDisplacementMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialDisplacementMap',
- onChange: update
- }, {
- xtype: 'number',
- id: 'materialDisplacementScale',
- value: 1,
- style: {
- width: '30px'
- },
- onChange: update
- }]
- }, { // roughness map
- xtype: 'row',
- id: 'materialRoughnessMapRow',
- children: [{
- xtype: 'label',
- text: '粗糙纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialRoughnessMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialRoughnessMap',
- onChange: update
- }]
- }, { // metalness map
- xtype: 'row',
- id: 'materialMetalnessMapRow',
- children: [{
- xtype: 'label',
- text: '金属纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialMetalnessMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialMetalnessMap',
- onChange: update
- }]
- }, { // specular map
- xtype: 'row',
- id: 'materialSpecularMapRow',
- children: [{
- xtype: 'label',
- text: '镜面纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialSpecularMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialSpecularMap',
- onChange: update
- }]
- }, { // env map
- xtype: 'row',
- id: 'materialEnvMapRow',
- children: [{
- xtype: 'label',
- text: '环境纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialEnvMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialEnvMap',
- mapping: THREE.SphericalReflectionMapping,
- onChange: update
- }, {
- xtype: 'number',
- id: 'materialReflectivity',
- value: 1,
- style: {
- width: '30px'
- },
- onChange: update
- }]
- }, { // light map
- xtype: 'row',
- id: 'materialLightMapRow',
- children: [{
- xtype: 'label',
- text: '光照纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialLightMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialLightMap',
- onChange: update
- }]
- }, { // ambient occlusion map
- xtype: 'row',
- id: 'materialAOMapRow',
- children: [{
- xtype: 'label',
- text: '遮挡纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialAOMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialAOMap',
- onChange: update
- }, {
- xtype: 'number',
- id: 'materialAOScale',
- value: 1,
- range: [0, 1],
- style: {
- width: '30px'
- },
- onChange: update
- }]
- }, { // emissive map
- xtype: 'row',
- id: 'materialEmissiveMapRow',
- children: [{
- xtype: 'label',
- text: '放射纹理'
- }, {
- xtype: 'checkbox',
- id: 'materialEmissiveMapEnabled',
- value: false,
- onChange: update
- }, {
- xtype: 'texture',
- id: 'materialEmissiveMap',
- onChange: update
- }]
- }, { // side
- xtype: 'row',
- id: 'materialSideRow',
- children: [{
- xtype: 'label',
- text: '剔除'
- }, {
- xtype: 'select',
- id: 'materialSide',
- options: {
- 0: '正面',
- 1: '反面',
- 2: '双面'
- },
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: update
- }]
- }, { // shading
- xtype: 'row',
- id: 'materialShadingRow',
- children: [{
- xtype: 'label',
- text: '着色'
- }, {
- xtype: 'select',
- id: 'materialShading',
- options: {
- 0: '无',
- 1: '平坦',
- 2: '光滑'
- },
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: update
- }]
- }, { // blending
- xtype: 'row',
- id: 'materialBlendingRow',
- children: [{
- xtype: 'label',
- text: '混合'
- }, {
- xtype: 'select',
- id: 'materialBlending',
- options: {
- 0: '不混合',
- 1: '一般混合',
- 2: '和混合',
- 3: '差混合',
- 4: '积混合',
- 5: '自定义混合'
- },
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: update
- }]
- }, { // opacity
- xtype: 'row',
- id: 'materialOpacityRow',
- children: [{
- xtype: 'label',
- text: '不透明度'
- }, {
- xtype: 'number',
- id: 'materialOpacity',
- value: 1,
- style: {
- width: '60px'
- },
- range: [0, 1],
- onChange: update
- }]
- }, { // transparent
- xtype: 'row',
- id: 'materialTransparentRow',
- children: [{
- xtype: 'label',
- text: '透明'
- }, {
- xtype: 'checkbox',
- id: 'materialTransparent',
- style: {
- left: '100px'
- },
- onChange: update
- }]
- }, { // alpha test
- xtype: 'row',
- id: 'materialAlphaTestRow',
- children: [{
- xtype: 'label',
- text: 'α测试'
- }, {
- xtype: 'number',
- id: 'materialAlphaTest',
- style: {
- width: '60px'
- },
- range: [0, 1],
- onChange: update
- }]
- }, { // wireframe
- xtype: 'row',
- id: 'materialWireframeRow',
- children: [{
- xtype: 'label',
- text: '线框'
- }, {
- xtype: 'checkbox',
- id: 'materialWireframe',
- value: false,
- onChange: update
- }, {
- xtype: 'number',
- id: 'materialWireframeLinewidth',
- value: 1,
- style: {
- width: '60px'
- },
- range: [0, 100],
- onChange: update
- }]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 物体面板
- * @author mrdoob / http://mrdoob.com/
- */
- function ObjectPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- ObjectPanel.prototype = Object.create(UI$1.Control.prototype);
- ObjectPanel.prototype.constructor = ObjectPanel;
-
- ObjectPanel.prototype.render = function () {
- var editor = this.app.editor;
-
- var _this = this;
-
- var update = function () {
- _this.app.call('updateObject', _this);
- };
-
- var data = {
- xtype: 'div',
- id: 'objectPanel',
- parent: this.parent,
- cls: 'Panel',
- style: {
- borderTop: 0,
- paddingTop: '20px',
- display: 'none'
- },
- children: [{ // type
- xtype: 'row',
- id: 'objectTypeRow',
- children: [{
- xtype: 'label',
- text: '类型'
- }, {
- xtype: 'text',
- id: 'objectType'
- }]
- }, { // uuid
- xtype: 'row',
- id: 'objectUUIDRow',
- children: [{
- xtype: 'label',
- text: 'UUID'
- }, {
- xtype: 'input',
- id: 'objectUUID',
- style: {
- width: '102px',
- fontSize: '12px'
- },
- disabled: true
- }, {
- xtype: 'button',
- id: 'objectUUIDRenew',
- text: '新建',
- style: {
- marginLeft: '7px'
- },
- onClick: function () {
- var objectUUID = UI$1.get('objectUUID');
- objectUUID.setValue(THREE.Math.generateUUID());
- editor.execute(new SetUuidCommand(editor.selected, objectUUID.getValue()));
- }
- }]
- }, { // name
- xtype: 'row',
- id: 'objectNameRow',
- children: [{
- xtype: 'label',
- text: '名称'
- }, {
- xtype: 'input',
- id: 'objectName',
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: function () {
- editor.execute(new SetValueCommand(editor.selected, 'name', this.getValue()));
- }
- }]
- }, { // position
- xtype: 'row',
- id: 'objectPositionRow',
- children: [{
- xtype: 'label',
- text: '位置'
- }, {
- xtype: 'number',
- id: 'objectPositionX',
- style: {
- width: '50px'
- },
- onChange: update
- }, {
- xtype: 'number',
- id: 'objectPositionY',
- style: {
- width: '50px'
- },
- onChange: update
- }, {
- xtype: 'number',
- id: 'objectPositionZ',
- style: {
- width: '50px'
- },
- onChange: update
- }]
- }, { // rotation
- xtype: 'row',
- id: 'objectRotationRow',
- children: [{
- xtype: 'label',
- text: '旋转'
- }, {
- xtype: 'number',
- id: 'objectRotationX',
- step: 10,
- unit: '°',
- style: {
- width: '50px'
- },
- onChange: update
- }, {
- xtype: 'number',
- id: 'objectRotationY',
- step: 10,
- unit: '°',
- style: {
- width: '50px'
- },
- onChange: update
- }, {
- xtype: 'number',
- id: 'objectRotationZ',
- step: 10,
- unit: '°',
- style: {
- width: '50px'
- },
- onChange: update
- }]
- }, { // scale
- xtype: 'row',
- id: 'objectScaleRow',
- children: [{
- xtype: 'label',
- text: '尺寸'
- }, {
- xtype: 'checkbox',
- id: 'objectScaleLock',
- value: true,
- style: {
- position: 'absolute',
- left: '75px'
- }
- }, {
- xtype: 'number',
- id: 'objectScaleX',
- value: 1,
- range: [0.01, Infinity],
- style: {
- width: '50px'
- },
- onChange: function () {
- _this.app.call('updateScaleX', _this);
- }
- }, {
- xtype: 'number',
- id: 'objectScaleY',
- value: 1,
- range: [0.01, Infinity],
- style: {
- width: '50px'
- },
- onChange: function () {
- _this.app.call('updateScaleY', _this);
- }
- }, {
- xtype: 'number',
- id: 'objectScaleZ',
- value: 1,
- range: [0.01, Infinity],
- style: {
- width: '50px'
- },
- onChange: function () {
- _this.app.call('updateScaleZ', _this);
- }
- }]
- }, { // fov
- xtype: 'row',
- id: 'objectFovRow',
- children: [{
- xtype: 'label',
- text: '视场'
- }, {
- xtype: 'number',
- id: 'objectFov',
- onChange: update
- }]
- }, { // near
- xtype: 'row',
- id: 'objectNearRow',
- children: [{
- xtype: 'label',
- text: '近点'
- }, {
- xtype: 'number',
- id: 'objectNear',
- onChange: update
- }]
- }, { // far
- xtype: 'row',
- id: 'objectFarRow',
- children: [{
- xtype: 'label',
- text: '远点'
- }, {
- xtype: 'number',
- id: 'objectFar',
- onChange: update
- }]
- }, { // intensity
- xtype: 'row',
- id: 'objectIntensityRow',
- children: [{
- xtype: 'label',
- text: '强度'
- }, {
- xtype: 'number',
- id: 'objectIntensity',
- range: [0, Infinity],
- onChange: update
- }]
- }, { // color
- xtype: 'row',
- id: 'objectColorRow',
- children: [{
- xtype: 'label',
- text: '颜色'
- }, {
- xtype: 'color',
- id: 'objectColor',
- onChange: update
- }]
- }, { // ground color
- xtype: 'row',
- id: 'objectGroundColorRow',
- children: [{
- xtype: 'label',
- text: '地面颜色'
- }, {
- xtype: 'color',
- id: 'objectGroundColor',
- onChange: update
- }]
- }, { // distance
- xtype: 'row',
- id: 'objectDistanceRow',
- children: [{
- xtype: 'label',
- text: '距离'
- }, {
- xtype: 'number',
- id: 'objectDistance',
- range: [0, Infinity],
- onChange: update
- }]
- }, { // angle
- xtype: 'row',
- id: 'objectAngleRow',
- children: [{
- xtype: 'label',
- text: '角度'
- }, {
- xtype: 'number',
- id: 'objectAngle',
- precision: 3,
- range: [0, Math.PI / 2],
- onChange: update
- }]
- }, { // penumbra
- xtype: 'row',
- id: 'objectPenumbraRow',
- children: [{
- xtype: 'label',
- text: '边缘'
- }, {
- xtype: 'number',
- id: 'objectPenumbra',
- range: [0, 1],
- onChange: update
- }]
- }, { // decay
- xtype: 'row',
- id: 'objectDecayRow',
- children: [{
- xtype: 'label',
- text: '衰变'
- }, {
- xtype: 'number',
- id: 'objectDecay',
- range: [0, Infinity],
- onChange: update
- }]
- }, { // shadow
- xtype: 'row',
- id: 'objectShadowRow',
- children: [{
- xtype: 'label',
- text: '阴影'
- }, {
- xtype: 'boolean',
- id: 'objectCastShadow',
- value: false,
- text: '产生',
- onChange: update
- }, {
- xtype: 'boolean',
- id: 'objectReceiveShadow',
- value: false,
- text: '接收',
- onChange: update
- }, {
- xtype: 'number',
- id: 'objectShadowRadius',
- value: 1,
- onChange: update
- }]
- }, { // visible
- xtype: 'row',
- id: 'objectVisibleRow',
- children: [{
- xtype: 'label',
- text: '可见性'
- }, {
- xtype: 'checkbox',
- id: 'objectVisible',
- onChange: update
- }]
- }, { // user data
- xtype: 'row',
- id: 'objectUserDataRow',
- children: [{
- xtype: 'label',
- text: '用户数据'
- }, {
- xtype: 'textarea',
- id: 'objectUserData',
- style: {
- width: '150px',
- height: '40px',
- fontSize: '12px'
- },
- onChange: update,
- onKeyUp: function () {
- try {
- JSON.parse(this.getValue());
- this.dom.classList.add('success');
- this.dom.classList.remove('fail');
- } catch (error) {
- this.dom.classList.remove('success');
- this.dom.classList.add('fail');
- }
- }
- }]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 工程面板
- * @author mrdoob / http://mrdoob.com/
- */
- function ProjectPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- ProjectPanel.prototype = Object.create(UI$1.Control.prototype);
- ProjectPanel.prototype.constructor = ProjectPanel;
-
- ProjectPanel.prototype.render = function () {
- var editor = this.app.editor;
- var config = editor.config;
-
- var rendererTypes = {
- 'WebGLRenderer': THREE.WebGLRenderer,
- 'CanvasRenderer': THREE.CanvasRenderer,
- 'SVGRenderer': THREE.SVGRenderer,
- 'SoftwareRenderer': THREE.SoftwareRenderer,
- 'RaytracingRenderer': THREE.RaytracingRenderer
- };
-
- var options = {};
-
- for (var key in rendererTypes) {
- if (key.indexOf('WebGL') >= 0 && System.support.webgl === false) continue;
- options[key] = key;
- }
-
- var _this = this;
-
- var updateRenderer = function () {
- _this.app.call('updateRenderer', _this);
- };
-
- var data = {
- xtype: 'div',
- id: 'projectPanel',
- parent: this.parent,
- style: {
- borderTop: 0,
- paddingTop: '20px'
- },
- cls: 'Panel',
- children: [{ // class
- xtype: 'row',
- id: 'rendererTypeRow',
- children: [{
- xtype: 'label',
- text: '渲染器',
- style: {
- width: '90px'
- }
- }, {
- xtype: 'select',
- id: 'rendererType',
- options: options,
- value: config.getKey('project/renderer'),
- style: {
- width: '150px'
- },
- onChange: function () {
- var value = this.getValue();
- config.setKey('project/renderer', value);
- updateRenderer();
- }
- }]
- }, {
- xtype: 'row',
- id: 'rendererPropertiesRow',
- style: {
- marginLeft: '90px'
- },
- children: [{ // antialiasing
- xtype: 'boolean',
- id: 'rendererAntialias',
- value: config.getKey('project/renderer/antialias'),
- text: '抗锯齿',
- onChange: function () {
- config.setKey('project/renderer/antialias', this.getValue());
- updateRenderer();
- }
- }, { // shadow
- xtype: 'boolean',
- id: 'rendererShadows',
- value: config.getKey('project/renderer/shadows'),
- text: '阴影',
- onChange: function () {
- config.setKey('project/renderer/shadows', this.getValue());
- updateRenderer();
- }
- }, {
- xtype: 'br'
- }, { // gamma input
- xtype: 'boolean',
- id: 'rendererGammaInput',
- value: config.getKey('project/renderer/gammaInput'),
- text: 'γ输入',
- onChange: function () {
- config.setKey('project/renderer/gammaInput', this.getValue());
- updateRenderer();
- }
- }, { // gamma output
- xtype: 'boolean',
- id: 'rendererGammaOutput',
- value: config.getKey('project/renderer/gammaOutput'),
- text: 'γ输出',
- onChange: function () {
- config.setKey('project/renderer/gammaOutput', this.getValue());
- updateRenderer();
- }
- }]
- }, { // VR
- xtype: 'row',
- id: 'vrRow',
- children: [{
- xtype: 'label',
- text: '虚拟现实',
- style: {
- width: '90px'
- }
- }, {
- xtype: 'checkbox',
- id: 'vr',
- value: config.getKey('project/vr'),
- style: {
- left: '100px'
- },
- onChange: function () {
- config.setKey('project/vr', this.getValue());
- // updateRenderer();
- }
- }]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 几何体信息面板
- * @author mrdoob / http://mrdoob.com/
- */
- function GeometryInfoPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- GeometryInfoPanel.prototype = Object.create(UI$1.Control.prototype);
- GeometryInfoPanel.prototype.constructor = GeometryInfoPanel;
-
- GeometryInfoPanel.prototype.render = function () {
- var editor = this.app.editor;
-
- this.children = {
- 'xtype': 'row',
- parent: this.parent,
- children: [{ // vertices
- xtype: 'row',
- children: [{
- xtype: 'label',
- text: '顶点'
- }, {
- xtype: 'text',
- id: 'geometryInfoVertices'
- }]
- }, { // faces
- xtype: 'row',
- children: [{
- xtype: 'label',
- text: '面'
- }, {
- xtype: 'text',
- id: 'geometryInfoFaces',
- }]
- }]
- };
-
- var container = UI$1.create(this.children);
- container.render();
-
- function update(object) {
- var vertices = UI$1.get('geometryInfoVertices');
- var faces = UI$1.get('geometryInfoFaces');
-
- if (object === null) return; // objectSelected.dispatch( null )
- if (object === undefined) return;
-
- var geometry = object.geometry;
-
- if (geometry instanceof THREE.Geometry) {
- container.dom.style.display = 'block';
-
- vertices.setValue((geometry.vertices.length).format());
- faces.setValue((geometry.faces.length).format());
- } else {
- container.dom.style.display = 'none';
- }
- }
-
- this.app.on('objectSelected.GeometryInfoPanel', function (mesh) {
- update(mesh);
- });
-
- this.app.on('geometryChanged.GeometryInfoPanel', function (mesh) {
- update(mesh);
- });
- };
-
- /**
- * 缓冲几何体面板
- * @author mrdoob / http://mrdoob.com/
- */
- function BufferGeometryPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- BufferGeometryPanel.prototype = Object.create(UI$1.Control.prototype);
- BufferGeometryPanel.prototype.constructor = BufferGeometryPanel;
-
- BufferGeometryPanel.prototype.render = function () {
- var editor = this.app.editor;
-
- var data = {
- xtype: 'row',
- id: 'bufferGeometryPanel',
- parent: this.parent
- };
-
- var container = UI$1.create(data);
- container.render();
-
- function update(object) {
- if (object === null) return; // objectSelected.dispatch( null )
- if (object === undefined) return;
-
- var geometry = object.geometry;
-
- if (geometry instanceof THREE.BufferGeometry) {
- container.dom.innerHTML = '';
- container.dom.style.display = 'block';
-
- var index = geometry.index;
-
- if (index !== null) {
- var panel = UI$1.create({
- xtype: 'row',
- parent: container.dom,
- children: [{
- xtype: 'label',
- text: '索引数'
- }, {
- xtype: 'text',
- text: (index.count).format(),
- style: {
- fontSize: '12px'
- }
- }]
- });
-
- panel.render();
- }
-
- var attributes = geometry.attributes;
-
- for (var name in attributes) {
-
- var attribute = attributes[name];
-
- var panel = UI$1.create({
- xtype: 'row',
- parent: container.dom,
- children: [{
- xtype: 'label',
- text: name
- }, {
- xtype: 'text',
- text: (attribute.count).format() + ' (' + attribute.itemSize + ')',
- style: {
- fontSize: '12px'
- }
- }]
- });
-
- panel.render();
- }
- } else {
- container.dom.style.display = 'none';
- }
- }
-
- this.app.on('objectSelected.BufferGeometryPanel', function (mesh) {
- update(mesh);
- });
-
- this.app.on('geometryChanged.BufferGeometryPanel', function (mesh) {
- update(mesh);
- });
- };
-
- /**
- * 几何体面板
- * @author mrdoob / http://mrdoob.com/
- */
- function GeometryPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- GeometryPanel.prototype = Object.create(UI$1.Control.prototype);
- GeometryPanel.prototype.constructor = GeometryPanel;
-
- GeometryPanel.prototype.render = function () {
- var editor = this.app.editor;
-
- this.children = [{
- xtype: 'div',
- id: 'geometryPanel',
- parent: this.parent,
- cls: 'Panel',
- style: {
- borderTop: 0,
- paddingTop: '20px',
- display: 'none'
- },
- children: [{ // type
- xtype: 'row',
- id: 'geometryTypeRow',
- children: [{
- xtype: 'label',
- text: '类型'
- }, {
- xtype: 'text',
- id: 'geometryType'
- }]
- }, { // uuid
- xtype: 'row',
- id: 'geometryUUIDRow',
- children: [{
- xtype: 'label',
- text: 'UUID'
- }, {
- xtype: 'input',
- id: 'geometryUUID',
- style: {
- width: '102px',
- fontSize: '12px'
- },
- disabled: true
- }, {
- xtype: 'button',
- id: 'geometryUUIDRenew',
- text: '新建',
- style: {
- marginLeft: '7px'
- },
- onClick: function () {
- geometryUUID.setValue(THREE.Math.generateUUID());
- editor.execute(new SetGeometryValueCommand(editor.selected, 'uuid', geometryUUID.getValue()));
- }
- }]
- }, { // name
- xtype: 'row',
- id: 'geometryNameRow',
- children: [{
- xtype: 'label',
- text: '名称'
- }, {
- xtype: 'input',
- id: 'geometryName',
- style: {
- width: '150px',
- fontSize: '12px'
- },
- onChange: function () {
- editor.execute(new SetGeometryValueCommand(editor.selected, 'name', this.getValue()));
- }
- }]
- }, {
- xtype: 'row',
- id: 'geometryParameters',
- children: [
- new BufferGeometryPanel({ app: this.app })
- ]
- },
- new GeometryInfoPanel({ app: this.app, id: 'geometryInfoPanel' })
- ]
- }];
-
- var container = UI$1.create(this.children[0]);
- container.render();
- };
-
- /**
- * 属性面板
- * @author mrdoob / http://mrdoob.com/
- */
- function PropertyPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- PropertyPanel.prototype = Object.create(UI$1.Control.prototype);
- PropertyPanel.prototype.constructor = PropertyPanel;
-
- PropertyPanel.prototype.render = function () {
- var editor = this.app.editor;
-
- var _this = this;
-
- var onClick = function (event) {
- _this.app.call('selectPropertyTab', _this, event.target.textContent);
- };
-
- var data = {
- xtype: 'div',
- id: 'propertyPanel',
- parent: this.parent,
- children: [{
- xtype: 'div',
- cls: 'tabs',
- children: [{
- xtype: 'text',
- id: 'objectTab',
- text: '物体',
- onClick: onClick
- }, {
- xtype: 'text',
- id: 'geometryTab',
- text: '几何',
- onClick: onClick
- }, {
- xtype: 'text',
- id: 'materialTab',
- text: '材质',
- onClick: onClick
- }]
- }, {
- xtype: 'div',
- children: [
- new ObjectPanel({ app: this.app, id: 'object' })
- ]
- }, {
- xtype: 'div',
- children: [
- new GeometryPanel({ app: this.app, id: 'geometry' })
- ]
- }, {
- xtype: 'div',
- children: [
- new MaterialPanel({ app: this.app, id: 'material' })
- ]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 场景面板
- * @author mrdoob / http://mrdoob.com/
- */
- function ScenePanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- ScenePanel.prototype = Object.create(UI$1.Control.prototype);
- ScenePanel.prototype.constructor = ScenePanel;
-
- ScenePanel.prototype.render = function () {
- var editor = this.app.editor;
-
- var _this = this;
-
- var onFogChanged = function () {
- var fogType = UI$1.get('fogType');
- var fogColor = UI$1.get('fogColor');
- var fogNear = UI$1.get('fogNear');
- var fogFar = UI$1.get('fogFar');
- var fogDensity = UI$1.get('fogDensity');
-
- _this.app.call('sceneFogChanged',
- _this,
- fogType.getValue(),
- fogColor.getHexValue(),
- fogNear.getValue(),
- fogFar.getValue(),
- fogDensity.getValue()
- );
- };
-
- var refreshFogUI = function () {
- _this.app.call('updateScenePanelFog', _this);
- };
-
- var data = {
- xtype: 'div',
- id: 'scenePanel',
- parent: this.parent,
- cls: 'Panel',
- children: [{ // outliner
- xtype: 'outliner',
- id: 'outliner',
- editor: editor,
- onChange: function () {
- _this.app.call('outlinerChange', _this, this);
- },
- onDblClick: function () {
- editor.focusById(parseInt(this.getValue()));
- }
- }, {
- xtype: 'br'
- }, { // background
- xtype: 'row',
- id: 'backgroundRow',
- children: [{
- xtype: 'label',
- text: '背景',
- style: {
- width: '90px'
- }
- }, {
- xtype: 'color',
- id: 'backgroundColor',
- value: '#aaaaaa',
- onChange: function () {
- _this.app.call('sceneBackgroundChanged', _this, this.getHexValue());
- }
- }]
- }, { // fog
- xtype: 'row',
- id: 'fogTypeRow',
- children: [{
- xtype: 'label',
- text: '雾',
- style: {
- width: '90px'
- }
- }, {
- xtype: 'select',
- id: 'fogType',
- options: {
- 'None': '无',
- 'Fog': '线性',
- 'FogExp2': '指数型'
- },
- style: {
- width: '150px'
- },
- onChange: function () {
- onFogChanged();
- refreshFogUI();
- }
- }]
- }, {
- xtype: 'row',
- id: 'fogPropertiesRow',
- children: [{ // fog color
- xtype: 'color',
- id: 'fogColor',
- value: '#aaaaaa',
- onChange: onFogChanged
- }, { // fog near
- xtype: 'number',
- id: 'fogNear',
- value: 0.1,
- style: {
- width: '40px'
- },
- range: [0, Infinity],
- onChange: onFogChanged
- }, { // fog far
- xtype: 'number',
- id: 'fogFar',
- value: 50,
- style: {
- width: '40px'
- },
- range: [0, Infinity],
- onChange: onFogChanged
- }, { // fog density
- xtype: 'number',
- id: 'fogDensity',
- value: 0.05,
- style: {
- width: '40px'
- },
- range: [0, 0.1],
- precision: 3,
- onChange: onFogChanged
- }]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 脚本面板
- * @author mrdoob / http://mrdoob.com/
- */
- function ScriptPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- ScriptPanel.prototype = Object.create(UI$1.Control.prototype);
- ScriptPanel.prototype.constructor = ScriptPanel;
-
- ScriptPanel.prototype.render = function () {
- var editor = this.app.editor;
-
- var data = {
- xtype: 'div',
- id: 'scriptPanel',
- parent: this.parent,
- cls: 'Panel scriptPanel',
- style: {
- display: 'none'
- },
- children: [{
- xtype: 'label',
- text: '脚本'
- }, {
- xtype: 'br'
- }, {
- xtype: 'br'
- }, {
- xtype: 'row',
- id: 'scriptsContainer'
- }, {
- xtype: 'button',
- id: 'newScript',
- text: '新建',
- onClick: function () {
- var script = { name: '', source: 'function update( event ) {}' };
- editor.execute(new AddScriptCommand(editor.selected, script));
- }
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 设置面板
- * @author mrdoob / http://mrdoob.com/
- */
- function SettingPanel(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- SettingPanel.prototype = Object.create(UI$1.Control.prototype);
- SettingPanel.prototype.constructor = SettingPanel;
-
- SettingPanel.prototype.render = function () {
- var editor = this.app.editor;
- var config = editor.config;
-
- var data = {
- xtype: 'div',
- id: 'settingPanel',
- parent: this.parent,
- cls: 'Panel',
- style: {
- borderTop: 0,
- paddingTop: '20px'
- },
- children: [{
- xtype: 'row',
- id: 'themeRow',
- children: [{
- xtype: 'label',
- text: '主题'
- }, { // class
- xtype: 'select',
- options: {
- 'assets/css/light.css': '浅色',
- 'assets/css/dark.css': '深色'
- },
- value: config.getKey('theme'),
- style: {
- width: '150px'
- },
- onChange: function () {
- var value = this.getValue();
- editor.setTheme(value);
- editor.config.setKey('theme', value);
- }
- }]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 侧边栏
- * @author mrdoob / http://mrdoob.com/
- */
- function Sidebar(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- Sidebar.prototype = Object.create(UI$1.Control.prototype);
- Sidebar.prototype.constructor = Sidebar;
-
- Sidebar.prototype.render = function () {
- var editor = this.app.editor;
- var _this = this;
-
- function onClick(event) {
- _this.app.call('selectTab', _this, event.target.textContent);
- }
-
- var data = {
- xtype: 'div',
- id: 'sidebar',
- cls: 'sidebar',
- parent: this.app.container,
- children: [{
- xtype: 'div',
- cls: 'tabs',
- children: [{
- xtype: 'text',
- id: 'sceneTab',
- text: '场景',
- onClick: onClick
- }, {
- xtype: 'text',
- id: 'projectTab',
- text: '工程',
- onClick: onClick
- }, {
- xtype: 'text',
- id: 'settingsTab',
- text: '设置',
- onClick: onClick
- }]
- }, { // scene
- xtype: 'div',
- id: 'scene',
- children: [
- new ScenePanel({ app: this.app }),
- new PropertyPanel({ app: this.app }),
- new ScriptPanel({ app: this.app })
- ]
- }, { // project
- xtype: 'div',
- id: 'project',
- children: [
- new ProjectPanel({ app: this.app })
- ]
- }, {
- xtype: 'div',
- id: 'settings',
- children: [
- new SettingPanel({ app: this.app }),
- new HistoryPanel({ app: this.app })
- ]
- }]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
/**
* Geometry序列化器
*/
@@ -49587,278 +49967,6 @@
this.dispatch.on(eventName, callback);
};
- /**
- * 配置选项
- * @param {*} options 配置选项
- */
- function Options(options) {
- options = options || {};
- this.server = options.server || location.origin;
-
- this.gravityConstant = -9.8; // 重力加速度
- }
-
- /**
- * 工具栏
- */
- function Toolbar(options) {
- UI$1.Control.call(this, options);
- this.app = options.app;
- }
- Toolbar.prototype = Object.create(UI$1.Control.prototype);
- Toolbar.prototype.constructor = Toolbar;
-
- Toolbar.prototype.render = function () {
-
- var data = {
- xtype: 'div',
- id: 'toolbar',
- parent: this.app.container,
- cls: 'toolbar',
- children: [{
- xtype: 'iconbutton',
- id: 'selectBtn',
- icon: 'icon-select',
- cls: 'Button IconButton selected',
- title: '选择'
- }, {
- xtype: 'iconbutton',
- id: 'translateBtn',
- icon: 'icon-translate',
- title: '平移(W)'
- }, {
- xtype: 'iconbutton',
- id: 'rotateBtn',
- icon: 'icon-rotate',
- title: '旋转(E)'
- }, {
- xtype: 'iconbutton',
- id: 'scaleBtn',
- icon: 'icon-scale',
- title: '缩放(R)'
- }, {
- xtype: 'hr'
- }, {
- xtype: 'iconbutton',
- id: 'modelBtn',
- icon: 'icon-model-view',
- title: '模型'
- }
- // , {
- // xtype: 'iconbutton',
- // id: 'handBtn',
- // icon: 'icon-hand',
- // title: '抓手'
- // }, {
- // xtype: 'iconbutton',
- // id: 'anchorPointBtn',
- // icon: 'icon-anchor-point',
- // title: '添加锚点'
- // }, {
- // xtype: 'iconbutton',
- // id: 'pathBtn',
- // icon: 'icon-path',
- // title: '绘制路径'
- // }
- ]
- };
-
- var control = UI$1.create(data);
- control.render();
- };
-
- /**
- * 时间线窗口
- * @param {*} options
- */
- function TimePanel(options) {
- Control.call(this, options);
- }
-
- TimePanel.prototype = Object.create(Control.prototype);
- TimePanel.prototype.constructor = TimePanel;
-
- TimePanel.prototype.render = function () {
- return;
- var target = {
- x: 0,
- y: 0,
- rotate: 0
- };
-
- var timeliner = new Timeliner(target, {
- position: 'absolute',
- left: '48px',
- right: '300px',
- bottom: '32px'
- });
-
- timeliner.load({
- 'version': '1.2.0',
- 'modified': 'Mon Dec 08 2014 10:41:11 GMT+0800 (SGT)',
- 'title': 'Untitled',
- 'layers': [{
- 'name': 'x',
- 'values': [{
- 'time': 0.1,
- 'value': 0,
- '_color': '#893c0f',
- 'tween': 'quadEaseIn'
- }, {
- 'time': 3,
- 'value': 3.500023,
- '_color': '#b074a0'
- }],
- 'tmpValue': 3.500023,
- '_color': '#6ee167'
- }, {
- 'name': 'y',
- 'values': [{
- 'time': 0.1,
- 'value': 0,
- '_color':
- '#abac31',
- 'tween': 'quadEaseOut'
- }, {
- 'time': 0.5,
- 'value': -1.000001,
- '_color': '#355ce8',
- 'tween': 'quadEaseIn'
- }, {
- 'time': 1.1,
- 'value': 0,
- '_color': '#47e90',
- 'tween': 'quadEaseOut'
- }, {
- 'time': 1.7,
- 'value': -0.5,
- '_color':
- '#f76bca',
- 'tween': 'quadEaseOut'
- }, {
- 'time': 2.3,
- 'value': 0,
- '_color': '#d59cfd'
- }],
- 'tmpValue': -0.5,
- '_color': '#8bd589'
- }, {
- 'name': 'rotate',
- 'values': [{
- 'time': 0.1,
- 'value': -25.700014000000003,
- '_color': '#f50ae9',
- 'tween': 'quadEaseInOut'
- }, {
- 'time': 2.8,
- 'value': 0,
- '_color': '#2e3712'
- }],
- 'tmpValue': -25.700014000000003,
- '_color': '#2d9f57'
- }]
- });
- };
-
- function Physics(options) {
- this.app = options.app;
-
- // Physics configuration
- this.collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration();
- this.dispatcher = new Ammo.btCollisionDispatcher(this.collisionConfiguration);
- this.broadphase = new Ammo.btDbvtBroadphase();
- this.solver = new Ammo.btSequentialImpulseConstraintSolver();
- this.softBodySolver = new Ammo.btDefaultSoftBodySolver();
-
- this.physicsWorld = new Ammo.btSoftRigidDynamicsWorld(this.dispatcher, this.broadphase, this.solver, this.collisionConfiguration, this.softBodySolver);
- this.physicsWorld.setGravity(new Ammo.btVector3(0, this.app.options.gravityConstant, 0));
- this.physicsWorld.getWorldInfo().set_m_gravity(new Ammo.btVector3(0, this.app.options.gravityConstant, 0));
- }
-
- Physics.prototype.init = function () {
-
- };
-
- /**
- * 应用程序
- */
- function Application(container, options) {
-
- // 容器
- this.container = container;
- this.width = this.container.clientWidth;
- this.height = this.container.clientHeight;
-
- // 配置
- this.options = new Options(options);
-
- // 事件
- this.event = new EventDispatcher(this);
- this.call = this.event.call.bind(this.event);
- this.on = this.event.on.bind(this.event);
-
- var params = { app: this, parent: this.container };
-
- // 用户界面
- this.ui = UI$1;
-
- this.menubar = new Menubar(params); // 菜单栏
- this.menubar.render();
-
- this.toolbar = new Toolbar(params); // 工具栏
- this.toolbar.render();
-
- this.viewport = new Viewport(params); // 场景编辑区
- this.viewport.render();
-
- this.editor = new Editor(this); // 编辑器
-
- this.sidebar = new Sidebar(params); // 侧边栏
- this.sidebar.render();
-
- this.statusBar = new StatusBar(params); // 状态栏
- this.statusBar.render();
-
- this.script = new Script(params); // 脚本编辑面板
- this.script.render();
-
- this.player = new Player(params); // 播放器面板
- this.player.render();
-
- this.timePanel = new TimePanel(params); // 时间面板
- this.timePanel.render();
-
- // 物理引擎
- this.physics = new Physics(params);
- this.physics.init();
-
- this.running = false;
-
- // 是否从文件中加载场景,从文件中加载场景的url格式是index.html#file=xxx
- this.isLoadingFromHash = false;
- }
-
- Application.prototype.start = function () {
- this.running = true;
-
- // 启动事件 - 事件要在ui创建完成后启动
- this.event.start();
-
- this.call('appStart', this);
- this.call('resize', this);
- this.call('initApp', this);
- this.call('appStarted', this);
- };
-
- Application.prototype.stop = function () {
- this.running = false;
-
- this.call('appStop', this);
- this.call('appStoped', this);
-
- this.event.stop();
- };
-
exports.Options = Options;
exports.Application = Application;
exports.System = System;
diff --git a/ShadowEditor.Web/src/serialization/BaseSerializer.js b/ShadowEditor.Web/src/serialization/BaseSerializer.js
index eefafa58..88bf9cf1 100644
--- a/ShadowEditor.Web/src/serialization/BaseSerializer.js
+++ b/ShadowEditor.Web/src/serialization/BaseSerializer.js
@@ -13,11 +13,11 @@ function BaseSerializer() {
}
/**
- * 判断对象或字符串是否满足转换条件,满足返回true,不满足返回false
+ * 判断对象是否满足转换条件,满足返回true,不满足返回false
* @param {*} obj
*/
BaseSerializer.prototype.filter = function (obj) {
-
+ return false;
};
/**
@@ -25,14 +25,21 @@ BaseSerializer.prototype.filter = function (obj) {
* @param {*} obj 对象
*/
BaseSerializer.prototype.toJSON = function (obj) {
- return {};
+ var json = {};
+ Object.assign(json, this.metadata);
+ return json;
};
/**
* json转对象
- * @param {*} json json字符串
+ * @param {*} json json对象
+ * @param {*} parent 父对象
*/
-BaseSerializer.prototype.fromJSON = function (json) {
+BaseSerializer.prototype.fromJSON = function (json, parent) {
+ if (parent) {
+ return parent;
+ }
+
return null;
};
diff --git a/ShadowEditor.Web/src/serialization/Converter.js b/ShadowEditor.Web/src/serialization/Converter.js
index 09648e42..37e27196 100644
--- a/ShadowEditor.Web/src/serialization/Converter.js
+++ b/ShadowEditor.Web/src/serialization/Converter.js
@@ -52,25 +52,23 @@ Converter.prototype = Object.create(BaseSerializer.prototype);
Converter.prototype.constructor = Converter;
Converter.prototype.filter = function (obj) {
- return true;
+ return false;
};
Converter.prototype.toJSON = function (app) {
var list = [];
// 配置
- var config = {
- Metadata: Serializers.Config.Metadata,
- Object: Serializers.Config.Serializer.toJSON(app.editor.config),
- };
+ var config = (new ConfigSerializer()).toJSON(app);
list.push(config);
// 相机
- var camera = {
- Metadata: Serializers.PerspectiveCamera.Metadata,
- Object: Serializers.PerspectiveCamera.Serializer.toJSON(app.editor.camera)
- };
- list.push(camera);
+ var camera;
+ if (app.editor.camera instanceof THREE.OrthographicCamera) {
+ camera = (new OrthographicCameraSerializer()).toJSON(app.editor.camera);
+ } else {
+ camera = (new PerspectiveCameraSerializer()).toJSON(app.editor.camera);
+ }
// 脚本
Object.keys(app.editor.scripts).forEach(function (id) {
@@ -88,17 +86,17 @@ Converter.prototype.toJSON = function (app) {
});
// 场景
- app.editor.scene.traverse(function (obj) {
- if (Serializers[obj.constructor.name] != null) {
- var json = {
- Metadata: Serializers[obj.constructor.name].Metadata,
- Object: Serializers[obj.constructor.name].Serializer.toJSON(obj)
- };
- list.push(json);
- } else {
- console.log(`There is no serializer to serialize ${obj.name}`);
- }
- });
+ // app.editor.scene.traverse(function (obj) {
+ // if (Serializers[obj.constructor.name] != null) {
+ // var json = {
+ // Metadata: Serializers[obj.constructor.name].Metadata,
+ // Object: Serializers[obj.constructor.name].Serializer.toJSON(obj)
+ // };
+ // list.push(json);
+ // } else {
+ // console.log(`There is no serializer to serialize ${obj.name}`);
+ // }
+ // });
return list;
};
diff --git a/ShadowEditor.Web/src/serialization/app/ConfigSerializer.js b/ShadowEditor.Web/src/serialization/app/ConfigSerializer.js
index 689613d7..da2807ec 100644
--- a/ShadowEditor.Web/src/serialization/app/ConfigSerializer.js
+++ b/ShadowEditor.Web/src/serialization/app/ConfigSerializer.js
@@ -1,7 +1,8 @@
import BaseSerializer from '../BaseSerializer';
+import Application from '../../Application';
/**
- * Object3D序列化器
+ * 配置序列化器
*/
function ConfigSerializer() {
BaseSerializer.call(this);
@@ -10,13 +11,26 @@ function ConfigSerializer() {
ConfigSerializer.prototype = Object.create(BaseSerializer.prototype);
ConfigSerializer.prototype.constructor = ConfigSerializer;
-ConfigSerializer.prototype.toJSON = function (obj) {
- var json = obj.toJSON();
+ConfigSerializer.prototype.filter = function (obj) {
+ if (obj instanceof Application) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
+ConfigSerializer.prototype.toJSON = function (app) {
+ var json = BaseSerializer.prototype.toJSON(app);
+ Object.assign(json, app.editor.config.toJSON());
return json;
};
-ConfigSerializer.prototype.fromJSON = function (json) {
-
+ConfigSerializer.prototype.fromJSON = function (app, json) {
+ Object.keys(json).forEach(key => {
+ app.editor.config.setKey(key, json[key]);
+ });
};
export default ConfigSerializer;
\ No newline at end of file
diff --git a/ShadowEditor.Web/src/serialization/app/ScriptSerializer.js b/ShadowEditor.Web/src/serialization/app/ScriptSerializer.js
index a8642768..97c93811 100644
--- a/ShadowEditor.Web/src/serialization/app/ScriptSerializer.js
+++ b/ShadowEditor.Web/src/serialization/app/ScriptSerializer.js
@@ -1,4 +1,5 @@
import BaseSerializer from '../BaseSerializer';
+import Application from '../../Application';
/**
* Object3D序列化器
@@ -10,12 +11,46 @@ function ScriptSerializer() {
ScriptSerializer.prototype = Object.create(BaseSerializer.prototype);
ScriptSerializer.prototype.constructor = ScriptSerializer;
-ScriptSerializer.prototype.toJSON = function (obj) {
- return obj;
+ScriptSerializer.prototype.filter = function (obj) {
+ if (obj instanceof Application) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
};
-ScriptSerializer.prototype.fromJSON = function (json) {
+ScriptSerializer.prototype.toJSON = function (app) {
+ var list = [];
+ Object.keys(app.editor.scripts).forEach(id => {
+ var json = BaseSerializer.prototype.toJSON(app);
+
+ var name = app.editor.scripts[id].name;
+ var source = app.editor.scripts[id].source;
+
+ Object.assign(json, {
+ id: id,
+ name: name,
+ source: source
+ });
+
+ list.push(json);
+ });
+
+ return list;
+};
+
+ScriptSerializer.prototype.fromJSON = function (app, json) {
+ app.editor.scripts = {};
+
+ json.forEach(n => {
+ app.editor.scripts[id] = {
+ name: n.name,
+ source: n.source
+ };
+ });
};
export default ScriptSerializer;
\ No newline at end of file
diff --git a/ShadowEditor.Web/src/serialization/camera/CameraSerializer.js b/ShadowEditor.Web/src/serialization/camera/CameraSerializer.js
index 97a883cb..fe7768f0 100644
--- a/ShadowEditor.Web/src/serialization/camera/CameraSerializer.js
+++ b/ShadowEditor.Web/src/serialization/camera/CameraSerializer.js
@@ -11,6 +11,16 @@ function CameraSerializer() {
CameraSerializer.prototype = Object.create(BaseSerializer.prototype);
CameraSerializer.prototype.constructor = CameraSerializer;
+CameraSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.Camera) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
CameraSerializer.prototype.toJSON = function (obj) {
var json = Object3DSerializer.prototype.toJSON(obj);
@@ -20,8 +30,12 @@ CameraSerializer.prototype.toJSON = function (obj) {
return json;
};
-CameraSerializer.prototype.fromJSON = function (json) {
+CameraSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? new THREE.Camera() : parent;
+ // TODO: Three.Camera反序列化
+
+ return obj;
};
export default CameraSerializer;
\ No newline at end of file
diff --git a/ShadowEditor.Web/src/serialization/camera/OrthographicCameraSerializer.js b/ShadowEditor.Web/src/serialization/camera/OrthographicCameraSerializer.js
index 2e7a4576..02a9e741 100644
--- a/ShadowEditor.Web/src/serialization/camera/OrthographicCameraSerializer.js
+++ b/ShadowEditor.Web/src/serialization/camera/OrthographicCameraSerializer.js
@@ -11,6 +11,16 @@ function OrthographicCameraSerializer() {
OrthographicCameraSerializer.prototype = Object.create(BaseSerializer.prototype);
OrthographicCameraSerializer.prototype.constructor = OrthographicCameraSerializer;
+OrthographicCameraSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.OrthographicCamera) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
OrthographicCameraSerializer.prototype.toJSON = function (obj) {
var json = CameraSerializer.prototype.toJSON(obj);
@@ -26,8 +36,12 @@ OrthographicCameraSerializer.prototype.toJSON = function (obj) {
return json;
};
-OrthographicCameraSerializer.prototype.fromJSON = function (json) {
+OrthographicCameraSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? new THREE.OrthographicCamera() : parent;
+ // TODO: THREE.OrthographicCamera反序列化
+
+ return obj;
};
export default OrthographicCameraSerializer;
\ No newline at end of file
diff --git a/ShadowEditor.Web/src/serialization/camera/PerspectiveCameraSerializer.js b/ShadowEditor.Web/src/serialization/camera/PerspectiveCameraSerializer.js
index 0c7eb54c..c3562c78 100644
--- a/ShadowEditor.Web/src/serialization/camera/PerspectiveCameraSerializer.js
+++ b/ShadowEditor.Web/src/serialization/camera/PerspectiveCameraSerializer.js
@@ -11,6 +11,16 @@ function PerspectiveCameraSerializer() {
PerspectiveCameraSerializer.prototype = Object.create(BaseSerializer.prototype);
PerspectiveCameraSerializer.prototype.constructor = PerspectiveCameraSerializer;
+PerspectiveCameraSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.PerspectiveCamera) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
PerspectiveCameraSerializer.prototype.toJSON = function (obj) {
var json = CameraSerializer.prototype.toJSON(obj);
@@ -27,8 +37,12 @@ PerspectiveCameraSerializer.prototype.toJSON = function (obj) {
return json;
};
-PerspectiveCameraSerializer.prototype.fromJSON = function (json) {
+PerspectiveCameraSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? new THREE.PerspectiveCamera() : parent;
+ // TODO: THREE.PerspectiveCamera 反序列化
+
+ return obj;
};
export default PerspectiveCameraSerializer;
\ No newline at end of file
diff --git a/ShadowEditor.Web/src/serialization/core/Object3DSerializer.js b/ShadowEditor.Web/src/serialization/core/Object3DSerializer.js
index bb0ebf66..30fe9cec 100644
--- a/ShadowEditor.Web/src/serialization/core/Object3DSerializer.js
+++ b/ShadowEditor.Web/src/serialization/core/Object3DSerializer.js
@@ -10,13 +10,23 @@ function Object3DSerializer() {
Object3DSerializer.prototype = Object.create(BaseSerializer.prototype);
Object3DSerializer.prototype.constructor = Object3DSerializer;
+Object3DSerializer.prototype.filter = function (obj) {
+ if (obj instanceof THREE.Object3D) {
+ return true;
+ } else if (obj.metadata && obj.metadata.generator === this.constructor.name) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
Object3DSerializer.prototype.toJSON = function (obj) {
var json = BaseSerializer.prototype.toJSON(obj);
json.type = obj.type;
json.uuid = obj.uuid;
json.castShadow = obj.castShadow;
- json.children = obj.children.map(function (child) {
+ json.children = obj.children.map(child => {
return child.uuid;
});
json.frustumCulled = obj.frustumCulled;
@@ -46,8 +56,12 @@ Object3DSerializer.prototype.toJSON = function (obj) {
return json;
};
-Object3DSerializer.prototype.fromJSON = function (json) {
+Object3DSerializer.prototype.fromJSON = function (json, parent) {
+ var obj = parent === undefined ? THREE.Object3D : parent;
+ // TODO: Object3D反序列化
+
+ return obj;
};
export default Object3DSerializer;
\ No newline at end of file