--------------------------------------------------------------------------------------
--
-- Copyright (c) Contributors to the Open 3D Engine Project.
-- For complete copyright and license terms please see the LICENSE at the root of this distribution.
--
-- SPDX-License-Identifier: Apache-2.0 OR MIT
--
--
--
----------------------------------------------------------------------------------------------------

function GetMaterialPropertyDependencies()
    return {"opacity.mode", "opacity.alphaSource", "opacity.textureMap"}
end
 
OpacityMode_Opaque = 0
OpacityMode_Cutout = 1
OpacityMode_Blended = 2
OpacityMode_TintedTransparent = 3

AlphaSource_Packed = 0
AlphaSource_Split = 1
AlphaSource_None = 2

function ConfigureAlphaBlending(shaderItem) 
    shaderItem:GetRenderStatesOverride():SetDepthEnabled(true)
    shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero)
    shaderItem:GetRenderStatesOverride():SetBlendEnabled(0, true)
    shaderItem:GetRenderStatesOverride():SetBlendSource(0, BlendFactor_One)
    shaderItem:GetRenderStatesOverride():SetBlendDest(0, BlendFactor_AlphaSourceInverse)
    shaderItem:GetRenderStatesOverride():SetBlendOp(0, BlendOp_Add)
end

function ConfigureDualSourceBlending(shaderItem)
    -- This blend multiplies the dest against color source 1, then adds color source 0.
    shaderItem:GetRenderStatesOverride():SetDepthEnabled(true)
    shaderItem:GetRenderStatesOverride():SetDepthWriteMask(DepthWriteMask_Zero)
    shaderItem:GetRenderStatesOverride():SetBlendEnabled(0, true)
    shaderItem:GetRenderStatesOverride():SetBlendSource(0, BlendFactor_One)
    shaderItem:GetRenderStatesOverride():SetBlendDest(0, BlendFactor_ColorSource1)
    shaderItem:GetRenderStatesOverride():SetBlendOp(0, BlendOp_Add)
end

function ResetAlphaBlending(shaderItem)
    shaderItem:GetRenderStatesOverride():ClearDepthEnabled()
    shaderItem:GetRenderStatesOverride():ClearDepthWriteMask()
    shaderItem:GetRenderStatesOverride():ClearBlendEnabled(0)
    shaderItem:GetRenderStatesOverride():ClearBlendSource(0)
    shaderItem:GetRenderStatesOverride():ClearBlendDest(0)
    shaderItem:GetRenderStatesOverride():ClearBlendOp(0)
end

function Process(context)
    local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode")

    local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS")

    if(opacityMode == OpacityMode_Blended) then
        ConfigureAlphaBlending(forwardPassEDS)
        forwardPassEDS:SetDrawListTagOverride("transparent")
    elseif(opacityMode == OpacityMode_TintedTransparent) then
        ConfigureDualSourceBlending(forwardPassEDS)
        forwardPassEDS:SetDrawListTagOverride("transparent")
    else
        ResetAlphaBlending(forwardPassEDS)
        forwardPassEDS:SetDrawListTagOverride("") -- reset to default draw list
    end
end

function ProcessEditor(context)
    local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode")
    
    local mainVisibility
    if(opacityMode == OpacityMode_Opaque) then
        mainVisibility = MaterialPropertyVisibility_Hidden
    else
        mainVisibility = MaterialPropertyVisibility_Enabled
    end
    
    context:SetMaterialPropertyVisibility("opacity.alphaSource", mainVisibility)
    context:SetMaterialPropertyVisibility("opacity.textureMap", mainVisibility)
    context:SetMaterialPropertyVisibility("opacity.textureMapUv", mainVisibility)
    context:SetMaterialPropertyVisibility("opacity.factor", mainVisibility)

    if(opacityMode == OpacityMode_Blended or opacityMode == OpacityMode_TintedTransparent) then
        context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Enabled)
    else
        context:SetMaterialPropertyVisibility("opacity.alphaAffectsSpecular", MaterialPropertyVisibility_Hidden)
    end

    if(mainVisibility == MaterialPropertyVisibility_Enabled) then
        local alphaSource = context:GetMaterialPropertyValue_enum("opacity.alphaSource")

        if (opacityMode == OpacityMode_Cutout and alphaSource == AlphaSource_None) then
            context:SetMaterialPropertyVisibility("opacity.factor", MaterialPropertyVisibility_Hidden)
        end

        if(alphaSource ~= AlphaSource_Split) then
            context:SetMaterialPropertyVisibility("opacity.textureMap", MaterialPropertyVisibility_Hidden)
            context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Hidden)
        else
            local textureMap = context:GetMaterialPropertyValue_Image("opacity.textureMap")

            if(nil == textureMap) then
                context:SetMaterialPropertyVisibility("opacity.textureMapUv", MaterialPropertyVisibility_Disabled)
                context:SetMaterialPropertyVisibility("opacity.factor", MaterialPropertyVisibility_Disabled)
            end
        end
    end
end
