2022-10-16 13:02:42 +02:00
// Copyright 2022 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ebiten
import (
"fmt"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
)
// Blend is a blending way of the source color and the destination color.
//
2022-10-17 04:20:15 +02:00
// The final color is calculated like this:
//
// c_src: source RGB values
// c_dst: destination RGB values
// c_out: result RGB values
// α _src: source alpha values
// α _dst: destination alpha values
// α _out: result alpha values
//
// c_out = BlendOperationRGB((BlendFactorSourceRGB) × c_src, (BlendFactorDestinationRGB) × c_dst)
// α _out = BlendOperationAlpha((BlendFactorSourceAlpha) × α _src, (BlendFactorDestinationAlpha) × α _dst)
//
// A blend factor is a factor for source and color destination color values.
// The default is source-over (regular alpha blending).
//
// A blend operation is a binary operator of a source color and a destination color.
// The default is adding.
2022-10-16 13:02:42 +02:00
type Blend struct {
2022-10-16 17:49:56 +02:00
// BlendFactorSourceRGB is a factor for source RGB values.
BlendFactorSourceRGB BlendFactor
2022-10-16 13:02:42 +02:00
// BlendFactorSourceAlpha is a factor for source alpha values.
BlendFactorSourceAlpha BlendFactor
2022-10-16 17:49:56 +02:00
// BlendFactorDestinationRGB is a factor for destination RGB values.
BlendFactorDestinationRGB BlendFactor
2022-10-16 13:02:42 +02:00
// BlendFactorDestinationAlpha is a factor for destination apha values.
BlendFactorDestinationAlpha BlendFactor
2022-10-16 17:49:56 +02:00
// BlendOperationRGB is an operation for source and destination RGB values.
BlendOperationRGB BlendOperation
2022-10-16 13:02:42 +02:00
// BlendOperationAlpha is an operation for source and destination alpha values.
BlendOperationAlpha BlendOperation
}
2023-08-20 09:19:04 +02:00
var (
defaultBlendInternalBlend = graphicsdriver . Blend {
BlendFactorSourceRGB : BlendFactorDefault . internalBlendFactor ( true ) ,
BlendFactorSourceAlpha : BlendFactorDefault . internalBlendFactor ( true ) ,
BlendFactorDestinationRGB : BlendFactorDefault . internalBlendFactor ( false ) ,
BlendFactorDestinationAlpha : BlendFactorDefault . internalBlendFactor ( false ) ,
BlendOperationRGB : BlendOperationAdd . internalBlendOperation ( ) ,
BlendOperationAlpha : BlendOperationAdd . internalBlendOperation ( ) ,
}
)
2022-10-16 13:02:42 +02:00
func ( b Blend ) internalBlend ( ) graphicsdriver . Blend {
2023-08-20 09:19:04 +02:00
// A shortcut for the most common blend.
if b == ( Blend { } ) {
return defaultBlendInternalBlend
}
2022-10-16 13:02:42 +02:00
return graphicsdriver . Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : b . BlendFactorSourceRGB . internalBlendFactor ( true ) ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : b . BlendFactorSourceAlpha . internalBlendFactor ( true ) ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : b . BlendFactorDestinationRGB . internalBlendFactor ( false ) ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : b . BlendFactorDestinationAlpha . internalBlendFactor ( false ) ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : b . BlendOperationRGB . internalBlendOperation ( ) ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : b . BlendOperationAlpha . internalBlendOperation ( ) ,
}
}
// BlendFactor is a factor for source and destination color values.
type BlendFactor byte
const (
// BlendFactorDefault is the default factor value.
// The actual value depends on which source or destination this value is used.
BlendFactorDefault BlendFactor = iota
2022-10-17 04:25:58 +02:00
// BlendFactorZero is a factor:
//
// 0
2022-10-16 13:02:42 +02:00
BlendFactorZero
2022-10-17 04:25:58 +02:00
// BlendFactorOne is a factor:
//
// 1
2022-10-16 13:02:42 +02:00
BlendFactorOne
2022-10-17 04:25:58 +02:00
// BlendFactorSourceColor is a factor:
//
// (source RGBA)
BlendFactorSourceColor
// BlendFactorOneMinusSourceColor is a factor:
//
// 1 - (source color)
BlendFactorOneMinusSourceColor
// BlendFactorSourceAlpha is a factor:
//
// (source alpha)
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha
2022-10-17 04:25:58 +02:00
// BlendFactorOneMinusSourceAlpha is a factor:
//
// 1 - (source alpha)
2022-10-16 13:02:42 +02:00
BlendFactorOneMinusSourceAlpha
2022-10-17 04:25:58 +02:00
// BlendFactorDestinationColor is a factor:
//
// (destination RGBA)
2022-10-16 18:00:02 +02:00
BlendFactorDestinationColor
2022-10-17 04:25:58 +02:00
// BlendFactorOneMinusDestinationColor is a factor:
//
// 1 - (destination RGBA)
BlendFactorOneMinusDestinationColor
// BlendFactorDestinationAlpha is a factor:
//
// (destination alpha)
BlendFactorDestinationAlpha
// BlendFactorOneMinusDestinationAlpha is a factor:
//
// 1 - (destination alpha)
BlendFactorOneMinusDestinationAlpha
// TODO: Add BlendFactorSourceAlphaSaturated. This might not work well on some platforms like Steam SDK (#2382).
2022-10-16 13:02:42 +02:00
)
func ( b BlendFactor ) internalBlendFactor ( source bool ) graphicsdriver . BlendFactor {
switch b {
case BlendFactorDefault :
// The default is the source-over composition (regular alpha blending).
if source {
return graphicsdriver . BlendFactorOne
}
return graphicsdriver . BlendFactorOneMinusSourceAlpha
case BlendFactorZero :
return graphicsdriver . BlendFactorZero
case BlendFactorOne :
return graphicsdriver . BlendFactorOne
2022-10-17 04:25:58 +02:00
case BlendFactorSourceColor :
return graphicsdriver . BlendFactorSourceColor
case BlendFactorOneMinusSourceColor :
return graphicsdriver . BlendFactorOneMinusSourceColor
2022-10-16 13:02:42 +02:00
case BlendFactorSourceAlpha :
return graphicsdriver . BlendFactorSourceAlpha
case BlendFactorOneMinusSourceAlpha :
return graphicsdriver . BlendFactorOneMinusSourceAlpha
2022-10-16 18:00:02 +02:00
case BlendFactorDestinationColor :
return graphicsdriver . BlendFactorDestinationColor
2022-10-17 04:25:58 +02:00
case BlendFactorOneMinusDestinationColor :
return graphicsdriver . BlendFactorOneMinusDestinationColor
case BlendFactorDestinationAlpha :
return graphicsdriver . BlendFactorDestinationAlpha
case BlendFactorOneMinusDestinationAlpha :
return graphicsdriver . BlendFactorOneMinusDestinationAlpha
2022-10-16 13:02:42 +02:00
default :
panic ( fmt . Sprintf ( "ebiten: invalid blend factor: %d" , b ) )
}
}
2023-01-28 11:06:38 +01:00
// BlendOperation is an operation for source and destination color values.
2022-10-16 13:02:42 +02:00
type BlendOperation byte
const (
// BlendOperationAdd represents adding the source and destination color.
2022-10-17 04:20:15 +02:00
//
// c_out = (BlendFactorSourceRGB) × c_src + (BlendFactorDestinationRGB) × c_dst
// α _out = (BlendFactorSourceAlpha) × α _src + (BlendFactorDestinationAlpha) × α _dst
2022-10-16 13:02:42 +02:00
BlendOperationAdd BlendOperation = iota
2022-10-16 16:33:16 +02:00
// BlendOperationSubtract represents subtracting the source and destination color.
2022-10-17 04:20:15 +02:00
//
// c_out = (BlendFactorSourceRGB) × c_src - (BlendFactorDestinationRGB) × c_dst
// α _out = (BlendFactorSourceAlpha) × α _src - (BlendFactorDestinationAlpha) × α _dst
2022-10-16 16:33:16 +02:00
BlendOperationSubtract
// BlendOperationReverseSubtract represents subtracting the source and destination color in a reversed order.
2022-10-17 04:20:15 +02:00
//
// c_out = (BlendFactorDestinationRGB) × c_dst - (BlendFactorSourceRGB) × c_src
// α _out = (BlendFactorDestinationAlpha) × α _dst - (BlendFactorSourceAlpha) × α _src
2022-10-16 16:33:16 +02:00
BlendOperationReverseSubtract
2023-10-12 16:55:31 +02:00
// BlendOperationMin represents a minimum function for the source and destination color.
// If BlendOperationMin is specified, blend factors are not used.
//
// c_out = min(c_dst, c_src)
// α _out = min(α _dst, α _src)
BlendOperationMin
// BlendOperationMax represents a maximum function for the source and destination color.
// If BlendOperationMax is specified, blend factors are not used.
//
// c_out = max(c_dst, c_src)
// α _out = max(α _dst, α _src)
BlendOperationMax
2022-10-16 13:02:42 +02:00
)
func ( b BlendOperation ) internalBlendOperation ( ) graphicsdriver . BlendOperation {
switch b {
case BlendOperationAdd :
return graphicsdriver . BlendOperationAdd
2022-10-16 16:33:16 +02:00
case BlendOperationSubtract :
return graphicsdriver . BlendOperationSubtract
case BlendOperationReverseSubtract :
return graphicsdriver . BlendOperationReverseSubtract
2023-10-12 16:55:31 +02:00
case BlendOperationMin :
return graphicsdriver . BlendOperationMin
case BlendOperationMax :
return graphicsdriver . BlendOperationMax
2022-10-16 13:02:42 +02:00
default :
panic ( fmt . Sprintf ( "ebiten: invalid blend operation: %d" , b ) )
}
}
// This name convention follows CSS compositing: https://drafts.fxtf.org/compositing-2/.
//
// In the comments,
// c_src, c_dst and c_out represent alpha-premultiplied RGB values of source, destination and output respectively. α _src and α _dst represent alpha values of source and destination respectively.
var (
2022-10-17 04:20:15 +02:00
// BlendSourceOver is a preset Blend for the regular alpha blending.
//
// c_out = c_src + c_dst × (1 - α _src)
// α _out = α _src + α _dst × (1 - α _src)
2022-10-16 13:02:42 +02:00
BlendSourceOver = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOne ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOne ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorOneMinusSourceAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorOneMinusSourceAlpha ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendClear is a preset Blend for Porter Duff's 'clear'.
//
// c_out = 0
// α _out = 0
2022-10-16 13:02:42 +02:00
BlendClear = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendCopy is a preset Blend for Porter Duff's 'copy'.
//
// c_out = c_src
// α _out = α _src
2022-10-16 13:02:42 +02:00
BlendCopy = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOne ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOne ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendDestination is a preset Blend for Porter Duff's 'destination'.
//
// c_out = c_dst
// α _out = α _dst
2022-10-16 13:02:42 +02:00
BlendDestination = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorOne ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorOne ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendDestinationOver is a preset Blend for Porter Duff's 'destination-over'.
//
// c_out = c_src × (1 - α _dst) + c_dst
// α _out = α _src × (1 - α _dst) + α _dst
2022-10-16 13:02:42 +02:00
BlendDestinationOver = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorOne ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorOne ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendSourceIn is a preset Blend for Porter Duff's 'source-in'.
//
// c_out = c_src × α _dst
// α _out = α _src × α _dst
2022-10-16 13:02:42 +02:00
BlendSourceIn = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorDestinationAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorDestinationAlpha ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendDestinationIn is a preset Blend for Porter Duff's 'destination-in'.
//
// c_out = c_dst × α _src
// α _out = α _dst × α _src
2022-10-16 13:02:42 +02:00
BlendDestinationIn = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorSourceAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorSourceAlpha ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendSourceOut is a preset Blend for Porter Duff's 'source-out'.
//
// c_out = c_src × (1 - α _dst)
// α _out = α _src × (1 - α _dst)
2022-10-16 13:02:42 +02:00
BlendSourceOut = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorZero ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorZero ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendDestinationOut is a preset Blend for Porter Duff's 'destination-out'.
//
// c_out = c_dst × (1 - α _src)
// α _out = α _dst × (1 - α _src)
2022-10-16 13:02:42 +02:00
BlendDestinationOut = Blend {
2023-02-05 19:28:58 +01:00
BlendFactorSourceRGB : BlendFactorZero ,
BlendFactorSourceAlpha : BlendFactorZero ,
BlendFactorDestinationRGB : BlendFactorOneMinusSourceAlpha ,
BlendFactorDestinationAlpha : BlendFactorOneMinusSourceAlpha ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendSourceAtop is a preset Blend for Porter Duff's 'source-atop'.
//
// c_out = c_src × α _dst + c_dst × (1 - α _src)
// α _out = α _src × α _dst + α _dst × (1 - α _src)
2022-10-16 13:02:42 +02:00
BlendSourceAtop = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorDestinationAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorDestinationAlpha ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorOneMinusSourceAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorOneMinusSourceAlpha ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendDestinationAtop is a preset Blend for Porter Duff's 'destination-atop'.
//
// c_out = c_src × (1 - α _dst) + c_dst × α _src
// α _out = α _src × (1 - α _dst) + α _dst × α _src
2022-10-16 13:02:42 +02:00
BlendDestinationAtop = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorSourceAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorSourceAlpha ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendXor is a preset Blend for Porter Duff's 'xor'.
//
// c_out = c_src × (1 - α _dst) + c_dst × (1 - α _src)
// α _out = α _src × (1 - α _dst) + α _dst × (1 - α _src)
2022-10-16 13:02:42 +02:00
BlendXor = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOneMinusDestinationAlpha ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorOneMinusSourceAlpha ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorOneMinusSourceAlpha ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
2022-10-17 04:20:15 +02:00
// BlendLighter is a preset Blend for Porter Duff's 'lighter'.
// This is sum of source and destination (a.k.a. 'plus' or 'additive')
//
// c_out = c_src + c_dst
// α _out = α _src + α _dst
2022-10-16 13:02:42 +02:00
BlendLighter = Blend {
2022-10-16 17:49:56 +02:00
BlendFactorSourceRGB : BlendFactorOne ,
2022-10-16 13:02:42 +02:00
BlendFactorSourceAlpha : BlendFactorOne ,
2022-10-16 17:49:56 +02:00
BlendFactorDestinationRGB : BlendFactorOne ,
2022-10-16 13:02:42 +02:00
BlendFactorDestinationAlpha : BlendFactorOne ,
2022-10-16 17:49:56 +02:00
BlendOperationRGB : BlendOperationAdd ,
2022-10-16 13:02:42 +02:00
BlendOperationAlpha : BlendOperationAdd ,
}
)