mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Cache inverted images
This commit is contained in:
parent
493365155f
commit
540a501b9a
@ -150,10 +150,12 @@ namespace NewHorizons.Builder.Props
|
||||
// to avoid doing a "is every element in the array `textures` not null" check every time a texture finishes loading
|
||||
int displaySlidesLoaded = 0;
|
||||
imageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int index) =>
|
||||
(Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
slideCollection.slides[index]._image = ImageUtilities.Invert(tex);
|
||||
var time = DateTime.Now;
|
||||
|
||||
slideCollection.slides[index]._image = ImageUtilities.Invert(mod, tex, originalPath);
|
||||
NHLogger.LogVerbose($"Slide reel make reel invert texture {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
// Track the first 15 to put on the slide reel object
|
||||
if (index < textures.Length)
|
||||
{
|
||||
@ -174,6 +176,8 @@ namespace NewHorizons.Builder.Props
|
||||
slidesFront.material.name = reelTexture.name;
|
||||
}
|
||||
}
|
||||
|
||||
NHLogger.LogVerbose($"Slide reel make reel texture {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
}
|
||||
);
|
||||
|
||||
@ -301,7 +305,12 @@ namespace NewHorizons.Builder.Props
|
||||
slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null
|
||||
|
||||
var imageLoader = AddAsyncLoader(projectorObj, mod, info.slides, ref slideCollection);
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = ImageUtilities.Invert(tex); });
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
slideCollection.slides[index]._image = ImageUtilities.Invert(mod, tex, originalPath);
|
||||
NHLogger.LogVerbose($"Slide reel invert time {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
});
|
||||
|
||||
slideCollectionContainer.slideCollection = slideCollection;
|
||||
|
||||
@ -340,7 +349,12 @@ namespace NewHorizons.Builder.Props
|
||||
slideCollection.streamingAssetIdentifier = string.Empty; // NREs if null
|
||||
|
||||
var imageLoader = AddAsyncLoader(g, mod, info.slides, ref slideCollection);
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index) => { slideCollection.slides[index]._image = tex; });
|
||||
imageLoader.imageLoadedEvent.AddListener((Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
slideCollection.slides[index]._image = tex;
|
||||
NHLogger.LogVerbose($"Slide reel set time {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
});
|
||||
|
||||
// attach a component to store all the data for the slides that play when a vision torch scans this target
|
||||
var target = g.AddComponent<VisionTorchTarget>();
|
||||
@ -395,8 +409,9 @@ namespace NewHorizons.Builder.Props
|
||||
// to avoid doing a "is every element in the array `slideCollection.slides` not null" check every time a texture finishes loading
|
||||
int displaySlidesLoaded = 0;
|
||||
imageLoader.imageLoadedEvent.AddListener(
|
||||
(Texture2D tex, int index) =>
|
||||
(Texture2D tex, int index, string originalPath) =>
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
slideCollection.slides[index]._image = tex;
|
||||
|
||||
if (Interlocked.Increment(ref displaySlidesLoaded) == slides.Length)
|
||||
@ -404,6 +419,7 @@ namespace NewHorizons.Builder.Props
|
||||
mindSlideProjector.enabled = true;
|
||||
visionBeamEffect.SetActive(true);
|
||||
}
|
||||
NHLogger.LogVerbose($"Slide reel another set time {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
}
|
||||
);
|
||||
|
||||
@ -429,6 +445,7 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
private static ImageUtilities.AsyncImageLoader AddAsyncLoader(GameObject gameObject, IModBehaviour mod, SlideInfo[] slides, ref SlideCollection slideCollection)
|
||||
{
|
||||
var invertedImageLoader = gameObject.AddComponent<ImageUtilities.AsyncImageLoader>();
|
||||
var imageLoader = gameObject.AddComponent<ImageUtilities.AsyncImageLoader>();
|
||||
for (int i = 0; i < slides.Length; i++)
|
||||
{
|
||||
@ -438,10 +455,16 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
if (string.IsNullOrEmpty(slideInfo.imagePath))
|
||||
{
|
||||
imageLoader.imageLoadedEvent?.Invoke(Texture2D.blackTexture, i);
|
||||
imageLoader.imageLoadedEvent?.Invoke(Texture2D.blackTexture, i, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
invertedImageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, "invertedSlideReelCache", slideInfo.imagePath)));
|
||||
invertedImageLoader.imageLoadedEvent.AddListener((Texture2D t, int i, string s) =>
|
||||
{
|
||||
var path = "\\" + Path.Combine(Path.GetFileName(Path.GetDirectoryName(mod.ModHelper.Manifest.ModFolderPath)), slides[i].imagePath) + " > invert";
|
||||
ImageUtilities.TrackCachedTexture(path, t);
|
||||
});
|
||||
imageLoader.PathsToLoad.Add((i, Path.Combine(mod.ModHelper.Manifest.ModFolderPath, slideInfo.imagePath)));
|
||||
}
|
||||
|
||||
@ -449,6 +472,8 @@ namespace NewHorizons.Builder.Props
|
||||
|
||||
slideCollection.slides[i] = slide;
|
||||
}
|
||||
invertedImageLoader.Start();
|
||||
imageLoader.Start();
|
||||
|
||||
return imageLoader;
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using NewHorizons.Utility.OWML;
|
||||
using OWML.Common;
|
||||
using OWML.ModHelper;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@ -19,14 +20,14 @@ namespace NewHorizons.Utility.Files
|
||||
// key is path + applied effects
|
||||
private static readonly Dictionary<string, Texture> _textureCache = new();
|
||||
public static bool CheckCachedTexture(string key, out Texture existingTexture) => _textureCache.TryGetValue(key, out existingTexture);
|
||||
public static void TrackCachedTexture(string key, Texture texture) => _textureCache.Add(key, texture);
|
||||
public static void TrackCachedTexture(string key, Texture texture) => _textureCache[key] = texture;
|
||||
|
||||
private static string GetKey(string path) => path.Substring(Main.Instance.ModHelper.OwmlConfig.ModsPath.Length);
|
||||
public static string GetKey(string path) => path.Substring(Main.Instance.ModHelper.OwmlConfig.ModsPath.Length);
|
||||
|
||||
public static bool IsTextureLoaded(IModBehaviour mod, string filename)
|
||||
{
|
||||
var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, filename);
|
||||
var key = GetKey(path);
|
||||
var key = GetKey(path).Replace('\\', '/');
|
||||
return _textureCache.ContainsKey(key);
|
||||
}
|
||||
|
||||
@ -101,7 +102,7 @@ namespace NewHorizons.Utility.Files
|
||||
/// used specifically for projected slides.
|
||||
/// also adds a border (to prevent weird visual bug) and makes the texture linear (otherwise the projected image is too bright).
|
||||
/// </summary>
|
||||
public static Texture2D Invert(Texture2D texture)
|
||||
public static Texture2D Invert(IModBehaviour mod, Texture2D texture, string originalPath)
|
||||
{
|
||||
var key = $"{texture.name} > invert";
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture)) return (Texture2D)existingTexture;
|
||||
@ -137,6 +138,14 @@ namespace NewHorizons.Utility.Files
|
||||
|
||||
_textureCache.Add(key, newTexture);
|
||||
|
||||
if (!string.IsNullOrEmpty(originalPath))
|
||||
{
|
||||
var path = Path.Combine(mod.ModHelper.Manifest.ModFolderPath, "invertedSlideReelCache", originalPath.Replace(mod.ModHelper.Manifest.ModFolderPath, ""));
|
||||
NHLogger.LogVerbose($"Caching inverted image to {path}");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
File.WriteAllBytes(path, newTexture.EncodeToPNG());
|
||||
}
|
||||
|
||||
return newTexture;
|
||||
}
|
||||
|
||||
@ -432,12 +441,49 @@ namespace NewHorizons.Utility.Files
|
||||
return sprite;
|
||||
}
|
||||
|
||||
public class SingletonAsyncImageLoader : MonoBehaviour
|
||||
{
|
||||
public static SingletonAsyncImageLoader Instance { get; private set; }
|
||||
|
||||
private Queue<AsyncImageLoader> loaders = new();
|
||||
|
||||
private bool _isLoading;
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void Load(AsyncImageLoader loader)
|
||||
{
|
||||
loaders.Enqueue(loader);
|
||||
if (!_isLoading)
|
||||
{
|
||||
StartCoroutine(Run());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator Run()
|
||||
{
|
||||
NHLogger.Log("Loading slide reels");
|
||||
_isLoading = true;
|
||||
while (loaders.Count > 0)
|
||||
{
|
||||
var loader = loaders.Dequeue();
|
||||
yield return loader.DownloadTextures();
|
||||
NHLogger.Log($"Finished a slide reel, {loaders.Count} left");
|
||||
}
|
||||
_isLoading = false;
|
||||
NHLogger.Log("Done loading slide reels");
|
||||
}
|
||||
}
|
||||
|
||||
// Modified from https://stackoverflow.com/a/69141085/9643841
|
||||
public class AsyncImageLoader : MonoBehaviour
|
||||
{
|
||||
public List<(int index, string path)> PathsToLoad { get; private set; } = new();
|
||||
|
||||
public class ImageLoadedEvent : UnityEvent<Texture2D, int> { }
|
||||
public class ImageLoadedEvent : UnityEvent<Texture2D, int, string> { }
|
||||
public ImageLoadedEvent imageLoadedEvent = new();
|
||||
|
||||
private readonly object _lockObj = new();
|
||||
@ -449,13 +495,25 @@ namespace NewHorizons.Utility.Files
|
||||
// and make use of that for at least for projector stuff (require player to be in the same sector as the slides
|
||||
// for them to start loading, and unload when the player leaves)
|
||||
|
||||
void Start()
|
||||
private bool _started;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
imageLoadedEvent.AddListener(OnImageLoaded);
|
||||
StartCoroutine(DownloadTextures());
|
||||
if (_started) return;
|
||||
|
||||
_started = true;
|
||||
|
||||
if (SingletonAsyncImageLoader.Instance == null)
|
||||
{
|
||||
Main.Instance.gameObject.AddComponent<SingletonAsyncImageLoader>();
|
||||
}
|
||||
|
||||
private void OnImageLoaded(Texture texture, int index)
|
||||
NHLogger.LogVerbose("Loading new slide reel");
|
||||
imageLoadedEvent.AddListener(OnImageLoaded);
|
||||
SingletonAsyncImageLoader.Instance.Load(this);
|
||||
}
|
||||
|
||||
private void OnImageLoaded(Texture texture, int index, string originalPath)
|
||||
{
|
||||
lock (_lockObj)
|
||||
{
|
||||
@ -469,11 +527,13 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator DownloadTextures()
|
||||
internal IEnumerator DownloadTextures()
|
||||
{
|
||||
foreach (var (index, path) in PathsToLoad)
|
||||
{
|
||||
yield return StartCoroutine(DownloadTexture(path, index));
|
||||
NHLogger.Log($"Loaded slide reel {index} of {PathsToLoad.Count}");
|
||||
|
||||
yield return DownloadTexture(path, index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,7 +543,7 @@ namespace NewHorizons.Utility.Files
|
||||
if (_textureCache.TryGetValue(key, out var existingTexture))
|
||||
{
|
||||
NHLogger.LogVerbose($"Already loaded image {index}:{url}");
|
||||
imageLoadedEvent?.Invoke((Texture2D)existingTexture, index);
|
||||
imageLoadedEvent?.Invoke((Texture2D)existingTexture, index, url);
|
||||
yield break;
|
||||
}
|
||||
|
||||
@ -517,7 +577,9 @@ namespace NewHorizons.Utility.Files
|
||||
}
|
||||
|
||||
yield return null;
|
||||
imageLoadedEvent?.Invoke(texture, index);
|
||||
var time = DateTime.Now;
|
||||
imageLoadedEvent?.Invoke(texture, index, url);
|
||||
NHLogger.LogVerbose($"Slide reel event? {(DateTime.Now - time).TotalMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user