Skip to content

Commit

Permalink
replace NRGBA to RGBA because Porter-Duff (!!!)
Browse files Browse the repository at this point in the history
  • Loading branch information
faiface committed Apr 9, 2017
1 parent 7d31dd8 commit f4916a4
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 138 deletions.
8 changes: 4 additions & 4 deletions batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type Batch struct {
cont Drawer

mat Matrix
col NRGBA
col RGBA
}

var _ BasicTarget = (*Batch)(nil)
Expand All @@ -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
}

Expand Down Expand Up @@ -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.
Expand Down
77 changes: 30 additions & 47 deletions color.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -43,67 +43,50 @@ 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,
A: c.A * scale,
}
}

// 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,
A: float64(c.A) / 255,
}
}
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 changes: 45 additions & 45 deletions data.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// TrianglesPosition, TrianglesColor and TrianglesPicture.
type TrianglesData []struct {
Position Vec
Color NRGBA
Color RGBA
Picture Vec
Intensity float64
}
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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
}

Expand All @@ -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
}
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -262,23 +262,23 @@ 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.
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),
}
}
Loading

0 comments on commit f4916a4

Please sign in to comment.