ebiten: add Blend and deprecate CompositeMode

Updates #2382
This commit is contained in:
Hajime Hoshi 2022-10-16 20:02:42 +09:00
parent bd0d43f98f
commit b79495761e
9 changed files with 369 additions and 75 deletions

254
blend.go Normal file
View File

@ -0,0 +1,254 @@
// 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.
//
// The default (zero) value is source-over (regular alpha blending).
type Blend struct {
// BlendFactorSourceColor is a factor for source RGB values.
BlendFactorSourceColor BlendFactor
// BlendFactorSourceAlpha is a factor for source alpha values.
BlendFactorSourceAlpha BlendFactor
// BlendFactorDestinationColor is a factor for destination RGB values.
BlendFactorDestinationColor BlendFactor
// BlendFactorDestinationAlpha is a factor for destination apha values.
BlendFactorDestinationAlpha BlendFactor
// BlendOperationColor is an operation for source and destination RGB values.
BlendOperationColor BlendOperation
// BlendOperationAlpha is an operation for source and destination alpha values.
BlendOperationAlpha BlendOperation
}
func (b Blend) internalBlend() graphicsdriver.Blend {
return graphicsdriver.Blend{
BlendFactorSourceColor: b.BlendFactorSourceColor.internalBlendFactor(true),
BlendFactorSourceAlpha: b.BlendFactorSourceAlpha.internalBlendFactor(true),
BlendFactorDestinationColor: b.BlendFactorDestinationColor.internalBlendFactor(false),
BlendFactorDestinationAlpha: b.BlendFactorDestinationAlpha.internalBlendFactor(false),
BlendOperationColor: b.BlendOperationColor.internalBlendOperation(),
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
BlendFactorZero
BlendFactorOne
BlendFactorSourceAlpha
BlendFactorDestinationAlpha
BlendFactorOneMinusSourceAlpha
BlendFactorOneMinusDestinationAlpha
BlendFactorDestinationColor
)
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
case BlendFactorSourceAlpha:
return graphicsdriver.BlendFactorSourceAlpha
case BlendFactorDestinationAlpha:
return graphicsdriver.BlendFactorDestinationAlpha
case BlendFactorOneMinusSourceAlpha:
return graphicsdriver.BlendFactorOneMinusSourceAlpha
case BlendFactorOneMinusDestinationAlpha:
return graphicsdriver.BlendFactorOneMinusDestinationAlpha
case BlendFactorDestinationColor:
return graphicsdriver.BlendFactorDestinationColor
default:
panic(fmt.Sprintf("ebiten: invalid blend factor: %d", b))
}
}
// BlendFactor is an operation for source and destination color values.
type BlendOperation byte
const (
// BlendOperationAdd represents adding the source and destination color.
// c_out = factor_src × c_src + factor_dst × c_dst
BlendOperationAdd BlendOperation = iota
)
func (b BlendOperation) internalBlendOperation() graphicsdriver.BlendOperation {
switch b {
case BlendOperationAdd:
return graphicsdriver.BlendOperationAdd
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 (
// BlendSourceOver represents the regular alpha blending.
// c_out = c_src + c_dst × (1 - α_src)
BlendSourceOver = Blend{
BlendFactorSourceColor: BlendFactorOne,
BlendFactorSourceAlpha: BlendFactorOne,
BlendFactorDestinationColor: BlendFactorOneMinusSourceAlpha,
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = 0
BlendClear = Blend{
BlendFactorSourceColor: BlendFactorZero,
BlendFactorSourceAlpha: BlendFactorZero,
BlendFactorDestinationColor: BlendFactorZero,
BlendFactorDestinationAlpha: BlendFactorZero,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src
BlendCopy = Blend{
BlendFactorSourceColor: BlendFactorOne,
BlendFactorSourceAlpha: BlendFactorOne,
BlendFactorDestinationColor: BlendFactorZero,
BlendFactorDestinationAlpha: BlendFactorZero,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_dst
BlendDestination = Blend{
BlendFactorSourceColor: BlendFactorZero,
BlendFactorSourceAlpha: BlendFactorZero,
BlendFactorDestinationColor: BlendFactorOne,
BlendFactorDestinationAlpha: BlendFactorOne,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src × (1 - α_dst) + c_dst
BlendDestinationOver = Blend{
BlendFactorSourceColor: BlendFactorOneMinusDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
BlendFactorDestinationColor: BlendFactorOne,
BlendFactorDestinationAlpha: BlendFactorOne,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src × α_dst
BlendSourceIn = Blend{
BlendFactorSourceColor: BlendFactorDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorDestinationAlpha,
BlendFactorDestinationColor: BlendFactorZero,
BlendFactorDestinationAlpha: BlendFactorZero,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_dst × α_src
BlendDestinationIn = Blend{
BlendFactorSourceColor: BlendFactorZero,
BlendFactorSourceAlpha: BlendFactorZero,
BlendFactorDestinationColor: BlendFactorSourceAlpha,
BlendFactorDestinationAlpha: BlendFactorSourceAlpha,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src × (1 - α_dst)
BlendSourceOut = Blend{
BlendFactorSourceColor: BlendFactorOneMinusDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
BlendFactorDestinationColor: BlendFactorZero,
BlendFactorDestinationAlpha: BlendFactorZero,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_dst × (1 - α_src)
BlendDestinationOut = Blend{
BlendFactorSourceColor: BlendFactorOneMinusDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
BlendFactorDestinationColor: BlendFactorZero,
BlendFactorDestinationAlpha: BlendFactorZero,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src × α_dst + c_dst × (1 - α_src)
BlendSourceAtop = Blend{
BlendFactorSourceColor: BlendFactorDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorDestinationAlpha,
BlendFactorDestinationColor: BlendFactorOneMinusSourceAlpha,
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src × (1 - α_dst) + c_dst × α_src
BlendDestinationAtop = Blend{
BlendFactorSourceColor: BlendFactorOneMinusDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
BlendFactorDestinationColor: BlendFactorSourceAlpha,
BlendFactorDestinationAlpha: BlendFactorSourceAlpha,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// c_out = c_src × (1 - α_dst) + c_dst × (1 - α_src)
BlendXor = Blend{
BlendFactorSourceColor: BlendFactorOneMinusDestinationAlpha,
BlendFactorSourceAlpha: BlendFactorOneMinusDestinationAlpha,
BlendFactorDestinationColor: BlendFactorOneMinusSourceAlpha,
BlendFactorDestinationAlpha: BlendFactorOneMinusSourceAlpha,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
// Sum of source and destination (a.k.a. 'plus' or 'additive')
// c_out = c_src + c_dst
BlendLighter = Blend{
BlendFactorSourceColor: BlendFactorOne,
BlendFactorSourceAlpha: BlendFactorOne,
BlendFactorDestinationColor: BlendFactorOne,
BlendFactorDestinationAlpha: BlendFactorOne,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
)

View File

@ -52,16 +52,16 @@ func (g *Game) Draw(screen *ebiten.Image) {
screen.Fill(color.NRGBA{0x00, 0x40, 0x80, 0xff}) screen.Fill(color.NRGBA{0x00, 0x40, 0x80, 0xff})
// Draw the image with 'Source Alpha' composite mode (default). // Draw the image with 'Source Over' blend mode (default).
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(ox, oy) op.GeoM.Translate(ox, oy)
screen.DrawImage(ebitenImage, op) screen.DrawImage(ebitenImage, op)
// Draw the image with 'Lighter (a.k.a Additive)' composite mode. // Draw the image with 'Lighter (a.k.a Additive)' blend mode.
op = &ebiten.DrawImageOptions{} op = &ebiten.DrawImageOptions{}
w, _ := ebitenImage.Size() w, _ := ebitenImage.Size()
op.GeoM.Translate(ox+float64(w), oy) op.GeoM.Translate(ox+float64(w), oy)
op.CompositeMode = ebiten.CompositeModeLighter op.Blend = ebiten.BlendLighter
screen.DrawImage(ebitenImage, op) screen.DrawImage(ebitenImage, op)
} }

View File

@ -62,15 +62,15 @@ func (g *Game) Draw(screen *ebiten.Image) {
for i := -3; i <= 3; i++ { for i := -3; i <= 3; i++ {
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(i), 244+float64(j)) op.GeoM.Translate(float64(i), 244+float64(j))
// This is a blur based on the CompositerModeSourceOver composition mode, // This is a blur based on the source-over blend mode,
// which is basically (GL_ONE, GL_ONE_MINUS_SRC_ALPHA). ColorM acts // which is basically (GL_ONE, GL_ONE_MINUS_SRC_ALPHA). ColorM acts
// on unpremultiplied colors, but all Ebitengine internal colors are // on unpremultiplied colors, but all Ebitengine internal colors are
// premultiplied, meaning this mode is regular alpha blending, // premultiplied, meaning this mode is regular alpha blending,
// computing each destination pixel as srcPix * alpha + dstPix * (1 - alpha). // computing each destination pixel as srcPix * alpha + dstPix * (1 - alpha).
// //
// This means that the final color is affected by the destination color when CompositeModeSourceOver is used. // This means that the final color is affected by the destination color when BlendSourceOver is used.
// This composite mode is the default mode. See how this is calculated at the doc: // This blend mode is the default mode. See how this is calculated at the doc:
// https://pkg.go.dev/github.com/hajimehoshi/ebiten/v2#CompositeMode // https://pkg.go.dev/github.com/hajimehoshi/ebiten/v2#Blend
// //
// So if using the same alpha every time, the end result will sure be biased towards the last layer. // So if using the same alpha every time, the end result will sure be biased towards the last layer.
// //

View File

@ -122,11 +122,11 @@ func (g *Game) Draw(screen *ebiten.Image) {
// Reset the maskedFgImage. // Reset the maskedFgImage.
maskedFgImage.Fill(color.White) maskedFgImage.Fill(color.White)
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.CompositeMode = ebiten.CompositeModeCopy op.Blend = ebiten.BlendCopy
op.GeoM.Translate(float64(g.spotLightX), float64(g.spotLightY)) op.GeoM.Translate(float64(g.spotLightX), float64(g.spotLightY))
maskedFgImage.DrawImage(spotLightImage, op) maskedFgImage.DrawImage(spotLightImage, op)
// Use 'source-in' composite mode so that the source image (fgImage) is used but the alpha // Use 'source-in' blend mode so that the source image (fgImage) is used but the alpha
// is determined by the destination image (maskedFgImage). // is determined by the destination image (maskedFgImage).
// //
// The result image is the source image with the destination alpha. In maskedFgImage, alpha // The result image is the source image with the destination alpha. In maskedFgImage, alpha
@ -136,7 +136,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
// //
// See also https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin. // See also https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin.
op = &ebiten.DrawImageOptions{} op = &ebiten.DrawImageOptions{}
op.CompositeMode = ebiten.CompositeModeSourceIn op.Blend = ebiten.BlendSourceIn
maskedFgImage.DrawImage(fgImage, op) maskedFgImage.DrawImage(fgImage, op)
screen.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff}) screen.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff})

View File

@ -234,7 +234,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
// Subtract ray triangles from shadow // Subtract ray triangles from shadow
opt := &ebiten.DrawTrianglesOptions{} opt := &ebiten.DrawTrianglesOptions{}
opt.Address = ebiten.AddressRepeat opt.Address = ebiten.AddressRepeat
opt.CompositeMode = ebiten.CompositeModeSourceOut opt.Blend = ebiten.BlendSourceOut
for i, line := range rays { for i, line := range rays {
nextLine := rays[(i+1)%len(rays)] nextLine := rays[(i+1)%len(rays)]

View File

@ -18,7 +18,6 @@ import (
"fmt" "fmt"
"github.com/hajimehoshi/ebiten/v2/internal/builtinshader" "github.com/hajimehoshi/ebiten/v2/internal/builtinshader"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/ui" "github.com/hajimehoshi/ebiten/v2/internal/ui"
) )
@ -34,101 +33,94 @@ const (
) )
// CompositeMode represents Porter-Duff composition mode. // CompositeMode represents Porter-Duff composition mode.
//
// Deprecated: as of v2.5. Use Blend instead.
type CompositeMode int type CompositeMode int
// 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.
const ( const (
// Regular alpha blending // CompositeModeCustom indicates to refer Blend.
// c_out = c_src + c_dst × (1 - α_src) CompositeModeCustom CompositeMode = iota
CompositeModeSourceOver CompositeMode = iota
// c_out = 0 // Deprecated: as of v2.5. Use BlendSourceOver instead.
CompositeModeSourceOver
// Deprecated: as of v2.5. Use BlendClear instead.
CompositeModeClear CompositeModeClear
// c_out = c_src // Deprecated: as of v2.5. Use BlendCopy instead.
CompositeModeCopy CompositeModeCopy
// c_out = c_dst // Deprecated: as of v2.5. Use BlendDestination instead.
CompositeModeDestination CompositeModeDestination
// c_out = c_src × (1 - α_dst) + c_dst // Deprecated: as of v2.5. Use BlendDestinationOver instead.
CompositeModeDestinationOver CompositeModeDestinationOver
// c_out = c_src × α_dst // Deprecated: as of v2.5. Use BlendSourceIn instead.
CompositeModeSourceIn CompositeModeSourceIn
// c_out = c_dst × α_src // Deprecated: as of v2.5. Use BlendDestinationIn instead.
CompositeModeDestinationIn CompositeModeDestinationIn
// c_out = c_src × (1 - α_dst) // Deprecated: as of v2.5. Use BlendSourceOut instead.
CompositeModeSourceOut CompositeModeSourceOut
// c_out = c_dst × (1 - α_src) // Deprecated: as of v2.5. Use BlendDestinationOut instead.
CompositeModeDestinationOut CompositeModeDestinationOut
// c_out = c_src × α_dst + c_dst × (1 - α_src) // Deprecated: as of v2.5. Use BlendSourceAtop instead.
CompositeModeSourceAtop CompositeModeSourceAtop
// c_out = c_src × (1 - α_dst) + c_dst × α_src // Deprecated: as of v2.5. Use BlendDestinationAtop instead.
CompositeModeDestinationAtop CompositeModeDestinationAtop
// c_out = c_src × (1 - α_dst) + c_dst × (1 - α_src) // Deprecated: as of v2.5. Use BlendXor instead.
CompositeModeXor CompositeModeXor
// Sum of source and destination (a.k.a. 'plus' or 'additive') // Deprecated: as of v2.5. Use BlendLighter instead.
// c_out = c_src + c_dst
CompositeModeLighter CompositeModeLighter
// The product of source and destination (a.k.a 'multiply blend mode') // Deprecated: as of v2.5. Use Blend with BlendFactorDestinationColor and BlendFactorZero instead.
// c_out = c_src * c_dst
CompositeModeMultiply CompositeModeMultiply
) )
func (c CompositeMode) blend() graphicsdriver.Blend { func (c CompositeMode) blend() Blend {
src, dst := c.blendFactors()
return graphicsdriver.Blend{
BlendFactorSourceColor: src,
BlendFactorSourceAlpha: src,
BlendFactorDestinationColor: dst,
BlendFactorDestinationAlpha: dst,
BlendOperationColor: graphicsdriver.BlendOperationAdd,
BlendOperationAlpha: graphicsdriver.BlendOperationAdd,
}
}
func (c CompositeMode) blendFactors() (src graphicsdriver.BlendFactor, dst graphicsdriver.BlendFactor) {
switch c { switch c {
case CompositeModeSourceOver: case CompositeModeSourceOver:
return graphicsdriver.BlendFactorOne, graphicsdriver.BlendFactorOneMinusSourceAlpha return BlendSourceOver
case CompositeModeClear: case CompositeModeClear:
return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorZero return BlendClear
case CompositeModeCopy: case CompositeModeCopy:
return graphicsdriver.BlendFactorOne, graphicsdriver.BlendFactorZero return BlendCopy
case CompositeModeDestination: case CompositeModeDestination:
return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorOne return BlendDestination
case CompositeModeDestinationOver: case CompositeModeDestinationOver:
return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorOne return BlendDestinationOver
case CompositeModeSourceIn: case CompositeModeSourceIn:
return graphicsdriver.BlendFactorDestinationAlpha, graphicsdriver.BlendFactorZero return BlendSourceIn
case CompositeModeDestinationIn: case CompositeModeDestinationIn:
return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorSourceAlpha return BlendDestinationIn
case CompositeModeSourceOut: case CompositeModeSourceOut:
return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorZero return BlendSourceOut
case CompositeModeDestinationOut: case CompositeModeDestinationOut:
return graphicsdriver.BlendFactorZero, graphicsdriver.BlendFactorOneMinusSourceAlpha return BlendDestinationOut
case CompositeModeSourceAtop: case CompositeModeSourceAtop:
return graphicsdriver.BlendFactorDestinationAlpha, graphicsdriver.BlendFactorOneMinusSourceAlpha return BlendSourceAtop
case CompositeModeDestinationAtop: case CompositeModeDestinationAtop:
return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorSourceAlpha return BlendDestinationAtop
case CompositeModeXor: case CompositeModeXor:
return graphicsdriver.BlendFactorOneMinusDestinationAlpha, graphicsdriver.BlendFactorOneMinusSourceAlpha return BlendXor
case CompositeModeLighter: case CompositeModeLighter:
return graphicsdriver.BlendFactorOne, graphicsdriver.BlendFactorOne return BlendLighter
case CompositeModeMultiply: case CompositeModeMultiply:
return graphicsdriver.BlendFactorDestinationColor, graphicsdriver.BlendFactorZero return Blend{
BlendFactorSourceColor: BlendFactorDestinationColor,
BlendFactorSourceAlpha: BlendFactorDestinationColor,
BlendFactorDestinationColor: BlendFactorZero,
BlendFactorDestinationAlpha: BlendFactorZero,
BlendOperationColor: BlendOperationAdd,
BlendOperationAlpha: BlendOperationAdd,
}
default: default:
panic(fmt.Sprintf("ebiten: invalid composite mode: %d", c)) panic(fmt.Sprintf("ebiten: invalid composite mode: %d", c))
} }

View File

@ -115,9 +115,16 @@ type DrawImageOptions struct {
ColorM ColorM ColorM ColorM
// CompositeMode is a composite mode to draw. // CompositeMode is a composite mode to draw.
// The default (zero) value is regular alpha blending. // The default (zero) value is CompositeModeCustom (Blend is used).
//
// Deprecated: as of v2.5. Use Blend instead.
CompositeMode CompositeMode CompositeMode CompositeMode
// Blend is a blending way of the source color and the destination color.
// Blend is used only when CompositeMode is CompositeModeCustom.
// The default (zero) value is the regular alpha blending.
Blend Blend
// Filter is a type of texture filter. // Filter is a type of texture filter.
// The default (zero) value is FilterNearest. // The default (zero) value is FilterNearest.
Filter Filter Filter Filter
@ -187,7 +194,7 @@ func (i *Image) adjustedRegion() graphicsdriver.Region {
// - If only (*ColorM).Scale is applied to a ColorM, the ColorM has only // - If only (*ColorM).Scale is applied to a ColorM, the ColorM has only
// diagonal elements. The other ColorM functions might modify the other // diagonal elements. The other ColorM functions might modify the other
// elements. // elements.
// - All CompositeMode values are same // - All CompositeMode/Blend values are same
// - All Filter values are same // - All Filter values are same
// //
// Even when all the above conditions are satisfied, multiple draw commands can // Even when all the above conditions are satisfied, multiple draw commands can
@ -215,7 +222,12 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
options = &DrawImageOptions{} options = &DrawImageOptions{}
} }
blend := options.CompositeMode.blend() var blend graphicsdriver.Blend
if options.CompositeMode == CompositeModeCustom {
blend = options.Blend.internalBlend()
} else {
blend = options.CompositeMode.blend().internalBlend()
}
filter := builtinshader.Filter(options.Filter) filter := builtinshader.Filter(options.Filter)
if offsetX, offsetY := i.adjustPosition(0, 0); offsetX != 0 || offsetY != 0 { if offsetX, offsetY := i.adjustPosition(0, 0); offsetX != 0 || offsetY != 0 {
@ -327,9 +339,16 @@ type DrawTrianglesOptions struct {
ColorScaleFormat ColorScaleFormat ColorScaleFormat ColorScaleFormat
// CompositeMode is a composite mode to draw. // CompositeMode is a composite mode to draw.
// The default (zero) value is regular alpha blending. // The default (zero) value is CompositeModeCustom (Blend is used).
//
// Deprecated: as of v2.5. Use Blend instead.
CompositeMode CompositeMode CompositeMode CompositeMode
// Blend is a blending way of the source color and the destination color.
// Blend is used only when CompositeMode is CompositeModeCustom.
// The default (zero) value is the regular alpha blending.
Blend Blend
// Filter is a type of texture filter. // Filter is a type of texture filter.
// The default (zero) value is FilterNearest. // The default (zero) value is FilterNearest.
Filter Filter Filter Filter
@ -396,7 +415,12 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
options = &DrawTrianglesOptions{} options = &DrawTrianglesOptions{}
} }
blend := options.CompositeMode.blend() var blend graphicsdriver.Blend
if options.CompositeMode == CompositeModeCustom {
blend = options.Blend.internalBlend()
} else {
blend = options.CompositeMode.blend().internalBlend()
}
address := builtinshader.Address(options.Address) address := builtinshader.Address(options.Address)
var sr graphicsdriver.Region var sr graphicsdriver.Region
@ -461,9 +485,16 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader. // DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
type DrawTrianglesShaderOptions struct { type DrawTrianglesShaderOptions struct {
// CompositeMode is a composite mode to draw. // CompositeMode is a composite mode to draw.
// The default (zero) value is regular alpha blending. // The default (zero) value is CompositeModeCustom (Blend is used).
//
// Deprecated: as of v2.5. Use Blend instead.
CompositeMode CompositeMode CompositeMode CompositeMode
// Blend is a blending way of the source color and the destination color.
// Blend is used only when CompositeMode is CompositeModeCustom.
// The default (zero) value is the regular alpha blending.
Blend Blend
// Uniforms is a set of uniform variables for the shader. // Uniforms is a set of uniform variables for the shader.
// The keys are the names of the uniform variables. // The keys are the names of the uniform variables.
// The values must be float or []float. // The values must be float or []float.
@ -525,7 +556,12 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
options = &DrawTrianglesShaderOptions{} options = &DrawTrianglesShaderOptions{}
} }
blend := options.CompositeMode.blend() var blend graphicsdriver.Blend
if options.CompositeMode == CompositeModeCustom {
blend = options.Blend.internalBlend()
} else {
blend = options.CompositeMode.blend().internalBlend()
}
vs := graphics.Vertices(len(vertices)) vs := graphics.Vertices(len(vertices))
dst := i dst := i
@ -604,9 +640,16 @@ type DrawRectShaderOptions struct {
ColorScale ColorScale ColorScale ColorScale
// CompositeMode is a composite mode to draw. // CompositeMode is a composite mode to draw.
// The default (zero) value is regular alpha blending. // The default (zero) value is CompositeModeCustom (Blend is used).
//
// Deprecated: as of v2.5. Use Blend instead.
CompositeMode CompositeMode CompositeMode CompositeMode
// Blend is a blending way of the source color and the destination color.
// Blend is used only when CompositeMode is CompositeModeCustom.
// The default (zero) value is the regular alpha blending.
Blend Blend
// Uniforms is a set of uniform variables for the shader. // Uniforms is a set of uniform variables for the shader.
// The keys are the names of the uniform variables. // The keys are the names of the uniform variables.
// The values must be float or []float. // The values must be float or []float.
@ -645,7 +688,12 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
options = &DrawRectShaderOptions{} options = &DrawRectShaderOptions{}
} }
blend := options.CompositeMode.blend() var blend graphicsdriver.Blend
if options.CompositeMode == CompositeModeCustom {
blend = options.Blend.internalBlend()
} else {
blend = options.CompositeMode.blend().internalBlend()
}
var imgs [graphics.ShaderImageCount]*ui.Image var imgs [graphics.ShaderImageCount]*ui.Image
for i, img := range options.Images { for i, img := range options.Images {

View File

@ -342,7 +342,7 @@ func min(a, b int) int {
return b return b
} }
func TestImageCompositeModeLighter(t *testing.T) { func TestImageBlendLighter(t *testing.T) {
img0, _, err := openEbitenImage() img0, _, err := openEbitenImage()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -353,7 +353,7 @@ func TestImageCompositeModeLighter(t *testing.T) {
img1 := ebiten.NewImage(w, h) img1 := ebiten.NewImage(w, h)
img1.Fill(color.RGBA{0x01, 0x02, 0x03, 0x04}) img1.Fill(color.RGBA{0x01, 0x02, 0x03, 0x04})
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.CompositeMode = ebiten.CompositeModeLighter op.Blend = ebiten.BlendLighter
img1.DrawImage(img0, op) img1.DrawImage(img0, op)
for j := 0; j < img1.Bounds().Size().Y; j++ { for j := 0; j < img1.Bounds().Size().Y; j++ {
for i := 0; i < img1.Bounds().Size().X; i++ { for i := 0; i < img1.Bounds().Size().X; i++ {
@ -2343,7 +2343,7 @@ func TestImageColorMCopy(t *testing.T) {
for k := 0; k < 256; k++ { for k := 0; k < 256; k++ {
op := &ebiten.DrawImageOptions{} op := &ebiten.DrawImageOptions{}
op.ColorM.Translate(1, 1, 1, float64(k)/0xff) op.ColorM.Translate(1, 1, 1, float64(k)/0xff)
op.CompositeMode = ebiten.CompositeModeCopy op.Blend = ebiten.BlendCopy
dst.DrawImage(src, op) dst.DrawImage(src, op)
for j := 0; j < h; j++ { for j := 0; j < h; j++ {

View File

@ -48,7 +48,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
g.dst = ebiten.NewImage(w, h) g.dst = ebiten.NewImage(w, h)
op := &ebiten.DrawRectShaderOptions{} op := &ebiten.DrawRectShaderOptions{}
op.CompositeMode = ebiten.CompositeModeCopy op.Blend = ebiten.BlendCopy
op.Uniforms = map[string]interface{}{ op.Uniforms = map[string]interface{}{
"Color": []float32{1, 1, 1, 1}, "Color": []float32{1, 1, 1, 1},
} }
@ -78,7 +78,7 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
} }
op := &ebiten.DrawRectShaderOptions{} op := &ebiten.DrawRectShaderOptions{}
op.CompositeMode = ebiten.CompositeModeCopy op.Blend = ebiten.BlendCopy
op.Uniforms = map[string]interface{}{ op.Uniforms = map[string]interface{}{
"Dummy": float32(0), "Dummy": float32(0),
"R": float32(0.5), "R": float32(0.5),