Bug fix: Consider color.Color.RGBA returns alpha-premultiplied values

This commit is contained in:
Hajime Hoshi 2014-12-22 00:02:14 +09:00
parent d34c94aa09
commit 99434fa9d3
11 changed files with 67 additions and 53 deletions

View File

@ -17,7 +17,6 @@ limitations under the License.
package ebiten
import (
"image/color"
"math"
)
@ -81,28 +80,26 @@ func Monochrome() ColorMatrix {
}
}
// ScaleColor returns a color matrix that scales a color matrix by clr.
func ScaleColor(clr color.Color) ColorMatrix {
rf, gf, bf, af := rgba(clr)
// ScaleColor returns a color matrix that scales a color matrix by the given color (r, g, b, a).
func ScaleColor(r, g, b, a float64) ColorMatrix {
return ColorMatrix{
[ColorMatrixDim - 1][ColorMatrixDim]float64{
{rf, 0, 0, 0, 0},
{0, gf, 0, 0, 0},
{0, 0, bf, 0, 0},
{0, 0, 0, af, 0},
{r, 0, 0, 0, 0},
{0, g, 0, 0, 0},
{0, 0, b, 0, 0},
{0, 0, 0, a, 0},
},
}
}
// TranslateColor returns a color matrix that translates a color matrix by clr.
func TranslateColor(clr color.Color) ColorMatrix {
rf, gf, bf, af := rgba(clr)
// TranslateColor returns a color matrix that translates a color matrix by the given color (r, g, b, a).
func TranslateColor(r, g, b, a float64) ColorMatrix {
return ColorMatrix{
[ColorMatrixDim - 1][ColorMatrixDim]float64{
{1, 0, 0, 0, rf},
{0, 1, 0, 0, gf},
{0, 0, 1, 0, bf},
{0, 0, 0, 1, af},
{1, 0, 0, 0, r},
{0, 1, 0, 0, g},
{0, 0, 1, 0, b},
{0, 0, 0, 1, a},
},
}
}
@ -123,11 +120,11 @@ func RotateHue(theta float64) ColorMatrix {
}
}
func rgba(clr color.Color) (float64, float64, float64, float64) {
r, g, b, a := clr.RGBA()
rf := float64(r) / float64(math.MaxUint16)
gf := float64(g) / float64(math.MaxUint16)
bf := float64(b) / float64(math.MaxUint16)
af := float64(a) / float64(math.MaxUint16)
func rgba(r, g, b, a uint8) (float64, float64, float64, float64) {
const max = math.MaxUint8
rf := float64(r) / max
gf := float64(g) / max
bf := float64(b) / max
af := float64(a) / max
return rf, gf, bf, af
}

View File

@ -18,6 +18,7 @@ package ebitenutil
import (
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/internal"
"github.com/hajimehoshi/ebiten/internal/assets"
"image/color"
)
@ -34,7 +35,7 @@ func DebugPrint(r *ebiten.RenderTarget, str string) {
defaultDebugPrintState.DebugPrint(r, str)
}
func (d *debugPrintState) drawText(r *ebiten.RenderTarget, str string, x, y int, clr color.Color) {
func (d *debugPrintState) drawText(rt *ebiten.RenderTarget, str string, x, y int, c color.Color) {
parts := []ebiten.ImagePart{}
locationX, locationY := 0, 0
for _, c := range str {
@ -53,11 +54,10 @@ func (d *debugPrintState) drawText(r *ebiten.RenderTarget, str string, x, y int,
})
locationX += assets.TextImageCharWidth
}
geom := ebiten.GeometryMatrixI()
geom.Concat(ebiten.TranslateGeometry(float64(x)+1, float64(y)))
clrm := ebiten.ColorMatrixI()
clrm.Concat(ebiten.ScaleColor(clr))
r.DrawImage(d.textTexture, parts, geom, clrm)
geo := ebiten.TranslateGeometry(float64(x)+1, float64(y))
r, g, b, a := internal.RGBA(c)
clr := ebiten.ScaleColor(r, g, b, a)
rt.DrawImage(d.textTexture, parts, geo, clr)
}
func (d *debugPrintState) DebugPrint(r *ebiten.RenderTarget, str string) {
@ -79,6 +79,6 @@ func (d *debugPrintState) DebugPrint(r *ebiten.RenderTarget, str string) {
panic(err)
}
}
d.drawText(r, str, 1, d.y+1, &color.RGBA{0x00, 0x00, 0x00, 0x80})
d.drawText(r, str, 0, d.y, &color.RGBA{0xff, 0xff, 0xff, 0xff})
d.drawText(r, str, 1, d.y+1, color.NRGBA{0x00, 0x00, 0x00, 0x80})
d.drawText(r, str, 0, d.y, color.NRGBA{0xff, 0xff, 0xff, 0xff})
}

View File

@ -52,13 +52,13 @@ func (g *Game) Update(r *ebiten.RenderTarget) error {
}
for i := 0; i < 10; i++ {
geo := ebiten.TranslateGeometry(15+float64(i)*(diff), 20)
clr := ebiten.ScaleColor(color.RGBA{0xff, 0xff, 0xff, 0x80})
clr := ebiten.ScaleColor(1.0, 1.0, 1.0, 0.5)
if err := ebiten.DrawWholeImage(g.tmpRenderTarget, g.ebitenImage, geo, clr); err != nil {
return err
}
}
r.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff})
r.Fill(color.NRGBA{0x00, 0x00, 0x80, 0xff})
for i := 0; i < 10; i++ {
geo := ebiten.TranslateGeometry(0, float64(i)*(diff))
clr := ebiten.ColorMatrixI()

View File

@ -19,6 +19,7 @@ package blocks
import (
"github.com/hajimehoshi/ebiten"
"image/color"
"math"
)
func init() {
@ -32,7 +33,7 @@ func textWidth(str string) int {
return charWidth * len(str)
}
func drawText(r *ebiten.RenderTarget, images *Images, str string, ox, oy, scale int, clr color.Color) {
func drawText(rt *ebiten.RenderTarget, images *Images, str string, ox, oy, scale int, c color.Color) {
fontImageId := images.GetImage("font")
parts := []ebiten.ImagePart{}
@ -53,13 +54,19 @@ func drawText(r *ebiten.RenderTarget, images *Images, str string, ox, oy, scale
locationX += charWidth
}
geoMat := ebiten.ScaleGeometry(float64(scale), float64(scale))
geoMat.Concat(ebiten.TranslateGeometry(float64(ox), float64(oy)))
clrMat := ebiten.ScaleColor(clr)
r.DrawImage(fontImageId, parts, geoMat, clrMat)
geo := ebiten.ScaleGeometry(float64(scale), float64(scale))
geo.Concat(ebiten.TranslateGeometry(float64(ox), float64(oy)))
c2 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
const max = math.MaxUint16
r := float64(c2.R) / max
g := float64(c2.G) / max
b := float64(c2.B) / max
a := float64(c2.A) / max
clr := ebiten.ScaleColor(r, g, b, a)
rt.DrawImage(fontImageId, parts, geo, clr)
}
func drawTextWithShadow(r *ebiten.RenderTarget, images *Images, str string, x, y, scale int, clr color.Color) {
drawText(r, images, str, x+1, y+1, scale, color.RGBA{0, 0, 0, 0x80})
drawText(r, images, str, x, y, scale, clr)
func drawTextWithShadow(rt *ebiten.RenderTarget, images *Images, str string, x, y, scale int, clr color.Color) {
drawText(rt, images, str, x+1, y+1, scale, color.NRGBA{0, 0, 0, 0x80})
drawText(rt, images, str, x, y, scale, clr)
}

View File

@ -116,7 +116,7 @@ func (s *GameScene) Draw(r *ebiten.RenderTarget, images *Images) {
w, h := field.Size()
geoMat := ebiten.ScaleGeometry(float64(fieldWidth)/float64(w), float64(fieldHeight)/float64(h))
geoMat.Concat(ebiten.TranslateGeometry(20, 20)) // TODO: magic number?
colorMat := ebiten.ScaleColor(color.RGBA{0, 0, 0, 0x80})
colorMat := ebiten.ScaleColor(0.0, 0.0, 0.0, 0.5)
ebiten.DrawWholeImage(r, field, geoMat, colorMat)
geoMat = ebiten.GeometryMatrixI()

View File

@ -47,7 +47,7 @@ func (s *TitleScene) Draw(r *ebiten.RenderTarget, images *Images) {
message := "PRESS SPACE TO START"
x := (ScreenWidth - textWidth(message)) / 2
y := ScreenHeight - 48
drawTextWithShadow(r, images, message, x, y, 1, color.RGBA{0x80, 0, 0, 0xff})
drawTextWithShadow(r, images, message, x, y, 1, color.NRGBA{0x80, 0, 0, 0xff})
}
func drawTitleBackground(r *ebiten.RenderTarget, images *Images, c int) {
@ -78,5 +78,5 @@ func drawLogo(r *ebiten.RenderTarget, images *Images, str string) {
textWidth := textWidth(str) * scale
x := (ScreenWidth - textWidth) / 2
y := 32
drawTextWithShadow(r, images, str, x, y, scale, color.RGBA{0x00, 0x00, 0x80, 0xff})
drawTextWithShadow(r, images, str, x, y, scale, color.NRGBA{0x00, 0x00, 0x80, 0xff})
}

View File

@ -51,7 +51,7 @@ func (g *Game) Update(r *ebiten.RenderTarget) error {
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
geo := ebiten.TranslateGeometry(float64(mx), float64(my))
clr := ebiten.ScaleColor(color.RGBA{0xff, 0x40, 0x40, 0xff})
clr := ebiten.ScaleColor(1.0, 0.25, 0.25, 1.0)
theta := 2.0 * math.Pi * float64(g.count%60) / 60.0
clr.Concat(ebiten.RotateHue(theta))
ebiten.DrawWholeImage(g.canvasRenderTarget, g.brushRenderTarget.Image(), geo, clr)

View File

@ -53,6 +53,7 @@ const (
)
// An Image represents an image to be rendered.
// An image's pixels are stored as non alpha-premultiplied.
type Image struct {
glTexture *opengl.Texture
}

View File

@ -16,6 +16,11 @@ limitations under the License.
package internal
import (
"image/color"
"math"
)
func NextPowerOf2(x uint64) uint64 {
x -= 1
x |= (x >> 1)
@ -30,3 +35,13 @@ func NextPowerOf2(x uint64) uint64 {
func NextPowerOf2Int(size int) int {
return int(NextPowerOf2(uint64(size)))
}
func RGBA(clr color.Color) (r, g, b, a float64) {
clr2 := color.NRGBA64Model.Convert(clr).(color.NRGBA64)
const max = math.MaxUint16
r = float64(clr2.R) / max
g = float64(clr2.G) / max
b = float64(clr2.B) / max
a = float64(clr2.A) / max
return
}

View File

@ -87,7 +87,7 @@ void main(void) {
color0 = (color_matrix * color0) + color_matrix_translation;
// Photoshop-like RGBA blending
gl_FragColor.a = color0.a + color1.a - color0.a * color1.a;
gl_FragColor.a = color0.a + (1.0 - color0.a) * color1.a;
gl_FragColor.rgb = (color0.a * color0.rgb + (1.0 - color0.a) * color1.a * color1.rgb) / gl_FragColor.a;
}
`,

View File

@ -22,7 +22,6 @@ import (
"github.com/hajimehoshi/ebiten/internal/opengl"
"github.com/hajimehoshi/ebiten/internal/opengl/internal/shader"
"image/color"
"math"
)
type innerRenderTarget struct {
@ -50,20 +49,15 @@ func (r *innerRenderTarget) size() (width, height int) {
}
func (r *innerRenderTarget) Clear() error {
return r.Fill(color.RGBA{0, 0, 0, 0})
return r.Fill(color.Transparent)
}
func (r *innerRenderTarget) Fill(clr color.Color) error {
if err := r.glRenderTarget.SetAsViewport(); err != nil {
return err
}
const max = math.MaxUint16
cr, cg, cb, ca := clr.RGBA()
rf := gl.GLclampf(float64(cr) / max)
gf := gl.GLclampf(float64(cg) / max)
bf := gl.GLclampf(float64(cb) / max)
af := gl.GLclampf(float64(ca) / max)
gl.ClearColor(rf, gf, bf, af)
rf, gf, bf, af := internal.RGBA(clr)
gl.ClearColor(gl.GLclampf(rf), gl.GLclampf(gf), gl.GLclampf(bf), gl.GLclampf(af))
gl.Clear(gl.COLOR_BUFFER_BIT)
return nil
}