From 5e459bbe42bc5cd8d42ae5675bc58d8bd94ad466 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 2 Oct 2022 13:26:33 +0900 Subject: [PATCH] internal/graphicsdriver/opengl, metal, directx: use premultiplied alpha format for color scales Updates #2365 --- image.go | 30 ++++++++----------- .../directx/pipeline_windows.go | 2 +- .../graphicsdriver/metal/graphics_darwin.go | 3 +- .../graphicsdriver/opengl/defaultshader.go | 4 +-- internal/ui/image.go | 12 +++----- 5 files changed, 19 insertions(+), 32 deletions(-) diff --git a/image.go b/image.go index 902d50f2c..5661bae57 100644 --- a/image.go +++ b/image.go @@ -87,12 +87,10 @@ func (i *Image) Fill(clr color.Color) { var crf, cgf, cbf, caf float32 cr, cg, cb, ca := clr.RGBA() - if ca != 0 { - crf = float32(cr) / float32(ca) - cgf = float32(cg) / float32(ca) - cbf = float32(cb) / float32(ca) - caf = float32(ca) / 0xffff - } + crf = float32(cr) / 0xffff + cgf = float32(cg) / 0xffff + cbf = float32(cb) / 0xffff + caf = float32(ca) / 0xffff b := i.Bounds() x, y := i.adjustPosition(b.Min.X, b.Min.Y) i.image.Fill(crf, cgf, cbf, caf, x, y, b.Dx(), b.Dy()) @@ -386,9 +384,9 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o sx, sy := img.adjustPositionF32(v.SrcX, v.SrcY) vs[i*graphics.VertexFloatCount+2] = sx vs[i*graphics.VertexFloatCount+3] = sy - vs[i*graphics.VertexFloatCount+4] = v.ColorR * cr - vs[i*graphics.VertexFloatCount+5] = v.ColorG * cg - vs[i*graphics.VertexFloatCount+6] = v.ColorB * cb + vs[i*graphics.VertexFloatCount+4] = v.ColorR * v.ColorA * cr + vs[i*graphics.VertexFloatCount+5] = v.ColorG * v.ColorA * cg + vs[i*graphics.VertexFloatCount+6] = v.ColorB * v.ColorA * cb vs[i*graphics.VertexFloatCount+7] = v.ColorA * ca } is := make([]uint16, len(indices)) @@ -994,14 +992,9 @@ func NewImageFromImageWithOptions(source image.Image, options *NewImageFromImage // colorMToScale returns a new color matrix and color sclaes that equal to the given matrix in terms of the effect. // // If the given matrix is merely a scaling matrix, colorMToScale returns -// an identity matrix and its scaling factors. This is useful to optimize -// the rendering speed by avoiding the use of the color matrix and instead -// multiplying all vertex colors by the scale. -// -// NOTE: this is only safe when not using a custom Kage shader, -// as custom shaders may be using vertex colors for different purposes -// than colorization. However, currently there are no Ebitengine APIs that -// support both shaders and color matrices. +// an identity matrix and its scaling factors in premultiplied-alpha format. +// This is useful to optimize the rendering speed by avoiding the use of the +// color matrix and instead multiplying all vertex colors by the scale. func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a float32) { if colorm.IsIdentity() { return colorm, 1, 1, 1, 1 @@ -1010,6 +1003,7 @@ func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a fl if !colorm.ScaleOnly() { return colorm, 1, 1, 1, 1 } + r = colorm.At(0, 0) g = colorm.At(1, 1) b = colorm.At(2, 2) @@ -1029,5 +1023,5 @@ func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a fl return colorm, 1, 1, 1, 1 } - return affine.ColorMIdentity{}, r, g, b, a + return affine.ColorMIdentity{}, r * a, g * a, b * a, a } diff --git a/internal/graphicsdriver/directx/pipeline_windows.go b/internal/graphicsdriver/directx/pipeline_windows.go index 1f5e7df8f..5b6b4c979 100644 --- a/internal/graphicsdriver/directx/pipeline_windows.go +++ b/internal/graphicsdriver/directx/pipeline_windows.go @@ -125,7 +125,7 @@ PSInput VSMain(float2 position : POSITION, float2 tex : TEXCOORD, float4 color : PSInput result; result.position = mul(projectionMatrix, float4(position, 0, 1)); result.texcoord = tex; - result.color = float4(color.rgb, 1) * color.a; + result.color = color; return result; } diff --git a/internal/graphicsdriver/metal/graphics_darwin.go b/internal/graphicsdriver/metal/graphics_darwin.go index 351b638d1..3f7133ef1 100644 --- a/internal/graphicsdriver/metal/graphics_darwin.go +++ b/internal/graphicsdriver/metal/graphics_darwin.go @@ -70,8 +70,7 @@ vertex VertexOut VertexShader( VertexOut out = { .position = projectionMatrix * float4(in.position, 0, 1), .tex = in.tex, - // Fragment shader wants premultiplied alpha. - .color = float4(in.color.rgb, 1) * in.color.a, + .color = in.color, }; return out; diff --git a/internal/graphicsdriver/opengl/defaultshader.go b/internal/graphicsdriver/opengl/defaultshader.go index 148f9b1e0..77d967a01 100644 --- a/internal/graphicsdriver/opengl/defaultshader.go +++ b/internal/graphicsdriver/opengl/defaultshader.go @@ -115,9 +115,7 @@ varying vec4 varying_color_scale; void main(void) { varying_tex = A1; - - // Fragment shader wants premultiplied alpha. - varying_color_scale = vec4(A2.rgb, 1) * A2.a; + varying_color_scale = A2; mat4 projection_matrix = mat4( vec4(2.0 / viewport_size.x, 0, 0, 0), diff --git a/internal/ui/image.go b/internal/ui/image.go index 7695295a0..67c01f67e 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -140,14 +140,10 @@ func (i *Image) resolveDotsCacheIfNeeded() { for p, c := range i.dotsCache { dx := float32(p[0]) dy := float32(p[1]) - - var crf, cgf, cbf, caf float32 - if c[3] != 0 { - crf = float32(c[0]) / float32(c[3]) - cgf = float32(c[1]) / float32(c[3]) - cbf = float32(c[2]) / float32(c[3]) - caf = float32(c[3]) / 0xff - } + crf := float32(c[0]) / 0xff + cgf := float32(c[1]) / 0xff + cbf := float32(c[2]) / 0xff + caf := float32(c[3]) / 0xff vs[graphics.VertexFloatCount*4*idx] = dx vs[graphics.VertexFloatCount*4*idx+1] = dy