123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- // 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 colorm_test
- import (
- "fmt"
- "image/color"
- "math"
- "testing"
- "github.com/hajimehoshi/ebiten/v2"
- "github.com/hajimehoshi/ebiten/v2/colorm"
- t "github.com/hajimehoshi/ebiten/v2/internal/testing"
- "github.com/hajimehoshi/ebiten/v2/internal/ui"
- )
- func abs(x int) int {
- if x < 0 {
- return -x
- }
- return x
- }
- // sameColors compares c1 and c2 and returns a boolean value indicating
- // if the two colors are (almost) same.
- //
- // Pixels read from GPU might include errors (#492), and
- // sameColors considers such errors as delta.
- func sameColors(c1, c2 color.RGBA, delta int) bool {
- return abs(int(c1.R)-int(c2.R)) <= delta &&
- abs(int(c1.G)-int(c2.G)) <= delta &&
- abs(int(c1.B)-int(c2.B)) <= delta &&
- abs(int(c1.A)-int(c2.A)) <= delta
- }
- func TestMain(m *testing.M) {
- ui.SetPanicOnErrorOnReadingPixelsForTesting(true)
- t.MainWithRunLoop(m)
- }
- func TestDrawTrianglesWithColorM(t *testing.T) {
- const w, h = 16, 16
- dst0 := ebiten.NewImage(w, h)
- src := ebiten.NewImage(w, h)
- src.Fill(color.White)
- vs0 := []ebiten.Vertex{
- {
- DstX: 0,
- DstY: 0,
- SrcX: 0,
- SrcY: 0,
- ColorR: 1,
- ColorG: 1,
- ColorB: 1,
- ColorA: 1,
- },
- {
- DstX: w,
- DstY: 0,
- SrcX: w,
- SrcY: 0,
- ColorR: 1,
- ColorG: 1,
- ColorB: 1,
- ColorA: 1,
- },
- {
- DstX: 0,
- DstY: h,
- SrcX: 0,
- SrcY: h,
- ColorR: 1,
- ColorG: 1,
- ColorB: 1,
- ColorA: 1,
- },
- {
- DstX: w,
- DstY: h,
- SrcX: w,
- SrcY: h,
- ColorR: 1,
- ColorG: 1,
- ColorB: 1,
- ColorA: 1,
- },
- }
- var cm colorm.ColorM
- cm.Scale(0.2, 0.4, 0.6, 0.8)
- op := &colorm.DrawTrianglesOptions{}
- is := []uint16{0, 1, 2, 1, 2, 3}
- colorm.DrawTriangles(dst0, vs0, is, src, cm, op)
- for _, format := range []ebiten.ColorScaleMode{
- ebiten.ColorScaleModeStraightAlpha,
- ebiten.ColorScaleModePremultipliedAlpha,
- } {
- format := format
- t.Run(fmt.Sprintf("format%d", format), func(t *testing.T) {
- var cr, cg, cb, ca float32
- switch format {
- case ebiten.ColorScaleModeStraightAlpha:
- // The values are the same as ColorM.Scale
- cr = 0.2
- cg = 0.4
- cb = 0.6
- ca = 0.8
- case ebiten.ColorScaleModePremultipliedAlpha:
- cr = 0.2 * 0.8
- cg = 0.4 * 0.8
- cb = 0.6 * 0.8
- ca = 0.8
- }
- vs1 := []ebiten.Vertex{
- {
- DstX: 0,
- DstY: 0,
- SrcX: 0,
- SrcY: 0,
- ColorR: cr,
- ColorG: cg,
- ColorB: cb,
- ColorA: ca,
- },
- {
- DstX: w,
- DstY: 0,
- SrcX: w,
- SrcY: 0,
- ColorR: cr,
- ColorG: cg,
- ColorB: cb,
- ColorA: ca,
- },
- {
- DstX: 0,
- DstY: h,
- SrcX: 0,
- SrcY: h,
- ColorR: cr,
- ColorG: cg,
- ColorB: cb,
- ColorA: ca,
- },
- {
- DstX: w,
- DstY: h,
- SrcX: w,
- SrcY: h,
- ColorR: cr,
- ColorG: cg,
- ColorB: cb,
- ColorA: ca,
- },
- }
- dst1 := ebiten.NewImage(w, h)
- op := &ebiten.DrawTrianglesOptions{}
- op.ColorScaleMode = format
- dst1.DrawTriangles(vs1, is, src, op)
- for j := 0; j < h; j++ {
- for i := 0; i < w; i++ {
- got := dst0.At(i, j)
- want := dst1.At(i, j)
- if got != want {
- t.Errorf("At(%d, %d): got: %v, want: %v", i, j, got, want)
- }
- }
- }
- })
- }
- }
- func TestColorMAndScale(t *testing.T) {
- const w, h = 16, 16
- src := ebiten.NewImage(w, h)
- src.Fill(color.RGBA{R: 0x80, G: 0x80, B: 0x80, A: 0x80})
- vs := []ebiten.Vertex{
- {
- SrcX: 0,
- SrcY: 0,
- DstX: 0,
- DstY: 0,
- ColorR: 0.5,
- ColorG: 0.25,
- ColorB: 0.5,
- ColorA: 0.75,
- },
- {
- SrcX: w,
- SrcY: 0,
- DstX: w,
- DstY: 0,
- ColorR: 0.5,
- ColorG: 0.25,
- ColorB: 0.5,
- ColorA: 0.75,
- },
- {
- SrcX: 0,
- SrcY: h,
- DstX: 0,
- DstY: h,
- ColorR: 0.5,
- ColorG: 0.25,
- ColorB: 0.5,
- ColorA: 0.75,
- },
- {
- SrcX: w,
- SrcY: h,
- DstX: w,
- DstY: h,
- ColorR: 0.5,
- ColorG: 0.25,
- ColorB: 0.5,
- ColorA: 0.75,
- },
- }
- is := []uint16{0, 1, 2, 1, 2, 3}
- for _, format := range []ebiten.ColorScaleMode{
- ebiten.ColorScaleModeStraightAlpha,
- ebiten.ColorScaleModePremultipliedAlpha,
- } {
- format := format
- t.Run(fmt.Sprintf("format%d", format), func(t *testing.T) {
- dst := ebiten.NewImage(w, h)
- var cm colorm.ColorM
- cm.Translate(0.25, 0.25, 0.25, 0)
- op := &colorm.DrawTrianglesOptions{}
- op.ColorScaleMode = format
- colorm.DrawTriangles(dst, vs, is, src, cm, op)
- got := dst.At(0, 0).(color.RGBA)
- alphaBeforeScale := 0.5
- var want color.RGBA
- switch format {
- case ebiten.ColorScaleModeStraightAlpha:
- want = color.RGBA{
- R: byte(math.Floor(0xff * (0.5/alphaBeforeScale + 0.25) * alphaBeforeScale * 0.5 * 0.75)),
- G: byte(math.Floor(0xff * (0.5/alphaBeforeScale + 0.25) * alphaBeforeScale * 0.25 * 0.75)),
- B: byte(math.Floor(0xff * (0.5/alphaBeforeScale + 0.25) * alphaBeforeScale * 0.5 * 0.75)),
- A: byte(math.Floor(0xff * alphaBeforeScale * 0.75)),
- }
- case ebiten.ColorScaleModePremultipliedAlpha:
- want = color.RGBA{
- R: byte(math.Floor(0xff * (0.5/alphaBeforeScale + 0.25) * alphaBeforeScale * 0.5)),
- G: byte(math.Floor(0xff * (0.5/alphaBeforeScale + 0.25) * alphaBeforeScale * 0.25)),
- B: byte(math.Floor(0xff * (0.5/alphaBeforeScale + 0.25) * alphaBeforeScale * 0.5)),
- A: byte(math.Floor(0xff * alphaBeforeScale * 0.75)),
- }
- }
- if !sameColors(got, want, 2) {
- t.Errorf("got: %v, want: %v", got, want)
- }
- })
- }
- }
- // Issue #1213
- func TestColorMCopy(t *testing.T) {
- const w, h = 16, 16
- dst := ebiten.NewImage(w, h)
- src := ebiten.NewImage(w, h)
- for k := 0; k < 256; k++ {
- var cm colorm.ColorM
- cm.Translate(1, 1, 1, float64(k)/0xff)
- op := &colorm.DrawImageOptions{}
- op.Blend = ebiten.BlendCopy
- colorm.DrawImage(dst, src, cm, op)
- for j := 0; j < h; j++ {
- for i := 0; i < w; i++ {
- got := dst.At(i, j).(color.RGBA)
- want := color.RGBA{R: byte(k), G: byte(k), B: byte(k), A: byte(k)}
- if !sameColors(got, want, 1) {
- t.Fatalf("dst.At(%d, %d), k: %d: got %v, want %v", i, j, k, got, want)
- }
- }
- }
- }
- }
|