/// Returns an ExportFileReference given an absolute http:// uri.
 /// Depending on settings, this may become a relative reference in the gltf.
 private ExportFileReference CreateExportFileReferenceFromHttp(string httpUri)
 {
     if (!AllowHttpUri)
     {
         string localPath = HostedUriToLocalFilename(httpUri);
         if (localPath != null)
         {
             return(ExportFileReference.GetOrCreateSafeLocal(
                        G.m_disambiguationContext,
                        Path.GetFileName(localPath), Path.GetDirectoryName(localPath),
                        "Brush_" + Path.GetFileName(localPath)));
         }
         Debug.LogWarning($"Cannot convert {httpUri} to local");
     }
     return(ExportFileReference.CreateHttp(httpUri));
 }
    // Pass:
    //   meshNamespace - A string used as the "namespace" of the mesh that owns this material.
    //     Useful for uniquifying names (texture file names, material names, ...) in a
    //     human-friendly way.
    //   hack - attributes of some mesh that uses this material
    private void ExportMaterial(
        SceneStatePayload payload,
        string meshNamespace,
        IExportableMaterial exportableMaterial,
        GlTF_Attributes hack)
    {
        //
        // Set culling and blending modes.
        //
        GlTF_Technique.States states = new GlTF_Technique.States();
        m_techniqueStates[exportableMaterial] = states;
        // Everyone gets depth test
        states.enable = new[] { GlTF_Technique.Enable.DEPTH_TEST }.ToList();

        if (exportableMaterial.EnableCull)
        {
            states.enable.Add(GlTF_Technique.Enable.CULL_FACE);
        }

        if (exportableMaterial.BlendMode == ExportableMaterialBlendMode.AdditiveBlend)
        {
            states.enable.Add(GlTF_Technique.Enable.BLEND);
            // Blend array format: [srcRGB, dstRGB, srcAlpha, dstAlpha]
            states.functions["blendFuncSeparate"] =
                new GlTF_Technique.Value(G, new Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // Additive.
            states.functions["depthMask"] = new GlTF_Technique.Value(G, false);   // No depth write.
            // Note: If we switch bloom to use LDR color, adding the alpha channels won't do.
            // GL_MIN would be a good choice for alpha, but it's unsupported by glTF 1.0.
        }
        else if (exportableMaterial.BlendMode == ExportableMaterialBlendMode.AlphaBlend)
        {
            states.enable.Add(GlTF_Technique.Enable.BLEND);
            // Blend array format: [srcRGB, dstRGB, srcAlpha, dstAlpha]
            // These enum values correspond to: [ONE, ONE_MINUS_SRC_ALPHA, ONE, ONE_MINUS_SRC_ALPHA]
            states.functions["blendFuncSeparate"] =
                new GlTF_Technique.Value(G, new Vector4(1.0f, 771.0f, 1.0f, 771.0f)); // Blend.
            states.functions["depthMask"] = new GlTF_Technique.Value(G, true);
        }
        else
        {
            // Standard z-buffering: Enable depth write.
            states.functions["depthMask"] = new GlTF_Technique.Value(G, true);
        }

        // First add the material, then export any per-material attributes, such as shader uniforms.
        AddMaterialWithDependencies(exportableMaterial, meshNamespace, hack);

        // Add lighting for this material.
        AddLights(exportableMaterial, payload);

        //
        // Export shader/material parameters.
        //

        foreach (var kvp in exportableMaterial.FloatParams)
        {
            ExportShaderUniform(exportableMaterial, kvp.Key, kvp.Value);
        }
        foreach (var kvp in exportableMaterial.ColorParams)
        {
            ExportShaderUniform(exportableMaterial, kvp.Key, kvp.Value);
        }
        foreach (var kvp in exportableMaterial.VectorParams)
        {
            ExportShaderUniform(exportableMaterial, kvp.Key, kvp.Value);
        }
        foreach (var kvp in exportableMaterial.TextureSizes)
        {
            float width  = kvp.Value.x;
            float height = kvp.Value.y;
            ExportShaderUniform(exportableMaterial, kvp.Key + "_TexelSize",
                                new Vector4(1 / width, 1 / height, width, height));
        }

        //
        // Export textures.
        //
        foreach (var kvp in exportableMaterial.TextureUris)
        {
            string textureName = kvp.Key;
            string textureUri  = kvp.Value;

            ExportFileReference fileRef;
            if (ExportFileReference.IsHttp(textureUri))
            {
                // Typically this happens for textures used by BrushDescriptor materials
                fileRef = CreateExportFileReferenceFromHttp(textureUri);
            }
            else
            {
                fileRef = ExportFileReference.GetOrCreateSafeLocal(
                    G.m_disambiguationContext, textureUri, exportableMaterial.UriBase,
                    $"{meshNamespace}_{Path.GetFileName(textureUri)}");
            }

            AddTextureToMaterial(exportableMaterial, textureName, fileRef);
        }
    }