module Graphics.LambdaCube.BlendMode where

import Graphics.LambdaCube.Types

-- | Type of texture blend mode.
data LayerBlendType
    = LBT_COLOUR
    | LBT_ALPHA
    deriving (Eq,Ord)

-- TODO: unify blend operation types

-- | Texture blending operations.
data LayerBlendOperation
    = LBO_REPLACE     -- ^ replace all colour with texture with no adjustment
    | LBO_ADD         -- ^ add colour components together
    | LBO_MODULATE    -- ^ multiply colour components together
    | LBO_ALPHA_BLEND -- ^ blend based on texture alpha
    deriving (Eq,Ord)

-- | Extended texture blending operations.
data LayerBlendOperationEx
    = LBX_SOURCE1               -- ^ use source1 without modification
    | LBX_SOURCE2               -- ^ use source2 without modification
    | LBX_MODULATE              -- ^ multiply source1 and source2 together
    | LBX_MODULATE_X2           -- ^ as LBX_MODULATE but brighten afterwards (x2)
    | LBX_MODULATE_X4           -- ^ as LBX_MODULATE but brighten more afterwards (x4)
    | LBX_ADD                   -- ^ add source1 and source2 together
    | LBX_ADD_SIGNED            -- ^ as LBX_ADD, but subtract 0.5 from the result
    | LBX_ADD_SMOOTH            -- ^ as LBX_ADD, but subtract product from the sum
    | LBX_SUBTRACT              -- ^ subtract source2 from source1
    | LBX_BLEND_DIFFUSE_ALPHA   -- ^ use interpolated alpha value from vertices to scale source1, then add source2 scaled by (1-alpha)
    | LBX_BLEND_TEXTURE_ALPHA   -- ^ as LBX_BLEND_DIFFUSE_ALPHA, but use alpha from texture
    | LBX_BLEND_CURRENT_ALPHA   -- ^ as LBX_BLEND_DIFFUSE_ALPHA, but use current alpha from previous stages
    | LBX_BLEND_MANUAL          -- ^ as LBX_BLEND_DIFFUSE_ALPHA but use a constant manual blend value (0.0-1.0)
    | LBX_DOTPRODUCT            -- ^ dot product of color1 and color2
    | LBX_BLEND_DIFFUSE_COLOUR  -- ^ use interpolated color values from vertices to scale source1, then add source2 scaled by (1-color)
    deriving (Eq,Ord)

-- | Sources of values for blending operations.
data LayerBlendSource
    = LBS_CURRENT   -- ^ the colour as built up from previous stages
    | LBS_TEXTURE   -- ^ the colour derived from the texture assigned to this layer
    | LBS_DIFFUSE   -- ^ the interpolated diffuse colour from the vertices
    | LBS_SPECULAR  -- ^ the interpolated specular colour from the vertices
    | LBS_MANUAL    -- ^ a colour supplied manually as a separate argument
    deriving (Eq,Ord)


data LayerBlendModeEx
    = LayerBlendModeEx
    { lbBlendType  :: LayerBlendType        -- ^ The type of blending (colour or alpha)
    , lbOperation  :: LayerBlendOperationEx -- ^ The operation to be applied
    , lbSource1    :: LayerBlendSource      -- ^ The first source of colour/alpha
    , lbSource2    :: LayerBlendSource      -- ^ The second source of colour/alpha
    , lbColourArg1 :: ColourValue           -- ^ Manual colour value for manual source1
    , lbColourArg2 :: ColourValue           -- ^ Manual colour value for manual source2
    , lbAlphaArg1  :: FloatType             -- ^ Manual alpha value for manual source1
    , lbAlphaArg2  :: FloatType             -- ^ Manual alpha value for manual source2
    , lbFactor     :: FloatType             -- ^ Manual blending factor
    }
    deriving (Eq,Ord)

-- | Types of blending that you can specify between an object and the
-- existing contents of the scene.
data SceneBlendType
    = SBT_TRANSPARENT_ALPHA  -- ^ Make the object transparent based on the final alpha values in the texture
    | SBT_TRANSPARENT_COLOUR -- ^ Make the object transparent based on the colour values in the texture (brighter = more opaque)
    | SBT_ADD                -- ^ Add the texture values to the existing scene content
    | SBT_MODULATE           -- ^ Multiply the 2 colours together
    | SBT_REPLACE            -- ^ The default blend mode where source replaces destination
    deriving (Eq,Ord)

-- | Blending factors for manually blending objects with the scene.
data SceneBlendFactor
    = SBF_ONE
    | SBF_ZERO
    | SBF_DEST_COLOUR
    | SBF_SOURCE_COLOUR
    | SBF_ONE_MINUS_DEST_COLOUR
    | SBF_ONE_MINUS_SOURCE_COLOUR
    | SBF_DEST_ALPHA
    | SBF_SOURCE_ALPHA
    | SBF_ONE_MINUS_DEST_ALPHA
    | SBF_ONE_MINUS_SOURCE_ALPHA
    deriving (Eq,Ord)

-- | Blending operations controls how objects are blended into the scene.
data SceneBlendOperation
    = SBO_ADD
    | SBO_SUBTRACT
    | SBO_REVERSE_SUBTRACT
    | SBO_MIN
    | SBO_MAX
    deriving (Eq,Ord)

-- | Converts SceneBlendType to SceneBlendFactor pair
convertSBTtoSBF :: SceneBlendType -> (SceneBlendFactor,SceneBlendFactor)
convertSBTtoSBF SBT_ADD                = (SBF_ONE,SBF_ONE)
convertSBTtoSBF SBT_MODULATE           = (SBF_DEST_COLOUR,SBF_ZERO)
convertSBTtoSBF SBT_TRANSPARENT_COLOUR = (SBF_SOURCE_COLOUR,SBF_ONE_MINUS_SOURCE_COLOUR)
convertSBTtoSBF SBT_TRANSPARENT_ALPHA  = (SBF_SOURCE_ALPHA,SBF_ONE_MINUS_SOURCE_ALPHA)
convertSBTtoSBF SBT_REPLACE            = (SBF_ONE,SBF_ZERO)