#nullable enable using System; using System.Collections.Generic; using System.Threading; using Cysharp.Threading.Tasks; using GLTFast; using UnityEngine; using UnityEngine.UIElements; using UVC.UI.List.Tree; using UVC.Util; namespace SHI.Modal.ISOP { /// /// glTF 모델을 비동기로 로드해 전용 카메라로 오프스크린 렌더링하고, 결과를 UIElements의 VisualElement에 출력하는 뷰입니다. /// 마우스 조작(이동/확대/회전), 항목 하이라이트, 와이어프레임 토글 등을 제공합니다. /// [UxmlElement] public partial class ISOPModelView : VisualElement { /// /// 뷰 내부에서 항목이 선택될 때 발생합니다. /// public Action? OnItemSelected; /// /// 모델 뷰가 확장 요청될 때 발생합니다. /// public Action? OnExpand; // 리소스 경로 상수 private const string UXML_PATH = "SHI/Modal/ISOP/ISOPModelView"; // Resources 폴더 기준 경로 // 설정 private Color cameraBackgroundColor = new Color(1f, 1f, 1f, 1f); private int modelLayer = 6; private bool createDefaultLight = true; // 마우스 조작 설정 private float panSpeed = 1.0f; private float rotateDegPerPixel = 0.2f; private float zoomSpeed = 5f; // 와이어프레임 private bool wireframeMode = true; private Camera? _viewCamera; private RenderTexture? _rt; private Material? _wireframeMat; private bool _wireframeApplied; // Orbit controls state private Vector3 _orbitTarget; private float _orbitDistance = 5f; private float _yaw = 0f; private float _pitch = 20f; // Drag state private bool _mmbDragging; private bool _rmbDragging; private Vector3 _mmbLastPos; private Vector3 _rmbStartPos; private float _yawStart; private float _pitchStart; private Quaternion _modelStartRot; private Vector3 _modelStartPos; private Vector3 _rmbPivot; private readonly Dictionary _idToObject = new Dictionary(); private readonly Dictionary _originalSharedByRenderer = new Dictionary(); private GameObject? _root; private int? _focusedId; // UI Element for rendering private VisualElement? _renderContainer; private Button? _expandBtn; private int itemIdSeed = 1; public ISOPModelView() { // UXML 로드 var visualTree = Resources.Load(UXML_PATH); if (visualTree != null) { visualTree.CloneTree(this); } else { Debug.LogError($"Failed to load UXML at path: {UXML_PATH}"); } // 렌더링 컨테이너 생성 _renderContainer = this.Q("render-container"); _expandBtn = this.Q