Menubar.File.js 8.1 KB
Newer Older
M
Mr.doob 已提交
1 2 3 4
/**
 * @author mrdoob / http://mrdoob.com/
 */

5
Menubar.File = function ( editor ) {
M
Mr.doob 已提交
6

7 8 9 10 11 12 13 14 15 16
	var NUMBER_PRECISION = 6;

	function parseNumber( key, value ) {

		return typeof value === 'number' ? parseFloat( value.toFixed( NUMBER_PRECISION ) ) : value;

	}

	//

M
Mr.doob 已提交
17 18
	var config = editor.config;

19 20
	var container = new UI.Panel();
	container.setClass( 'menu' );
M
Mr.doob 已提交
21

22 23 24 25
	var title = new UI.Panel();
	title.setClass( 'title' );
	title.setTextContent( 'File' );
	container.add( title );
M
Mr.doob 已提交
26

27 28 29
	var options = new UI.Panel();
	options.setClass( 'options' );
	container.add( options );
M
Mr.doob 已提交
30

31
	// New
32

M
Mr.doob 已提交
33
	var option = new UI.Row();
34 35 36
	option.setClass( 'option' );
	option.setTextContent( 'New' );
	option.onClick( function () {
37

M
Mr.doob 已提交
38
		if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
39

M
Mr.doob 已提交
40
			editor.clear();
M
Mr.doob 已提交
41 42

		}
43

44 45
	} );
	options.add( option );
M
Mr.doob 已提交
46

47
	//
48

49
	options.add( new UI.HorizontalRule() );
50

51
	// Import
52

53 54 55 56
	var form = document.createElement( 'form' );
	form.style.display = 'none';
	document.body.appendChild( form );

57
	var fileInput = document.createElement( 'input' );
58
	fileInput.multiple = true;
59 60
	fileInput.type = 'file';
	fileInput.addEventListener( 'change', function ( event ) {
61

62
		editor.loader.loadFiles( fileInput.files );
63
		form.reset();
M
Mr.doob 已提交
64

65
	} );
66
	form.appendChild( fileInput );
M
Mr.doob 已提交
67

M
Mr.doob 已提交
68
	var option = new UI.Row();
69 70 71
	option.setClass( 'option' );
	option.setTextContent( 'Import' );
	option.onClick( function () {
M
Mr.doob 已提交
72

73
		fileInput.click();
M
Mr.doob 已提交
74

75 76
	} );
	options.add( option );
77

78
	//
79

80
	options.add( new UI.HorizontalRule() );
81

82
	// Export Geometry
83

M
Mr.doob 已提交
84
	var option = new UI.Row();
85 86 87
	option.setClass( 'option' );
	option.setTextContent( 'Export Geometry' );
	option.onClick( function () {
88

89
		var object = editor.selected;
90

91
		if ( object === null ) {
92

93 94
			alert( 'No object selected.' );
			return;
95

96
		}
97

98 99 100 101 102 103
		var geometry = object.geometry;

		if ( geometry === undefined ) {

			alert( 'The selected object doesn\'t have geometry.' );
			return;
104

105
		}
106

107
		var output = geometry.toJSON();
M
Mr.doob 已提交
108

M
makc 已提交
109
		try {
M
Mr.doob 已提交
110

111
			output = JSON.stringify( output, parseNumber, '\t' );
M
makc 已提交
112
			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
M
Mr.doob 已提交
113

M
Mr.doob 已提交
114
		} catch ( e ) {
M
Mr.doob 已提交
115

M
makc 已提交
116
			output = JSON.stringify( output );
M
Mr.doob 已提交
117

M
makc 已提交
118
		}
119

M
Mr.doob 已提交
120
		saveString( output, 'geometry.json' );
121

122 123 124 125
	} );
	options.add( option );

	// Export Object
M
Mr.doob 已提交
126

M
Mr.doob 已提交
127
	var option = new UI.Row();
128 129 130
	option.setClass( 'option' );
	option.setTextContent( 'Export Object' );
	option.onClick( function () {
131

132 133 134
		var object = editor.selected;

		if ( object === null ) {
135 136 137 138 139 140

			alert( 'No object selected' );
			return;

		}

141
		var output = object.toJSON();
M
Mr.doob 已提交
142

M
makc 已提交
143
		try {
M
Mr.doob 已提交
144

145
			output = JSON.stringify( output, parseNumber, '\t' );
M
makc 已提交
146
			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
M
Mr.doob 已提交
147

M
Mr.doob 已提交
148
		} catch ( e ) {
M
Mr.doob 已提交
149

M
makc 已提交
150
			output = JSON.stringify( output );
M
Mr.doob 已提交
151

M
makc 已提交
152
		}
153

M
Mr.doob 已提交
154
		saveString( output, 'model.json' );
155

156 157 158 159
	} );
	options.add( option );

	// Export Scene
160

M
Mr.doob 已提交
161
	var option = new UI.Row();
162 163 164
	option.setClass( 'option' );
	option.setTextContent( 'Export Scene' );
	option.onClick( function () {
165

166
		var output = editor.scene.toJSON();
M
Mr.doob 已提交
167

M
makc 已提交
168
		try {
M
Mr.doob 已提交
169

170
			output = JSON.stringify( output, parseNumber, '\t' );
M
makc 已提交
171
			output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
M
Mr.doob 已提交
172

M
Mr.doob 已提交
173
		} catch ( e ) {
M
Mr.doob 已提交
174

M
makc 已提交
175
			output = JSON.stringify( output );
M
Mr.doob 已提交
176

M
makc 已提交
177
		}
178

M
Mr.doob 已提交
179
		saveString( output, 'scene.json' );
180

181 182
	} );
	options.add( option );
M
Mr.doob 已提交
183

M
Mr.doob 已提交
184 185 186 187
	//

	options.add( new UI.HorizontalRule() );

M
Mr.doob 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
	// Export DAE

	var option = new UI.Row();
	option.setClass( 'option' );
	option.setTextContent( 'Export DAE' );
	option.onClick( function () {

		var exporter = new THREE.ColladaExporter();

		exporter.parse( editor.scene, function ( result ) {

			saveString( result.data, 'scene.dae' );

		} );

	} );
	options.add( option );

M
Mr.doob 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218
	// Export GLB

	var option = new UI.Row();
	option.setClass( 'option' );
	option.setTextContent( 'Export GLB' );
	option.onClick( function () {

		var exporter = new THREE.GLTFExporter();

		exporter.parse( editor.scene, function ( result ) {

			saveArrayBuffer( result, 'scene.glb' );

219
			// forceIndices: true, forcePowerOfTwoTextures: true
220
			// to allow compatibility with facebook
221
		}, { binary: true, forceIndices: true, forcePowerOfTwoTextures: true } );
M
Mr.doob 已提交
222

M
Mr.doob 已提交
223 224 225
	} );
	options.add( option );

M
Mr.doob 已提交
226
	// Export GLTF
227

M
Mr.doob 已提交
228
	var option = new UI.Row();
229
	option.setClass( 'option' );
M
Mr.doob 已提交
230
	option.setTextContent( 'Export GLTF' );
231
	option.onClick( function () {
232

M
Mr.doob 已提交
233
		var exporter = new THREE.GLTFExporter();
234

M
Mr.doob 已提交
235
		exporter.parse( editor.scene, function ( result ) {
236

M
Mr.doob 已提交
237
			saveString( JSON.stringify( result, null, 2 ), 'scene.gltf' );
238

M
Mr.doob 已提交
239
		} );
240

241

242 243 244
	} );
	options.add( option );

M
Mr.doob 已提交
245
	// Export OBJ
F
Fernando Serrano 已提交
246 247 248

	var option = new UI.Row();
	option.setClass( 'option' );
M
Mr.doob 已提交
249
	option.setTextContent( 'Export OBJ' );
F
Fernando Serrano 已提交
250 251
	option.onClick( function () {

M
Mr.doob 已提交
252
		var object = editor.selected;
F
Fernando Serrano 已提交
253

M
Mr.doob 已提交
254
		if ( object === null ) {
F
Fernando Serrano 已提交
255

M
Mr.doob 已提交
256 257
			alert( 'No object selected.' );
			return;
F
Fernando Serrano 已提交
258

M
Mr.doob 已提交
259
		}
F
Fernando Serrano 已提交
260

M
Mr.doob 已提交
261 262 263
		var exporter = new THREE.OBJExporter();

		saveString( exporter.parse( object ), 'model.obj' );
F
Fernando Serrano 已提交
264 265 266 267

	} );
	options.add( option );

268
	// Export STL (ASCII)
269

M
Mr.doob 已提交
270
	var option = new UI.Row();
271 272 273
	option.setClass( 'option' );
	option.setTextContent( 'Export STL' );
	option.onClick( function () {
M
Mr.doob 已提交
274

M
Mr.doob 已提交
275
		var exporter = new THREE.STLExporter();
276

M
Mr.doob 已提交
277
		saveString( exporter.parse( editor.scene ), 'model.stl' );
M
Mr.doob 已提交
278

279 280 281
	} );
	options.add( option );

282 283 284 285 286 287 288 289 290
	// Export STL (Binary)
	
	var option = new UI.Row();
	option.setClass( 'option' );
	option.setTextContent( 'Export STL (Binary)' );
	option.onClick( function () {

		var exporter = new THREE.STLExporter();

291
		saveArrayBuffer( exporter.parse( editor.scene, { binary: true } ), 'model-binary.stl' );
292 293 294 295

	} );
	options.add( option );
	
M
Mr.doob 已提交
296
	//
297 298

	options.add( new UI.HorizontalRule() );
M
Mr.doob 已提交
299

300
	// Publish
301

M
Mr.doob 已提交
302
	var option = new UI.Row();
303
	option.setClass( 'option' );
304
	option.setTextContent( 'Publish' );
305
	option.onClick( function () {
306

M
Mr.doob 已提交
307 308 309 310
		var zip = new JSZip();

		//

M
Mr.doob 已提交
311
		var output = editor.toJSON();
M
Mr.doob 已提交
312 313 314
		output.metadata.type = 'App';
		delete output.history;

315 316
		var vr = output.project.vr;

317
		output = JSON.stringify( output, parseNumber, '\t' );
M
Mr.doob 已提交
318 319
		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );

M
Mr.doob 已提交
320
		zip.file( 'app.json', output );
M
Mr.doob 已提交
321 322 323

		//

M
Mr.doob 已提交
324 325
		var title = config.getKey( 'project/title' );

M
Mr.doob 已提交
326 327
		var manager = new THREE.LoadingManager( function () {

M
Mr.doob 已提交
328
			save( zip.generate( { type: 'blob' } ), ( title !== '' ? title : 'untitled' ) + '.zip' );
M
Mr.doob 已提交
329 330 331

		} );

332
		var loader = new THREE.FileLoader( manager );
333 334
		loader.load( 'js/libs/app/index.html', function ( content ) {

M
Mr.doob 已提交
335 336
			content = content.replace( '<!-- title -->', title );

337 338 339 340
			var includes = [];

			if ( vr ) {

M
Mr.doob 已提交
341
				includes.push( '<script src="js/WebVR.js"></script>' );
342 343 344 345 346

			}

			content = content.replace( '<!-- includes -->', includes.join( '\n\t\t' ) );

347 348
			var editButton = '';

M
Mr.doob 已提交
349
			if ( config.getKey( 'project/editable' ) ) {
350

M
Mr.doob 已提交
351 352 353 354 355 356 357 358 359 360
				editButton = [
					'',
					'			var button = document.createElement( \'a\' );',
					'			button.href = \'https://threejs.org/editor/#file=\' + location.href.split( \'/\' ).slice( 0, - 1 ).join( \'/\' ) + \'/app.json\';',
					'			button.style.cssText = \'position: absolute; bottom: 20px; right: 20px; padding: 12px 14px; color: #fff; border: 1px solid #fff; border-radius: 4px; text-decoration: none;\';',
					'			button.target = \'_blank\';',
					'			button.textContent = \'EDIT\';',
					'			document.body.appendChild( button );',
					''
				].join( '\n' );
361 362
			}

M
Mr.doob 已提交
363
			content = content.replace( '\n\t\t\t/* edit button */\n', editButton );
364

365 366 367
			zip.file( 'index.html', content );

		} );
M
Mr.doob 已提交
368
		loader.load( 'js/libs/app.js', function ( content ) {
M
Mr.doob 已提交
369

M
Mr.doob 已提交
370
			zip.file( 'js/app.js', content );
M
Mr.doob 已提交
371 372

		} );
M
Mr.doob 已提交
373
		loader.load( '../build/three.min.js', function ( content ) {
M
Mr.doob 已提交
374

M
Mr.doob 已提交
375
			zip.file( 'js/three.min.js', content );
M
Mr.doob 已提交
376 377

		} );
378

379
		if ( vr ) {
380

M
Mr.doob 已提交
381
			loader.load( '../examples/js/vr/WebVR.js', function ( content ) {
M
Mr.doob 已提交
382 383 384 385 386

				zip.file( 'js/WebVR.js', content );

			} );

387
		}
388

389 390
	} );
	options.add( option );
391

392
	//
393

M
Mr.doob 已提交
394 395 396 397
	var link = document.createElement( 'a' );
	link.style.display = 'none';
	document.body.appendChild( link ); // Firefox workaround, see #6594

M
Mr.doob 已提交
398
	function save( blob, filename ) {
399

M
Mr.doob 已提交
400
		link.href = URL.createObjectURL( blob );
M
Mr.doob 已提交
401
		link.download = filename || 'data.json';
M
Mr.doob 已提交
402 403 404 405 406 407
		link.click();

		// URL.revokeObjectURL( url ); breaks Firefox...

	}

M
Mr.doob 已提交
408 409 410 411 412 413
	function saveArrayBuffer( buffer, filename ) {

		save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );

	}

M
Mr.doob 已提交
414
	function saveString( text, filename ) {
G
gero3 已提交
415

M
Mr.doob 已提交
416
		save( new Blob( [ text ], { type: 'text/plain' } ), filename );
417

M
Mr.doob 已提交
418
	}
419

420
	return container;
M
Mr.doob 已提交
421

422
};