using UnityEngine; using UnityEditor; using SplashEdit.RuntimeCode; using System.Linq; namespace SplashEdit.EditorCode { [CustomEditor(typeof(PSXSceneExporter))] public class PSXSceneExporterEditor : UnityEditor.Editor { private SerializedProperty gteScalingProp; private SerializedProperty sceneLuaProp; private SerializedProperty fogEnabledProp; private SerializedProperty fogColorProp; private SerializedProperty fogDensityProp; private SerializedProperty sceneTypeProp; private SerializedProperty cutscenesProp; private SerializedProperty loadingScreenProp; private SerializedProperty previewBVHProp; private SerializedProperty bvhDepthProp; private bool _savedFog; private Color _savedFogColor; private FogMode _savedFogMode; private float _savedFogStart; private float _savedFogEnd; private bool _previewActive = false; private bool showFog = true; private bool showCutscenes = true; private bool showDebug = false; private void OnEnable() { gteScalingProp = serializedObject.FindProperty("GTEScaling"); sceneLuaProp = serializedObject.FindProperty("SceneLuaFile"); fogEnabledProp = serializedObject.FindProperty("FogEnabled"); fogColorProp = serializedObject.FindProperty("FogColor"); fogDensityProp = serializedObject.FindProperty("FogDensity"); sceneTypeProp = serializedObject.FindProperty("SceneType"); cutscenesProp = serializedObject.FindProperty("Cutscenes"); loadingScreenProp = serializedObject.FindProperty("LoadingScreenPrefab"); previewBVHProp = serializedObject.FindProperty("PreviewBVH"); bvhDepthProp = serializedObject.FindProperty("BVHPreviewDepth"); SaveAndApplyFogPreview(); EditorApplication.update += OnEditorUpdate; } private void OnDisable() { EditorApplication.update -= OnEditorUpdate; RestoreFog(); } private void OnEditorUpdate() { if (_previewActive) ApplyFogPreview(); } public override void OnInspectorGUI() { serializedObject.Update(); var exporter = (PSXSceneExporter)target; DrawHeader(); EditorGUILayout.Space(4); DrawSceneSettings(); PSXEditorStyles.DrawSeparator(6, 6); DrawFogSection(exporter); PSXEditorStyles.DrawSeparator(6, 6); DrawCutscenesSection(); PSXEditorStyles.DrawSeparator(6, 6); DrawLoadingSection(); PSXEditorStyles.DrawSeparator(6, 6); DrawDebugSection(); PSXEditorStyles.DrawSeparator(6, 6); DrawSceneStats(); serializedObject.ApplyModifiedProperties(); } private void DrawHeader() { EditorGUILayout.BeginVertical(PSXEditorStyles.CardStyle); EditorGUILayout.LabelField("Scene Exporter", PSXEditorStyles.CardHeaderStyle); EditorGUILayout.EndVertical(); } private void DrawSceneSettings() { EditorGUILayout.PropertyField(sceneTypeProp, new GUIContent("Scene Type")); bool isInterior = (PSXSceneType)sceneTypeProp.enumValueIndex == PSXSceneType.Interior; EditorGUILayout.LabelField( isInterior ? "Room/portal occlusion culling." : "BVH frustum culling.", PSXEditorStyles.RichLabel); EditorGUILayout.Space(4); EditorGUILayout.PropertyField(gteScalingProp, new GUIContent("GTE Scaling")); EditorGUILayout.PropertyField(sceneLuaProp, new GUIContent("Scene Lua")); if (sceneLuaProp.objectReferenceValue != null) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(EditorGUI.indentLevel * 15); if (GUILayout.Button("Edit", EditorStyles.miniButtonLeft, GUILayout.Width(50))) AssetDatabase.OpenAsset(sceneLuaProp.objectReferenceValue); if (GUILayout.Button("Clear", EditorStyles.miniButtonRight, GUILayout.Width(50))) sceneLuaProp.objectReferenceValue = null; GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); } } private void DrawFogSection(PSXSceneExporter exporter) { showFog = EditorGUILayout.Foldout(showFog, "Fog", true, PSXEditorStyles.FoldoutHeader); if (!showFog) return; EditorGUI.indentLevel++; EditorGUILayout.PropertyField(fogEnabledProp, new GUIContent("Enabled")); if (fogEnabledProp.boolValue) { EditorGUILayout.PropertyField(fogColorProp, new GUIContent("Color")); EditorGUILayout.PropertyField(fogDensityProp, new GUIContent("Density")); float gteScale = exporter.GTEScaling; int density = Mathf.Clamp(exporter.FogDensity, 1, 10); float fogFarUnity = (8000f / density) * gteScale / 4096f; float fogNearUnity = fogFarUnity / 3f; EditorGUILayout.Space(2); EditorGUILayout.LabelField( $"Preview: {fogNearUnity:F1} – {fogFarUnity:F1} units | " + $"GTE: {8000f / (density * 3f):F0} – {8000f / density:F0} SZ", PSXEditorStyles.RichLabel); ApplyFogPreview(); } else { RenderSettings.fog = false; } EditorGUI.indentLevel--; } private void DrawCutscenesSection() { showCutscenes = EditorGUILayout.Foldout(showCutscenes, "Cutscenes", true, PSXEditorStyles.FoldoutHeader); if (!showCutscenes) return; EditorGUI.indentLevel++; EditorGUILayout.PropertyField(cutscenesProp, new GUIContent("Clips"), true); EditorGUI.indentLevel--; } private void DrawLoadingSection() { EditorGUILayout.PropertyField(loadingScreenProp, new GUIContent("Loading Screen Prefab")); if (loadingScreenProp.objectReferenceValue != null) { var go = loadingScreenProp.objectReferenceValue as GameObject; if (go != null && go.GetComponentInChildren() == null) { EditorGUILayout.LabelField( "Prefab has no PSXCanvas component.", PSXEditorStyles.RichLabel); } } } private void DrawDebugSection() { showDebug = EditorGUILayout.Foldout(showDebug, "Debug", true, PSXEditorStyles.FoldoutHeader); if (!showDebug) return; EditorGUI.indentLevel++; EditorGUILayout.PropertyField(previewBVHProp, new GUIContent("Preview BVH")); if (previewBVHProp.boolValue) EditorGUILayout.PropertyField(bvhDepthProp, new GUIContent("BVH Depth")); EditorGUI.indentLevel--; } private void DrawSceneStats() { var exporters = FindObjectsOfType(); int total = exporters.Length; int active = exporters.Count(e => e.IsActive); int withCollision = exporters.Count(e => e.CollisionType != PSXCollisionType.None); int staticCol = exporters.Count(e => e.StaticCollider && e.CollisionType != PSXCollisionType.None); EditorGUILayout.BeginVertical(PSXEditorStyles.CardStyle); EditorGUILayout.LabelField( $"{active}/{total} objects | {withCollision} colliders ({staticCol} static)", PSXEditorStyles.RichLabel); EditorGUILayout.EndVertical(); } private void SaveAndApplyFogPreview() { _savedFog = RenderSettings.fog; _savedFogColor = RenderSettings.fogColor; _savedFogMode = RenderSettings.fogMode; _savedFogStart = RenderSettings.fogStartDistance; _savedFogEnd = RenderSettings.fogEndDistance; _previewActive = true; ApplyFogPreview(); } private void ApplyFogPreview() { var exporter = (PSXSceneExporter)target; if (exporter == null) return; if (!exporter.FogEnabled) { RenderSettings.fog = false; return; } float gteScale = exporter.GTEScaling; int density = Mathf.Clamp(exporter.FogDensity, 1, 10); float fogFarSZ = 8000f / density; float fogNearSZ = fogFarSZ / 3f; RenderSettings.fog = true; RenderSettings.fogColor = exporter.FogColor; RenderSettings.fogMode = FogMode.Linear; RenderSettings.fogStartDistance = fogNearSZ * gteScale / 4096f; RenderSettings.fogEndDistance = fogFarSZ * gteScale / 4096f; } private void RestoreFog() { if (!_previewActive) return; _previewActive = false; RenderSettings.fog = _savedFog; RenderSettings.fogColor = _savedFogColor; RenderSettings.fogMode = _savedFogMode; RenderSettings.fogStartDistance = _savedFogStart; RenderSettings.fogEndDistance = _savedFogEnd; } } }