diff --git a/NewHorizons/Builder/StarSystem/SkyboxBuilder.cs b/NewHorizons/Builder/StarSystem/SkyboxBuilder.cs index 44d27945..892d784f 100644 --- a/NewHorizons/Builder/StarSystem/SkyboxBuilder.cs +++ b/NewHorizons/Builder/StarSystem/SkyboxBuilder.cs @@ -1,12 +1,17 @@ using NewHorizons.External.Configs; using NewHorizons.Utility; using OWML.Common; +using System; using UnityEngine; using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.Builder.StarSystem { public class SkyboxBuilder { + private static int _skyboxLayer = -1; + private static Shader _unlitShader; + + [Obsolete] public static void Make(StarSystemConfig.SkyboxConfig info, IModBehaviour mod) { Logger.Log("Building Skybox"); @@ -17,5 +22,134 @@ namespace NewHorizons.Builder.StarSystem camera.clearFlags = CameraClearFlags.Skybox; } } + + public static void Make(StarSystemConfig.SkyboxModule module, IModBehaviour mod) + { + Logger.Log("Building Skybox"); + BuildSkySphere(module, mod); + } + + public static GameObject BuildSkySphere(StarSystemConfig.SkyboxModule module, IModBehaviour mod) + { + var skybox = SearchUtilities.Find("Skybox"); + + var rightTex = ImageUtilities.GetTexture(mod, module.rightPath); + var leftTex = ImageUtilities.GetTexture(mod, module.leftPath); + var topTex = ImageUtilities.GetTexture(mod, module.topPath); + var bottomTex = ImageUtilities.GetTexture(mod, module.bottomPath); + var frontTex = ImageUtilities.GetTexture(mod, module.frontPath); + var backTex = ImageUtilities.GetTexture(mod, module.backPath); + + if (_skyboxLayer == -1) _skyboxLayer = LayerMask.NameToLayer("Skybox"); + if (!_unlitShader) _unlitShader = Shader.Find("Unlit/Texture"); + + var mesh = BuildSkySphereFaceMesh(module.useCube ? 1 : 32); + + var skySphere = new GameObject("Sky Sphere"); + skySphere.transform.SetParent(skybox.transform, false); + skySphere.layer = _skyboxLayer; + skySphere.transform.localScale = Vector3.one * 5f; + + BuildSkySphereFace(skySphere, "Right", Quaternion.Euler(0f, 90f, 0f), mesh, rightTex); + BuildSkySphereFace(skySphere, "Left", Quaternion.Euler(0f, 270f, 0f), mesh, leftTex); + BuildSkySphereFace(skySphere, "Top", Quaternion.Euler(270f, 0f, 0f), mesh, topTex); + BuildSkySphereFace(skySphere, "Bottom", Quaternion.Euler(90f, 0f, 0f), mesh, bottomTex); + BuildSkySphereFace(skySphere, "Front", Quaternion.Euler(0f, 0f, 0f), mesh, frontTex); + BuildSkySphereFace(skySphere, "Back", Quaternion.Euler(0f, 180f, 0f), mesh, backTex); + + return skySphere; + } + + public static GameObject BuildSkySphereFace(GameObject skySphere, string name, Quaternion rotation, Mesh mesh, Texture2D tex) + { + if (!tex) + { + Logger.LogError($"Failed to load texture for skybox {name.ToLower()} face"); + return null; + } + + var go = new GameObject(name) + { + layer = _skyboxLayer + }; + + var mf = go.AddComponent(); + mf.sharedMesh = mesh; + + var mat = new Material(_unlitShader) + { + name = $"Sky Sphere {name}", + mainTexture = tex + }; + + var mr = go.AddComponent(); + mr.sharedMaterial = mat; + + var sr = go.AddComponent(); + Delay.RunWhen(() => SkyboxRenderer.s_active.Contains(sr), () => + { + SkyboxRenderer.s_active.Remove(sr); + SkyboxRenderer.s_active.Insert(0, sr); + }); + + go.transform.SetParent(skySphere.transform, false); + go.transform.localRotation = rotation; + go.transform.localScale = Vector3.one; + + return go; + } + + public static Mesh BuildSkySphereFaceMesh(int quadsPerAxis) + { + var mesh = new Mesh + { + name = $"Sky Sphere Face" + }; + + var vertices = new Vector3[(quadsPerAxis + 1) * (quadsPerAxis + 1)]; + var normals = new Vector3[vertices.Length]; + var uvs = new Vector2[vertices.Length]; + var tris = new int[quadsPerAxis * quadsPerAxis * 2 * 3]; + + for (var x = 0; x <= quadsPerAxis; x++) + { + for (var y = 0; y <= quadsPerAxis; y++) + { + var i = y * (quadsPerAxis + 1) + x; + var fx = (float)x / quadsPerAxis; + var fy = (float)y / quadsPerAxis; + vertices[i] = new Vector3(-0.5f + fx, -0.5f + fy, 0.5f).normalized; + normals[i] = -vertices[i].normalized; + uvs[i] = new Vector2(fx, fy); + } + } + + int t = 0; + for (var x = 0; x < quadsPerAxis; x++) + { + for (var y = 0; y < quadsPerAxis; y++) + { + var i0 = (y + 1) * (quadsPerAxis + 1) + (x + 0); + var i1 = (y + 1) * (quadsPerAxis + 1) + (x + 1); + var i2 = (y + 0) * (quadsPerAxis + 1) + (x + 1); + var i3 = (y + 0) * (quadsPerAxis + 1) + (x + 0); + + tris[t++] = i0; + tris[t++] = i1; + tris[t++] = i2; + + tris[t++] = i2; + tris[t++] = i3; + tris[t++] = i0; + } + } + + mesh.vertices = vertices; + mesh.normals = normals; + mesh.uv = uvs; + mesh.triangles = tris; + + return mesh; + } } } \ No newline at end of file diff --git a/NewHorizons/Handlers/SystemCreationHandler.cs b/NewHorizons/Handlers/SystemCreationHandler.cs index 545c0cde..571502e8 100644 --- a/NewHorizons/Handlers/SystemCreationHandler.cs +++ b/NewHorizons/Handlers/SystemCreationHandler.cs @@ -12,15 +12,27 @@ namespace NewHorizons.Handlers { var skybox = SearchUtilities.Find("Skybox/Starfield"); - if (system.Config.skybox?.destroyStarField ?? false) + if (system.Config.Skybox?.destroyStarField ?? false) { Object.Destroy(skybox); } + if (system.Config.Skybox?.rightPath != null || + system.Config.Skybox?.leftPath != null || + system.Config.Skybox?.topPath != null || + system.Config.Skybox?.bottomPath != null || + system.Config.Skybox?.frontPath != null || + system.Config.Skybox?.bottomPath != null) + { + SkyboxBuilder.Make(system.Config.Skybox, system.Mod); + } + +#pragma warning disable CS0618, CS0612 // Type or member is obsolete if (system.Config.skybox?.assetBundle != null && system.Config.skybox?.path != null) { SkyboxBuilder.Make(system.Config.skybox, system.Mod); } +#pragma warning restore CS0618, CS0612 // Type or member is obsolete if (system.Config.enableTimeLoop) {