using System.IO;
using System.Threading.Tasks;
using MyInfoMate.Vr.Net;
using UnityEngine;
namespace MyInfoMate.Vr.Menu
{
///
/// Ce qu'il faut savoir pour faire d'une équirectangulaire un ciel — mis en commun
/// entre la lecture 360 d'une section () et le fond immersif
/// d'une visite ().
///
/// Deux pièges vivent ici, et une seule fois. Le shader absent du build (ciel
/// magenta sur le casque, correct dans l'éditeur) et la texture décodée en RGBA32
/// (134 Mo pour une 8192×4096) sont exactement le genre de choses qu'on corrige d'un
/// côté en oubliant l'autre.
///
public static class PanoramicSky
{
const string PanoramicShader = "Skybox/Panoramic";
///
/// Le matériau de ciel, ou null si le shader n'a pas survécu au build.
///
/// ⚠️ Skybox/Panoramic est construit au runtime : aucune scène ne le
/// référence, donc le build l'élimine s'il n'est pas dans Project Settings →
/// Graphics → Always Included Shaders. Le symptôme est un ciel magenta sur le
/// casque, et rien du tout dans l'éditeur — c'est le piège déjà payé avec glTFast.
///
public static Material CreateMaterial()
{
var shader = Shader.Find(PanoramicShader);
if (shader == null)
{
Debug.LogError($"[Sky] Shader « {PanoramicShader} » absent du build. " +
"Project Settings → Graphics → Always Included Shaders.");
return null;
}
var material = new Material(shader);
material.SetFloat("_Mapping", 1f); // Latitude-longitude (équirectangulaire)
material.SetFloat("_ImageType", 0f); // 360°, pas 180°
return material;
}
///
/// La texture d'une image équirectangulaire mise en cache, ou null.
///
/// ⚠️ Mémoire. LoadImage décode en RGBA32 : une 8192×4096 occupe
/// 134 Mo de mémoire graphique, pour une seule image, sur un casque qui en
/// a quelques Go partagés avec le système. La compression matérielle (ASTC sur
/// Quest) divise ça par six à huit, au prix d'une seconde au chargement et d'une
/// perte invisible sur une photo. C'est elle qui décide si on peut enchaîner
/// plusieurs 360 sans que l'app se fasse tuer.
///
public static async Task LoadEquirectangularAsync(ApiClient client, string url)
{
var path = await ContentCache.MediaPathAsync(client, url);
if (path == null) return null;
// Pas de mipmaps : une équirectangulaire est vue à taille réelle, et les
// niveaux intermédiaires coûteraient un tiers de mémoire pour rien.
var texture = new Texture2D(2, 2, TextureFormat.RGBA32, mipChain: false);
if (!texture.LoadImage(File.ReadAllBytes(path)))
{
Debug.LogError($"[Sky] Image illisible : {url}");
Object.Destroy(texture);
return null;
}
// Sans cela, la couture verticale du panorama apparaît comme un trait net.
texture.wrapModeU = TextureWrapMode.Repeat;
texture.wrapModeV = TextureWrapMode.Clamp;
texture.Compress(highQuality: true);
texture.Apply(updateMipmaps: false, makeNoLongerReadable: true);
return texture;
}
}
}