replace NRGBA to RGBA because Porter-Duff (!!!)

This commit is contained in:
faiface 2017-04-09 22:00:26 +02:00
parent 317cfb17b0
commit 32ae09e1e5
11 changed files with 122 additions and 138 deletions

View File

@ -13,7 +13,7 @@ type Batch struct {
cont Drawer
mat Matrix
col NRGBA
col RGBA
}
var _ BasicTarget = (*Batch)(nil)
@ -28,7 +28,7 @@ var _ BasicTarget = (*Batch)(nil)
func NewBatch(container Triangles, pic Picture) *Batch {
b := &Batch{cont: Drawer{Triangles: container, Picture: pic}}
b.SetMatrix(IM)
b.SetColorMask(NRGBA{1, 1, 1, 1})
b.SetColorMask(RGBA{1, 1, 1, 1})
return b
}
@ -62,10 +62,10 @@ func (b *Batch) SetMatrix(m Matrix) {
// SetColorMask sets a mask color used in the following draws onto the Batch.
func (b *Batch) SetColorMask(c color.Color) {
if c == nil {
b.col = NRGBA{1, 1, 1, 1}
b.col = RGBA{1, 1, 1, 1}
return
}
b.col = ToNRGBA(c)
b.col = ToRGBA(c)
}
// MakeTriangles returns a specialized copy of the provided Triangles that draws onto this Batch.

View File

@ -2,17 +2,17 @@ package pixel
import "image/color"
// NRGBA represents a non-alpha-premultiplied RGBA color with components within range [0, 1].
// RGBA represents a alpha-premultiplied RGBA color with components within range [0, 1].
//
// The difference between color.NRGBA is that the value range is [0, 1] and the values are floats.
type NRGBA struct {
// The difference between color.RGBA is that the value range is [0, 1] and the values are floats.
type RGBA struct {
R, G, B, A float64
}
// Add adds color d to color c component-wise and returns the result (the components are not
// clamped).
func (c NRGBA) Add(d NRGBA) NRGBA {
return NRGBA{
func (c RGBA) Add(d RGBA) RGBA {
return RGBA{
R: c.R + d.R,
G: c.G + d.G,
B: c.B + d.B,
@ -22,8 +22,8 @@ func (c NRGBA) Add(d NRGBA) NRGBA {
// Sub subtracts color d from color c component-wise and returns the result (the components
// are not clamped).
func (c NRGBA) Sub(d NRGBA) NRGBA {
return NRGBA{
func (c RGBA) Sub(d RGBA) RGBA {
return RGBA{
R: c.R - d.R,
G: c.G - d.G,
B: c.B - d.B,
@ -32,8 +32,8 @@ func (c NRGBA) Sub(d NRGBA) NRGBA {
}
// Mul multiplies color c by color d component-wise (the components are not clamped).
func (c NRGBA) Mul(d NRGBA) NRGBA {
return NRGBA{
func (c RGBA) Mul(d RGBA) RGBA {
return RGBA{
R: c.R * d.R,
G: c.G * d.G,
B: c.B * d.B,
@ -43,8 +43,8 @@ func (c NRGBA) Mul(d NRGBA) NRGBA {
// Scaled multiplies each component of color c by scale and returns the result (the components
// are not clamped).
func (c NRGBA) Scaled(scale float64) NRGBA {
return NRGBA{
func (c RGBA) Scaled(scale float64) RGBA {
return RGBA{
R: c.R * scale,
G: c.G * scale,
B: c.B * scale,
@ -52,37 +52,23 @@ func (c NRGBA) Scaled(scale float64) NRGBA {
}
}
// RGBA returns alpha-premultiplied red, green, blue and alpha components of the NRGBA color.
func (c NRGBA) RGBA() (r, g, b, a uint32) {
c.R = clamp(c.R, 0, 1)
c.G = clamp(c.G, 0, 1)
c.B = clamp(c.B, 0, 1)
c.A = clamp(c.A, 0, 1)
r = uint32(0xffff * c.R * c.A)
g = uint32(0xffff * c.G * c.A)
b = uint32(0xffff * c.B * c.A)
// RGBA returns alpha-premultiplied red, green, blue and alpha components of the RGBA color.
func (c RGBA) RGBA() (r, g, b, a uint32) {
r = uint32(0xffff * c.R)
g = uint32(0xffff * c.G)
b = uint32(0xffff * c.B)
a = uint32(0xffff * c.A)
return
}
func clamp(x, low, high float64) float64 {
if x < low {
return low
}
if x > high {
return high
}
return x
}
// ToNRGBA converts a color to NRGBA format. Using this function is preferred to using NRGBAModel,
// for performance (using NRGBAModel introduced additional unnecessary allocations).
func ToNRGBA(c color.Color) NRGBA {
if c, ok := c.(NRGBA); ok {
// ToRGBA converts a color to RGBA format. Using this function is preferred to using RGBAModel, for
// performance (using RGBAModel introduced additional unnecessary allocations).
func ToRGBA(c color.Color) RGBA {
if c, ok := c.(RGBA); ok {
return c
}
if c, ok := c.(color.NRGBA); ok {
return NRGBA{
if c, ok := c.(color.RGBA); ok {
return RGBA{
R: float64(c.R) / 255,
G: float64(c.G) / 255,
B: float64(c.B) / 255,
@ -90,20 +76,17 @@ func ToNRGBA(c color.Color) NRGBA {
}
}
r, g, b, a := c.RGBA()
if a == 0 {
return NRGBA{0, 0, 0, 0}
}
return NRGBA{
float64(r) / float64(a),
float64(g) / float64(a),
float64(b) / float64(a),
return RGBA{
float64(r) / 0xffff,
float64(g) / 0xffff,
float64(b) / 0xffff,
float64(a) / 0xffff,
}
}
// NRGBAModel converts colors to NRGBA format.
var NRGBAModel = color.ModelFunc(nrgbaModel)
// RGBAModel converts colors to RGBA format.
var RGBAModel = color.ModelFunc(rgbaModel)
func nrgbaModel(c color.Color) color.Color {
return ToNRGBA(c)
func rgbaModel(c color.Color) color.Color {
return ToRGBA(c)
}

90
data.go
View File

@ -12,7 +12,7 @@ import (
// TrianglesPosition, TrianglesColor and TrianglesPicture.
type TrianglesData []struct {
Position Vec
Color NRGBA
Color RGBA
Picture Vec
Intensity float64
}
@ -42,10 +42,10 @@ func (td *TrianglesData) SetLen(len int) {
for i := 0; i < needAppend; i++ {
*td = append(*td, struct {
Position Vec
Color NRGBA
Color RGBA
Picture Vec
Intensity float64
}{V(0, 0), NRGBA{1, 1, 1, 1}, V(0, 0), 0})
}{V(0, 0), RGBA{1, 1, 1, 1}, V(0, 0), 0})
}
}
if len < td.Len() {
@ -108,7 +108,7 @@ func (td *TrianglesData) Position(i int) Vec {
}
// Color returns the color property of i-th vertex.
func (td *TrianglesData) Color(i int) NRGBA {
func (td *TrianglesData) Color(i int) RGBA {
return (*td)[i].Color
}
@ -126,10 +126,10 @@ func (td *TrianglesData) Picture(i int) (pic Vec, intensity float64) {
//
// The struct's innards are exposed for convenience, manual modification is at your own risk.
//
// The format of the pixels is color.NRGBA and not pixel.NRGBA for a very serious reason:
// pixel.NRGBA takes up 8x more memory than color.NRGBA.
// The format of the pixels is color.RGBA and not pixel.RGBA for a very serious reason:
// pixel.RGBA takes up 8x more memory than color.RGBA.
type PictureData struct {
Pix []color.NRGBA
Pix []color.RGBA
Stride int
Rect Rect
}
@ -142,18 +142,18 @@ func MakePictureData(rect Rect) *PictureData {
Stride: w,
Rect: rect,
}
pd.Pix = make([]color.NRGBA, w*h)
pd.Pix = make([]color.RGBA, w*h)
return pd
}
func verticalFlip(nrgba *image.NRGBA) {
bounds := nrgba.Bounds()
func verticalFlip(rgba *image.RGBA) {
bounds := rgba.Bounds()
width := bounds.Dx()
tmpRow := make([]uint8, width*4)
for i, j := 0, bounds.Dy()-1; i < j; i, j = i+1, j-1 {
iRow := nrgba.Pix[i*nrgba.Stride : i*nrgba.Stride+width*4]
jRow := nrgba.Pix[j*nrgba.Stride : j*nrgba.Stride+width*4]
iRow := rgba.Pix[i*rgba.Stride : i*rgba.Stride+width*4]
jRow := rgba.Pix[j*rgba.Stride : j*rgba.Stride+width*4]
copy(tmpRow, iRow)
copy(iRow, jRow)
@ -165,28 +165,28 @@ func verticalFlip(nrgba *image.NRGBA) {
//
// The resulting PictureData's Bounds will be the equivalent of the supplied image.Image's Bounds.
func PictureDataFromImage(img image.Image) *PictureData {
var nrgba *image.NRGBA
if nrgbaImg, ok := img.(*image.NRGBA); ok {
nrgba = nrgbaImg
var rgba *image.RGBA
if rgbaImg, ok := img.(*image.RGBA); ok {
rgba = rgbaImg
} else {
nrgba = image.NewNRGBA(img.Bounds())
draw.Draw(nrgba, nrgba.Bounds(), img, img.Bounds().Min, draw.Src)
rgba = image.NewRGBA(img.Bounds())
draw.Draw(rgba, rgba.Bounds(), img, img.Bounds().Min, draw.Src)
}
verticalFlip(nrgba)
verticalFlip(rgba)
pd := MakePictureData(R(
float64(nrgba.Bounds().Min.X),
float64(nrgba.Bounds().Min.Y),
float64(nrgba.Bounds().Dx()),
float64(nrgba.Bounds().Dy()),
float64(rgba.Bounds().Min.X),
float64(rgba.Bounds().Min.Y),
float64(rgba.Bounds().Dx()),
float64(rgba.Bounds().Dy()),
))
for i := range pd.Pix {
pd.Pix[i].R = nrgba.Pix[i*4+0]
pd.Pix[i].G = nrgba.Pix[i*4+1]
pd.Pix[i].B = nrgba.Pix[i*4+2]
pd.Pix[i].A = nrgba.Pix[i*4+3]
pd.Pix[i].R = rgba.Pix[i*4+0]
pd.Pix[i].G = rgba.Pix[i*4+1]
pd.Pix[i].B = rgba.Pix[i*4+2]
pd.Pix[i].A = rgba.Pix[i*4+3]
}
return pd
@ -220,33 +220,33 @@ func PictureDataFromPicture(pic Picture) *PictureData {
return pd
}
// Image converts PictureData into an image.NRGBA.
// Image converts PictureData into an image.RGBA.
//
// The resulting image.NRGBA's Bounds will be equivalent of the PictureData's Bounds.
func (pd *PictureData) Image() *image.NRGBA {
// The resulting image.RGBA's Bounds will be equivalent of the PictureData's Bounds.
func (pd *PictureData) Image() *image.RGBA {
bounds := image.Rect(
int(math.Floor(pd.Rect.Min.X())),
int(math.Floor(pd.Rect.Min.Y())),
int(math.Ceil(pd.Rect.Max.X())),
int(math.Ceil(pd.Rect.Max.Y())),
)
nrgba := image.NewNRGBA(bounds)
rgba := image.NewRGBA(bounds)
i := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
off := pd.Index(V(float64(x), float64(y)))
nrgba.Pix[i*4+0] = pd.Pix[off].R
nrgba.Pix[i*4+1] = pd.Pix[off].G
nrgba.Pix[i*4+2] = pd.Pix[off].B
nrgba.Pix[i*4+3] = pd.Pix[off].A
rgba.Pix[i*4+0] = pd.Pix[off].R
rgba.Pix[i*4+1] = pd.Pix[off].G
rgba.Pix[i*4+2] = pd.Pix[off].B
rgba.Pix[i*4+3] = pd.Pix[off].A
i++
}
}
verticalFlip(nrgba)
verticalFlip(rgba)
return nrgba
return rgba
}
// Index returns the index of the pixel at the specified position inside the Pix slice.
@ -262,11 +262,11 @@ func (pd *PictureData) Bounds() Rect {
}
// Color returns the color located at the given position.
func (pd *PictureData) Color(at Vec) NRGBA {
func (pd *PictureData) Color(at Vec) RGBA {
if !pd.Rect.Contains(at) {
return NRGBA{0, 0, 0, 0}
return RGBA{0, 0, 0, 0}
}
return ToNRGBA(pd.Pix[pd.Index(at)])
return ToRGBA(pd.Pix[pd.Index(at)])
}
// SetColor changes the color located at the given position.
@ -274,11 +274,11 @@ func (pd *PictureData) SetColor(at Vec, col color.Color) {
if !pd.Rect.Contains(at) {
return
}
nrgba := ToNRGBA(col)
pd.Pix[pd.Index(at)] = color.NRGBA{
R: uint8(nrgba.R * 255),
G: uint8(nrgba.G * 255),
B: uint8(nrgba.B * 255),
A: uint8(nrgba.A * 255),
rgba := ToRGBA(col)
pd.Pix[pd.Index(at)] = color.RGBA{
R: uint8(rgba.R * 255),
G: uint8(rgba.G * 255),
B: uint8(rgba.B * 255),
A: uint8(rgba.A * 255),
}
}

View File

@ -23,7 +23,7 @@ import (
//
// Use various methods to change properties of Pushed points:
//
// imd.Color(pixel.NRGBA{R: 1, G: 0, B: 0, A: 1})
// imd.Color(pixel.RGBA{R: 1, G: 0, B: 0, A: 1})
// imd.Push(pixel.V(200, 200))
// imd.Circle(400, 0)
//
@ -46,7 +46,7 @@ type IMDraw struct {
points []point
opts point
matrix pixel.Matrix
mask pixel.NRGBA
mask pixel.RGBA
tri *pixel.TrianglesData
batch *pixel.Batch
@ -56,7 +56,7 @@ var _ pixel.BasicTarget = (*IMDraw)(nil)
type point struct {
pos pixel.Vec
col pixel.NRGBA
col pixel.RGBA
pic pixel.Vec
in float64
precision int
@ -87,7 +87,7 @@ func New(pic pixel.Picture) *IMDraw {
batch: pixel.NewBatch(tri, pic),
}
im.SetMatrix(pixel.IM)
im.SetColorMask(pixel.NRGBA{R: 1, G: 1, B: 1, A: 1})
im.SetColorMask(pixel.RGBA{R: 1, G: 1, B: 1, A: 1})
im.Reset()
return im
}
@ -127,7 +127,7 @@ func (imd *IMDraw) pushPt(pos pixel.Vec, pt point) {
// Color sets the color of the next Pushed points.
func (imd *IMDraw) Color(color color.Color) {
imd.opts.col = pixel.ToNRGBA(color)
imd.opts.col = pixel.ToRGBA(color)
}
// Picture sets the Picture coordinates of the next Pushed points.
@ -160,7 +160,7 @@ func (imd *IMDraw) SetMatrix(m pixel.Matrix) {
// SetColorMask sets a color that all further point's color will be multiplied by.
func (imd *IMDraw) SetColorMask(color color.Color) {
imd.mask = pixel.ToNRGBA(color)
imd.mask = pixel.ToRGBA(color)
imd.batch.SetColorMask(imd.mask)
}

View File

@ -89,7 +89,7 @@ type TrianglesPosition interface {
// TrianglesColor specifies Triangles with Color property.
type TrianglesColor interface {
Triangles
Color(i int) NRGBA
Color(i int) RGBA
}
// TrianglesPicture specifies Triangles with Picture propery.
@ -126,8 +126,8 @@ type TargetPicture interface {
// PictureColor specifies Picture with Color property, so that every position inside the Picture's
// Bounds has a color.
//
// Positions outside the Picture's Bounds must return transparent black (NRGBA{R: 0, G: 0, B: 0, A: 0}).
// Positions outside the Picture's Bounds must return full transparent (RGBA{R: 0, G: 0, B: 0, A: 0}).
type PictureColor interface {
Picture
Color(at Vec) NRGBA
Color(at Vec) RGBA
}

View File

@ -95,15 +95,15 @@ func (c *Canvas) SetMatrix(m pixel.Matrix) {
// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
func (c *Canvas) SetColorMask(col color.Color) {
nrgba := pixel.NRGBA{R: 1, G: 1, B: 1, A: 1}
rgba := pixel.RGBA{R: 1, G: 1, B: 1, A: 1}
if col != nil {
nrgba = pixel.ToNRGBA(col)
rgba = pixel.ToRGBA(col)
}
c.col = mgl32.Vec4{
float32(nrgba.R),
float32(nrgba.G),
float32(nrgba.B),
float32(nrgba.A),
float32(rgba.R),
float32(rgba.G),
float32(rgba.B),
float32(rgba.A),
}
}
@ -139,10 +139,10 @@ func (c *Canvas) setGlhfBounds() {
func (c *Canvas) Clear(color color.Color) {
c.gf.Dirty()
nrgba := pixel.ToNRGBA(color)
rgba := pixel.ToRGBA(color)
// color masking
nrgba = nrgba.Mul(pixel.NRGBA{
rgba = rgba.Mul(pixel.RGBA{
R: float64(c.col[0]),
G: float64(c.col[1]),
B: float64(c.col[2]),
@ -153,17 +153,17 @@ func (c *Canvas) Clear(color color.Color) {
c.setGlhfBounds()
c.gf.Frame().Begin()
glhf.Clear(
float32(nrgba.R),
float32(nrgba.G),
float32(nrgba.B),
float32(nrgba.A),
float32(rgba.R),
float32(rgba.G),
float32(rgba.B),
float32(rgba.A),
)
c.gf.Frame().End()
})
}
// Color returns the color of the pixel over the given position inside the Canvas.
func (c *Canvas) Color(at pixel.Vec) pixel.NRGBA {
func (c *Canvas) Color(at pixel.Vec) pixel.RGBA {
return c.gf.Color(at)
}
@ -324,9 +324,10 @@ void main() {
color = colorMask * Color;
} else {
color = vec4(0, 0, 0, 0);
color += (1 - Intensity) * colorMask * Color;
color += (1 - Intensity) * Color;
vec2 t = (Texture - texBounds.xy) / texBounds.zw;
color += Intensity * colorMask * Color * texture(tex, t);
color += Intensity * Color * texture(tex, t);
color *= colorMask;
}
}
`

View File

@ -56,7 +56,7 @@ func (gf *GLFrame) Bounds() pixel.Rect {
}
// Color returns the color of the pixel under the specified position.
func (gf *GLFrame) Color(at pixel.Vec) pixel.NRGBA {
func (gf *GLFrame) Color(at pixel.Vec) pixel.RGBA {
if gf.dirty {
mainthread.Call(func() {
tex := gf.frame.Texture()
@ -67,12 +67,12 @@ func (gf *GLFrame) Color(at pixel.Vec) pixel.NRGBA {
gf.dirty = false
}
if !gf.bounds.Contains(at) {
return pixel.NRGBA{}
return pixel.RGBA{}
}
bx, by, bw, _ := intBounds(gf.bounds)
x, y := int(at.X())-bx, int(at.Y())-by
off := y*bw + x
return pixel.NRGBA{
return pixel.RGBA{
R: float64(gf.pixels[off*4+0]) / 255,
G: float64(gf.pixels[off*4+1]) / 255,
B: float64(gf.pixels[off*4+2]) / 255,

View File

@ -30,12 +30,12 @@ func NewGLPicture(p pixel.Picture) GLPicture {
// PictureData short path
for y := 0; y < bh; y++ {
for x := 0; x < bw; x++ {
nrgba := pd.Pix[y*pd.Stride+x]
rgba := pd.Pix[y*pd.Stride+x]
off := (y*bw + x) * 4
pixels[off+0] = nrgba.R
pixels[off+1] = nrgba.G
pixels[off+2] = nrgba.B
pixels[off+3] = nrgba.A
pixels[off+0] = rgba.R
pixels[off+1] = rgba.G
pixels[off+2] = rgba.B
pixels[off+3] = rgba.A
}
}
} else if p, ok := p.(pixel.PictureColor); ok {
@ -82,14 +82,14 @@ func (gp *glPicture) Texture() *glhf.Texture {
return gp.tex
}
func (gp *glPicture) Color(at pixel.Vec) pixel.NRGBA {
func (gp *glPicture) Color(at pixel.Vec) pixel.RGBA {
if !gp.bounds.Contains(at) {
return pixel.NRGBA{}
return pixel.RGBA{}
}
bx, by, bw, _ := intBounds(gp.bounds)
x, y := int(at.X())-bx, int(at.Y())-by
off := y*bw + x
return pixel.NRGBA{
return pixel.RGBA{
R: float64(gp.pixels[off*4+0]) / 255,
G: float64(gp.pixels[off*4+1]) / 255,
B: float64(gp.pixels[off*4+2]) / 255,

View File

@ -178,12 +178,12 @@ func (gt *GLTriangles) Position(i int) pixel.Vec {
}
// Color returns the Color property of the i-th vertex.
func (gt *GLTriangles) Color(i int) pixel.NRGBA {
func (gt *GLTriangles) Color(i int) pixel.RGBA {
r := gt.data[i*gt.vs.Stride()+2]
g := gt.data[i*gt.vs.Stride()+3]
b := gt.data[i*gt.vs.Stride()+4]
a := gt.data[i*gt.vs.Stride()+5]
return pixel.NRGBA{
return pixel.RGBA{
R: float64(r),
G: float64(g),
B: float64(b),

View File

@ -399,6 +399,6 @@ func (w *Window) Clear(c color.Color) {
}
// Color returns the color of the pixel over the given position inside the Window.
func (w *Window) Color(at pixel.Vec) pixel.NRGBA {
func (w *Window) Color(at pixel.Vec) pixel.RGBA {
return w.canvas.Color(at)
}

View File

@ -17,7 +17,7 @@ type Sprite struct {
d Drawer
matrix Matrix
mask NRGBA
mask RGBA
}
// NewSprite creates a Sprite from the supplied frame of a Picture.
@ -28,7 +28,7 @@ func NewSprite(pic Picture, frame Rect) *Sprite {
d: Drawer{Triangles: tri},
}
s.matrix = IM
s.mask = NRGBA{1, 1, 1, 1}
s.mask = RGBA{1, 1, 1, 1}
s.Set(pic, frame)
return s
}
@ -73,12 +73,12 @@ func (s *Sprite) Matrix() Matrix {
// Note, that this has nothing to do with BasicTarget's SetColorMask method. This only affects this
// Sprite and is usable with any Target.
func (s *Sprite) SetColorMask(mask color.Color) {
s.mask = ToNRGBA(mask)
s.mask = ToRGBA(mask)
s.calcData()
}
// ColorMask returns the currently set color mask.
func (s *Sprite) ColorMask() NRGBA {
func (s *Sprite) ColorMask() RGBA {
return s.mask
}