Skip to content

Instantly share code, notes, and snippets.

@Frooxius
Created January 26, 2021 18:44
Show Gist options
  • Save Frooxius/ced29bc9f326161841cd915c4194278f to your computer and use it in GitHub Desktop.
Save Frooxius/ced29bc9f326161841cd915c4194278f to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using BaseX;
namespace CodeX
{
public static class TextureVariantGenerator
{
public static List<ComputedVariantResult> GenerateVariants(string file, Texture2DVariantDescriptor variantDescriptor, int maxThreads = -1,
VariantGeneratedHandler variantGenerated = null, Predicate<string> variantFilter = null)
{
var results = new List<ComputedVariantResult>();
// generate chain
var variants = variantDescriptor.GenerateCloudChain();
var bitmap = Bitmap2D.Load(file, false, false);
switch(variantDescriptor.TextureCompression)
{
case TextureCompression.RawRGBA:
if (bitmap.Format != TextureFormat.RGBA32 && bitmap.Format != TextureFormat.RGB24 && bitmap.Format != TextureFormat.ARGB32)
bitmap = bitmap.ConvertTo(TextureFormat.RGBA32);
break;
case TextureCompression.BC3nm_Crunched:
case TextureCompression.BC3nm_LZMA:
if (!bitmap.Format.SupportsAlpha())
bitmap = bitmap.ConvertTo(TextureFormat.RGBA32);
bitmap.PackNormalMap();
break;
}
var bitmaps = new List<Bitmap2D>();
foreach (var v in variants)
{
bitmap = bitmap.GetRescaled(new int2(v.Width, v.Height), v.MipMaps, false, v.Filtering);
bitmaps.Add(bitmap);
}
// generate bitmap variants from the end (smallest mipmap), since this is the order in which they're loaded as well
for (int i = variants.Count - 1; i >= 0; i--)
{
var v = variants[i];
var b = bitmaps[i];
if (variantFilter != null && !variantFilter(v.VariantIdentifier))
continue;
// use GUID for the filename, the actual temp filenames have problem on Android with Unity
string generatedFile = Path.Combine(AssetVariantHelper.TempFolder ?? Path.GetTempPath(), Guid.NewGuid().ToString());
switch (v.TextureCompression)
{
case TextureCompression.BC1_Crunched:
if (!b.CrunchCompress(generatedFile, TextureFormat.BC1, false, maxThreads))
throw new Exception($"Could not compress with BC1. Bitmap: {b.ToString()}");
break;
case TextureCompression.BC3_Crunched:
if(!b.CrunchCompress(generatedFile, TextureFormat.BC3, false, maxThreads))
throw new Exception($"Could not compress with BC3. Bitmap: {b.ToString()}");
break;
case TextureCompression.BC3nm_Crunched:
if (!b.CrunchCompress(generatedFile, TextureFormat.BC3, true, maxThreads))
throw new Exception($"Could not compress with BC3. Bitmap: {b.ToString()}");
break;
case TextureCompression.ETC2_RGB_Crunched:
if(!b.CrunchCompress(generatedFile, TextureFormat.ETC2_RGB, false, maxThreads))
throw new Exception($"Could not compress with ETC2_RGB. Bitmap: {b.ToString()}");
break;
case TextureCompression.ETC2_RGBA8_Crunched:
if(!b.CrunchCompress(generatedFile, TextureFormat.ETC2_RGBA8, false, maxThreads))
throw new Exception($"Could not compress with ETC2_RGBA8. Bitmap: {b.ToString()}");
break;
case TextureCompression.BC1_LZMA:
case TextureCompression.BC3_LZMA:
case TextureCompression.BC3nm_LZMA:
case TextureCompression.ETC2_RGB_LZMA:
case TextureCompression.ETC2_RGBA8_LZMA:
case TextureCompression.BC4_LZMA:
case TextureCompression.BC6H_LZMA:
case TextureCompression.BC7_LZMA:
case TextureCompression.ASTC_4x4_LZMA:
case TextureCompression.ASTC_5x5_LZMA:
case TextureCompression.ASTC_6x6_LZMA:
case TextureCompression.ASTC_8x8_LZMA:
case TextureCompression.ASTC_10x10_LZMA:
case TextureCompression.ASTC_12x12_LZMA:
var targetFormat = v.TextureCompression.ToFormat();
if(Bitmap2D.SupportsBlockCompression(targetFormat))
{
var compressed = b.BlockCompress(targetFormat, v.CompressionQuality * 0.01f, maxThreads);
compressed.SaveRaw(generatedFile);
}
else
generatedFile = null;
break;
case TextureCompression.RawRGBA:
generatedFile += ".webp";
b.Save(generatedFile, 200);
break;
default:
throw new Exception("Invalid texture compression: " + v.TextureCompression);
}
var result = new ComputedVariantResult(v.VariantIdentifier, generatedFile);
// null it immediatelly, allowing GC to free it up if possible
bitmaps[i] = null;
results.Add(result);
// raise event for the generated variant immediatelly so any process listening to this can use it up immediatelly
// while others are being generated
variantGenerated?.Invoke(result);
}
return results;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment