// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Standard Library
using System;
// Unity
using UnityEditor;
using UnityEngine;
namespace AWS.GameKit.Editor.Utils
{
///
/// A lazy loading wrapper for an asset stored in a "Resources" folder.
///
/// The asset is loaded and cached the first time Get() is called.
///
/// For details on Unity's special "Resources" folders and how to load data from them, please read: https://docs.unity3d.com/ScriptReference/Resources.Load.html
///
/// The type to load the asset as.
public class LazyLoadedResourceForCurrentResolution : IGettable where T : UnityEngine.Object
{
public delegate T ResourceLoader(string path);
private enum ResourceSize
{
ONE_K,
TWO_K,
FOUR_K,
EIGHT_K
}
private const string TWO_K_POSTFIX = "-2k";
private const string FOUR_K_POSTFIX = "-4k";
private const string EIGHT_K_POSTFIX = "-8k";
private readonly string[] _paths = new string[Enum.GetNames(typeof(ResourceSize)).Length];
private Lazy _cachedResource;
private Resolution _resolution;
private ResourceLoader _resourceLoader;
///
/// Create a new LazyLoadedResource for the specified resource path.
///
/// The path to the resource relative to any Resources folder. See official docs for details: https://docs.unity3d.com/ScriptReference/Resources.Load.html
/// A Unity object that specifies the height and width of the desktop.
/// A delegate that takes a string and returns a type T. This delegate is used to perform that actual resource loading.
public LazyLoadedResourceForCurrentResolution(string path, Resolution resolution, ResourceLoader resourceLoader)
{
_resolution = resolution;
_resourceLoader = resourceLoader;
_paths[(int)ResourceSize.ONE_K] = path;
_paths[(int)ResourceSize.TWO_K] = path + TWO_K_POSTFIX;
_paths[(int)ResourceSize.FOUR_K] = path + FOUR_K_POSTFIX;
_paths[(int)ResourceSize.EIGHT_K] = path + EIGHT_K_POSTFIX;
_cachedResource = new Lazy(() => LoadResource(IdealResolution()));
}
///
/// Create a new LazyLoadedResource for the specified resource path.
///
/// The path to the resource relative to any Resources folder. See official docs for details: https://docs.unity3d.com/ScriptReference/Resources.Load.html
public LazyLoadedResourceForCurrentResolution(string path) : this(path, Screen.currentResolution, (path) => (T)AssetDatabase.LoadAssetAtPath(path, typeof(T))) { }
///
/// Get the resource. Cache the resource if this is the first time calling Get().
///
public T Get()
{
return _cachedResource.Value;
}
private ResourceSize IdealResolution()
{
// get the longest edge, in case the monitor is rotated - landscape vs portrait
double longestEdge = Math.Max(_resolution.width, _resolution.height);
// convert to kilos and then determine how many we have
double numberOfK = Math.Round(longestEdge / 1000.0);
if (numberOfK <= 1)
{
return ResourceSize.ONE_K;
}
else if (numberOfK <= 2)
{
return ResourceSize.TWO_K;
}
else if (numberOfK <= 4)
{
return ResourceSize.FOUR_K;
}
else
{
return ResourceSize.EIGHT_K;
}
}
private T LoadResource(ResourceSize idealResourceSize)
{
int size = (int)idealResourceSize;
T resource = null;
// attempt to load the current ideal resolution for the resource, if nothing loads then decrement and attempt the next best resolution
do
{
resource = _resourceLoader(_paths[size]);
--size;
}
while (size >= (int)ResourceSize.ONE_K && resource == null);
return resource;
}
}
}