Warning, /firebird/firebird-ng/src/app/components/scene-export/scene-export.ts is written in an unsupported language. File is not indexed.
0001 import {
0002 Component,
0003 ViewChild,
0004 TemplateRef,
0005 ElementRef,
0006 ViewContainerRef,
0007 } from '@angular/core';
0008 import * as THREE from 'three';
0009
0010 import { ThreeService } from '../../services/three.service';
0011 import { MatIconButton } from "@angular/material/button";
0012 import { MatDialog, MatDialogClose, MatDialogRef } from "@angular/material/dialog";
0013 import { MatIcon } from "@angular/material/icon";
0014 import { MatTooltip } from "@angular/material/tooltip";
0015 import { MatMenuItem } from "@angular/material/menu";
0016 import { MatSlideToggle } from "@angular/material/slide-toggle";
0017 import { FormsModule } from "@angular/forms";
0018
0019 import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
0020
0021 @Component({
0022 selector: 'app-scene-export',
0023 templateUrl: './scene-export.html',
0024 styleUrls: ['./scene-export.scss'],
0025 imports: [
0026 MatIconButton,
0027 MatIcon,
0028 MatDialogClose,
0029 MatTooltip,
0030 MatMenuItem,
0031 MatSlideToggle,
0032 FormsModule,
0033 ]
0034 })
0035 export class SceneExportComponent {
0036 @ViewChild('openBtn', { read: ElementRef }) openBtn!: ElementRef;
0037 @ViewChild('dialogTemplate') dialogTemplate!: TemplateRef<any>;
0038 dialogRef: MatDialogRef<any> | null = null;
0039
0040 isExporting = false;
0041 useBinaryFormat = true; // GLB by default
0042
0043 constructor(
0044 private threeService: ThreeService,
0045 private dialog: MatDialog,
0046 private viewContainerRef: ViewContainerRef,
0047 ) {}
0048
0049 openDialog(): void {
0050 if (this.dialogRef) {
0051 this.dialogRef.close();
0052 return;
0053 }
0054
0055 const rect = this.openBtn.nativeElement.getBoundingClientRect();
0056 const dialogWidth = 280;
0057
0058 const left = Math.max(rect.right - dialogWidth, 8);
0059 const top = rect.bottom + 12;
0060
0061 this.dialogRef = this.dialog.open(this.dialogTemplate, {
0062 position: {
0063 top: `${top}px`,
0064 left: `${left}px`
0065 },
0066 hasBackdrop: false,
0067 panelClass: 'custom-position-dialog',
0068 autoFocus: false,
0069 viewContainerRef: this.viewContainerRef
0070 });
0071
0072 this.dialogRef.afterClosed().subscribe(() => {
0073 this.dialogRef = null;
0074 });
0075 }
0076
0077 exportFullScene(): void {
0078 const ext = this.useBinaryFormat ? 'glb' : 'gltf';
0079 this.exportToGLTF(this.threeService.scene, `firebird-scene.${ext}`);
0080 }
0081
0082 exportGeometryOnly(): void {
0083 const ext = this.useBinaryFormat ? 'glb' : 'gltf';
0084 this.exportToGLTF(this.threeService.sceneGeometry, `firebird-geometry.${ext}`);
0085 }
0086
0087 private exportToGLTF(object: THREE.Object3D, filename: string): void {
0088 if (this.isExporting) return;
0089
0090 this.isExporting = true;
0091 const exporter = new GLTFExporter();
0092
0093 exporter.parse(
0094 object,
0095 (result) => {
0096 this.downloadFile(result, filename);
0097 this.isExporting = false;
0098 if (this.dialogRef) {
0099 this.dialogRef.close();
0100 }
0101 },
0102 (error) => {
0103 console.error('Error exporting scene:', error);
0104 this.isExporting = false;
0105 },
0106 { binary: this.useBinaryFormat }
0107 );
0108 }
0109
0110 private downloadFile(data: ArrayBuffer | object, filename: string): void {
0111 let blob: Blob;
0112
0113 if (data instanceof ArrayBuffer) {
0114 blob = new Blob([data], { type: 'application/octet-stream' });
0115 } else {
0116 const jsonString = JSON.stringify(data);
0117 blob = new Blob([jsonString], { type: 'application/json' });
0118 }
0119
0120 const url = URL.createObjectURL(blob);
0121 const link = document.createElement('a');
0122 link.href = url;
0123 link.download = filename;
0124 link.click();
0125
0126 URL.revokeObjectURL(url);
0127 }
0128 }