private static void ComputeCompressionScalers(ProceduralTexture2D target)
 {
     target.compressionScalers = Vector4.one;
     if (target.compressionQuality != ProceduralTexture2D.CompressionLevel.None && target.type != ProceduralTexture2D.TextureType.Other)
     {
         target.compressionScalers.x = 1.0f / target.colorSpaceVector1.magnitude;
         target.compressionScalers.y = 1.0f / target.colorSpaceVector2.magnitude;
         target.compressionScalers.z = 1.0f / target.colorSpaceVector3.magnitude;
     }
 }
    private static void PreprocessData(ProceduralTexture2D target)
    {
        if (target.input == null)
        {
            return;
        }

        // Init progress bar
        stepCounter = 0;
        totalSteps  = (target.type != ProceduralTexture2D.TextureType.Other ? 4 : 0) + (target.type != ProceduralTexture2D.TextureType.Other ? 9 : 12) + 1;
        EditorUtility.DisplayProgressBar("Pre-processing Procedural Texture Data", target.name, (float)stepCounter / (totalSteps - 1));

        // Section 1.4 Improvement: using a decorrelated color space for Color RGB and Normal XYZ textures
        TextureFormat inputFormat  = TextureFormat.RGB24;
        TextureData   albedoData   = TextureToTextureData(target.input, ref inputFormat);
        TextureData   decorrelated = new TextureData(albedoData);

        if (target.type != ProceduralTexture2D.TextureType.Other)
        {
            DecorrelateColorSpace(ref albedoData, ref decorrelated, ref target.colorSpaceVector1, ref target.colorSpaceVector2, ref target.colorSpaceVector3, ref target.colorSpaceOrigin, target.name);
        }
        ComputeCompressionScalers(target);

        // Perform precomputations
        TextureData Tinput = new TextureData(decorrelated.width, decorrelated.height);
        TextureData invT   = new TextureData(LUT_WIDTH, (int)(Mathf.Log((float)Tinput.width) / Mathf.Log(2.0f))); // Height = Number of prefiltered LUT levels

        List <int> channelsToProcess = new List <int> {
            0, 1, 2
        };

        if ((target.type == ProceduralTexture2D.TextureType.Color && target.includeAlpha == true) || target.type == ProceduralTexture2D.TextureType.Other)
        {
            channelsToProcess.Add(3);
        }
        Precomputations(ref decorrelated, channelsToProcess, ref Tinput, ref invT, target.name);

        RescaleForCompression(target, ref Tinput);
        EditorUtility.DisplayProgressBar("Pre-processing Procedural Texture Data", target.name, (float)stepCounter++ / (totalSteps - 1));

        // Serialize precomputed data and setup material
        FinalizePrecomputedTextures(ref inputFormat, target, ref Tinput, ref invT);

        target.memoryUsageBytes = target.Tinput.GetRawTextureData().Length + target.invT.GetRawTextureData().Length;

        EditorUtility.ClearProgressBar();

        // Update current applied settings
        target.currentInput              = target.input;
        target.currentIncludeAlpha       = target.includeAlpha;
        target.currentGenerateMipMaps    = target.generateMipMaps;
        target.currentFilterMode         = target.filterMode;
        target.currentAnisoLevel         = target.anisoLevel;
        target.currentCompressionQuality = target.compressionQuality;
    }
    static void FinalizePrecomputedTextures(ref TextureFormat inputFormat, ProceduralTexture2D target, ref TextureData Tinput, ref TextureData invT)
    {
        // Serialize precomputed data as new subasset texture. Reuse existing texture if possible to avoid breaking texture references in shadergraph.
        if (target.Tinput == null)
        {
            target.Tinput = new Texture2D(Tinput.width, Tinput.height, inputFormat, target.generateMipMaps, true);
            AssetDatabase.AddObjectToAsset(target.Tinput, target);
        }
        target.Tinput.Resize(Tinput.width, Tinput.height, inputFormat, target.generateMipMaps);
        target.Tinput.name = target.input.name + "_T";
        target.Tinput.SetPixels(Tinput.data);
        target.Tinput.wrapMode   = TextureWrapMode.Repeat;
        target.Tinput.filterMode = target.filterMode;
        target.Tinput.anisoLevel = target.anisoLevel;
        target.Tinput.Apply();
        if (target.compressionQuality != ProceduralTexture2D.CompressionLevel.None)
        {
            if (target.compressionQuality == ProceduralTexture2D.CompressionLevel.HighQuality)
            {
                EditorUtility.CompressTexture(target.Tinput, TextureFormat.BC7, (int)target.compressionQuality);
            }
            else if (inputFormat == TextureFormat.RGBA32)
            {
                EditorUtility.CompressTexture(target.Tinput, TextureFormat.DXT5, (int)target.compressionQuality);
            }
            else
            {
                EditorUtility.CompressTexture(target.Tinput, TextureFormat.DXT1, (int)target.compressionQuality);
            }
        }
        target.Tinput.Apply();

        if (target.invT == null)
        {
            target.invT = new Texture2D(invT.width, invT.height, inputFormat, false, true);
            AssetDatabase.AddObjectToAsset(target.invT, target);
        }
        target.invT.Resize(invT.width, invT.height, inputFormat, false);
        target.invT.name       = target.input.name + "_invT";
        target.invT.wrapMode   = TextureWrapMode.Clamp;
        target.invT.filterMode = FilterMode.Bilinear;
        target.invT.SetPixels(invT.data);
        target.invT.Apply();

        // Update asset database
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }
 private bool UnappliedSettingChanges(ProceduralTexture2D target)
 {
     if (target.currentInput != target.input ||
         target.currentIncludeAlpha != target.includeAlpha ||
         target.currentGenerateMipMaps != target.generateMipMaps ||
         target.currentFilterMode != target.filterMode ||
         target.currentAnisoLevel != target.anisoLevel ||
         target.currentCompressionQuality != target.compressionQuality)
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
    private void CopyInputTextureImportType(ProceduralTexture2D target)
    {
        string          path          = AssetDatabase.GetAssetPath(target.input);
        TextureImporter inputImporter = (TextureImporter)TextureImporter.GetAtPath(path);

        switch (inputImporter.textureType)
        {
        case TextureImporterType.NormalMap:
            target.type = ProceduralTexture2D.TextureType.Normal;
            break;

        default:
            target.type = ProceduralTexture2D.TextureType.Color;
            break;
        }
    }
    private static void RescaleForCompression(ProceduralTexture2D target, ref TextureData Tinput)
    {
        int channelCount = (target.type == ProceduralTexture2D.TextureType.Color && target.includeAlpha == true) || target.type == ProceduralTexture2D.TextureType.Other ?
                           4 : 3;

        // If we use DXT compression
        // we need to rescale the Gaussian channels (see Section 1.6)
        if (target.compressionQuality != ProceduralTexture2D.CompressionLevel.None && target.type != ProceduralTexture2D.TextureType.Other)
        {
            for (int y = 0; y < Tinput.height; y++)
            {
                for (int x = 0; x < Tinput.width; x++)
                {
                    for (int i = 0; i < channelCount; i++)
                    {
                        float v = Tinput.GetColor(x, y)[i];
                        v = (v - 0.5f) / target.compressionScalers[i] + 0.5f;
                        Tinput.GetColorRef(x, y)[i] = v;
                    }
                }
            }
        }
    }