feature: Added psxsplash installer, added basic BSP implementation (non-functional)
This commit is contained in:
872
Debug.unity
Normal file
872
Debug.unity
Normal file
@@ -0,0 +1,872 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!29 &1
|
||||||
|
OcclusionCullingSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_OcclusionBakeSettings:
|
||||||
|
smallestOccluder: 5
|
||||||
|
smallestHole: 0.25
|
||||||
|
backfaceThreshold: 100
|
||||||
|
m_SceneGUID: 00000000000000000000000000000000
|
||||||
|
m_OcclusionCullingData: {fileID: 0}
|
||||||
|
--- !u!104 &2
|
||||||
|
RenderSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 10
|
||||||
|
m_Fog: 0
|
||||||
|
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||||
|
m_FogMode: 3
|
||||||
|
m_FogDensity: 0.01
|
||||||
|
m_LinearFogStart: 0
|
||||||
|
m_LinearFogEnd: 300
|
||||||
|
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||||
|
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||||
|
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||||
|
m_AmbientIntensity: 1
|
||||||
|
m_AmbientMode: 0
|
||||||
|
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||||
|
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_HaloStrength: 0.5
|
||||||
|
m_FlareStrength: 1
|
||||||
|
m_FlareFadeSpeed: 3
|
||||||
|
m_HaloTexture: {fileID: 0}
|
||||||
|
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
m_DefaultReflectionMode: 0
|
||||||
|
m_DefaultReflectionResolution: 128
|
||||||
|
m_ReflectionBounces: 1
|
||||||
|
m_ReflectionIntensity: 1
|
||||||
|
m_CustomReflection: {fileID: 0}
|
||||||
|
m_Sun: {fileID: 0}
|
||||||
|
m_UseRadianceAmbientProbe: 0
|
||||||
|
--- !u!157 &3
|
||||||
|
LightmapSettings:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 13
|
||||||
|
m_BakeOnSceneLoad: 0
|
||||||
|
m_GISettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_BounceScale: 1
|
||||||
|
m_IndirectOutputScale: 1
|
||||||
|
m_AlbedoBoost: 1
|
||||||
|
m_EnvironmentLightingMode: 0
|
||||||
|
m_EnableBakedLightmaps: 1
|
||||||
|
m_EnableRealtimeLightmaps: 0
|
||||||
|
m_LightmapEditorSettings:
|
||||||
|
serializedVersion: 12
|
||||||
|
m_Resolution: 2
|
||||||
|
m_BakeResolution: 40
|
||||||
|
m_AtlasSize: 1024
|
||||||
|
m_AO: 0
|
||||||
|
m_AOMaxDistance: 1
|
||||||
|
m_CompAOExponent: 1
|
||||||
|
m_CompAOExponentDirect: 0
|
||||||
|
m_ExtractAmbientOcclusion: 0
|
||||||
|
m_Padding: 2
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_LightmapsBakeMode: 1
|
||||||
|
m_TextureCompression: 1
|
||||||
|
m_ReflectionCompression: 2
|
||||||
|
m_MixedBakeMode: 2
|
||||||
|
m_BakeBackend: 1
|
||||||
|
m_PVRSampling: 1
|
||||||
|
m_PVRDirectSampleCount: 32
|
||||||
|
m_PVRSampleCount: 512
|
||||||
|
m_PVRBounces: 2
|
||||||
|
m_PVREnvironmentSampleCount: 256
|
||||||
|
m_PVREnvironmentReferencePointCount: 2048
|
||||||
|
m_PVRFilteringMode: 1
|
||||||
|
m_PVRDenoiserTypeDirect: 1
|
||||||
|
m_PVRDenoiserTypeIndirect: 1
|
||||||
|
m_PVRDenoiserTypeAO: 1
|
||||||
|
m_PVRFilterTypeDirect: 0
|
||||||
|
m_PVRFilterTypeIndirect: 0
|
||||||
|
m_PVRFilterTypeAO: 0
|
||||||
|
m_PVREnvironmentMIS: 1
|
||||||
|
m_PVRCulling: 1
|
||||||
|
m_PVRFilteringGaussRadiusDirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusIndirect: 1
|
||||||
|
m_PVRFilteringGaussRadiusAO: 1
|
||||||
|
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||||
|
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||||
|
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||||
|
m_ExportTrainingData: 0
|
||||||
|
m_TrainingDataDestination: TrainingData
|
||||||
|
m_LightProbeSampleCountMultiplier: 4
|
||||||
|
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_LightingSettings: {fileID: 0}
|
||||||
|
--- !u!196 &4
|
||||||
|
NavMeshSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_BuildSettings:
|
||||||
|
serializedVersion: 3
|
||||||
|
agentTypeID: 0
|
||||||
|
agentRadius: 0.5
|
||||||
|
agentHeight: 2
|
||||||
|
agentSlope: 45
|
||||||
|
agentClimb: 0.4
|
||||||
|
ledgeDropHeight: 0
|
||||||
|
maxJumpAcrossDistance: 0
|
||||||
|
minRegionArea: 2
|
||||||
|
manualCellSize: 0
|
||||||
|
cellSize: 0.16666667
|
||||||
|
manualTileSize: 0
|
||||||
|
tileSize: 256
|
||||||
|
buildHeightMesh: 0
|
||||||
|
maxJobWorkers: 0
|
||||||
|
preserveTilesOutsideBounds: 0
|
||||||
|
debug:
|
||||||
|
m_Flags: 0
|
||||||
|
m_NavMeshData: {fileID: 0}
|
||||||
|
--- !u!1 &283344192
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 283344197}
|
||||||
|
- component: {fileID: 283344196}
|
||||||
|
- component: {fileID: 283344195}
|
||||||
|
- component: {fileID: 283344194}
|
||||||
|
- component: {fileID: 283344193}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: f (1)
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &283344193
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 283344192}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: bea0f31a495202580ac77bd9fd6e99f2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
IsActive: 1
|
||||||
|
bitDepth: 8
|
||||||
|
luaFile: {fileID: 0}
|
||||||
|
previewNormals: 0
|
||||||
|
normalPreviewLength: 0.5
|
||||||
|
--- !u!65 &283344194
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 283344192}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!23 &283344195
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 283344192}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!33 &283344196
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 283344192}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!4 &283344197
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 283344192}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0.1479161, y: 0.37224695, z: -0.33835596, w: 0.85150945}
|
||||||
|
m_LocalPosition: {x: -30.19757, y: 0, z: 8.341}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 47.226, z: -43.342}
|
||||||
|
--- !u!1 &1293128684
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1293128689}
|
||||||
|
- component: {fileID: 1293128688}
|
||||||
|
- component: {fileID: 1293128687}
|
||||||
|
- component: {fileID: 1293128686}
|
||||||
|
- component: {fileID: 1293128685}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: f
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1293128685
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1293128684}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: bea0f31a495202580ac77bd9fd6e99f2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
IsActive: 1
|
||||||
|
bitDepth: 8
|
||||||
|
luaFile: {fileID: 0}
|
||||||
|
previewNormals: 0
|
||||||
|
normalPreviewLength: 0.5
|
||||||
|
--- !u!65 &1293128686
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1293128684}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!23 &1293128687
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1293128684}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!33 &1293128688
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1293128684}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!4 &1293128689
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1293128684}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0.13355339, y: 0.35044792, z: -0.3301185, w: 0.8662399}
|
||||||
|
m_LocalPosition: {x: -30.19757, y: 0, z: 10.84006}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 44.053, z: -41.723}
|
||||||
|
--- !u!1 &1331845601
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1331845603}
|
||||||
|
- component: {fileID: 1331845602}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Exp
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1331845602
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1331845601}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: ab5195ad94fd173cfb6d48ee06eaf245, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
GTEScaling: 100
|
||||||
|
SceneLuaFile: {fileID: 0}
|
||||||
|
BSPPreviewDepth: 2
|
||||||
|
--- !u!4 &1331845603
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1331845601}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: -31.5414, y: 0, z: 10.89769}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1337453585
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1337453587}
|
||||||
|
- component: {fileID: 1337453586}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Directional Light
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!108 &1337453586
|
||||||
|
Light:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1337453585}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 11
|
||||||
|
m_Type: 1
|
||||||
|
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||||
|
m_Intensity: 1
|
||||||
|
m_Range: 10
|
||||||
|
m_SpotAngle: 30
|
||||||
|
m_InnerSpotAngle: 21.80208
|
||||||
|
m_CookieSize: 10
|
||||||
|
m_Shadows:
|
||||||
|
m_Type: 2
|
||||||
|
m_Resolution: -1
|
||||||
|
m_CustomResolution: -1
|
||||||
|
m_Strength: 1
|
||||||
|
m_Bias: 0.05
|
||||||
|
m_NormalBias: 0.4
|
||||||
|
m_NearPlane: 0.2
|
||||||
|
m_CullingMatrixOverride:
|
||||||
|
e00: 1
|
||||||
|
e01: 0
|
||||||
|
e02: 0
|
||||||
|
e03: 0
|
||||||
|
e10: 0
|
||||||
|
e11: 1
|
||||||
|
e12: 0
|
||||||
|
e13: 0
|
||||||
|
e20: 0
|
||||||
|
e21: 0
|
||||||
|
e22: 1
|
||||||
|
e23: 0
|
||||||
|
e30: 0
|
||||||
|
e31: 0
|
||||||
|
e32: 0
|
||||||
|
e33: 1
|
||||||
|
m_UseCullingMatrixOverride: 0
|
||||||
|
m_Cookie: {fileID: 0}
|
||||||
|
m_DrawHalo: 0
|
||||||
|
m_Flare: {fileID: 0}
|
||||||
|
m_RenderMode: 0
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_Lightmapping: 4
|
||||||
|
m_LightShadowCasterMode: 0
|
||||||
|
m_AreaSize: {x: 1, y: 1}
|
||||||
|
m_BounceIntensity: 1
|
||||||
|
m_ColorTemperature: 6570
|
||||||
|
m_UseColorTemperature: 0
|
||||||
|
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_UseBoundingSphereOverride: 0
|
||||||
|
m_UseViewFrustumForShadowCasterCull: 1
|
||||||
|
m_ForceVisible: 0
|
||||||
|
m_ShadowRadius: 0
|
||||||
|
m_ShadowAngle: 0
|
||||||
|
m_LightUnit: 1
|
||||||
|
m_LuxAtDistance: 1
|
||||||
|
m_EnableSpotReflector: 1
|
||||||
|
--- !u!4 &1337453587
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1337453585}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||||
|
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||||
|
--- !u!1 &1388445967
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1388445970}
|
||||||
|
- component: {fileID: 1388445969}
|
||||||
|
- component: {fileID: 1388445968}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: Main Camera
|
||||||
|
m_TagString: MainCamera
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!81 &1388445968
|
||||||
|
AudioListener:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1388445967}
|
||||||
|
m_Enabled: 1
|
||||||
|
--- !u!20 &1388445969
|
||||||
|
Camera:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1388445967}
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 2
|
||||||
|
m_ClearFlags: 1
|
||||||
|
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||||
|
m_projectionMatrixMode: 1
|
||||||
|
m_GateFitMode: 2
|
||||||
|
m_FOVAxisMode: 0
|
||||||
|
m_Iso: 200
|
||||||
|
m_ShutterSpeed: 0.005
|
||||||
|
m_Aperture: 16
|
||||||
|
m_FocusDistance: 10
|
||||||
|
m_FocalLength: 50
|
||||||
|
m_BladeCount: 5
|
||||||
|
m_Curvature: {x: 2, y: 11}
|
||||||
|
m_BarrelClipping: 0.25
|
||||||
|
m_Anamorphism: 0
|
||||||
|
m_SensorSize: {x: 36, y: 24}
|
||||||
|
m_LensShift: {x: 0, y: 0}
|
||||||
|
m_NormalizedViewPortRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
near clip plane: 0.3
|
||||||
|
far clip plane: 1000
|
||||||
|
field of view: 60
|
||||||
|
orthographic: 0
|
||||||
|
orthographic size: 5
|
||||||
|
m_Depth: -1
|
||||||
|
m_CullingMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 4294967295
|
||||||
|
m_RenderingPath: -1
|
||||||
|
m_TargetTexture: {fileID: 0}
|
||||||
|
m_TargetDisplay: 0
|
||||||
|
m_TargetEye: 3
|
||||||
|
m_HDR: 1
|
||||||
|
m_AllowMSAA: 1
|
||||||
|
m_AllowDynamicResolution: 0
|
||||||
|
m_ForceIntoRT: 0
|
||||||
|
m_OcclusionCulling: 1
|
||||||
|
m_StereoConvergence: 10
|
||||||
|
m_StereoSeparation: 0.022
|
||||||
|
--- !u!4 &1388445970
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1388445967}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!1 &1392840323
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1392840328}
|
||||||
|
- component: {fileID: 1392840327}
|
||||||
|
- component: {fileID: 1392840326}
|
||||||
|
- component: {fileID: 1392840325}
|
||||||
|
- component: {fileID: 1392840324}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: f (2)
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1392840324
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1392840323}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: bea0f31a495202580ac77bd9fd6e99f2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
IsActive: 1
|
||||||
|
bitDepth: 8
|
||||||
|
luaFile: {fileID: 0}
|
||||||
|
previewNormals: 0
|
||||||
|
normalPreviewLength: 0.5
|
||||||
|
--- !u!65 &1392840325
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1392840323}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!23 &1392840326
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1392840323}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!33 &1392840327
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1392840323}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!4 &1392840328
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1392840323}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0.409346, y: -0.7736037, z: 0.22623056, w: 0.42754278}
|
||||||
|
m_LocalPosition: {x: -30.19757, y: 2.041, z: 10.84006}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: -122.144, z: 55.77}
|
||||||
|
--- !u!1 &1513869424
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 1513869429}
|
||||||
|
- component: {fileID: 1513869428}
|
||||||
|
- component: {fileID: 1513869427}
|
||||||
|
- component: {fileID: 1513869426}
|
||||||
|
- component: {fileID: 1513869425}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: f (3)
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &1513869425
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1513869424}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: bea0f31a495202580ac77bd9fd6e99f2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
IsActive: 1
|
||||||
|
bitDepth: 8
|
||||||
|
luaFile: {fileID: 0}
|
||||||
|
previewNormals: 0
|
||||||
|
normalPreviewLength: 0.5
|
||||||
|
--- !u!65 &1513869426
|
||||||
|
BoxCollider:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1513869424}
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_IncludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_ExcludeLayers:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 0
|
||||||
|
m_LayerOverridePriority: 0
|
||||||
|
m_IsTrigger: 0
|
||||||
|
m_ProvidesContacts: 0
|
||||||
|
m_Enabled: 1
|
||||||
|
serializedVersion: 3
|
||||||
|
m_Size: {x: 1, y: 1, z: 1}
|
||||||
|
m_Center: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!23 &1513869427
|
||||||
|
MeshRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1513869424}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_CastShadows: 1
|
||||||
|
m_ReceiveShadows: 1
|
||||||
|
m_DynamicOccludee: 1
|
||||||
|
m_StaticShadowCaster: 0
|
||||||
|
m_MotionVectors: 1
|
||||||
|
m_LightProbeUsage: 1
|
||||||
|
m_ReflectionProbeUsage: 1
|
||||||
|
m_RayTracingMode: 2
|
||||||
|
m_RayTraceProcedural: 0
|
||||||
|
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||||
|
m_RayTracingAccelStructBuildFlags: 1
|
||||||
|
m_SmallMeshCulling: 1
|
||||||
|
m_RenderingLayerMask: 1
|
||||||
|
m_RendererPriority: 0
|
||||||
|
m_Materials:
|
||||||
|
- {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
|
||||||
|
m_StaticBatchInfo:
|
||||||
|
firstSubMesh: 0
|
||||||
|
subMeshCount: 0
|
||||||
|
m_StaticBatchRoot: {fileID: 0}
|
||||||
|
m_ProbeAnchor: {fileID: 0}
|
||||||
|
m_LightProbeVolumeOverride: {fileID: 0}
|
||||||
|
m_ScaleInLightmap: 1
|
||||||
|
m_ReceiveGI: 1
|
||||||
|
m_PreserveUVs: 0
|
||||||
|
m_IgnoreNormalsForChartDetection: 0
|
||||||
|
m_ImportantGI: 0
|
||||||
|
m_StitchLightmapSeams: 1
|
||||||
|
m_SelectedEditorRenderState: 3
|
||||||
|
m_MinimumChartSize: 4
|
||||||
|
m_AutoUVMaxDistance: 0.5
|
||||||
|
m_AutoUVMaxAngle: 89
|
||||||
|
m_LightmapParameters: {fileID: 0}
|
||||||
|
m_SortingLayerID: 0
|
||||||
|
m_SortingLayer: 0
|
||||||
|
m_SortingOrder: 0
|
||||||
|
m_AdditionalVertexStreams: {fileID: 0}
|
||||||
|
--- !u!33 &1513869428
|
||||||
|
MeshFilter:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1513869424}
|
||||||
|
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
|
--- !u!4 &1513869429
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1513869424}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: -0.09615398, y: 0.2551484, z: 0.3392829, w: 0.9003004}
|
||||||
|
m_LocalPosition: {x: -27.156, y: 0, z: 9.065}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: -20.259, y: 24.845, z: 36.791}
|
||||||
|
--- !u!1660057539 &9223372036854775807
|
||||||
|
SceneRoots:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_Roots:
|
||||||
|
- {fileID: 1388445970}
|
||||||
|
- {fileID: 1337453587}
|
||||||
|
- {fileID: 1293128689}
|
||||||
|
- {fileID: 283344197}
|
||||||
|
- {fileID: 1392840328}
|
||||||
|
- {fileID: 1513869429}
|
||||||
|
- {fileID: 1331845603}
|
||||||
7
Debug.unity.meta
Normal file
7
Debug.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 14e1ffa687155c145bfed30e28f26bc1
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -2,214 +2,521 @@ using UnityEngine;
|
|||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using SplashEdit.RuntimeCode;
|
using SplashEdit.RuntimeCode;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public class InstallerWindow : EditorWindow
|
|
||||||
|
namespace SplashEdit.EditorCode
|
||||||
{
|
{
|
||||||
// Cached status for MIPS toolchain binaries.
|
public class InstallerWindow : EditorWindow
|
||||||
private Dictionary<string, bool> mipsToolStatus = new Dictionary<string, bool>();
|
|
||||||
|
|
||||||
// Cached status for optional tools.
|
|
||||||
private bool makeInstalled;
|
|
||||||
private bool gdbInstalled;
|
|
||||||
private string pcsxReduxPath;
|
|
||||||
|
|
||||||
private bool isInstalling = false;
|
|
||||||
|
|
||||||
[MenuItem("PSX/Toolchain & Build Tools Installer")]
|
|
||||||
public static void ShowWindow()
|
|
||||||
{
|
{
|
||||||
InstallerWindow window = GetWindow<InstallerWindow>("Toolchain Installer");
|
// Cached status for MIPS toolchain binaries.
|
||||||
window.RefreshToolStatus();
|
private Dictionary<string, bool> mipsToolStatus = new Dictionary<string, bool>();
|
||||||
window.pcsxReduxPath = DataStorage.LoadData().PCSXReduxPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
// Cached status for optional tools.
|
||||||
/// Refresh the cached statuses for all tools.
|
private bool makeInstalled;
|
||||||
/// </summary>
|
private bool gdbInstalled;
|
||||||
private void RefreshToolStatus()
|
private string pcsxReduxPath;
|
||||||
{
|
|
||||||
mipsToolStatus.Clear();
|
// PSXSplash related variables
|
||||||
foreach (var tool in ToolchainChecker.GetRequiredTools())
|
private bool psxsplashInstalled = false;
|
||||||
|
private bool psxsplashInstalling = false;
|
||||||
|
private bool psxsplashFetching = false;
|
||||||
|
private string selectedVersion = "main";
|
||||||
|
private Dictionary<string, string> availableBranches = new Dictionary<string, string>();
|
||||||
|
private List<string> availableReleases = new List<string>();
|
||||||
|
private bool showBranches = true;
|
||||||
|
private bool showReleases = false;
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private Vector2 versionScrollPosition;
|
||||||
|
|
||||||
|
private bool isInstalling = false;
|
||||||
|
|
||||||
|
[MenuItem("PSX/Toolchain & Build Tools Installer")]
|
||||||
|
public static void ShowWindow()
|
||||||
{
|
{
|
||||||
mipsToolStatus[tool] = ToolchainChecker.IsToolAvailable(tool);
|
InstallerWindow window = GetWindow<InstallerWindow>("Toolchain Installer");
|
||||||
|
window.RefreshToolStatus();
|
||||||
|
window.pcsxReduxPath = DataStorage.LoadData().PCSXReduxPath;
|
||||||
|
window.CheckPSXSplashInstallation();
|
||||||
}
|
}
|
||||||
|
|
||||||
makeInstalled = ToolchainChecker.IsToolAvailable("make");
|
/// <summary>
|
||||||
gdbInstalled = ToolchainChecker.IsToolAvailable("gdb-multiarch");
|
/// Refresh the cached statuses for all tools.
|
||||||
}
|
/// </summary>
|
||||||
|
private void RefreshToolStatus()
|
||||||
private void OnGUI()
|
|
||||||
{
|
|
||||||
GUILayout.Label("Toolchain & Build Tools Installer", EditorStyles.boldLabel);
|
|
||||||
GUILayout.Space(5);
|
|
||||||
|
|
||||||
if (GUILayout.Button("Refresh Status"))
|
|
||||||
{
|
{
|
||||||
RefreshToolStatus();
|
mipsToolStatus.Clear();
|
||||||
}
|
foreach (var tool in ToolchainChecker.GetRequiredTools())
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
|
||||||
DrawToolchainColumn();
|
|
||||||
DrawAdditionalToolsColumn();
|
|
||||||
EditorGUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawToolchainColumn()
|
|
||||||
{
|
|
||||||
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(position.width / 2 - 10));
|
|
||||||
GUILayout.Label("MIPS Toolchain", EditorStyles.boldLabel);
|
|
||||||
GUILayout.Space(5);
|
|
||||||
|
|
||||||
// Display cached status for each required MIPS tool.
|
|
||||||
foreach (var kvp in mipsToolStatus)
|
|
||||||
{
|
|
||||||
GUI.color = kvp.Value ? Color.green : Color.red;
|
|
||||||
GUILayout.Label($"{kvp.Key}: {(kvp.Value ? "Found" : "Missing")}");
|
|
||||||
}
|
|
||||||
GUI.color = Color.white;
|
|
||||||
GUILayout.Space(5);
|
|
||||||
|
|
||||||
if (GUILayout.Button("Install MIPS Toolchain"))
|
|
||||||
{
|
|
||||||
if (!isInstalling)
|
|
||||||
InstallMipsToolchainAsync();
|
|
||||||
}
|
|
||||||
EditorGUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawAdditionalToolsColumn()
|
|
||||||
{
|
|
||||||
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(position.width / 2 - 10));
|
|
||||||
GUILayout.Label("Optional Tools", EditorStyles.boldLabel);
|
|
||||||
GUILayout.Space(5);
|
|
||||||
|
|
||||||
// GNU Make status (required).
|
|
||||||
GUI.color = makeInstalled ? Color.green : Color.red;
|
|
||||||
GUILayout.Label($"GNU Make: {(makeInstalled ? "Found" : "Missing")} (Required)");
|
|
||||||
GUI.color = Color.white;
|
|
||||||
GUILayout.Space(5);
|
|
||||||
if (GUILayout.Button("Install GNU Make"))
|
|
||||||
{
|
|
||||||
if (!isInstalling)
|
|
||||||
InstallMakeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
// GDB status (optional).
|
|
||||||
GUI.color = gdbInstalled ? Color.green : Color.red;
|
|
||||||
GUILayout.Label($"GDB: {(gdbInstalled ? "Found" : "Missing")} (Optional)");
|
|
||||||
GUI.color = Color.white;
|
|
||||||
GUILayout.Space(5);
|
|
||||||
if (GUILayout.Button("Install GDB"))
|
|
||||||
{
|
|
||||||
if (!isInstalling)
|
|
||||||
InstallGDBAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.Space(10);
|
|
||||||
|
|
||||||
// PCSX-Redux (manual install)
|
|
||||||
GUI.color = string.IsNullOrEmpty(pcsxReduxPath) ? Color.red : Color.green;
|
|
||||||
GUILayout.Label($"PCSX-Redux: {(string.IsNullOrEmpty(pcsxReduxPath) ? "Not Configured" : "Configured")} (Optional)");
|
|
||||||
GUI.color = Color.white;
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal();
|
|
||||||
if (GUILayout.Button("Browse for PCSX-Redux"))
|
|
||||||
{
|
|
||||||
string selectedPath = EditorUtility.OpenFilePanel("Select PCSX-Redux Executable", "", "");
|
|
||||||
if (!string.IsNullOrEmpty(selectedPath))
|
|
||||||
{
|
{
|
||||||
pcsxReduxPath = selectedPath;
|
mipsToolStatus[tool] = ToolchainChecker.IsToolAvailable(tool);
|
||||||
PSXData data = DataStorage.LoadData();
|
}
|
||||||
data.PCSXReduxPath = pcsxReduxPath;
|
|
||||||
DataStorage.StoreData(data);
|
makeInstalled = ToolchainChecker.IsToolAvailable("make");
|
||||||
|
gdbInstalled = ToolchainChecker.IsToolAvailable("gdb-multiarch");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckPSXSplashInstallation()
|
||||||
|
{
|
||||||
|
psxsplashInstalled = PSXSplashInstaller.IsInstalled();
|
||||||
|
|
||||||
|
if (psxsplashInstalled)
|
||||||
|
{
|
||||||
|
FetchPSXSplashVersions();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
availableBranches = new Dictionary<string, string>();
|
||||||
|
availableReleases = new List<string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(pcsxReduxPath))
|
|
||||||
|
private async void FetchPSXSplashVersions()
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("Clear", GUILayout.Width(60)))
|
if (psxsplashFetching) return;
|
||||||
|
|
||||||
|
psxsplashFetching = true;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
pcsxReduxPath = "";
|
// Fetch latest from remote
|
||||||
PSXData data = DataStorage.LoadData();
|
await PSXSplashInstaller.FetchLatestAsync();
|
||||||
data.PCSXReduxPath = pcsxReduxPath;
|
|
||||||
DataStorage.StoreData(data);
|
// Get all available versions
|
||||||
|
var branchesTask = PSXSplashInstaller.GetBranchesWithLatestCommitsAsync();
|
||||||
|
var releasesTask = PSXSplashInstaller.GetReleasesAsync();
|
||||||
|
|
||||||
|
await Task.WhenAll(branchesTask, releasesTask);
|
||||||
|
|
||||||
|
availableBranches = branchesTask.Result;
|
||||||
|
availableReleases = releasesTask.Result;
|
||||||
|
|
||||||
|
// If no branches were found, add main as default
|
||||||
|
if (!availableBranches.Any())
|
||||||
|
{
|
||||||
|
availableBranches["main"] = "latest";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the first branch by default
|
||||||
|
if (availableBranches.Any() && string.IsNullOrEmpty(selectedVersion))
|
||||||
|
{
|
||||||
|
selectedVersion = availableBranches.Keys.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
Repaint();
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Failed to fetch PSXSplash versions: {e.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
psxsplashFetching = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
EditorGUILayout.EndVertical();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void InstallMipsToolchainAsync()
|
private void OnGUI()
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
isInstalling = true;
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||||
EditorUtility.DisplayProgressBar("Installing MIPS Toolchain",
|
|
||||||
"Please wait while the MIPS toolchain is being installed...", 0f);
|
GUILayout.Label("Toolchain & Build Tools Installer", EditorStyles.boldLabel);
|
||||||
bool success = await ToolchainInstaller.InstallToolchain();
|
GUILayout.Space(5);
|
||||||
EditorUtility.ClearProgressBar();
|
|
||||||
if (success)
|
if (GUILayout.Button("Refresh Status"))
|
||||||
{
|
{
|
||||||
EditorUtility.DisplayDialog("Installation Complete", "MIPS toolchain installed successfully.", "OK");
|
RefreshToolStatus();
|
||||||
|
CheckPSXSplashInstallation();
|
||||||
}
|
}
|
||||||
RefreshToolStatus(); // Update cached statuses after installation
|
GUILayout.Space(10);
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
EditorUtility.ClearProgressBar();
|
|
||||||
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
isInstalling = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void InstallMakeAsync()
|
EditorGUILayout.BeginHorizontal();
|
||||||
{
|
DrawToolchainColumn();
|
||||||
try
|
DrawAdditionalToolsColumn();
|
||||||
{
|
DrawPSXSplashColumn();
|
||||||
isInstalling = true;
|
EditorGUILayout.EndHorizontal();
|
||||||
EditorUtility.DisplayProgressBar("Installing GNU Make",
|
|
||||||
"Please wait while GNU Make is being installed...", 0f);
|
|
||||||
await ToolchainInstaller.InstallMake();
|
|
||||||
EditorUtility.ClearProgressBar();
|
|
||||||
EditorUtility.DisplayDialog("Installation Complete", "GNU Make installed successfully.", "OK");
|
|
||||||
RefreshToolStatus();
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
EditorUtility.ClearProgressBar();
|
|
||||||
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
isInstalling = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void InstallGDBAsync()
|
EditorGUILayout.EndScrollView();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
isInstalling = true;
|
|
||||||
EditorUtility.DisplayProgressBar("Installing GDB",
|
|
||||||
"Please wait while GDB is being installed...", 0f);
|
|
||||||
await ToolchainInstaller.InstallGDB();
|
|
||||||
EditorUtility.ClearProgressBar();
|
|
||||||
EditorUtility.DisplayDialog("Installation Complete", "GDB installed successfully.", "OK");
|
|
||||||
RefreshToolStatus();
|
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
|
||||||
|
private void DrawToolchainColumn()
|
||||||
{
|
{
|
||||||
EditorUtility.ClearProgressBar();
|
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(position.width / 3 - 10));
|
||||||
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
GUILayout.Label("MIPS Toolchain", EditorStyles.boldLabel);
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
// Display cached status for each required MIPS tool.
|
||||||
|
foreach (var kvp in mipsToolStatus)
|
||||||
|
{
|
||||||
|
GUI.color = kvp.Value ? Color.green : Color.red;
|
||||||
|
GUILayout.Label($"{kvp.Key}: {(kvp.Value ? "Found" : "Missing")}");
|
||||||
|
}
|
||||||
|
GUI.color = Color.white;
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
if (GUILayout.Button("Install MIPS Toolchain"))
|
||||||
|
{
|
||||||
|
if (!isInstalling)
|
||||||
|
InstallMipsToolchainAsync();
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
|
private void DrawAdditionalToolsColumn()
|
||||||
{
|
{
|
||||||
isInstalling = false;
|
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(position.width / 3 - 10));
|
||||||
|
GUILayout.Label("Optional Tools", EditorStyles.boldLabel);
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
// GNU Make status (required).
|
||||||
|
GUI.color = makeInstalled ? Color.green : Color.red;
|
||||||
|
GUILayout.Label($"GNU Make: {(makeInstalled ? "Found" : "Missing")} (Required)");
|
||||||
|
GUI.color = Color.white;
|
||||||
|
GUILayout.Space(5);
|
||||||
|
if (GUILayout.Button("Install GNU Make"))
|
||||||
|
{
|
||||||
|
if (!isInstalling)
|
||||||
|
InstallMakeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
// GDB status (optional).
|
||||||
|
GUI.color = gdbInstalled ? Color.green : Color.red;
|
||||||
|
GUILayout.Label($"GDB: {(gdbInstalled ? "Found" : "Missing")} (Optional)");
|
||||||
|
GUI.color = Color.white;
|
||||||
|
GUILayout.Space(5);
|
||||||
|
if (GUILayout.Button("Install GDB"))
|
||||||
|
{
|
||||||
|
if (!isInstalling)
|
||||||
|
InstallGDBAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
// PCSX-Redux (manual install)
|
||||||
|
GUI.color = string.IsNullOrEmpty(pcsxReduxPath) ? Color.red : Color.green;
|
||||||
|
GUILayout.Label($"PCSX-Redux: {(string.IsNullOrEmpty(pcsxReduxPath) ? "Not Configured" : "Configured")} (Optional)");
|
||||||
|
GUI.color = Color.white;
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal();
|
||||||
|
if (GUILayout.Button("Browse for PCSX-Redux"))
|
||||||
|
{
|
||||||
|
string selectedPath = EditorUtility.OpenFilePanel("Select PCSX-Redux Executable", "", "");
|
||||||
|
if (!string.IsNullOrEmpty(selectedPath))
|
||||||
|
{
|
||||||
|
pcsxReduxPath = selectedPath;
|
||||||
|
PSXData data = DataStorage.LoadData();
|
||||||
|
data.PCSXReduxPath = pcsxReduxPath;
|
||||||
|
DataStorage.StoreData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(pcsxReduxPath))
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("Clear", GUILayout.Width(60)))
|
||||||
|
{
|
||||||
|
pcsxReduxPath = "";
|
||||||
|
PSXData data = DataStorage.LoadData();
|
||||||
|
data.PCSXReduxPath = pcsxReduxPath;
|
||||||
|
DataStorage.StoreData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPSXSplashColumn()
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginVertical("box", GUILayout.MaxWidth(position.width / 3 - 10));
|
||||||
|
GUILayout.Label("PSXSplash", EditorStyles.boldLabel);
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
// PSXSplash status
|
||||||
|
GUI.color = psxsplashInstalled ? Color.green : Color.red;
|
||||||
|
GUILayout.Label($"PSXSplash: {(psxsplashInstalled ? "Installed" : "Not Installed")}");
|
||||||
|
GUI.color = Color.white;
|
||||||
|
|
||||||
|
if (psxsplashFetching)
|
||||||
|
{
|
||||||
|
GUILayout.Label("Fetching versions...");
|
||||||
|
}
|
||||||
|
else if (!psxsplashInstalled)
|
||||||
|
{
|
||||||
|
GUILayout.Space(5);
|
||||||
|
EditorGUILayout.HelpBox("Git is required to install PSXSplash. Make sure it's installed and available in your PATH.", MessageType.Info);
|
||||||
|
|
||||||
|
// Show version selection even before installation
|
||||||
|
DrawVersionSelection();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Install PSXSplash") && !psxsplashInstalling)
|
||||||
|
{
|
||||||
|
InstallPSXSplashAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
// Current version
|
||||||
|
EditorGUILayout.LabelField($"Current Version: {selectedVersion}", EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
// Version selection
|
||||||
|
DrawVersionSelection();
|
||||||
|
|
||||||
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
// Refresh and update buttons
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
if (GUILayout.Button("Refresh Versions"))
|
||||||
|
{
|
||||||
|
FetchPSXSplashVersions();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Update PSXSplash"))
|
||||||
|
{
|
||||||
|
UpdatePSXSplashAsync();
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawVersionSelection()
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("Available Versions:", EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
versionScrollPosition = EditorGUILayout.BeginScrollView(versionScrollPosition, GUILayout.Height(200));
|
||||||
|
|
||||||
|
// Branches (with latest commits)
|
||||||
|
showBranches = EditorGUILayout.Foldout(showBranches, $"Branches ({availableBranches.Count})");
|
||||||
|
if (showBranches && availableBranches.Any())
|
||||||
|
{
|
||||||
|
foreach (var branch in availableBranches)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
bool isSelected = selectedVersion == branch.Key;
|
||||||
|
if (GUILayout.Toggle(isSelected, "", GUILayout.Width(20)) && !isSelected)
|
||||||
|
{
|
||||||
|
selectedVersion = branch.Key;
|
||||||
|
if (psxsplashInstalled)
|
||||||
|
{
|
||||||
|
CheckoutPSXSplashVersionAsync(branch.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUILayout.Label($"{branch.Key} (Latest: {branch.Value})", EditorStyles.label);
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (showBranches)
|
||||||
|
{
|
||||||
|
GUILayout.Label("No branches available");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releases
|
||||||
|
showReleases = EditorGUILayout.Foldout(showReleases, $"Releases ({availableReleases.Count})");
|
||||||
|
if (showReleases && availableReleases.Any())
|
||||||
|
{
|
||||||
|
foreach (var release in availableReleases)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
bool isSelected = selectedVersion == release;
|
||||||
|
if (GUILayout.Toggle(isSelected, "", GUILayout.Width(20)) && !isSelected)
|
||||||
|
{
|
||||||
|
selectedVersion = release;
|
||||||
|
if (psxsplashInstalled)
|
||||||
|
{
|
||||||
|
CheckoutPSXSplashVersionAsync(release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUILayout.Label(release, EditorStyles.label);
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (showReleases)
|
||||||
|
{
|
||||||
|
GUILayout.Label("No releases available");
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void InstallPSXSplashAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
psxsplashInstalling = true;
|
||||||
|
EditorUtility.DisplayProgressBar("Installing PSXSplash", "Cloning repository...", 0.3f);
|
||||||
|
|
||||||
|
bool success = await PSXSplashInstaller.Install();
|
||||||
|
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Installation Complete", "PSXSplash installed successfully.", "OK");
|
||||||
|
CheckPSXSplashInstallation();
|
||||||
|
|
||||||
|
// Checkout the selected version after installation
|
||||||
|
if (!string.IsNullOrEmpty(selectedVersion))
|
||||||
|
{
|
||||||
|
await CheckoutPSXSplashVersionAsync(selectedVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Installation Failed",
|
||||||
|
"Failed to install PSXSplash. Make sure Git is installed and available in your PATH.", "OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
psxsplashInstalling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> CheckoutPSXSplashVersionAsync(string version)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
psxsplashInstalling = true;
|
||||||
|
EditorUtility.DisplayProgressBar("Checking Out Version", $"Switching to {version}...", 0.3f);
|
||||||
|
|
||||||
|
bool success = await PSXSplashInstaller.CheckoutVersionAsync(version);
|
||||||
|
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Checkout Complete", $"Switched to {version} successfully.", "OK");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Checkout Failed",
|
||||||
|
$"Failed to switch to {version}.", "OK");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Checkout Failed", $"Error: {ex.Message}", "OK");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
psxsplashInstalling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void UpdatePSXSplashAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
psxsplashInstalling = true;
|
||||||
|
EditorUtility.DisplayProgressBar("Updating PSXSplash", "Pulling latest changes...", 0.3f);
|
||||||
|
|
||||||
|
// Pull the latest changes
|
||||||
|
bool success = await PSXSplashInstaller.CheckoutVersionAsync(selectedVersion);
|
||||||
|
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Update Complete", "PSXSplash updated successfully.", "OK");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Update Failed",
|
||||||
|
"Failed to update PSXSplash.", "OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Update Failed", $"Error: {ex.Message}", "OK");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
psxsplashInstalling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void InstallMipsToolchainAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isInstalling = true;
|
||||||
|
EditorUtility.DisplayProgressBar("Installing MIPS Toolchain",
|
||||||
|
"Please wait while the MIPS toolchain is being installed...", 0f);
|
||||||
|
bool success = await ToolchainInstaller.InstallToolchain();
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
EditorUtility.DisplayDialog("Installation Complete", "MIPS toolchain installed successfully.", "OK");
|
||||||
|
}
|
||||||
|
RefreshToolStatus(); // Update cached statuses after installation
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isInstalling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void InstallMakeAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isInstalling = true;
|
||||||
|
EditorUtility.DisplayProgressBar("Installing GNU Make",
|
||||||
|
"Please wait while GNU Make is being installed...", 0f);
|
||||||
|
await ToolchainInstaller.InstallMake();
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Installation Complete", "GNU Make installed successfully.", "OK");
|
||||||
|
RefreshToolStatus();
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isInstalling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void InstallGDBAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isInstalling = true;
|
||||||
|
EditorUtility.DisplayProgressBar("Installing GDB",
|
||||||
|
"Please wait while GDB is being installed...", 0f);
|
||||||
|
await ToolchainInstaller.InstallGDB();
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Installation Complete", "GDB installed successfully.", "OK");
|
||||||
|
RefreshToolStatus();
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
EditorUtility.DisplayDialog("Installation Failed", $"Error: {ex.Message}", "OK");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
isInstalling = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
203
Editor/PSXSplashInstaller.cs
Normal file
203
Editor/PSXSplashInstaller.cs
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SplashEdit.EditorCode
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class PSXSplashInstaller
|
||||||
|
{
|
||||||
|
public static readonly string RepoUrl = "https://github.com/psxsplash/psxsplash.git";
|
||||||
|
public static readonly string InstallPath = "Assets/psxsplash";
|
||||||
|
public static readonly string FullInstallPath;
|
||||||
|
|
||||||
|
static PSXSplashInstaller()
|
||||||
|
{
|
||||||
|
FullInstallPath = Path.Combine(Application.dataPath, "psxsplash");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInstalled()
|
||||||
|
{
|
||||||
|
return Directory.Exists(FullInstallPath) &&
|
||||||
|
Directory.EnumerateFileSystemEntries(FullInstallPath).Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<bool> Install()
|
||||||
|
{
|
||||||
|
if (IsInstalled()) return true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Create the parent directory if it doesn't exist
|
||||||
|
Directory.CreateDirectory(Application.dataPath);
|
||||||
|
|
||||||
|
// Clone the repository
|
||||||
|
var result = await RunGitCommandAsync($"clone --recursive {RepoUrl} \"{FullInstallPath}\"", Application.dataPath);
|
||||||
|
return !result.Contains("error");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Failed to install PSXSplash: {e.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Dictionary<string, string>> GetBranchesWithLatestCommitsAsync()
|
||||||
|
{
|
||||||
|
if (!IsInstalled()) return new Dictionary<string, string>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Fetch all branches and tags
|
||||||
|
await RunGitCommandAsync("fetch --all", FullInstallPath);
|
||||||
|
|
||||||
|
// Get all remote branches
|
||||||
|
var branchesOutput = await RunGitCommandAsync("branch -r", FullInstallPath);
|
||||||
|
var branches = branchesOutput.Split('\n')
|
||||||
|
.Where(b => !string.IsNullOrEmpty(b.Trim()))
|
||||||
|
.Select(b => b.Trim().Replace("origin/", ""))
|
||||||
|
.Where(b => !b.Contains("HEAD"))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var branchesWithCommits = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
// Get the latest commit for each branch
|
||||||
|
foreach (var branch in branches)
|
||||||
|
{
|
||||||
|
var commitOutput = await RunGitCommandAsync($"log origin/{branch} -1 --pretty=format:%h", FullInstallPath);
|
||||||
|
if (!string.IsNullOrEmpty(commitOutput))
|
||||||
|
{
|
||||||
|
branchesWithCommits[branch] = commitOutput.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return branchesWithCommits;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Failed to get branches: {e.Message}");
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<List<string>> GetReleasesAsync()
|
||||||
|
{
|
||||||
|
if (!IsInstalled()) return new List<string>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await RunGitCommandAsync("fetch --tags", FullInstallPath);
|
||||||
|
var output = await RunGitCommandAsync("tag -l", FullInstallPath);
|
||||||
|
|
||||||
|
return output.Split('\n')
|
||||||
|
.Where(t => !string.IsNullOrEmpty(t.Trim()))
|
||||||
|
.Select(t => t.Trim())
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Failed to get releases: {e.Message}");
|
||||||
|
return new List<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<bool> CheckoutVersionAsync(string version)
|
||||||
|
{
|
||||||
|
if (!IsInstalled()) return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// If it's a branch name, checkout the branch
|
||||||
|
// If it's a commit hash, checkout the commit
|
||||||
|
var result = await RunGitCommandAsync($"checkout {version}", FullInstallPath);
|
||||||
|
var result2 = await RunGitCommandAsync("submodule update --init --recursive", FullInstallPath);
|
||||||
|
|
||||||
|
return !result.Contains("error") && !result2.Contains("error");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Failed to checkout version: {e.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<bool> FetchLatestAsync()
|
||||||
|
{
|
||||||
|
if (!IsInstalled()) return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await RunGitCommandAsync("fetch --all", FullInstallPath);
|
||||||
|
return !result.Contains("error");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Failed to fetch latest: {e.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<string> RunGitCommandAsync(string arguments, string workingDirectory)
|
||||||
|
{
|
||||||
|
var processInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "git",
|
||||||
|
Arguments = arguments,
|
||||||
|
WorkingDirectory = workingDirectory,
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
CreateNoWindow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var process = new Process())
|
||||||
|
{
|
||||||
|
process.StartInfo = processInfo;
|
||||||
|
var outputBuilder = new System.Text.StringBuilder();
|
||||||
|
var errorBuilder = new System.Text.StringBuilder();
|
||||||
|
|
||||||
|
process.OutputDataReceived += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(e.Data))
|
||||||
|
outputBuilder.AppendLine(e.Data);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.ErrorDataReceived += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(e.Data))
|
||||||
|
errorBuilder.AppendLine(e.Data);
|
||||||
|
};
|
||||||
|
|
||||||
|
process.Start();
|
||||||
|
process.BeginOutputReadLine();
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
|
||||||
|
// Wait for exit with timeout
|
||||||
|
var timeout = TimeSpan.FromSeconds(30);
|
||||||
|
if (await Task.Run(() => process.WaitForExit((int)timeout.TotalMilliseconds)))
|
||||||
|
{
|
||||||
|
process.WaitForExit(); // Ensure all output is processed
|
||||||
|
|
||||||
|
string output = outputBuilder.ToString();
|
||||||
|
string error = errorBuilder.ToString();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(error))
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogError($"Git error: {error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
process.Kill();
|
||||||
|
throw new TimeoutException("Git command timed out");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/PSXSplashInstaller.cs.meta
Normal file
2
Editor/PSXSplashInstaller.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 72d1da27a16f0794cb1ad49c00799e74
|
||||||
39
Editor/SerialConnection.cs
Normal file
39
Editor/SerialConnection.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System.IO.Ports;
|
||||||
|
|
||||||
|
|
||||||
|
namespace SplashEdit.EditorCode
|
||||||
|
{
|
||||||
|
public class SerialConnection
|
||||||
|
{
|
||||||
|
private static SerialPort serialPort;
|
||||||
|
|
||||||
|
public SerialConnection(string portName, int baudRate)
|
||||||
|
{
|
||||||
|
serialPort = new SerialPort(portName, baudRate);
|
||||||
|
serialPort.ReadTimeout = 50;
|
||||||
|
serialPort.WriteTimeout = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Open()
|
||||||
|
{ serialPort.Open(); }
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{ serialPort.Close(); }
|
||||||
|
|
||||||
|
public int ReadByte()
|
||||||
|
{ return serialPort.ReadByte(); }
|
||||||
|
|
||||||
|
public int ReadChar()
|
||||||
|
{ return serialPort.ReadChar(); }
|
||||||
|
|
||||||
|
public void Write(string text)
|
||||||
|
{ serialPort.Write(text); }
|
||||||
|
|
||||||
|
public void Write(char[] buffer, int offset, int count)
|
||||||
|
{ serialPort.Write(buffer, offset, count); }
|
||||||
|
|
||||||
|
public void Write(byte[] buffer, int offset, int count)
|
||||||
|
{ serialPort.Write(buffer, offset, count); }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/SerialConnection.cs.meta
Normal file
2
Editor/SerialConnection.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 714bd2374b7a9a14686078e5eb431795
|
||||||
22
Editor/UniromConnection.cs
Normal file
22
Editor/UniromConnection.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
namespace SplashEdit.EditorCode
|
||||||
|
{
|
||||||
|
public class UniromConnection
|
||||||
|
{
|
||||||
|
|
||||||
|
private SerialConnection serialConnection;
|
||||||
|
|
||||||
|
public UniromConnection(int baudRate, string portName)
|
||||||
|
{
|
||||||
|
serialConnection = new SerialConnection(portName, baudRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
serialConnection.Open();
|
||||||
|
serialConnection.Write("REST");
|
||||||
|
serialConnection.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/UniromConnection.cs.meta
Normal file
2
Editor/UniromConnection.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d8fbc734f42ab9d42a843b6718127da7
|
||||||
145
Editor/UniromConnectionWindow.cs
Normal file
145
Editor/UniromConnectionWindow.cs
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Collections;
|
||||||
|
using SplashEdit.RuntimeCode;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SplashEdit.EditorCode
|
||||||
|
{
|
||||||
|
public class PSXConnectionConfigWindow : EditorWindow
|
||||||
|
{
|
||||||
|
|
||||||
|
public PSXConnectionType connectionType = PSXConnectionType.REAL_HARDWARE;
|
||||||
|
|
||||||
|
// REAL HARDWARE (Unirom) SETTINGS
|
||||||
|
private string[] portNames;
|
||||||
|
private int selectedPortIndex = 1;
|
||||||
|
private int[] baudRates = { 9600, 115200 };
|
||||||
|
private int selectedBaudIndex = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private string statusMessage = "";
|
||||||
|
private MessageType statusType;
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
|
||||||
|
[MenuItem("PSX/Console or Emulator Connection")]
|
||||||
|
public static void ShowWindow()
|
||||||
|
{
|
||||||
|
GetWindow<PSXConnectionConfigWindow>("Serial Config");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
RefreshPorts();
|
||||||
|
LoadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshPorts()
|
||||||
|
{
|
||||||
|
portNames = SerialPort.GetPortNames();
|
||||||
|
if (portNames.Length == 0)
|
||||||
|
{
|
||||||
|
portNames = new[] { "No ports available" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPosition))
|
||||||
|
{
|
||||||
|
scrollPosition = scrollView.scrollPosition;
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField("Pick connection type", EditorStyles.boldLabel);
|
||||||
|
connectionType = (PSXConnectionType)EditorGUILayout.EnumPopup("Connection Type", connectionType);
|
||||||
|
|
||||||
|
if (connectionType == PSXConnectionType.REAL_HARDWARE)
|
||||||
|
{
|
||||||
|
// Port selection
|
||||||
|
EditorGUILayout.LabelField("Select COM Port", EditorStyles.boldLabel);
|
||||||
|
selectedPortIndex = EditorGUILayout.Popup("Available Ports", selectedPortIndex, portNames);
|
||||||
|
|
||||||
|
// Baud rate selection
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
EditorGUILayout.LabelField("Select Baud Rate", EditorStyles.boldLabel);
|
||||||
|
selectedBaudIndex = EditorGUILayout.Popup("Baud Rate", selectedBaudIndex, new[] { "9600", "115200" });
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
using (new EditorGUILayout.HorizontalScope())
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("Refresh Ports"))
|
||||||
|
{
|
||||||
|
RefreshPorts();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Test Connection"))
|
||||||
|
{
|
||||||
|
TestConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Save settings"))
|
||||||
|
{
|
||||||
|
SaveSettings();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status message
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
if (!string.IsNullOrEmpty(statusMessage))
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox(statusMessage, statusType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSettings()
|
||||||
|
{
|
||||||
|
PSXData _psxData = DataStorage.LoadData();
|
||||||
|
if (_psxData != null)
|
||||||
|
{
|
||||||
|
connectionType = _psxData.ConnectionType;
|
||||||
|
selectedBaudIndex = System.Array.IndexOf(baudRates, _psxData.BaudRate);
|
||||||
|
if (selectedBaudIndex == -1) selectedBaudIndex = 0;
|
||||||
|
|
||||||
|
RefreshPorts();
|
||||||
|
selectedPortIndex = System.Array.IndexOf(portNames, _psxData.PortName);
|
||||||
|
if (selectedPortIndex == -1) selectedPortIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TestConnection()
|
||||||
|
{
|
||||||
|
if (portNames.Length == 0 || portNames[0] == "No ports available")
|
||||||
|
{
|
||||||
|
statusMessage = "No serial ports available";
|
||||||
|
statusType = MessageType.Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniromConnection connection = new UniromConnection(baudRates[selectedBaudIndex], portNames[selectedPortIndex]);
|
||||||
|
connection.Reset();
|
||||||
|
|
||||||
|
statusMessage = "Connection tested. If your PlayStation reset, it worked!";
|
||||||
|
statusType = MessageType.Info;
|
||||||
|
Repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveSettings()
|
||||||
|
{
|
||||||
|
PSXData _psxData = DataStorage.LoadData();
|
||||||
|
_psxData.ConnectionType = connectionType;
|
||||||
|
_psxData.BaudRate = baudRates[selectedBaudIndex];
|
||||||
|
_psxData.PortName = portNames[selectedPortIndex];
|
||||||
|
DataStorage.StoreData(_psxData);
|
||||||
|
statusMessage = "Settings saved";
|
||||||
|
statusType = MessageType.Info;
|
||||||
|
Repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/UniromConnectionWindow.cs.meta
Normal file
2
Editor/UniromConnectionWindow.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ade0bf0fd69f449458c5b43e0f48ddff
|
||||||
845
Runtime/BSP.cs
Normal file
845
Runtime/BSP.cs
Normal file
@@ -0,0 +1,845 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using SplashEdit.RuntimeCode;
|
||||||
|
|
||||||
|
public class BSP
|
||||||
|
{
|
||||||
|
private List<PSXObjectExporter> _objects;
|
||||||
|
private Node root;
|
||||||
|
private const float EPSILON = 1e-6f;
|
||||||
|
private const int MAX_TRIANGLES_PER_LEAF = 256;
|
||||||
|
private const int MAX_TREE_DEPTH = 50;
|
||||||
|
private const int CANDIDATE_PLANE_COUNT = 15;
|
||||||
|
|
||||||
|
// Statistics
|
||||||
|
private int totalTrianglesProcessed;
|
||||||
|
private int totalSplits;
|
||||||
|
private int treeDepth;
|
||||||
|
private Stopwatch buildTimer;
|
||||||
|
|
||||||
|
public bool verboseLogging = false;
|
||||||
|
|
||||||
|
// Store the triangle that was used for the split plane for debugging
|
||||||
|
private Dictionary<Node, Triangle> splitPlaneTriangles = new Dictionary<Node, Triangle>();
|
||||||
|
|
||||||
|
private struct Triangle
|
||||||
|
{
|
||||||
|
public Vector3 v0;
|
||||||
|
public Vector3 v1;
|
||||||
|
public Vector3 v2;
|
||||||
|
public Vector3 n0;
|
||||||
|
public Vector3 n1;
|
||||||
|
public Vector3 n2;
|
||||||
|
public Vector2 uv0;
|
||||||
|
public Vector2 uv1;
|
||||||
|
public Vector2 uv2;
|
||||||
|
public Plane plane;
|
||||||
|
public Bounds bounds;
|
||||||
|
public PSXObjectExporter sourceExporter;
|
||||||
|
public int materialIndex; // Store material index instead of submesh index
|
||||||
|
|
||||||
|
public Triangle(Vector3 a, Vector3 b, Vector3 c, Vector3 na, Vector3 nb, Vector3 nc,
|
||||||
|
Vector2 uva, Vector2 uvb, Vector2 uvc, PSXObjectExporter exporter, int matIndex)
|
||||||
|
{
|
||||||
|
v0 = a;
|
||||||
|
v1 = b;
|
||||||
|
v2 = c;
|
||||||
|
n0 = na;
|
||||||
|
n1 = nb;
|
||||||
|
n2 = nc;
|
||||||
|
uv0 = uva;
|
||||||
|
uv1 = uvb;
|
||||||
|
uv2 = uvc;
|
||||||
|
sourceExporter = exporter;
|
||||||
|
materialIndex = matIndex;
|
||||||
|
|
||||||
|
// Calculate plane
|
||||||
|
Vector3 edge1 = v1 - v0;
|
||||||
|
Vector3 edge2 = v2 - v0;
|
||||||
|
Vector3 normal = Vector3.Cross(edge1, edge2);
|
||||||
|
|
||||||
|
if (normal.sqrMagnitude < 1e-4f)
|
||||||
|
{
|
||||||
|
plane = new Plane(Vector3.up, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
normal.Normalize();
|
||||||
|
plane = new Plane(normal, v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate bounds
|
||||||
|
bounds = new Bounds(v0, Vector3.zero);
|
||||||
|
bounds.Encapsulate(v1);
|
||||||
|
bounds.Encapsulate(v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Transform(Matrix4x4 matrix)
|
||||||
|
{
|
||||||
|
v0 = matrix.MultiplyPoint3x4(v0);
|
||||||
|
v1 = matrix.MultiplyPoint3x4(v1);
|
||||||
|
v2 = matrix.MultiplyPoint3x4(v2);
|
||||||
|
|
||||||
|
// Transform normals (using inverse transpose for correct scaling)
|
||||||
|
Matrix4x4 invTranspose = matrix.inverse.transpose;
|
||||||
|
n0 = invTranspose.MultiplyVector(n0).normalized;
|
||||||
|
n1 = invTranspose.MultiplyVector(n1).normalized;
|
||||||
|
n2 = invTranspose.MultiplyVector(n2).normalized;
|
||||||
|
|
||||||
|
// Recalculate plane and bounds after transformation
|
||||||
|
Vector3 edge1 = v1 - v0;
|
||||||
|
Vector3 edge2 = v2 - v0;
|
||||||
|
Vector3 normal = Vector3.Cross(edge1, edge2);
|
||||||
|
|
||||||
|
if (normal.sqrMagnitude < 1e-4f)
|
||||||
|
{
|
||||||
|
plane = new Plane(Vector3.up, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
normal.Normalize();
|
||||||
|
plane = new Plane(normal, v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bounds = new Bounds(v0, Vector3.zero);
|
||||||
|
bounds.Encapsulate(v1);
|
||||||
|
bounds.Encapsulate(v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Node
|
||||||
|
{
|
||||||
|
public Plane plane;
|
||||||
|
public Node front;
|
||||||
|
public Node back;
|
||||||
|
public List<Triangle> triangles;
|
||||||
|
public bool isLeaf = false;
|
||||||
|
public Bounds bounds;
|
||||||
|
public int depth;
|
||||||
|
public int triangleSourceIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BSP(List<PSXObjectExporter> objects)
|
||||||
|
{
|
||||||
|
_objects = objects;
|
||||||
|
buildTimer = new Stopwatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Build()
|
||||||
|
{
|
||||||
|
buildTimer.Start();
|
||||||
|
|
||||||
|
List<Triangle> triangles = ExtractTrianglesFromMeshes();
|
||||||
|
totalTrianglesProcessed = triangles.Count;
|
||||||
|
|
||||||
|
if (verboseLogging)
|
||||||
|
UnityEngine.Debug.Log($"Starting BSP build with {totalTrianglesProcessed} triangles");
|
||||||
|
|
||||||
|
if (triangles.Count == 0)
|
||||||
|
{
|
||||||
|
root = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate overall bounds
|
||||||
|
Bounds overallBounds = CalculateBounds(triangles);
|
||||||
|
|
||||||
|
// Build tree recursively with depth tracking
|
||||||
|
root = BuildNode(triangles, overallBounds, 0);
|
||||||
|
|
||||||
|
// Create modified meshes for all exporters
|
||||||
|
CreateModifiedMeshes();
|
||||||
|
|
||||||
|
buildTimer.Stop();
|
||||||
|
|
||||||
|
if (verboseLogging)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.Log($"BSP build completed in {buildTimer.Elapsed.TotalMilliseconds}ms");
|
||||||
|
UnityEngine.Debug.Log($"Total splits: {totalSplits}, Max depth: {treeDepth}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Triangle> ExtractTrianglesFromMeshes()
|
||||||
|
{
|
||||||
|
List<Triangle> triangles = new List<Triangle>();
|
||||||
|
|
||||||
|
foreach (var meshObj in _objects)
|
||||||
|
{
|
||||||
|
if (!meshObj.IsActive) continue;
|
||||||
|
|
||||||
|
MeshFilter mf = meshObj.GetComponent<MeshFilter>();
|
||||||
|
Renderer renderer = meshObj.GetComponent<Renderer>();
|
||||||
|
if (mf == null || mf.sharedMesh == null || renderer == null) continue;
|
||||||
|
|
||||||
|
Mesh mesh = mf.sharedMesh;
|
||||||
|
Vector3[] vertices = mesh.vertices;
|
||||||
|
Vector3[] normals = mesh.normals.Length > 0 ? mesh.normals : new Vector3[vertices.Length];
|
||||||
|
Vector2[] uvs = mesh.uv.Length > 0 ? mesh.uv : new Vector2[vertices.Length];
|
||||||
|
Matrix4x4 matrix = meshObj.transform.localToWorldMatrix;
|
||||||
|
|
||||||
|
// Handle case where normals are missing
|
||||||
|
if (mesh.normals.Length == 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < normals.Length; i++)
|
||||||
|
{
|
||||||
|
normals[i] = Vector3.up;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle case where UVs are missing
|
||||||
|
if (mesh.uv.Length == 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < uvs.Length; i++)
|
||||||
|
{
|
||||||
|
uvs[i] = Vector2.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each submesh and track material index
|
||||||
|
for (int submesh = 0; submesh < mesh.subMeshCount; submesh++)
|
||||||
|
{
|
||||||
|
int materialIndex = Mathf.Min(submesh, renderer.sharedMaterials.Length - 1);
|
||||||
|
int[] indices = mesh.GetTriangles(submesh);
|
||||||
|
|
||||||
|
for (int i = 0; i < indices.Length; i += 3)
|
||||||
|
{
|
||||||
|
int idx0 = indices[i];
|
||||||
|
int idx1 = indices[i + 1];
|
||||||
|
int idx2 = indices[i + 2];
|
||||||
|
|
||||||
|
Vector3 v0 = vertices[idx0];
|
||||||
|
Vector3 v1 = vertices[idx1];
|
||||||
|
Vector3 v2 = vertices[idx2];
|
||||||
|
|
||||||
|
// Skip degenerate triangles
|
||||||
|
if (Vector3.Cross(v1 - v0, v2 - v0).sqrMagnitude < 1e-4f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Vector3 n0 = normals[idx0];
|
||||||
|
Vector3 n1 = normals[idx1];
|
||||||
|
Vector3 n2 = normals[idx2];
|
||||||
|
|
||||||
|
Vector2 uv0 = uvs[idx0];
|
||||||
|
Vector2 uv1 = uvs[idx1];
|
||||||
|
Vector2 uv2 = uvs[idx2];
|
||||||
|
|
||||||
|
Triangle tri = new Triangle(v0, v1, v2, n0, n1, n2, uv0, uv1, uv2, meshObj, materialIndex);
|
||||||
|
tri.Transform(matrix);
|
||||||
|
triangles.Add(tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return triangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node BuildNode(List<Triangle> triangles, Bounds bounds, int depth)
|
||||||
|
{
|
||||||
|
if (triangles == null || triangles.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Node node = new Node
|
||||||
|
{
|
||||||
|
triangles = new List<Triangle>(),
|
||||||
|
bounds = bounds,
|
||||||
|
depth = depth
|
||||||
|
};
|
||||||
|
|
||||||
|
treeDepth = Mathf.Max(treeDepth, depth);
|
||||||
|
|
||||||
|
// Create leaf node if conditions are met
|
||||||
|
if (triangles.Count <= MAX_TRIANGLES_PER_LEAF || depth >= MAX_TREE_DEPTH)
|
||||||
|
{
|
||||||
|
node.isLeaf = true;
|
||||||
|
node.triangles = triangles;
|
||||||
|
|
||||||
|
if (verboseLogging && depth >= MAX_TREE_DEPTH)
|
||||||
|
UnityEngine.Debug.LogWarning($"Max tree depth reached at depth {depth} with {triangles.Count} triangles");
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the best splitting plane using multiple strategies
|
||||||
|
Triangle? splitTriangle = null;
|
||||||
|
if (!SelectBestSplittingPlane(triangles, bounds, out node.plane, out splitTriangle))
|
||||||
|
{
|
||||||
|
// Fallback: create leaf if no good split found
|
||||||
|
node.isLeaf = true;
|
||||||
|
node.triangles = triangles;
|
||||||
|
|
||||||
|
if (verboseLogging)
|
||||||
|
UnityEngine.Debug.Log($"Created leaf node with {triangles.Count} triangles (no good split found)");
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the triangle that provided the split plane for debugging
|
||||||
|
if (splitTriangle.HasValue)
|
||||||
|
{
|
||||||
|
splitPlaneTriangles[node] = splitTriangle.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Triangle> frontList = new List<Triangle>();
|
||||||
|
List<Triangle> backList = new List<Triangle>();
|
||||||
|
List<Triangle> coplanarList = new List<Triangle>();
|
||||||
|
|
||||||
|
// Classify all triangles
|
||||||
|
foreach (var tri in triangles)
|
||||||
|
{
|
||||||
|
ClassifyTriangle(tri, node.plane, coplanarList, frontList, backList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle cases where splitting doesn't provide benefit
|
||||||
|
if (frontList.Count == 0 || backList.Count == 0)
|
||||||
|
{
|
||||||
|
// If split doesn't separate geometry, create a leaf
|
||||||
|
node.isLeaf = true;
|
||||||
|
node.triangles = triangles;
|
||||||
|
|
||||||
|
if (verboseLogging)
|
||||||
|
UnityEngine.Debug.Log($"Created leaf node with {triangles.Count} triangles (ineffective split)");
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribute coplanar triangles to the side with fewer triangles
|
||||||
|
if (coplanarList.Count > 0)
|
||||||
|
{
|
||||||
|
if (frontList.Count <= backList.Count)
|
||||||
|
{
|
||||||
|
frontList.AddRange(coplanarList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backList.AddRange(coplanarList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verboseLogging)
|
||||||
|
UnityEngine.Debug.Log($"Node at depth {depth}: {triangles.Count} triangles -> {frontList.Count} front, {backList.Count} back");
|
||||||
|
|
||||||
|
// Calculate bounds for children
|
||||||
|
Bounds frontBounds = CalculateBounds(frontList);
|
||||||
|
Bounds backBounds = CalculateBounds(backList);
|
||||||
|
|
||||||
|
// Recursively build child nodes
|
||||||
|
node.front = BuildNode(frontList, frontBounds, depth + 1);
|
||||||
|
node.back = BuildNode(backList, backBounds, depth + 1);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SelectBestSplittingPlane(List<Triangle> triangles, Bounds bounds, out Plane bestPlane, out Triangle? splitTriangle)
|
||||||
|
{
|
||||||
|
bestPlane = new Plane();
|
||||||
|
splitTriangle = null;
|
||||||
|
int bestScore = int.MaxValue;
|
||||||
|
bool foundValidPlane = false;
|
||||||
|
|
||||||
|
// Strategy 1: Try planes from triangle centroids
|
||||||
|
int candidatesToTry = Mathf.Min(CANDIDATE_PLANE_COUNT, triangles.Count);
|
||||||
|
for (int i = 0; i < candidatesToTry; i++)
|
||||||
|
{
|
||||||
|
Triangle tri = triangles[i];
|
||||||
|
Plane candidate = tri.plane;
|
||||||
|
|
||||||
|
int score = EvaluateSplitPlane(triangles, candidate);
|
||||||
|
if (score < bestScore && score >= 0)
|
||||||
|
{
|
||||||
|
bestScore = score;
|
||||||
|
bestPlane = candidate;
|
||||||
|
splitTriangle = tri;
|
||||||
|
foundValidPlane = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 2: Try axis-aligned planes through bounds center
|
||||||
|
if (!foundValidPlane || bestScore > triangles.Count * 3)
|
||||||
|
{
|
||||||
|
Vector3[] axes = { Vector3.right, Vector3.up, Vector3.forward };
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
Plane candidate = new Plane(axes[i], bounds.center);
|
||||||
|
int score = EvaluateSplitPlane(triangles, candidate);
|
||||||
|
if (score < bestScore && score >= 0)
|
||||||
|
{
|
||||||
|
bestScore = score;
|
||||||
|
bestPlane = candidate;
|
||||||
|
splitTriangle = null;
|
||||||
|
foundValidPlane = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 3: Try planes based on bounds extents
|
||||||
|
if (!foundValidPlane)
|
||||||
|
{
|
||||||
|
Vector3 extents = bounds.extents;
|
||||||
|
if (extents.x >= extents.y && extents.x >= extents.z)
|
||||||
|
bestPlane = new Plane(Vector3.right, bounds.center);
|
||||||
|
else if (extents.y >= extents.x && extents.y >= extents.z)
|
||||||
|
bestPlane = new Plane(Vector3.up, bounds.center);
|
||||||
|
else
|
||||||
|
bestPlane = new Plane(Vector3.forward, bounds.center);
|
||||||
|
|
||||||
|
splitTriangle = null;
|
||||||
|
foundValidPlane = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundValidPlane;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int EvaluateSplitPlane(List<Triangle> triangles, Plane plane)
|
||||||
|
{
|
||||||
|
int frontCount = 0;
|
||||||
|
int backCount = 0;
|
||||||
|
int splitCount = 0;
|
||||||
|
int coplanarCount = 0;
|
||||||
|
|
||||||
|
foreach (var tri in triangles)
|
||||||
|
{
|
||||||
|
float d0 = plane.GetDistanceToPoint(tri.v0);
|
||||||
|
float d1 = plane.GetDistanceToPoint(tri.v1);
|
||||||
|
float d2 = plane.GetDistanceToPoint(tri.v2);
|
||||||
|
|
||||||
|
// Check for NaN/infinity
|
||||||
|
if (float.IsNaN(d0) || float.IsNaN(d1) || float.IsNaN(d2) ||
|
||||||
|
float.IsInfinity(d0) || float.IsInfinity(d1) || float.IsInfinity(d2))
|
||||||
|
{
|
||||||
|
return int.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool front = d0 > EPSILON || d1 > EPSILON || d2 > EPSILON;
|
||||||
|
bool back = d0 < -EPSILON || d1 < -EPSILON || d2 < -EPSILON;
|
||||||
|
|
||||||
|
if (front && back)
|
||||||
|
splitCount++;
|
||||||
|
else if (front)
|
||||||
|
frontCount++;
|
||||||
|
else if (back)
|
||||||
|
backCount++;
|
||||||
|
else
|
||||||
|
coplanarCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject planes that would cause too many splits or imbalanced trees
|
||||||
|
if (splitCount > triangles.Count / 2)
|
||||||
|
return int.MaxValue;
|
||||||
|
|
||||||
|
// Score based on balance and split count
|
||||||
|
return Mathf.Abs(frontCount - backCount) + splitCount * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClassifyTriangle(Triangle tri, Plane plane, List<Triangle> coplanar, List<Triangle> front, List<Triangle> back)
|
||||||
|
{
|
||||||
|
float d0 = plane.GetDistanceToPoint(tri.v0);
|
||||||
|
float d1 = plane.GetDistanceToPoint(tri.v1);
|
||||||
|
float d2 = plane.GetDistanceToPoint(tri.v2);
|
||||||
|
|
||||||
|
// Check for numerical issues
|
||||||
|
if (float.IsNaN(d0) || float.IsNaN(d1) || float.IsNaN(d2) ||
|
||||||
|
float.IsInfinity(d0) || float.IsInfinity(d1) || float.IsInfinity(d2))
|
||||||
|
{
|
||||||
|
coplanar.Add(tri);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool front0 = d0 > EPSILON;
|
||||||
|
bool front1 = d1 > EPSILON;
|
||||||
|
bool front2 = d2 > EPSILON;
|
||||||
|
|
||||||
|
bool back0 = d0 < -EPSILON;
|
||||||
|
bool back1 = d1 < -EPSILON;
|
||||||
|
bool back2 = d2 < -EPSILON;
|
||||||
|
|
||||||
|
int fCount = (front0 ? 1 : 0) + (front1 ? 1 : 0) + (front2 ? 1 : 0);
|
||||||
|
int bCount = (back0 ? 1 : 0) + (back1 ? 1 : 0) + (back2 ? 1 : 0);
|
||||||
|
|
||||||
|
if (fCount == 3)
|
||||||
|
{
|
||||||
|
front.Add(tri);
|
||||||
|
}
|
||||||
|
else if (bCount == 3)
|
||||||
|
{
|
||||||
|
back.Add(tri);
|
||||||
|
}
|
||||||
|
else if (fCount == 0 && bCount == 0)
|
||||||
|
{
|
||||||
|
coplanar.Add(tri);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalSplits++;
|
||||||
|
SplitTriangle(tri, plane, front, back);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SplitTriangle(Triangle tri, Plane plane, List<Triangle> front, List<Triangle> back)
|
||||||
|
{
|
||||||
|
// Get distances
|
||||||
|
float d0 = plane.GetDistanceToPoint(tri.v0);
|
||||||
|
float d1 = plane.GetDistanceToPoint(tri.v1);
|
||||||
|
float d2 = plane.GetDistanceToPoint(tri.v2);
|
||||||
|
|
||||||
|
// Classify points
|
||||||
|
bool[] frontSide = { d0 > EPSILON, d1 > EPSILON, d2 > EPSILON };
|
||||||
|
bool[] backSide = { d0 < -EPSILON, d1 < -EPSILON, d2 < -EPSILON };
|
||||||
|
|
||||||
|
// Count how many points are on each side
|
||||||
|
int frontCount = (frontSide[0] ? 1 : 0) + (frontSide[1] ? 1 : 0) + (frontSide[2] ? 1 : 0);
|
||||||
|
int backCount = (backSide[0] ? 1 : 0) + (backSide[1] ? 1 : 0) + (backSide[2] ? 1 : 0);
|
||||||
|
|
||||||
|
// 2 points on one side, 1 on the other
|
||||||
|
if (frontCount == 2 && backCount == 1)
|
||||||
|
{
|
||||||
|
int loneIndex = backSide[0] ? 0 : (backSide[1] ? 1 : 2);
|
||||||
|
SplitTriangle2To1(tri, plane, loneIndex, true, front, back);
|
||||||
|
}
|
||||||
|
else if (backCount == 2 && frontCount == 1)
|
||||||
|
{
|
||||||
|
int loneIndex = frontSide[0] ? 0 : (frontSide[1] ? 1 : 2);
|
||||||
|
SplitTriangle2To1(tri, plane, loneIndex, false, front, back);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Complex case - add to both sides (should be rare)
|
||||||
|
front.Add(tri);
|
||||||
|
back.Add(tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SplitTriangle2To1(Triangle tri, Plane plane, int loneIndex, bool loneIsBack,
|
||||||
|
List<Triangle> front, List<Triangle> back)
|
||||||
|
{
|
||||||
|
Vector3[] v = { tri.v0, tri.v1, tri.v2 };
|
||||||
|
Vector3[] n = { tri.n0, tri.n1, tri.n2 };
|
||||||
|
Vector2[] uv = { tri.uv0, tri.uv1, tri.uv2 };
|
||||||
|
|
||||||
|
Vector3 loneVertex = v[loneIndex];
|
||||||
|
Vector3 loneNormal = n[loneIndex];
|
||||||
|
Vector2 loneUV = uv[loneIndex];
|
||||||
|
|
||||||
|
Vector3 v1 = v[(loneIndex + 1) % 3];
|
||||||
|
Vector3 v2 = v[(loneIndex + 2) % 3];
|
||||||
|
Vector3 n1 = n[(loneIndex + 1) % 3];
|
||||||
|
Vector3 n2 = n[(loneIndex + 2) % 3];
|
||||||
|
Vector2 uv1 = uv[(loneIndex + 1) % 3];
|
||||||
|
Vector2 uv2 = uv[(loneIndex + 2) % 3];
|
||||||
|
|
||||||
|
Vector3 i1 = PlaneIntersection(plane, loneVertex, v1);
|
||||||
|
float t1 = CalculateInterpolationFactor(plane, loneVertex, v1);
|
||||||
|
Vector3 n_i1 = Vector3.Lerp(loneNormal, n1, t1).normalized;
|
||||||
|
Vector2 uv_i1 = Vector2.Lerp(loneUV, uv1, t1);
|
||||||
|
|
||||||
|
Vector3 i2 = PlaneIntersection(plane, loneVertex, v2);
|
||||||
|
float t2 = CalculateInterpolationFactor(plane, loneVertex, v2);
|
||||||
|
Vector3 n_i2 = Vector3.Lerp(loneNormal, n2, t2).normalized;
|
||||||
|
Vector2 uv_i2 = Vector2.Lerp(loneUV, uv2, t2);
|
||||||
|
|
||||||
|
// Desired normal: prefer triangle's plane normal, fallback to geometric normal
|
||||||
|
Vector3 desired = tri.plane.normal;
|
||||||
|
if (desired.sqrMagnitude < 1e-4f)
|
||||||
|
desired = Vector3.Cross(tri.v1 - tri.v0, tri.v2 - tri.v0).normalized;
|
||||||
|
if (desired.sqrMagnitude < 1e-4f)
|
||||||
|
desired = Vector3.up;
|
||||||
|
|
||||||
|
// Helper: decide and swap b/c if necessary, then add triangle
|
||||||
|
void AddTriClockwise(List<Triangle> list,
|
||||||
|
Vector3 a, Vector3 b, Vector3 c,
|
||||||
|
Vector3 na, Vector3 nb, Vector3 nc,
|
||||||
|
Vector2 ua, Vector2 ub, Vector2 uc)
|
||||||
|
{
|
||||||
|
Vector3 cross = Vector3.Cross(b - a, c - a);
|
||||||
|
if (cross.z > 0f) // <-- assumes you're working in PS1 screen space (z forward)
|
||||||
|
{
|
||||||
|
// swap b <-> c
|
||||||
|
var tmpV = b; b = c; c = tmpV;
|
||||||
|
var tmpN = nb; nb = nc; nc = tmpN;
|
||||||
|
var tmpUv = ub; ub = uc; uc = tmpUv;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add(new Triangle(a, b, c, na, nb, nc, ua, ub, uc, tri.sourceExporter, tri.materialIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loneIsBack)
|
||||||
|
{
|
||||||
|
// back: (lone, i1, i2)
|
||||||
|
AddTriClockwise(back, loneVertex, i1, i2, loneNormal, n_i1, n_i2, loneUV, uv_i1, uv_i2);
|
||||||
|
|
||||||
|
// front: (v1, i1, i2) and (v1, i2, v2)
|
||||||
|
AddTriClockwise(front, v1, i1, i2, n1, n_i1, n_i2, uv1, uv_i1, uv_i2);
|
||||||
|
AddTriClockwise(front, v1, i2, v2, n1, n_i2, n2, uv1, uv_i2, uv2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// front: (lone, i1, i2)
|
||||||
|
AddTriClockwise(front, loneVertex, i1, i2, loneNormal, n_i1, n_i2, loneUV, uv_i1, uv_i2);
|
||||||
|
|
||||||
|
// back: (v1, i1, i2) and (v1, i2, v2)
|
||||||
|
AddTriClockwise(back, v1, i1, i2, n1, n_i1, n_i2, uv1, uv_i1, uv_i2);
|
||||||
|
AddTriClockwise(back, v1, i2, v2, n1, n_i2, n2, uv1, uv_i2, uv2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Vector3 PlaneIntersection(Plane plane, Vector3 a, Vector3 b)
|
||||||
|
{
|
||||||
|
Vector3 ba = b - a;
|
||||||
|
float denominator = Vector3.Dot(plane.normal, ba);
|
||||||
|
|
||||||
|
// Check for parallel line (shouldn't happen in our case)
|
||||||
|
if (Mathf.Abs(denominator) < 1e-4f)
|
||||||
|
return a;
|
||||||
|
|
||||||
|
float t = (-plane.distance - Vector3.Dot(plane.normal, a)) / denominator;
|
||||||
|
return a + ba * Mathf.Clamp01(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float CalculateInterpolationFactor(Plane plane, Vector3 a, Vector3 b)
|
||||||
|
{
|
||||||
|
Vector3 ba = b - a;
|
||||||
|
float denominator = Vector3.Dot(plane.normal, ba);
|
||||||
|
|
||||||
|
if (Mathf.Abs(denominator) < 1e-4f)
|
||||||
|
return 0.5f;
|
||||||
|
|
||||||
|
float t = (-plane.distance - Vector3.Dot(plane.normal, a)) / denominator;
|
||||||
|
return Mathf.Clamp01(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bounds CalculateBounds(List<Triangle> triangles)
|
||||||
|
{
|
||||||
|
if (triangles == null || triangles.Count == 0)
|
||||||
|
return new Bounds();
|
||||||
|
|
||||||
|
Bounds bounds = triangles[0].bounds;
|
||||||
|
for (int i = 1; i < triangles.Count; i++)
|
||||||
|
{
|
||||||
|
bounds.Encapsulate(triangles[i].bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a method to create modified meshes after BSP construction
|
||||||
|
// Add a method to create modified meshes after BSP construction
|
||||||
|
private void CreateModifiedMeshes()
|
||||||
|
{
|
||||||
|
if (root == null) return;
|
||||||
|
|
||||||
|
// Collect all triangles from the BSP tree
|
||||||
|
List<Triangle> allTriangles = new List<Triangle>();
|
||||||
|
CollectTrianglesFromNode(root, allTriangles);
|
||||||
|
|
||||||
|
// Group triangles by their source exporter and material index
|
||||||
|
Dictionary<PSXObjectExporter, Dictionary<int, List<Triangle>>> exporterTriangles =
|
||||||
|
new Dictionary<PSXObjectExporter, Dictionary<int, List<Triangle>>>();
|
||||||
|
|
||||||
|
foreach (var tri in allTriangles)
|
||||||
|
{
|
||||||
|
if (!exporterTriangles.ContainsKey(tri.sourceExporter))
|
||||||
|
{
|
||||||
|
exporterTriangles[tri.sourceExporter] = new Dictionary<int, List<Triangle>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var materialDict = exporterTriangles[tri.sourceExporter];
|
||||||
|
if (!materialDict.ContainsKey(tri.materialIndex))
|
||||||
|
{
|
||||||
|
materialDict[tri.materialIndex] = new List<Triangle>();
|
||||||
|
}
|
||||||
|
|
||||||
|
materialDict[tri.materialIndex].Add(tri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create modified meshes for each exporter
|
||||||
|
foreach (var kvp in exporterTriangles)
|
||||||
|
{
|
||||||
|
PSXObjectExporter exporter = kvp.Key;
|
||||||
|
Dictionary<int, List<Triangle>> materialTriangles = kvp.Value;
|
||||||
|
|
||||||
|
Mesh originalMesh = exporter.GetComponent<MeshFilter>().sharedMesh;
|
||||||
|
Renderer renderer = exporter.GetComponent<Renderer>();
|
||||||
|
|
||||||
|
Mesh modifiedMesh = new Mesh();
|
||||||
|
modifiedMesh.name = originalMesh.name + "_BSP";
|
||||||
|
|
||||||
|
List<Vector3> vertices = new List<Vector3>();
|
||||||
|
List<Vector3> normals = new List<Vector3>();
|
||||||
|
List<Vector2> uvs = new List<Vector2>();
|
||||||
|
List<Vector4> tangents = new List<Vector4>();
|
||||||
|
List<Color> colors = new List<Color>();
|
||||||
|
|
||||||
|
// Create a list for each material's triangles
|
||||||
|
List<List<int>> materialIndices = new List<List<int>>();
|
||||||
|
for (int i = 0; i < renderer.sharedMaterials.Length; i++)
|
||||||
|
{
|
||||||
|
materialIndices.Add(new List<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the inverse transform to convert from world space back to object space
|
||||||
|
Matrix4x4 worldToLocal = exporter.transform.worldToLocalMatrix;
|
||||||
|
|
||||||
|
// Process each material
|
||||||
|
foreach (var materialKvp in materialTriangles)
|
||||||
|
{
|
||||||
|
int materialIndex = materialKvp.Key;
|
||||||
|
List<Triangle> triangles = materialKvp.Value;
|
||||||
|
|
||||||
|
// Add vertices, normals, and uvs for this material
|
||||||
|
for (int i = 0; i < triangles.Count; i++)
|
||||||
|
{
|
||||||
|
Triangle tri = triangles[i];
|
||||||
|
|
||||||
|
// Transform vertices from world space back to object space
|
||||||
|
Vector3 v0 = worldToLocal.MultiplyPoint3x4(tri.v0);
|
||||||
|
Vector3 v1 = worldToLocal.MultiplyPoint3x4(tri.v1);
|
||||||
|
Vector3 v2 = worldToLocal.MultiplyPoint3x4(tri.v2);
|
||||||
|
|
||||||
|
int vertexIndex = vertices.Count;
|
||||||
|
vertices.Add(v0);
|
||||||
|
vertices.Add(v1);
|
||||||
|
vertices.Add(v2);
|
||||||
|
|
||||||
|
// Transform normals from world space back to object space
|
||||||
|
Vector3 n0 = worldToLocal.MultiplyVector(tri.n0).normalized;
|
||||||
|
Vector3 n1 = worldToLocal.MultiplyVector(tri.n1).normalized;
|
||||||
|
Vector3 n2 = worldToLocal.MultiplyVector(tri.n2).normalized;
|
||||||
|
|
||||||
|
normals.Add(n0);
|
||||||
|
normals.Add(n1);
|
||||||
|
normals.Add(n2);
|
||||||
|
|
||||||
|
uvs.Add(tri.uv0);
|
||||||
|
uvs.Add(tri.uv1);
|
||||||
|
uvs.Add(tri.uv2);
|
||||||
|
|
||||||
|
// Add default tangents and colors (will be recalculated later)
|
||||||
|
tangents.Add(new Vector4(1, 0, 0, 1));
|
||||||
|
tangents.Add(new Vector4(1, 0, 0, 1));
|
||||||
|
tangents.Add(new Vector4(1, 0, 0, 1));
|
||||||
|
|
||||||
|
colors.Add(Color.white);
|
||||||
|
colors.Add(Color.white);
|
||||||
|
colors.Add(Color.white);
|
||||||
|
|
||||||
|
// Add indices for this material
|
||||||
|
materialIndices[materialIndex].Add(vertexIndex);
|
||||||
|
materialIndices[materialIndex].Add(vertexIndex + 1);
|
||||||
|
materialIndices[materialIndex].Add(vertexIndex + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign data to the mesh
|
||||||
|
modifiedMesh.vertices = vertices.ToArray();
|
||||||
|
modifiedMesh.normals = normals.ToArray();
|
||||||
|
modifiedMesh.uv = uvs.ToArray();
|
||||||
|
modifiedMesh.tangents = tangents.ToArray();
|
||||||
|
modifiedMesh.colors = colors.ToArray();
|
||||||
|
|
||||||
|
// Set up submeshes based on materials
|
||||||
|
modifiedMesh.subMeshCount = materialIndices.Count;
|
||||||
|
for (int i = 0; i < materialIndices.Count; i++)
|
||||||
|
{
|
||||||
|
modifiedMesh.SetTriangles(materialIndices[i].ToArray(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate important mesh properties
|
||||||
|
modifiedMesh.RecalculateBounds();
|
||||||
|
modifiedMesh.RecalculateTangents();
|
||||||
|
|
||||||
|
// Assign the modified mesh to the exporter
|
||||||
|
exporter.ModifiedMesh = modifiedMesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Helper method to collect all triangles from the BSP tree
|
||||||
|
private void CollectTrianglesFromNode(Node node, List<Triangle> triangles)
|
||||||
|
{
|
||||||
|
if (node == null) return;
|
||||||
|
|
||||||
|
if (node.isLeaf)
|
||||||
|
{
|
||||||
|
triangles.AddRange(node.triangles);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CollectTrianglesFromNode(node.front, triangles);
|
||||||
|
CollectTrianglesFromNode(node.back, triangles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawGizmos(int maxDepth)
|
||||||
|
{
|
||||||
|
if (root == null) return;
|
||||||
|
|
||||||
|
DrawNodeGizmos(root, 0, maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawNodeGizmos(Node node, int depth, int maxDepth)
|
||||||
|
{
|
||||||
|
if (node == null) return;
|
||||||
|
if (depth > maxDepth) return;
|
||||||
|
|
||||||
|
Color nodeColor = Color.HSVToRGB((depth * 0.1f) % 1f, 0.8f, 0.8f);
|
||||||
|
Gizmos.color = nodeColor;
|
||||||
|
|
||||||
|
if (node.isLeaf)
|
||||||
|
{
|
||||||
|
foreach (var tri in node.triangles)
|
||||||
|
{
|
||||||
|
DrawTriangleGizmo(tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawPlaneGizmo(node.plane, node.bounds);
|
||||||
|
|
||||||
|
// Draw the triangle that was used for the split plane if available
|
||||||
|
if (splitPlaneTriangles.ContainsKey(node))
|
||||||
|
{
|
||||||
|
Gizmos.color = Color.magenta;
|
||||||
|
DrawTriangleGizmo(splitPlaneTriangles[node]);
|
||||||
|
Gizmos.color = nodeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawNodeGizmos(node.front, depth + 1, maxDepth);
|
||||||
|
DrawNodeGizmos(node.back, depth + 1, maxDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTriangleGizmo(Triangle tri)
|
||||||
|
{
|
||||||
|
Gizmos.DrawLine(tri.v0, tri.v1);
|
||||||
|
Gizmos.DrawLine(tri.v1, tri.v2);
|
||||||
|
Gizmos.DrawLine(tri.v2, tri.v0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPlaneGizmo(Plane plane, Bounds bounds)
|
||||||
|
{
|
||||||
|
Vector3 center = bounds.center;
|
||||||
|
Vector3 normal = plane.normal;
|
||||||
|
|
||||||
|
Vector3 tangent = Vector3.Cross(normal, Vector3.up);
|
||||||
|
if (tangent.magnitude < 0.1f) tangent = Vector3.Cross(normal, Vector3.right);
|
||||||
|
tangent = tangent.normalized;
|
||||||
|
|
||||||
|
Vector3 bitangent = Vector3.Cross(normal, tangent).normalized;
|
||||||
|
|
||||||
|
float size = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z) * 0.5f;
|
||||||
|
tangent *= size;
|
||||||
|
bitangent *= size;
|
||||||
|
|
||||||
|
Vector3 p0 = center - tangent - bitangent;
|
||||||
|
Vector3 p1 = center + tangent - bitangent;
|
||||||
|
Vector3 p2 = center + tangent + bitangent;
|
||||||
|
Vector3 p3 = center - tangent + bitangent;
|
||||||
|
|
||||||
|
Gizmos.DrawLine(p0, p1);
|
||||||
|
Gizmos.DrawLine(p1, p2);
|
||||||
|
Gizmos.DrawLine(p2, p3);
|
||||||
|
Gizmos.DrawLine(p3, p0);
|
||||||
|
|
||||||
|
Gizmos.color = Color.red;
|
||||||
|
Gizmos.DrawLine(center, center + normal * size * 0.5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Runtime/BSP.cs.meta
Normal file
2
Runtime/BSP.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 15144e67b42b92447a546346e594155b
|
||||||
@@ -3,14 +3,36 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace SplashEdit.RuntimeCode
|
namespace SplashEdit.RuntimeCode
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public enum PSXConnectionType
|
||||||
|
{
|
||||||
|
REAL_HARDWARE, // Unirom
|
||||||
|
EMULATOR // PCSX-Redux
|
||||||
|
}
|
||||||
|
|
||||||
[CreateAssetMenu(fileName = "PSXData", menuName = "Scriptable Objects/PSXData")]
|
[CreateAssetMenu(fileName = "PSXData", menuName = "Scriptable Objects/PSXData")]
|
||||||
public class PSXData : ScriptableObject
|
public class PSXData : ScriptableObject
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Texture packing settings
|
||||||
public Vector2 OutputResolution = new Vector2(320, 240);
|
public Vector2 OutputResolution = new Vector2(320, 240);
|
||||||
public bool DualBuffering = true;
|
public bool DualBuffering = true;
|
||||||
public bool VerticalBuffering = true;
|
public bool VerticalBuffering = true;
|
||||||
public List<ProhibitedArea> ProhibitedAreas = new List<ProhibitedArea>();
|
public List<ProhibitedArea> ProhibitedAreas = new List<ProhibitedArea>();
|
||||||
|
|
||||||
|
|
||||||
|
// Connection settings
|
||||||
|
public PSXConnectionType ConnectionType = PSXConnectionType.REAL_HARDWARE;
|
||||||
|
|
||||||
|
// Real hardware settings
|
||||||
|
public string PortName = "COM3";
|
||||||
|
public int BaudRate = 0;
|
||||||
|
|
||||||
|
// Emulator settings
|
||||||
public string PCSXReduxPath = "";
|
public string PCSXReduxPath = "";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ namespace SplashEdit.RuntimeCode
|
|||||||
public PSXVertex v1;
|
public PSXVertex v1;
|
||||||
public PSXVertex v2;
|
public PSXVertex v2;
|
||||||
|
|
||||||
public int TextureIndex;
|
public int TextureIndex;
|
||||||
public readonly PSXVertex[] Vertexes => new PSXVertex[] { v0, v1, v2 };
|
public readonly PSXVertex[] Vertexes => new PSXVertex[] { v0, v1, v2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,77 +82,176 @@ namespace SplashEdit.RuntimeCode
|
|||||||
/// <param name="textureHeight">Height of the texture (default is 256).</param>
|
/// <param name="textureHeight">Height of the texture (default is 256).</param>
|
||||||
/// <param name="transform">Optional transform to convert vertices to world space.</param>
|
/// <param name="transform">Optional transform to convert vertices to world space.</param>
|
||||||
/// <returns>A new PSXMesh containing the converted triangles.</returns>
|
/// <returns>A new PSXMesh containing the converted triangles.</returns>
|
||||||
public static PSXMesh CreateFromUnityRenderer(Renderer renderer, float GTEScaling, Transform transform, List<PSXTexture2D> textures)
|
public static PSXMesh CreateFromUnityRenderer(Renderer renderer, float GTEScaling, Transform transform, List<PSXTexture2D> textures)
|
||||||
{
|
|
||||||
PSXMesh psxMesh = new PSXMesh { Triangles = new List<Tri>() };
|
|
||||||
Material[] materials = renderer.sharedMaterials;
|
|
||||||
Mesh mesh = renderer.GetComponent<MeshFilter>().sharedMesh;
|
|
||||||
|
|
||||||
for (int submeshIndex = 0; submeshIndex < materials.Length; submeshIndex++)
|
|
||||||
{
|
|
||||||
int[] submeshTriangles = mesh.GetTriangles(submeshIndex);
|
|
||||||
Material material = materials[submeshIndex];
|
|
||||||
Texture2D texture = material.mainTexture as Texture2D;
|
|
||||||
|
|
||||||
// Find texture index instead of the texture itself
|
|
||||||
int textureIndex = -1;
|
|
||||||
if (texture != null)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < textures.Count; i++)
|
PSXMesh psxMesh = new PSXMesh { Triangles = new List<Tri>() };
|
||||||
|
Material[] materials = renderer.sharedMaterials;
|
||||||
|
Mesh mesh = renderer.GetComponent<MeshFilter>().sharedMesh;
|
||||||
|
|
||||||
|
for (int submeshIndex = 0; submeshIndex < materials.Length; submeshIndex++)
|
||||||
{
|
{
|
||||||
if (textures[i].OriginalTexture == texture)
|
int[] submeshTriangles = mesh.GetTriangles(submeshIndex);
|
||||||
|
Material material = materials[submeshIndex];
|
||||||
|
Texture2D texture = material.mainTexture as Texture2D;
|
||||||
|
|
||||||
|
// Find texture index instead of the texture itself
|
||||||
|
int textureIndex = -1;
|
||||||
|
if (texture != null)
|
||||||
{
|
{
|
||||||
textureIndex = i;
|
for (int i = 0; i < textures.Count; i++)
|
||||||
break;
|
{
|
||||||
|
if (textures[i].OriginalTexture == texture)
|
||||||
|
{
|
||||||
|
textureIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureIndex == -1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mesh data arrays
|
||||||
|
mesh.RecalculateNormals();
|
||||||
|
Vector3[] vertices = mesh.vertices;
|
||||||
|
Vector3[] normals = mesh.normals;
|
||||||
|
Vector3[] smoothNormals = RecalculateSmoothNormals(mesh);
|
||||||
|
Vector2[] uv = mesh.uv;
|
||||||
|
|
||||||
|
PSXVertex convertData(int index)
|
||||||
|
{
|
||||||
|
Vector3 v = Vector3.Scale(vertices[index], transform.lossyScale);
|
||||||
|
Vector3 wv = transform.TransformPoint(vertices[index]);
|
||||||
|
Vector3 wn = transform.TransformDirection(smoothNormals[index]).normalized;
|
||||||
|
Color c = PSXLightingBaker.ComputeLighting(wv, wn);
|
||||||
|
return ConvertToPSXVertex(v, GTEScaling, normals[index], uv[index], textures[textureIndex]?.Width, textures[textureIndex]?.Height, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < submeshTriangles.Length; i += 3)
|
||||||
|
{
|
||||||
|
int vid0 = submeshTriangles[i];
|
||||||
|
int vid1 = submeshTriangles[i + 1];
|
||||||
|
int vid2 = submeshTriangles[i + 2];
|
||||||
|
|
||||||
|
Vector3 faceNormal = Vector3.Cross(vertices[vid1] - vertices[vid0], vertices[vid2] - vertices[vid0]).normalized;
|
||||||
|
|
||||||
|
if (Vector3.Dot(faceNormal, normals[vid0]) < 0)
|
||||||
|
{
|
||||||
|
(vid1, vid2) = (vid2, vid1);
|
||||||
|
}
|
||||||
|
|
||||||
|
psxMesh.Triangles.Add(new Tri
|
||||||
|
{
|
||||||
|
v0 = convertData(vid0),
|
||||||
|
v1 = convertData(vid1),
|
||||||
|
v2 = convertData(vid2),
|
||||||
|
TextureIndex = textureIndex
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return psxMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textureIndex == -1)
|
public static PSXMesh CreateFromUnityMesh(Mesh mesh, Renderer renderer, float GTEScaling, Transform transform, List<PSXTexture2D> textures)
|
||||||
{
|
{
|
||||||
continue;
|
PSXMesh psxMesh = new PSXMesh { Triangles = new List<Tri>() };
|
||||||
}
|
Material[] materials = renderer.sharedMaterials;
|
||||||
|
|
||||||
// Get mesh data arrays
|
// Ensure mesh has required data
|
||||||
mesh.RecalculateNormals();
|
if (mesh.normals == null || mesh.normals.Length == 0)
|
||||||
Vector3[] vertices = mesh.vertices;
|
|
||||||
Vector3[] normals = mesh.normals;
|
|
||||||
Vector3[] smoothNormals = RecalculateSmoothNormals(mesh);
|
|
||||||
Vector2[] uv = mesh.uv;
|
|
||||||
|
|
||||||
PSXVertex convertData(int index)
|
|
||||||
{
|
|
||||||
Vector3 v = Vector3.Scale(vertices[index], transform.lossyScale);
|
|
||||||
Vector3 wv = transform.TransformPoint(vertices[index]);
|
|
||||||
Vector3 wn = transform.TransformDirection(smoothNormals[index]).normalized;
|
|
||||||
Color c = PSXLightingBaker.ComputeLighting(wv, wn);
|
|
||||||
return ConvertToPSXVertex(v, GTEScaling, normals[index], uv[index], textures[textureIndex]?.Width, textures[textureIndex]?.Height, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < submeshTriangles.Length; i += 3)
|
|
||||||
{
|
|
||||||
int vid0 = submeshTriangles[i];
|
|
||||||
int vid1 = submeshTriangles[i + 1];
|
|
||||||
int vid2 = submeshTriangles[i + 2];
|
|
||||||
|
|
||||||
Vector3 faceNormal = Vector3.Cross(vertices[vid1] - vertices[vid0], vertices[vid2] - vertices[vid0]).normalized;
|
|
||||||
|
|
||||||
if (Vector3.Dot(faceNormal, normals[vid0]) < 0)
|
|
||||||
{
|
{
|
||||||
(vid1, vid2) = (vid2, vid1);
|
mesh.RecalculateNormals();
|
||||||
}
|
}
|
||||||
|
|
||||||
psxMesh.Triangles.Add(new Tri {
|
if (mesh.uv == null || mesh.uv.Length == 0)
|
||||||
v0 = convertData(vid0),
|
{
|
||||||
v1 = convertData(vid1),
|
Vector2[] uvs = new Vector2[mesh.vertices.Length];
|
||||||
v2 = convertData(vid2),
|
mesh.uv = uvs;
|
||||||
TextureIndex = textureIndex
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return psxMesh;
|
// Precompute smooth normals for the entire mesh
|
||||||
}
|
Vector3[] smoothNormals = RecalculateSmoothNormals(mesh);
|
||||||
|
|
||||||
|
// Precompute world positions and normals for all vertices
|
||||||
|
Vector3[] worldVertices = new Vector3[mesh.vertices.Length];
|
||||||
|
Vector3[] worldNormals = new Vector3[mesh.normals.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < mesh.vertices.Length; i++)
|
||||||
|
{
|
||||||
|
worldVertices[i] = transform.TransformPoint(mesh.vertices[i]);
|
||||||
|
worldNormals[i] = transform.TransformDirection(mesh.normals[i]).normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int submeshIndex = 0; submeshIndex < mesh.subMeshCount; submeshIndex++)
|
||||||
|
{
|
||||||
|
int materialIndex = Mathf.Min(submeshIndex, materials.Length - 1);
|
||||||
|
Material material = materials[materialIndex];
|
||||||
|
Texture2D texture = material.mainTexture as Texture2D;
|
||||||
|
|
||||||
|
// Find texture index
|
||||||
|
int textureIndex = -1;
|
||||||
|
if (texture != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < textures.Count; i++)
|
||||||
|
{
|
||||||
|
if (textures[i].OriginalTexture == texture)
|
||||||
|
{
|
||||||
|
textureIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] submeshTriangles = mesh.GetTriangles(submeshIndex);
|
||||||
|
|
||||||
|
// Get mesh data arrays
|
||||||
|
Vector3[] vertices = mesh.vertices;
|
||||||
|
Vector3[] normals = mesh.normals;
|
||||||
|
Vector2[] uv = mesh.uv;
|
||||||
|
|
||||||
|
PSXVertex convertData(int index)
|
||||||
|
{
|
||||||
|
Vector3 v = Vector3.Scale(vertices[index], transform.lossyScale);
|
||||||
|
|
||||||
|
// Use precomputed world position and normal for consistent lighting
|
||||||
|
Vector3 wv = worldVertices[index];
|
||||||
|
Vector3 wn = worldNormals[index];
|
||||||
|
|
||||||
|
// For split triangles, use the original vertex's lighting if possible
|
||||||
|
Color c = PSXLightingBaker.ComputeLighting(wv, wn);
|
||||||
|
|
||||||
|
return ConvertToPSXVertex(v, GTEScaling, normals[index], uv[index],
|
||||||
|
textures[textureIndex]?.Width, textures[textureIndex]?.Height, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < submeshTriangles.Length; i += 3)
|
||||||
|
{
|
||||||
|
int vid0 = submeshTriangles[i];
|
||||||
|
int vid1 = submeshTriangles[i + 1];
|
||||||
|
int vid2 = submeshTriangles[i + 2];
|
||||||
|
|
||||||
|
Vector3 faceNormal = Vector3.Cross(vertices[vid1] - vertices[vid0], vertices[vid2] - vertices[vid0]).normalized;
|
||||||
|
|
||||||
|
if (Vector3.Dot(faceNormal, normals[vid0]) < 0)
|
||||||
|
{
|
||||||
|
(vid1, vid2) = (vid2, vid1);
|
||||||
|
}
|
||||||
|
|
||||||
|
psxMesh.Triangles.Add(new Tri
|
||||||
|
{
|
||||||
|
v0 = convertData(vid0),
|
||||||
|
v1 = convertData(vid1),
|
||||||
|
v2 = convertData(vid2),
|
||||||
|
TextureIndex = textureIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return psxMesh;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a Unity vertex into a PSXVertex by applying fixed-point conversion, shading, and UV mapping.
|
/// Converts a Unity vertex into a PSXVertex by applying fixed-point conversion, shading, and UV mapping.
|
||||||
|
|||||||
@@ -12,19 +12,30 @@ namespace SplashEdit.RuntimeCode
|
|||||||
|
|
||||||
public bool IsActive = true;
|
public bool IsActive = true;
|
||||||
|
|
||||||
public List<PSXTexture2D> Textures { get; set; } = new List<PSXTexture2D>(); // Stores the converted PlayStation-style texture
|
public List<PSXTexture2D> Textures { get; set; } = new List<PSXTexture2D>();
|
||||||
public PSXMesh Mesh { get; protected set; } // Stores the converted PlayStation-style mesh
|
public PSXMesh Mesh { get; protected set; }
|
||||||
|
|
||||||
[Header("Export Settings")]
|
[Header("Export Settings")]
|
||||||
[FormerlySerializedAs("BitDepth")]
|
[FormerlySerializedAs("BitDepth")]
|
||||||
[SerializeField] private PSXBPP bitDepth = PSXBPP.TEX_8BIT; // Defines the bit depth of the texture (e.g., 4BPP, 8BPP)
|
[SerializeField] private PSXBPP bitDepth = PSXBPP.TEX_8BIT;
|
||||||
[SerializeField] private LuaFile luaFile;
|
[SerializeField] private LuaFile luaFile;
|
||||||
|
|
||||||
|
[Header("BSP Settings")]
|
||||||
|
[SerializeField] private Mesh _modifiedMesh; // Mesh after BSP processing
|
||||||
|
|
||||||
[Header("Gizmo Settings")]
|
[Header("Gizmo Settings")]
|
||||||
[FormerlySerializedAs("PreviewNormals")]
|
[FormerlySerializedAs("PreviewNormals")]
|
||||||
[SerializeField] private bool previewNormals = false;
|
[SerializeField] private bool previewNormals = false;
|
||||||
[SerializeField] private float normalPreviewLength = 0.5f; // Length of the normal lines
|
[SerializeField] private float normalPreviewLength = 0.5f;
|
||||||
|
|
||||||
private readonly Dictionary<(int, PSXBPP), PSXTexture2D> cache = new();
|
private readonly Dictionary<(int, PSXBPP), PSXTexture2D> cache = new();
|
||||||
|
|
||||||
|
public Mesh ModifiedMesh
|
||||||
|
{
|
||||||
|
get => _modifiedMesh;
|
||||||
|
set => _modifiedMesh = value;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDrawGizmos()
|
private void OnDrawGizmos()
|
||||||
{
|
{
|
||||||
if (previewNormals)
|
if (previewNormals)
|
||||||
@@ -37,25 +48,19 @@ namespace SplashEdit.RuntimeCode
|
|||||||
Vector3[] vertices = mesh.vertices;
|
Vector3[] vertices = mesh.vertices;
|
||||||
Vector3[] normals = mesh.normals;
|
Vector3[] normals = mesh.normals;
|
||||||
|
|
||||||
Gizmos.color = Color.green; // Normal color
|
Gizmos.color = Color.green;
|
||||||
|
|
||||||
for (int i = 0; i < vertices.Length; i++)
|
for (int i = 0; i < vertices.Length; i++)
|
||||||
{
|
{
|
||||||
Vector3 worldVertex = transform.TransformPoint(vertices[i]); // Convert to world space
|
Vector3 worldVertex = transform.TransformPoint(vertices[i]);
|
||||||
Vector3 worldNormal = transform.TransformDirection(normals[i]); // Transform normal to world space
|
Vector3 worldNormal = transform.TransformDirection(normals[i]);
|
||||||
|
|
||||||
Gizmos.DrawLine(worldVertex, worldVertex + worldNormal * normalPreviewLength);
|
Gizmos.DrawLine(worldVertex, worldVertex + worldNormal * normalPreviewLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the object's material texture into a PlayStation-compatible texture.
|
|
||||||
/// </summary>
|
|
||||||
///
|
|
||||||
public void CreatePSXTextures2D()
|
public void CreatePSXTextures2D()
|
||||||
{
|
{
|
||||||
Renderer renderer = GetComponent<Renderer>();
|
Renderer renderer = GetComponent<Renderer>();
|
||||||
@@ -71,14 +76,12 @@ namespace SplashEdit.RuntimeCode
|
|||||||
Texture mainTexture = mat.mainTexture;
|
Texture mainTexture = mat.mainTexture;
|
||||||
Texture2D tex2D = null;
|
Texture2D tex2D = null;
|
||||||
|
|
||||||
// Check if it's already a Texture2D
|
|
||||||
if (mainTexture is Texture2D existingTex2D)
|
if (mainTexture is Texture2D existingTex2D)
|
||||||
{
|
{
|
||||||
tex2D = existingTex2D;
|
tex2D = existingTex2D;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If not a Texture2D, try to convert
|
|
||||||
tex2D = ConvertToTexture2D(mainTexture);
|
tex2D = ConvertToTexture2D(mainTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +95,7 @@ namespace SplashEdit.RuntimeCode
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
tex = PSXTexture2D.CreateFromTexture2D(tex2D, bitDepth);
|
tex = PSXTexture2D.CreateFromTexture2D(tex2D, bitDepth);
|
||||||
tex.OriginalTexture = tex2D; // Store reference to the original texture
|
tex.OriginalTexture = tex2D;
|
||||||
cache.Add((tex2D.GetInstanceID(), bitDepth), tex);
|
cache.Add((tex2D.GetInstanceID(), bitDepth), tex);
|
||||||
}
|
}
|
||||||
Textures.Add(tex);
|
Textures.Add(tex);
|
||||||
@@ -104,10 +107,8 @@ namespace SplashEdit.RuntimeCode
|
|||||||
|
|
||||||
private Texture2D ConvertToTexture2D(Texture texture)
|
private Texture2D ConvertToTexture2D(Texture texture)
|
||||||
{
|
{
|
||||||
// Create a new Texture2D with the same dimensions and format
|
|
||||||
Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
|
Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
|
||||||
|
|
||||||
// Read the texture pixels
|
|
||||||
RenderTexture currentActiveRT = RenderTexture.active;
|
RenderTexture currentActiveRT = RenderTexture.active;
|
||||||
RenderTexture.active = texture as RenderTexture;
|
RenderTexture.active = texture as RenderTexture;
|
||||||
|
|
||||||
@@ -128,16 +129,35 @@ namespace SplashEdit.RuntimeCode
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public void CreatePSXMesh(float GTEScaling, bool useBSP = false)
|
||||||
/// Converts the object's mesh into a PlayStation-compatible mesh.
|
|
||||||
/// </summary>
|
|
||||||
public void CreatePSXMesh(float GTEScaling)
|
|
||||||
{
|
{
|
||||||
Renderer renderer = GetComponent<Renderer>();
|
Renderer renderer = GetComponent<Renderer>();
|
||||||
if (renderer != null)
|
if (renderer != null)
|
||||||
{
|
{
|
||||||
Mesh = PSXMesh.CreateFromUnityRenderer(renderer, GTEScaling, transform, Textures);
|
if (useBSP && _modifiedMesh != null)
|
||||||
|
{
|
||||||
|
// Create a temporary GameObject with the modified mesh but same materials
|
||||||
|
GameObject tempGO = new GameObject("TempBSPMesh");
|
||||||
|
tempGO.transform.position = transform.position;
|
||||||
|
tempGO.transform.rotation = transform.rotation;
|
||||||
|
tempGO.transform.localScale = transform.localScale;
|
||||||
|
|
||||||
|
MeshFilter tempMF = tempGO.AddComponent<MeshFilter>();
|
||||||
|
tempMF.sharedMesh = _modifiedMesh;
|
||||||
|
|
||||||
|
MeshRenderer tempMR = tempGO.AddComponent<MeshRenderer>();
|
||||||
|
tempMR.sharedMaterials = renderer.sharedMaterials;
|
||||||
|
|
||||||
|
Mesh = PSXMesh.CreateFromUnityRenderer(tempMR, GTEScaling, transform, Textures);
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
GameObject.DestroyImmediate(tempGO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Mesh = PSXMesh.CreateFromUnityRenderer(renderer, GTEScaling, transform, Textures);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,11 @@ namespace SplashEdit.RuntimeCode
|
|||||||
private Quaternion _playerRot;
|
private Quaternion _playerRot;
|
||||||
private float _playerHeight;
|
private float _playerHeight;
|
||||||
|
|
||||||
|
private BSP _bsp;
|
||||||
|
|
||||||
|
public bool PreviewBSP = true;
|
||||||
|
public int BSPPreviewDepth = 9999;
|
||||||
|
|
||||||
public void Export()
|
public void Export()
|
||||||
{
|
{
|
||||||
_psxData = DataStorage.LoadData(out selectedResolution, out dualBuffering, out verticalLayout, out prohibitedAreas);
|
_psxData = DataStorage.LoadData(out selectedResolution, out dualBuffering, out verticalLayout, out prohibitedAreas);
|
||||||
@@ -42,7 +47,7 @@ namespace SplashEdit.RuntimeCode
|
|||||||
PSXObjectExporter exp = _exporters[i];
|
PSXObjectExporter exp = _exporters[i];
|
||||||
EditorUtility.DisplayProgressBar($"{nameof(PSXSceneExporter)}", $"Export {nameof(PSXObjectExporter)}", ((float)i) / _exporters.Length);
|
EditorUtility.DisplayProgressBar($"{nameof(PSXSceneExporter)}", $"Export {nameof(PSXObjectExporter)}", ((float)i) / _exporters.Length);
|
||||||
exp.CreatePSXTextures2D();
|
exp.CreatePSXTextures2D();
|
||||||
exp.CreatePSXMesh(GTEScaling);
|
exp.CreatePSXMesh(GTEScaling, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_navmeshes = FindObjectsByType<PSXNavMesh>(FindObjectsSortMode.None);
|
_navmeshes = FindObjectsByType<PSXNavMesh>(FindObjectsSortMode.None);
|
||||||
@@ -66,6 +71,9 @@ namespace SplashEdit.RuntimeCode
|
|||||||
_playerRot = player.transform.rotation;
|
_playerRot = player.transform.rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_bsp = new BSP(_exporters.ToList());
|
||||||
|
_bsp.Build();
|
||||||
|
|
||||||
ExportFile();
|
ExportFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,6 +458,10 @@ namespace SplashEdit.RuntimeCode
|
|||||||
Vector3 cubeSize = new Vector3(8.0f * GTEScaling, 8.0f * GTEScaling, 8.0f * GTEScaling);
|
Vector3 cubeSize = new Vector3(8.0f * GTEScaling, 8.0f * GTEScaling, 8.0f * GTEScaling);
|
||||||
Gizmos.color = Color.red;
|
Gizmos.color = Color.red;
|
||||||
Gizmos.DrawWireCube(sceneOrigin, cubeSize);
|
Gizmos.DrawWireCube(sceneOrigin, cubeSize);
|
||||||
|
|
||||||
|
if (_bsp == null || !PreviewBSP) return;
|
||||||
|
_bsp.DrawGizmos(BSPPreviewDepth);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user