Просмотр исходного кода

Editor: Add dialog for glTF import. (#32784)

Michael Herzog 1 месяц назад
Родитель
Сommit
9bcbade584
4 измененных файлов с 266 добавлено и 40 удалено
  1. 112 0
      editor/js/GLTFImportDialog.js
  2. 117 34
      editor/js/Loader.js
  3. 36 6
      editor/js/Strings.js
  4. 1 0
      editor/sw.js

+ 112 - 0
editor/js/GLTFImportDialog.js

@@ -0,0 +1,112 @@
+import { UIRow, UIText, UICheckbox, UIButton } from './libs/ui.js';
+
+class GLTFImportDialog {
+
+	constructor( strings ) {
+
+		this.strings = strings;
+
+		const dom = document.createElement( 'div' );
+		dom.className = 'Dialog';
+		this.dom = dom;
+
+		const background = document.createElement( 'div' );
+		background.className = 'Dialog-background';
+		background.addEventListener( 'click', () => this.cancel() );
+		dom.appendChild( background );
+
+		const content = document.createElement( 'div' );
+		content.className = 'Dialog-content';
+		dom.appendChild( content );
+
+		// Title
+
+		const titleBar = document.createElement( 'div' );
+		titleBar.className = 'Dialog-title';
+		titleBar.textContent = strings.getKey( 'dialog/gltf/title' );
+		content.appendChild( titleBar );
+
+		// Body
+
+		const body = document.createElement( 'div' );
+		body.className = 'Dialog-body';
+		content.appendChild( body );
+
+		// As Scene Checkbox
+
+		const asSceneRow = new UIRow();
+		body.appendChild( asSceneRow.dom );
+
+		this.asSceneCheckbox = new UICheckbox( false );
+		asSceneRow.add( this.asSceneCheckbox );
+
+		asSceneRow.add( new UIText( strings.getKey( 'dialog/gltf/asScene' ) ).setMarginLeft( '6px' ) );
+
+		// Buttons
+
+		const buttonsRow = document.createElement( 'div' );
+		buttonsRow.className = 'Dialog-buttons';
+		body.appendChild( buttonsRow );
+
+		const okButton = new UIButton( strings.getKey( 'dialog/ok' ) );
+		okButton.setWidth( '80px' );
+		okButton.onClick( () => this.confirm() );
+		buttonsRow.appendChild( okButton.dom );
+
+		const cancelButton = new UIButton( strings.getKey( 'dialog/cancel' ) );
+		cancelButton.setWidth( '80px' );
+		cancelButton.setMarginLeft( '8px' );
+		cancelButton.onClick( () => this.cancel() );
+		buttonsRow.appendChild( cancelButton.dom );
+
+		// Promise handlers
+
+		this.resolve = null;
+		this.reject = null;
+
+	}
+
+	show() {
+
+		document.body.appendChild( this.dom );
+
+		return new Promise( ( resolve, reject ) => {
+
+			this.resolve = resolve;
+			this.reject = reject;
+
+		} );
+
+	}
+
+	confirm() {
+
+		const result = {
+			asScene: this.asSceneCheckbox.getValue()
+		};
+
+		this.dom.remove();
+
+		if ( this.resolve ) {
+
+			this.resolve( result );
+
+		}
+
+	}
+
+	cancel() {
+
+		this.dom.remove();
+
+		if ( this.reject ) {
+
+			this.reject( new Error( 'Import cancelled' ) );
+
+		}
+
+	}
+
+}
+
+export { GLTFImportDialog };

+ 117 - 34
editor/js/Loader.js

@@ -3,9 +3,12 @@ import * as THREE from 'three';
 import { TGALoader } from 'three/addons/loaders/TGALoader.js';
 
 import { AddObjectCommand } from './commands/AddObjectCommand.js';
+import { SetSceneCommand } from './commands/SetSceneCommand.js';
 
 import { LoaderUtils } from './LoaderUtils.js';
 
+import { GLTFImportDialog } from './GLTFImportDialog.js';
+
 import { unzipSync, strFromU8 } from 'three/addons/libs/fflate.module.js';
 
 function Loader( editor ) {
@@ -268,20 +271,40 @@ function Loader( editor ) {
 
 					const contents = event.target.result;
 
-					const loader = await createGLTFLoader();
+					try {
+
+						const dialog = new GLTFImportDialog( editor.strings );
+						const options = await dialog.show();
 
-					loader.parse( contents, '', function ( result ) {
+						const loader = await createGLTFLoader();
 
-						const scene = result.scene;
-						scene.name = filename;
+						loader.parse( contents, '', function ( result ) {
 
-						scene.animations.push( ...result.animations );
-						editor.execute( new AddObjectCommand( editor, scene ) );
+							const scene = result.scene;
+							scene.name = filename;
 
-						loader.dracoLoader.dispose();
-						loader.ktx2Loader.dispose();
+							scene.animations.push( ...result.animations );
 
-					} );
+							if ( options.asScene ) {
+
+								editor.execute( new SetSceneCommand( editor, scene ) );
+
+							} else {
+
+								editor.execute( new AddObjectCommand( editor, scene ) );
+
+							}
+
+							loader.dracoLoader.dispose();
+							loader.ktx2Loader.dispose();
+
+						} );
+
+					} catch ( e ) {
+
+						// Import cancelled
+
+					}
 
 				}, false );
 				reader.readAsArrayBuffer( file );
@@ -298,20 +321,40 @@ function Loader( editor ) {
 
 					const contents = event.target.result;
 
-					const loader = await createGLTFLoader( manager );
+					try {
 
-					loader.parse( contents, '', function ( result ) {
+						const dialog = new GLTFImportDialog( editor.strings );
+						const options = await dialog.show();
 
-						const scene = result.scene;
-						scene.name = filename;
+						const loader = await createGLTFLoader( manager );
 
-						scene.animations.push( ...result.animations );
-						editor.execute( new AddObjectCommand( editor, scene ) );
+						loader.parse( contents, '', function ( result ) {
 
-						loader.dracoLoader.dispose();
-						loader.ktx2Loader.dispose();
+							const scene = result.scene;
+							scene.name = filename;
 
-					} );
+							scene.animations.push( ...result.animations );
+
+							if ( options.asScene ) {
+
+								editor.execute( new SetSceneCommand( editor, scene ) );
+
+							} else {
+
+								editor.execute( new AddObjectCommand( editor, scene ) );
+
+							}
+
+							loader.dracoLoader.dispose();
+							loader.ktx2Loader.dispose();
+
+						} );
+
+					} catch ( e ) {
+
+						// Import cancelled
+
+					}
 
 				}, false );
 				reader.readAsArrayBuffer( file );
@@ -915,19 +958,39 @@ function Loader( editor ) {
 
 				{
 
-					const loader = await createGLTFLoader();
+					try {
 
-					loader.parse( file.buffer, '', function ( result ) {
+						const dialog = new GLTFImportDialog( editor.strings );
+						const options = await dialog.show();
 
-						const scene = result.scene;
+						const loader = await createGLTFLoader();
 
-						scene.animations.push( ...result.animations );
-						editor.execute( new AddObjectCommand( editor, scene ) );
+						loader.parse( file.buffer, '', function ( result ) {
 
-						loader.dracoLoader.dispose();
-						loader.ktx2Loader.dispose();
+							const scene = result.scene;
 
-					} );
+							scene.animations.push( ...result.animations );
+
+							if ( options.asScene ) {
+
+								editor.execute( new SetSceneCommand( editor, scene ) );
+
+							} else {
+
+								editor.execute( new AddObjectCommand( editor, scene ) );
+
+							}
+
+							loader.dracoLoader.dispose();
+							loader.ktx2Loader.dispose();
+
+						} );
+
+					} catch ( e ) {
+
+						// Import cancelled
+
+					}
 
 					break;
 
@@ -937,19 +1000,39 @@ function Loader( editor ) {
 
 				{
 
-					const loader = await createGLTFLoader( manager );
+					try {
 
-					loader.parse( strFromU8( file ), '', function ( result ) {
+						const dialog = new GLTFImportDialog( editor.strings );
+						const options = await dialog.show();
 
-						const scene = result.scene;
+						const loader = await createGLTFLoader( manager );
 
-						scene.animations.push( ...result.animations );
-						editor.execute( new AddObjectCommand( editor, scene ) );
+						loader.parse( strFromU8( file ), '', function ( result ) {
 
-						loader.dracoLoader.dispose();
-						loader.ktx2Loader.dispose();
+							const scene = result.scene;
 
-					} );
+							scene.animations.push( ...result.animations );
+
+							if ( options.asScene ) {
+
+								editor.execute( new SetSceneCommand( editor, scene ) );
+
+							} else {
+
+								editor.execute( new AddObjectCommand( editor, scene ) );
+
+							}
+
+							loader.dracoLoader.dispose();
+							loader.ktx2Loader.dispose();
+
+						} );
+
+					} catch ( e ) {
+
+						// Import cancelled
+
+					}
 
 					break;
 

+ 36 - 6
editor/js/Strings.js

@@ -409,7 +409,12 @@ function Strings( config ) {
 
 			'script/title/vertexShader': 'شیدر راس',
 			'script/title/fragmentShader': 'شیدر فرگمنت',
-			'script/title/programInfo': 'خواص برنامه'
+			'script/title/programInfo': 'خواص برنامه',
+
+			'dialog/gltf/title': 'Import glTF',
+			'dialog/gltf/asScene': 'Import glTF as root scene',
+			'dialog/ok': 'OK',
+			'dialog/cancel': 'Cancel'
 
 		},
 		en: {
@@ -819,7 +824,12 @@ function Strings( config ) {
 
 			'script/title/vertexShader': 'Vertex Shader',
 			'script/title/fragmentShader': 'Fragment Shader',
-			'script/title/programInfo': 'Program Properties'
+			'script/title/programInfo': 'Program Properties',
+
+			'dialog/gltf/title': 'Import glTF',
+			'dialog/gltf/asScene': 'Import glTF as root scene',
+			'dialog/ok': 'OK',
+			'dialog/cancel': 'Cancel'
 
 		},
 
@@ -1230,7 +1240,12 @@ function Strings( config ) {
 
 			'script/title/vertexShader': 'Vertex Shader',
 			'script/title/fragmentShader': 'Fragment Shader',
-			'script/title/programInfo': 'Propriétés du programme'
+			'script/title/programInfo': 'Propriétés du programme',
+
+			'dialog/gltf/title': 'Importer glTF',
+			'dialog/gltf/asScene': 'Importer glTF comme scène racine',
+			'dialog/ok': 'OK',
+			'dialog/cancel': 'Annuler'
 
 		},
 
@@ -1641,7 +1656,12 @@ function Strings( config ) {
 
 			'script/title/vertexShader': '顶点着色器',
 			'script/title/fragmentShader': '片段着色器',
-			'script/title/programInfo': '程序属性'
+			'script/title/programInfo': '程序属性',
+
+			'dialog/gltf/title': '导入 glTF',
+			'dialog/gltf/asScene': '将 glTF 导入为根场景',
+			'dialog/ok': '确定',
+			'dialog/cancel': '取消'
 
 		},
 
@@ -2052,7 +2072,12 @@ function Strings( config ) {
 
 			'script/title/vertexShader': '頂点シェーダー',
 			'script/title/fragmentShader': 'フラグメントシェーダ',
-			'script/title/programInfo': 'プログラムのプロパティ'
+			'script/title/programInfo': 'プログラムのプロパティ',
+
+			'dialog/gltf/title': 'glTFをインポート',
+			'dialog/gltf/asScene': 'glTFをルートシーンとしてインポート',
+			'dialog/ok': 'OK',
+			'dialog/cancel': 'キャンセル'
 
 		},
 
@@ -2462,7 +2487,12 @@ function Strings( config ) {
 
 			'script/title/vertexShader': '버텍스 셰이더',
 			'script/title/fragmentShader': '프래그먼트 셰이더',
-			'script/title/programInfo': '프로그램 속성'
+			'script/title/programInfo': '프로그램 속성',
+
+			'dialog/gltf/title': 'glTF 가져오기',
+			'dialog/gltf/asScene': 'glTF를 루트 씬으로 가져오기',
+			'dialog/ok': '확인',
+			'dialog/cancel': '취소'
 		}
 	};
 

+ 1 - 0
editor/sw.js

@@ -138,6 +138,7 @@ const assets = [
 	'./js/History.js',
 	'./js/Loader.js',
 	'./js/LoaderUtils.js',
+	'./js/GLTFImportDialog.js',
 	'./js/Menubar.js',
 	'./js/Menubar.File.js',
 	'./js/Menubar.Edit.js',

粤ICP备19079148号