import {AfterViewInit, Component, ElementRef, inject, OnDestroy, ViewChild} from '@angular/core'; import {MatMiniFabButton} from '@angular/material/button'; import {IntersectionPlaneService, PlaneOrientation} from '../../services/intersection-plane.service'; import {MatIcon} from '@angular/material/icon'; import {MatTooltip} from '@angular/material/tooltip'; import {RendererService} from '../../services/renderer.service'; import {PlayerModelService} from '../../services/player-model.service'; import {InputHandlerService} from '../../services/input-handler.service'; import {FormsModule} from '@angular/forms'; import {MatFormField, MatInput, MatLabel} from '@angular/material/input'; import {ParticleManagerService} from '../../services/particle-manager.service'; @Component({ selector: 'app-render-container', imports: [ MatIcon, MatMiniFabButton, MatTooltip, FormsModule, MatInput, MatFormField, MatLabel ], templateUrl: './render-container.component.html', styleUrl: './render-container.component.scss' }) export class RenderContainerComponent implements AfterViewInit, OnDestroy { @ViewChild('rendererContainer') rendererContainer!: ElementRef; private readonly intersectionPlaneService = inject(IntersectionPlaneService); private readonly playerModelService = inject(PlayerModelService); private readonly inputHandlerService = inject(InputHandlerService); private readonly rendererService = inject(RendererService); private readonly particleManagerService = inject(ParticleManagerService); ngAfterViewInit(): void { this.initializeScene(); this.animate(); } /** * Clean up resources when component is destroyed */ ngOnDestroy(): void { if (this.rendererService.renderer) { this.inputHandlerService.cleanup(this.rendererService.renderer.domElement); } } /** * Initialize the 3D scene and all related components */ private initializeScene(): void { this.rendererService.initializeRenderer(this.rendererContainer); this.playerModelService.loadSkinTexture('/public/img/skins/steve.png') .then(() => { // Then create the player model with the texture applied this.playerModelService.createPlayerModel(); }); this.intersectionPlaneService.createIntersectionPlane(); this.inputHandlerService.initializeInputHandlers(this.rendererService.renderer.domElement); } /** * Animation loop */ private animate(): void { requestAnimationFrame(this.animate.bind(this)); this.intersectionPlaneService.updatePlaneOrientation(this.rendererService.camera); this.rendererService.render(); } /** * Get whether the plane is locked */ public get isPlaneLocked(): boolean { return this.intersectionPlaneService.isPlaneLocked(); } public set opacity(opacity: number) { this.intersectionPlaneService.currentOpacity = opacity; } public get opacity(): number { return this.intersectionPlaneService.currentOpacity; } /** * Toggle the plane locked state */ public togglePlaneLock(): void { const newLockedState = !this.isPlaneLocked; this.intersectionPlaneService.setPlaneLocked(newLockedState); } public resetCamera(): void { this.rendererService.resetCamera(); } public toggleShowParticlesWhenIntersectingPlane(): void { this.particleManagerService.onlyIntersectingParticles = !this.particleManagerService.onlyIntersectingParticles; } /** * Get the current plane orientation */ public get currentPlaneOrientation(): PlaneOrientation { return this.intersectionPlaneService.getCurrentOrientation(); } /** * Retrieves the value indicating whether only intersecting particles are being considered. */ public get onlyIntersecting(): boolean { return this.particleManagerService.onlyIntersectingParticles; } /** * Set the plane orientation */ public setPlaneOrientation(orientation: PlaneOrientation): void { this.intersectionPlaneService.setPlaneOrientation(orientation); } /** * Get all available plane orientations */ public get planeOrientations(): typeof PlaneOrientation { return PlaneOrientation; } }