From 1f70307582854625d5f1e4e945dfe4ec1e94c408 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Fri, 30 Sep 2022 19:28:43 +0900 Subject: [PATCH] ebiten: add DrawRectShaderOptions.ColorScale This change also introduces a new struct ColorScale. Closes #2361 --- colorscale.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ image.go | 8 ++++- shader_test.go | 33 +++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 colorscale.go diff --git a/colorscale.go b/colorscale.go new file mode 100644 index 000000000..5e051879b --- /dev/null +++ b/colorscale.go @@ -0,0 +1,96 @@ +// 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" + "image/color" +) + +// ColorScale represents a scale of RGBA color. +// +// The initial (zero) value of ColorScale is an identity scale (1, 1, 1, 1). +type ColorScale struct { + // These values are adjusted by -1 from the actual values. + // It's because the initial value should be 1 instead of 0. + r_1, g_1, b_1, a_1 float32 +} + +// String returns a string represeting the color scale. +func (c *ColorScale) String() string { + return fmt.Sprintf("(%f,%f,%f,%f)", c.r_1+1, c.g_1+1, c.b_1+1, c.a_1+1) +} + +// R returns the red scale. +func (c *ColorScale) R() float32 { + return c.r_1 + 1 +} + +// G returns the green scale. +func (c *ColorScale) G() float32 { + return c.g_1 + 1 +} + +// B returns the blue scale. +func (c *ColorScale) B() float32 { + return c.b_1 + 1 +} + +// A returns the alpha scale. +func (c *ColorScale) A() float32 { + return c.a_1 + 1 +} + +func (c *ColorScale) elements() (float32, float32, float32, float32) { + return c.r_1 + 1, c.g_1 + 1, c.b_1 + 1, c.a_1 + 1 +} + +// SetR overwrites the current red value with r. +func (c *ColorScale) SetR(r float32) { + c.r_1 = r - 1 +} + +// SetG overwrites the current green value with g. +func (c *ColorScale) SetG(g float32) { + c.g_1 = g - 1 +} + +// SetB overwrites the current blue value with b. +func (c *ColorScale) SetB(b float32) { + c.b_1 = b - 1 +} + +// SetA overwrites the current alpha value with a. +func (c *ColorScale) SetA(a float32) { + c.a_1 = a - 1 +} + +// Scale multiplies the given values to the current scale. +func (c *ColorScale) Scale(r, g, b, a float32) { + c.r_1 = (c.r_1+1)*r - 1 + c.g_1 = (c.g_1+1)*g - 1 + c.b_1 = (c.b_1+1)*b - 1 + c.a_1 = (c.a_1+1)*a - 1 +} + +// ScaleWithColor multiplies the given color values to the current scale. +func (c *ColorScale) ScaleWithColor(clr color.Color) { + cr, cg, cb, ca := clr.RGBA() + if ca == 0 { + c.Scale(0, 0, 0, 0) + return + } + c.Scale(float32(cr)/float32(ca), float32(cg)/float32(ca), float32(cb)/float32(ca), float32(ca)/0xffff) +} diff --git a/image.go b/image.go index 671938278..c33da7e7d 100644 --- a/image.go +++ b/image.go @@ -547,6 +547,11 @@ type DrawRectShaderOptions struct { // The default (zero) value is identity, which draws the rectangle at (0, 0). GeoM GeoM + // ColorScale is a scale of color. + // This scaling values are passed to the `color vec4` argument of the Fragment function in a Kage program. + // The default (zero) value is identity, which is (1, 1, 1, 1). + ColorScale ColorScale + // CompositeMode is a composite mode to draw. // The default (zero) value is regular alpha blending. CompositeMode CompositeMode @@ -619,7 +624,8 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR options.GeoM.Translate(float64(offsetX), float64(offsetY)) } a, b, c, d, tx, ty := options.GeoM.elements32() - vs := graphics.QuadVertices(float32(sx), float32(sy), float32(sx+width), float32(sy+height), a, b, c, d, tx, ty, 1, 1, 1, 1) + cr, cg, cb, ca := options.ColorScale.elements() + vs := graphics.QuadVertices(float32(sx), float32(sy), float32(sx+width), float32(sy+height), a, b, c, d, tx, ty, cr, cg, cb, ca) is := graphics.QuadIndices() var offsets [graphics.ShaderImageCount - 1][2]float32 diff --git a/shader_test.go b/shader_test.go index ff8c2ba97..174e116d4 100644 --- a/shader_test.go +++ b/shader_test.go @@ -1236,3 +1236,36 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { } } } + +func TestShaderDrawRectColorScale(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return color +} +`)) + if err != nil { + t.Fatal(err) + } + + op := &ebiten.DrawRectShaderOptions{} + op.ColorScale.SetR(4.0 / 8.0) + op.ColorScale.SetG(5.0 / 8.0) + op.ColorScale.SetB(6.0 / 8.0) + op.ColorScale.SetA(7.0 / 8.0) + op.ColorScale.Scale(1.0/4.0, 2.0/4.0, 3.0/4.0, 4.0/4.0) + dst.DrawRectShader(w, h, s, op) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{0x20, 0x50, 0x90, 0xe0} + if !sameColors(got, want, 1) { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +}