Skip to content

Commit

Permalink
Remove x,y,w,h from PixMap.Copy, Merge and Foreach
Browse files Browse the repository at this point in the history
  • Loading branch information
elgopher committed Oct 24, 2023
1 parent 8c481dc commit 32e319a
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 28 deletions.
2 changes: 1 addition & 1 deletion devtools/internal/inspector/spr.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (m *sprSelectionMode) update(spr *Spr) {
}

func (m *sprSelectionMode) draw() {
pi.SprSheet().Copy(0, 0, pi.SprSheet().Width(), pi.SprSheet().Height(), pi.Scr(), m.camera.X, m.camera.Y)
pi.SprSheet().Copy(pi.Scr(), m.camera.X, m.camera.Y)

mouseX, mouseY := pi.MousePos.X, pi.MousePos.Y

Expand Down
9 changes: 6 additions & 3 deletions examples/pixmap/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,23 @@ func main() {
pi.Load(resources)

// copy from sprite-sheet to sprite-sheet:
pi.SprSheet().Copy(10, 0, 100, 100, pi.SprSheet(), 0, 0)
src := pi.SprSheet().WithClip(10, 0, 100, 100)
src.Copy(pi.SprSheet(), 0, 0)

// draw a filled rectangle directly to sprite-sheet:
pi.SprSheet().RectFill(60, 30, 70, 40, 7)

// merge from sprite-sheet to screen using custom merge function, which merges two lines
pi.SprSheet().Merge(-1, -1, 103, 70, pi.Scr(), -1, -1, func(dst, src []byte) {
src = pi.SprSheet().WithClip(-1, -1, 103, 70)
src.Merge(pi.Scr(), -1, -1, func(dst, src []byte) {
for x := 0; x < len(dst); x++ {
dst[x] += pi.Pal[src[x]] + 1
}
})

// update each line in a loop:
pi.Scr().Foreach(10, 10, 16, 16, func(x, y int, line []byte) {
src = pi.Scr().WithClip(10, 10, 16, 16)
src.Foreach(func(x, y int, line []byte) {
for i := 0; i < len(line); i++ {
line[i] = byte(i)
}
Expand Down
25 changes: 15 additions & 10 deletions pixmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ type Pointer struct {
RemainingLines int
}

// Copy copies the region specified by x, y, w, h into dst PixMap at dstX,dstY position.
func (p PixMap) Copy(x, y, w, h int, dst PixMap, dstX, dstY int) {
dstPtr, srcPtr := p.pointersForCopy(x, y, w, h, dst, dstX, dstY)
// Copy copies the clipped pixmap into dst PixMap at dstX,dstY position.
func (p PixMap) Copy(dst PixMap, dstX, dstY int) {
dstPtr, srcPtr := p.pointersForCopy(dst, dstX, dstY)

remainingLines := MinInt(dstPtr.RemainingLines, srcPtr.RemainingLines)

Expand All @@ -247,8 +247,8 @@ func (p PixMap) Copy(x, y, w, h int, dst PixMap, dstX, dstY int) {
}

// Merge merges destination with source by running merge operation for each destination line.
func (p PixMap) Merge(x, y, w, h int, dst PixMap, dstX, dstY int, merge func(dst, src []byte)) {
dstPtr, srcPtr := p.pointersForCopy(x, y, w, h, dst, dstX, dstY)
func (p PixMap) Merge(dst PixMap, dstX, dstY int, merge func(dst, src []byte)) {
dstPtr, srcPtr := p.pointersForCopy(dst, dstX, dstY)

remainingLines := MinInt(dstPtr.RemainingLines, srcPtr.RemainingLines)

Expand All @@ -266,14 +266,19 @@ func (p PixMap) Merge(x, y, w, h int, dst PixMap, dstX, dstY int, merge func(dst
}
}

// Foreach runs the update function on PixMap fragment specified by x, y, w and h.
// Foreach runs the update function on clipped PixMap.
//
// The update function accepts entire line to increase the performance.
func (p PixMap) Foreach(x, y, w, h int, update func(x, y int, dst []byte)) {
func (p PixMap) Foreach(update func(x, y int, dst []byte)) {
if update == nil {
return
}

x := p.clip.X
y := p.clip.Y
w := p.clip.W
h := p.clip.H

ptr, ok := p.Pointer(x, y, w, h)
if !ok {
return
Expand Down Expand Up @@ -334,9 +339,9 @@ func (p PixMap) lineOfColor(col byte, length int) []byte {
return line
}

func (p PixMap) pointersForCopy(srcX int, srcY int, w int, h int, dst PixMap, dstX int, dstY int) (Pointer, Pointer) {
dstPtr, _ := dst.Pointer(dstX, dstY, w, h)
srcPtr, _ := p.Pointer(srcX, srcY, w, h)
func (p PixMap) pointersForCopy(dst PixMap, dstX int, dstY int) (Pointer, Pointer) {
dstPtr, _ := dst.Pointer(dstX, dstY, p.clip.W, p.clip.H)
srcPtr, _ := p.Pointer(p.clip.X, p.clip.Y, p.clip.W, p.clip.H)

// both maps must be moved by the same DeltaX and DeltaY
if srcPtr.DeltaX > dstPtr.DeltaX {
Expand Down
38 changes: 24 additions & 14 deletions pixmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,15 @@ func TestPixMap_Pointer(t *testing.T) {
func TestPixMap_Foreach(t *testing.T) {
t.Run("should not do anything when update function is nil", func(t *testing.T) {
pixMap := pi.NewPixMap(2, 2)
pixMap.Foreach(0, 0, 2, 2, nil)
pixMap.Foreach(nil)
})

t.Run("should run update line number of times", func(t *testing.T) {
t.Run("inside clipping range", func(t *testing.T) {
pixMap := pi.NewPixMap(1, 3)
timesRun := 0
pixMap.Foreach(0, 0, 1, 2, func(x, y int, dst []byte) {
src := pixMap.WithClip(0, 0, 1, 2)
src.Foreach(func(x, y int, dst []byte) {
timesRun++
})
assert.Equal(t, 2, timesRun)
Expand All @@ -367,7 +368,8 @@ func TestPixMap_Foreach(t *testing.T) {
t.Run("outside clipping range", func(t *testing.T) {
pixMap := pi.NewPixMap(1, 3)
timesRun := 0
pixMap.Foreach(0, 0, 1, 4, func(x, y int, dst []byte) {
src := pixMap.WithClip(0, 0, 1, 4)
src.Foreach(func(x, y int, dst []byte) {
timesRun++
})
assert.Equal(t, 3, timesRun)
Expand All @@ -380,15 +382,17 @@ func TestPixMap_Foreach(t *testing.T) {

t.Run("x=0", func(t *testing.T) {
var lines [][]byte
pixMap.Foreach(0, 0, 2, 3, func(x, y int, dst []byte) {
src := pixMap.WithClip(0, 0, 2, 3)
src.Foreach(func(x, y int, dst []byte) {
lines = append(lines, dst)
})
assert.Equal(t, [][]byte{{0, 1}, {3, 4}, {6, 7}}, lines)
})

t.Run("x=1", func(t *testing.T) {
var lines [][]byte
pixMap.Foreach(1, 0, 2, 3, func(x, y int, dst []byte) {
src := pixMap.WithClip(1, 0, 2, 3)
src.Foreach(func(x, y int, dst []byte) {
lines = append(lines, dst)
})
assert.Equal(t, [][]byte{{1, 2}, {4, 5}, {7, 8}}, lines)
Expand All @@ -401,15 +405,17 @@ func TestPixMap_Foreach(t *testing.T) {

t.Run("inside clipping range", func(t *testing.T) {
var coords []pi.Position
pixMap.Foreach(1, 1, 2, 2, func(x, y int, dst []byte) {
src := pixMap.WithClip(1, 1, 2, 2)
src.Foreach(func(x, y int, dst []byte) {
coords = append(coords, pi.Position{X: x, Y: y})
})
assert.Equal(t, []pi.Position{{X: 1, Y: 1}, {X: 1, Y: 2}}, coords)
})

t.Run("outside clipping range", func(t *testing.T) {
var coords []pi.Position
pixMap.Foreach(-1, -1, 3, 3, func(x, y int, dst []byte) {
src := pixMap.WithClip(-1, -1, 3, 3)
src.Foreach(func(x, y int, dst []byte) {
coords = append(coords, pi.Position{X: x, Y: y})
})
assert.Equal(t, []pi.Position{{X: 0, Y: 0}, {X: 0, Y: 1}}, coords)
Expand All @@ -422,14 +428,16 @@ func TestPixMap_Foreach(t *testing.T) {
update := func(x, y int, dst []byte) {
executed = true
}
pixMap.Foreach(0, 0, 0, 1, update) // width = 0
src := pixMap.WithClip(0, 0, 0, 1) // width = 0
src.Foreach(update)
assert.False(t, executed)
})

t.Run("should update pixels", func(t *testing.T) {
pixMap := pi.NewPixMap(2, 3)
i := byte(1)
pixMap.Foreach(0, 0, 2, 3, func(x, y int, dst []byte) {
src := pixMap.WithClip(0, 0, 2, 3)
src.Foreach(func(x, y int, dst []byte) {
dst[0] = i
dst[1] = i + 1
i += 2
Expand All @@ -442,7 +450,7 @@ func TestPixMap_Copy(t *testing.T) {
testPixMapCopy(t, pi.PixMap.Copy)
}

func testPixMapCopy(t *testing.T, merge func(pi.PixMap, int, int, int, int, pi.PixMap, int, int)) {
func testPixMapCopy(t *testing.T, merge func(pi.PixMap, pi.PixMap, int, int)) {
t.Run("src bigger than dst", func(t *testing.T) {
src := pi.NewPixMapWithPix([]byte{
1, 2, 3,
Expand Down Expand Up @@ -488,7 +496,8 @@ func testPixMapCopy(t *testing.T, merge func(pi.PixMap, int, int, int, int, pi.P
for name, test := range tests {
t.Run(name, func(t *testing.T) {
dst := pi.NewPixMap(dstWidth, dstHeight)
merge(src, test.x, test.y, test.w, test.h, dst, test.dstX, test.dstY)
source := src.WithClip(test.x, test.y, test.w, test.h)
merge(source, dst, test.dstX, test.dstY)
assert.Equal(t, test.expected, dst.Pix())
})
}
Expand Down Expand Up @@ -517,16 +526,17 @@ func testPixMapCopy(t *testing.T, merge func(pi.PixMap, int, int, int, int, pi.P
for name, test := range tests {
t.Run(name, func(t *testing.T) {
dst := pi.NewPixMap(dstWidth, dstHeight)
merge(src, test.x, test.y, test.w, test.h, dst, test.dstX, test.dstY)
source := src.WithClip(test.x, test.y, test.w, test.h)
merge(source, dst, test.dstX, test.dstY)
assert.Equal(t, test.expected, dst.Pix())
})
}
})
}

func TestPixMap_Merge(t *testing.T) {
testPixMapCopy(t, func(src pi.PixMap, x int, y int, w int, h int, dst pi.PixMap, dstX int, dstY int) {
src.Merge(x, y, w, h, dst, dstX, dstY, func(dst, src []byte) {
testPixMapCopy(t, func(src pi.PixMap, dst pi.PixMap, dstX int, dstY int) {
src.Merge(dst, dstX, dstY, func(dst, src []byte) {
copy(dst, src)
})
})
Expand Down

0 comments on commit 32e319a

Please sign in to comment.